├── Media
├── tetris.gif
└── monkeyspin.gif
├── Examples
├── App.config
├── README.md
├── Example_HelloWorld.cs
├── Properties
│ └── AssemblyInfo.cs
├── ConsoleGameEngineExamples.csproj
├── Tetris.cs
├── Example_3D.cs
├── monkey.obj
└── caligraphy.flf
├── Source
├── Utility.cs
├── Color.cs
├── ConsoleFont.cs
├── ConsoleBuffer.cs
├── Vector.cs
├── Properties
│ └── AssemblyInfo.cs
├── Point.cs
├── ConsoleEnums.cs
├── FigletFont.cs
├── ConsolePalette.cs
├── ConsoleGameEngine.csproj
├── ConsoleGame.cs
├── ConsoleHelper.cs
└── ConsoleEngine.cs
├── UNLICENSE
├── ConsoleGameEngineSolution.sln
├── README.md
└── .gitignore
/Media/tetris.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanselman/ConsoleGameEngine/master/Media/tetris.gif
--------------------------------------------------------------------------------
/Media/monkeyspin.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shanselman/ConsoleGameEngine/master/Media/monkeyspin.gif
--------------------------------------------------------------------------------
/Examples/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Source/Utility.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace ConsoleGameEngine {
6 | /// Utility class.
7 | public class Utility {
8 | static public int Clamp(int a, int min, int max) {
9 | a = (a > max) ? max : a;
10 | a = (a < min) ? min : a;
11 |
12 | return a;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Examples/README.md:
--------------------------------------------------------------------------------
1 | # Examples
2 |
3 | ### 3D
4 | not much to say. Ignore most of the 3D code, fun to play around with but nothing researchable in there ;)
5 |
6 |
7 |
8 |
9 |
10 |
11 | ### Tetris
12 | Just a basic tetris clone. works pretty well, and demostrates how the update loop could be modified!
13 |
14 |
15 |
16 |
17 |
18 | ### HelloWorld
19 |
--------------------------------------------------------------------------------
/Source/Color.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleGameEngine {
2 | /// Represents an RGB color.
3 | public class Color {
4 | /// Red component.
5 | public uint R { get; set; }
6 | /// Green component.
7 | public uint G { get; set; }
8 | /// Bkue component.
9 | public uint B { get; set; }
10 |
11 | /// Creates a new Color from rgb.
12 | public Color(int r, int g, int b) {
13 | this.R = (uint)r;
14 | this.G = (uint)g;
15 | this.B = (uint)b;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Source/ConsoleFont.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleGameEngine {
2 | using System;
3 | using System.Runtime.InteropServices;
4 |
5 | class ConsoleFont {
6 |
7 |
8 |
9 | internal static int SetFont(IntPtr h, short sizeX, short sizeY) {
10 | if (h == new IntPtr(-1)) {
11 | return Marshal.GetLastWin32Error();
12 | }
13 |
14 | NativeMethods.CONSOLE_FONT_INFO_EX cfi = new NativeMethods.CONSOLE_FONT_INFO_EX();
15 | cfi.cbSize = (uint)Marshal.SizeOf(cfi);
16 | cfi.nFont = 0;
17 |
18 | cfi.dwFontSize.X = sizeX;
19 | cfi.dwFontSize.Y = sizeY;
20 |
21 | // sätter font till Terminal (Raster)
22 | if (sizeX < 4 || sizeY < 4) cfi.FaceName = "Consolas";
23 | else cfi.FaceName = "Terminal";
24 |
25 | NativeMethods.SetCurrentConsoleFontEx(h, false, ref cfi);
26 | return 0;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Examples/Example_HelloWorld.cs:
--------------------------------------------------------------------------------
1 | using ConsoleGameEngine;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 |
6 | namespace ConsoleGameEngineExamples {
7 |
8 | internal class HelloWorld : ConsoleGame {
9 | private static void Main(string[] args) {
10 | new HelloWorld().Construct(128, 64, 4, 4, FramerateMode.MaxFps);
11 | }
12 |
13 | Point p = new Point(32, 14);
14 | int i = 0;
15 | FigletFont font;
16 |
17 | public override void Create() {
18 | Engine.SetPalette(Palettes.Pico8);
19 | Engine.Borderless(true);
20 |
21 | TargetFramerate = 15;
22 |
23 | font = FigletFont.Load("caligraphy.flf");
24 | }
25 |
26 | public override void Update() {
27 | p.Y = 14 + (int)(Math.Sin(i * 0.1f) * 4f);
28 | i++;
29 | }
30 |
31 | public override void Render() {
32 | Engine.ClearBuffer();
33 |
34 | Engine.WriteFiglet(p, "Hello", font, 8);
35 |
36 | Engine.DisplayBuffer();
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/UNLICENSE:
--------------------------------------------------------------------------------
1 | This is free and unencumbered software released into the public domain.
2 |
3 | Anyone is free to copy, modify, publish, use, compile, sell, or
4 | distribute this software, either in source code form or as a compiled
5 | binary, for any purpose, commercial or non-commercial, and by any
6 | means.
7 |
8 | In jurisdictions that recognize copyright laws, the author or authors
9 | of this software dedicate any and all copyright interest in the
10 | software to the public domain. We make this dedication for the benefit
11 | of the public at large and to the detriment of our heirs and
12 | successors. We intend this dedication to be an overt act of
13 | relinquishment in perpetuity of all present and future rights to this
14 | software under copyright law.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
24 | For more information, please refer to http://unlicense.org/
25 |
--------------------------------------------------------------------------------
/Source/ConsoleBuffer.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleGameEngine {
2 | using System;
3 | using System.IO;
4 | using Microsoft.Win32.SafeHandles;
5 |
6 | class ConsoleBuffer {
7 | private NativeMethods.CharInfo[] CharInfoBuffer { get; set; }
8 | SafeFileHandle h;
9 |
10 | readonly int width, height;
11 |
12 | public ConsoleBuffer(int w, int he) {
13 | width = w;
14 | height = he;
15 |
16 | h = NativeMethods.CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
17 |
18 | if (!h.IsInvalid) {
19 | CharInfoBuffer = new NativeMethods.CharInfo[width * height];
20 | }
21 | }
22 |
23 | public void SetBuffer(char[,] charBuffer, int[,] colorBuffer, int background) {
24 | for (int y = 0; y < height; y++) {
25 | for (int x = 0; x < width; x++) {
26 | int i = (y * width) + x;
27 |
28 | CharInfoBuffer[i].Attributes = (short)(colorBuffer[x, y] |(background << 4) );
29 | CharInfoBuffer[i].UnicodeChar = charBuffer[x, y];
30 | }
31 | }
32 | }
33 |
34 | public bool Blit() {
35 | NativeMethods.SmallRect rect = new NativeMethods.SmallRect() { Left = 0, Top = 0, Right = (short)width, Bottom = (short)height };
36 |
37 | return NativeMethods.WriteConsoleOutputW(h, CharInfoBuffer,
38 | new NativeMethods.Coord() { X = (short)width, Y = (short)height },
39 | new NativeMethods.Coord() { X = 0, Y = 0 }, ref rect);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Source/Vector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ConsoleGameEngine {
8 | /// Vector of two floats.
9 | public struct Vector {
10 | public float X { get; set; }
11 | public float Y { get; set; }
12 |
13 |
14 | public static Vector Zero { get; private set; } = new Vector(0, 0);
15 | public Vector(float x, float y) {
16 | this.X = x;
17 | this.Y = y;
18 | }
19 |
20 | public Point ToPoint => new Point((int)Math.Round(X, 0), (int)Math.Round(Y, 0));
21 |
22 | public void Rotate(float a) {
23 | Vector n = Vector.Zero;
24 |
25 | n.X = (float)(X * Math.Cos(a / 57.3f) - Y * Math.Sin(a / 57.3f));
26 | n.Y = (float)(X * Math.Sin(a / 57.3f) + Y * Math.Cos(a / 57.3f));
27 |
28 | X = n.X;
29 | Y = n.Y;
30 | }
31 |
32 | public static Vector operator + (Vector a, Vector b) {
33 | return new Vector(a.X + b.X, a.Y + b.Y);
34 | }
35 | public static Vector operator - (Vector a, Vector b) {
36 | return new Vector(a.X - b.X, a.Y - b.Y);
37 | }
38 |
39 | public static Vector operator / (Vector a, float b) {
40 | return new Vector((a.X / b), (a.Y / b));
41 | }
42 | public static Vector operator * (Vector a, float b) {
43 | return new Vector((a.X * b), (a.Y * b));
44 | }
45 |
46 | public static float Distance(Vector a, Vector b) {
47 | Vector dV = b - a;
48 | float d = (float)Math.Sqrt(Math.Pow(dV.X, 2) + Math.Pow(dV.Y, 2));
49 | return d;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Source/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("ConsoleGameEngine")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("ConsoleGameEngine")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("7af47a03-fabf-458b-be6f-4f8bef89a7e6")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Examples/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("ConsoleGameEngineExamples")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("ConsoleGameEngineExamples")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("44eb6014-cbfa-4561-9848-f2923137bf08")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Source/Point.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace ConsoleGameEngine {
6 | /// A Vector containing two ints.
7 | public struct Point {
8 | public int X { get; set; }
9 | public int Y { get; set; }
10 |
11 | public const float Rad2Deg = 180f / (float)Math.PI;
12 | public const float Deg2Rad = (float)Math.PI / 180f;
13 |
14 | /// new Point(0, 0);
15 | public static Point Zero { get; private set; } = new Point(0, 0);
16 |
17 | public Point(int x, int y) {
18 | this.X = x;
19 | this.Y = y;
20 | }
21 |
22 | public Vector ToVector() => new Vector((float)X, (float)Y);
23 | public override string ToString() => String.Format("({0}, {1})", X, Y);
24 |
25 | public static Point operator +(Point a, Point b) {
26 | return new Point(a.X + b.X, a.Y + b.Y);
27 | }
28 | public static Point operator -(Point a, Point b) {
29 | return new Point(a.X - b.X, a.Y - b.Y);
30 | }
31 |
32 | public static Point operator /(Point a, float b) {
33 | return new Point((int)(a.X / b), (int)(a.Y / b));
34 | }
35 | public static Point operator *(Point a, float b) {
36 | return new Point((int)(a.X * b), (int)(a.Y * b));
37 | }
38 |
39 | /// Calculates distance between two points.
40 | /// Point A
41 | /// Point B
42 | /// Distance between A and B
43 | public static float Distance(Point a, Point b) {
44 | Point dV = b - a;
45 | float d = (float)Math.Sqrt(Math.Pow(dV.X, 2) + Math.Pow(dV.Y, 2));
46 | return d;
47 | }
48 |
49 | public void Clamp(Point min, Point max) {
50 | X = (X > max.X) ? max.X : X;
51 | X = (X < min.X) ? min.X : X;
52 |
53 | Y = (Y > max.Y) ? max.Y : Y;
54 | Y = (Y < min.Y) ? min.Y : Y;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/ConsoleGameEngineSolution.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28010.2026
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8C08CF5D-46ED-4A02-850B-93765D06C9CC}"
7 | ProjectSection(SolutionItems) = preProject
8 | README.md = README.md
9 | TODO.txt = TODO.txt
10 | EndProjectSection
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleGameEngineExamples", "Examples\ConsoleGameEngineExamples.csproj", "{44EB6014-CBFA-4561-9848-F2923137BF08}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleGameEngine", "Source\ConsoleGameEngine.csproj", "{7AF47A03-FABF-458B-BE6F-4F8BEF89A7E6}"
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Release|Any CPU = Release|Any CPU
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {44EB6014-CBFA-4561-9848-F2923137BF08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {44EB6014-CBFA-4561-9848-F2923137BF08}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {44EB6014-CBFA-4561-9848-F2923137BF08}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {44EB6014-CBFA-4561-9848-F2923137BF08}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {7AF47A03-FABF-458B-BE6F-4F8BEF89A7E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {7AF47A03-FABF-458B-BE6F-4F8BEF89A7E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {7AF47A03-FABF-458B-BE6F-4F8BEF89A7E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {7AF47A03-FABF-458B-BE6F-4F8BEF89A7E6}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {B1520222-3D85-43B1-B1AE-B8B2C66B7282}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/Source/ConsoleEnums.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleGameEngine {
2 | /// Enum for basic Unicodes.
3 | public enum ConsoleCharacter {
4 | Null = 0x0000,
5 |
6 | Full = 0x2588,
7 | Dark = 0x2593,
8 | Medium = 0x2592,
9 | Light = 0x2591,
10 |
11 | // box drawing syboler
12 | // ┌───────┐
13 | // │ │
14 | // │ │
15 | // └───────┘
16 | BoxDrawingL_H = 0x2500,
17 | BoxDrawingL_V = 0x2502,
18 | BoxDrawingL_DR = 0x250C,
19 | BoxDrawingL_DL = 0x2510,
20 | BoxDrawingL_UL = 0x2518,
21 | BoxDrawingL_UR = 0x2514,
22 | }
23 |
24 | /// Enum for Different Gameloop modes.
25 | public enum FramerateMode {
26 | /// Run at max speed, but no higher than TargetFramerate.
27 | MaxFps,
28 | /// Run at max speed.
29 | Unlimited
30 | }
31 |
32 | /// Represents prebuilt palettes.
33 | public static class Palettes {
34 | /// Pico8 palette.
35 | public static Color[] Pico8 { get; set; } = new Color[16] {
36 | new Color(0, 0, 0), // Black
37 | new Color(29, 43, 83),
38 | new Color(126, 37, 83),
39 | new Color(0, 135, 81),
40 | new Color(171, 82, 54),
41 | new Color(95, 87, 79),
42 | new Color(194, 195, 199),
43 | new Color(255, 241, 232),
44 | new Color(255, 0, 77),
45 | new Color(255, 163, 0),
46 | new Color(255, 236, 39),
47 | new Color(0, 228, 54),
48 | new Color(41, 173, 255),
49 | new Color(131, 118, 156),
50 | new Color(255, 119, 168),
51 | new Color(255, 204, 170),
52 | };
53 |
54 | /// default windows console palette.
55 | public static Color[] Default { get; set; } = new Color[16] {
56 | new Color(12, 12, 12), // Black
57 | new Color(0, 55, 218), // DarkBlue
58 | new Color(19, 161, 14), // DarkGreen
59 | new Color(58, 150, 221), // DarkCyan
60 | new Color(197, 15, 31), // DarkRed
61 | new Color(136, 23, 152), // DarkMagenta
62 | new Color(193, 156, 0), // DarkYellow
63 | new Color(204, 204, 204), // Gray
64 | new Color(118, 118, 118), // DarkGray
65 | new Color(59, 120, 255), // Blue
66 | new Color(22, 192, 12), // Green
67 | new Color(97, 214, 214), // Cyan
68 | new Color(231, 72, 86), // Red
69 | new Color(180, 0, 158), // Magenta
70 | new Color(249, 241, 165), // Yellow
71 | new Color(242, 242, 242), // White
72 | };
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/Source/FigletFont.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text.RegularExpressions;
6 |
7 | namespace ConsoleGameEngine {
8 | /// A FIGlet font.
9 | public class FigletFont {
10 |
11 | public int CommentLines { get; private set; }
12 | public string HardBlank { get; private set; }
13 | public int Height { get; private set; }
14 | public int Kerning { get; private set; }
15 | public string[] Lines { get; private set; }
16 | public int MaxLength { get; private set; }
17 | public string Signature { get; private set; }
18 |
19 | public static FigletFont Load(string filePath) {
20 | if (filePath == null) throw new ArgumentNullException(nameof(filePath));
21 | IEnumerable fontLines = File.ReadLines(filePath);
22 |
23 | FigletFont font = new FigletFont() {
24 | Lines = fontLines.ToArray()
25 | };
26 | var cs = font.Lines.First();
27 | var configs = cs.Split(' ');
28 | font.Signature = configs.First().Remove(configs.First().Length - 1);
29 |
30 | if(font.Signature == "flf2a") {
31 | font.HardBlank = configs.First().Last().ToString();
32 | font.Height = ParseInt(configs, 1);
33 | font.MaxLength = ParseInt(configs, 3);
34 | font.CommentLines = ParseInt(configs, 5);
35 | }
36 |
37 |
38 | return font;
39 | }
40 |
41 | private static int ParseInt(string[] values, int index) {
42 | var i = 0;
43 | if(values.Length > index) {
44 | int.TryParse(values[index], out i);
45 | }
46 |
47 | return i;
48 | }
49 |
50 |
51 |
52 | // ----
53 | internal static int GetStringWidth(FigletFont font, string value) {
54 | List charWidths = new List();
55 | foreach (var character in value) {
56 | int charWidth = 0;
57 | for (int line = 1; line <= font.Height; line++) {
58 | string figletCharacter = GetCharacter(font, character, line);
59 |
60 | charWidth = figletCharacter.Length > charWidth ? figletCharacter.Length : charWidth;
61 | }
62 | charWidths.Add(charWidth);
63 | }
64 |
65 | return charWidths.Sum();
66 | }
67 |
68 | internal static string GetCharacter(FigletFont font, char character, int line) {
69 | var start = font.CommentLines + ((Convert.ToInt32(character) - 32) * font.Height);
70 | var result = font.Lines[start + line];
71 | var lineEnding = result[result.Length - 1];
72 | result = Regex.Replace(result, @"\" + lineEnding + "{1,2}$", string.Empty);
73 |
74 | if (font.Kerning > 0) {
75 | result += new string(' ', font.Kerning);
76 | }
77 |
78 | return result.Replace(font.HardBlank, " ");
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Source/ConsolePalette.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleGameEngine {
2 | using System;
3 | using System.Runtime.InteropServices;
4 |
5 | class ConsolePalette {
6 |
7 | public static int SetColor(int consoleColor, Color targetColor) {
8 | return SetColor(consoleColor, targetColor.R, targetColor.G, targetColor.B);
9 | }
10 |
11 | private static int SetColor(int color, uint r, uint g, uint b) {
12 | NativeMethods.CONSOLE_SCREEN_BUFFER_INFO_EX csbe = new NativeMethods.CONSOLE_SCREEN_BUFFER_INFO_EX();
13 | csbe.cbSize = Marshal.SizeOf(csbe);
14 | IntPtr hConsoleOutput = NativeMethods.GetStdHandle(-11);
15 | if (hConsoleOutput == new IntPtr(-1)) {
16 | return Marshal.GetLastWin32Error();
17 | }
18 | bool brc = NativeMethods.GetConsoleScreenBufferInfoEx(hConsoleOutput, ref csbe);
19 | if (!brc) {
20 | return Marshal.GetLastWin32Error();
21 | }
22 |
23 | switch (color) {
24 | case 0:
25 | csbe.black = new NativeMethods.ColorRef(r, g, b);
26 | break;
27 | case 1:
28 | csbe.darkBlue = new NativeMethods.ColorRef(r, g, b);
29 | break;
30 | case 2:
31 | csbe.darkGreen = new NativeMethods.ColorRef(r, g, b);
32 | break;
33 | case 3:
34 | csbe.darkCyan = new NativeMethods.ColorRef(r, g, b);
35 | break;
36 | case 4:
37 | csbe.darkRed = new NativeMethods.ColorRef(r, g, b);
38 | break;
39 | case 5:
40 | csbe.darkMagenta = new NativeMethods.ColorRef(r, g, b);
41 | break;
42 | case 6:
43 | csbe.darkYellow = new NativeMethods.ColorRef(r, g, b);
44 | break;
45 | case 7:
46 | csbe.gray = new NativeMethods.ColorRef(r, g, b);
47 | break;
48 | case 8:
49 | csbe.darkGray = new NativeMethods.ColorRef(r, g, b);
50 | break;
51 | case 9:
52 | csbe.blue = new NativeMethods.ColorRef(r, g, b);
53 | break;
54 | case 10:
55 | csbe.green = new NativeMethods.ColorRef(r, g, b);
56 | break;
57 | case 11:
58 | csbe.cyan = new NativeMethods.ColorRef(r, g, b);
59 | break;
60 | case 12:
61 | csbe.red = new NativeMethods.ColorRef(r, g, b);
62 | break;
63 | case 13:
64 | csbe.magenta = new NativeMethods.ColorRef(r, g, b);
65 | break;
66 | case 14:
67 | csbe.yellow = new NativeMethods.ColorRef(r, g, b);
68 | break;
69 | case 15:
70 | csbe.white = new NativeMethods.ColorRef(r, g, b);
71 | break;
72 | }
73 |
74 | ++csbe.srWindow.Bottom;
75 | ++csbe.srWindow.Right;
76 |
77 | brc = NativeMethods.SetConsoleScreenBufferInfoEx(hConsoleOutput, ref csbe);
78 | if (!brc) {
79 | return Marshal.GetLastWin32Error();
80 | }
81 | return 0;
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/Examples/ConsoleGameEngineExamples.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {44EB6014-CBFA-4561-9848-F2923137BF08}
8 | Exe
9 | ConsoleGameEngineExamples
10 | ConsoleGameEngineExamples
11 | v4.6.1
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 | ConsoleGameEngineExamples.Tetris
37 |
38 |
39 |
40 | False
41 | ..\Source\bin\Debug\ConsoleGameEngine.dll
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/Source/ConsoleGameEngine.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {7AF47A03-FABF-458B-BE6F-4F8BEF89A7E6}
8 | Library
9 | Properties
10 | ConsoleGameEngine
11 | ConsoleGameEngine
12 | v4.6.1
13 | 512
14 | true
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | bin\Debug\ConsoleGameEngine.xml
25 | false
26 |
27 |
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/Source/ConsoleGame.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleGameEngine {
2 |
3 | using System;
4 | using System.Linq;
5 | using System.Threading;
6 |
7 | ///
8 | /// Abstract class to aid in Gamemaking.
9 | /// Implements an instance of the ConsoleEngine and has Looping methods.
10 | ///
11 | public abstract class ConsoleGame {
12 | /// Instance of a ConsoleEngine.
13 | public ConsoleEngine Engine { get; private set; }
14 |
15 | /// A counter representing the current unique frame we're at.
16 | public int FrameCounter { get; set; }
17 | /// Factor for generating framerate-independent physics. time between last frame and current.
18 | public float DeltaTime { get; set; }
19 |
20 | /// The framerate the engine is trying to run at.
21 | public int TargetFramerate { get; set; }
22 |
23 | private bool Running { get; set; }
24 | private Thread gameThread;
25 |
26 | private double[] framerateSamples;
27 |
28 | /// Initializes the ConsoleGame. Creates the instance of a ConsoleEngine and starts the game loop.
29 | /// Width of the window.
30 | /// Height of the window.
31 | /// Width of the font.
32 | /// ´Height of the font.
33 | /// Framerate mode to run at.
34 | ///
35 | public void Construct(int width, int height, int fontW, int fontH, FramerateMode m) {
36 | TargetFramerate = 30;
37 |
38 | Engine = new ConsoleEngine(width, height, fontW, fontH);
39 | Create();
40 |
41 | if (m == FramerateMode.Unlimited) gameThread = new Thread(new ThreadStart(GameLoopUnlimited));
42 | if (m == FramerateMode.MaxFps) gameThread = new Thread(new ThreadStart(GameLoopLocked));
43 | Running = true;
44 | gameThread.Start();
45 |
46 | // gör special checks som ska gå utanför spelloopen
47 | // om spel-loopen hänger sig ska man fortfarande kunna avsluta
48 | while (Running) {
49 | CheckForExit();
50 | }
51 | }
52 |
53 | private void GameLoopLocked() {
54 | int sampleCount = TargetFramerate;
55 | framerateSamples = new double[sampleCount];
56 |
57 | DateTime lastTime;
58 | float uncorrectedSleepDuration = 1000 / TargetFramerate;
59 | while (Running) {
60 | lastTime = DateTime.UtcNow;
61 |
62 | FrameCounter++;
63 | FrameCounter = FrameCounter % sampleCount;
64 |
65 | // kör main programmet
66 | Update();
67 | Render();
68 |
69 | float computingDuration = (float)(DateTime.UtcNow - lastTime).TotalMilliseconds;
70 | int sleepDuration = (int)(uncorrectedSleepDuration - computingDuration);
71 | if (sleepDuration > 0) {
72 | // programmet ligger före maxFps, sänker det
73 | Thread.Sleep(sleepDuration);
74 | }
75 |
76 | // beräknar framerate
77 | TimeSpan diff = DateTime.UtcNow - lastTime;
78 | DeltaTime = (float)(1 / (TargetFramerate * diff.TotalSeconds));
79 |
80 | framerateSamples[FrameCounter] = (double)diff.TotalSeconds;
81 | }
82 | }
83 |
84 | private void GameLoopUnlimited() {
85 | int sampleCount = TargetFramerate;
86 | framerateSamples = new double[sampleCount];
87 |
88 | DateTime lastTime;
89 | while (Running) {
90 | lastTime = DateTime.UtcNow;
91 |
92 | FrameCounter++;
93 | FrameCounter = FrameCounter % sampleCount;
94 |
95 | Update();
96 | Render();
97 |
98 | // beräknar framerate
99 | TimeSpan diff = DateTime.UtcNow - lastTime;
100 | DeltaTime = (float)diff.TotalSeconds;
101 |
102 | framerateSamples[FrameCounter] = diff.TotalSeconds;
103 |
104 | // kollar om spelaren vill sluta
105 | CheckForExit();
106 | }
107 | }
108 |
109 | /// Gets the current framerate the application is running at.
110 | /// Application Framerate.
111 | public double GetFramerate() {
112 | return 1 / (framerateSamples.Sum() / (TargetFramerate));
113 | }
114 |
115 | private void CheckForExit() {
116 | if (Engine.GetKeyDown(ConsoleKey.Delete)) {
117 | Running = false;
118 | }
119 | }
120 |
121 | /// Run once on Creating, import Resources here.
122 | public abstract void Create();
123 | /// Run every frame before rendering. Do math here.
124 | public abstract void Update();
125 | /// Run every frame after updating. Do drawing here.
126 | public abstract void Render();
127 | }
128 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ConsoleGameEngine
2 | ### C# Graphics Library for drawing graphics in Windows Command Prompt
3 | Olle Logdahl, 24 November 2018
4 |
5 | ---
6 | **ConsoleGameEngine** is a C# library that wraps around the `System.Console` class, adding enhanced
7 | functionality for displaying graphics. Implements a new ConsoleGame abstract, a custom buffer, custom
8 | color palette, fullscreen capabilites, input handling and more.
9 |
10 |
11 |
12 |
13 |
14 | ## Installation / Getting Started
15 | - [Download Lastest Build](https://github.com/ollelogdahl/ConsoleGameEngine/releases/)
16 | - Clone git repo and build yourself
17 | > git clone https://github.com/ollelogdahl/ConsoleGameEngine.git
18 |
19 |
20 |
21 | After installing you'll have to:
22 | 1. Import `ConsoleGameEngine.dll` to project.
23 | 2. Reference the namespace `using ConsoleGameEngine;`
24 |
25 | ---
26 |
27 | ## Why?
28 | I created this Library to make graphics more available for beginners and hobbyists alike. The first programs
29 | you create are usually made in the console, but when users want to migrate to actual graphics there is a steep
30 | learning curve. My ambition with this library is to depricate the need for psuedo-graphics in the console,
31 | usually done by moving the cursor, writing a short string and clearing the actual screen. Not only is that
32 | solution unintuitive in the long run, but also highly inefficient.
33 |
34 | #### Uses
35 | - retro-terminal-styled games and applications
36 | - easy-to-use graphics library for basic and advanced graphics in games and applications
37 | - ~~Creating heavy 3D graphics running in 4K~~
38 |
39 | Does the last apply to you? Then sorry, *this is not the library you are looking for.*
40 |
41 | ## Usage / Features
42 | Library contains two main classes, `ConsoleEngine` and `ConsoleGame`
43 |
44 | - Custom character screen buffer, allows clearing and blitting to console window
45 | - Console colors with full rgb capabilities
46 | - Custom & premade Palettes, used for changing console window palette
47 | - Accessing and setting pixels individually
48 | - Functions to draw basic shapes and primitives (Triangles, Rectangles, Lines etc.)
49 | - Writing characters to screen using plain-text and FIGlet fonts
50 | - Multiple game loops, including fixed framerate and deltatime settings
51 | - Point and Vector class, for int and float positions
52 | - Setting console window settings, changing window size and running console borderless
53 | - Input handling
54 |
55 | #### ConsoleEngine
56 | Is used to draw to the screen, replacement for the `System.Console` class *(kind of)*
57 |
58 | ```c#
59 | using ConsoleGameEngine;
60 | ...
61 | Engine = new ConsoleEngine(windowWidth, windowHeight, fontWidth, fontHeight);
62 |
63 | Engine.SetPixel(new Point(8, 8), ConsoleCharacter.Full, 15);
64 |
65 | ```
66 |
67 | #### ConsoleGame
68 | Keeps an instance of the `ConsoleEngine` and implements game loops.
69 |
70 | **Note** *Not neccessary, you could use the ConsoleEngine as is*
71 |
72 | ```c#
73 | using ConsoleGameEngine;
74 | ...
75 |
76 | new AppName.Construct(windowWidth, windowHeight, fontWidth, fontHeight, FramerateMode.Unlimited);
77 | class AppName : ConsoleGame {
78 | public override void Create() {
79 | }
80 |
81 | public override void Update() {
82 | }
83 |
84 | public override void Render() {
85 | }
86 | }
87 | ```
88 |
89 | ##### Try out some example games over [here](https://github.com/ollelogdahl/ConsoleGameEngine/tree/master/Examples)
90 |
91 | ## Notes
92 | - Color palette limited to 16 colors in a single session *(this is an internal limitation, see [MDSN](https://docs.microsoft.com/en-us/windows/console/console-screen-buffer-infoex))*
93 | - Only **ONE** reference to a `ConsoleEngine` is allowed per session
94 | - Press *Delete Key* to close application if running in borderless
95 | ---
96 |
97 | ## Links
98 |
99 | - [Repository](https://github.com/ollelogdahl/ConsoleGameEngine/)
100 | - For reporting errors, visit [Issue Tracker](https://github.com/ollelogdahl/ConsoleGameEngine/issues)!
101 | - Related Projects:
102 | - [olcConsoleGameEngine (c++)](https://github.com/OneLoneCoder/videos/blob/master/olcConsoleGameEngine.h) by Javidx9
103 | - [ColorfulConsole (C#)](http://colorfulconsole.com/) by Tom Akita
104 | - Special Thanks to:
105 | - [pinvoke.net](http://www.pinvoke.net/) by Redgate Software, for windows api documentation
106 | - [ScreenToGif](https://www.screentogif.com) by Nicke Manarin, for making screen-gif capturing easy :)
107 |
108 | ## Licensing
109 |
110 | This project, and all code it contains, is licensed under *The Unlicense* and can be read [here](UNLICENSE).
111 |
--------------------------------------------------------------------------------
/Source/ConsoleHelper.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleGameEngine {
2 | using System;
3 | using System.IO;
4 | using System.Runtime.InteropServices;
5 | using Microsoft.Win32.SafeHandles;
6 |
7 | // En helper klass för att wrappa User32 och Kernel32 dll
8 | class NativeMethods {
9 | #region Signatures
10 |
11 | [DllImport("user32.dll", SetLastError = true)]
12 | public static extern short GetAsyncKeyState(Int32 vKey);
13 | [DllImport("user32.dll", SetLastError = true)]
14 | public static extern bool GetCursorPos(out POINT vKey);
15 |
16 |
17 | [DllImport("user32.dll", SetLastError = true)]
18 | public static extern bool GetWindowRect(IntPtr hWnd, ref Rect lpRect);
19 | [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
20 | public static extern IntPtr GetDesktopWindow();
21 |
22 | [DllImport("user32.dll", SetLastError = true)]
23 | public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
24 | [DllImport("user32.dll", SetLastError = true)]
25 | public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
26 | [DllImport("user32.dll", SetLastError = true)]
27 | public static extern bool DrawMenuBar(IntPtr hWnd);
28 | [DllImport("user32.dll", SetLastError = true)]
29 | public static extern int MapWindowPoints(IntPtr hWndFrom, IntPtr hWndTo, [In, Out] ref Rect rect, [MarshalAs(UnmanagedType.U4)] int cPoints);
30 |
31 |
32 |
33 | [DllImport("kernel32.dll", SetLastError = true)]
34 | public static extern IntPtr GetStdHandle(int nStdHandle);
35 | [DllImport("kernel32.dll", SetLastError = true)]
36 | public static extern IntPtr GetConsoleWindow();
37 |
38 |
39 | [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
40 | public static extern SafeFileHandle CreateFile(
41 | string fileName,
42 | [MarshalAs(UnmanagedType.U4)] uint fileAccess,
43 | [MarshalAs(UnmanagedType.U4)] uint fileShare,
44 | IntPtr securityAttributes,
45 | [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
46 | [MarshalAs(UnmanagedType.U4)] int flags,
47 | IntPtr template);
48 |
49 | [DllImport("kernel32.dll", SetLastError = true)]
50 | public static extern bool WriteConsoleOutputW(
51 | SafeFileHandle hConsoleOutput,
52 | CharInfo[] lpBuffer,
53 | Coord dwBufferSize,
54 | Coord dwBufferCoord,
55 | ref SmallRect lpWriteRegion);
56 |
57 | [DllImport("kernel32.dll", SetLastError = true)]
58 | public static extern bool GetConsoleScreenBufferInfoEx( IntPtr hConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFO_EX csbe );
59 |
60 | [DllImport("kernel32.dll", SetLastError = true)]
61 | public static extern bool SetConsoleScreenBufferInfoEx( IntPtr ConsoleOutput, ref CONSOLE_SCREEN_BUFFER_INFO_EX csbe );
62 |
63 | [DllImport("kernel32.dll", SetLastError = true)]
64 | public static extern Int32 SetCurrentConsoleFontEx(
65 | IntPtr ConsoleOutput,
66 | bool MaximumWindow,
67 | ref CONSOLE_FONT_INFO_EX ConsoleCurrentFontEx);
68 |
69 | [DllImport("kernel32.dll", SetLastError = true)]
70 | public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
71 |
72 | #endregion
73 |
74 | #region Structs
75 |
76 | // Basic
77 | [StructLayout(LayoutKind.Sequential)]
78 | public struct POINT {
79 | public int X;
80 | public int Y;
81 | }
82 |
83 | [StructLayout(LayoutKind.Sequential)]
84 | public struct Coord {
85 | public short X;
86 | public short Y;
87 |
88 | public Coord(short X, short Y) {
89 | this.X = X;
90 | this.Y = Y;
91 | }
92 | };
93 | [StructLayout(LayoutKind.Sequential)]
94 | public struct Rect {
95 | public int Left;
96 | public int Top;
97 | public int Right;
98 | public int Bottom;
99 | }
100 | [StructLayout(LayoutKind.Sequential)]
101 | public struct SmallRect {
102 | public short Left;
103 | public short Top;
104 | public short Right;
105 | public short Bottom;
106 | }
107 |
108 | // Tecken, används av buffern
109 | [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
110 | public struct CharInfo {
111 | [FieldOffset(0)] public char UnicodeChar;
112 | [FieldOffset(0)] public byte AsciiChar;
113 | [FieldOffset(2)] public short Attributes;
114 | }
115 |
116 | // Används for att ändra ColorRef, custom palette :)
117 | [StructLayout(LayoutKind.Sequential)]
118 | public struct ColorRef {
119 | internal uint ColorDWORD;
120 |
121 | internal ColorRef(Color color) {
122 | ColorDWORD = (uint)color.R + (((uint)color.G) << 8) + (((uint)color.B) << 16);
123 | }
124 |
125 | internal ColorRef(uint r, uint g, uint b) {
126 | ColorDWORD = r + (g << 8) + (b << 16);
127 | }
128 |
129 | internal Color GetColor() {
130 | return new Color((int)(0x000000FFU & ColorDWORD),
131 | (int)(0x0000FF00U & ColorDWORD) >> 8, (int)(0x00FF0000U & ColorDWORD) >> 16);
132 | }
133 |
134 | internal void SetColor(Color color) {
135 | ColorDWORD = (uint)color.R + (((uint)color.G) << 8) + (((uint)color.B) << 16);
136 | }
137 | }
138 |
139 | [StructLayout(LayoutKind.Sequential)]
140 | public struct CONSOLE_SCREEN_BUFFER_INFO_EX {
141 | public int cbSize;
142 | public Coord dwSize;
143 | public Coord dwCursorPosition;
144 | public short wAttributes;
145 | public SmallRect srWindow;
146 | public Coord dwMaximumWindowSize;
147 |
148 | public ushort wPopupAttributes;
149 | public bool bFullscreenSupported;
150 |
151 | internal ColorRef black;
152 | internal ColorRef darkBlue;
153 | internal ColorRef darkGreen;
154 | internal ColorRef darkCyan;
155 | internal ColorRef darkRed;
156 | internal ColorRef darkMagenta;
157 | internal ColorRef darkYellow;
158 | internal ColorRef gray;
159 | internal ColorRef darkGray;
160 | internal ColorRef blue;
161 | internal ColorRef green;
162 | internal ColorRef cyan;
163 | internal ColorRef red;
164 | internal ColorRef magenta;
165 | internal ColorRef yellow;
166 | internal ColorRef white;
167 | }
168 |
169 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
170 | public struct CONSOLE_FONT_INFO_EX {
171 | public uint cbSize;
172 | public uint nFont;
173 | public Coord dwFontSize;
174 | public int FontFamily;
175 | public int FontWeight;
176 |
177 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] // Edit sizeconst if the font name is too big
178 | public string FaceName;
179 | }
180 |
181 | #endregion
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.iobj
67 | *.pch
68 | *.pdb
69 | *.ipdb
70 | *.pgc
71 | *.pgd
72 | *.rsp
73 | *.sbr
74 | *.tlb
75 | *.tli
76 | *.tlh
77 | *.tmp
78 | *.tmp_proj
79 | *.log
80 | *.vspscc
81 | *.vssscc
82 | .builds
83 | *.pidb
84 | *.svclog
85 | *.scc
86 |
87 | # Chutzpah Test files
88 | _Chutzpah*
89 |
90 | # Visual C++ cache files
91 | ipch/
92 | *.aps
93 | *.ncb
94 | *.opendb
95 | *.opensdf
96 | *.sdf
97 | *.cachefile
98 | *.VC.db
99 | *.VC.VC.opendb
100 |
101 | # Visual Studio profiler
102 | *.psess
103 | *.vsp
104 | *.vspx
105 | *.sap
106 |
107 | # Visual Studio Trace Files
108 | *.e2e
109 |
110 | # TFS 2012 Local Workspace
111 | $tf/
112 |
113 | # Guidance Automation Toolkit
114 | *.gpState
115 |
116 | # ReSharper is a .NET coding add-in
117 | _ReSharper*/
118 | *.[Rr]e[Ss]harper
119 | *.DotSettings.user
120 |
121 | # JustCode is a .NET coding add-in
122 | .JustCode
123 |
124 | # TeamCity is a build add-in
125 | _TeamCity*
126 |
127 | # DotCover is a Code Coverage Tool
128 | *.dotCover
129 |
130 | # AxoCover is a Code Coverage Tool
131 | .axoCover/*
132 | !.axoCover/settings.json
133 |
134 | # Visual Studio code coverage results
135 | *.coverage
136 | *.coveragexml
137 |
138 | # NCrunch
139 | _NCrunch_*
140 | .*crunch*.local.xml
141 | nCrunchTemp_*
142 |
143 | # MightyMoose
144 | *.mm.*
145 | AutoTest.Net/
146 |
147 | # Web workbench (sass)
148 | .sass-cache/
149 |
150 | # Installshield output folder
151 | [Ee]xpress/
152 |
153 | # DocProject is a documentation generator add-in
154 | DocProject/buildhelp/
155 | DocProject/Help/*.HxT
156 | DocProject/Help/*.HxC
157 | DocProject/Help/*.hhc
158 | DocProject/Help/*.hhk
159 | DocProject/Help/*.hhp
160 | DocProject/Help/Html2
161 | DocProject/Help/html
162 |
163 | # Click-Once directory
164 | publish/
165 |
166 | # Publish Web Output
167 | *.[Pp]ublish.xml
168 | *.azurePubxml
169 | # Note: Comment the next line if you want to checkin your web deploy settings,
170 | # but database connection strings (with potential passwords) will be unencrypted
171 | *.pubxml
172 | *.publishproj
173 |
174 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
175 | # checkin your Azure Web App publish settings, but sensitive information contained
176 | # in these scripts will be unencrypted
177 | PublishScripts/
178 |
179 | # NuGet Packages
180 | *.nupkg
181 | # The packages folder can be ignored because of Package Restore
182 | **/[Pp]ackages/*
183 | # except build/, which is used as an MSBuild target.
184 | !**/[Pp]ackages/build/
185 | # Uncomment if necessary however generally it will be regenerated when needed
186 | #!**/[Pp]ackages/repositories.config
187 | # NuGet v3's project.json files produces more ignorable files
188 | *.nuget.props
189 | *.nuget.targets
190 |
191 | # Microsoft Azure Build Output
192 | csx/
193 | *.build.csdef
194 |
195 | # Microsoft Azure Emulator
196 | ecf/
197 | rcf/
198 |
199 | # Windows Store app package directories and files
200 | AppPackages/
201 | BundleArtifacts/
202 | Package.StoreAssociation.xml
203 | _pkginfo.txt
204 | *.appx
205 |
206 | # Visual Studio cache files
207 | # files ending in .cache can be ignored
208 | *.[Cc]ache
209 | # but keep track of directories ending in .cache
210 | !*.[Cc]ache/
211 |
212 | # Others
213 | ClientBin/
214 | ~$*
215 | *~
216 | *.dbmdl
217 | *.dbproj.schemaview
218 | *.jfm
219 | *.pfx
220 | *.publishsettings
221 | orleans.codegen.cs
222 |
223 | # Including strong name files can present a security risk
224 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
225 | #*.snk
226 |
227 | # Since there are multiple workflows, uncomment next line to ignore bower_components
228 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
229 | #bower_components/
230 |
231 | # RIA/Silverlight projects
232 | Generated_Code/
233 |
234 | # Backup & report files from converting an old project file
235 | # to a newer Visual Studio version. Backup files are not needed,
236 | # because we have git ;-)
237 | _UpgradeReport_Files/
238 | Backup*/
239 | UpgradeLog*.XML
240 | UpgradeLog*.htm
241 | ServiceFabricBackup/
242 | *.rptproj.bak
243 |
244 | # SQL Server files
245 | *.mdf
246 | *.ldf
247 | *.ndf
248 |
249 | # Business Intelligence projects
250 | *.rdl.data
251 | *.bim.layout
252 | *.bim_*.settings
253 | *.rptproj.rsuser
254 |
255 | # Microsoft Fakes
256 | FakesAssemblies/
257 |
258 | # GhostDoc plugin setting file
259 | *.GhostDoc.xml
260 |
261 | # Node.js Tools for Visual Studio
262 | .ntvs_analysis.dat
263 | node_modules/
264 |
265 | # Visual Studio 6 build log
266 | *.plg
267 |
268 | # Visual Studio 6 workspace options file
269 | *.opt
270 |
271 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
272 | *.vbw
273 |
274 | # Visual Studio LightSwitch build output
275 | **/*.HTMLClient/GeneratedArtifacts
276 | **/*.DesktopClient/GeneratedArtifacts
277 | **/*.DesktopClient/ModelManifest.xml
278 | **/*.Server/GeneratedArtifacts
279 | **/*.Server/ModelManifest.xml
280 | _Pvt_Extensions
281 |
282 | # Paket dependency manager
283 | .paket/paket.exe
284 | paket-files/
285 |
286 | # FAKE - F# Make
287 | .fake/
288 |
289 | # JetBrains Rider
290 | .idea/
291 | *.sln.iml
292 |
293 | # CodeRush
294 | .cr/
295 |
296 | # Python Tools for Visual Studio (PTVS)
297 | __pycache__/
298 | *.pyc
299 |
300 | # Cake - Uncomment if you are using it
301 | # tools/**
302 | # !tools/packages.config
303 |
304 | # Tabs Studio
305 | *.tss
306 |
307 | # Telerik's JustMock configuration file
308 | *.jmconfig
309 |
310 | # BizTalk build output
311 | *.btp.cs
312 | *.btm.cs
313 | *.odx.cs
314 | *.xsd.cs
315 |
316 | # OpenCover UI analysis results
317 | OpenCover/
318 |
319 | # Azure Stream Analytics local run output
320 | ASALocalRun/
321 |
322 | # MSBuild Binary and Structured Log
323 | *.binlog
324 |
325 | # NVidia Nsight GPU debugger configuration file
326 | *.nvuser
327 |
328 | # MFractors (Xamarin productivity tool) working folder
329 | .mfractor/
330 |
--------------------------------------------------------------------------------
/Examples/Tetris.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text.RegularExpressions;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using ConsoleGameEngine;
6 | using System.Threading;
7 |
8 | namespace ConsoleGameEngineExamples {
9 | class Tetris : ConsoleGame {
10 |
11 | readonly Random rand = new Random();
12 | readonly string[] tetromino = new string[7];
13 |
14 | int[] playingField;
15 |
16 | static int fieldWidth = 14; static int fieldHeight = 24;
17 |
18 | int currentTetromino = 0;
19 | int rotation = 0;
20 | Point current;
21 |
22 | List lines = new List();
23 |
24 | int highscore = 0;
25 | int score = 0;
26 |
27 | bool gameover = false;
28 |
29 | private static void Main(string[] args) {
30 | new Tetris().Construct(fieldWidth + 2, fieldHeight + 4, 8, 8, FramerateMode.MaxFps);
31 | }
32 | public override void Create() {
33 | Engine.SetPalette(Palettes.Pico8);
34 | Engine.Borderless();
35 | Console.Title = "Tetris";
36 | TargetFramerate = 16;
37 |
38 | tetromino[0] = "..0...0...0...0.";
39 | tetromino[1] = "..1..11...1.....";
40 | tetromino[2] = ".....22..22.....";
41 | tetromino[3] = "..3..33..3......";
42 | tetromino[4] = ".4...44...4.....";
43 | tetromino[5] = ".5...5...55.....";
44 | tetromino[6] = "..6...6..66.....";
45 |
46 | Restart();
47 | }
48 |
49 | public override void Update() {
50 | if (!gameover) {
51 | // hanterar input
52 | if (Engine.GetKeyDown(ConsoleKey.RightArrow)) {
53 | current.X += DoesPieceFit(currentTetromino, rotation, current + new Point(1, 0)) ? 1 : 0;
54 | }
55 | if (Engine.GetKeyDown(ConsoleKey.LeftArrow)) {
56 | current.X -= DoesPieceFit(currentTetromino, rotation, current - new Point(1, 0)) ? 1 : 0;
57 | }
58 | if (Engine.GetKey(ConsoleKey.DownArrow)) {
59 | current.Y += DoesPieceFit(currentTetromino, rotation, current + new Point(0, 1)) ? 1 : 0;
60 | }
61 |
62 | if (Engine.GetKeyDown(ConsoleKey.UpArrow)) {
63 | rotation += DoesPieceFit(currentTetromino, rotation + 1, current) ? 1 : 0;
64 | }
65 |
66 | // gör endast denna uppdatering ibland (högre framerate på input)
67 | if (FrameCounter % 8 == 0) {
68 | // tvingar tetrominon neråt
69 | if (DoesPieceFit(currentTetromino, rotation, current + new Point(0, 1))) {
70 | current.Y += 1;
71 | } else {
72 | // placerar tetrominon på spelfältet
73 | for (int px = 0; px < 4; px++) {
74 | for (int py = 0; py < 4; py++) {
75 | if (tetromino[currentTetromino][Rotate(new Point(px, py), rotation)] != '.') {
76 | playingField[(current.Y + py) * fieldWidth + (current.X + px)] = currentTetromino + 1;
77 | }
78 | }
79 | }
80 |
81 | // kollar efter rader
82 | for (int py = 0; py < 4; py++) {
83 | if (current.Y + py < fieldHeight - 1) {
84 | bool bline = true;
85 | for (int px = 1; px < fieldWidth - 1; px++) bline &= (playingField[(current.Y + py) * fieldWidth + px]) != 0;
86 |
87 | if (bline) {
88 | // ta bort linje
89 | for (int px = 1; px < fieldWidth - 1; px++) {
90 | playingField[(current.Y + py) * fieldWidth + px] = 8; // 8 för animation :)
91 | }
92 |
93 | lines.Add(current.Y + py);
94 | }
95 | }
96 | }
97 |
98 | score += 25;
99 |
100 | // gravitation av mappen ifall man gör en rad
101 | if (lines.Any()) {
102 | for (int line = 0; line < lines.Count; line++) {
103 | for (int x = 1; x < fieldWidth - 1; x++) {
104 | // börja nerifrån
105 | for (int y = lines[line]; y > 0; y--) {
106 | if (y - 1 > 0) playingField[y * fieldWidth + x] = playingField[(y - 1) * fieldWidth + x];
107 | else playingField[y * fieldWidth + x] = 0;
108 | }
109 | }
110 |
111 | score += 100;
112 | }
113 | }
114 | lines.Clear();
115 |
116 | current.X = fieldWidth / 2 -2;
117 | current.Y = 0;
118 | rotation = 0;
119 | currentTetromino = rand.Next(0, tetromino.Length);
120 |
121 | // om tetrominon inte får plats direkt förlorar spelaren
122 | gameover = !DoesPieceFit(currentTetromino, rotation, current);
123 | }
124 | }
125 |
126 | } else {
127 | Engine.Fill(new Point(fieldWidth / 2 - 5, fieldHeight / 2 - 1), new Point(fieldWidth / 2 + 6, fieldHeight / 2 + 3), 0, ConsoleCharacter.Full);
128 | Engine.WriteText(new Point(fieldWidth / 2 - 4, fieldHeight/2), "Game Over!", 8);
129 | Engine.WriteText(new Point(fieldWidth / 2 - 4, fieldHeight / 2 + 1), "Highscore:", 7);
130 |
131 | if(highscore < score) {
132 | highscore = score;
133 | }
134 |
135 | Engine.WriteText(new Point(fieldWidth / 2 - 4, fieldHeight / 2 + 2), highscore.ToString(), 9);
136 |
137 | Engine.Frame(new Point(fieldWidth / 2 - 5, fieldHeight / 2 - 1), new Point(fieldWidth / 2 + 6, fieldHeight / 2 + 3), 7);
138 |
139 | Engine.DisplayBuffer();
140 |
141 | Thread.Sleep(4000);
142 | Restart();
143 | }
144 | }
145 |
146 | public override void Render() {
147 | Engine.ClearBuffer();
148 |
149 | // ritar banan
150 | for(int x = 0; x < fieldWidth; x++) {
151 | for(int y = 0; y < fieldHeight; y++) {
152 | if(playingField[(y) * fieldWidth + x] != 0) Engine.SetPixel(new Point(x+1, y+1), playingField[y * fieldWidth + x] + 7);
153 | }
154 | }
155 |
156 | // ritar nuvarande tetromino
157 | for(int px = 0; px < 4; px ++) {
158 | for(int py = 0; py < 4; py++) {
159 | if(tetromino[currentTetromino][Rotate(new Point(px, py), rotation)] != '.') {
160 | Engine.SetPixel(new Point(current.X + px+1, current.Y + py+1), GetTetrominoColor(currentTetromino) + 8);
161 | }
162 | }
163 | }
164 | Engine.Frame(new Point(1, 0), new Point(fieldWidth, fieldHeight), 7);
165 | Engine.WriteText(new Point(1, fieldHeight+1), "Score", 7);
166 | Engine.WriteText(new Point(1, fieldHeight+2), score.ToString("N0"), 9);
167 |
168 | Engine.DisplayBuffer();
169 | }
170 |
171 |
172 |
173 | int Rotate(Point p, int r) {
174 | int i = 0;
175 | switch(r % 4) {
176 | case 0: // 0 grader
177 | i = p.Y * 4 + p.X;
178 | break;
179 | case 1: // 90 grader
180 | i = 12 + p.Y - (p.X * 4);
181 | break;
182 | case 2: // 180 grader
183 | i = 15 - (p.Y * 4) - p.X;
184 | break;
185 | case 3: // 270 grader
186 | i = 3 - p.Y + (p.X * 4);
187 | break;
188 | }
189 | return i;
190 | }
191 |
192 | bool DoesPieceFit(int selTetromino, int rot, Point pos) {
193 | for(int px = 0; px < 4; px++) {
194 | for(int py = 0; py < 4; py++) {
195 | int pieceIndex = Rotate(new Point(px, py), rot);
196 |
197 | int fieldIndex = (pos.Y + py) * fieldWidth + (pos.X + px);
198 |
199 | if( pos.X + px >= 0 && pos.X + px < fieldWidth &&
200 | pos.Y + py >= 0 && pos.Y + py < fieldHeight) {
201 | if (tetromino[selTetromino][pieceIndex] != '.' && playingField[fieldIndex] != 0) return false;
202 | }
203 | }
204 | }
205 |
206 | return true;
207 | }
208 |
209 | int GetTetrominoColor(int t) {
210 | Match m = Regex.Match(tetromino[t], @"\d");
211 | return Convert.ToInt32(m.Value[0]);
212 | }
213 |
214 | void Restart() {
215 | score = 0;
216 | gameover = false;
217 |
218 | playingField = new int[fieldWidth * fieldHeight];
219 | for (int x = 0; x < fieldWidth; x++) // kant för banan
220 | for (int y = 0; y < fieldHeight; y++)
221 | playingField[y * fieldWidth + x] = (x == 0 || x == fieldWidth - 1 || y == fieldHeight - 1) ? -1 : 0; // väggar
222 |
223 | current = new Point(fieldWidth / 2 - 2, 0);
224 | currentTetromino = rand.Next(0, tetromino.Length);
225 | }
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/Examples/Example_3D.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | using ConsoleGameEngine;
9 |
10 | namespace ConsoleGameEngineExamples {
11 | class Example3D : ConsoleGame {
12 | static void Main(string[] args) {
13 | new Example3D().Construct(256, 256, 2, 2, FramerateMode.Unlimited);
14 | }
15 | readonly Random rand = new Random();
16 |
17 | Mesh mesh;
18 | Matrix projectionMatrix;
19 | Vec3D modelPosition = new Vec3D(0, 0, 4);
20 |
21 | Vec3D camera = new Vec3D(0, 0, 0);
22 | Vec3D lookDirection = new Vec3D(0, 0, 0);
23 | Vec3D lightDirection = new Vec3D(0.0f, 0.0f, -1.0f);
24 |
25 | List trianglesToRaster = new List();
26 |
27 | Point lastMousePos = Point.Zero;
28 |
29 |
30 | private bool drawWireframe = false;
31 | private bool drawSolid = true;
32 |
33 | private float yRot = 0;
34 | private float xRot = 0;
35 |
36 | private int consoleHeight;
37 | private int consoleWidth;
38 |
39 | public override void Create() {
40 | Engine.SetPalette(Palettes.Pico8);
41 | Engine.SetBackground(0);
42 | Engine.Borderless();
43 |
44 | Console.Title = "3D Demo";
45 |
46 | mesh.LoadFromObj("monkey.obj");
47 |
48 | consoleWidth = Engine.WindowSize.X;
49 | consoleHeight = Engine.WindowSize.Y;
50 |
51 | // projektions matris
52 | float near = 0.1f;
53 | float far = 1000.0f;
54 | float fov = 90.0f;
55 | float aspectRatio = (float)consoleHeight / (float)consoleWidth;
56 | projectionMatrix = Matrix.ProjectionMatrix(fov, aspectRatio, near, far);
57 |
58 | // normaliserar ljusriktningen
59 | lightDirection.Normalize();
60 | }
61 |
62 | public override void Update() {
63 | if (Engine.GetKeyDown(ConsoleKey.Y)) {
64 | drawWireframe = !drawWireframe;
65 | }
66 | if (Engine.GetKeyDown(ConsoleKey.H)) {
67 | drawSolid = !drawSolid;
68 | }
69 |
70 | if(Engine.GetMouseLeft()) {
71 | Point delta = Engine.GetMousePos() - lastMousePos;
72 | yRot += delta.X / 80f;
73 | xRot += delta.Y / 80f;
74 | }
75 |
76 | lastMousePos = Engine.GetMousePos();
77 |
78 | // matriserar
79 | Matrix transformMat, rotationMat;
80 | rotationMat = Matrix.RotationMatrixY(yRot);
81 | rotationMat *= Matrix.RotationMatrixX(xRot);
82 | transformMat = Matrix.Translation(modelPosition);
83 |
84 | // generera trianglar
85 | for (int i = 0; i < mesh.Triangles.Length; i++) {
86 | Triangle vertex = mesh.Triangles[i];
87 | Triangle rotated = vertex.MatMul(rotationMat);
88 |
89 | Triangle transformed = rotated.MatMul(transformMat);
90 |
91 | // beräknar kryssprodukt av line1 och line2 för att hitta normal.
92 | Vec3D normal, line1, line2;
93 | line1 = transformed.p[1] - transformed.p[0];
94 | line2 = transformed.p[2] - transformed.p[0];
95 |
96 | normal = Vec3D.Cross(line1, line2);
97 | normal.Normalize();
98 |
99 | // testar ifall vi kan se ytan
100 | if (Vec3D.Dot(normal, transformed.p[0] - camera) < 0.0f) {
101 | // beräknar ljus
102 | float l = Vec3D.Dot(lightDirection, normal);
103 | ConsoleCharacter character = ConsoleCharacter.Light;
104 | if (l > 0.4) character = ConsoleCharacter.Medium;
105 | if (l > 0.7) character = ConsoleCharacter.Dark;
106 | if (l > 1) character = ConsoleCharacter.Full;
107 |
108 | // projekterar från 3D -> 2D
109 | Triangle projected = new Triangle(null);
110 | projected = transformed.MatMul(projectionMatrix);
111 |
112 | // transformerar och skalar projektionen
113 | Vec3D offsetView = new Vec3D(1, 1, 0);
114 | projected.p[0] += offsetView;
115 | projected.p[1] += offsetView;
116 | projected.p[2] += offsetView;
117 |
118 | projected.p[0].x *= 0.5f * consoleWidth; projected.p[0].y *= 0.5f * consoleHeight;
119 | projected.p[1].x *= 0.5f * consoleWidth; projected.p[1].y *= 0.5f * consoleHeight;
120 | projected.p[2].x *= 0.5f * consoleWidth; projected.p[2].y *= 0.5f * consoleHeight;
121 |
122 | projected.c = character;
123 | trianglesToRaster.Add(projected);
124 | }
125 | }
126 |
127 | // sortera
128 | trianglesToRaster.Sort((t1, t2) => ((t2.p[0].z + t2.p[1].z + t2.p[2].z).CompareTo((t1.p[0].z + t1.p[1].z + t1.p[2].z))));
129 | }
130 |
131 | public override void Render() {
132 | Engine.ClearBuffer();
133 |
134 |
135 | foreach(Triangle t in trianglesToRaster) {
136 | Point a = new Point((int)t.p[0].x, (int)t.p[0].y);
137 | Point b = new Point((int)t.p[1].x, (int)t.p[1].y);
138 | Point c = new Point((int)t.p[2].x, (int)t.p[2].y);
139 | if(drawSolid) Engine.FillTriangle(b, a, c, 9, t.c);
140 | if(drawWireframe) Engine.Triangle(b, a, c, 7, t.c);
141 | }
142 |
143 | trianglesToRaster.Clear();
144 |
145 | Engine.DisplayBuffer();
146 | }
147 | }
148 |
149 | public struct Vec3D {
150 | public float x, y, z, w;
151 |
152 | public Vec3D(float a, float b, float c) {
153 | x = a;
154 | y = b;
155 | z = c;
156 | w = 0;
157 | }
158 |
159 | public void Normalize() {
160 | float l = (float)Math.Sqrt(x * x + y * y + z * z);
161 | x /= l; y /= l; z /= l;
162 | }
163 |
164 | // skalärprodukt https://sv.wikipedia.org/wiki/Skalärprodukt
165 | public static float Dot(Vec3D a, Vec3D b) {
166 | return a.x * b.x + a.y * b.y + a.z * b.z;
167 | }
168 |
169 | public static Vec3D Cross(Vec3D a, Vec3D b) {
170 | Vec3D n = new Vec3D {
171 | x = a.y * b.z - a.z * b.y,
172 | y = a.z * b.x - a.x * b.z,
173 | z = a.x * b.y - a.y * b.x
174 | };
175 |
176 | return n;
177 | }
178 |
179 | public static Vec3D operator +(Vec3D a, Vec3D b) {
180 | return new Vec3D(a.x + b.x, a.y + b.y, a.z + b.z);
181 | }
182 | public static Vec3D operator +(Vec3D a, float b) {
183 | return new Vec3D(a.x + b, a.y + b, a.z + b);
184 | }
185 |
186 | public static Vec3D operator -(Vec3D a, Vec3D b) {
187 | return new Vec3D(a.x - b.x, a.y - b.y, a.z - b.z);
188 | }
189 |
190 | public static Vec3D operator *(Vec3D a, float b) {
191 | return new Vec3D(a.x * b, a.y * b, a.z * b);
192 | }
193 |
194 | }
195 | public struct Triangle {
196 | public Vec3D[] p;
197 |
198 | public int color;
199 | public ConsoleCharacter c;
200 |
201 | public Triangle(Vec3D pa, Vec3D pb, Vec3D pc) {
202 | p = new Vec3D[3];
203 | p[0] = pa;
204 | p[1] = pb;
205 | p[2] = pc;
206 |
207 | color = 0;
208 | c = ConsoleCharacter.Null;
209 | }
210 |
211 | public Triangle(object n) {
212 | p = new Vec3D[3];
213 | color = 0;
214 | c = ConsoleCharacter.Null;
215 | }
216 |
217 | public void Translate(Vec3D delta) {
218 | p[0] += delta;
219 | p[1] += delta;
220 | p[2] += delta;
221 | }
222 |
223 | public Triangle MatMul(Matrix m) {
224 | Triangle t = new Triangle(null);
225 | t.p[0] = Matrix.MultiplyVector(p[0], m);
226 | t.p[1] = Matrix.MultiplyVector(p[1], m);
227 | t.p[2] = Matrix.MultiplyVector(p[2], m);
228 |
229 | return t;
230 | }
231 | }
232 |
233 | public struct Mesh {
234 | public Vec3D[] Vertices { get; set; }
235 | public Triangle[] Triangles { get; set; }
236 |
237 | public bool LoadFromObj(string filename) {
238 | StreamReader s = new StreamReader(filename);
239 |
240 | List verts = new List();
241 | List tris = new List();
242 |
243 | while(!s.EndOfStream) {
244 | string line = s.ReadLine();
245 |
246 | if(line[0] == 'v') {
247 | Vec3D v = new Vec3D();
248 | string[] str = line.Replace('.', ',').Split();
249 | v.x = float.Parse(str[1]);
250 | v.y = float.Parse(str[2]);
251 | v.z = float.Parse(str[3]);
252 | verts.Add(v);
253 | }
254 | if(line[0] == 'f') {
255 | Triangle t = new Triangle();
256 | string[] str = line.Split();
257 | t.p = new Vec3D[3];
258 | t.color = 6;
259 | t.p[0] = verts[Convert.ToInt32(str[1]) - 1];
260 | t.p[1] = verts[Convert.ToInt32(str[2]) - 1];
261 | t.p[2] = verts[Convert.ToInt32(str[3]) - 1];
262 | tris.Add(t);
263 | }
264 | }
265 |
266 | Vertices = verts.ToArray();
267 | Triangles = tris.ToArray();
268 |
269 | return true;
270 | }
271 | }
272 |
273 | public class Matrix {
274 | public float[,] m = new float[4, 4];
275 |
276 | public static Matrix operator *(Matrix a, Matrix b) {
277 | Matrix mat = new Matrix();
278 | for(int c = 0; c < 4; c++) {
279 | for(int r = 0; r < 4; r++) {
280 | mat.m[r, c] = a.m[r, 0] * b.m[0, c] + a.m[r, 1] * b.m[1, c] + a.m[r, 2] * b.m[2, c] + a.m[r, 3] * b.m[3, c];
281 | }
282 | }
283 | return mat;
284 | }
285 |
286 | public static Vec3D MultiplyVector(Vec3D i, Matrix m) {
287 | Vec3D v = new Vec3D();
288 | float w = 0;
289 | v.x = i.x * m.m[0, 0] + i.y * m.m[1, 0] + i.z * m.m[2, 0] + m.m[3, 0];
290 | v.y = i.x * m.m[0, 1] + i.y * m.m[1, 1] + i.z * m.m[2, 1] + m.m[3, 1];
291 | v.z = i.x * m.m[0, 2] + i.y * m.m[1, 2] + i.z * m.m[2, 2] + m.m[3, 2];
292 | w = i.x * m.m[0, 3] + i.y * m.m[1, 3] + i.z * m.m[2, 3] + m.m[3, 3];
293 |
294 | if (w != 0.0f) {
295 | v.x /= w; v.y /= w; v.z /= w;
296 | }
297 |
298 | return v;
299 | }
300 |
301 | public static Matrix Translation(Vec3D t) {
302 | Matrix mat = new Matrix();
303 | mat.m[0, 0] = 1.0f;
304 | mat.m[1, 1] = 1.0f;
305 | mat.m[2, 2] = 1.0f;
306 | mat.m[3, 3] = 1.0f;
307 | mat.m[3, 0] = t.x;
308 | mat.m[3, 1] = t.y;
309 | mat.m[3, 2] = t.z;
310 | return mat;
311 | }
312 |
313 | public static Matrix Identity() {
314 | Matrix mat = new Matrix();
315 | mat.m[0, 0] = 1.0f; mat.m[0, 1] = 1.0f; mat.m[0, 2] = 1.0f; mat.m[0, 3] = 1.0f;
316 | mat.m[1, 0] = 1.0f; mat.m[1, 1] = 1.0f; mat.m[1, 2] = 1.0f; mat.m[1, 3] = 1.0f;
317 | mat.m[2, 0] = 1.0f; mat.m[2, 1] = 1.0f; mat.m[2, 2] = 1.0f; mat.m[2, 3] = 1.0f;
318 | mat.m[3, 0] = 1.0f; mat.m[3, 1] = 1.0f; mat.m[3, 2] = 1.0f; mat.m[3, 3] = 1.0f;
319 | return mat;
320 | }
321 |
322 | public static Matrix PointAtMatrix(Vec3D pos, Vec3D target, Vec3D up) {
323 | // ny frammåt
324 | Vec3D newForward = target - pos;
325 | newForward.Normalize();
326 |
327 | // ny uppåt
328 | Vec3D a = newForward * Vec3D.Dot(up, newForward);
329 | Vec3D newUp = up - a;
330 | newUp.Normalize();
331 |
332 | Vec3D newRight = Vec3D.Cross(newUp, newForward);
333 | Matrix mat = new Matrix();
334 | mat.m[0, 0] = newRight.x; mat.m[0, 1] = newRight.y; mat.m[0, 2] = newRight.z; mat.m[0, 3] = 0.0f;
335 | mat.m[1, 0] = newUp.x; mat.m[1, 1] = newUp.y; mat.m[1, 2] = newUp.z; mat.m[1, 3] = 0.0f;
336 | mat.m[2, 0] = newForward.x; mat.m[2, 1] = newForward.y; mat.m[2, 2] = newForward.z; mat.m[2, 3] = 0.0f;
337 | mat.m[3, 0] = pos.x; mat.m[2, 1] = pos.y; mat.m[2, 2] = pos.z; mat.m[2, 3] = 1.0f;
338 | return mat;
339 | }
340 | public static Matrix ProjectionMatrix(float fov, float aspect, float near, float far) {
341 | Matrix mat = new Matrix();
342 | float fovRad = 1.0f / (float)Math.Tan(fov * 0.5f / (180 / (float)Math.PI));
343 | mat.m[0, 0] = aspect * fovRad;
344 | mat.m[1, 1] = fovRad;
345 | mat.m[2, 2] = far / (far - near);
346 | mat.m[3, 2] = (-far * near) / (far - near);
347 | mat.m[2, 3] = 1.0f;
348 | mat.m[3, 3] = 0.0f;
349 |
350 | return mat;
351 | }
352 |
353 | // Endast för rotation/translations matriser
354 | public static Matrix QuickInverse(Matrix m) {
355 | Matrix matrix = new Matrix();
356 | matrix.m[0, 0] = m.m[0, 0]; matrix.m[0, 1] = m.m[1, 0]; matrix.m[0, 2] = m.m[2, 0]; matrix.m[0, 3] = 0.0f;
357 | matrix.m[1, 0] = m.m[0, 1]; matrix.m[1, 1] = m.m[1, 1]; matrix.m[1, 2] = m.m[2, 1]; matrix.m[1, 3] = 0.0f;
358 | matrix.m[2, 0] = m.m[0, 2]; matrix.m[2, 1] = m.m[1, 2]; matrix.m[2, 2] = m.m[2, 2]; matrix.m[2, 3] = 0.0f;
359 | matrix.m[3, 0] = -(m.m[3, 0] * matrix.m[0, 0] + m.m[3, 1] * matrix.m[1, 0] + m.m[3, 2] * matrix.m[2, 0]);
360 | matrix.m[3, 1] = -(m.m[3, 0] * matrix.m[0, 1] + m.m[3, 1] * matrix.m[1, 1] + m.m[3, 2] * matrix.m[2, 1]);
361 | matrix.m[3, 2] = -(m.m[3, 0] * matrix.m[0, 2] + m.m[3, 1] * matrix.m[1, 2] + m.m[3, 2] * matrix.m[2, 2]);
362 | matrix.m[3, 3] = 1.0f;
363 | return matrix;
364 | }
365 |
366 | public static Matrix RotationMatrixX(float fAngleRad) {
367 | Matrix mat = new Matrix();
368 | mat.m[0, 0] = 1.0f;
369 | mat.m[1, 1] = (float)Math.Cos(fAngleRad);
370 | mat.m[1, 2] = (float)Math.Sin(fAngleRad);
371 | mat.m[2, 1] = (float)-Math.Sin(fAngleRad);
372 | mat.m[2, 2] = (float)Math.Cos(fAngleRad);
373 | mat.m[3, 3] = 1.0f;
374 | return mat;
375 | }
376 |
377 | public static Matrix RotationMatrixY(float fAngleRad) {
378 | Matrix mat = new Matrix();
379 | mat.m[0, 0] = (float)Math.Cos(fAngleRad);
380 | mat.m[0, 2] = (float)Math.Sin(fAngleRad);
381 | mat.m[2, 0] = (float)-Math.Sin(fAngleRad);
382 | mat.m[1, 1] = 1.0f;
383 | mat.m[2, 2] = (float)Math.Cos(fAngleRad);
384 | mat.m[3, 3] = 1.0f;
385 | return mat;
386 | }
387 |
388 | public static Matrix RotationMatrixZ(float fAngleRad) {
389 | Matrix mat = new Matrix();
390 | mat.m[0, 0] = (float)Math.Cos(fAngleRad);
391 | mat.m[0, 1] = (float)Math.Sin(fAngleRad);
392 | mat.m[1, 0] = (float)-Math.Sin(fAngleRad);
393 | mat.m[1, 1] = (float)Math.Cos(fAngleRad);
394 | mat.m[2, 2] = 1.0f;
395 | mat.m[3, 3] = 1.0f;
396 | return mat;
397 | }
398 | }
399 | }
400 |
--------------------------------------------------------------------------------
/Source/ConsoleEngine.cs:
--------------------------------------------------------------------------------
1 | namespace ConsoleGameEngine {
2 |
3 | using System;
4 | using System.Text;
5 |
6 | ///
7 | /// Class for Drawing to a console window.
8 | ///
9 | public class ConsoleEngine {
10 |
11 | // pekare för ConsoleHelper-anrop
12 | private readonly IntPtr stdInputHandle = NativeMethods.GetStdHandle(-10);
13 | private readonly IntPtr stdOutputHandle = NativeMethods.GetStdHandle(-11);
14 | private readonly IntPtr stdErrorHandle = NativeMethods.GetStdHandle(-12);
15 | private readonly IntPtr consoleHandle = NativeMethods.GetConsoleWindow();
16 |
17 | /// The active color palette.
18 | public Color[] Palette { get; private set; }
19 |
20 | /// The current size of the font.
21 | public Point FontSize { get; private set; }
22 |
23 | /// The dimensions of the window in characters.
24 | public Point WindowSize { get; private set; }
25 |
26 | private char[,] CharBuffer { get; set; }
27 | private int[,] ColorBuffer { get; set; }
28 | private int Background { get; set; }
29 | private ConsoleBuffer ConsoleBuffer { get; set; }
30 | private bool IsBorderless { get; set; }
31 |
32 | /// Creates a new ConsoleEngine.
33 | /// Target window width.
34 | /// Target window height.
35 | /// Target font width.
36 | /// Target font height.
37 | public ConsoleEngine(int width, int height, int fontW, int fontH) {
38 | if (width < 1 || height < 1) throw new ArgumentOutOfRangeException();
39 | if (fontW < 1 || fontH < 1) throw new ArgumentOutOfRangeException();
40 |
41 | Console.Title = "Untitled console application";
42 | Console.CursorVisible = false;
43 |
44 | // sätter fönstret och bufferns storlek
45 | // buffern måste sättas efter fönsret, eftersom den aldrig får vara mindre än skärmen
46 | Console.SetWindowSize(width, height);
47 | Console.SetBufferSize(width, height);
48 |
49 | ConsoleBuffer = new ConsoleBuffer(width, height);
50 |
51 | WindowSize = new Point(width, height);
52 | FontSize = new Point(fontW, fontH);
53 |
54 | CharBuffer = new char[width, height];
55 | ColorBuffer = new int[width, height];
56 |
57 | SetBackground(0);
58 | SetPalette(Palettes.Default);
59 |
60 | // Stänger av alla standard ConsoleInput metoder (Quick-edit etc)
61 | NativeMethods.SetConsoleMode(stdInputHandle, 0x0080);
62 |
63 | // Sätter fontstorlek och tvingar Raster (Terminal) / Consolas
64 | // Detta måste göras efter SetBufferSize, annars ger den en IOException
65 | ConsoleFont.SetFont(stdOutputHandle, (short)fontW, (short)fontH);
66 | }
67 |
68 | // Rita
69 | private void SetPixel(Point selectedPoint, int color, char character) {
70 | if (selectedPoint.X >= CharBuffer.GetLength(0) || selectedPoint.Y >= CharBuffer.GetLength(1)
71 | || selectedPoint.X < 0 || selectedPoint.Y < 0) return;
72 |
73 | CharBuffer[selectedPoint.X, selectedPoint.Y] = character;
74 | ColorBuffer[selectedPoint.X, selectedPoint.Y] = color;
75 | }
76 |
77 | /// Sets the console's color palette
78 | ///
79 | ///
80 | public void SetPalette(Color[] colors) {
81 | if (colors.Length > 16) throw new ArgumentException("Windows command prompt only support 16 colors.");
82 | Palette = colors ?? throw new ArgumentNullException();
83 |
84 | for (int i = 0; i < colors.Length; i++) {
85 | ConsolePalette.SetColor(i, colors[i]);
86 | }
87 | }
88 |
89 | /// Sets the console's background color to one in the active palette.
90 | /// Index of background color in palette.
91 | public void SetBackground(int color = 0) {
92 | if (color > 16 || color < 0) throw new IndexOutOfRangeException();
93 | Background = color;
94 | }
95 |
96 | /// Clears the screenbuffer.
97 | public void ClearBuffer() {
98 | Array.Clear(CharBuffer, 0, CharBuffer.Length);
99 | Array.Clear(ColorBuffer, 0, ColorBuffer.Length);
100 | }
101 |
102 | /// Blits the screenbuffer to the Console window.
103 | public void DisplayBuffer() {
104 | ConsoleBuffer.SetBuffer(CharBuffer, ColorBuffer, Background);
105 | ConsoleBuffer.Blit();
106 | }
107 |
108 | /// Sets the window to borderless mode.
109 | public void Borderless() {
110 | IsBorderless = true;
111 |
112 | int GWL_STYLE = -16; // hex konstant för stil-förändring
113 | int WS_BORDERLESS = 0x00080000; // helt borderless
114 |
115 | NativeMethods.Rect rect = new NativeMethods.Rect();
116 | NativeMethods.Rect desktopRect = new NativeMethods.Rect();
117 |
118 | NativeMethods.GetWindowRect(consoleHandle, ref rect);
119 | IntPtr desktopHandle = NativeMethods.GetDesktopWindow();
120 | NativeMethods.MapWindowPoints(desktopHandle, consoleHandle, ref rect, 2);
121 | NativeMethods.GetWindowRect(desktopHandle, ref desktopRect);
122 |
123 | Point wPos = new Point(
124 | (desktopRect.Right / 2) - ((WindowSize.X * FontSize.X) / 2),
125 | (desktopRect.Bottom / 2) - ((WindowSize.Y * FontSize.Y) / 2));
126 |
127 | NativeMethods.SetWindowLong(consoleHandle, GWL_STYLE, WS_BORDERLESS);
128 | NativeMethods.SetWindowPos(consoleHandle, -2, wPos.X, wPos.Y, rect.Right - 8, rect.Bottom - 8, 0x0040);
129 |
130 | NativeMethods.DrawMenuBar(consoleHandle);
131 | }
132 |
133 | #region Primitives
134 |
135 | /// Draws a single pixel to the screenbuffer.
136 | /// The Point that should be drawn to.
137 | /// The color index.
138 | /// The character that should be drawn with.
139 | public void SetPixel(Point v, int color, ConsoleCharacter c = ConsoleCharacter.Full) {
140 | SetPixel(v, color, (char)c);
141 | }
142 |
143 | /// Draws a frame using boxdrawing symbols.
144 | /// Top Left corner of box.
145 | /// Bottom Right corner of box.
146 | /// The specified color index.
147 | public void Frame(Point pos, Point end, int color) {
148 | for (int i = 1; i < end.X - pos.X; i++) {
149 | SetPixel(new Point(pos.X + i, pos.Y), color, ConsoleCharacter.BoxDrawingL_H);
150 | SetPixel(new Point(pos.X + i, end.Y), color, ConsoleCharacter.BoxDrawingL_H);
151 | }
152 |
153 | for (int i = 1; i < end.Y - pos.Y; i++) {
154 | SetPixel(new Point(pos.X, pos.Y + i), color, ConsoleCharacter.BoxDrawingL_V);
155 | SetPixel(new Point(end.X, pos.Y + i), color, ConsoleCharacter.BoxDrawingL_V);
156 | }
157 |
158 | SetPixel(new Point(pos.X, pos.Y), color, ConsoleCharacter.BoxDrawingL_DR);
159 | SetPixel(new Point(end.X, pos.Y), color, ConsoleCharacter.BoxDrawingL_DL);
160 | SetPixel(new Point(pos.X, end.Y), color, ConsoleCharacter.BoxDrawingL_UR);
161 | SetPixel(new Point(end.X, end.Y), color, ConsoleCharacter.BoxDrawingL_UL);
162 | }
163 |
164 | /// Writes plain text to the buffer.
165 | /// The position to write to.
166 | /// String to write.
167 | /// Specified color index to write with.
168 | public void WriteText(Point pos, string text, int color) {
169 | for (int i = 0; i < text.Length; i++) {
170 | SetPixel(new Point(pos.X + i, pos.Y), color, text[i]);
171 | }
172 | }
173 |
174 | /// Writes text to the buffer in a FIGlet font.
175 | /// The Top left corner of the text.
176 | /// String to write.
177 | /// FIGLET font to write with.
178 | /// Specified color index to write with.
179 | ///
180 | public void WriteFiglet(Point pos, string text, FigletFont font, int color) {
181 | if (text == null) throw new ArgumentNullException(nameof(text));
182 | if (Encoding.UTF8.GetByteCount(text) != text.Length) throw new ArgumentException("String contains non-ascii characters");
183 |
184 | int sWidth = FigletFont.GetStringWidth(font, text);
185 |
186 | for (int line = 1; line <= font.Height; line++) {
187 | int runningWidthTotal = 0;
188 |
189 | for (int c = 0; c < text.Length; c++) {
190 | char character = text[c];
191 | string fragment = FigletFont.GetCharacter(font, character, line);
192 | for (int f = 0; f < fragment.Length; f++) {
193 | if (fragment[f] != ' ') {
194 | SetPixel(new Point(pos.X + runningWidthTotal + f, pos.Y + line - 1), color, fragment[f]);
195 | }
196 | }
197 | runningWidthTotal += fragment.Length;
198 | }
199 | }
200 | }
201 |
202 | /// Draws an Arc.
203 | /// Center of Arc.
204 | /// Radius of Arc.
205 | /// Specified color index.
206 | /// angle in degrees, 360 if not specified.
207 | /// Character to use.
208 | public void Arc(Point pos, int radius, int col, int arc = 360, ConsoleCharacter c = ConsoleCharacter.Full) {
209 | for (int a = 0; a < arc; a++) {
210 | int x = (int)(radius * Math.Cos((float)a / 57.29577f));
211 | int y = (int)(radius * Math.Sin((float)a / 57.29577f));
212 |
213 | Point v = new Point(pos.X + x, pos.Y + y);
214 | SetPixel(v, col, ConsoleCharacter.Full);
215 | }
216 | }
217 |
218 | /// Draws a filled Arc.
219 | /// Center of Arc.
220 | /// Radius of Arc.
221 | /// Start angle in degrees.
222 | /// End angle in degrees.
223 | /// Specified color index.
224 | /// Character to use.
225 | public void SemiCircle(Point pos, int radius, int start, int arc, int col, ConsoleCharacter c = ConsoleCharacter.Full) {
226 | for (int a = start; a > -arc + start; a--) {
227 | for (int r = 0; r < radius + 1; r++) {
228 | int x = (int)(r * Math.Cos((float)a / 57.29577f));
229 | int y = (int)(r * Math.Sin((float)a / 57.29577f));
230 |
231 | Point v = new Point(pos.X + x, pos.Y + y);
232 | SetPixel(v, col, c);
233 | }
234 | }
235 | }
236 |
237 | // Bresenhams Line Algorithm
238 | // https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
239 | /// Draws a line from start to end. (Bresenhams Line)
240 | /// Point to draw line from.
241 | /// Point to end line at.
242 | /// Color to draw with.
243 | /// Character to use.
244 | public void Line(Point start, Point end, int col, ConsoleCharacter c = ConsoleCharacter.Full) {
245 | Point delta = end - start;
246 | Point da = Point.Zero, db = Point.Zero;
247 | if (delta.X < 0) da.X = -1; else if (delta.X > 0) da.X = 1;
248 | if (delta.Y < 0) da.Y = -1; else if (delta.Y > 0) da.Y = 1;
249 | if (delta.X < 0) db.X = -1; else if (delta.X > 0) db.X = 1;
250 | int longest = Math.Abs(delta.X);
251 | int shortest = Math.Abs(delta.Y);
252 |
253 | if (!(longest > shortest)) {
254 | longest = Math.Abs(delta.Y);
255 | shortest = Math.Abs(delta.X);
256 | if (delta.Y < 0) db.Y = -1; else if (delta.Y > 0) db.Y = 1;
257 | db.X = 0;
258 | }
259 |
260 | int numerator = longest >> 1;
261 | Point p = new Point(start.X, start.Y);
262 | for (int i = 0; i <= longest; i++) {
263 | SetPixel(p, col, c);
264 | numerator += shortest;
265 | if (!(numerator < longest)) {
266 | numerator -= longest;
267 | p += da;
268 | } else {
269 | p += db;
270 | }
271 | }
272 | }
273 |
274 | /// Draws a Rectangle.
275 | /// Top Left corner of rectangle.
276 | /// Bottom Right corner of rectangle.
277 | /// Color to draw with.
278 | /// Character to use.
279 | public void Rectangle(Point pos, Point end, int col, ConsoleCharacter c = ConsoleCharacter.Full) {
280 | for (int i = 0; i < end.X - pos.X; i++) {
281 | SetPixel(new Point(pos.X + i, pos.Y), col, c);
282 | SetPixel(new Point(pos.X + i, end.Y), col, c);
283 | }
284 |
285 | for (int i = 0; i < end.Y - pos.Y + 1; i++) {
286 | SetPixel(new Point(pos.X, pos.Y + i), col, c);
287 | SetPixel(new Point(end.X, pos.Y + i), col, c);
288 | }
289 | }
290 |
291 | /// Draws a Rectangle and fills it.
292 | /// Top Left corner of rectangle.
293 | /// Bottom Right corner of rectangle.
294 | /// Color to draw with.
295 | /// Character to use.
296 | public void Fill(Point a, Point b, int col, ConsoleCharacter c = ConsoleCharacter.Full) {
297 | for (int y = a.Y; y < b.Y; y++) {
298 | for (int x = a.X; x < b.X; x++) {
299 | SetPixel(new Point(x, y), col, c);
300 | }
301 | }
302 | }
303 |
304 | /// Draws a grid.
305 | /// Top Left corner of grid.
306 | /// Bottom Right corner of grid.
307 | /// the spacing until next line
308 | /// Color to draw with.
309 | /// Character to use.
310 | public void Grid(Point a, Point b, int spacing, int col, ConsoleCharacter c = ConsoleCharacter.Full) {
311 | for (int y = a.Y; y < b.Y / spacing; y++) {
312 | Line(new Point(a.X, y * spacing), new Point(b.X, y * spacing), col, c);
313 | }
314 | for (int x = a.X; x < b.X / spacing; x++) {
315 | Line(new Point(x * spacing, a.Y), new Point(x * spacing, b.Y), col, c);
316 | }
317 | }
318 |
319 | /// Draws a Triangle.
320 | /// Point A.
321 | /// Point B.
322 | /// Point C.
323 | /// Color to draw with.
324 | /// Character to use.
325 | public void Triangle(Point a, Point b, Point c, int col, ConsoleCharacter character = ConsoleCharacter.Full) {
326 | Line(a, b, col, character);
327 | Line(b, c, col, character);
328 | Line(c, a, col, character);
329 | }
330 |
331 | // Bresenhams Triangle Algorithm
332 |
333 | /// Draws a Triangle and fills it.
334 | /// Point A.
335 | /// Point B.
336 | /// Point C.
337 | /// Color to draw with.
338 | /// Character to use.
339 | public void FillTriangle(Point a, Point b, Point c, int col, ConsoleCharacter character = ConsoleCharacter.Full) {
340 | Point min = new Point(Math.Min(Math.Min(a.X, b.X), c.X), Math.Min(Math.Min(a.Y, b.Y), c.Y));
341 | Point max = new Point(Math.Max(Math.Max(a.X, b.X), c.X), Math.Max(Math.Max(a.Y, b.Y), c.Y));
342 |
343 | Point p = new Point();
344 | for (p.Y = min.Y; p.Y < max.Y; p.Y++) {
345 | for (p.X = min.X; p.X < max.X; p.X++) {
346 | int w0 = Orient(b, c, p);
347 | int w1 = Orient(c, a, p);
348 | int w2 = Orient(a, b, p);
349 |
350 | if (w0 >= 0 && w1 >= 0 && w2 >= 0) SetPixel(p, col, character);
351 | }
352 | }
353 | }
354 |
355 | private int Orient(Point a, Point b, Point c) {
356 | return ((b.X - a.X) * (c.Y - a.Y)) - ((b.Y - a.Y) * (c.X - a.X));
357 | }
358 |
359 | #endregion Primitives
360 |
361 | // Input
362 |
363 | /// Checks if specified key is pressed.
364 | /// The key to check.
365 | /// True if key is pressed
366 | public bool GetKey(ConsoleKey key) {
367 | short s = NativeMethods.GetAsyncKeyState((int)key);
368 | return (s & 0x8000) > 0;
369 | }
370 |
371 | /// Checks if specified key is pressed down.
372 | /// The key to check.
373 | /// True if key is down
374 | public bool GetKeyDown(ConsoleKey key) {
375 | int s = Convert.ToInt32(NativeMethods.GetAsyncKeyState((int)key));
376 | return (s == -32767);
377 | }
378 |
379 | /// Checks if left mouse button is pressed down.
380 | /// True if left mouse button is down
381 | public bool GetMouseLeft() {
382 | short s = NativeMethods.GetAsyncKeyState(0x01);
383 | return (s & 0x8000) > 0;
384 | }
385 |
386 | /// Gets the mouse position.
387 | /// The mouse's position in character-space.
388 | ///
389 | public Point GetMousePos() {
390 | NativeMethods.Rect r = new NativeMethods.Rect();
391 | NativeMethods.GetWindowRect(consoleHandle, ref r);
392 |
393 | if (NativeMethods.GetCursorPos(out NativeMethods.POINT p)) {
394 | Point point = new Point();
395 | if (!IsBorderless) {
396 | p.Y -= 29;
397 | point = new Point(
398 | (int)Math.Floor(((p.X - r.Left) / (float)FontSize.X) - 0.5f),
399 | (int)Math.Floor(((p.Y - r.Top) / (float)FontSize.Y))
400 | );
401 | } else {
402 | point = new Point(
403 | (int)Math.Floor(((p.X - r.Left) / (float)FontSize.X)),
404 | (int)Math.Floor(((p.Y - r.Top) / (float)FontSize.Y))
405 | );
406 | }
407 | return new Point(Utility.Clamp(point.X, 0, WindowSize.X - 1), Utility.Clamp(point.Y, 0, WindowSize.Y - 1));
408 | }
409 | throw new Exception();
410 | }
411 | }
412 | }
--------------------------------------------------------------------------------
/Examples/monkey.obj:
--------------------------------------------------------------------------------
1 | # Blender v2.79 (sub 0) OBJ File: ''
2 | # www.blender.org
3 | v 0.437500 -0.164062 -0.765625
4 | v -0.437500 -0.164062 -0.765625
5 | v 0.500000 -0.093750 -0.687500
6 | v -0.500000 -0.093750 -0.687500
7 | v 0.546875 -0.054688 -0.578125
8 | v -0.546875 -0.054688 -0.578125
9 | v 0.351562 0.023438 -0.617188
10 | v -0.351562 0.023438 -0.617188
11 | v 0.351562 -0.031250 -0.718750
12 | v -0.351562 -0.031250 -0.718750
13 | v 0.351562 -0.132812 -0.781250
14 | v -0.351562 -0.132812 -0.781250
15 | v 0.273438 -0.164062 -0.796875
16 | v -0.273438 -0.164062 -0.796875
17 | v 0.203125 -0.093750 -0.742188
18 | v -0.203125 -0.093750 -0.742188
19 | v 0.156250 -0.054688 -0.648438
20 | v -0.156250 -0.054688 -0.648438
21 | v 0.078125 -0.242188 -0.656250
22 | v -0.078125 -0.242188 -0.656250
23 | v 0.140625 -0.242188 -0.742188
24 | v -0.140625 -0.242188 -0.742188
25 | v 0.242188 -0.242188 -0.796875
26 | v -0.242188 -0.242188 -0.796875
27 | v 0.273438 -0.328125 -0.796875
28 | v -0.273438 -0.328125 -0.796875
29 | v 0.203125 -0.390625 -0.742188
30 | v -0.203125 -0.390625 -0.742188
31 | v 0.156250 -0.437500 -0.648438
32 | v -0.156250 -0.437500 -0.648438
33 | v 0.351562 -0.515625 -0.617188
34 | v -0.351562 -0.515625 -0.617188
35 | v 0.351562 -0.453125 -0.718750
36 | v -0.351562 -0.453125 -0.718750
37 | v 0.351562 -0.359375 -0.781250
38 | v -0.351562 -0.359375 -0.781250
39 | v 0.437500 -0.328125 -0.765625
40 | v -0.437500 -0.328125 -0.765625
41 | v 0.500000 -0.390625 -0.687500
42 | v -0.500000 -0.390625 -0.687500
43 | v 0.546875 -0.437500 -0.578125
44 | v -0.546875 -0.437500 -0.578125
45 | v 0.625000 -0.242188 -0.562500
46 | v -0.625000 -0.242188 -0.562500
47 | v 0.562500 -0.242188 -0.671875
48 | v -0.562500 -0.242188 -0.671875
49 | v 0.468750 -0.242188 -0.757812
50 | v -0.468750 -0.242188 -0.757812
51 | v 0.476562 -0.242188 -0.773438
52 | v -0.476562 -0.242188 -0.773438
53 | v 0.445312 -0.335938 -0.781250
54 | v -0.445312 -0.335938 -0.781250
55 | v 0.351562 -0.375000 -0.804688
56 | v -0.351562 -0.375000 -0.804688
57 | v 0.265625 -0.335938 -0.820312
58 | v -0.265625 -0.335938 -0.820312
59 | v 0.226562 -0.242188 -0.820312
60 | v -0.226562 -0.242188 -0.820312
61 | v 0.265625 -0.156250 -0.820312
62 | v -0.265625 -0.156250 -0.820312
63 | v 0.351562 -0.242188 -0.828125
64 | v -0.351562 -0.242188 -0.828125
65 | v 0.351562 -0.117188 -0.804688
66 | v -0.351562 -0.117188 -0.804688
67 | v 0.445312 -0.156250 -0.781250
68 | v -0.445312 -0.156250 -0.781250
69 | v 0.000000 -0.429688 -0.742188
70 | v 0.000000 -0.351562 -0.820312
71 | v 0.000000 0.679688 -0.734375
72 | v 0.000000 0.320312 -0.781250
73 | v 0.000000 0.187500 -0.796875
74 | v 0.000000 0.773438 -0.718750
75 | v 0.000000 -0.406250 -0.601562
76 | v 0.000000 -0.570312 -0.570312
77 | v 0.000000 -0.898438 0.546875
78 | v 0.000000 -0.562500 0.851562
79 | v 0.000000 -0.070312 0.828125
80 | v 0.000000 0.382812 0.351562
81 | v 0.203125 0.187500 -0.562500
82 | v -0.203125 0.187500 -0.562500
83 | v 0.312500 0.437500 -0.570312
84 | v -0.312500 0.437500 -0.570312
85 | v 0.351562 0.695312 -0.570312
86 | v -0.351562 0.695312 -0.570312
87 | v 0.367188 0.890625 -0.531250
88 | v -0.367188 0.890625 -0.531250
89 | v 0.328125 0.945312 -0.523438
90 | v -0.328125 0.945312 -0.523438
91 | v 0.179688 0.968750 -0.554688
92 | v -0.179688 0.968750 -0.554688
93 | v 0.000000 0.984375 -0.578125
94 | v 0.437500 0.140625 -0.531250
95 | v -0.437500 0.140625 -0.531250
96 | v 0.632812 0.039062 -0.539062
97 | v -0.632812 0.039062 -0.539062
98 | v 0.828125 -0.148438 -0.445312
99 | v -0.828125 -0.148438 -0.445312
100 | v 0.859375 -0.429688 -0.593750
101 | v -0.859375 -0.429688 -0.593750
102 | v 0.710938 -0.484375 -0.625000
103 | v -0.710938 -0.484375 -0.625000
104 | v 0.492188 -0.601562 -0.687500
105 | v -0.492188 -0.601562 -0.687500
106 | v 0.320312 -0.757812 -0.734375
107 | v -0.320312 -0.757812 -0.734375
108 | v 0.156250 -0.718750 -0.757812
109 | v -0.156250 -0.718750 -0.757812
110 | v 0.062500 -0.492188 -0.750000
111 | v -0.062500 -0.492188 -0.750000
112 | v 0.164062 -0.414062 -0.773438
113 | v -0.164062 -0.414062 -0.773438
114 | v 0.125000 -0.304688 -0.765625
115 | v -0.125000 -0.304688 -0.765625
116 | v 0.203125 -0.093750 -0.742188
117 | v -0.203125 -0.093750 -0.742188
118 | v 0.375000 -0.015625 -0.703125
119 | v -0.375000 -0.015625 -0.703125
120 | v 0.492188 -0.062500 -0.671875
121 | v -0.492188 -0.062500 -0.671875
122 | v 0.625000 -0.187500 -0.648438
123 | v -0.625000 -0.187500 -0.648438
124 | v 0.640625 -0.296875 -0.648438
125 | v -0.640625 -0.296875 -0.648438
126 | v 0.601562 -0.375000 -0.664062
127 | v -0.601562 -0.375000 -0.664062
128 | v 0.429688 -0.437500 -0.718750
129 | v -0.429688 -0.437500 -0.718750
130 | v 0.250000 -0.468750 -0.757812
131 | v -0.250000 -0.468750 -0.757812
132 | v 0.000000 0.765625 -0.734375
133 | v 0.109375 0.718750 -0.734375
134 | v -0.109375 0.718750 -0.734375
135 | v 0.117188 0.835938 -0.710938
136 | v -0.117188 0.835938 -0.710938
137 | v 0.062500 0.882812 -0.695312
138 | v -0.062500 0.882812 -0.695312
139 | v 0.000000 0.890625 -0.687500
140 | v 0.000000 0.195312 -0.750000
141 | v 0.000000 0.140625 -0.742188
142 | v 0.101562 0.148438 -0.742188
143 | v -0.101562 0.148438 -0.742188
144 | v 0.125000 0.226562 -0.750000
145 | v -0.125000 0.226562 -0.750000
146 | v 0.085938 0.289062 -0.742188
147 | v -0.085938 0.289062 -0.742188
148 | v 0.398438 0.046875 -0.671875
149 | v -0.398438 0.046875 -0.671875
150 | v 0.617188 -0.054688 -0.625000
151 | v -0.617188 -0.054688 -0.625000
152 | v 0.726562 -0.203125 -0.601562
153 | v -0.726562 -0.203125 -0.601562
154 | v 0.742188 -0.375000 -0.656250
155 | v -0.742188 -0.375000 -0.656250
156 | v 0.687500 -0.414062 -0.726562
157 | v -0.687500 -0.414062 -0.726562
158 | v 0.437500 -0.546875 -0.796875
159 | v -0.437500 -0.546875 -0.796875
160 | v 0.312500 -0.640625 -0.835938
161 | v -0.312500 -0.640625 -0.835938
162 | v 0.203125 -0.617188 -0.851562
163 | v -0.203125 -0.617188 -0.851562
164 | v 0.101562 -0.429688 -0.843750
165 | v -0.101562 -0.429688 -0.843750
166 | v 0.125000 0.101562 -0.812500
167 | v -0.125000 0.101562 -0.812500
168 | v 0.210938 0.445312 -0.710938
169 | v -0.210938 0.445312 -0.710938
170 | v 0.250000 0.703125 -0.687500
171 | v -0.250000 0.703125 -0.687500
172 | v 0.265625 0.820312 -0.664062
173 | v -0.265625 0.820312 -0.664062
174 | v 0.234375 0.914062 -0.632812
175 | v -0.234375 0.914062 -0.632812
176 | v 0.164062 0.929688 -0.632812
177 | v -0.164062 0.929688 -0.632812
178 | v 0.000000 0.945312 -0.640625
179 | v 0.000000 -0.046875 -0.726562
180 | v 0.000000 -0.210938 -0.765625
181 | v 0.328125 -0.476562 -0.742188
182 | v -0.328125 -0.476562 -0.742188
183 | v 0.164062 -0.140625 -0.750000
184 | v -0.164062 -0.140625 -0.750000
185 | v 0.132812 -0.210938 -0.757812
186 | v -0.132812 -0.210938 -0.757812
187 | v 0.117188 0.687500 -0.734375
188 | v -0.117188 0.687500 -0.734375
189 | v 0.078125 0.445312 -0.750000
190 | v -0.078125 0.445312 -0.750000
191 | v 0.000000 0.445312 -0.750000
192 | v 0.000000 0.328125 -0.742188
193 | v 0.093750 0.273438 -0.781250
194 | v -0.093750 0.273438 -0.781250
195 | v 0.132812 0.226562 -0.796875
196 | v -0.132812 0.226562 -0.796875
197 | v 0.109375 0.132812 -0.781250
198 | v -0.109375 0.132812 -0.781250
199 | v 0.039062 0.125000 -0.781250
200 | v -0.039062 0.125000 -0.781250
201 | v 0.000000 0.203125 -0.828125
202 | v 0.046875 0.148438 -0.812500
203 | v -0.046875 0.148438 -0.812500
204 | v 0.093750 0.156250 -0.812500
205 | v -0.093750 0.156250 -0.812500
206 | v 0.109375 0.226562 -0.828125
207 | v -0.109375 0.226562 -0.828125
208 | v 0.078125 0.250000 -0.804688
209 | v -0.078125 0.250000 -0.804688
210 | v 0.000000 0.289062 -0.804688
211 | v 0.257812 0.312500 -0.554688
212 | v -0.257812 0.312500 -0.554688
213 | v 0.164062 0.242188 -0.710938
214 | v -0.164062 0.242188 -0.710938
215 | v 0.179688 0.312500 -0.710938
216 | v -0.179688 0.312500 -0.710938
217 | v 0.234375 0.250000 -0.554688
218 | v -0.234375 0.250000 -0.554688
219 | v 0.000000 0.875000 -0.687500
220 | v 0.046875 0.867188 -0.687500
221 | v -0.046875 0.867188 -0.687500
222 | v 0.093750 0.820312 -0.710938
223 | v -0.093750 0.820312 -0.710938
224 | v 0.093750 0.742188 -0.726562
225 | v -0.093750 0.742188 -0.726562
226 | v 0.000000 0.781250 -0.656250
227 | v 0.093750 0.750000 -0.664062
228 | v -0.093750 0.750000 -0.664062
229 | v 0.093750 0.812500 -0.640625
230 | v -0.093750 0.812500 -0.640625
231 | v 0.046875 0.851562 -0.632812
232 | v -0.046875 0.851562 -0.632812
233 | v 0.000000 0.859375 -0.632812
234 | v 0.171875 -0.218750 -0.781250
235 | v -0.171875 -0.218750 -0.781250
236 | v 0.187500 -0.156250 -0.773438
237 | v -0.187500 -0.156250 -0.773438
238 | v 0.335938 -0.429688 -0.757812
239 | v -0.335938 -0.429688 -0.757812
240 | v 0.273438 -0.421875 -0.773438
241 | v -0.273438 -0.421875 -0.773438
242 | v 0.421875 -0.398438 -0.773438
243 | v -0.421875 -0.398438 -0.773438
244 | v 0.562500 -0.351562 -0.695312
245 | v -0.562500 -0.351562 -0.695312
246 | v 0.585938 -0.289062 -0.687500
247 | v -0.585938 -0.289062 -0.687500
248 | v 0.578125 -0.195312 -0.679688
249 | v -0.578125 -0.195312 -0.679688
250 | v 0.476562 -0.101562 -0.718750
251 | v -0.476562 -0.101562 -0.718750
252 | v 0.375000 -0.062500 -0.742188
253 | v -0.375000 -0.062500 -0.742188
254 | v 0.226562 -0.109375 -0.781250
255 | v -0.226562 -0.109375 -0.781250
256 | v 0.179688 -0.296875 -0.781250
257 | v -0.179688 -0.296875 -0.781250
258 | v 0.210938 -0.375000 -0.781250
259 | v -0.210938 -0.375000 -0.781250
260 | v 0.234375 -0.359375 -0.757812
261 | v -0.234375 -0.359375 -0.757812
262 | v 0.195312 -0.296875 -0.757812
263 | v -0.195312 -0.296875 -0.757812
264 | v 0.242188 -0.125000 -0.757812
265 | v -0.242188 -0.125000 -0.757812
266 | v 0.375000 -0.085938 -0.726562
267 | v -0.375000 -0.085938 -0.726562
268 | v 0.460938 -0.117188 -0.703125
269 | v -0.460938 -0.117188 -0.703125
270 | v 0.546875 -0.210938 -0.671875
271 | v -0.546875 -0.210938 -0.671875
272 | v 0.554688 -0.281250 -0.671875
273 | v -0.554688 -0.281250 -0.671875
274 | v 0.531250 -0.335938 -0.679688
275 | v -0.531250 -0.335938 -0.679688
276 | v 0.414062 -0.390625 -0.750000
277 | v -0.414062 -0.390625 -0.750000
278 | v 0.281250 -0.398438 -0.765625
279 | v -0.281250 -0.398438 -0.765625
280 | v 0.335938 -0.406250 -0.750000
281 | v -0.335938 -0.406250 -0.750000
282 | v 0.203125 -0.171875 -0.750000
283 | v -0.203125 -0.171875 -0.750000
284 | v 0.195312 -0.226562 -0.750000
285 | v -0.195312 -0.226562 -0.750000
286 | v 0.109375 -0.460938 -0.609375
287 | v -0.109375 -0.460938 -0.609375
288 | v 0.195312 -0.664062 -0.617188
289 | v -0.195312 -0.664062 -0.617188
290 | v 0.335938 -0.687500 -0.593750
291 | v -0.335938 -0.687500 -0.593750
292 | v 0.484375 -0.554688 -0.554688
293 | v -0.484375 -0.554688 -0.554688
294 | v 0.679688 -0.453125 -0.492188
295 | v -0.679688 -0.453125 -0.492188
296 | v 0.796875 -0.406250 -0.460938
297 | v -0.796875 -0.406250 -0.460938
298 | v 0.773438 -0.164062 -0.375000
299 | v -0.773438 -0.164062 -0.375000
300 | v 0.601562 0.000000 -0.414062
301 | v -0.601562 0.000000 -0.414062
302 | v 0.437500 0.093750 -0.468750
303 | v -0.437500 0.093750 -0.468750
304 | v 0.000000 -0.898438 -0.289062
305 | v 0.000000 -0.984375 0.078125
306 | v 0.000000 0.195312 0.671875
307 | v 0.000000 0.460938 -0.187500
308 | v 0.000000 0.976562 -0.460938
309 | v 0.000000 0.804688 -0.343750
310 | v 0.000000 0.570312 -0.320312
311 | v 0.000000 0.484375 -0.281250
312 | v 0.851562 -0.234375 -0.054688
313 | v -0.851562 -0.234375 -0.054688
314 | v 0.859375 -0.320312 0.046875
315 | v -0.859375 -0.320312 0.046875
316 | v 0.773438 -0.265625 0.437500
317 | v -0.773438 -0.265625 0.437500
318 | v 0.460938 -0.437500 0.703125
319 | v -0.460938 -0.437500 0.703125
320 | v 0.734375 0.046875 -0.070312
321 | v -0.734375 0.046875 -0.070312
322 | v 0.593750 0.125000 0.164062
323 | v -0.593750 0.125000 0.164062
324 | v 0.640625 0.007812 0.429688
325 | v -0.640625 0.007812 0.429688
326 | v 0.335938 -0.054688 0.664062
327 | v -0.335938 -0.054688 0.664062
328 | v 0.234375 0.351562 -0.406250
329 | v -0.234375 0.351562 -0.406250
330 | v 0.179688 0.414062 -0.257812
331 | v -0.179688 0.414062 -0.257812
332 | v 0.289062 0.710938 -0.382812
333 | v -0.289062 0.710938 -0.382812
334 | v 0.250000 0.500000 -0.390625
335 | v -0.250000 0.500000 -0.390625
336 | v 0.328125 0.914062 -0.398438
337 | v -0.328125 0.914062 -0.398438
338 | v 0.140625 0.757812 -0.367188
339 | v -0.140625 0.757812 -0.367188
340 | v 0.125000 0.539062 -0.359375
341 | v -0.125000 0.539062 -0.359375
342 | v 0.164062 0.945312 -0.437500
343 | v -0.164062 0.945312 -0.437500
344 | v 0.218750 0.281250 -0.429688
345 | v -0.218750 0.281250 -0.429688
346 | v 0.210938 0.226562 -0.468750
347 | v -0.210938 0.226562 -0.468750
348 | v 0.203125 0.171875 -0.500000
349 | v -0.203125 0.171875 -0.500000
350 | v 0.210938 0.390625 -0.164062
351 | v -0.210938 0.390625 -0.164062
352 | v 0.296875 0.312500 0.265625
353 | v -0.296875 0.312500 0.265625
354 | v 0.343750 0.148438 0.539062
355 | v -0.343750 0.148438 0.539062
356 | v 0.453125 -0.867188 0.382812
357 | v -0.453125 -0.867188 0.382812
358 | v 0.453125 -0.929688 0.070312
359 | v -0.453125 -0.929688 0.070312
360 | v 0.453125 -0.851562 -0.234375
361 | v -0.453125 -0.851562 -0.234375
362 | v 0.460938 -0.523438 -0.429688
363 | v -0.460938 -0.523438 -0.429688
364 | v 0.726562 -0.406250 -0.335938
365 | v -0.726562 -0.406250 -0.335938
366 | v 0.632812 -0.453125 -0.281250
367 | v -0.632812 -0.453125 -0.281250
368 | v 0.640625 -0.703125 -0.054688
369 | v -0.640625 -0.703125 -0.054688
370 | v 0.796875 -0.562500 -0.125000
371 | v -0.796875 -0.562500 -0.125000
372 | v 0.796875 -0.617188 0.117188
373 | v -0.796875 -0.617188 0.117188
374 | v 0.640625 -0.750000 0.195312
375 | v -0.640625 -0.750000 0.195312
376 | v 0.640625 -0.679688 0.445312
377 | v -0.640625 -0.679688 0.445312
378 | v 0.796875 -0.539062 0.359375
379 | v -0.796875 -0.539062 0.359375
380 | v 0.617188 -0.328125 0.585938
381 | v -0.617188 -0.328125 0.585938
382 | v 0.484375 -0.023438 0.546875
383 | v -0.484375 -0.023438 0.546875
384 | v 0.820312 -0.328125 0.203125
385 | v -0.820312 -0.328125 0.203125
386 | v 0.406250 0.171875 -0.148438
387 | v -0.406250 0.171875 -0.148438
388 | v 0.429688 0.195312 0.210938
389 | v -0.429688 0.195312 0.210938
390 | v 0.890625 -0.406250 0.234375
391 | v -0.890625 -0.406250 0.234375
392 | v 0.773438 0.140625 0.125000
393 | v -0.773438 0.140625 0.125000
394 | v 1.039062 0.101562 0.328125
395 | v -1.039062 0.101562 0.328125
396 | v 1.281250 -0.054688 0.429688
397 | v -1.281250 -0.054688 0.429688
398 | v 1.351562 -0.320312 0.421875
399 | v -1.351562 -0.320312 0.421875
400 | v 1.234375 -0.507812 0.421875
401 | v -1.234375 -0.507812 0.421875
402 | v 1.023438 -0.476562 0.312500
403 | v -1.023438 -0.476562 0.312500
404 | v 1.015625 -0.414062 0.289062
405 | v -1.015625 -0.414062 0.289062
406 | v 1.187500 -0.437500 0.390625
407 | v -1.187500 -0.437500 0.390625
408 | v 1.265625 -0.289062 0.406250
409 | v -1.265625 -0.289062 0.406250
410 | v 1.210938 -0.078125 0.406250
411 | v -1.210938 -0.078125 0.406250
412 | v 1.031250 0.039062 0.304688
413 | v -1.031250 0.039062 0.304688
414 | v 0.828125 0.070312 0.132812
415 | v -0.828125 0.070312 0.132812
416 | v 0.921875 -0.359375 0.218750
417 | v -0.921875 -0.359375 0.218750
418 | v 0.945312 -0.304688 0.289062
419 | v -0.945312 -0.304688 0.289062
420 | v 0.882812 0.023438 0.210938
421 | v -0.882812 0.023438 0.210938
422 | v 1.039062 0.000000 0.367188
423 | v -1.039062 0.000000 0.367188
424 | v 1.187500 -0.093750 0.445312
425 | v -1.187500 -0.093750 0.445312
426 | v 1.234375 -0.250000 0.445312
427 | v -1.234375 -0.250000 0.445312
428 | v 1.171875 -0.359375 0.437500
429 | v -1.171875 -0.359375 0.437500
430 | v 1.023438 -0.343750 0.359375
431 | v -1.023438 -0.343750 0.359375
432 | v 0.843750 -0.289062 0.210938
433 | v -0.843750 -0.289062 0.210938
434 | v 0.835938 -0.171875 0.273438
435 | v -0.835938 -0.171875 0.273438
436 | v 0.757812 -0.093750 0.273438
437 | v -0.757812 -0.093750 0.273438
438 | v 0.820312 -0.085938 0.273438
439 | v -0.820312 -0.085938 0.273438
440 | v 0.843750 -0.015625 0.273438
441 | v -0.843750 -0.015625 0.273438
442 | v 0.812500 0.015625 0.273438
443 | v -0.812500 0.015625 0.273438
444 | v 0.726562 0.000000 0.070312
445 | v -0.726562 0.000000 0.070312
446 | v 0.718750 0.023438 0.171875
447 | v -0.718750 0.023438 0.171875
448 | v 0.718750 -0.039062 0.187500
449 | v -0.718750 -0.039062 0.187500
450 | v 0.796875 -0.203125 0.210938
451 | v -0.796875 -0.203125 0.210938
452 | v 0.890625 -0.242188 0.265625
453 | v -0.890625 -0.242188 0.265625
454 | v 0.890625 -0.234375 0.320312
455 | v -0.890625 -0.234375 0.320312
456 | v 0.812500 0.015625 0.320312
457 | v -0.812500 0.015625 0.320312
458 | v 0.851562 -0.015625 0.320312
459 | v -0.851562 -0.015625 0.320312
460 | v 0.828125 -0.078125 0.320312
461 | v -0.828125 -0.078125 0.320312
462 | v 0.765625 -0.093750 0.320312
463 | v -0.765625 -0.093750 0.320312
464 | v 0.843750 -0.171875 0.320312
465 | v -0.843750 -0.171875 0.320312
466 | v 1.039062 -0.328125 0.414062
467 | v -1.039062 -0.328125 0.414062
468 | v 1.187500 -0.343750 0.484375
469 | v -1.187500 -0.343750 0.484375
470 | v 1.257812 -0.242188 0.492188
471 | v -1.257812 -0.242188 0.492188
472 | v 1.210938 -0.085938 0.484375
473 | v -1.210938 -0.085938 0.484375
474 | v 1.046875 0.000000 0.421875
475 | v -1.046875 0.000000 0.421875
476 | v 0.882812 0.015625 0.265625
477 | v -0.882812 0.015625 0.265625
478 | v 0.953125 -0.289062 0.343750
479 | v -0.953125 -0.289062 0.343750
480 | v 0.890625 -0.109375 0.328125
481 | v -0.890625 -0.109375 0.328125
482 | v 0.937500 -0.062500 0.335938
483 | v -0.937500 -0.062500 0.335938
484 | v 1.000000 -0.125000 0.367188
485 | v -1.000000 -0.125000 0.367188
486 | v 0.960938 -0.171875 0.351562
487 | v -0.960938 -0.171875 0.351562
488 | v 1.015625 -0.234375 0.375000
489 | v -1.015625 -0.234375 0.375000
490 | v 1.054688 -0.187500 0.382812
491 | v -1.054688 -0.187500 0.382812
492 | v 1.109375 -0.210938 0.390625
493 | v -1.109375 -0.210938 0.390625
494 | v 1.085938 -0.273438 0.390625
495 | v -1.085938 -0.273438 0.390625
496 | v 1.023438 -0.437500 0.484375
497 | v -1.023438 -0.437500 0.484375
498 | v 1.250000 -0.468750 0.546875
499 | v -1.250000 -0.468750 0.546875
500 | v 1.367188 -0.296875 0.500000
501 | v -1.367188 -0.296875 0.500000
502 | v 1.312500 -0.054688 0.531250
503 | v -1.312500 -0.054688 0.531250
504 | v 1.039062 0.085938 0.492188
505 | v -1.039062 0.085938 0.492188
506 | v 0.789062 0.125000 0.328125
507 | v -0.789062 0.125000 0.328125
508 | v 0.859375 -0.382812 0.382812
509 | v -0.859375 -0.382812 0.382812
510 | s off
511 | f 47 3 45
512 | f 4 48 46
513 | f 45 5 43
514 | f 6 46 44
515 | f 3 7 5
516 | f 8 4 6
517 | f 1 9 3
518 | f 10 2 4
519 | f 11 15 9
520 | f 16 12 10
521 | f 9 17 7
522 | f 18 10 8
523 | f 21 17 15
524 | f 22 18 20
525 | f 13 21 15
526 | f 22 14 16
527 | f 23 27 21
528 | f 28 24 22
529 | f 27 19 21
530 | f 28 20 30
531 | f 33 29 27
532 | f 34 30 32
533 | f 35 27 25
534 | f 36 28 34
535 | f 37 33 35
536 | f 38 34 40
537 | f 39 31 33
538 | f 40 32 42
539 | f 45 41 39
540 | f 46 42 44
541 | f 47 39 37
542 | f 48 40 46
543 | f 37 49 47
544 | f 38 50 52
545 | f 35 51 37
546 | f 36 52 54
547 | f 25 53 35
548 | f 26 54 56
549 | f 23 55 25
550 | f 24 56 58
551 | f 23 59 57
552 | f 60 24 58
553 | f 13 63 59
554 | f 64 14 60
555 | f 11 65 63
556 | f 66 12 64
557 | f 1 49 65
558 | f 50 2 66
559 | f 61 65 49
560 | f 50 66 62
561 | f 63 65 61
562 | f 62 66 64
563 | f 61 59 63
564 | f 64 60 62
565 | f 61 57 59
566 | f 60 58 62
567 | f 61 55 57
568 | f 58 56 62
569 | f 61 53 55
570 | f 56 54 62
571 | f 61 51 53
572 | f 54 52 62
573 | f 61 49 51
574 | f 52 50 62
575 | f 174 91 89
576 | f 175 91 176
577 | f 172 89 87
578 | f 173 90 175
579 | f 85 172 87
580 | f 173 86 88
581 | f 83 170 85
582 | f 171 84 86
583 | f 81 168 83
584 | f 169 82 84
585 | f 79 146 164
586 | f 147 80 165
587 | f 94 146 92
588 | f 95 147 149
589 | f 94 150 148
590 | f 151 95 149
591 | f 98 150 96
592 | f 99 151 153
593 | f 100 152 98
594 | f 101 153 155
595 | f 102 154 100
596 | f 103 155 157
597 | f 102 158 156
598 | f 159 103 157
599 | f 106 158 104
600 | f 107 159 161
601 | f 108 160 106
602 | f 109 161 163
603 | f 67 162 108
604 | f 67 163 68
605 | f 128 162 110
606 | f 129 163 161
607 | f 128 158 160
608 | f 159 129 161
609 | f 156 179 126
610 | f 157 180 159
611 | f 154 126 124
612 | f 155 127 157
613 | f 152 124 122
614 | f 153 125 155
615 | f 150 122 120
616 | f 151 123 153
617 | f 148 120 118
618 | f 149 121 151
619 | f 146 118 116
620 | f 147 119 149
621 | f 164 116 114
622 | f 165 117 147
623 | f 114 177 164
624 | f 177 115 165
625 | f 162 112 110
626 | f 163 113 68
627 | f 112 178 183
628 | f 178 113 184
629 | f 181 178 177
630 | f 182 178 184
631 | f 135 176 174
632 | f 176 136 175
633 | f 133 174 172
634 | f 175 134 173
635 | f 133 170 131
636 | f 134 171 173
637 | f 166 185 168
638 | f 186 167 169
639 | f 131 168 185
640 | f 169 132 186
641 | f 190 187 144
642 | f 190 188 189
643 | f 187 69 185
644 | f 188 69 189
645 | f 131 69 130
646 | f 132 69 186
647 | f 142 191 144
648 | f 192 143 145
649 | f 140 193 142
650 | f 194 141 143
651 | f 197 140 139
652 | f 198 141 196
653 | f 71 139 138
654 | f 71 139 198
655 | f 144 70 190
656 | f 145 70 192
657 | f 191 208 70
658 | f 192 208 207
659 | f 71 200 197
660 | f 201 71 198
661 | f 197 202 195
662 | f 203 198 196
663 | f 202 193 195
664 | f 203 194 205
665 | f 193 206 191
666 | f 207 194 192
667 | f 204 200 199
668 | f 205 201 203
669 | f 199 206 204
670 | f 207 199 205
671 | f 139 164 177
672 | f 165 139 177
673 | f 140 211 164
674 | f 212 141 165
675 | f 144 211 142
676 | f 145 212 214
677 | f 187 213 144
678 | f 188 214 167
679 | f 209 166 81
680 | f 210 167 214
681 | f 215 213 209
682 | f 216 214 212
683 | f 79 211 215
684 | f 212 80 216
685 | f 130 222 131
686 | f 130 223 72
687 | f 133 222 220
688 | f 223 134 221
689 | f 135 220 218
690 | f 221 136 219
691 | f 137 218 217
692 | f 219 137 217
693 | f 218 231 217
694 | f 219 231 230
695 | f 218 227 229
696 | f 228 219 230
697 | f 220 225 227
698 | f 226 221 228
699 | f 72 225 222
700 | f 72 226 224
701 | f 224 229 225
702 | f 230 224 226
703 | f 225 229 227
704 | f 228 230 226
705 | f 183 234 232
706 | f 235 184 233
707 | f 112 232 254
708 | f 233 113 255
709 | f 112 256 110
710 | f 113 257 255
711 | f 114 234 181
712 | f 115 235 253
713 | f 114 250 252
714 | f 251 115 253
715 | f 116 248 250
716 | f 249 117 251
717 | f 118 246 248
718 | f 247 119 249
719 | f 120 244 246
720 | f 245 121 247
721 | f 124 244 122
722 | f 125 245 243
723 | f 126 242 124
724 | f 127 243 241
725 | f 126 236 240
726 | f 237 127 241
727 | f 179 238 236
728 | f 239 180 237
729 | f 128 256 238
730 | f 257 129 239
731 | f 256 276 238
732 | f 257 277 259
733 | f 236 276 278
734 | f 277 237 279
735 | f 236 274 240
736 | f 237 275 279
737 | f 240 272 242
738 | f 241 273 275
739 | f 244 272 270
740 | f 273 245 271
741 | f 244 268 246
742 | f 245 269 271
743 | f 248 268 266
744 | f 269 249 267
745 | f 248 264 250
746 | f 249 265 267
747 | f 250 262 252
748 | f 251 263 265
749 | f 234 262 280
750 | f 263 235 281
751 | f 256 260 258
752 | f 261 257 259
753 | f 254 282 260
754 | f 283 255 261
755 | f 232 280 282
756 | f 281 233 283
757 | f 67 284 73
758 | f 285 67 73
759 | f 108 286 284
760 | f 287 109 285
761 | f 104 286 106
762 | f 105 287 289
763 | f 102 288 104
764 | f 103 289 291
765 | f 100 290 102
766 | f 101 291 293
767 | f 100 294 292
768 | f 295 101 293
769 | f 96 294 98
770 | f 97 295 297
771 | f 96 298 296
772 | f 299 97 297
773 | f 94 300 298
774 | f 301 95 299
775 | f 309 338 308
776 | f 309 339 329
777 | f 308 336 307
778 | f 308 337 339
779 | f 307 340 306
780 | f 307 341 337
781 | f 89 306 340
782 | f 306 90 341
783 | f 87 340 334
784 | f 341 88 335
785 | f 85 334 330
786 | f 335 86 331
787 | f 83 330 332
788 | f 331 84 333
789 | f 330 338 332
790 | f 339 331 333
791 | f 334 336 330
792 | f 335 337 341
793 | f 332 328 326
794 | f 333 329 339
795 | f 81 332 326
796 | f 333 82 327
797 | f 342 215 209
798 | f 343 216 345
799 | f 326 209 81
800 | f 327 210 343
801 | f 215 346 79
802 | f 216 347 345
803 | f 346 92 79
804 | f 347 93 301
805 | f 324 304 77
806 | f 325 304 353
807 | f 352 78 304
808 | f 353 78 351
809 | f 78 348 305
810 | f 349 78 305
811 | f 305 328 309
812 | f 329 305 309
813 | f 328 342 326
814 | f 329 343 349
815 | f 296 318 310
816 | f 319 297 311
817 | f 316 77 76
818 | f 317 77 325
819 | f 358 303 302
820 | f 359 303 357
821 | f 303 354 75
822 | f 355 303 75
823 | f 75 316 76
824 | f 317 75 76
825 | f 292 362 364
826 | f 363 293 365
827 | f 364 368 366
828 | f 369 365 367
829 | f 366 370 372
830 | f 371 367 373
831 | f 372 376 374
832 | f 377 373 375
833 | f 378 376 314
834 | f 379 377 375
835 | f 316 374 378
836 | f 375 317 379
837 | f 354 372 374
838 | f 373 355 375
839 | f 356 366 372
840 | f 367 357 373
841 | f 358 364 366
842 | f 365 359 367
843 | f 292 360 290
844 | f 293 361 365
845 | f 360 302 74
846 | f 361 302 359
847 | f 284 288 290
848 | f 289 285 291
849 | f 284 360 74
850 | f 361 285 74
851 | f 73 284 74
852 | f 74 285 73
853 | f 296 362 294
854 | f 297 363 311
855 | f 310 368 362
856 | f 369 311 363
857 | f 312 370 368
858 | f 371 313 369
859 | f 376 382 314
860 | f 377 383 371
861 | f 350 384 348
862 | f 351 385 387
863 | f 384 320 318
864 | f 385 321 387
865 | f 298 384 318
866 | f 385 299 319
867 | f 300 342 384
868 | f 343 301 385
869 | f 342 348 384
870 | f 385 349 343
871 | f 300 346 344
872 | f 345 347 301
873 | f 322 378 314
874 | f 323 379 381
875 | f 378 324 316
876 | f 379 325 381
877 | f 386 322 320
878 | f 387 323 381
879 | f 352 386 350
880 | f 353 387 381
881 | f 324 380 352
882 | f 353 381 325
883 | f 388 402 400
884 | f 389 403 415
885 | f 400 404 398
886 | f 405 401 399
887 | f 404 396 398
888 | f 405 397 407
889 | f 406 394 396
890 | f 407 395 409
891 | f 408 392 394
892 | f 409 393 411
893 | f 392 412 390
894 | f 413 393 391
895 | f 410 418 412
896 | f 419 411 413
897 | f 408 420 410
898 | f 421 409 411
899 | f 424 408 406
900 | f 425 409 423
901 | f 426 406 404
902 | f 427 407 425
903 | f 428 404 402
904 | f 429 405 427
905 | f 402 416 428
906 | f 417 403 429
907 | f 320 442 318
908 | f 321 443 445
909 | f 390 444 320
910 | f 391 445 413
911 | f 310 442 312
912 | f 443 311 313
913 | f 382 414 388
914 | f 415 383 389
915 | f 412 440 444
916 | f 441 413 445
917 | f 446 440 438
918 | f 447 441 445
919 | f 434 438 436
920 | f 439 435 437
921 | f 448 434 432
922 | f 449 435 447
923 | f 448 450 430
924 | f 449 451 433
925 | f 430 416 414
926 | f 431 417 451
927 | f 312 430 382
928 | f 431 313 383
929 | f 442 448 312
930 | f 443 449 447
931 | f 442 444 446
932 | f 447 445 443
933 | f 416 452 476
934 | f 453 417 477
935 | f 432 452 450
936 | f 433 453 463
937 | f 432 460 462
938 | f 461 433 463
939 | f 436 460 434
940 | f 437 461 459
941 | f 438 458 436
942 | f 439 459 457
943 | f 438 454 456
944 | f 455 439 457
945 | f 440 474 454
946 | f 475 441 455
947 | f 428 476 464
948 | f 477 429 465
949 | f 426 464 466
950 | f 465 427 467
951 | f 424 466 468
952 | f 467 425 469
953 | f 424 470 422
954 | f 425 471 469
955 | f 422 472 420
956 | f 423 473 471
957 | f 420 474 418
958 | f 421 475 473
959 | f 456 478 458
960 | f 457 479 481
961 | f 480 484 478
962 | f 481 485 483
963 | f 484 488 486
964 | f 489 485 487
965 | f 488 492 486
966 | f 489 493 491
967 | f 464 486 492
968 | f 487 465 493
969 | f 484 476 452
970 | f 485 477 487
971 | f 462 484 452
972 | f 463 485 479
973 | f 458 462 460
974 | f 463 459 461
975 | f 474 456 454
976 | f 475 457 481
977 | f 472 480 474
978 | f 481 473 475
979 | f 488 472 470
980 | f 489 473 483
981 | f 490 470 468
982 | f 491 471 489
983 | f 466 490 468
984 | f 491 467 469
985 | f 464 492 466
986 | f 467 493 465
987 | f 392 504 502
988 | f 505 393 503
989 | f 394 502 500
990 | f 503 395 501
991 | f 394 498 396
992 | f 395 499 501
993 | f 396 496 398
994 | f 397 497 499
995 | f 398 494 400
996 | f 399 495 497
997 | f 400 506 388
998 | f 401 507 495
999 | f 502 506 494
1000 | f 503 507 505
1001 | f 494 500 502
1002 | f 501 495 503
1003 | f 496 498 500
1004 | f 501 499 497
1005 | f 382 506 314
1006 | f 383 507 389
1007 | f 314 504 322
1008 | f 505 315 323
1009 | f 320 504 390
1010 | f 505 321 391
1011 | f 47 1 3
1012 | f 4 2 48
1013 | f 45 3 5
1014 | f 6 4 46
1015 | f 3 9 7
1016 | f 8 10 4
1017 | f 1 11 9
1018 | f 10 12 2
1019 | f 11 13 15
1020 | f 16 14 12
1021 | f 9 15 17
1022 | f 18 16 10
1023 | f 21 19 17
1024 | f 22 16 18
1025 | f 13 23 21
1026 | f 22 24 14
1027 | f 23 25 27
1028 | f 28 26 24
1029 | f 27 29 19
1030 | f 28 22 20
1031 | f 33 31 29
1032 | f 34 28 30
1033 | f 35 33 27
1034 | f 36 26 28
1035 | f 37 39 33
1036 | f 38 36 34
1037 | f 39 41 31
1038 | f 40 34 32
1039 | f 45 43 41
1040 | f 46 40 42
1041 | f 47 45 39
1042 | f 48 38 40
1043 | f 37 51 49
1044 | f 38 48 50
1045 | f 35 53 51
1046 | f 36 38 52
1047 | f 25 55 53
1048 | f 26 36 54
1049 | f 23 57 55
1050 | f 24 26 56
1051 | f 23 13 59
1052 | f 60 14 24
1053 | f 13 11 63
1054 | f 64 12 14
1055 | f 11 1 65
1056 | f 66 2 12
1057 | f 1 47 49
1058 | f 50 48 2
1059 | f 174 176 91
1060 | f 175 90 91
1061 | f 172 174 89
1062 | f 173 88 90
1063 | f 85 170 172
1064 | f 173 171 86
1065 | f 83 168 170
1066 | f 171 169 84
1067 | f 81 166 168
1068 | f 169 167 82
1069 | f 79 92 146
1070 | f 147 93 80
1071 | f 94 148 146
1072 | f 95 93 147
1073 | f 94 96 150
1074 | f 151 97 95
1075 | f 98 152 150
1076 | f 99 97 151
1077 | f 100 154 152
1078 | f 101 99 153
1079 | f 102 156 154
1080 | f 103 101 155
1081 | f 102 104 158
1082 | f 159 105 103
1083 | f 106 160 158
1084 | f 107 105 159
1085 | f 108 162 160
1086 | f 109 107 161
1087 | f 67 68 162
1088 | f 67 109 163
1089 | f 128 160 162
1090 | f 129 111 163
1091 | f 128 179 158
1092 | f 159 180 129
1093 | f 156 158 179
1094 | f 157 127 180
1095 | f 154 156 126
1096 | f 155 125 127
1097 | f 152 154 124
1098 | f 153 123 125
1099 | f 150 152 122
1100 | f 151 121 123
1101 | f 148 150 120
1102 | f 149 119 121
1103 | f 146 148 118
1104 | f 147 117 119
1105 | f 164 146 116
1106 | f 165 115 117
1107 | f 114 181 177
1108 | f 177 182 115
1109 | f 162 68 112
1110 | f 163 111 113
1111 | f 112 68 178
1112 | f 178 68 113
1113 | f 181 183 178
1114 | f 182 177 178
1115 | f 135 137 176
1116 | f 176 137 136
1117 | f 133 135 174
1118 | f 175 136 134
1119 | f 133 172 170
1120 | f 134 132 171
1121 | f 166 187 185
1122 | f 186 188 167
1123 | f 131 170 168
1124 | f 169 171 132
1125 | f 190 189 187
1126 | f 190 145 188
1127 | f 187 189 69
1128 | f 188 186 69
1129 | f 131 185 69
1130 | f 132 130 69
1131 | f 142 193 191
1132 | f 192 194 143
1133 | f 140 195 193
1134 | f 194 196 141
1135 | f 197 195 140
1136 | f 198 139 141
1137 | f 71 197 139
1138 | f 71 138 139
1139 | f 144 191 70
1140 | f 145 190 70
1141 | f 191 206 208
1142 | f 192 70 208
1143 | f 71 199 200
1144 | f 201 199 71
1145 | f 197 200 202
1146 | f 203 201 198
1147 | f 202 204 193
1148 | f 203 196 194
1149 | f 193 204 206
1150 | f 207 205 194
1151 | f 204 202 200
1152 | f 205 199 201
1153 | f 199 208 206
1154 | f 207 208 199
1155 | f 139 140 164
1156 | f 165 141 139
1157 | f 140 142 211
1158 | f 212 143 141
1159 | f 144 213 211
1160 | f 145 143 212
1161 | f 187 166 213
1162 | f 188 145 214
1163 | f 209 213 166
1164 | f 210 82 167
1165 | f 215 211 213
1166 | f 216 210 214
1167 | f 79 164 211
1168 | f 212 165 80
1169 | f 130 72 222
1170 | f 130 132 223
1171 | f 133 131 222
1172 | f 223 132 134
1173 | f 135 133 220
1174 | f 221 134 136
1175 | f 137 135 218
1176 | f 219 136 137
1177 | f 218 229 231
1178 | f 219 217 231
1179 | f 218 220 227
1180 | f 228 221 219
1181 | f 220 222 225
1182 | f 226 223 221
1183 | f 72 224 225
1184 | f 72 223 226
1185 | f 224 231 229
1186 | f 230 231 224
1187 | f 183 181 234
1188 | f 235 182 184
1189 | f 112 183 232
1190 | f 233 184 113
1191 | f 112 254 256
1192 | f 113 111 257
1193 | f 114 252 234
1194 | f 115 182 235
1195 | f 114 116 250
1196 | f 251 117 115
1197 | f 116 118 248
1198 | f 249 119 117
1199 | f 118 120 246
1200 | f 247 121 119
1201 | f 120 122 244
1202 | f 245 123 121
1203 | f 124 242 244
1204 | f 125 123 245
1205 | f 126 240 242
1206 | f 127 125 243
1207 | f 126 179 236
1208 | f 237 180 127
1209 | f 179 128 238
1210 | f 239 129 180
1211 | f 128 110 256
1212 | f 257 111 129
1213 | f 256 258 276
1214 | f 257 239 277
1215 | f 236 238 276
1216 | f 277 239 237
1217 | f 236 278 274
1218 | f 237 241 275
1219 | f 240 274 272
1220 | f 241 243 273
1221 | f 244 242 272
1222 | f 273 243 245
1223 | f 244 270 268
1224 | f 245 247 269
1225 | f 248 246 268
1226 | f 269 247 249
1227 | f 248 266 264
1228 | f 249 251 265
1229 | f 250 264 262
1230 | f 251 253 263
1231 | f 234 252 262
1232 | f 263 253 235
1233 | f 256 254 260
1234 | f 261 255 257
1235 | f 254 232 282
1236 | f 283 233 255
1237 | f 232 234 280
1238 | f 281 235 233
1239 | f 67 108 284
1240 | f 285 109 67
1241 | f 108 106 286
1242 | f 287 107 109
1243 | f 104 288 286
1244 | f 105 107 287
1245 | f 102 290 288
1246 | f 103 105 289
1247 | f 100 292 290
1248 | f 101 103 291
1249 | f 100 98 294
1250 | f 295 99 101
1251 | f 96 296 294
1252 | f 97 99 295
1253 | f 96 94 298
1254 | f 299 95 97
1255 | f 94 92 300
1256 | f 301 93 95
1257 | f 309 328 338
1258 | f 309 308 339
1259 | f 308 338 336
1260 | f 308 307 337
1261 | f 307 336 340
1262 | f 307 306 341
1263 | f 89 91 306
1264 | f 306 91 90
1265 | f 87 89 340
1266 | f 341 90 88
1267 | f 85 87 334
1268 | f 335 88 86
1269 | f 83 85 330
1270 | f 331 86 84
1271 | f 330 336 338
1272 | f 339 337 331
1273 | f 334 340 336
1274 | f 335 331 337
1275 | f 332 338 328
1276 | f 333 327 329
1277 | f 81 83 332
1278 | f 333 84 82
1279 | f 342 344 215
1280 | f 343 210 216
1281 | f 326 342 209
1282 | f 327 82 210
1283 | f 215 344 346
1284 | f 216 80 347
1285 | f 346 300 92
1286 | f 347 80 93
1287 | f 324 352 304
1288 | f 325 77 304
1289 | f 352 350 78
1290 | f 353 304 78
1291 | f 78 350 348
1292 | f 349 351 78
1293 | f 305 348 328
1294 | f 329 349 305
1295 | f 328 348 342
1296 | f 329 327 343
1297 | f 296 298 318
1298 | f 319 299 297
1299 | f 316 324 77
1300 | f 317 76 77
1301 | f 358 356 303
1302 | f 359 302 303
1303 | f 303 356 354
1304 | f 355 357 303
1305 | f 75 354 316
1306 | f 317 355 75
1307 | f 292 294 362
1308 | f 363 295 293
1309 | f 364 362 368
1310 | f 369 363 365
1311 | f 366 368 370
1312 | f 371 369 367
1313 | f 372 370 376
1314 | f 377 371 373
1315 | f 378 374 376
1316 | f 379 315 377
1317 | f 316 354 374
1318 | f 375 355 317
1319 | f 354 356 372
1320 | f 373 357 355
1321 | f 356 358 366
1322 | f 367 359 357
1323 | f 358 360 364
1324 | f 365 361 359
1325 | f 292 364 360
1326 | f 293 291 361
1327 | f 360 358 302
1328 | f 361 74 302
1329 | f 284 286 288
1330 | f 289 287 285
1331 | f 284 290 360
1332 | f 361 291 285
1333 | f 296 310 362
1334 | f 297 295 363
1335 | f 310 312 368
1336 | f 369 313 311
1337 | f 312 382 370
1338 | f 371 383 313
1339 | f 376 370 382
1340 | f 377 315 383
1341 | f 350 386 384
1342 | f 351 349 385
1343 | f 384 386 320
1344 | f 385 319 321
1345 | f 298 300 384
1346 | f 385 301 299
1347 | f 300 344 342
1348 | f 343 345 301
1349 | f 322 380 378
1350 | f 323 315 379
1351 | f 378 380 324
1352 | f 379 317 325
1353 | f 386 380 322
1354 | f 387 321 323
1355 | f 352 380 386
1356 | f 353 351 387
1357 | f 388 414 402
1358 | f 389 401 403
1359 | f 400 402 404
1360 | f 405 403 401
1361 | f 404 406 396
1362 | f 405 399 397
1363 | f 406 408 394
1364 | f 407 397 395
1365 | f 408 410 392
1366 | f 409 395 393
1367 | f 392 410 412
1368 | f 413 411 393
1369 | f 410 420 418
1370 | f 419 421 411
1371 | f 408 422 420
1372 | f 421 423 409
1373 | f 424 422 408
1374 | f 425 407 409
1375 | f 426 424 406
1376 | f 427 405 407
1377 | f 428 426 404
1378 | f 429 403 405
1379 | f 402 414 416
1380 | f 417 415 403
1381 | f 320 444 442
1382 | f 321 319 443
1383 | f 390 412 444
1384 | f 391 321 445
1385 | f 310 318 442
1386 | f 443 319 311
1387 | f 382 430 414
1388 | f 415 431 383
1389 | f 412 418 440
1390 | f 441 419 413
1391 | f 446 444 440
1392 | f 447 439 441
1393 | f 434 446 438
1394 | f 439 447 435
1395 | f 448 446 434
1396 | f 449 433 435
1397 | f 448 432 450
1398 | f 449 431 451
1399 | f 430 450 416
1400 | f 431 415 417
1401 | f 312 448 430
1402 | f 431 449 313
1403 | f 442 446 448
1404 | f 443 313 449
1405 | f 416 450 452
1406 | f 453 451 417
1407 | f 432 462 452
1408 | f 433 451 453
1409 | f 432 434 460
1410 | f 461 435 433
1411 | f 436 458 460
1412 | f 437 435 461
1413 | f 438 456 458
1414 | f 439 437 459
1415 | f 438 440 454
1416 | f 455 441 439
1417 | f 440 418 474
1418 | f 475 419 441
1419 | f 428 416 476
1420 | f 477 417 429
1421 | f 426 428 464
1422 | f 465 429 427
1423 | f 424 426 466
1424 | f 467 427 425
1425 | f 424 468 470
1426 | f 425 423 471
1427 | f 422 470 472
1428 | f 423 421 473
1429 | f 420 472 474
1430 | f 421 419 475
1431 | f 456 480 478
1432 | f 457 459 479
1433 | f 480 482 484
1434 | f 481 479 485
1435 | f 484 482 488
1436 | f 489 483 485
1437 | f 488 490 492
1438 | f 489 487 493
1439 | f 464 476 486
1440 | f 487 477 465
1441 | f 484 486 476
1442 | f 485 453 477
1443 | f 462 478 484
1444 | f 463 453 485
1445 | f 458 478 462
1446 | f 463 479 459
1447 | f 474 480 456
1448 | f 475 455 457
1449 | f 472 482 480
1450 | f 481 483 473
1451 | f 488 482 472
1452 | f 489 471 473
1453 | f 490 488 470
1454 | f 491 469 471
1455 | f 466 492 490
1456 | f 491 493 467
1457 | f 392 390 504
1458 | f 505 391 393
1459 | f 394 392 502
1460 | f 503 393 395
1461 | f 394 500 498
1462 | f 395 397 499
1463 | f 396 498 496
1464 | f 397 399 497
1465 | f 398 496 494
1466 | f 399 401 495
1467 | f 400 494 506
1468 | f 401 389 507
1469 | f 502 504 506
1470 | f 503 495 507
1471 | f 494 496 500
1472 | f 501 497 495
1473 | f 382 388 506
1474 | f 383 315 507
1475 | f 314 506 504
1476 | f 505 507 315
1477 | f 320 322 504
1478 | f 505 323 321
1479 |
--------------------------------------------------------------------------------
/Examples/caligraphy.flf:
--------------------------------------------------------------------------------
1 | flf2a$ 21 19 30 -1 14
2 | caligraphy.flf composed by Vinney Thai
3 | caligraphy font (J, O, R) composed by Jorn
4 | date: Oct 23, 1994
5 |
6 | Explanation of first line:
7 | flf2 - "magic number" for file identification
8 | a - should always be `a', for now
9 | $ - the "hardblank" -- prints as a blank, but can't be smushed
10 | 21 - height of a character
11 | 19 - height of a character, not including descenders
12 | 20 - max line length (excluding comment lines) + a fudge factor
13 | -1 - default smushmode for this font (like "-m 0" on command line)
14 | 15 - number of comment lines
15 |
16 | $ $@
17 | $ $@
18 | $ $@
19 | $ $@
20 | $ $@
21 | $ $@
22 | $ $@
23 | $ $@
24 | $ $@
25 | $ $@
26 | $ $@
27 | $ $@
28 | $ $@
29 | $ $@
30 | $ $@
31 | $ $@
32 | $ $@
33 | $ $@
34 | $ $@
35 | $ $@
36 | $ $@@
37 | @
38 | @
39 | @
40 | @
41 | @
42 | @
43 | @
44 | @
45 | @
46 | e$@
47 | x$@
48 | c$@
49 | l$@
50 | a$@
51 | m$@
52 | a$@
53 | t$@
54 | i$@
55 | o$@
56 | n$@
57 | @@
58 | @
59 | @
60 | @
61 | @
62 | @
63 | @
64 | @
65 | @
66 | @
67 | d$@
68 | o$@
69 | u$@
70 | b$@
71 | l$@
72 | e$@
73 | q$@
74 | u$@
75 | o$@
76 | t$@
77 | e$@
78 | @@
79 | @
80 | @
81 | @
82 | @
83 | @
84 | @
85 | @
86 | @
87 | @
88 | @
89 | @
90 | @
91 | @
92 | @
93 | @
94 | p$@
95 | o$@
96 | u$@
97 | n$@
98 | d$@
99 | @@
100 | @
101 | @
102 | @
103 | @
104 | @
105 | @
106 | @
107 | @
108 | @
109 | @
110 | @
111 | @
112 | @
113 | @
114 | d$@
115 | o$@
116 | l$@
117 | l$@
118 | a$@
119 | r$@
120 | @@
121 | @
122 | @
123 | @
124 | @
125 | @
126 | @
127 | @
128 | @
129 | @
130 | @
131 | @
132 | @
133 | @
134 | p$@
135 | e$@
136 | r$@
137 | c$@
138 | e$@
139 | n$@
140 | t$@
141 | @@
142 | @
143 | @
144 | @
145 | @
146 | @
147 | @
148 | @
149 | @
150 | @
151 | @
152 | @
153 | a$@
154 | m$@
155 | p$@
156 | e$@
157 | r$@
158 | s$@
159 | a$@
160 | n$@
161 | d$@
162 | @@
163 | @
164 | @
165 | @
166 | @
167 | @
168 | @
169 | @
170 | @
171 | @
172 | s$@
173 | i$@
174 | n$@
175 | g$@
176 | l$@
177 | e$@
178 | q$@
179 | u$@
180 | o$@
181 | t$@
182 | e$@
183 | @@
184 | @
185 | @
186 | @
187 | @
188 | @
189 | @
190 | o$@
191 | p$@
192 | e$@
193 | n$@
194 | p$@
195 | a$@
196 | r$@
197 | e$@
198 | n$@
199 | t$@
200 | h$@
201 | e$@
202 | s$@
203 | y$@
204 | @@
205 | @
206 | @
207 | @
208 | @
209 | @
210 | c$@
211 | l$@
212 | o$@
213 | s$@
214 | e$@
215 | p$@
216 | a$@
217 | r$@
218 | e$@
219 | n$@
220 | t$@
221 | h$@
222 | e$@
223 | s$@
224 | y$@
225 | @@
226 | @
227 | @
228 | @
229 | @
230 | @
231 | @
232 | @
233 | @
234 | @
235 | @
236 | @
237 | @
238 | a$@
239 | s$@
240 | t$@
241 | e$@
242 | r$@
243 | i$@
244 | s$@
245 | t$@
246 | @@
247 | @
248 | @
249 | @
250 | @
251 | @
252 | @
253 | @
254 | @
255 | @
256 | @
257 | @
258 | @
259 | @
260 | @
261 | @
262 | @
263 | p$@
264 | l$@
265 | u$@
266 | s$@
267 | @@
268 | @
269 | @
270 | @
271 | @
272 | @
273 | @
274 | @
275 | @
276 | @
277 | @
278 | @
279 | @
280 | @
281 | @
282 | @
283 | c$@
284 | o$@
285 | m$@
286 | m$@
287 | a$@
288 | @@
289 | @
290 | @
291 | @
292 | @
293 | @
294 | @
295 | @
296 | @
297 | @
298 | @
299 | @
300 | @
301 | @
302 | @
303 | @
304 | m$@
305 | i$@
306 | n$@
307 | u$@
308 | s$@
309 | @@
310 | @
311 | @
312 | @
313 | @
314 | @
315 | @
316 | @
317 | @
318 | @
319 | @
320 | @
321 | @
322 | @
323 | @
324 | p$@
325 | e$@
326 | r$@
327 | i$@
328 | o$@
329 | d$@
330 | @@
331 | @
332 | @
333 | @
334 | @
335 | @
336 | @
337 | @
338 | @
339 | @
340 | @
341 | @
342 | @
343 | @
344 | @
345 | @
346 | s$@
347 | l$@
348 | a$@
349 | s$@
350 | h$@
351 | @@
352 | @
353 | @
354 | @
355 | @
356 | @
357 | @
358 | @
359 | @
360 | @
361 | @
362 | @
363 | @
364 | @
365 | n$@
366 | u$@
367 | m$@
368 | b$@
369 | e$@
370 | r$@
371 | 0$@
372 | @@
373 | @
374 | @
375 | @
376 | @
377 | @
378 | @
379 | @
380 | @
381 | @
382 | @
383 | @
384 | @
385 | @
386 | n$@
387 | u$@
388 | m$@
389 | b$@
390 | e$@
391 | r$@
392 | 1$@
393 | @@
394 | @
395 | @
396 | @
397 | @
398 | @
399 | @
400 | @
401 | @
402 | @
403 | @
404 | @
405 | @
406 | @
407 | n$@
408 | u$@
409 | m$@
410 | b$@
411 | e$@
412 | r$@
413 | 2$@
414 | @@
415 | @
416 | @
417 | @
418 | @
419 | @
420 | @
421 | @
422 | @
423 | @
424 | @
425 | @
426 | @
427 | @
428 | n$@
429 | u$@
430 | m$@
431 | b$@
432 | e$@
433 | r$@
434 | 3$@
435 | @@
436 | @
437 | @
438 | @
439 | @
440 | @
441 | @
442 | @
443 | @
444 | @
445 | @
446 | @
447 | @
448 | @
449 | n$@
450 | u$@
451 | m$@
452 | b$@
453 | e$@
454 | r$@
455 | 4$@
456 | @@
457 | @
458 | @
459 | @
460 | @
461 | @
462 | @
463 | @
464 | @
465 | @
466 | @
467 | @
468 | @
469 | @
470 | n$@
471 | u$@
472 | m$@
473 | b$@
474 | e$@
475 | r$@
476 | 5$@
477 | @@
478 | @
479 | @
480 | @
481 | @
482 | @
483 | @
484 | @
485 | @
486 | @
487 | @
488 | @
489 | @
490 | @
491 | n$@
492 | u$@
493 | m$@
494 | b$@
495 | e$@
496 | r$@
497 | 6$@
498 | @@
499 | @
500 | @
501 | @
502 | @
503 | @
504 | @
505 | @
506 | @
507 | @
508 | @
509 | @
510 | @
511 | @
512 | n$@
513 | u$@
514 | m$@
515 | b$@
516 | e$@
517 | r$@
518 | 7$@
519 | @@
520 | @
521 | @
522 | @
523 | @
524 | @
525 | @
526 | @
527 | @
528 | @
529 | @
530 | @
531 | @
532 | @
533 | n$@
534 | u$@
535 | m$@
536 | b$@
537 | e$@
538 | r$@
539 | 8$@
540 | @@
541 | @
542 | @
543 | @
544 | @
545 | @
546 | @
547 | @
548 | @
549 | @
550 | @
551 | @
552 | @
553 | @
554 | n$@
555 | u$@
556 | m$@
557 | b$@
558 | e$@
559 | r$@
560 | 9$@
561 | @@
562 | @
563 | @
564 | @
565 | @
566 | @
567 | @
568 | @
569 | @
570 | @
571 | @
572 | @
573 | @
574 | @
575 | @
576 | @
577 | c$@
578 | o$@
579 | l$@
580 | o$@
581 | n$@
582 | @@
583 | @
584 | @
585 | @
586 | @
587 | @
588 | @
589 | @
590 | @
591 | @
592 | @
593 | @
594 | s$@
595 | e$@
596 | m$@
597 | i$@
598 | c$@
599 | o$@
600 | l$@
601 | o$@
602 | n$@
603 | @@
604 | @
605 | @
606 | @
607 | @
608 | @
609 | @
610 | @
611 | @
612 | @
613 | @
614 | @
615 | @
616 | @
617 | @
618 | l$@
619 | e$@
620 | s$@
621 | s$@
622 | e$@
623 | r$@
624 | @@
625 | @
626 | @
627 | @
628 | @
629 | @
630 | @
631 | @
632 | @
633 | @
634 | @
635 | @
636 | @
637 | @
638 | @
639 | @
640 | e$@
641 | q$@
642 | u$@
643 | a$@
644 | l$@
645 | @@
646 | @
647 | @
648 | @
649 | @
650 | @
651 | @
652 | @
653 | @
654 | @
655 | @
656 | @
657 | @
658 | @
659 | g$@
660 | r$@
661 | e$@
662 | a$@
663 | t$@
664 | e$@
665 | r$@
666 | @@
667 | @
668 | @
669 | @
670 | @
671 | @
672 | @
673 | @
674 | @
675 | @
676 | @
677 | @
678 | @
679 | q$@
680 | u$@
681 | e$@
682 | s$@
683 | t$@
684 | i$@
685 | o$@
686 | n$@
687 | @@
688 | @
689 | @
690 | @
691 | @
692 | @
693 | @
694 | @
695 | @
696 | @
697 | @
698 | @
699 | @
700 | @
701 | @
702 | @
703 | @
704 | @
705 | @
706 | a$@
707 | t$@
708 | @@
709 | @
710 | ██$ @
711 | █████$ @
712 | █ ███$ @
713 | ███$ @
714 | █ ██$ @
715 | █ ██$ @
716 | █ ██$ @
717 | █ ██$ @
718 | █ ██$ @
719 | █████████$ @
720 | █ ██$ @
721 | █ ██$ @
722 | █████ ██$ @
723 | █ ████ ██ █$@
724 | █ ██ ██$ @
725 | █$ @
726 | ██$ @
727 | @
728 | @
729 | @@
730 | @
731 | █████ ██$ @
732 | ██████ ███$ @
733 | ██ █ █ ██$ @
734 | █ █ █ ██$ @
735 | █ █ █$ @
736 | ██ ██ █$ @
737 | ██ ██ █$ @
738 | ██ ███$ @
739 | ██ ██ ███$ @
740 | ██ ██ ███$ @
741 | █ ██ ██$@
742 | █ ██$@
743 | ████ ███$ @
744 | █ ████████$ @
745 | █ ████$ @
746 | █$ @
747 | ██$ @
748 | @
749 | @
750 | @@
751 | @
752 | █ ███$ @
753 | █ ████ █$@
754 | █ █ ████$ @
755 | █ ██ ██$ @
756 | █ ███$ @
757 | ██ ██$ @
758 | ██ ██$ @
759 | ██ ██$ @
760 | ██ ██$ @
761 | ██ ██$ @
762 | ██ ██$ @
763 | ██ █ █$ @
764 | ███ █$ @
765 | ███████$ @
766 | ███$ @
767 | @
768 | @
769 | @
770 | @
771 | @@
772 | @
773 | █████ ██$ @
774 | ██████ ███$ @
775 | ██ █ █ ███$ @
776 | █ █ █ ███$ @
777 | █ █ ███$@
778 | ██ ██ ██$@
779 | ██ ██ ██$@
780 | ██ ██ ██$@
781 | ██ ██ ██$@
782 | ██ ██ ██$@
783 | █ ██ ██$@
784 | █ █$ @
785 | █████ █$ @
786 | █ █████████$ @
787 | █ ████$ @
788 | █$ @
789 | ██$ @
790 | @
791 | @
792 | @@
793 | @
794 | █████ ██$ @
795 | ██████ ████ █$@
796 | ██ █ █ ████$ @
797 | █ █ █ ██$ @
798 | █ █$ @
799 | ██ ██$ @
800 | ██ ██$ @
801 | ██ ██████$ @
802 | ██ █████$ @
803 | ██ ██$ @
804 | █ ██$ @
805 | █$ @
806 | ████ █$@
807 | █ ███████████$ @
808 | █ ██████$ @
809 | █$ @
810 | ██$ @
811 | @
812 | @
813 | @@
814 | @
815 | █████ ██$ @
816 | ██████ ████ █$@
817 | ██ █ █ ███$ @
818 | █ █ █ █$ @
819 | █ █$ @
820 | ██ ██$ @
821 | ██ ██$ @
822 | ██ ██████$ @
823 | ██ █████$ @
824 | ██ ██$ @
825 | █ ██$ @
826 | █$ @
827 | █████$ @
828 | █ █████$ @
829 | █ ███$ @
830 | █$ @
831 | ██$ @
832 | @
833 | @
834 | @@
835 | @
836 | █ ███$ @
837 | █ ████ █$ @
838 | █ █ ████$ @
839 | █ ██ ██$ @
840 | █ ███$ @
841 | ██ ██$ @
842 | ██ ██ ███$ @
843 | ██ ██ ████ █$@
844 | ██ ██ █ ████$ @
845 | ██ ███ ██$ @
846 | ██ ██ █$ @
847 | ██ █ █$ @
848 | ███ █$ @
849 | ███████$ @
850 | ███$ @
851 | @
852 | @
853 | @
854 | @
855 | @@
856 | @
857 | █████ ██$ @
858 | ██████ █ ████ █$@
859 | ██ █ █ █████$ @
860 | █ █ █ █ █$ @
861 | █ █ █$ @
862 | ██ ██ █$ @
863 | ██ ██ █$ @
864 | ██ ████████$ @
865 | ██ ██ █$ @
866 | ██ ██ ██$ @
867 | █ ██ ██$ @
868 | █ ██$ @
869 | ████ ██$ @
870 | █ █████ ██$ @
871 | █ ██$ @
872 | █$ @
873 | ██$ @
874 | @
875 | @
876 | @@
877 | @
878 | █████ █$@
879 | ██████ █$ @
880 | ██ █ █$ @
881 | █ █ █$ @
882 | █ █$ @
883 | ██ ██$ @
884 | ██ ██$ @
885 | ████ ██$ @
886 | █ ███ ██$ @
887 | ██ ██$ @
888 | ██ ██ ██$ @
889 | ███ █ █$ @
890 | ███ █$ @
891 | ██████$ @
892 | ███$ @
893 | @
894 | @
895 | @
896 | @
897 | @@
898 | @
899 | █████ ██$ @
900 | ██████ ████ █$@
901 | ██ █ █ ████$ @
902 | █ █ █ ██$ @
903 | █ █$ @
904 | ██ ██$ @
905 | ██ ██$ @
906 | ████ ██$ @
907 | █ ███ ██$ @
908 | ██ ██$ @
909 | ██ ██$ @
910 | ██ ██$ @
911 | ██ ██$ @
912 | █ █$ @
913 | ██ █$ @
914 | ████ █$ @
915 | █ █ ██$ @
916 | █ ██$ @
917 | █$ @
918 | @@
919 | @
920 | █████$ @
921 | ██████$ @
922 | ██ █ █ ██$ @
923 | █ █ █ ████ █$ @
924 | █ █ ████$ @
925 | ██ ██ █ ██$ @
926 | ██ ██ █$ @
927 | ██ █████$ @
928 | ██ ██ ███$ @
929 | ██ ██ ███$ @
930 | █ ██ ███$ @
931 | █ ███$ @
932 | ████ ███$ @
933 | █ █████ ███ █$@
934 | █ ███ ███$ @
935 | █$ @
936 | ██$ @
937 | @
938 | @
939 | @@
940 | @
941 | █████ █$ @
942 | ██████ █$ @
943 | ██ █ █$ @
944 | █ █ █$ @
945 | █ █$ @
946 | ██ ██$ @
947 | ██ ██$ @
948 | ██ ██$ @
949 | ██ ██$ @
950 | ██ ██$ @
951 | █ ██$ @
952 | █$ @
953 | ████ █$@
954 | █ █████████████$ @
955 | █ █████████$ @
956 | █$ @
957 | ██$ @
958 | @
959 | @
960 | @@
961 | @
962 | █████ ██ ██$ @
963 | ██████ █████ █████$ @
964 | ██ █ █ █████ █████$@
965 | █ █ █ █ ██ █ ██$ @
966 | █ █ █ █$ @
967 | ██ ██ █ █$ @
968 | ██ ██ █ █$ @
969 | ██ ██ █ █$ @
970 | ██ ██ █ █$ @
971 | ██ ██ █ ██$ @
972 | █ ██ █ ██$ @
973 | █ █ ██$ @
974 | ████ █ ██$ @
975 | █ █████ ██$ @
976 | █ ██$ @
977 | █$ @
978 | ██$ @
979 | @
980 | @
981 | @@
982 | @
983 | █████ █ ██$ @
984 | ██████ ██ ████ █$@
985 | ██ █ █ ██ ████$ @
986 | █ █ █ ██ █ █$ @
987 | █ █ ██ █$ @
988 | ██ ██ ██ █$ @
989 | ██ ██ ██ █$ @
990 | ██ ██ ██ █$ @
991 | ██ ██ ██ █$ @
992 | ██ ██ ██ █$ @
993 | █ ██ ███$ @
994 | █ ███$ @
995 | ████ ██$ @
996 | █ █████$ @
997 | █ ██$ @
998 | █$ @
999 | ██$ @
1000 | @
1001 | @
1002 | @@
1003 | @
1004 | █ ███$ @
1005 | █ ████$ @
1006 | █ █ ███$ @
1007 | █ ██ ███$ @
1008 | █ ███ ███$@
1009 | ██ ██ ██$@
1010 | ██ ██ ██$@
1011 | ██ ██ ██$@
1012 | ██ ██ ██$@
1013 | ██ ██ ██$@
1014 | ██ ██ ██$@
1015 | ██ █ █$ @
1016 | ███ █$ @
1017 | ███████$ @
1018 | ███$ @
1019 | @
1020 | @
1021 | @
1022 | @
1023 | @@
1024 | @
1025 | █████ ██$ @
1026 | ██████ ████$ @
1027 | ██ █ █ ███$ @
1028 | █ █ █ ███$@
1029 | █ █ ██$@
1030 | ██ ██ ██$@
1031 | ██ ██ ██$@
1032 | ████ ██ █$ @
1033 | █ ███ ██ █$ @
1034 | ██ ███████$ @
1035 | ██ ██████$ @
1036 | ██ ██$ @
1037 | ██ ██$ @
1038 | ██ ██$ @
1039 | ██ ██ ██$ @
1040 | ███ █ █$ @
1041 | ███ █$ @
1042 | ██████$ @
1043 | ███$ @
1044 | @@
1045 | @
1046 | █ ███$ @
1047 | █ ████$ @
1048 | █ █ ███$ @
1049 | █ ██ ███$ @
1050 | █ ███ ███$@
1051 | ██ ██ ██$@
1052 | ██ ██ ██$@
1053 | ██ ██ ██$@
1054 | ██ ██ ██$@
1055 | ██ ██ ██$@
1056 | ██ ██ ███ ██$@
1057 | ██ █ ████$ @
1058 | ███ ███$@
1059 | ███████ ██$@
1060 | ███ ██$@
1061 | ██$@
1062 | █$ @
1063 | █$ @
1064 | █$ @
1065 | @@
1066 | @
1067 | █████ ███$ @
1068 | ██████ █ ██$ @
1069 | ██ █ █ ██$ @
1070 | █ █ █ ██$ @
1071 | █ █ █$ @
1072 | ██ ██ █$ @
1073 | ██ ██ █$ @
1074 | ██ ████$ @
1075 | ██ ██ ███$ @
1076 | ██ ██ ██$ @
1077 | █ ██ ██$ @
1078 | █ ██$ @
1079 | ████ ███$@
1080 | █ ████ ██$ @
1081 | █ ██ █$ @
1082 | █$ @
1083 | ██$ @
1084 | @
1085 | @
1086 | @@
1087 | @
1088 | ███████$ @
1089 | █ ███$ @
1090 | █ ██$ @
1091 | ██ █$ @
1092 | ███$ @
1093 | ██ ███$ @
1094 | ███ ███$ @
1095 | ███ ███$ @
1096 | ███ ███$ @
1097 | ██ ███$@
1098 | ██ ██$@
1099 | █ █$ @
1100 | ███ █$ @
1101 | █ █████████$ @
1102 | █ █████$ @
1103 | █$ @
1104 | ██$ @
1105 | @
1106 | @
1107 | @@
1108 | @
1109 | ████ █$@
1110 | █ █████████████$ @
1111 | █ █████████$ @
1112 | █ █ █$ @
1113 | ██ █ ██$ @
1114 | █ ███$ @
1115 | ██ ██$ @
1116 | ██ ██$ @
1117 | ██ ██$ @
1118 | ██ ██$ @
1119 | ██ ██$ @
1120 | ██ █ █$ @
1121 | ███ █$ @
1122 | ███████$ @
1123 | ███$ @
1124 | @
1125 | @
1126 | @
1127 | @
1128 | @@
1129 | @
1130 | █████ █ ██$ @
1131 | ██████ █ █████$ @
1132 | ██ █ █ █████$@
1133 | █ █ ██ █ ██$ @
1134 | █ ███ █$ @
1135 | ██ ██ █$ @
1136 | ██ ██ █$ @
1137 | ██ ██ █$ @
1138 | ██ ██ █$ @
1139 | ██ ██ █$ @
1140 | ██ ██ █$ @
1141 | ██ █ █$ @
1142 | ███ █$ @
1143 | ████████$ @
1144 | ████$ @
1145 | @
1146 | @
1147 | @
1148 | @
1149 | @@
1150 | @
1151 | █████ █ ██$ @
1152 | ██████ █ █████$ @
1153 | ██ █ █ █████$@
1154 | █ █ ██ █ ██$ @
1155 | █ ███ █$ @
1156 | ██ ██ █$ @
1157 | ██ ██ █$ @
1158 | ██ ██ █$ @
1159 | ██ ██ █$ @
1160 | ██ ██ █$ @
1161 | ██ ██ █$ @
1162 | ██ █ █$ @
1163 | ███ █$ @
1164 | ███████$ @
1165 | ███$ @
1166 | @
1167 | @
1168 | @
1169 | @
1170 | @@
1171 | @
1172 | █████ █ ██ ███$ @
1173 | ██████ █ █████ ███$ @
1174 | ██ █ █ █████ ███$ @
1175 | █ █ ██ █ ██ ██$@
1176 | █ ███ █ ██$@
1177 | ██ ██ █ ██$@
1178 | ██ ██ █ ██$@
1179 | ██ ██ █ ██$@
1180 | ██ ██ █ ██$@
1181 | ██ ██ █ ██$@
1182 | ██ ██ █ ██$@
1183 | ██ █ █ █$ @
1184 | ███ ███ █$ @
1185 | ████████ ████████$ @
1186 | ████ ████$ @
1187 | @
1188 | @
1189 | @
1190 | @
1191 | @@
1192 | @
1193 | ███ ██$ @
1194 | █████ ████ █$ @
1195 | █ ███ ██████$ @
1196 | ███ █ ██$ @
1197 | ███ █$ @
1198 | ████$ @
1199 | ███$ @
1200 | ████$ @
1201 | █ ███$ @
1202 | █ ███$ @
1203 | █ ███$ @
1204 | █ ███$ @
1205 | █ ███ █$@
1206 | █ █████$ @
1207 | █ ███$ @
1208 | @
1209 | @
1210 | @
1211 | @
1212 | @@
1213 | @
1214 | █████ █ ██$ @
1215 | ██████ █ █████$ @
1216 | ██ █ █ █████$@
1217 | █ █ ██ █ ██$ @
1218 | █ ███ █$ @
1219 | ██ ██ █$ @
1220 | ██ ██ █$ @
1221 | ██ ██ █$ @
1222 | ██ ██ █$ @
1223 | ██ ██ █$ @
1224 | ██ ██ █$ @
1225 | ██ █ █$ @
1226 | ███ █$ @
1227 | █████████$ @
1228 | ████ ███$ @
1229 | ███$ @
1230 | ████████ ███$ @
1231 | █████████████ ██$ @
1232 | █ ████$ @
1233 | @@
1234 | @
1235 | ████ █$@
1236 | █ █████████████$ @
1237 | █ ██████████$ @
1238 | █ █$ @
1239 | ██ █$ @
1240 | █$ @
1241 | █$ @
1242 | █$ @
1243 | █$ @
1244 | █$ @
1245 | █$ @
1246 | █$ @
1247 | ████ █$@
1248 | █ █████████████$ @
1249 | █ ██████████$ @
1250 | @
1251 | @
1252 | @
1253 | @
1254 | @@
1255 | @
1256 | @
1257 | @
1258 | @
1259 | @
1260 | @
1261 | @
1262 | @
1263 | @
1264 | l$@
1265 | e$@
1266 | f$@
1267 | t$@
1268 | b$@
1269 | r$@
1270 | a$@
1271 | c$@
1272 | k$@
1273 | e$@
1274 | t$@
1275 | @@
1276 | @
1277 | @
1278 | @
1279 | @
1280 | @
1281 | @
1282 | @
1283 | @
1284 | @
1285 | @
1286 | @
1287 | b$@
1288 | a$@
1289 | c$@
1290 | k$@
1291 | s$@
1292 | l$@
1293 | a$@
1294 | s$@
1295 | h$@
1296 | @@
1297 | @
1298 | @
1299 | @
1300 | @
1301 | @
1302 | @
1303 | @
1304 | @
1305 | r$@
1306 | i$@
1307 | g$@
1308 | h$@
1309 | t$@
1310 | b$@
1311 | r$@
1312 | a$@
1313 | c$@
1314 | k$@
1315 | e$@
1316 | t$@
1317 | @@
1318 | @
1319 | @
1320 | @
1321 | @
1322 | @
1323 | @
1324 | @
1325 | @
1326 | @
1327 | @
1328 | @
1329 | @
1330 | @
1331 | @
1332 | @
1333 | c$@
1334 | a$@
1335 | r$@
1336 | e$@
1337 | t$@
1338 | @@
1339 | @
1340 | @
1341 | @
1342 | @
1343 | @
1344 | @
1345 | @
1346 | @
1347 | @
1348 | @
1349 | u$@
1350 | n$@
1351 | d$@
1352 | e$@
1353 | r$@
1354 | s$@
1355 | c$@
1356 | o$@
1357 | r$@
1358 | e$@
1359 | @@
1360 | @
1361 | @
1362 | @
1363 | @
1364 | @
1365 | @
1366 | @
1367 | @
1368 | @
1369 | @
1370 | @
1371 | l$@
1372 | e$@
1373 | f$@
1374 | t$@
1375 | q$@
1376 | u$@
1377 | o$@
1378 | t$@
1379 | e$@
1380 | @@
1381 | @
1382 | @
1383 | @
1384 | @
1385 | @
1386 | @
1387 | ████$ @
1388 | █ ███ █$@
1389 | █ ████$ @
1390 | ██ ██$ @
1391 | ██ ██$ @
1392 | ██ ██$ @
1393 | ██ ██$ @
1394 | ██ ██$ @
1395 | █████ ██$ @
1396 | ███ ██$@
1397 | @
1398 | @
1399 | @
1400 | @
1401 | @@
1402 | @
1403 | █$ @
1404 | ██$ @
1405 | ██$ @
1406 | ██$ @
1407 | ██$ @
1408 | ██ ████$ @
1409 | ███ ███ █$@
1410 | ██ ████$ @
1411 | ██ ██$ @
1412 | ██ ██$ @
1413 | ██ ██$ @
1414 | ██ ██$ @
1415 | ██ ██$ @
1416 | █████$ @
1417 | ███$ @
1418 | @
1419 | @
1420 | @
1421 | @
1422 | @@
1423 | @
1424 | @
1425 | @
1426 | @
1427 | @
1428 | @
1429 | ████$ @
1430 | █ ███ █$@
1431 | █ ████$ @
1432 | ██$ @
1433 | ██$ @
1434 | ██$ @
1435 | ██$ @
1436 | ███ █$ @
1437 | ███████$ @
1438 | █████$ @
1439 | @
1440 | @
1441 | @
1442 | @
1443 | @@
1444 | @
1445 | ██$ @
1446 | ██$ @
1447 | ██$ @
1448 | ██$ @
1449 | ██$ @
1450 | ███ ██$ @
1451 | █████████$@
1452 | ██ ████$ @
1453 | ██ ██$ @
1454 | ██ ██$ @
1455 | ██ ██$ @
1456 | ██ ██$ @
1457 | ██ ██$ @
1458 | █████$ @
1459 | ███$ @
1460 | @
1461 | @
1462 | @
1463 | @
1464 | @@
1465 | @
1466 | @
1467 | @
1468 | @
1469 | @
1470 | @
1471 | ███$ @
1472 | █ ███$ @
1473 | █ ███$ @
1474 | ██ ███$@
1475 | ████████$ @
1476 | ███████$ @
1477 | ██$ @
1478 | ████ █$@
1479 | ███████$ @
1480 | █████$ @
1481 | @
1482 | @
1483 | @
1484 | @
1485 | @@
1486 | @
1487 | ███$ @
1488 | ██ ███$ @
1489 | ██ ███$@
1490 | ██$ @
1491 | ██$ @
1492 | ██████$ @
1493 | █████$ @
1494 | ██$ @
1495 | ██$ @
1496 | ██$ @
1497 | ██$ @
1498 | ██$ @
1499 | ██$ @
1500 | ██$ @
1501 | ██$ @
1502 | @
1503 | @
1504 | @
1505 | @
1506 | @@
1507 | @
1508 | @
1509 | @
1510 | @
1511 | @
1512 | @
1513 | ████$ @
1514 | █ ███ █$ @
1515 | █ ████$ @
1516 | ██ ██$ @
1517 | ██ ██$ @
1518 | ██ ██$ @
1519 | ██ ██$ @
1520 | ██ ██$ @
1521 | ████████$ @
1522 | ███ ███$ @
1523 | ███$ @
1524 | ████ ███$@
1525 | ███████ ██$ @
1526 | █ ████$ @
1527 | @@
1528 | @
1529 | █$ @
1530 | ██$ @
1531 | ██$ @
1532 | ██$ @
1533 | ██$ @
1534 | ██ ███$ @
1535 | ██ █ ███$ @
1536 | ███ ███$@
1537 | ██ ██$@
1538 | ██ ██$@
1539 | ██ ██$@
1540 | ██ ██$@
1541 | ██ ██$@
1542 | ██ ██$@
1543 | ██ ██$@
1544 | █$ @
1545 | █$ @
1546 | █$ @
1547 | █$ @
1548 | @@
1549 | @
1550 | @
1551 | █$ @
1552 | ███$ @
1553 | █$ @
1554 | @
1555 | ███$ @
1556 | ███$ @
1557 | ██$ @
1558 | ██$ @
1559 | ██$ @
1560 | ██$ @
1561 | ██$ @
1562 | ██$ @
1563 | ███ █$@
1564 | ███$ @
1565 | @
1566 | @
1567 | @
1568 | @
1569 | @@
1570 | @
1571 | @
1572 | █$ @
1573 | ███$ @
1574 | █$ @
1575 | @
1576 | ███$ @
1577 | ███$ @
1578 | ██$ @
1579 | █$ @
1580 | █$ @
1581 | ███$ @
1582 | ███$ @
1583 | ███$ @
1584 | ███$@
1585 | ██$@
1586 | ██$@
1587 | █$ @
1588 | █$ @
1589 | █$ @
1590 | @@
1591 | @
1592 | █$ @
1593 | ██$ @
1594 | ██$ @
1595 | ██$ @
1596 | ██$ @
1597 | ██ ███$ @
1598 | ██ █ ███$ @
1599 | ███ █$ @
1600 | ██ █$ @
1601 | ██ █$ @
1602 | ██ ██$ @
1603 | ██████$ @
1604 | ██ ███$ @
1605 | ██ ███ █$@
1606 | ██ ███$ @
1607 | @
1608 | @
1609 | @
1610 | @
1611 | @@
1612 | @
1613 | ███$ @
1614 | ███$ @
1615 | ██$ @
1616 | ██$ @
1617 | ██$ @
1618 | ██$ @
1619 | ██$ @
1620 | ██$ @
1621 | ██$ @
1622 | ██$ @
1623 | ██$ @
1624 | ██$ @
1625 | ██$ @
1626 | ███ █$@
1627 | ███$ @
1628 | @
1629 | @
1630 | @
1631 | @
1632 | @@
1633 | @
1634 | @
1635 | @
1636 | @
1637 | @
1638 | @
1639 | ███ ████ ████$ @
1640 | ███ ████ ███ █$@
1641 | ██ ████ ████$ @
1642 | ██ ██ ██$ @
1643 | ██ ██ ██$ @
1644 | ██ ██ ██$ @
1645 | ██ ██ ██$ @
1646 | ██ ██ ██$ @
1647 | ███ ███ ███$ @
1648 | ███ ███ ███$@
1649 | @
1650 | @
1651 | @
1652 | @
1653 | @@
1654 | @
1655 | @
1656 | @
1657 | @
1658 | @
1659 | @
1660 | ███ ████$ @
1661 | ████ ████ █$@
1662 | ██ ████$ @
1663 | ██ ██$ @
1664 | ██ ██$ @
1665 | ██ ██$ @
1666 | ██ ██$ @
1667 | ██ ██$ @
1668 | ███ ███$ @
1669 | ███ ███$@
1670 | @
1671 | @
1672 | @
1673 | @
1674 | @@
1675 | @
1676 | @
1677 | @
1678 | @
1679 | @
1680 | ████$ @
1681 | █ ███ █$@
1682 | █ ████$ @
1683 | ██ ██$ @
1684 | ██ ██$ @
1685 | ██ ██$ @
1686 | ██ ██$ @
1687 | ██ ██$ @
1688 | ██████$ @
1689 | ████$ @
1690 | @
1691 | @
1692 | @
1693 | @
1694 | @
1695 | @@
1696 | @
1697 | @
1698 | @
1699 | @
1700 | @
1701 | ████$ @
1702 | █ ███ █$@
1703 | █ ████$ @
1704 | ██ ██$ @
1705 | ██ ██$ @
1706 | ██ ██$ @
1707 | ██ ██$ @
1708 | ██ ██$ @
1709 | ███████$ @
1710 | ██████$ @
1711 | ██$ @
1712 | ██$ @
1713 | ██$ @
1714 | ██$ @
1715 | @
1716 | @@
1717 | @
1718 | @
1719 | @
1720 | @
1721 | @
1722 | ████$ @
1723 | █ ███ █$@
1724 | █ ████$ @
1725 | ██ ██$ @
1726 | ██ ██$ @
1727 | ██ ██$ @
1728 | ██ ██$ @
1729 | ██ ██$ @
1730 | ███████$ @
1731 | ██████$ @
1732 | ██$ @
1733 | ██$ @
1734 | ██$ @
1735 | ██$ @
1736 | @
1737 | @@
1738 | @
1739 | @
1740 | @
1741 | @
1742 | @
1743 | ███ ████$ @
1744 | ████ ████ █$@
1745 | ██ ████$ @
1746 | ██$ @
1747 | ██$ @
1748 | ██$ @
1749 | ██$ @
1750 | ██$ @
1751 | ███$ @
1752 | ███$ @
1753 | @
1754 | @
1755 | @
1756 | @
1757 | @
1758 | @@
1759 | @
1760 | @
1761 | @
1762 | @
1763 | @
1764 | ████$ @
1765 | █ ████ █$@
1766 | ██ ████$ @
1767 | ████$ @
1768 | ███$ @
1769 | ███$ @
1770 | ███$ @
1771 | ████ ██$ @
1772 | █ ████ █$ @
1773 | ████$ @
1774 | @
1775 | @
1776 | @
1777 | @
1778 | @
1779 | @@
1780 | @
1781 | @
1782 | █$ @
1783 | ██$ @
1784 | ██$ @
1785 | ████████$@
1786 | ████████$ @
1787 | ██$ @
1788 | ██$ @
1789 | ██$ @
1790 | ██$ @
1791 | ██$ @
1792 | ██$ @
1793 | ██$ @
1794 | ██$ @
1795 | @
1796 | @
1797 | @
1798 | @
1799 | @
1800 | @@
1801 | @
1802 | @
1803 | @
1804 | @
1805 | @
1806 | ██ ████$ @
1807 | ██ ███ █$@
1808 | ██ ████$ @
1809 | ██ ██$ @
1810 | ██ ██$ @
1811 | ██ ██$ @
1812 | ██ ██$ @
1813 | ██ ██$ @
1814 | ███████ ██$ @
1815 | █████ ██$@
1816 | @
1817 | @
1818 | @
1819 | @
1820 | @
1821 | @@
1822 | @
1823 | @
1824 | @
1825 | ██$ @
1826 | ██$ @
1827 | ██ ███$ @
1828 | ██ ███$ @
1829 | ██ ███$@
1830 | ██ ██$@
1831 | ██ ██$@
1832 | ██ ██$@
1833 | ██ ██$@
1834 | ██ █$ @
1835 | ███████$ @
1836 | █████$ @
1837 | @
1838 | @
1839 | @
1840 | @
1841 | @
1842 | @@
1843 | @
1844 | @
1845 | @
1846 | ██$ @
1847 | ██$ @
1848 | ██ ███ ████$ @
1849 | ██ ███ ███ █$@
1850 | ██ ███ ████$ @
1851 | ██ ██ ██$ @
1852 | ██ ██ ██$ @
1853 | ██ ██ ██$ @
1854 | ██ ██ ██$ @
1855 | ██ ██ █$ @
1856 | ███████ ███████$ @
1857 | █████ █████ $ @
1858 | @
1859 | @
1860 | @
1861 | @
1862 | @
1863 | @@
1864 | @
1865 | @
1866 | @
1867 | @
1868 | @
1869 | ███ ███$ @
1870 | █ ███ ████ █$ @
1871 | ███ █████$ @
1872 | ███ ██$ @
1873 | ███$ @
1874 | █ ███$ @
1875 | █ ███$ @
1876 | █ ███$ @
1877 | █ ███ █$@
1878 | █ ███$ @
1879 | @
1880 | @
1881 | @
1882 | @
1883 | @
1884 | @@
1885 | @
1886 | @
1887 | @
1888 | @
1889 | @
1890 | ██ ████$ @
1891 | ██ ███ █$ @
1892 | ██ ████$ @
1893 | ██ ██$ @
1894 | ██ ██$ @
1895 | ██ ██$ @
1896 | ██ ██$ @
1897 | ██ ██$ @
1898 | █████████$ @
1899 | ████ ███$ @
1900 | ███$ @
1901 | █████ ███$@
1902 | ████████ ██$ @
1903 | █ ████$ @
1904 | @
1905 | @@
1906 | @
1907 | @
1908 | @
1909 | @
1910 | @
1911 | ██████$ @
1912 | ████████$ @
1913 | █ ██$ @
1914 | █$ @
1915 | █$ @
1916 | ███$ @
1917 | ███$ @
1918 | ███$@
1919 | ██$@
1920 | ██$@
1921 | █$ @
1922 | █$ @
1923 | █$ @
1924 | █$ @
1925 | @
1926 | @@
1927 | @
1928 | @
1929 | @
1930 | @
1931 | l$@
1932 | e$@
1933 | f$@
1934 | t$@
1935 | c$@
1936 | u$@
1937 | r$@
1938 | l$@
1939 | y$@
1940 | b$@
1941 | r$@
1942 | a$@
1943 | c$@
1944 | k$@
1945 | e$@
1946 | t$@
1947 | @@
1948 | @
1949 | @
1950 | @
1951 | @
1952 | @
1953 | @
1954 | @
1955 | @
1956 | @
1957 | @
1958 | @
1959 | @
1960 | @
1961 | @
1962 | @
1963 | @
1964 | p$@
1965 | i$@
1966 | p$@
1967 | e$@
1968 | @@
1969 | @
1970 | @
1971 | @
1972 | r$@
1973 | i$@
1974 | g$@
1975 | h$@
1976 | t$@
1977 | c$@
1978 | r$@
1979 | u$@
1980 | l$@
1981 | y$@
1982 | b$@
1983 | r$@
1984 | a$@
1985 | c$@
1986 | k$@
1987 | e$@
1988 | t$@
1989 | @@
1990 | @
1991 | @
1992 | @
1993 | @
1994 | @
1995 | @
1996 | @
1997 | @
1998 | @
1999 | @
2000 | @
2001 | @
2002 | @
2003 | @
2004 | @
2005 | t$@
2006 | i$@
2007 | d$@
2008 | l$@
2009 | e$@
2010 | @@
2011 | @
2012 | @
2013 | @
2014 | @
2015 | @
2016 | @
2017 | @
2018 | @
2019 | @
2020 | @
2021 | @
2022 | @
2023 | @
2024 | @
2025 | @
2026 | @
2027 | @
2028 | @
2029 | @
2030 | @
2031 | @@
2032 | @
2033 | @
2034 | @
2035 | @
2036 | @
2037 | @
2038 | @
2039 | @
2040 | @
2041 | @
2042 | @
2043 | @
2044 | @
2045 | @
2046 | @
2047 | @
2048 | @
2049 | @
2050 | @
2051 | @
2052 | @@
2053 | @
2054 | @
2055 | @
2056 | @
2057 | @
2058 | @
2059 | @
2060 | @
2061 | @
2062 | @
2063 | @
2064 | @
2065 | @
2066 | @
2067 | @
2068 | @
2069 | @
2070 | @
2071 | @
2072 | @
2073 | @@
2074 | @
2075 | @
2076 | @
2077 | @
2078 | @
2079 | @
2080 | @
2081 | @
2082 | @
2083 | @
2084 | @
2085 | @
2086 | @
2087 | @
2088 | @
2089 | @
2090 | @
2091 | @
2092 | @
2093 | @
2094 | @@
2095 | @
2096 | @
2097 | @
2098 | @
2099 | @
2100 | @
2101 | @
2102 | @
2103 | @
2104 | @
2105 | @
2106 | @
2107 | @
2108 | @
2109 | @
2110 | @
2111 | @
2112 | @
2113 | @
2114 | @
2115 | @@
2116 | @
2117 | @
2118 | @
2119 | @
2120 | @
2121 | @
2122 | @
2123 | @
2124 | @
2125 | @
2126 | @
2127 | @
2128 | @
2129 | @
2130 | @
2131 | @
2132 | @
2133 | @
2134 | @
2135 | @
2136 | @@
2137 | @
2138 | @
2139 | @
2140 | @
2141 | @
2142 | @
2143 | @
2144 | @
2145 | @
2146 | @
2147 | @
2148 | @
2149 | @
2150 | @
2151 | @
2152 | @
2153 | @
2154 | @
2155 | @
2156 | @
2157 | @@
2158 |
--------------------------------------------------------------------------------