From 22fd1e95abdec7f1e9187a0d0f71b50aafc8b167 Mon Sep 17 00:00:00 2001 From: jared bw Date: Tue, 23 Mar 2021 11:43:30 +0000 Subject: [PATCH 1/2] Added namespacing, documentation, also renamed stuff with standard naming conventions (not that they matter... easier to read i guess), also mightve slightly increased the speed, such as not creating a 30kb buffer every time the game renders --- .vs/ProjectSettings.json | 3 + .vs/slnx.sqlite | Bin 0 -> 221184 bytes FrameBuffer.cs | 71 - Game.cs | 190 +++ Material.cs | 28 - Maths/MathHelper.cs | 51 + Maths/Matrix.cs | 34 + Maths/Triangle.cs | 34 + Maths/Vector2.cs | 13 + Maths/Vector3.cs | 108 ++ Matrix.cs | 67 - Mesh.cs | 125 -- Program.cs | 238 --- Rasterize.cs | 366 ----- Render/FrameBuffer.cs | 78 + Render/Light.cs | 16 + Render/Material.cs | 27 + Render/Mesh.cs | 159 ++ Render/Rasterize.cs | 379 +++++ .../Textures/YoungLink.bmp | Bin levels.txt => Resources/levels.txt | 0 Utils/ThreeState.cs | 17 + csbuild.csproj | 24 +- link.obj | 1340 ----------------- 24 files changed, 1124 insertions(+), 2244 deletions(-) create mode 100644 .vs/ProjectSettings.json create mode 100644 .vs/slnx.sqlite delete mode 100644 FrameBuffer.cs create mode 100644 Game.cs delete mode 100644 Material.cs create mode 100644 Maths/MathHelper.cs create mode 100644 Maths/Matrix.cs create mode 100644 Maths/Triangle.cs create mode 100644 Maths/Vector2.cs create mode 100644 Maths/Vector3.cs delete mode 100644 Matrix.cs delete mode 100644 Mesh.cs delete mode 100644 Program.cs delete mode 100644 Rasterize.cs create mode 100644 Render/FrameBuffer.cs create mode 100644 Render/Light.cs create mode 100644 Render/Material.cs create mode 100644 Render/Mesh.cs create mode 100644 Render/Rasterize.cs rename YoungLink.bmp => Resources/Textures/YoungLink.bmp (100%) rename levels.txt => Resources/levels.txt (100%) create mode 100644 Utils/ThreeState.cs delete mode 100644 link.obj diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json new file mode 100644 index 0000000..f8b4888 --- /dev/null +++ b/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": null +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..2ae2e41da9c6a49c7bfe38a6816191e738d23f6f GIT binary patch literal 221184 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 literal 0 HcmV?d00001 diff --git a/FrameBuffer.cs b/FrameBuffer.cs deleted file mode 100644 index ce19694..0000000 --- a/FrameBuffer.cs +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Print image to screen. - * - * Just 'draw' the byte array to the buffer. - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.IO; - -namespace ConsoleGraphics -{ - class FrameBuffer : Program - { - private static int lastTime; - private static int numRenderings = 0; - private const short sampleSize = 100; - private string lastFrame = ""; - Stream s = Console.OpenStandardOutput(); - - private void vSync(short targetFrameRate, int delay, int startDrawTime) - { - //Synchronize frames and display framerate to the lower right corner of the render window - int targetDelay = 1000 / targetFrameRate; - if (delay < targetDelay && VSYNC_ON)//we're too fast - { - System.Threading.Thread.Sleep(targetDelay - delay); - } - - if (numRenderings == sampleSize) - { - int y = Environment.TickCount - lastTime; - if (y != 0) - printch((sampleSize * 1000 / y).ToString().ToCharArray(), RENDER_WIDTH - 50, RENDER_HEIGHT + 1); - numRenderings = 0; - } - } - - public void drawFrame(byte[,] image, int a = 0, int b = 0) - { - //use cudafy / multithreading to paint quickly, also invoke writetoconsole? - byte[] bufImg = new byte[RENDER_HEIGHT * RENDER_WIDTH]; - - for (int x = 0; x < RENDER_WIDTH; x++) - for (int y = 0; y < RENDER_HEIGHT; y++) - bufImg[x+y*RENDER_WIDTH] = image[x,y]; - int beginRender = Environment.TickCount; - - Console.SetCursorPosition(a, b); - //.Flush(); - //string iString = bufImg.ToString(); - //byte[] b = Encoding.UTF8.GetBytes(iString); - //if (string.Compare(lastFrame, iString) != 0) - //{ - s.Write(bufImg, 0, bufImg.Length); - // lastFrame = iString; - //} - int endRender = Environment.TickCount - beginRender; - - vSync(MAX_FPS, endRender, beginRender); - - if (numRenderings == 0) - lastTime = Environment.TickCount; - - numRenderings++; - } - } -} diff --git a/Game.cs b/Game.cs new file mode 100644 index 0000000..b67affe --- /dev/null +++ b/Game.cs @@ -0,0 +1,190 @@ +using System; +using System.Threading; +using System.IO; +using ConsoleGraphics.Maths; +using ConsoleGraphics.Render; +using ConsoleGraphics.Utils; + +namespace ConsoleGraphics +{ + public static class Game + { + //special characters:█ ▄ ▀ ■ + //public bool FRAMERATE_ON = true; + + public static bool USE_VSYNC = false; + public static ThreeState renderState = new ThreeState(0); + public const short RENDER_WIDTH = 300; + public const short RENDER_HEIGHT = 100; + public const short MAX_FPS = 1000; + public const float PI = (float)3.1415926535; + + //static char[, ,] numerals = new char[9, 8, 10]; + public static char[] levels; + + public static volatile Mesh ActiveMesh = null; + public static Light light1 = new Light(0, 0, 0, 700); + + public static void Main(string[] args) + { + try + { + ActiveMesh = Mesh.LoadMeshFromFile(@"Resources\Meshes\link.obj"); + } + catch(Exception e) + { + Console.WriteLine($"Failed to load mesh: {e.Message}"); + Console.Read(); + return; + } + + //BrightnessInit.go(); + //BrightnessInit.sortstuff(); + GameInit(RENDER_WIDTH, RENDER_HEIGHT, "render"); + ActiveMesh.Translate(new Vector3(-800, -300, -8)); + //someShape.rotate((float)0.25); + + FrameBuffer.DrawFrame(Rasterizer.RenderSolid(ActiveMesh)); + //Console.ReadLine(); + //someShape.rotate((float)(3.1415)); + + // render loop + while (true) + { + //light1.intensity = (int)((double)800 * Math.Sin(4*i)); + //someShape.rotate(0.005, 0); + //someShape.rotate(0.005, 1); + //someShape.rotate(0.005, 2); + //someShape.translate(new Mesh.point3((float)Math.Sin(i), 0, 0)); + // buffer.drawFrame(drawLine(new byte[RENDER_HEIGHT * RENDER_WIDTH], a1, a2)); + if (renderState.x == 0) + FrameBuffer.DrawFrame(Rasterizer.RenderSolid(ActiveMesh)); + else if (renderState.x == 1) + FrameBuffer.DrawFrame(Rasterizer.RenderVertices(ActiveMesh)); + else if (renderState.x == 2) + FrameBuffer.DrawFrame(Rasterizer.RenderWire(ActiveMesh)); + + //light1.coords.x = 1000 * (float)Math.Sin(i); + // light1.coords.y = 1000 * (float)Math.Sin(i); + //light1.coords.z = 100 * (float)Math.Sin(i); + //someShape.rotate((float)0.005, 0); + //someShape.rotate((float)0.005, 1); + } + } + + private static void GameInit(short width, short height, string title) + { + Console.Title = title; + Console.CursorVisible = false; + Console.BackgroundColor = ConsoleColor.Black; + + SetConsoleSize(width, height); + + //clear colors from user preset. + Console.Clear(); + Console.SetCursorPosition(0, height); + Console.Write(new String('▄', RENDER_WIDTH)); + Console.ForegroundColor = ConsoleColor.Cyan; + + StreamReader levelsReader = new StreamReader("Resources\\levels.txt"); + + levels = new char[256]; + int index = 0; + while (!levelsReader.EndOfStream && index < 256) + { + string e1 = levelsReader.ReadLine(); + levels[index] = Char.Parse(e1); + index++; + } + + Thread inputThread = new Thread(MainGetInput); + inputThread.Start(); + //Thread soundPlayer = new Thread(playSound); + //soundPlayer.Start(); + } + + private static void SetConsoleSize(short width, short height) + { + // loop forever. only return when the window size and buffer size is set + while (true) + { + try + { + Console.SetWindowSize(width, height + 15); + Console.SetBufferSize(width, height + 15); + // exit the function allowing everything else to initialise + return; + } + catch (ArgumentOutOfRangeException) + { + Console.WriteLine("Decrease your font size and press enter"); + Console.WriteLine("You can resize the font using 'CTRL + MouseWheel'"); + Console.ReadLine(); + } + } + } + + private static byte[,] LoadTexture(string loc) + { + byte[,] loadedTexture = new byte[2, 2]; + return (loadedTexture); + } + + public static void printch(char[] charId, int x, int y) + { + Console.SetCursorPosition(0, RENDER_HEIGHT + 4); + Console.Write(new string(' ', 10)); + Console.SetCursorPosition(0, RENDER_HEIGHT + 4); + Console.Write(charId); + } + + private static void MainGetInput() + { + //Console.TreatControlCAsInput = true; + + while (true) + { + ConsoleKeyInfo keyInfo = Console.ReadKey(); + if (keyInfo.Key == ConsoleKey.Escape) + { + Environment.Exit(0); + return; + } + + switch (keyInfo.Key) + { + case ConsoleKey.Spacebar: + renderState.changeState(); + break; + case ConsoleKey.W: + ActiveMesh.Translate(0, 0, 0.1f); + break; + case ConsoleKey.A: + ActiveMesh.Translate(-10.0f, 0, 0); + break; + case ConsoleKey.S: + ActiveMesh.Translate(0, 0, -0.1f); + break; + case ConsoleKey.D: + ActiveMesh.Translate(10.0f, 0, 0); + break; + case ConsoleKey.R: + ActiveMesh.Rotate(0.01, 0); + break; + case ConsoleKey.T: + ActiveMesh.Rotate(0.01, 1); + break; + case ConsoleKey.Y: + ActiveMesh.Rotate(0.01, 2); + break; + case ConsoleKey.Q: + ActiveMesh.Translate(0, -10.0f, 0); + break; + case ConsoleKey.E: + ActiveMesh.Translate(0, 10.0f, 0); + break; + } + } + } + } +} diff --git a/Material.cs b/Material.cs deleted file mode 100644 index 027a3ba..0000000 --- a/Material.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using System.Drawing; -using System.IO; - -namespace ConsoleGraphics -{ - class Material - //convert textures - { - public byte[,] bitmapColorsCached; - public int SIZE; - - public Material(string fileName) - { - Bitmap sourceBmp = (Bitmap)Image.FromFile(fileName, true);//load character set (digits 1->9..) - bitmapColorsCached = new byte[sourceBmp.Width, sourceBmp.Height]; - SIZE = sourceBmp.Width; - for (int i = 0; i < sourceBmp.Width; i++) - for (int j = 0; j < sourceBmp.Height; j++) - { - Color c = sourceBmp.GetPixel(i, j); - bitmapColorsCached[i,j] = (byte)((c.R + c.B + c.G) / 3); - } - } - } -} diff --git a/Maths/MathHelper.cs b/Maths/MathHelper.cs new file mode 100644 index 0000000..767b215 --- /dev/null +++ b/Maths/MathHelper.cs @@ -0,0 +1,51 @@ +namespace ConsoleGraphics.Maths +{ + /// + /// A helper class that contains useful function for doing maths + /// + public class MathHelper + { + /// + /// Swaps the values of the 2 given floats + /// + /// + /// + public static void Swap(ref float x, ref float y) + { + float temp = x; + x = y; + y = temp; + } + + /// + /// Swaps the values of the 2 given integers + /// + /// + /// + public static void Swap(ref int x, ref int y) + { + int temp = x; + x = y; + y = temp; + } + + /// + /// Clamps the given value between the given min and max value. + /// + /// e.g. Clamp(420, 50, 500) return 420, Clamp(100, 5, 50) return 50, Clamp( + /// + /// + /// + /// + /// + /// + public static float Clamp(float value, float min, float max) + { + if (value > max) + return max; + if (value < min) + return min; + return value; + } + } +} diff --git a/Maths/Matrix.cs b/Maths/Matrix.cs new file mode 100644 index 0000000..0d024f2 --- /dev/null +++ b/Maths/Matrix.cs @@ -0,0 +1,34 @@ +namespace ConsoleGraphics.Maths +{ + /// + /// Matrix. N x N matricies + /// + public class Matrix + { + /// + /// Row,Column + /// + public float[,] M; + + public Matrix(float[,] vals, int rows, int cols) + { + M = new float[rows, cols]; + for (int i = 0; i < rows; i++) + { + for (int j = 0; j < cols; j++) + { + M[i, j] = vals[i, j]; + } + } + } + + public Vector3 Multiply(Vector3 vector) + { + Vector3 pNew; + pNew.X = vector.X * M[0, 0] + vector.Y * M[0, 1] + vector.Z * M[0, 2]; + pNew.Y = vector.X * M[1, 0] + vector.Y * M[1, 1] + vector.Z * M[1, 2]; + pNew.Z = vector.X * M[2, 0] + vector.Y * M[2, 1] + vector.Z * M[2, 2]; + return pNew; + } + } +} diff --git a/Maths/Triangle.cs b/Maths/Triangle.cs new file mode 100644 index 0000000..f3bf472 --- /dev/null +++ b/Maths/Triangle.cs @@ -0,0 +1,34 @@ +namespace ConsoleGraphics.Maths +{ + /// + /// A face that contains a indexes which can be used to point to vertices, texture coordinates, and a material + /// + public struct Triangle + { + /// + /// An array of indexes which point to a vertex somewhere else + /// + public int[] VertexIds; + /// + /// An array of indexes which point to a texture coordinate somewhere else + /// + public int[] UVIds; + /// + /// An index that points to a material somewhere else + /// + public int MaterialId; + + public Triangle(int v1, int v2, int v3, int vt1, int vt2, int vt3, int mid) + { + VertexIds = new int[3]; + VertexIds[0] = v1; + VertexIds[1] = v2; + VertexIds[2] = v3; + UVIds = new int[3]; + UVIds[0] = vt1; + UVIds[1] = vt2; + UVIds[2] = vt3; + MaterialId = mid; + } + } +} diff --git a/Maths/Vector2.cs b/Maths/Vector2.cs new file mode 100644 index 0000000..aaa76b1 --- /dev/null +++ b/Maths/Vector2.cs @@ -0,0 +1,13 @@ +namespace ConsoleGraphics.Maths +{ + public struct Vector2 + { + public float X, Y; + + public Vector2(float x, float y) + { + X = x; + Y = y; + } + } +} diff --git a/Maths/Vector3.cs b/Maths/Vector3.cs new file mode 100644 index 0000000..fc46b1a --- /dev/null +++ b/Maths/Vector3.cs @@ -0,0 +1,108 @@ +using System; + +namespace ConsoleGraphics.Maths +{ + /// + /// A struct containing an X, Y and Z value, and basic functions for manipulating those values, e.g. the dot product, normalisation, etc + /// + public struct Vector3 + { + public float X, Y, Z; + + public Vector3(float x, float y, float z = 0) + { + X = x; + Y = y; + Z = z; + } + + /// + /// Adds the given XYZ values to this vector instance's XYZ values + /// + /// + /// + /// + public void Add(float x, float y, float z) + { + this.X += x; + this.Y += y; + this.Z += z; + } + + /// + /// Adds the XYZ values of the given vector to this vector instance's XYZ values + /// + /// + /// + /// + public void Add(Vector3 v) + { + Add(v.X, v.Y, v.Z); + } + + /// + /// Returns the dot product between this vector instance and the given vector + /// + /// + /// + public float Dot(Vector3 v) + { + return X * v.X + Y * v.Y + Z * v.Z; + } + + /// + /// Returns the squared magnitude of this vector instance + /// + /// + public float MagnitudeSquared() + { + return X * X + Y * Y + Z * Z; + } + + /// + /// Returns the magnitude of this vector instance + /// + /// + public float Magnitude() + { + return (float)Math.Sqrt(MagnitudeSquared()); + } + + public static Vector3 Normalize(Vector3 a) + { + float norm = (float)Math.Sqrt(a.X * a.X + a.Y * a.Y + a.Z * a.Z); + return (new Vector3(a.X / norm, a.Y / norm, a.Z / norm)); + } + + public static Vector3 Cross(Vector3 a, Vector3 b) + { + Vector3 resultant; + resultant.X = a.Y * b.Z - a.Z * b.Y; + resultant.Y = a.Z * b.X - a.X * b.Z; + resultant.Z = a.X * b.Y - a.Y * b.X; + return (resultant); + } + + /// + /// Returns a new vector where the XYZ values of a and b have been added + /// + /// + /// + /// + public static Vector3 Add(Vector3 a, Vector3 b) + { + return (new Vector3((a.X + b.X), (a.Y + b.Y), (a.Z + b.Z))); + } + + /// + /// Returns a new vector which contains the dot product between the a and b vector + /// + /// + /// + /// + public static float Dot(Vector3 a, Vector3 b) + { + return (a.X * b.X + a.Y * b.Y + a.Z * b.Z); + } + } +} diff --git a/Matrix.cs b/Matrix.cs deleted file mode 100644 index 22719a9..0000000 --- a/Matrix.cs +++ /dev/null @@ -1,67 +0,0 @@ -/* - * N x N matricies - * Define & perform basic operations on matricies. - * - */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ConsoleGraphics -{ - class Matrix : Program - { - public float[,] m_i;//row,col - - public Matrix(float[,] vals, int rows, int cols) - { - m_i = new float[rows, cols]; - for (int i = 0; i < rows; i++) - { - for (int j = 0; j < cols; j++) - { - m_i[i, j] = vals[i, j]; - } - } - } - - public static float magnitude(Mesh.point3 a) - { - return((float)Math.Sqrt(dot(a,a))); - } - public static Mesh.point3 normalize(Mesh.point3 a) - { - float norm = (float)Math.Sqrt(a.x * a.x + a.y * a.y + a.z * a.z); - return (new Mesh.point3(a.x/norm, a.y/norm, a.z/norm)); - } - public static Mesh.point3 cross(Mesh.point3 a, Mesh.point3 b) - { - Mesh.point3 resultant; - resultant.x = a.y * b.z - a.z * b.y; - resultant.y = a.z * b.x - a.x * b.z; - resultant.z = a.x * b.y - a.y * b.x; - return (resultant); - } - - public static Mesh.point3 add(Mesh.point3 a, Mesh.point3 b) - { - return (new Mesh.point3((a.x + b.x), (a.y + b.y), (a.z + b.z))); - } - - public static float dot(Mesh.point3 a, Mesh.point3 b) - { - return (a.x * b.x + a.y * b.y + a.z * b.z); - } - - public Mesh.point3 multiply(Mesh.point3 vector) - { - Mesh.point3 pNew; - pNew.x = vector.x * m_i[0, 0] + vector.y * m_i[0, 1] + vector.z * m_i[0, 2]; - pNew.y = vector.x * m_i[1, 0] + vector.y * m_i[1, 1] + vector.z * m_i[1, 2]; - pNew.z = vector.x * m_i[2, 0] + vector.y * m_i[2, 1] + vector.z * m_i[2, 2]; - return (pNew); - } - } -} diff --git a/Mesh.cs b/Mesh.cs deleted file mode 100644 index c038743..0000000 --- a/Mesh.cs +++ /dev/null @@ -1,125 +0,0 @@ -/* Mesh - all the things that define a mesh. triangles, edges, verticies... later UVs... - * - * - */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ConsoleGraphics -{ - class Mesh : Program - { - public Mesh(point3[] meshVerts, triangle[] meshFaces, point2[] meshUvs, Material[] mtls = null) - { - verts = meshVerts; - vertCount = verts.Length; - faces = meshFaces; - faceCount = faces.Length; - uvVerts = meshUvs; - matIDs = mtls; - } - - public struct triangle - { - public int[] vertIDs; - public int[] uvIds; - public int matID; - public triangle(int v1, int v2, int v3, int vt1, int vt2, int vt3, int mid) - { - vertIDs = new int[3]; - vertIDs[0] = v1; - vertIDs[1] = v2; - vertIDs[2] = v3; - uvIds = new int[3]; - uvIds[0] = vt1; - uvIds[1] = vt2; - uvIds[2] = vt3; - matID = mid; - } - }; - - public struct point3 - { - public float x, y, z; - public point3(float newX, float newY, float newZ = 0) - { - x = newX; - y = newY; - z = newZ; - } - }; - - public struct point2 - { - public float x, y; - public point2(float newX, float newY) - { - x = newX; - y = newY; - } - }; - - public point3[] verts; - public triangle[] faces; - public point2[] uvVerts; - public int vertCount; - public int faceCount; - public Material[] matIDs; - public void translate(point3 translation) - { - for (int i = 0; i < verts.Length; i++) - { - verts[i] = Matrix.add(verts[i], translation); - } - } - - public void rotate(double angle, byte dir) - { - //Rotate about centerpoint of the shape: translate the center of our shape to the origin, rotate, translate back. - float cosAngle = (float)Math.Cos(angle); - float sinAngle = (float)Math.Sin(angle); - Matrix rotMtrx = null; - point3 startCoords = verts[0]; - translate(new Mesh.point3(-startCoords.x, -startCoords.y, -startCoords.z)); - #region rotations - /* Rotate about X Axis {{1,0, 0}, - {0, cosAngle,sinAngle*100}, - {0, -sinAngle/100, cosAngle}}, 3, 3); - - - * Rotate about Y Axis {{cosAngle,0,-sinAngle*100}, - {0, 1, 0}, - {sinAngle, 0, cosAngle}}, 3, 3); - Rotate about Z axis - * {{cosAngle,-sinAngle,0}, - {sinAngle, cosAngle,0}, - {0, 0, 1}},3,3); - */ - #endregion - int x = Environment.TickCount; - - if (dir == 0) - rotMtrx = new Matrix(new float[,] {{1,0,0}, - {0, cosAngle,sinAngle*100}, - {0, -sinAngle/100, cosAngle}}, 3, 3); - else if (dir == 1) - rotMtrx = new Matrix(new float[,] {{cosAngle,0,-sinAngle*100}, - {0, 1, 0}, - {sinAngle/100, 0, cosAngle}}, 3, 3); - else - rotMtrx = new Matrix(new float[,] {{cosAngle,-sinAngle,0}, - {sinAngle, cosAngle,0}, - {0, 0, 1}}, 3, 3); - x = Environment.TickCount - x; - - for (int i = 0; i < vertCount; i++) - { - verts[i] = rotMtrx.multiply(verts[i]); - } - translate(new Mesh.point3(startCoords.x, startCoords.y, startCoords.z)); - } - } -} diff --git a/Program.cs b/Program.cs deleted file mode 100644 index 65e0314..0000000 --- a/Program.cs +++ /dev/null @@ -1,238 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.IO; -using System.Drawing; - -namespace ConsoleGraphics -{ - class Program - { - //special characters:█ ▄ ▀ ■ - - public bool VSYNC_ON = false; - public static threeState ts = new threeState(0); - // public bool FRAMERATE_ON = true; - public const short RENDER_WIDTH = 300; - public const short RENDER_HEIGHT = 100; - public const short MAX_FPS = 1000; - public const float pi = (float)3.1415926535; - static char[, ,] numerals = new char[9, 8, 10]; - public static char[] levels; - - public struct threeState - { - public byte x; - public threeState(byte initialState) - { - x = 0; - } - public void changeState() - { - x = (byte)((x + 1) % 3); - } - } - - public struct light - { - public Mesh.point3 coords; - public float intensity; - public light(float x, float y, float z, float setIntensity) - { - coords = new Mesh.point3(x, y, z); - intensity = setIntensity; - } - }; - - static void init(short width, short height, string title) - { - Console.Title = title; - Console.CursorVisible = false; - Console.BackgroundColor = ConsoleColor.Black; - reTry: - try - { - Console.SetWindowSize(width, height + 15); - Console.SetBufferSize(width, height + 15); - } - catch (ArgumentOutOfRangeException) - { - Console.WriteLine("Decrease your font size and press enter"); - Console.ReadLine(); - goto reTry; - } - Console.Clear();//clear colors from user preset. - Console.SetCursorPosition(0, height); - Console.Write(new String('▄', RENDER_WIDTH)); - Console.ForegroundColor = ConsoleColor.Cyan; - - StreamReader r = new StreamReader("levels.txt"); - - levels = new char[256]; - int index = 0; - while (!r.EndOfStream && index < 256) - { - string e1 = r.ReadLine(); - levels[index] = Char.Parse(e1); - index++; - } - - Thread cin = new Thread(getInput); - cin.Start(); - //Thread soundPlayer = new Thread(playSound); - //soundPlayer.Start(); - } - - static byte[,] loadTex(string loc) - { - byte[,] loadedTexture = new byte[2, 2]; - return (loadedTexture); - } - - static Mesh loadObj(string loc) - { - StreamReader r = new StreamReader(loc + ".obj"); - List loadedVerts = new List(); - List loadedUvs = new List(); - List loadedFaces = new List(); - List loadedUvFaces = new List(); - List mtls = new List(); - int vertCount = 0; - int faceCount = 0; - - while (!r.EndOfStream) - { - string e1 = r.ReadLine(); - if (e1 != "") - { - if (e1[0] == 'v' && e1[1] == 't')//texture verticies - { - string temp = e1.Substring(3, e1.Length - 3); - string[] coords = temp.Split(' '); - Mesh.point2 p = new Mesh.point2(float.Parse(coords[0]), float.Parse(coords[1])); - loadedUvs.Add(p); - } - else if (e1[0] == 'v')//vertex - { - vertCount++; - string temp = e1.Substring(3, e1.Length - 3); - string[] coords = temp.Split(' '); - Mesh.point3 p = new Mesh.point3(float.Parse(coords[0]) * 100, float.Parse(coords[1]) * 100, float.Parse(coords[2])); - //if z is positive it's off screen, z=0 we clip - loadedVerts.Add(p); - } - else if (e1[0] == 'u') - {//use this mtl for rest of faces faces material - Material m = new Material(e1.Substring(7, e1.Length - 7)); - mtls.Add(m); - } - else if (e1[0] == 'f')//edge - { - faceCount++; - string temp = e1.Substring(2, e1.Length - 2); - string[] coords = temp.Split(' ', '/'); - Mesh.triangle f = new Mesh.triangle(int.Parse(coords[0]) - 1, int.Parse(coords[2]) - 1, int.Parse(coords[4]) - 1, /*UV ID's*/ int.Parse(coords[1]) - 1, int.Parse(coords[3]) - 1, int.Parse(coords[5]) - 1, mtls.Count); - // Mesh.triangle uvf = new Mesh.triangle(int.Parse(coords[1]), int.Parse(coords[3]), int.Parse(coords[5])); - loadedFaces.Add(f); - // loadedUvFaces.Add(uvf); - } - } - } - return (new Mesh(loadedVerts.ToArray(), loadedFaces.ToArray(), loadedUvs.ToArray(), mtls.ToArray())); - } - - public static Mesh someShape = loadObj("link"); - public static light light1 = new light(0, 0, 0, 700); - - public static void Main(string[] args) - { - //BrightnessInit.go(); - //BrightnessInit.sortstuff(); - init(RENDER_WIDTH, RENDER_HEIGHT, "render"); - FrameBuffer buffer = new FrameBuffer(); - Rasterizer rast = new Rasterizer(); - someShape.translate(new Mesh.point3(-800, -300, -8)); - //someShape.rotate((float)0.25); - - buffer.drawFrame(rast.renderSolid()); - Console.ReadLine(); - //someShape.rotate((float)(3.1415)); - for (double i = 0; i < 1000; i += 0.01) - { - //light1.intensity = (int)((double)800 * Math.Sin(4*i)); - //someShape.rotate(0.005, 0); - //someShape.rotate(0.005, 1); - //someShape.rotate(0.005, 2); - //someShape.translate(new Mesh.point3((float)Math.Sin(i), 0, 0)); - // buffer.drawFrame(drawLine(new byte[RENDER_HEIGHT * RENDER_WIDTH], a1, a2)); - if (ts.x == 0) - buffer.drawFrame(rast.renderSolid()); - else if (ts.x == 2) - buffer.drawFrame(rast.renderWire(someShape)); - else if (ts.x == 1) - buffer.drawFrame(rast.renderVerts(someShape)); - - //light1.coords.x = 1000 * (float)Math.Sin(i); - // light1.coords.y = 1000 * (float)Math.Sin(i); - //light1.coords.z = 100 * (float)Math.Sin(i); - //someShape.rotate((float)0.005, 0); - //someShape.rotate((float)0.005, 1); - } - Console.ReadLine(); - } - - static void getInput() - { - ConsoleKeyInfo cki; - // Console.TreatControlCAsInput = true; - do - { - cki = Console.ReadKey(); - switch (cki.Key) - { - case ConsoleKey.Spacebar: - ts.changeState(); - break; - case ConsoleKey.W: - someShape.translate(new Mesh.point3(0, 0, (float)0.1)); - break; - case ConsoleKey.A: - someShape.translate(new Mesh.point3(-10, 0, 0)); - break; - case ConsoleKey.S: - someShape.translate(new Mesh.point3(0, 0, (float)-0.1)); - break; - case ConsoleKey.D: - someShape.translate(new Mesh.point3(10, 0, 0)); - break; - case ConsoleKey.R: - someShape.rotate(0.01, 0); - break; - case ConsoleKey.T: - someShape.rotate(0.01, 1); - break; - case ConsoleKey.Y: - someShape.rotate(0.01, 2); - break; - case ConsoleKey.Q: - someShape.translate(new Mesh.point3(0, -10, 0)); - break; - case ConsoleKey.E: - someShape.translate(new Mesh.point3(0, 10, 0)); - break; - } - } while (cki.Key != ConsoleKey.Escape); - } - - public static void printch(char[] charId, int x, int y) - { - Console.SetCursorPosition(0, RENDER_HEIGHT + 4); - Console.Write(new string(' ', 10)); - Console.SetCursorPosition(0, RENDER_HEIGHT + 4); - Console.Write(charId); - } - } -} diff --git a/Rasterize.cs b/Rasterize.cs deleted file mode 100644 index 9a58540..0000000 --- a/Rasterize.cs +++ /dev/null @@ -1,366 +0,0 @@ -/* Rasterization - all the grunt work! - * Determine pixle 'colors'.. - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Drawing; - -namespace ConsoleGraphics -{ - class Rasterizer : Program - { - public static int[,] zBuffer = new int[RENDER_WIDTH, RENDER_HEIGHT]; - - void swap(ref float x, ref float y) - { - float temp = x; - x = y; - y = temp; - } - - void swap(ref int x, ref int y) - { - int temp = x; - x = y; - y = temp; - } - - float clamp(float val, float min, float max) - { - return (Math.Max(Math.Min(val, max), min)); - } - - public byte[,] renderVerts(Mesh someShape) - { - byte[,] image = new byte[RENDER_WIDTH, RENDER_HEIGHT];// - - for (int x = 0; x < RENDER_WIDTH; x++) - for (int y = 0; y < RENDER_HEIGHT; y++) - image[x, y] = 32; - - foreach (Mesh.triangle f in someShape.faces) - { - for (int i = 0; i < 3; i++)//each vertex - { - double depth = someShape.verts[f.vertIDs[i]].z; - int P_x1 = (int)(someShape.verts[f.vertIDs[i]].x / depth); - int P_y1 = (int)(someShape.verts[f.vertIDs[i]].y / depth); - - if (P_y1 < RENDER_HEIGHT - 1 && P_y1 >= 0 && P_x1 < RENDER_WIDTH - 1 && P_x1 >= 0)//the vert is in bounds with the screen - image[P_x1, P_y1] = 177; - } - } - return (image); - } - - public byte[,] renderWire(Mesh someShape) - { - byte[,] image = new byte[RENDER_WIDTH, RENDER_HEIGHT];// - - for (int x = 0; x < RENDER_WIDTH; x++) - for (int y = 0; y < RENDER_HEIGHT; y++) - image[x, y] = 32; - - foreach (Mesh.triangle f in someShape.faces) - { - for (int i = 0; i < 3; i++)//each vertex - { - double depth = someShape.verts[f.vertIDs[i]].z; - int P_x1 = (int)((RENDER_WIDTH / 2) + someShape.verts[f.vertIDs[i]].x / depth); - int P_y1 = (int)(((RENDER_HEIGHT - 15) / 2) + someShape.verts[f.vertIDs[i]].y / depth); - - if (P_y1 < RENDER_HEIGHT - 1 && P_y1 >= 0 && P_x1 < RENDER_WIDTH - 1 && P_x1 >= 0)//the vert is in bounds with the screen - for (int j = 0; j < 2; j++)//each of the 2 neighboring verts - { - double depth2 = someShape.verts[f.vertIDs[j]].z; - int P_x = (int)((RENDER_WIDTH / 2) + someShape.verts[f.vertIDs[j]].x / depth2); - int P_y = (int)(((RENDER_HEIGHT - 15) / 2) + someShape.verts[f.vertIDs[j]].y / depth2); - - if (P_y < RENDER_HEIGHT - 1 && P_y >= 0 && P_x < RENDER_WIDTH - 1 && P_x >= 0) - image = drawLine(image, P_x, P_y, P_x1, P_y1, true); - } - } - } - return (image); - } - Mesh.triangle targFace; - public byte[,] renderSolid() - { - byte[,] image = new byte[RENDER_WIDTH, RENDER_HEIGHT];// - - for (int x = 0; x < RENDER_WIDTH; x++) - for (int y = 0; y < RENDER_HEIGHT; y++) - { - image[x, y] = 32; //space character is drawn faster than the null character (0) - zBuffer[x, y] = -100; //far clipping plane - } - - foreach (Mesh.triangle f in someShape.faces) - { - targFace = f; - Mesh.point3 a = Matrix.add(someShape.verts[f.vertIDs[0]], new Mesh.point3(-someShape.verts[f.vertIDs[2]].x, -someShape.verts[f.vertIDs[2]].y, -someShape.verts[f.vertIDs[2]].z)); - Mesh.point3 b = Matrix.add(someShape.verts[f.vertIDs[0]], new Mesh.point3(-someShape.verts[f.vertIDs[1]].x, -someShape.verts[f.vertIDs[1]].y, -someShape.verts[f.vertIDs[1]].z)); - Mesh.point3 surfaceNorm1 = Matrix.cross(a, b); - - surfaceNorm1 = Matrix.normalize(surfaceNorm1); - - Mesh.point3 lightNorm1 = Matrix.add(light1.coords, new Mesh.point3(-someShape.verts[f.vertIDs[0]].x, -someShape.verts[f.vertIDs[0]].y, -someShape.verts[f.vertIDs[0]].z));//arbitrary vert - lightNorm1 = Matrix.normalize(lightNorm1); - //////////////////////////////////// - Mesh.point3 a1 = Matrix.add(someShape.verts[f.vertIDs[1]], new Mesh.point3(-someShape.verts[f.vertIDs[2]].x, -someShape.verts[f.vertIDs[2]].y, -someShape.verts[f.vertIDs[2]].z)); - Mesh.point3 b1 = Matrix.add(someShape.verts[f.vertIDs[1]], new Mesh.point3(-someShape.verts[f.vertIDs[0]].x, -someShape.verts[f.vertIDs[0]].y, -someShape.verts[f.vertIDs[0]].z)); - Mesh.point3 surfaceNorm2 = Matrix.cross(a1, b1); - - surfaceNorm2 = Matrix.normalize(surfaceNorm2); - - Mesh.point3 lightNorm2 = Matrix.add(light1.coords, new Mesh.point3(-someShape.verts[f.vertIDs[1]].x, -someShape.verts[f.vertIDs[1]].y, -someShape.verts[f.vertIDs[1]].z));//arbitrary vert - lightNorm2 = Matrix.normalize(lightNorm2); - ////////////////////////////////////////////// - Mesh.point3 a2 = Matrix.add(someShape.verts[f.vertIDs[2]], new Mesh.point3(-someShape.verts[f.vertIDs[0]].x, -someShape.verts[f.vertIDs[0]].y, -someShape.verts[f.vertIDs[0]].z)); - Mesh.point3 b2 = Matrix.add(someShape.verts[f.vertIDs[2]], new Mesh.point3(-someShape.verts[f.vertIDs[1]].x, -someShape.verts[f.vertIDs[1]].y, -someShape.verts[f.vertIDs[1]].z)); - Mesh.point3 surfaceNorm3 = Matrix.cross(a2, b2); - - surfaceNorm3 = Matrix.normalize(surfaceNorm3); - - Mesh.point3 lightNorm3 = Matrix.add(light1.coords, new Mesh.point3(-someShape.verts[f.vertIDs[2]].x, -someShape.verts[f.vertIDs[2]].y, -someShape.verts[f.vertIDs[2]].z));//arbitrary vert - lightNorm3 = Matrix.normalize(lightNorm3); - //////////////////////////////////////////// - - //perspective projection - float[] depth = {someShape.verts[f.vertIDs[0]].z, - someShape.verts[f.vertIDs[1]].z, - someShape.verts[f.vertIDs[2]].z}; - - if (depth[0] < 0 && depth[1] < 0 && depth[2] < 0) - { //>= one vertex is in screen - int x0 = (int)((RENDER_WIDTH / 2) + someShape.verts[f.vertIDs[0]].x / depth[0]); - int y0 = (int)(((RENDER_HEIGHT - 15) / 2) + someShape.verts[f.vertIDs[0]].y / depth[0]); - - int x1 = (int)((RENDER_WIDTH / 2) + someShape.verts[f.vertIDs[1]].x / depth[1]); - int y1 = (int)(((RENDER_HEIGHT - 15) / 2) + someShape.verts[f.vertIDs[1]].y / depth[1]); - - int x2 = (int)((RENDER_WIDTH / 2) + someShape.verts[f.vertIDs[2]].x / depth[2]); - int y2 = (int)(((RENDER_HEIGHT - 15) / 2) + someShape.verts[f.vertIDs[2]].y / depth[2]); - - - Mesh.point2[] uvs = new Mesh.point2[] { someShape.uvVerts[f.uvIds[0]], - someShape.uvVerts[f.uvIds[1]], - someShape.uvVerts[f.uvIds[2]] - }; - Mesh.point3[] projPoints = new Mesh.point3[] {new Mesh.point3(x0, y0, depth[0]), - new Mesh.point3(x1, y1, depth[1]), - new Mesh.point3(x2, y2, depth[2])}; - - byte[] colors = {(byte)(light1.intensity * Math.Max(0, Matrix.dot(surfaceNorm1, lightNorm1))), - (byte)(light1.intensity * Math.Max(0, Matrix.dot(surfaceNorm2, lightNorm2))), - (byte)(light1.intensity * Math.Max(0, Matrix.dot(surfaceNorm3, lightNorm3)))}; - - image = drawTriangle(image, projPoints, uvs, colors); - } - } - return (image); - } - - private byte[,] drawTriangle(byte[,] image, Mesh.point3[] points, Mesh.point2[] uvs, byte[] brightness = null) - { - /* - * A - * B------- - * C - * - */ - //sort by lowest y value (highest on screen) - Mesh.point3[] unsortedPoints = new Mesh.point3[3]; - points.CopyTo(unsortedPoints, 0); - - if (points[1].y < points[0].y) - {//swap point[1] and point[0] - swap(ref points[0].y, ref points[1].y); - swap(ref points[0].x, ref points[1].x); - } - if (points[2].y < points[0].y) - {//swap point[0] and point[2] - swap(ref points[0].y, ref points[2].y); - swap(ref points[0].x, ref points[2].x); - } - if (points[2].y < points[1].y) - {//swap point[1] & point[2] - swap(ref points[1].y, ref points[2].y); - swap(ref points[1].x, ref points[2].x); - } - - if (points[0].y == points[1].y) - {//flat top - image = fillFlatTop(image, points, unsortedPoints, brightness, uvs); - } - else if (points[1].y == points[2].y) - {//flat bottom - image = fillFlatBottom(image, points, unsortedPoints, brightness, uvs); - } - else - {//nontrivial - Mesh.point3 midpoint = new Mesh.point3((int)(Math.Ceiling(points[0].x + ((float)(points[1].y - points[0].y) / (float)(points[2].y - points[0].y)) * (points[2].x - points[0].x))), points[1].y); - fillFlatBottom(image, new Mesh.point3[] { points[0], points[1], midpoint }, unsortedPoints, brightness, uvs); - fillFlatTop(image, new Mesh.point3[] { points[1], midpoint, points[2] }, unsortedPoints, brightness, uvs); - } - return (image); - } - - private byte[,] fillFlatTop(byte[,] image, Mesh.point3[] sortedPoints, Mesh.point3[] unsortedPoints, byte[] brightness, Mesh.point2[] uvs = null) - { - float startX = sortedPoints[2].x; - float endX = sortedPoints[2].x; - - float invslope1 = (float)(sortedPoints[2].x - sortedPoints[0].x) / (float)(sortedPoints[2].y - sortedPoints[0].y); - float invslope2 = (float)(sortedPoints[2].x - sortedPoints[1].x) / (float)(sortedPoints[2].y - sortedPoints[1].y); - - for (int scanlineY = (int)sortedPoints[2].y; scanlineY > sortedPoints[0].y; scanlineY--) - { - drawLine(image, (int)startX, scanlineY, (int)endX, scanlineY, false, unsortedPoints, brightness, uvs); - startX -= invslope1; - endX -= invslope2; - } - return (image); - } - - private byte[,] fillFlatBottom(byte[,] image, Mesh.point3[] sortedPoints, Mesh.point3[] unsortedPoints, byte[] brightness, Mesh.point2[] uvs = null) - { - float invslope1 = (float)(sortedPoints[2].x - sortedPoints[0].x) / (float)(sortedPoints[2].y - sortedPoints[0].y); - float invslope2 = (float)(sortedPoints[0].x - sortedPoints[1].x) / (float)(sortedPoints[0].y - sortedPoints[1].y); - - float curx1 = sortedPoints[0].x; - float curx2 = sortedPoints[0].x; - - for (int scanlineY = (int)sortedPoints[0].y; scanlineY <= sortedPoints[1].y; scanlineY++) - { - drawLine(image, (int)curx1, scanlineY, (int)curx2, scanlineY, false, unsortedPoints, brightness, uvs); - curx1 += invslope1; - curx2 += invslope2; - } - return (image); - } - - public byte[,] drawLine(byte[,] image, /*start*/int x0, int y0, int x1, int y1,/*end*/ bool drawWireFrame, Mesh.point3[] unsortedPoints = null, byte[] color = null, Mesh.point2[] uvs = null) - { - float rise = y1 - y0; - float run = x1 - x0; - byte txl = 219; - //if (color != null) - //{ - // color[0] = 0; - // color[1] = 50; - // color[2] = 100; - //} - if (run == 0) - { - if (drawWireFrame) - txl = 124;// | - - if (y0 > y1) - swap(ref y0, ref y1); - - while (y0 < y1)//DRAW - { - image[x0, y0] = txl; - y0++; - } - return (image); - } - - float m = rise / run; - - if (-1 <= rise / run && rise / run <= 1) - { - - if (drawWireFrame) - { - if (rise / run > 0.5) - txl = 92;// / - else if (rise / run < -0.5) - txl = 47;// \ - else - txl = 95;// - - } - - if (x0 > x1) - { - swap(ref x0, ref x1); - swap(ref y0, ref y1); - } - - float y = y0; - float x = x0; - float denom = 0; - if (!drawWireFrame) - denom = ((unsortedPoints[1].y - unsortedPoints[2].y) * (unsortedPoints[0].x - unsortedPoints[2].x) + (unsortedPoints[2].x - unsortedPoints[1].x) * (unsortedPoints[0].y - unsortedPoints[2].y)); - - while (x <= x1 && y < RENDER_HEIGHT && x < RENDER_WIDTH && y >= 0) - { - if (x > 0)//clipping logic < ^ - { - int xtoi = (int)x; - int ytoi = (int)y; - if (drawWireFrame) - { - image[xtoi, ytoi] = txl; - y += m; - } - else//HERE'S WHERE WE DRAW TRIANGLES! - { - float b1 = (((unsortedPoints[1].y - unsortedPoints[2].y) * (x - unsortedPoints[2].x)) + ((unsortedPoints[2].x - unsortedPoints[1].x) * (y - unsortedPoints[2].y))) / denom; - float b2 = (((unsortedPoints[2].y - unsortedPoints[0].y) * (x - unsortedPoints[2].x)) + ((unsortedPoints[0].x - unsortedPoints[2].x) * (y - unsortedPoints[2].y))) / denom; - float b3 = 1 - b1 - b2; - - int interpolatedZ = (int)(b1 * unsortedPoints[0].z + b2 * unsortedPoints[1].z + b3 * unsortedPoints[2].z); - - if (interpolatedZ > zBuffer[xtoi, ytoi]) - { // use barycentric interpolation to do everything.. - float interpU = (float)(b1 * uvs[0].x + b2 * uvs[1].x + b3 * uvs[2].x); - float interpV = (float)(b1 * uvs[0].y + b2 * uvs[1].y + b3 * uvs[2].y); - float interpBright = color[1];// + b2 * (float)color[1] + b3 * (float)color[2]); - Material someMat = someShape.matIDs[targFace.matID-1]; - int xpos = Math.Min(Math.Max((int)(interpU * someMat.SIZE), 0), someMat.SIZE-1); - int ypos = Math.Min(Math.Max((int)(interpV * someMat.SIZE), 0), someMat.SIZE-1); - - byte fa = someMat.bitmapColorsCached[(int)clamp(xpos, 0, someMat.SIZE-1), (int)clamp(ypos, 0, someMat.SIZE-1)]; - image[xtoi, ytoi] = (byte)(Convert.ToInt32(levels[(int)clamp(fa + interpBright, 0, 255)])); - zBuffer[xtoi, ytoi] = interpolatedZ; - } - } - } - x++; - } - } - else - { - if (run / rise > 0.5) - txl = 92;// / - else if (run / rise < -0.5) - txl = 47;// \ - else - txl = 124;// - - - if (y0 > y1) - { - swap(ref x0, ref x1); - swap(ref y0, ref y1); - } - - float x = x0; - float invSlope = 1 / m; - - while (y0 < y1) - { - image[(int)x, y0] = txl; - x += invSlope; - y0++; - } - } - return (image); - } - } -} diff --git a/Render/FrameBuffer.cs b/Render/FrameBuffer.cs new file mode 100644 index 0000000..f999177 --- /dev/null +++ b/Render/FrameBuffer.cs @@ -0,0 +1,78 @@ +using System; +using System.IO; +using System.Threading; + +namespace ConsoleGraphics.Render +{ + /// + /// Draws a buffer (an array of bytes) to the console buffer/screen + /// + public static class FrameBuffer + { + private static int LastRenderTick; + private static int numRenderings = 0; + private const short sampleSize = 100; + //private string lastFrame = ""; + + /// + /// STDOUT + /// + public static Stream ConsoleOutput = Console.OpenStandardOutput(); + + // defining it static. saves creating a 30000 byte long array every time the game renders + // probably makes the garbage collector happier too lol + private static byte[] ViewportBuffer = new byte[Game.RENDER_HEIGHT * Game.RENDER_WIDTH]; + + public static void DrawFrame(byte[,] image, int a = 0, int b = 0) + { + //use cudafy / multithreading to paint quickly, also invoke writetoconsole? + + for (int x = 0; x < Game.RENDER_WIDTH; x++) + { + for (int y = 0; y < Game.RENDER_HEIGHT; y++) + { + ViewportBuffer[x + y * Game.RENDER_WIDTH] = image[x, y]; + } + } + + Console.SetCursorPosition(a, b); + + int beginRender = Environment.TickCount; + //.Flush(); + //string iString = bufImg.ToString(); + //byte[] b = Encoding.UTF8.GetBytes(iString); + //if (string.Compare(lastFrame, iString) != 0) + //{ + ConsoleOutput.Write(ViewportBuffer, 0, ViewportBuffer.Length); + // lastFrame = iString; + //} + int endRender = Environment.TickCount - beginRender; + + VerticalSync(Game.MAX_FPS, endRender, beginRender); + + if (numRenderings == 0) + LastRenderTick = Environment.TickCount; + + numRenderings++; + } + + public static void VerticalSync(short targetFrameRate, int delay, int startDrawTime) + { + //Synchronize frames and display framerate to the lower right corner of the render window + int targetDelay = 1000 / targetFrameRate; + //we're too fast + if (delay < targetDelay && Game.USE_VSYNC) + { + Thread.Sleep(targetDelay - delay); + } + + if (numRenderings == sampleSize) + { + int ticksElapsed = Environment.TickCount - LastRenderTick; + if (ticksElapsed != 0) + Game.printch((sampleSize * 1000 / ticksElapsed).ToString().ToCharArray(), Game.RENDER_WIDTH - 50, Game.RENDER_HEIGHT + 1); + numRenderings = 0; + } + } + } +} diff --git a/Render/Light.cs b/Render/Light.cs new file mode 100644 index 0000000..6861d02 --- /dev/null +++ b/Render/Light.cs @@ -0,0 +1,16 @@ +using ConsoleGraphics.Maths; + +namespace ConsoleGraphics.Render +{ + public struct Light + { + public Vector3 Coordinates; + public float Intensity; + + public Light(float x, float y, float z, float intensity) + { + Coordinates = new Vector3(x, y, z); + Intensity = intensity; + } + } +} diff --git a/Render/Material.cs b/Render/Material.cs new file mode 100644 index 0000000..b6b9d17 --- /dev/null +++ b/Render/Material.cs @@ -0,0 +1,27 @@ +using System.Drawing; + +namespace ConsoleGraphics.Render +{ + //convert textures + public class Material + { + public byte[,] BitmapColorsCached; + public int Size; + + public Material(string fileName) + { + //load character set (digits 1->9..) + Bitmap sourceBmp = (Bitmap)Image.FromFile(fileName, true); + BitmapColorsCached = new byte[sourceBmp.Width, sourceBmp.Height]; + Size = sourceBmp.Width; + for (int w = 0; w < sourceBmp.Width; w++) + { + for (int h = 0; h < sourceBmp.Height; h++) + { + Color c = sourceBmp.GetPixel(w, h); + BitmapColorsCached[w, h] = (byte)((c.R + c.B + c.G) / 3); + } + } + } + } +} diff --git a/Render/Mesh.cs b/Render/Mesh.cs new file mode 100644 index 0000000..01fb1fe --- /dev/null +++ b/Render/Mesh.cs @@ -0,0 +1,159 @@ +/* Mesh - all the things that define a mesh. triangles, edges, verticies... later UVs... + * + * + */ +using System; +using System.Collections.Generic; +using System.IO; +using ConsoleGraphics.Maths; + +namespace ConsoleGraphics.Render +{ + public class Mesh + { + public Vector3[] Vertices; + public Triangle[] Faces; + public Vector2[] UVs; + public Material[] Materials; + public int VerticesCount; + public int FacesCount; + + public Mesh(Vector3[] meshVerts, Triangle[] meshFaces, Vector2[] meshUvs, Material[] mats = null) + { + Vertices = meshVerts; + VerticesCount = Vertices.Length; + Faces = meshFaces; + FacesCount = Faces.Length; + UVs = meshUvs; + Materials = mats; + } + + public static Mesh LoadMeshFromFile(string fileName) + { + StreamReader reader = new StreamReader(fileName); + List loadedVerts = new List(); + List loadedUvs = new List(); + List loadedFaces = new List(); + //List loadedUvFaces = new List(); + List mtls = new List(); + int vertCount = 0; + int faceCount = 0; + + while (!reader.EndOfStream) + { + string e1 = reader.ReadLine(); + if (e1 != "") + { + if (e1[0] == 'v' && e1[1] == 't')//texture verticies + { + string temp = e1.Substring(3, e1.Length - 3); + string[] coords = temp.Split(' '); + Vector2 p = new Vector2(float.Parse(coords[0]), float.Parse(coords[1])); + loadedUvs.Add(p); + } + else if (e1[0] == 'v')//vertex + { + vertCount++; + string temp = e1.Substring(3, e1.Length - 3); + string[] coords = temp.Split(' '); + Vector3 p = new Vector3(float.Parse(coords[0]) * 100, float.Parse(coords[1]) * 100, float.Parse(coords[2])); + //if z is positive it's off screen, z=0 we clip + loadedVerts.Add(p); + } + else if (e1[0] == 'u') + {//use this mtl for rest of faces faces material + Material m = new Material(e1.Substring(7, e1.Length - 7)); + mtls.Add(m); + } + else if (e1[0] == 'f')//edge + { + faceCount++; + string temp = e1.Substring(2, e1.Length - 2); + string[] coords = temp.Split(' ', '/'); + Triangle f = new Triangle(int.Parse(coords[0]) - 1, int.Parse(coords[2]) - 1, int.Parse(coords[4]) - 1, /*UV ID's*/ int.Parse(coords[1]) - 1, int.Parse(coords[3]) - 1, int.Parse(coords[5]) - 1, mtls.Count); + // Triangle uvf = new Triangle(int.Parse(coords[1]), int.Parse(coords[3]), int.Parse(coords[5])); + loadedFaces.Add(f); + // loadedUvFaces.Add(uvf); + } + } + } + return (new Mesh(loadedVerts.ToArray(), loadedFaces.ToArray(), loadedUvs.ToArray(), mtls.ToArray())); + } + + public void Translate(Vector3 translation) + { + for (int i = 0; i < Vertices.Length; i++) + { + Vertices[i].Add(translation); + } + } + + public void Translate(float x, float y, float z) + { + for (int i = 0; i < Vertices.Length; i++) + { + Vertices[i].Add(x, y, z); + } + } + + public void Rotate(double angle, byte dir) + { + //Rotate about centerpoint of the shape: translate the center of our shape to the origin, rotate, translate back. + float cosAngle = (float)Math.Cos(angle); + float sinAngle = (float)Math.Sin(angle); + Vector3 startCoords = Vertices[0]; + Translate(new Vector3(-startCoords.X, -startCoords.Y, -startCoords.Z)); + #region rotations + /* Rotate about X Axis {{1,0, 0}, + {0, cosAngle,sinAngle*100}, + {0, -sinAngle/100, cosAngle}}, 3, 3); + + + * Rotate about Y Axis {{cosAngle,0,-sinAngle*100}, + {0, 1, 0}, + {sinAngle, 0, cosAngle}}, 3, 3); + Rotate about Z axis + * {{cosAngle,-sinAngle,0}, + {sinAngle, cosAngle,0}, + {0, 0, 1}},3,3); + */ + #endregion + int x = Environment.TickCount; + + Matrix rotationMatrix; + if (dir == 0) + rotationMatrix = new Matrix( + new float[,] + { + {1, 0, 0}, + {0, cosAngle, sinAngle * 100}, + {0, -sinAngle / 100, cosAngle} + }, 3, 3); + else if (dir == 1) + rotationMatrix = new Matrix( + new float[,] + { + {cosAngle, 0, -sinAngle * 100}, + {0, 1, 0}, + {sinAngle / 100, 0, cosAngle} + }, 3, 3); + else + rotationMatrix = new Matrix( + new float[,] + { + {cosAngle, -sinAngle, 0}, + {sinAngle, cosAngle, 0}, + {0, 0, 1} + }, 3, 3); + + x = Environment.TickCount - x; + + for (int i = 0; i < VerticesCount; i++) + { + Vertices[i] = rotationMatrix.Multiply(Vertices[i]); + } + + Translate(new Vector3(startCoords.X, startCoords.Y, startCoords.Z)); + } + } +} diff --git a/Render/Rasterize.cs b/Render/Rasterize.cs new file mode 100644 index 0000000..8e543b2 --- /dev/null +++ b/Render/Rasterize.cs @@ -0,0 +1,379 @@ +/* Rasterization - all the grunt work! + * Determine pixle 'colors'.. + */ + +using System; +using ConsoleGraphics.Maths; + +namespace ConsoleGraphics.Render +{ + public class Rasterizer + { + public static int[,] zBuffer = new int[Game.RENDER_WIDTH, Game.RENDER_HEIGHT]; + + private static Triangle TargetFace; + + public static byte[,] RenderVertices(Mesh someShape) + { + byte[,] image = new byte[Game.RENDER_WIDTH, Game.RENDER_HEIGHT]; + + for (int x = 0; x < Game.RENDER_WIDTH; x++) + for (int y = 0; y < Game.RENDER_HEIGHT; y++) + image[x, y] = 32; + + foreach (Triangle f in someShape.Faces) + { + // each vertex + for (int i = 0; i < 3; i++) + { + double depth = someShape.Vertices[f.VertexIds[i]].Z; + int P_x1 = (int)(someShape.Vertices[f.VertexIds[i]].X / depth); + int P_y1 = (int)(someShape.Vertices[f.VertexIds[i]].Y / depth); + + //the vert is in bounds with the screen + if (P_y1 < Game.RENDER_HEIGHT - 1 && P_y1 >= 0 && P_x1 < Game.RENDER_WIDTH - 1 && P_x1 >= 0) + image[P_x1, P_y1] = 177; + } + } + return (image); + } + + public static byte[,] RenderWire(Mesh someShape) + { + byte[,] image = new byte[Game.RENDER_WIDTH, Game.RENDER_HEIGHT];// + + for (int x = 0; x < Game.RENDER_WIDTH; x++) + for (int y = 0; y < Game.RENDER_HEIGHT; y++) + image[x, y] = 32; + + foreach (Triangle f in someShape.Faces) + { + for (int i = 0; i < 3; i++)//each vertex + { + double depth = someShape.Vertices[f.VertexIds[i]].Z; + int P_x1 = (int)((Game.RENDER_WIDTH / 2) + someShape.Vertices[f.VertexIds[i]].X / depth); + int P_y1 = (int)(((Game.RENDER_HEIGHT - 15) / 2) + someShape.Vertices[f.VertexIds[i]].Y / depth); + + //the vert is in bounds with the screen + if (P_y1 < Game.RENDER_HEIGHT - 1 && P_y1 >= 0 && P_x1 < Game.RENDER_WIDTH - 1 && P_x1 >= 0) + { + //each of the 2 neighboring verts + for (int j = 0; j < 2; j++) + { + double depth2 = someShape.Vertices[f.VertexIds[j]].Z; + int P_x = (int)((Game.RENDER_WIDTH / 2) + someShape.Vertices[f.VertexIds[j]].X / depth2); + int P_y = (int)(((Game.RENDER_HEIGHT - 15) / 2) + someShape.Vertices[f.VertexIds[j]].Y / depth2); + + if (P_y < Game.RENDER_HEIGHT - 1 && P_y >= 0 && P_x < Game.RENDER_WIDTH - 1 && P_x >= 0) + image = DrawLine(image, P_x, P_y, P_x1, P_y1, true); + } + } + } + } + return (image); + } + + public static byte[,] RenderSolid(Mesh someShape) + { + byte[,] image = new byte[Game.RENDER_WIDTH, Game.RENDER_HEIGHT]; + + for (int x = 0; x < Game.RENDER_WIDTH; x++) + { + for (int y = 0; y < Game.RENDER_HEIGHT; y++) + { + image[x, y] = 32; //space character is drawn faster than the null character (0) + zBuffer[x, y] = -100; //far clipping plane + } + } + + foreach (Triangle f in someShape.Faces) + { + TargetFace = f; + Vector3 a = Vector3.Add(someShape.Vertices[f.VertexIds[0]], new Vector3(-someShape.Vertices[f.VertexIds[2]].X, -someShape.Vertices[f.VertexIds[2]].Y, -someShape.Vertices[f.VertexIds[2]].Z)); + Vector3 b = Vector3.Add(someShape.Vertices[f.VertexIds[0]], new Vector3(-someShape.Vertices[f.VertexIds[1]].X, -someShape.Vertices[f.VertexIds[1]].Y, -someShape.Vertices[f.VertexIds[1]].Z)); + Vector3 surfaceNorm1 = Vector3.Cross(a, b); + + surfaceNorm1 = Vector3.Normalize(surfaceNorm1); + + Vector3 lightNorm1 = Vector3.Add(Game.light1.Coordinates, new Vector3(-someShape.Vertices[f.VertexIds[0]].X, -someShape.Vertices[f.VertexIds[0]].Y, -someShape.Vertices[f.VertexIds[0]].Z));//arbitrary vert + lightNorm1 = Vector3.Normalize(lightNorm1); + //////////////////////////////////// + Vector3 a1 = Vector3.Add(someShape.Vertices[f.VertexIds[1]], new Vector3(-someShape.Vertices[f.VertexIds[2]].X, -someShape.Vertices[f.VertexIds[2]].Y, -someShape.Vertices[f.VertexIds[2]].Z)); + Vector3 b1 = Vector3.Add(someShape.Vertices[f.VertexIds[1]], new Vector3(-someShape.Vertices[f.VertexIds[0]].X, -someShape.Vertices[f.VertexIds[0]].Y, -someShape.Vertices[f.VertexIds[0]].Z)); + Vector3 surfaceNorm2 = Vector3.Cross(a1, b1); + + surfaceNorm2 = Vector3.Normalize(surfaceNorm2); + + Vector3 lightNorm2 = Vector3.Add(Game.light1.Coordinates, new Vector3(-someShape.Vertices[f.VertexIds[1]].X, -someShape.Vertices[f.VertexIds[1]].Y, -someShape.Vertices[f.VertexIds[1]].Z));//arbitrary vert + lightNorm2 = Vector3.Normalize(lightNorm2); + ////////////////////////////////////////////// + Vector3 a2 = Vector3.Add(someShape.Vertices[f.VertexIds[2]], new Vector3(-someShape.Vertices[f.VertexIds[0]].X, -someShape.Vertices[f.VertexIds[0]].Y, -someShape.Vertices[f.VertexIds[0]].Z)); + Vector3 b2 = Vector3.Add(someShape.Vertices[f.VertexIds[2]], new Vector3(-someShape.Vertices[f.VertexIds[1]].X, -someShape.Vertices[f.VertexIds[1]].Y, -someShape.Vertices[f.VertexIds[1]].Z)); + Vector3 surfaceNorm3 = Vector3.Cross(a2, b2); + + surfaceNorm3 = Vector3.Normalize(surfaceNorm3); + + Vector3 lightNorm3 = Vector3.Add(Game.light1.Coordinates, new Vector3(-someShape.Vertices[f.VertexIds[2]].X, -someShape.Vertices[f.VertexIds[2]].Y, -someShape.Vertices[f.VertexIds[2]].Z));//arbitrary vert + lightNorm3 = Vector3.Normalize(lightNorm3); + //////////////////////////////////////////// + + //perspective projection + float[] depth = {someShape.Vertices[f.VertexIds[0]].Z, + someShape.Vertices[f.VertexIds[1]].Z, + someShape.Vertices[f.VertexIds[2]].Z}; + + if (depth[0] < 0 && depth[1] < 0 && depth[2] < 0) + { //>= one vertex is in screen + int x0 = (int)((Game.RENDER_WIDTH / 2) + someShape.Vertices[f.VertexIds[0]].X / depth[0]); + int y0 = (int)(((Game.RENDER_HEIGHT - 15) / 2) + someShape.Vertices[f.VertexIds[0]].Y / depth[0]); + + int x1 = (int)((Game.RENDER_WIDTH / 2) + someShape.Vertices[f.VertexIds[1]].X / depth[1]); + int y1 = (int)(((Game.RENDER_HEIGHT - 15) / 2) + someShape.Vertices[f.VertexIds[1]].Y / depth[1]); + + int x2 = (int)((Game.RENDER_WIDTH / 2) + someShape.Vertices[f.VertexIds[2]].X / depth[2]); + int y2 = (int)(((Game.RENDER_HEIGHT - 15) / 2) + someShape.Vertices[f.VertexIds[2]].Y / depth[2]); + + + Vector2[] uvs = new Vector2[] + { + someShape.UVs[f.UVIds[0]], + someShape.UVs[f.UVIds[1]], + someShape.UVs[f.UVIds[2]] + }; + + Vector3[] projPoints = new Vector3[] + { + new Vector3(x0, y0, depth[0]), + new Vector3(x1, y1, depth[1]), + new Vector3(x2, y2, depth[2]) + }; + + byte[] colors = new byte[] + { + (byte)(Game.light1.Intensity * Math.Max(0, Vector3.Dot(surfaceNorm1, lightNorm1))), + (byte)(Game.light1.Intensity * Math.Max(0, Vector3.Dot(surfaceNorm2, lightNorm2))), + (byte)(Game.light1.Intensity * Math.Max(0, Vector3.Dot(surfaceNorm3, lightNorm3))) + }; + + image = DrawTriangle(image, projPoints, uvs, colors); + } + } + return image; + } + + private static byte[,] DrawTriangle(byte[,] image, Vector3[] points, Vector2[] uvs, byte[] brightness = null) + { + /* + * A + * B------- + * C + * + */ + //sort by lowest y value (highest on screen) + Vector3[] unsortedPoints = new Vector3[3]; + points.CopyTo(unsortedPoints, 0); + + if (points[1].Y < points[0].Y) + {//swap point[1] and point[0] + MathHelper.Swap(ref points[0].Y, ref points[1].Y); + MathHelper.Swap(ref points[0].X, ref points[1].X); + } + if (points[2].Y < points[0].Y) + {//swap point[0] and point[2] + MathHelper.Swap(ref points[0].Y, ref points[2].Y); + MathHelper.Swap(ref points[0].X, ref points[2].X); + } + if (points[2].Y < points[1].Y) + {//swap point[1] & point[2] + MathHelper.Swap(ref points[1].Y, ref points[2].Y); + MathHelper.Swap(ref points[1].X, ref points[2].X); + } + + if (points[0].Y == points[1].Y) + {//flat top + image = FillFlatTop(image, points, unsortedPoints, brightness, uvs); + } + else if (points[1].Y == points[2].Y) + {//flat bottom + image = FillFlatBottom(image, points, unsortedPoints, brightness, uvs); + } + else + {//nontrivial + Vector3 midpoint = new Vector3((int)(Math.Ceiling(points[0].X + ((float)(points[1].Y - points[0].Y) / (float)(points[2].Y - points[0].Y)) * (points[2].X - points[0].X))), points[1].Y); + FillFlatBottom(image, new Vector3[] { points[0], points[1], midpoint }, unsortedPoints, brightness, uvs); + FillFlatTop(image, new Vector3[] { points[1], midpoint, points[2] }, unsortedPoints, brightness, uvs); + } + return (image); + } + + private static byte[,] FillFlatTop(byte[,] image, Vector3[] sortedPoints, Vector3[] unsortedPoints, byte[] brightness, Vector2[] uvs = null) + { + float startX = sortedPoints[2].X; + float endX = sortedPoints[2].X; + + float invslope1 = (float)(sortedPoints[2].X - sortedPoints[0].X) / (float)(sortedPoints[2].Y - sortedPoints[0].Y); + float invslope2 = (float)(sortedPoints[2].X - sortedPoints[1].X) / (float)(sortedPoints[2].Y - sortedPoints[1].Y); + + for (int scanlineY = (int)sortedPoints[2].Y; scanlineY > sortedPoints[0].Y; scanlineY--) + { + DrawLine(image, (int)startX, scanlineY, (int)endX, scanlineY, false, unsortedPoints, brightness, uvs); + startX -= invslope1; + endX -= invslope2; + } + return (image); + } + + private static byte[,] FillFlatBottom( + byte[,] image, + Vector3[] sortedPoints, + Vector3[] unsortedPoints, + byte[] brightness, + Vector2[] uvs = null) + { + float invslope1 = (float)(sortedPoints[2].X - sortedPoints[0].X) / (float)(sortedPoints[2].Y - sortedPoints[0].Y); + float invslope2 = (float)(sortedPoints[0].X - sortedPoints[1].X) / (float)(sortedPoints[0].Y - sortedPoints[1].Y); + + float curx1 = sortedPoints[0].X; + float curx2 = sortedPoints[0].X; + + for (int scanlineY = (int)sortedPoints[0].Y; scanlineY <= sortedPoints[1].Y; scanlineY++) + { + DrawLine(image, (int)curx1, scanlineY, (int)curx2, scanlineY, false, unsortedPoints, brightness, uvs); + curx1 += invslope1; + curx2 += invslope2; + } + return (image); + } + + public static byte[,] DrawLine( + byte[,] image, + // start + int x0, int y0, + int x1, int y1, + // end + bool drawWireFrame, + Vector3[] unsortedPoints = null, + byte[] color = null, + Vector2[] uvs = null) + { + float rise = y1 - y0; + float run = x1 - x0; + byte txl = 219; + //if (color != null) + //{ + // color[0] = 0; + // color[1] = 50; + // color[2] = 100; + //} + if (run == 0) + { + if (drawWireFrame) + txl = 124;// | + + if (y0 > y1) + MathHelper.Swap(ref y0, ref y1); + + while (y0 < y1)//DRAW + { + image[x0, y0] = txl; + y0++; + } + return (image); + } + + float m = rise / run; + + if (-1 <= rise / run && rise / run <= 1) + { + + if (drawWireFrame) + { + if (rise / run > 0.5) + txl = 92;// / + else if (rise / run < -0.5) + txl = 47;// \ + else + txl = 95;// - + } + + if (x0 > x1) + { + MathHelper.Swap(ref x0, ref x1); + MathHelper.Swap(ref y0, ref y1); + } + + float y = y0; + float x = x0; + float denom = 0; + if (!drawWireFrame) + denom = ((unsortedPoints[1].Y - unsortedPoints[2].Y) * (unsortedPoints[0].X - unsortedPoints[2].X) + (unsortedPoints[2].X - unsortedPoints[1].X) * (unsortedPoints[0].Y - unsortedPoints[2].Y)); + + while (x <= x1 && y < Game.RENDER_HEIGHT && x < Game.RENDER_WIDTH && y >= 0) + { + if (x > 0)//clipping logic < ^ + { + int xtoi = (int)x; + int ytoi = (int)y; + if (drawWireFrame) + { + image[xtoi, ytoi] = txl; + y += m; + } + else + { + //HERE'S WHERE WE DRAW TRIANGLES! + float b1 = (((unsortedPoints[1].Y - unsortedPoints[2].Y) * (x - unsortedPoints[2].X)) + ((unsortedPoints[2].X - unsortedPoints[1].X) * (y - unsortedPoints[2].Y))) / denom; + float b2 = (((unsortedPoints[2].Y - unsortedPoints[0].Y) * (x - unsortedPoints[2].X)) + ((unsortedPoints[0].X - unsortedPoints[2].X) * (y - unsortedPoints[2].Y))) / denom; + float b3 = 1 - b1 - b2; + + int interpolatedZ = (int)(b1 * unsortedPoints[0].Z + b2 * unsortedPoints[1].Z + b3 * unsortedPoints[2].Z); + + if (interpolatedZ > zBuffer[xtoi, ytoi]) + { + // use barycentric interpolation to do everything.. + float interpU = (float)(b1 * uvs[0].X + b2 * uvs[1].X + b3 * uvs[2].X); + float interpV = (float)(b1 * uvs[0].Y + b2 * uvs[1].Y + b3 * uvs[2].Y); + float interpBright = color[1];// + b2 * (float)color[1] + b3 * (float)color[2]); + Material material = Game.ActiveMesh.Materials[TargetFace.MaterialId - 1]; + + int xpos = Math.Min(Math.Max((int)(interpU * material.Size), 0), material.Size - 1); + int ypos = Math.Min(Math.Max((int)(interpV * material.Size), 0), material.Size - 1); + + byte fa = material.BitmapColorsCached[(int)MathHelper.Clamp(xpos, 0, material.Size - 1), (int)MathHelper.Clamp(ypos, 0, material.Size - 1)]; + image[xtoi, ytoi] = (byte)(Convert.ToInt32(Game.levels[(int)MathHelper.Clamp(fa + interpBright, 0, 255)])); + zBuffer[xtoi, ytoi] = interpolatedZ; + } + } + } + x++; + } + } + else + { + if (run / rise > 0.5) + txl = 92;// / + else if (run / rise < -0.5) + txl = 47;// \ + else + txl = 124;// - + + if (y0 > y1) + { + MathHelper.Swap(ref x0, ref x1); + MathHelper.Swap(ref y0, ref y1); + } + + float x = x0; + float invSlope = 1 / m; + + while (y0 < y1) + { + image[(int)x, y0] = txl; + x += invSlope; + y0++; + } + } + return (image); + } + } +} diff --git a/YoungLink.bmp b/Resources/Textures/YoungLink.bmp similarity index 100% rename from YoungLink.bmp rename to Resources/Textures/YoungLink.bmp diff --git a/levels.txt b/Resources/levels.txt similarity index 100% rename from levels.txt rename to Resources/levels.txt diff --git a/Utils/ThreeState.cs b/Utils/ThreeState.cs new file mode 100644 index 0000000..ddd511d --- /dev/null +++ b/Utils/ThreeState.cs @@ -0,0 +1,17 @@ +namespace ConsoleGraphics.Utils +{ + public struct ThreeState + { + public byte x; + + public ThreeState(byte initialState) + { + x = 0; + } + + public void changeState() + { + x = (byte)((x + 1) % 3); + } + } +} diff --git a/csbuild.csproj b/csbuild.csproj index d2c9584..42aaf39 100644 --- a/csbuild.csproj +++ b/csbuild.csproj @@ -42,16 +42,22 @@ - - - - - - + + + + + + + + + + + + - + Always @@ -62,12 +68,12 @@ - + Always - + Always diff --git a/link.obj b/link.obj deleted file mode 100644 index ae433c9..0000000 --- a/link.obj +++ /dev/null @@ -1,1340 +0,0 @@ -# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware -# File Created: 10.01.2015 11:09:19 - -# -# object Regroup24 -# - -v 0.6500 3.7043 0.1008 -v 0.5093 3.7324 0.2711 -v 0.4631 3.6402 0.3538 -v 0.2454 3.3350 0.1493 -v 0.2538 3.2557 0.5010 -v 0.0148 3.2065 0.3867 -v -0.3575 3.4402 0.1700 -v -0.3551 3.3859 0.4216 -v -0.3724 3.5410 0.4660 -v -0.2984 3.3805 0.6717 -v -0.2391 3.2557 0.5010 -v -0.1771 3.2376 0.6692 -v -0.2266 3.3350 0.1493 -v 0.0001 3.1298 0.6558 -v -0.2525 3.5116 0.7146 -v -0.2625 3.6870 0.7385 -v 0.0001 3.5293 0.7754 -v -0.3898 3.7002 0.5074 -v -0.0835 3.3643 0.7914 -v 0.0001 3.4326 0.9066 -v -0.4437 3.6402 0.3538 -v 0.1952 3.2370 0.6694 -v 0.1006 3.3640 0.7910 -v 0.0001 3.7097 0.7920 -v -0.0313 3.8689 0.7830 -v -0.1495 3.9362 0.7218 -v 0.3140 3.3805 0.6717 -v 0.2685 3.5107 0.7154 -v 0.1156 3.9497 0.7369 -v 0.2803 3.6862 0.7394 -v 0.4182 3.7002 0.5074 -v 0.3888 3.5409 0.4666 -v 0.3718 3.3859 0.4216 -v -0.6353 3.7054 0.1015 -v -0.4942 3.7324 0.2711 -v -0.0994 3.3517 0.0201 -v 0.3725 3.4400 0.1705 -v 0.1283 3.3524 0.0219 -v -0.0985 3.2386 -0.0081 -v 0.1320 3.2386 -0.0081 -v 0.1972 3.1373 0.1448 -v 0.0001 3.0061 0.3165 -v -0.1777 3.1373 0.1448 -v 0.1438 2.1895 0.2657 -v 0.0001 2.2184 -0.2293 -v -0.1670 2.1887 0.2638 -v 0.4045 1.9710 0.0343 -v 0.3971 2.2023 0.0498 -v -0.1690 1.8902 0.2460 -v -0.4167 2.1994 0.0479 -v -0.4228 1.9710 0.0343 -v 0.1470 1.8902 0.2460 -v 0.0001 1.9902 -0.2582 -v -0.0305 4.1649 0.7574 -v 0.0065 4.2353 1.0055 -v 0.0395 4.2251 0.6670 -v 0.2261 3.9369 1.0735 -v 0.3460 4.1908 0.7374 -v 0.5075 3.8941 0.7437 -v 0.5150 3.5445 0.7498 -v 0.2975 3.6246 0.9042 -v 0.4138 4.0891 0.5413 -v -0.4365 3.5391 0.7632 -v -0.5406 3.8380 0.6363 -v -0.3481 3.6452 0.8526 -v -0.2905 3.9799 1.0519 -v -0.0996 4.2112 1.0295 -v -0.1185 4.2251 0.6670 -v -0.4369 4.1037 0.6108 -v 0.0091 3.3358 -0.1591 -v 0.3366 3.4630 0.0013 -v -0.3206 3.4640 -0.0009 -v 0.1944 3.0332 0.2829 -v -0.2425 3.2223 -0.0503 -v -0.2006 3.0332 0.2829 -v 0.0001 2.8189 0.4559 -v 0.2211 3.2223 -0.0503 -v 0.0001 3.2593 0.7577 -v 0.3546 2.9628 0.4124 -v 0.2646 3.3363 -0.0869 -v -0.3615 2.9628 0.4127 -v -0.2473 3.3363 -0.1090 -v 0.0001 4.4341 0.3208 -v -0.2971 4.3602 0.1926 -v 0.0001 4.4821 -0.1856 -v 0.3144 4.3602 0.1926 -v 0.4781 4.2168 -0.1794 -v -0.4619 4.2168 -0.1794 -v -0.4527 3.7130 -0.1694 -v 0.4696 3.7116 -0.1661 -v -0.5317 3.0904 0.1047 -v -0.5577 3.0459 -0.1571 -v -0.5683 2.8166 -0.1824 -v -0.2924 2.4178 -0.3895 -v -0.6009 2.3787 -0.1960 -v 0.5605 2.8166 -0.1824 -v 0.5923 2.3787 -0.1960 -v 0.2824 2.4178 -0.3895 -v 0.0001 2.5555 0.5125 -v -0.3173 2.1172 0.4856 -v 0.3073 2.1172 0.4856 -v 0.6261 2.7180 0.0008 -v 0.5652 2.7107 0.3069 -v 0.5825 2.3508 0.1888 -v -0.2834 3.0914 -0.1868 -v -0.5899 2.3508 0.1888 -v -0.4289 1.9806 0.2741 -v 0.4181 1.9806 0.2741 -v -0.5652 2.7107 0.3070 -v -0.5382 2.9454 0.2761 -v 0.5384 2.9454 0.2762 -v -0.6335 2.7180 0.0008 -v 0.5320 3.0904 0.1047 -v 0.0001 1.9957 -0.0645 -v 0.4173 2.1454 -0.3814 -v -0.4298 2.1454 -0.3814 -v 0.2749 3.0914 -0.1868 -v 0.5575 3.0459 -0.1571 -v -0.5964 2.6538 -0.1795 -v -0.5850 2.4241 -0.0510 -v 0.5964 2.6538 -0.1803 -v 0.5851 2.4243 -0.0538 -v -0.3823 3.5667 -0.4784 -v 0.3903 3.5667 -0.4784 -v 0.2851 3.7159 -0.6525 -v 0.2905 3.5394 -0.0945 -v -0.2806 3.7159 -0.6525 -v 0.0001 3.7098 -0.8376 -v -0.2836 3.5394 -0.0945 -v 0.2970 3.2345 -0.5518 -v 0.0114 3.2172 -0.3064 -v -0.2717 3.2345 -0.5518 -v 0.0001 2.8602 -0.5945 -v 0.0088 3.2931 -0.8176 -v -0.4272 1.9463 -0.1506 -v 0.4116 1.9463 -0.1510 -v -0.3998 1.8717 0.1756 -v -0.3223 1.9184 -0.2891 -v 0.6075 1.1533 -0.1356 -v 0.6252 1.6673 -0.0918 -v 0.7651 1.2474 0.0888 -v 0.4753 1.8045 0.1205 -v 0.4442 1.3427 0.5996 -v 0.6779 1.3491 0.4073 -v 0.2949 1.1058 -0.2049 -v 0.4742 1.5854 -0.2767 -v 0.2592 1.5098 -0.3445 -v 0.2364 1.3125 0.6031 -v 0.1564 1.8345 0.2917 -v 0.0349 1.6952 0.3177 -v 0.0001 1.3786 0.2859 -v 0.0001 1.3434 -0.5335 -v 0.3860 1.8717 0.1756 -v 0.5543 1.8395 0.0233 -v 0.0352 1.7029 -0.4445 -v 0.3076 1.9184 -0.2891 -v 0.0414 1.8419 -0.3975 -v -0.7843 1.2474 0.0888 -v -0.4711 1.5854 -0.2767 -v -0.6101 1.1533 -0.1356 -v -0.4981 1.3427 0.5996 -v -0.5002 1.8045 0.1205 -v -0.7192 1.3491 0.4073 -v -0.2504 1.5098 -0.3445 -v -0.2936 1.1061 -0.2060 -v -0.6351 1.6673 -0.0918 -v -0.2905 1.3125 0.6031 -v -0.1699 1.8345 0.2919 -v -0.0462 1.6944 0.3146 -v -0.5683 1.8395 0.0233 -v -0.0511 1.7029 -0.4445 -v -0.0574 1.8419 -0.3975 -v 0.3669 0.5949 0.4079 -v 0.1074 0.7729 0.0465 -v 0.2581 0.3109 -0.0222 -v 0.2503 0.3707 -0.2076 -v 0.3183 0.8381 -0.2049 -v 0.5227 0.4206 -0.2834 -v 0.6660 0.6512 0.3267 -v 0.3568 0.7591 0.3005 -v 0.5643 0.7974 0.2441 -v 0.6560 0.8763 -0.0878 -v 0.6474 0.3841 -0.1308 -v 0.5029 0.2752 0.0655 -v 0.2171 0.8500 0.0713 -v 0.3398 0.9269 -0.0631 -v 0.5643 0.9154 -0.0161 -v 0.4760 0.0149 -0.3733 -v 0.1870 0.0143 0.0759 -v 0.3252 0.1550 0.3433 -v 0.5876 0.2785 0.2208 -v 0.2116 0.0173 -0.2542 -v 0.7396 0.0115 -0.1727 -v 0.8469 0.1524 0.1097 -v 0.5773 0.0071 0.5454 -v 0.2939 0.0107 0.3538 -v 0.8757 0.0076 0.0919 -v 0.6789 0.1808 0.4272 -v 0.8312 0.0059 0.4311 -v 0.3511 0.9560 0.3969 -v 0.5533 0.9947 0.3415 -v 0.3175 1.1236 -0.0066 -v 0.5645 1.1095 0.1034 -v 0.2027 1.0429 0.2015 -v 0.2279 1.0698 0.2428 -v 0.3638 1.0581 0.1120 -v 0.5113 1.2343 0.3911 -v 0.3234 1.1973 0.4439 -v 0.5330 1.1301 0.1580 -v 0.4816 1.4650 -0.0181 -v 0.2363 1.4470 -0.0890 -v 0.1566 1.4343 0.0823 -v 0.5000 1.4371 0.2679 -v 0.2308 1.3887 0.3437 -v 0.8832 2.4410 0.0089 -v 0.8694 2.3330 -0.0968 -v 0.8359 2.4247 -0.1333 -v 0.7617 2.3497 0.2301 -v 0.7375 2.4769 0.1133 -v 0.9566 2.3269 0.1115 -v 0.6206 2.4234 0.0410 -v 0.6278 2.2247 0.1094 -v 0.7246 2.2901 -0.1053 -v 0.7001 2.3592 -0.1351 -v 0.9174 2.1939 -0.0606 -v 0.8454 1.8851 0.1941 -v 0.7173 2.1413 -0.0469 -v 0.9522 1.9197 0.1994 -v 0.7735 1.9567 0.2996 -v 0.9647 2.0000 0.2952 -v 0.8626 2.0135 0.3633 -v 0.7062 2.5424 -0.1761 -v 0.8296 2.5442 0.1063 -v 0.6372 2.6072 0.1816 -v 0.8679 2.5743 -0.0818 -v 1.1037 1.5774 0.3775 -v 0.8769 1.5347 0.5967 -v 0.6960 1.6892 0.4880 -v 1.0247 1.7881 0.6604 -v 0.9322 1.9818 0.5498 -v 1.1546 1.7148 0.3738 -v 1.1061 1.8395 0.2604 -v 0.8877 2.0259 0.3737 -v 0.7540 1.9545 0.3154 -v 0.8576 1.8862 0.1687 -v 0.9167 1.6631 0.3033 -v 0.6549 1.8655 0.4703 -v 0.9761 1.7458 0.1736 -v 0.9915 1.9568 0.2277 -v 0.7793 2.7864 0.1381 -v 0.7598 2.8999 0.1175 -v 0.5384 2.9454 0.2760 -v 0.8153 2.8149 -0.0433 -v 1.0201 2.5364 0.0521 -v -0.8359 2.4247 -0.1333 -v -0.8694 2.3330 -0.0968 -v -0.8832 2.4410 0.0089 -v -0.7375 2.4769 0.1133 -v -0.7617 2.3497 0.2301 -v -0.9566 2.3269 0.1115 -v -0.6278 2.2247 0.1094 -v -0.6206 2.4234 0.0410 -v -0.7001 2.3592 -0.1351 -v -0.7246 2.2901 -0.1053 -v -0.9174 2.1939 -0.0606 -v -0.9522 1.9197 0.1994 -v -0.7173 2.1413 -0.0469 -v -0.8454 1.8851 0.1941 -v -0.7735 1.9567 0.2996 -v -0.9647 2.0000 0.2952 -v -0.8626 2.0135 0.3633 -v -0.7062 2.5424 -0.1761 -v -0.6372 2.6072 0.1816 -v -0.8296 2.5442 0.1063 -v -0.8679 2.5743 -0.0818 -v -0.6960 1.6892 0.4880 -v -0.8769 1.5347 0.5967 -v -1.1037 1.5774 0.3775 -v -1.0247 1.7881 0.6604 -v -0.9322 1.9818 0.5498 -v -1.1061 1.8395 0.2604 -v -1.1546 1.7148 0.3738 -v -0.8877 2.0259 0.3737 -v -0.8576 1.8862 0.1687 -v -0.7540 1.9545 0.3154 -v -0.6549 1.8655 0.4703 -v -0.9167 1.6631 0.3033 -v -0.9761 1.7458 0.1736 -v -0.9915 1.9568 0.2277 -v -0.7598 2.8999 0.1175 -v -0.7793 2.7864 0.1381 -v -0.8153 2.8149 -0.0433 -v -1.0201 2.5364 0.0521 -v -0.2581 0.3109 -0.0222 -v -0.1074 0.7729 0.0465 -v -0.3669 0.5949 0.4079 -v -0.2503 0.3707 -0.2076 -v -0.3183 0.8381 -0.2049 -v -0.5227 0.4206 -0.2834 -v -0.3568 0.7591 0.3005 -v -0.6660 0.6512 0.3267 -v -0.5643 0.7974 0.2441 -v -0.6560 0.8763 -0.0878 -v -0.6474 0.3841 -0.1308 -v -0.5029 0.2752 0.0655 -v -0.3398 0.9269 -0.0631 -v -0.2171 0.8500 0.0713 -v -0.5643 0.9154 -0.0161 -v -0.4760 0.0149 -0.3733 -v -0.1870 0.0143 0.0759 -v -0.5876 0.2785 0.2208 -v -0.3252 0.1550 0.3433 -v -0.2116 0.0173 -0.2542 -v -0.7396 0.0115 -0.1727 -v -0.8469 0.1524 0.1097 -v -0.2939 0.0107 0.3538 -v -0.5773 0.0071 0.5454 -v -0.8757 0.0076 0.0919 -v -0.6789 0.1808 0.4272 -v -0.8312 0.0059 0.4311 -v -0.5533 0.9947 0.3415 -v -0.3511 0.9560 0.3969 -v -0.5645 1.1095 0.1034 -v -0.3175 1.1236 -0.0066 -v -0.2027 1.0429 0.2015 -v -0.3638 1.0581 0.1120 -v -0.2279 1.0698 0.2428 -v -0.5113 1.2343 0.3911 -v -0.3234 1.1973 0.4439 -v -0.5330 1.1301 0.1580 -v -0.4816 1.4650 -0.0181 -v -0.2363 1.4470 -0.0890 -v -0.1566 1.4343 0.0823 -v -0.5000 1.4371 0.2679 -v -0.2308 1.3887 0.3437 -# 335 vertices - -vt 0.2135 0.0260 0.0000 -vt 0.2591 0.0428 0.0000 -vt 0.2222 0.0676 0.0000 -vt 0.1124 0.1603 0.0000 -vt 0.0642 0.1761 0.0000 -vt 0.0951 0.2220 0.0000 -vt 0.3095 0.2325 0.0000 -vt 0.2772 0.2438 0.0000 -vt 0.3622 0.2162 0.0000 -vt 0.2576 0.2373 0.0000 -vt 0.1799 0.2519 0.0000 -vt 0.1533 0.2468 0.0000 -vt 0.2235 0.2329 0.0000 -vt 0.0528 0.2394 0.0000 -vt 0.3151 0.2047 0.0000 -vt 0.4101 0.1722 0.0000 -vt 0.2625 0.1615 0.0000 -vt 0.4512 0.1876 0.0000 -vt 0.1970 0.2081 0.0000 -vt 0.2097 0.1811 0.0000 -vt 0.4310 0.2082 0.0000 -vt 0.0654 0.1897 0.0000 -vt 0.1534 0.1797 0.0000 -vt 0.3574 0.1263 0.0000 -vt 0.4512 0.1014 0.0000 -vt 0.5152 0.1062 0.0000 -vt 0.1137 0.1432 0.0000 -vt 0.1924 0.1250 0.0000 -vt 0.4595 0.0628 0.0000 -vt 0.2820 0.0889 0.0000 -vt 0.2590 0.0646 0.0000 -vt 0.1837 0.0996 0.0000 -vt 0.1063 0.1323 0.0000 -vt 0.5156 0.2228 0.0000 -vt 0.4944 0.1969 0.0000 -vt 0.2041 0.2096 0.0000 -vt 0.1379 0.1203 0.0000 -vt 0.1505 0.1745 0.0000 -vt 0.1389 0.2343 0.0000 -vt 0.0845 0.1988 0.0000 -vt 0.0316 0.2012 0.0000 -vt 0.0265 0.2483 0.0000 -vt 0.1201 0.2589 0.0000 -vt 0.8245 0.3764 0.0000 -vt 0.8552 0.3620 0.0000 -vt 0.8515 0.3759 0.0000 -vt 0.8046 0.3199 0.0000 -vt 0.7671 0.3625 0.0000 -vt 0.8032 0.3704 0.0000 -vt 0.7088 0.3112 0.0000 -vt 0.7312 0.3699 0.0000 -vt 0.7296 0.3196 0.0000 -vt 0.8257 0.3108 0.0000 -vt 0.7671 0.3118 0.0000 -vt 0.7104 0.3767 0.0000 -vt 0.7941 0.8715 0.0000 -vt 0.8152 0.8743 0.0000 -vt 0.7814 0.8715 0.0000 -vt 0.8160 0.8556 0.0000 -vt 0.8060 0.8547 0.0000 -vt 0.8423 0.8531 0.0000 -vt 0.7907 0.8603 0.0000 -vt 0.8108 0.8388 0.0000 -vt 0.8341 0.8195 0.0000 -vt 0.8449 0.8323 0.0000 -vt 0.7768 0.8511 0.0000 -vt 0.7868 0.8236 0.0000 -vt 0.7717 0.8262 0.0000 -vt 0.7991 0.8293 0.0000 -vt 0.8044 0.8213 0.0000 -vt 0.7821 0.8149 0.0000 -vt 0.7931 0.8223 0.0000 -vt 0.7682 0.8166 0.0000 -vt 0.8315 0.8149 0.0000 -vt 0.7989 0.8237 0.0000 -vt 0.8328 0.8250 0.0000 -vt 0.7977 0.8469 0.0000 -vt 0.8299 0.8463 0.0000 -vt 0.8102 0.8661 0.0000 -vt 0.8077 0.8496 0.0000 -vt 0.7849 0.8640 0.0000 -vt 0.7730 0.8618 0.0000 -vt 0.7773 0.8412 0.0000 -vt 0.8004 0.8431 0.0000 -vt 0.7773 0.8669 0.0000 -vt 0.8175 0.8526 0.0000 -vt 0.8327 0.8278 0.0000 -vt 0.8955 0.8308 0.0000 -vt 0.7126 0.9067 0.0000 -vt 0.7122 0.9055 0.0000 -vt 0.6562 0.8658 0.0000 -vt 0.7125 0.9010 0.0000 -vt 0.6316 0.8917 0.0000 -vt 0.7138 0.8403 0.0000 -vt 0.6525 0.8642 0.0000 -vt 0.7151 0.8399 0.0000 -vt 0.3771 0.6591 0.0000 -vt 0.4945 0.6355 0.0000 -vt 0.4423 0.7310 0.0000 -vt 0.5454 0.6962 0.0000 -vt 0.5968 0.6356 0.0000 -vt 0.5452 0.7879 0.0000 -vt 0.6480 0.7314 0.0000 -vt 0.7153 0.6600 0.0000 -vt 0.6163 0.0332 0.0000 -vt 0.6640 0.0716 0.0000 -vt 0.5685 0.0716 0.0000 -vt 0.5873 0.2558 0.0000 -vt 0.5703 0.1607 0.0000 -vt 0.5767 0.1372 0.0000 -vt 0.5790 0.1445 0.0000 -vt 0.5685 0.1681 0.0000 -vt 0.5986 0.1305 0.0000 -vt 0.5726 0.1759 0.0000 -vt 0.5985 0.1597 0.0000 -vt 0.5777 0.2146 0.0000 -vt 0.5713 0.1746 0.0000 -vt 0.5984 0.2161 0.0000 -vt 0.5848 0.2442 0.0000 -vt 0.5982 0.2580 0.0000 -vt 0.8853 0.6459 0.0000 -vt 0.8556 0.6355 0.0000 -vt 0.8881 0.6562 0.0000 -vt 0.8883 0.6804 0.0000 -vt 0.8605 0.7261 0.0000 -vt 0.8915 0.7259 0.0000 -vt 0.7747 0.6804 0.0000 -vt 0.7715 0.7259 0.0000 -vt 0.8027 0.7261 0.0000 -vt 0.8316 0.6925 0.0000 -vt 0.8631 0.7384 0.0000 -vt 0.8002 0.7384 0.0000 -vt 0.7682 0.6867 0.0000 -vt 0.7726 0.7205 0.0000 -vt 0.8597 0.6522 0.0000 -vt 0.8906 0.7205 0.0000 -vt 0.8743 0.7572 0.0000 -vt 0.7891 0.7572 0.0000 -vt 0.8860 0.6572 0.0000 -vt 0.7770 0.6572 0.0000 -vt 0.8948 0.6867 0.0000 -vt 0.8316 0.6665 0.0000 -vt 0.8116 0.6480 0.0000 -vt 0.7777 0.6459 0.0000 -vt 0.8514 0.6480 0.0000 -vt 0.8310 0.7629 0.0000 -vt 0.7891 0.7542 0.0000 -vt 0.8743 0.7542 0.0000 -vt 0.8035 0.6522 0.0000 -vt 0.7750 0.6562 0.0000 -vt 0.8089 0.6355 0.0000 -vt 0.9088 0.3283 0.0000 -vt 0.9347 0.3327 0.0000 -vt 0.9121 0.3504 0.0000 -vt 0.9135 0.3216 0.0000 -vt 0.9509 0.3223 0.0000 -vt 0.9443 0.3530 0.0000 -vt 0.9735 0.3592 0.0000 -vt 0.9692 0.3308 0.0000 -vt 0.9684 0.3675 0.0000 -vt 0.9263 0.3658 0.0000 -vt 0.5507 0.8617 0.0000 -vt 0.5279 0.8750 0.0000 -vt 0.5279 0.8465 0.0000 -vt 0.5470 0.8498 0.0000 -vt 0.5470 0.8828 0.0000 -vt 0.5319 0.8403 0.0000 -vt 0.5279 0.8961 0.0000 -vt 0.5496 0.8399 0.0000 -vt 0.5645 0.8636 0.0000 -vt 0.5620 0.8770 0.0000 -vt 0.5742 0.8681 0.0000 -vt 0.5654 0.8482 0.0000 -vt 0.4749 0.8399 0.0000 -vt 0.3867 0.9042 0.0000 -vt 0.4750 0.9042 0.0000 -vt 0.3879 0.8399 0.0000 -vt 0.6367 0.1288 0.0000 -vt 0.5886 0.1338 0.0000 -vt 0.5890 0.1288 0.0000 -vt 0.6846 0.1341 0.0000 -vt 0.6838 0.1286 0.0000 -vt 0.5916 0.1410 0.0000 -vt 0.6180 0.1379 0.0000 -vt 0.6005 0.1390 0.0000 -vt 0.6978 0.2376 0.0000 -vt 0.7052 0.1822 0.0000 -vt 0.7052 0.2450 0.0000 -vt 0.6893 0.1737 0.0000 -vt 0.6623 0.2482 0.0000 -vt 0.6931 0.2461 0.0000 -vt 0.6657 0.2279 0.0000 -vt 0.6966 0.1777 0.0000 -vt 0.6741 0.1748 0.0000 -vt 0.6393 0.2442 0.0000 -vt 0.6584 0.1476 0.0000 -vt 0.6446 0.1649 0.0000 -vt 0.6397 0.2053 0.0000 -vt 0.6394 0.2172 0.0000 -vt 0.6844 0.1441 0.0000 -vt 0.7033 0.1498 0.0000 -vt 0.6445 0.1708 0.0000 -vt 0.6755 0.1425 0.0000 -vt 0.6454 0.1528 0.0000 -vt 0.6875 0.1377 0.0000 -vt 0.5724 0.2532 0.0000 -vt 0.5865 0.1723 0.0000 -vt 0.5844 0.2452 0.0000 -vt 0.6193 0.2589 0.0000 -vt 0.5938 0.1674 0.0000 -vt 0.5889 0.2558 0.0000 -vt 0.6089 0.1691 0.0000 -vt 0.6164 0.2339 0.0000 -vt 0.5744 0.1790 0.0000 -vt 0.6422 0.2545 0.0000 -vt 0.6249 0.1363 0.0000 -vt 0.6428 0.2071 0.0000 -vt 0.6386 0.1578 0.0000 -vt 0.6426 0.2217 0.0000 -vt 0.5802 0.1377 0.0000 -vt 0.6382 0.1650 0.0000 -vt 0.6377 0.1431 0.0000 -vt 0.6080 0.1297 0.0000 -vt 0.5963 0.1236 0.0000 -vt 0.6815 0.1413 0.0000 -vt 0.6543 0.1378 0.0000 -vt 0.6421 0.1506 0.0000 -vt 0.6314 0.1701 0.0000 -vt 0.6307 0.1506 0.0000 -vt 0.7008 0.1472 0.0000 -vt 0.6414 0.1640 0.0000 -vt 0.6319 0.1642 0.0000 -vt 0.6366 0.2080 0.0000 -vt 0.6554 0.1451 0.0000 -vt 0.5723 0.1468 0.0000 -vt 0.6414 0.1701 0.0000 -vt 0.6362 0.2206 0.0000 -vt 0.6177 0.1450 0.0000 -vt 0.6726 0.1392 0.0000 -vt 0.1171 0.8175 0.0000 -vt 0.0996 0.8137 0.0000 -vt 0.1074 0.9276 0.0000 -vt 0.0971 0.9343 0.0000 -vt 0.0895 0.8288 0.0000 -vt 0.1582 0.8282 0.0000 -vt 0.1511 0.9341 0.0000 -vt 0.1676 0.9337 0.0000 -vt 0.1274 0.8172 0.0000 -vt 0.1151 0.8003 0.0000 -vt 0.1286 0.8000 0.0000 -vt 0.1449 0.8111 0.0000 -vt 0.1397 0.9273 0.0000 -vt 0.1232 0.9292 0.0000 -vt 0.0981 0.8030 0.0000 -vt 0.0894 0.8016 0.0000 -vt 0.1581 0.8009 0.0000 -vt 0.1460 0.8016 0.0000 -vt 0.8961 0.2518 0.0000 -vt 0.8864 0.1335 0.0000 -vt 0.8902 0.1363 0.0000 -vt 0.8510 0.2514 0.0000 -vt 0.8561 0.1236 0.0000 -vt 0.8322 0.1284 0.0000 -vt 0.8033 0.2053 0.0000 -vt 0.8046 0.1568 0.0000 -vt 0.8615 0.1271 0.0000 -vt 0.7586 0.2512 0.0000 -vt 0.8033 0.2515 0.0000 -vt 0.7682 0.1938 0.0000 -vt 0.7144 0.9075 0.0000 -vt 0.7152 0.9064 0.0000 -vt 0.7131 0.9080 0.0000 -vt 0.7135 0.9053 0.0000 -vt 0.9034 0.5146 0.0000 -vt 0.9377 0.5020 0.0000 -vt 0.9412 0.5360 0.0000 -vt 0.9496 0.5254 0.0000 -vt 0.9455 0.5426 0.0000 -vt 0.9465 0.5156 0.0000 -vt 0.9546 0.5330 0.0000 -vt 0.9510 0.5622 0.0000 -vt 0.9070 0.5309 0.0000 -vt 0.9021 0.5563 0.0000 -vt 0.9344 0.5805 0.0000 -vt 0.9309 0.5801 0.0000 -vt 0.9057 0.5775 0.0000 -vt 0.9081 0.5372 0.0000 -vt 0.9493 0.5614 0.0000 -vt 0.8939 0.5549 0.0000 -vt 0.9094 0.5780 0.0000 -vt 0.9499 0.5624 0.0000 -vt 0.9433 0.3160 0.0000 -vt 0.9536 0.3109 0.0000 -vt 0.9714 0.3317 0.0000 -vt 0.9377 0.3407 0.0000 -vt 0.9207 0.3279 0.0000 -vt 0.9700 0.3185 0.0000 -vt 0.9081 0.3108 0.0000 -# 298 texture coords - -g Regroup24 -usemtl YoungLink.bmp -f 1/1 2/2 3/3 -f 4/4 5/5 6/6 -f 7/7 8/8 9/9 -f 10/10 11/11 12/12 -f 11/11 10/10 8/8 -f 8/8 7/7 11/11 -f 11/11 13/13 6/6 -f 11/11 14/14 12/12 -f 15/15 16/16 9/9 -f 16/16 15/15 17/17 -f 9/9 16/16 18/18 -f 15/15 19/19 17/17 -f 20/20 17/17 19/19 -f 9/9 18/18 21/21 -f 14/14 5/5 22/22 -f 20/20 23/23 17/17 -f 24/24 16/16 17/17 -f 25/25 26/26 24/24 -f 27/27 28/28 23/23 -f 16/16 24/24 26/26 -f 29/29 30/30 31/31 -f 29/29 24/24 30/30 -f 16/16 26/26 18/18 -f 28/28 30/30 17/17 -f 32/32 30/30 28/28 -f 30/30 32/32 31/31 -f 30/30 24/24 17/17 -f 27/27 5/5 33/33 -f 23/23 28/28 17/17 -f 27/27 22/22 5/5 -f 27/27 32/32 28/28 -f 34/34 21/21 35/35 -f 34/34 35/35 7/7 -f 10/10 19/19 15/15 -f 27/27 33/33 32/32 -f 36/36 13/13 7/7 -f 10/10 15/15 9/9 -f 14/14 11/11 6/6 -f 6/6 5/5 14/14 -f 5/5 4/4 37/37 -f 4/4 38/38 37/37 -f 8/8 10/10 9/9 -f 13/13 11/11 7/7 -f 33/33 5/5 37/37 -f 1/1 37/37 2/2 -f 33/33 37/37 32/32 -f 29/29 25/25 24/24 -f 39/39 13/13 36/36 -f 40/40 4/4 41/41 -f 40/40 36/36 38/38 -f 42/42 4/4 6/6 -f 42/42 13/13 43/43 -f 39/39 36/36 40/40 -f 4/4 42/42 41/41 -f 13/13 42/42 6/6 -f 13/13 39/39 43/43 -f 4/4 40/40 38/38 -f 44/44 45/45 46/46 -f 47/47 45/48 48/49 -f 49/50 50/51 51/52 -f 52/53 48/49 44/44 -f 45/48 47/47 53/54 -f 45/48 44/44 48/49 -f 48/49 52/53 47/47 -f 45/48 51/52 50/51 -f 46/55 45/48 50/51 -f 50/51 49/50 46/55 -f 51/52 45/48 53/54 -f 54/56 55/57 56/58 -f 55/57 54/56 25/59 -f 55/57 29/60 57/61 -f 55/57 57/61 58/62 -f 59/63 58/62 57/61 -f 55/57 58/62 56/58 -f 60/64 59/63 61/65 -f 59/63 62/66 58/62 -f 3/67 2/68 31/69 -f 31/69 32/70 3/67 -f 60/64 2/68 59/63 -f 60/64 61/65 29/60 -f 56/58 58/62 62/66 -f 60/64 31/69 2/68 -f 59/63 2/68 62/66 -f 60/64 29/60 31/69 -f 59/63 57/61 61/65 -f 61/65 57/61 29/60 -f 55/57 25/59 29/60 -f 21/71 18/72 35/73 -f 63/74 64/75 35/73 -f 65/76 26/77 66/78 -f 65/76 18/72 26/77 -f 67/79 25/80 54/81 -f 63/74 65/76 64/75 -f 66/78 26/77 67/79 -f 67/79 26/77 25/80 -f 63/74 18/72 65/76 -f 54/81 68/82 67/79 -f 64/75 65/76 66/78 -f 64/75 66/78 69/83 -f 67/79 69/83 66/78 -f 67/79 68/82 69/83 -f 63/74 35/73 18/72 -f 64/75 69/83 35/73 -f 38/84 70/85 71/86 -f 37/87 38/84 71/86 -f 72/86 7/87 35/88 -f 71/86 2/88 37/87 -f 72/86 36/84 7/87 -f 36/84 70/85 38/84 -f 70/85 36/84 72/86 -f 41/89 42/89 73/89 -f 43/89 74/89 75/89 -f 40/89 74/89 39/89 -f 42/89 76/90 73/89 -f 41/89 77/89 40/89 -f 77/89 74/89 40/89 -f 43/89 75/89 42/89 -f 74/89 43/89 39/89 -f 75/89 76/90 42/89 -f 77/89 41/89 73/89 -f 21/91 7/92 9/93 -f 34/94 7/92 21/91 -f 3/95 32/93 37/92 -f 1/96 3/95 37/92 -f 27/97 23/98 22/99 -f 78/100 23/98 19/101 -f 14/102 22/99 78/100 -f 78/100 22/99 23/98 -f 12/103 19/101 10/104 -f 12/103 14/102 78/100 -f 12/103 78/100 19/101 -f 20/105 19/106 23/107 -f 79/108 80/108 77/108 -f 74/108 81/108 75/108 -f 82/108 74/108 77/108 -f 82/108 77/108 80/108 -f 73/108 76/108 79/108 -f 77/108 73/108 79/108 -f 82/108 81/108 74/108 -f 75/108 81/108 76/108 -f 68/109 83/110 84/111 -f 83/110 68/109 56/109 -f 54/112 56/109 68/109 -f 84/111 83/110 85/113 -f 86/111 56/109 62/114 -f 87/115 62/114 2/116 -f 86/111 87/115 85/113 -f 86/111 85/113 83/110 -f 86/111 62/114 87/115 -f 86/111 83/110 56/109 -f 69/117 84/111 88/115 -f 85/113 88/115 84/111 -f 35/116 88/115 89/118 -f 88/115 35/116 69/117 -f 90/118 71/119 70/120 -f 89/118 70/120 72/119 -f 90/118 2/116 71/119 -f 2/116 90/118 87/115 -f 35/116 89/118 72/119 -f 68/109 84/111 69/117 -f 91/121 74/122 92/123 -f 93/124 94/125 95/126 -f 96/127 97/128 98/129 -f 99/130 100/131 101/132 -f 102/133 103/127 104/134 -f 94/125 92/123 105/135 -f 100/131 106/136 107/137 -f 104/134 101/132 108/138 -f 109/124 99/130 110/139 -f 111/140 99/130 103/127 -f 112/141 95/126 106/136 -f 109/124 112/141 106/136 -f 76/142 111/140 73/143 -f 113/144 73/143 111/140 -f 76/142 110/139 99/130 -f 110/139 76/142 75/145 -f 114/146 115/147 108/138 -f 108/138 97/128 104/134 -f 105/135 98/129 94/125 -f 114/146 116/148 115/147 -f 107/137 116/148 114/146 -f 117/149 98/129 105/135 -f 118/150 98/129 117/149 -f 95/126 107/137 106/136 -f 95/126 94/125 116/148 -f 114/146 108/138 107/137 -f 92/123 74/122 105/135 -f 115/147 98/129 97/128 -f 74/122 117/149 105/135 -f 77/151 118/150 117/149 -f 101/132 107/137 108/138 -f 77/151 117/149 74/122 -f 115/147 94/125 98/129 -f 100/131 107/137 101/132 -f 97/128 102/133 104/134 -f 116/148 94/125 115/147 -f 73/143 113/144 77/151 -f 101/132 103/127 99/130 -f 74/122 91/121 75/145 -f 97/128 96/127 102/133 -f 112/141 93/124 95/126 -f 75/145 91/121 110/139 -f 99/130 111/140 76/142 -f 94/125 93/124 92/123 -f 103/127 101/132 104/134 -f 100/131 109/124 106/136 -f 107/137 95/126 116/148 -f 109/124 100/131 99/130 -f 118/150 77/151 113/144 -f 97/128 108/138 115/147 -f 98/129 118/150 96/127 -f 93/152 119/153 92/154 -f 119/153 93/152 112/155 -f 109/152 120/156 112/155 -f 120/156 119/153 112/155 -f 121/157 96/158 118/159 -f 96/158 121/157 102/160 -f 121/157 122/161 102/160 -f 122/161 103/158 102/160 -f 123/162 89/163 88/164 -f 87/164 124/162 125/165 -f 124/162 90/163 126/166 -f 88/164 127/165 123/162 -f 85/167 127/165 88/164 -f 125/165 85/167 87/164 -f 70/168 126/166 90/163 -f 85/167 125/165 128/169 -f 89/163 123/162 129/166 -f 127/165 85/167 128/169 -f 129/166 70/168 89/163 -f 90/163 124/162 87/164 -f 70/168 129/166 126/166 -f 130/170 126/166 131/171 -f 129/166 132/170 131/171 -f 133/172 131/171 132/170 -f 134/173 132/170 127/165 -f 130/170 125/165 124/162 -f 134/173 127/165 128/169 -f 130/170 134/173 125/165 -f 130/170 131/171 133/172 -f 132/170 134/173 133/172 -f 126/166 129/166 131/171 -f 125/165 134/173 128/169 -f 127/165 132/170 123/162 -f 126/166 130/170 124/162 -f 134/173 130/170 133/172 -f 132/170 129/166 123/162 -f 44/174 49/175 52/176 -f 49/175 44/174 46/177 -f 53/178 135/179 51/180 -f 136/181 53/178 47/182 -f 51/180 137/183 49/184 -f 135/179 53/178 138/185 -f 139/186 140/187 141/188 -f 142/189 143/190 144/191 -f 145/192 146/193 139/186 -f 146/193 140/187 139/186 -f 141/188 142/189 144/191 -f 147/194 146/193 145/192 -f 140/187 142/189 141/188 -f 148/195 149/196 150/197 -f 150/197 151/198 148/195 -f 152/199 147/194 145/192 -f 142/189 140/187 153/200 -f 153/200 140/187 154/201 -f 147/194 155/202 156/203 -f 156/203 155/202 157/204 -f 136/205 146/193 156/203 -f 156/203 146/193 147/194 -f 153/200 143/190 142/189 -f 140/187 136/205 154/201 -f 149/196 148/195 143/190 -f 149/196 143/190 153/200 -f 147/194 152/199 155/202 -f 136/205 140/187 146/193 -f 158/206 159/207 160/208 -f 161/209 162/210 163/211 -f 160/208 164/212 165/213 -f 166/214 159/207 158/206 -f 163/211 166/214 158/206 -f 159/207 164/212 160/208 -f 162/210 166/214 163/211 -f 167/215 168/216 161/209 -f 151/217 169/218 167/215 -f 164/212 152/219 165/213 -f 166/214 162/210 170/220 -f 170/220 162/210 137/113 -f 171/221 164/212 172/222 -f 172/222 164/212 138/223 -f 159/207 135/224 164/212 -f 164/212 135/224 138/223 -f 162/210 168/216 137/113 -f 135/224 166/214 170/220 -f 168/216 167/215 169/218 -f 161/209 168/216 162/210 -f 152/219 164/212 171/221 -f 166/214 135/224 159/207 -f 153/225 47/182 52/226 -f 157/227 171/228 172/229 -f 47/182 153/225 154/230 -f 53/178 172/229 138/185 -f 150/231 169/232 151/233 -f 47/182 154/230 136/181 -f 52/226 149/234 153/225 -f 137/183 51/180 170/235 -f 53/178 157/227 172/229 -f 171/228 155/236 152/237 -f 49/184 137/183 168/238 -f 53/178 156/239 157/227 -f 51/180 135/179 170/235 -f 49/184 149/234 52/226 -f 171/228 157/227 155/236 -f 168/238 150/231 149/234 -f 168/238 149/234 49/184 -f 169/232 150/231 168/238 -f 53/178 136/181 156/239 -f 51/180 135/179 53/178 -f 47/182 53/178 136/181 -f 49/184 137/183 51/180 -f 138/185 53/178 135/179 -f 141/188 140/187 139/186 -f 144/191 143/190 142/189 -f 139/186 146/193 145/192 -f 139/186 140/187 146/193 -f 144/191 142/189 141/188 -f 145/192 146/193 147/194 -f 141/188 142/189 140/187 -f 150/197 149/196 148/195 -f 148/195 151/198 150/197 -f 145/192 147/194 152/199 -f 153/200 140/187 142/189 -f 154/201 140/187 153/200 -f 156/203 155/202 147/194 -f 157/204 155/202 156/203 -f 156/203 146/193 136/205 -f 147/194 146/193 156/203 -f 142/189 143/190 153/200 -f 154/201 136/205 140/187 -f 143/190 148/195 149/196 -f 153/200 143/190 149/196 -f 155/202 152/199 147/194 -f 146/193 140/187 136/205 -f 160/208 159/207 158/206 -f 163/211 162/210 161/209 -f 165/213 164/212 160/208 -f 158/206 159/207 166/214 -f 158/206 166/214 163/211 -f 160/208 164/212 159/207 -f 163/211 166/214 162/210 -f 161/209 168/216 167/215 -f 167/215 169/218 151/217 -f 165/213 152/219 164/212 -f 170/220 162/210 166/214 -f 137/113 162/210 170/220 -f 172/222 164/212 171/221 -f 138/223 164/212 172/222 -f 164/212 135/224 159/207 -f 138/223 135/224 164/212 -f 137/113 168/216 162/210 -f 170/220 166/214 135/224 -f 169/218 167/215 168/216 -f 162/210 168/216 161/209 -f 171/221 164/212 152/219 -f 159/207 135/224 166/214 -f 52/226 47/182 153/225 -f 172/229 171/228 157/227 -f 154/230 153/225 47/182 -f 138/185 172/229 53/178 -f 151/233 169/232 150/231 -f 136/181 154/230 47/182 -f 153/225 149/234 52/226 -f 170/235 51/180 137/183 -f 172/229 157/227 53/178 -f 152/237 155/236 171/228 -f 168/238 137/183 49/184 -f 157/227 156/239 53/178 -f 170/235 135/179 51/180 -f 52/226 149/234 49/184 -f 155/236 157/227 171/228 -f 149/234 150/231 168/238 -f 49/184 149/234 168/238 -f 168/238 150/231 169/232 -f 156/239 136/181 53/178 -f 173/240 174/241 175/242 -f 176/243 175/242 174/241 -f 174/241 177/244 176/243 -f 177/245 178/246 176/247 -f 173/240 179/248 180/249 -f 180/249 179/248 181/250 -f 179/248 182/251 181/250 -f 182/251 183/252 178/246 -f 179/248 184/253 183/252 -f 184/253 173/240 175/242 -f 185/254 186/255 177/244 -f 179/248 173/240 184/253 -f 183/252 182/251 179/248 -f 186/256 187/257 177/245 -f 174/241 173/240 180/249 -f 177/245 182/251 178/246 -f 180/249 185/254 174/241 -f 187/257 181/250 182/251 -f 185/254 177/244 174/241 -f 177/245 187/257 182/251 -f 188/258 176/259 178/260 -f 189/261 175/262 176/259 -f 184/263 190/264 191/265 -f 192/258 176/259 188/258 -f 176/259 192/258 189/261 -f 175/262 190/264 184/263 -f 188/258 178/260 193/261 -f 183/266 193/261 178/260 -f 194/264 183/266 191/265 -f 191/265 183/266 184/263 -f 175/262 189/261 190/264 -f 193/261 183/266 194/264 -f 193/261 189/261 188/258 -f 188/258 189/261 192/258 -f 195/267 190/264 196/268 -f 193/261 194/264 197/268 -f 198/269 194/264 191/265 -f 198/269 190/264 195/267 -f 193/261 196/268 189/261 -f 197/268 196/268 193/261 -f 199/267 194/264 198/269 -f 198/269 195/267 199/267 -f 190/264 198/269 191/265 -f 194/264 199/267 197/268 -f 196/268 197/268 195/267 -f 195/267 197/268 199/267 -f 190/264 189/261 196/268 -f 200/270 180/270 201/270 -f 201/270 180/270 181/270 -f 187/271 202/271 203/271 -f 202/271 185/271 204/271 -f 203/271 201/270 181/270 -f 185/271 202/271 186/271 -f 185/271 180/270 204/271 -f 181/270 187/271 203/271 -f 200/270 204/271 180/270 -f 202/271 187/271 186/271 -f 204/271 205/270 206/271 -f 201/270 203/271 207/270 -f 207/270 208/270 201/270 -f 201/270 208/270 200/270 -f 205/270 204/271 208/270 -f 206/271 203/271 202/271 -f 203/271 209/270 207/270 -f 208/270 204/271 200/270 -f 209/270 203/271 206/271 -f 204/271 206/271 202/271 -f 210/89 207/270 209/270 -f 210/89 209/270 211/89 -f 211/89 205/270 212/89 -f 213/270 207/270 210/89 -f 211/89 209/270 206/271 -f 205/270 211/89 206/271 -f 212/89 205/270 214/270 -f 214/270 205/270 208/270 -f 214/270 208/270 213/270 -f 213/270 208/270 207/270 -f 215/89 216/90 217/90 -f 218/272 215/89 219/89 -f 215/89 218/272 220/89 -f 218/272 221/89 222/89 -f 217/90 223/89 224/89 -f 221/89 223/89 222/89 -f 221/89 218/272 219/89 -f 216/90 223/89 217/90 -f 225/273 215/89 220/89 -f 223/89 221/89 224/89 -f 216/90 215/89 225/273 -f 226/271 227/89 228/271 -f 228/271 227/89 225/273 -f 222/89 227/89 229/270 -f 229/270 227/89 226/271 -f 225/273 220/89 228/271 -f 228/271 220/89 230/270 -f 218/272 222/89 231/270 -f 231/270 222/89 229/270 -f 227/89 216/90 225/273 -f 222/89 223/89 227/89 -f 231/270 220/89 218/272 -f 223/89 216/90 227/89 -f 229/270 230/270 231/270 -f 230/270 220/89 231/270 -f 228/271 230/270 226/271 -f 226/271 230/270 229/270 -f 224/273 122/89 232/90 -f 219/89 233/89 234/89 -f 215/89 235/90 233/89 -f 217/273 235/90 215/89 -f 122/89 224/273 221/89 -f 233/89 219/89 215/89 -f 234/89 221/89 219/89 -f 217/273 232/90 235/90 -f 122/89 121/90 232/90 -f 121/90 235/90 232/90 -f 232/90 217/273 224/273 -f 221/89 234/89 122/89 -f 236/274 237/275 238/276 -f 236/274 239/277 237/275 -f 238/278 237/279 239/280 -f 240/281 238/278 239/280 -f 240/281 241/282 242/283 -f 242/283 243/284 240/281 -f 244/285 243/284 245/286 -f 239/277 241/282 240/281 -f 241/282 236/274 242/283 -f 239/277 236/274 241/282 -f 246/287 247/288 245/286 -f 248/289 245/286 242/283 -f 238/276 247/288 246/287 -f 248/289 246/287 245/286 -f 238/276 246/287 236/274 -f 236/274 246/287 248/289 -f 243/284 242/283 249/290 -f 242/283 236/274 248/289 -f 249/290 242/283 245/286 -f 243/284 249/290 245/286 -f 240/281 243/284 247/288 -f 238/278 240/281 247/291 -f 244/285 245/286 247/288 -f 243/284 244/285 247/288 -f 250/292 251/293 252/294 -f 103/158 122/161 234/295 -f 250/292 103/158 233/296 -f 233/296 103/158 234/295 -f 113/297 252/294 251/293 -f 251/293 118/159 113/297 -f 118/159 253/292 121/157 -f 118/159 251/293 253/292 -f 103/158 250/292 252/294 -f 254/298 250/292 233/296 -f 254/298 253/292 250/292 -f 233/296 235/296 254/298 -f 253/292 254/298 235/296 -f 251/293 250/292 253/292 -f 235/296 121/157 253/292 -f 255/90 256/90 257/89 -f 258/89 257/89 259/272 -f 260/89 259/272 257/89 -f 261/89 262/89 259/272 -f 263/89 264/89 255/90 -f 261/89 264/89 262/89 -f 258/89 259/272 262/89 -f 255/90 264/89 256/90 -f 260/89 257/89 265/273 -f 263/89 262/89 264/89 -f 265/273 257/89 256/90 -f 266/271 267/89 268/271 -f 265/273 267/89 266/271 -f 269/270 267/89 261/89 -f 268/271 267/89 269/270 -f 266/271 260/89 265/273 -f 270/270 260/89 266/271 -f 271/270 261/89 259/272 -f 269/270 261/89 271/270 -f 265/273 256/90 267/89 -f 267/89 264/89 261/89 -f 259/272 260/89 271/270 -f 267/89 256/90 264/89 -f 271/270 270/270 269/270 -f 271/270 260/89 270/270 -f 268/271 270/270 266/271 -f 269/270 270/270 268/271 -f 272/90 120/89 263/273 -f 273/89 274/89 258/89 -f 274/89 275/90 257/89 -f 257/89 275/90 255/273 -f 262/89 263/273 120/89 -f 257/89 258/89 274/89 -f 258/89 262/89 273/89 -f 275/90 272/90 255/273 -f 272/90 119/90 120/89 -f 272/90 275/90 119/90 -f 263/273 255/273 272/90 -f 120/89 273/89 262/89 -f 276/276 277/275 278/274 -f 277/275 279/277 278/274 -f 279/280 277/279 276/278 -f 279/280 276/278 280/281 -f 281/283 282/282 280/281 -f 280/281 283/284 281/283 -f 284/286 283/284 285/285 -f 280/281 282/282 279/277 -f 281/283 278/274 282/282 -f 282/282 278/274 279/277 -f 284/286 286/288 287/287 -f 281/283 284/286 288/289 -f 287/287 286/288 276/276 -f 284/286 287/287 288/289 -f 278/274 287/287 276/276 -f 288/289 287/287 278/274 -f 289/290 281/283 283/284 -f 288/289 278/274 281/283 -f 284/286 281/283 289/290 -f 284/286 289/290 283/284 -f 286/288 283/284 280/281 -f 286/291 280/281 276/278 -f 286/288 284/286 285/285 -f 286/288 285/285 283/284 -f 110/294 290/293 291/292 -f 273/295 120/161 109/158 -f 274/296 109/158 291/292 -f 273/295 109/158 274/296 -f 290/293 110/294 91/297 -f 91/297 92/159 290/293 -f 119/157 292/292 92/159 -f 292/292 290/293 92/159 -f 110/294 291/292 109/158 -f 274/296 291/292 293/298 -f 291/292 292/292 293/298 -f 293/298 275/296 274/296 -f 275/296 293/298 292/292 -f 292/292 291/292 290/293 -f 292/292 119/157 275/296 -f 294/242 295/241 296/240 -f 295/241 294/242 297/243 -f 297/243 298/244 295/241 -f 297/247 299/246 298/245 -f 300/249 301/248 296/240 -f 302/250 301/248 300/249 -f 302/250 303/251 301/248 -f 299/246 304/252 303/251 -f 304/252 305/253 301/248 -f 294/242 296/240 305/253 -f 298/244 306/255 307/254 -f 305/253 296/240 301/248 -f 301/248 303/251 304/252 -f 298/245 308/257 306/256 -f 300/249 296/240 295/241 -f 299/246 303/251 298/245 -f 295/241 307/254 300/249 -f 303/251 302/250 308/257 -f 295/241 298/244 307/254 -f 303/251 308/257 298/245 -f 299/260 297/259 309/258 -f 297/259 294/262 310/261 -f 311/265 312/264 305/263 -f 309/258 297/259 313/258 -f 310/261 313/258 297/259 -f 305/263 312/264 294/262 -f 314/261 299/260 309/258 -f 299/260 314/261 304/266 -f 311/265 304/266 315/264 -f 305/263 304/266 311/265 -f 312/264 310/261 294/262 -f 315/264 304/266 314/261 -f 309/258 310/261 314/261 -f 313/258 310/261 309/258 -f 316/268 312/264 317/267 -f 318/268 315/264 314/261 -f 311/265 315/264 319/269 -f 317/267 312/264 319/269 -f 310/261 316/268 314/261 -f 314/261 316/268 318/268 -f 319/269 315/264 320/267 -f 320/267 317/267 319/269 -f 311/265 319/269 312/264 -f 318/268 320/267 315/264 -f 317/267 318/268 316/268 -f 320/267 318/268 317/267 -f 316/268 310/261 312/264 -f 321/270 300/270 322/270 -f 302/270 300/270 321/270 -f 323/271 324/271 308/271 -f 325/271 307/271 324/271 -f 302/270 321/270 323/271 -f 306/271 324/271 307/271 -f 325/271 300/270 307/271 -f 323/271 308/271 302/270 -f 300/270 325/271 322/270 -f 306/271 308/271 324/271 -f 326/271 327/270 325/271 -f 328/270 323/271 321/270 -f 321/270 329/270 328/270 -f 322/270 329/270 321/270 -f 329/270 325/271 327/270 -f 324/271 323/271 326/271 -f 328/270 330/270 323/271 -f 322/270 325/271 329/270 -f 326/271 323/271 330/270 -f 324/271 326/271 325/271 -f 330/270 328/270 331/89 -f 332/89 330/270 331/89 -f 333/89 327/270 332/89 -f 331/89 328/270 334/270 -f 326/271 330/270 332/89 -f 326/271 332/89 327/270 -f 335/270 327/270 333/89 -f 329/270 327/270 335/270 -f 334/270 329/270 335/270 -f 328/270 329/270 334/270 -# 693 faces From 921d33ed079ab362d449d5af235e55faa1a2bf9e Mon Sep 17 00:00:00 2001 From: jared bw Date: Tue, 23 Mar 2021 11:49:00 +0000 Subject: [PATCH 2/2] added obj file --- Resources/Meshes/link.obj | 1340 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1340 insertions(+) create mode 100644 Resources/Meshes/link.obj diff --git a/Resources/Meshes/link.obj b/Resources/Meshes/link.obj new file mode 100644 index 0000000..4b1ace9 --- /dev/null +++ b/Resources/Meshes/link.obj @@ -0,0 +1,1340 @@ +# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware +# File Created: 10.01.2015 11:09:19 + +# +# object Regroup24 +# + +v 0.6500 3.7043 0.1008 +v 0.5093 3.7324 0.2711 +v 0.4631 3.6402 0.3538 +v 0.2454 3.3350 0.1493 +v 0.2538 3.2557 0.5010 +v 0.0148 3.2065 0.3867 +v -0.3575 3.4402 0.1700 +v -0.3551 3.3859 0.4216 +v -0.3724 3.5410 0.4660 +v -0.2984 3.3805 0.6717 +v -0.2391 3.2557 0.5010 +v -0.1771 3.2376 0.6692 +v -0.2266 3.3350 0.1493 +v 0.0001 3.1298 0.6558 +v -0.2525 3.5116 0.7146 +v -0.2625 3.6870 0.7385 +v 0.0001 3.5293 0.7754 +v -0.3898 3.7002 0.5074 +v -0.0835 3.3643 0.7914 +v 0.0001 3.4326 0.9066 +v -0.4437 3.6402 0.3538 +v 0.1952 3.2370 0.6694 +v 0.1006 3.3640 0.7910 +v 0.0001 3.7097 0.7920 +v -0.0313 3.8689 0.7830 +v -0.1495 3.9362 0.7218 +v 0.3140 3.3805 0.6717 +v 0.2685 3.5107 0.7154 +v 0.1156 3.9497 0.7369 +v 0.2803 3.6862 0.7394 +v 0.4182 3.7002 0.5074 +v 0.3888 3.5409 0.4666 +v 0.3718 3.3859 0.4216 +v -0.6353 3.7054 0.1015 +v -0.4942 3.7324 0.2711 +v -0.0994 3.3517 0.0201 +v 0.3725 3.4400 0.1705 +v 0.1283 3.3524 0.0219 +v -0.0985 3.2386 -0.0081 +v 0.1320 3.2386 -0.0081 +v 0.1972 3.1373 0.1448 +v 0.0001 3.0061 0.3165 +v -0.1777 3.1373 0.1448 +v 0.1438 2.1895 0.2657 +v 0.0001 2.2184 -0.2293 +v -0.1670 2.1887 0.2638 +v 0.4045 1.9710 0.0343 +v 0.3971 2.2023 0.0498 +v -0.1690 1.8902 0.2460 +v -0.4167 2.1994 0.0479 +v -0.4228 1.9710 0.0343 +v 0.1470 1.8902 0.2460 +v 0.0001 1.9902 -0.2582 +v -0.0305 4.1649 0.7574 +v 0.0065 4.2353 1.0055 +v 0.0395 4.2251 0.6670 +v 0.2261 3.9369 1.0735 +v 0.3460 4.1908 0.7374 +v 0.5075 3.8941 0.7437 +v 0.5150 3.5445 0.7498 +v 0.2975 3.6246 0.9042 +v 0.4138 4.0891 0.5413 +v -0.4365 3.5391 0.7632 +v -0.5406 3.8380 0.6363 +v -0.3481 3.6452 0.8526 +v -0.2905 3.9799 1.0519 +v -0.0996 4.2112 1.0295 +v -0.1185 4.2251 0.6670 +v -0.4369 4.1037 0.6108 +v 0.0091 3.3358 -0.1591 +v 0.3366 3.4630 0.0013 +v -0.3206 3.4640 -0.0009 +v 0.1944 3.0332 0.2829 +v -0.2425 3.2223 -0.0503 +v -0.2006 3.0332 0.2829 +v 0.0001 2.8189 0.4559 +v 0.2211 3.2223 -0.0503 +v 0.0001 3.2593 0.7577 +v 0.3546 2.9628 0.4124 +v 0.2646 3.3363 -0.0869 +v -0.3615 2.9628 0.4127 +v -0.2473 3.3363 -0.1090 +v 0.0001 4.4341 0.3208 +v -0.2971 4.3602 0.1926 +v 0.0001 4.4821 -0.1856 +v 0.3144 4.3602 0.1926 +v 0.4781 4.2168 -0.1794 +v -0.4619 4.2168 -0.1794 +v -0.4527 3.7130 -0.1694 +v 0.4696 3.7116 -0.1661 +v -0.5317 3.0904 0.1047 +v -0.5577 3.0459 -0.1571 +v -0.5683 2.8166 -0.1824 +v -0.2924 2.4178 -0.3895 +v -0.6009 2.3787 -0.1960 +v 0.5605 2.8166 -0.1824 +v 0.5923 2.3787 -0.1960 +v 0.2824 2.4178 -0.3895 +v 0.0001 2.5555 0.5125 +v -0.3173 2.1172 0.4856 +v 0.3073 2.1172 0.4856 +v 0.6261 2.7180 0.0008 +v 0.5652 2.7107 0.3069 +v 0.5825 2.3508 0.1888 +v -0.2834 3.0914 -0.1868 +v -0.5899 2.3508 0.1888 +v -0.4289 1.9806 0.2741 +v 0.4181 1.9806 0.2741 +v -0.5652 2.7107 0.3070 +v -0.5382 2.9454 0.2761 +v 0.5384 2.9454 0.2762 +v -0.6335 2.7180 0.0008 +v 0.5320 3.0904 0.1047 +v 0.0001 1.9957 -0.0645 +v 0.4173 2.1454 -0.3814 +v -0.4298 2.1454 -0.3814 +v 0.2749 3.0914 -0.1868 +v 0.5575 3.0459 -0.1571 +v -0.5964 2.6538 -0.1795 +v -0.5850 2.4241 -0.0510 +v 0.5964 2.6538 -0.1803 +v 0.5851 2.4243 -0.0538 +v -0.3823 3.5667 -0.4784 +v 0.3903 3.5667 -0.4784 +v 0.2851 3.7159 -0.6525 +v 0.2905 3.5394 -0.0945 +v -0.2806 3.7159 -0.6525 +v 0.0001 3.7098 -0.8376 +v -0.2836 3.5394 -0.0945 +v 0.2970 3.2345 -0.5518 +v 0.0114 3.2172 -0.3064 +v -0.2717 3.2345 -0.5518 +v 0.0001 2.8602 -0.5945 +v 0.0088 3.2931 -0.8176 +v -0.4272 1.9463 -0.1506 +v 0.4116 1.9463 -0.1510 +v -0.3998 1.8717 0.1756 +v -0.3223 1.9184 -0.2891 +v 0.6075 1.1533 -0.1356 +v 0.6252 1.6673 -0.0918 +v 0.7651 1.2474 0.0888 +v 0.4753 1.8045 0.1205 +v 0.4442 1.3427 0.5996 +v 0.6779 1.3491 0.4073 +v 0.2949 1.1058 -0.2049 +v 0.4742 1.5854 -0.2767 +v 0.2592 1.5098 -0.3445 +v 0.2364 1.3125 0.6031 +v 0.1564 1.8345 0.2917 +v 0.0349 1.6952 0.3177 +v 0.0001 1.3786 0.2859 +v 0.0001 1.3434 -0.5335 +v 0.3860 1.8717 0.1756 +v 0.5543 1.8395 0.0233 +v 0.0352 1.7029 -0.4445 +v 0.3076 1.9184 -0.2891 +v 0.0414 1.8419 -0.3975 +v -0.7843 1.2474 0.0888 +v -0.4711 1.5854 -0.2767 +v -0.6101 1.1533 -0.1356 +v -0.4981 1.3427 0.5996 +v -0.5002 1.8045 0.1205 +v -0.7192 1.3491 0.4073 +v -0.2504 1.5098 -0.3445 +v -0.2936 1.1061 -0.2060 +v -0.6351 1.6673 -0.0918 +v -0.2905 1.3125 0.6031 +v -0.1699 1.8345 0.2919 +v -0.0462 1.6944 0.3146 +v -0.5683 1.8395 0.0233 +v -0.0511 1.7029 -0.4445 +v -0.0574 1.8419 -0.3975 +v 0.3669 0.5949 0.4079 +v 0.1074 0.7729 0.0465 +v 0.2581 0.3109 -0.0222 +v 0.2503 0.3707 -0.2076 +v 0.3183 0.8381 -0.2049 +v 0.5227 0.4206 -0.2834 +v 0.6660 0.6512 0.3267 +v 0.3568 0.7591 0.3005 +v 0.5643 0.7974 0.2441 +v 0.6560 0.8763 -0.0878 +v 0.6474 0.3841 -0.1308 +v 0.5029 0.2752 0.0655 +v 0.2171 0.8500 0.0713 +v 0.3398 0.9269 -0.0631 +v 0.5643 0.9154 -0.0161 +v 0.4760 0.0149 -0.3733 +v 0.1870 0.0143 0.0759 +v 0.3252 0.1550 0.3433 +v 0.5876 0.2785 0.2208 +v 0.2116 0.0173 -0.2542 +v 0.7396 0.0115 -0.1727 +v 0.8469 0.1524 0.1097 +v 0.5773 0.0071 0.5454 +v 0.2939 0.0107 0.3538 +v 0.8757 0.0076 0.0919 +v 0.6789 0.1808 0.4272 +v 0.8312 0.0059 0.4311 +v 0.3511 0.9560 0.3969 +v 0.5533 0.9947 0.3415 +v 0.3175 1.1236 -0.0066 +v 0.5645 1.1095 0.1034 +v 0.2027 1.0429 0.2015 +v 0.2279 1.0698 0.2428 +v 0.3638 1.0581 0.1120 +v 0.5113 1.2343 0.3911 +v 0.3234 1.1973 0.4439 +v 0.5330 1.1301 0.1580 +v 0.4816 1.4650 -0.0181 +v 0.2363 1.4470 -0.0890 +v 0.1566 1.4343 0.0823 +v 0.5000 1.4371 0.2679 +v 0.2308 1.3887 0.3437 +v 0.8832 2.4410 0.0089 +v 0.8694 2.3330 -0.0968 +v 0.8359 2.4247 -0.1333 +v 0.7617 2.3497 0.2301 +v 0.7375 2.4769 0.1133 +v 0.9566 2.3269 0.1115 +v 0.6206 2.4234 0.0410 +v 0.6278 2.2247 0.1094 +v 0.7246 2.2901 -0.1053 +v 0.7001 2.3592 -0.1351 +v 0.9174 2.1939 -0.0606 +v 0.8454 1.8851 0.1941 +v 0.7173 2.1413 -0.0469 +v 0.9522 1.9197 0.1994 +v 0.7735 1.9567 0.2996 +v 0.9647 2.0000 0.2952 +v 0.8626 2.0135 0.3633 +v 0.7062 2.5424 -0.1761 +v 0.8296 2.5442 0.1063 +v 0.6372 2.6072 0.1816 +v 0.8679 2.5743 -0.0818 +v 1.1037 1.5774 0.3775 +v 0.8769 1.5347 0.5967 +v 0.6960 1.6892 0.4880 +v 1.0247 1.7881 0.6604 +v 0.9322 1.9818 0.5498 +v 1.1546 1.7148 0.3738 +v 1.1061 1.8395 0.2604 +v 0.8877 2.0259 0.3737 +v 0.7540 1.9545 0.3154 +v 0.8576 1.8862 0.1687 +v 0.9167 1.6631 0.3033 +v 0.6549 1.8655 0.4703 +v 0.9761 1.7458 0.1736 +v 0.9915 1.9568 0.2277 +v 0.7793 2.7864 0.1381 +v 0.7598 2.8999 0.1175 +v 0.5384 2.9454 0.2760 +v 0.8153 2.8149 -0.0433 +v 1.0201 2.5364 0.0521 +v -0.8359 2.4247 -0.1333 +v -0.8694 2.3330 -0.0968 +v -0.8832 2.4410 0.0089 +v -0.7375 2.4769 0.1133 +v -0.7617 2.3497 0.2301 +v -0.9566 2.3269 0.1115 +v -0.6278 2.2247 0.1094 +v -0.6206 2.4234 0.0410 +v -0.7001 2.3592 -0.1351 +v -0.7246 2.2901 -0.1053 +v -0.9174 2.1939 -0.0606 +v -0.9522 1.9197 0.1994 +v -0.7173 2.1413 -0.0469 +v -0.8454 1.8851 0.1941 +v -0.7735 1.9567 0.2996 +v -0.9647 2.0000 0.2952 +v -0.8626 2.0135 0.3633 +v -0.7062 2.5424 -0.1761 +v -0.6372 2.6072 0.1816 +v -0.8296 2.5442 0.1063 +v -0.8679 2.5743 -0.0818 +v -0.6960 1.6892 0.4880 +v -0.8769 1.5347 0.5967 +v -1.1037 1.5774 0.3775 +v -1.0247 1.7881 0.6604 +v -0.9322 1.9818 0.5498 +v -1.1061 1.8395 0.2604 +v -1.1546 1.7148 0.3738 +v -0.8877 2.0259 0.3737 +v -0.8576 1.8862 0.1687 +v -0.7540 1.9545 0.3154 +v -0.6549 1.8655 0.4703 +v -0.9167 1.6631 0.3033 +v -0.9761 1.7458 0.1736 +v -0.9915 1.9568 0.2277 +v -0.7598 2.8999 0.1175 +v -0.7793 2.7864 0.1381 +v -0.8153 2.8149 -0.0433 +v -1.0201 2.5364 0.0521 +v -0.2581 0.3109 -0.0222 +v -0.1074 0.7729 0.0465 +v -0.3669 0.5949 0.4079 +v -0.2503 0.3707 -0.2076 +v -0.3183 0.8381 -0.2049 +v -0.5227 0.4206 -0.2834 +v -0.3568 0.7591 0.3005 +v -0.6660 0.6512 0.3267 +v -0.5643 0.7974 0.2441 +v -0.6560 0.8763 -0.0878 +v -0.6474 0.3841 -0.1308 +v -0.5029 0.2752 0.0655 +v -0.3398 0.9269 -0.0631 +v -0.2171 0.8500 0.0713 +v -0.5643 0.9154 -0.0161 +v -0.4760 0.0149 -0.3733 +v -0.1870 0.0143 0.0759 +v -0.5876 0.2785 0.2208 +v -0.3252 0.1550 0.3433 +v -0.2116 0.0173 -0.2542 +v -0.7396 0.0115 -0.1727 +v -0.8469 0.1524 0.1097 +v -0.2939 0.0107 0.3538 +v -0.5773 0.0071 0.5454 +v -0.8757 0.0076 0.0919 +v -0.6789 0.1808 0.4272 +v -0.8312 0.0059 0.4311 +v -0.5533 0.9947 0.3415 +v -0.3511 0.9560 0.3969 +v -0.5645 1.1095 0.1034 +v -0.3175 1.1236 -0.0066 +v -0.2027 1.0429 0.2015 +v -0.3638 1.0581 0.1120 +v -0.2279 1.0698 0.2428 +v -0.5113 1.2343 0.3911 +v -0.3234 1.1973 0.4439 +v -0.5330 1.1301 0.1580 +v -0.4816 1.4650 -0.0181 +v -0.2363 1.4470 -0.0890 +v -0.1566 1.4343 0.0823 +v -0.5000 1.4371 0.2679 +v -0.2308 1.3887 0.3437 +# 335 vertices + +vt 0.2135 0.0260 0.0000 +vt 0.2591 0.0428 0.0000 +vt 0.2222 0.0676 0.0000 +vt 0.1124 0.1603 0.0000 +vt 0.0642 0.1761 0.0000 +vt 0.0951 0.2220 0.0000 +vt 0.3095 0.2325 0.0000 +vt 0.2772 0.2438 0.0000 +vt 0.3622 0.2162 0.0000 +vt 0.2576 0.2373 0.0000 +vt 0.1799 0.2519 0.0000 +vt 0.1533 0.2468 0.0000 +vt 0.2235 0.2329 0.0000 +vt 0.0528 0.2394 0.0000 +vt 0.3151 0.2047 0.0000 +vt 0.4101 0.1722 0.0000 +vt 0.2625 0.1615 0.0000 +vt 0.4512 0.1876 0.0000 +vt 0.1970 0.2081 0.0000 +vt 0.2097 0.1811 0.0000 +vt 0.4310 0.2082 0.0000 +vt 0.0654 0.1897 0.0000 +vt 0.1534 0.1797 0.0000 +vt 0.3574 0.1263 0.0000 +vt 0.4512 0.1014 0.0000 +vt 0.5152 0.1062 0.0000 +vt 0.1137 0.1432 0.0000 +vt 0.1924 0.1250 0.0000 +vt 0.4595 0.0628 0.0000 +vt 0.2820 0.0889 0.0000 +vt 0.2590 0.0646 0.0000 +vt 0.1837 0.0996 0.0000 +vt 0.1063 0.1323 0.0000 +vt 0.5156 0.2228 0.0000 +vt 0.4944 0.1969 0.0000 +vt 0.2041 0.2096 0.0000 +vt 0.1379 0.1203 0.0000 +vt 0.1505 0.1745 0.0000 +vt 0.1389 0.2343 0.0000 +vt 0.0845 0.1988 0.0000 +vt 0.0316 0.2012 0.0000 +vt 0.0265 0.2483 0.0000 +vt 0.1201 0.2589 0.0000 +vt 0.8245 0.3764 0.0000 +vt 0.8552 0.3620 0.0000 +vt 0.8515 0.3759 0.0000 +vt 0.8046 0.3199 0.0000 +vt 0.7671 0.3625 0.0000 +vt 0.8032 0.3704 0.0000 +vt 0.7088 0.3112 0.0000 +vt 0.7312 0.3699 0.0000 +vt 0.7296 0.3196 0.0000 +vt 0.8257 0.3108 0.0000 +vt 0.7671 0.3118 0.0000 +vt 0.7104 0.3767 0.0000 +vt 0.7941 0.8715 0.0000 +vt 0.8152 0.8743 0.0000 +vt 0.7814 0.8715 0.0000 +vt 0.8160 0.8556 0.0000 +vt 0.8060 0.8547 0.0000 +vt 0.8423 0.8531 0.0000 +vt 0.7907 0.8603 0.0000 +vt 0.8108 0.8388 0.0000 +vt 0.8341 0.8195 0.0000 +vt 0.8449 0.8323 0.0000 +vt 0.7768 0.8511 0.0000 +vt 0.7868 0.8236 0.0000 +vt 0.7717 0.8262 0.0000 +vt 0.7991 0.8293 0.0000 +vt 0.8044 0.8213 0.0000 +vt 0.7821 0.8149 0.0000 +vt 0.7931 0.8223 0.0000 +vt 0.7682 0.8166 0.0000 +vt 0.8315 0.8149 0.0000 +vt 0.7989 0.8237 0.0000 +vt 0.8328 0.8250 0.0000 +vt 0.7977 0.8469 0.0000 +vt 0.8299 0.8463 0.0000 +vt 0.8102 0.8661 0.0000 +vt 0.8077 0.8496 0.0000 +vt 0.7849 0.8640 0.0000 +vt 0.7730 0.8618 0.0000 +vt 0.7773 0.8412 0.0000 +vt 0.8004 0.8431 0.0000 +vt 0.7773 0.8669 0.0000 +vt 0.8175 0.8526 0.0000 +vt 0.8327 0.8278 0.0000 +vt 0.8955 0.8308 0.0000 +vt 0.7126 0.9067 0.0000 +vt 0.7122 0.9055 0.0000 +vt 0.6562 0.8658 0.0000 +vt 0.7125 0.9010 0.0000 +vt 0.6316 0.8917 0.0000 +vt 0.7138 0.8403 0.0000 +vt 0.6525 0.8642 0.0000 +vt 0.7151 0.8399 0.0000 +vt 0.3771 0.6591 0.0000 +vt 0.4945 0.6355 0.0000 +vt 0.4423 0.7310 0.0000 +vt 0.5454 0.6962 0.0000 +vt 0.5968 0.6356 0.0000 +vt 0.5452 0.7879 0.0000 +vt 0.6480 0.7314 0.0000 +vt 0.7153 0.6600 0.0000 +vt 0.6163 0.0332 0.0000 +vt 0.6640 0.0716 0.0000 +vt 0.5685 0.0716 0.0000 +vt 0.5873 0.2558 0.0000 +vt 0.5703 0.1607 0.0000 +vt 0.5767 0.1372 0.0000 +vt 0.5790 0.1445 0.0000 +vt 0.5685 0.1681 0.0000 +vt 0.5986 0.1305 0.0000 +vt 0.5726 0.1759 0.0000 +vt 0.5985 0.1597 0.0000 +vt 0.5777 0.2146 0.0000 +vt 0.5713 0.1746 0.0000 +vt 0.5984 0.2161 0.0000 +vt 0.5848 0.2442 0.0000 +vt 0.5982 0.2580 0.0000 +vt 0.8853 0.6459 0.0000 +vt 0.8556 0.6355 0.0000 +vt 0.8881 0.6562 0.0000 +vt 0.8883 0.6804 0.0000 +vt 0.8605 0.7261 0.0000 +vt 0.8915 0.7259 0.0000 +vt 0.7747 0.6804 0.0000 +vt 0.7715 0.7259 0.0000 +vt 0.8027 0.7261 0.0000 +vt 0.8316 0.6925 0.0000 +vt 0.8631 0.7384 0.0000 +vt 0.8002 0.7384 0.0000 +vt 0.7682 0.6867 0.0000 +vt 0.7726 0.7205 0.0000 +vt 0.8597 0.6522 0.0000 +vt 0.8906 0.7205 0.0000 +vt 0.8743 0.7572 0.0000 +vt 0.7891 0.7572 0.0000 +vt 0.8860 0.6572 0.0000 +vt 0.7770 0.6572 0.0000 +vt 0.8948 0.6867 0.0000 +vt 0.8316 0.6665 0.0000 +vt 0.8116 0.6480 0.0000 +vt 0.7777 0.6459 0.0000 +vt 0.8514 0.6480 0.0000 +vt 0.8310 0.7629 0.0000 +vt 0.7891 0.7542 0.0000 +vt 0.8743 0.7542 0.0000 +vt 0.8035 0.6522 0.0000 +vt 0.7750 0.6562 0.0000 +vt 0.8089 0.6355 0.0000 +vt 0.9088 0.3283 0.0000 +vt 0.9347 0.3327 0.0000 +vt 0.9121 0.3504 0.0000 +vt 0.9135 0.3216 0.0000 +vt 0.9509 0.3223 0.0000 +vt 0.9443 0.3530 0.0000 +vt 0.9735 0.3592 0.0000 +vt 0.9692 0.3308 0.0000 +vt 0.9684 0.3675 0.0000 +vt 0.9263 0.3658 0.0000 +vt 0.5507 0.8617 0.0000 +vt 0.5279 0.8750 0.0000 +vt 0.5279 0.8465 0.0000 +vt 0.5470 0.8498 0.0000 +vt 0.5470 0.8828 0.0000 +vt 0.5319 0.8403 0.0000 +vt 0.5279 0.8961 0.0000 +vt 0.5496 0.8399 0.0000 +vt 0.5645 0.8636 0.0000 +vt 0.5620 0.8770 0.0000 +vt 0.5742 0.8681 0.0000 +vt 0.5654 0.8482 0.0000 +vt 0.4749 0.8399 0.0000 +vt 0.3867 0.9042 0.0000 +vt 0.4750 0.9042 0.0000 +vt 0.3879 0.8399 0.0000 +vt 0.6367 0.1288 0.0000 +vt 0.5886 0.1338 0.0000 +vt 0.5890 0.1288 0.0000 +vt 0.6846 0.1341 0.0000 +vt 0.6838 0.1286 0.0000 +vt 0.5916 0.1410 0.0000 +vt 0.6180 0.1379 0.0000 +vt 0.6005 0.1390 0.0000 +vt 0.6978 0.2376 0.0000 +vt 0.7052 0.1822 0.0000 +vt 0.7052 0.2450 0.0000 +vt 0.6893 0.1737 0.0000 +vt 0.6623 0.2482 0.0000 +vt 0.6931 0.2461 0.0000 +vt 0.6657 0.2279 0.0000 +vt 0.6966 0.1777 0.0000 +vt 0.6741 0.1748 0.0000 +vt 0.6393 0.2442 0.0000 +vt 0.6584 0.1476 0.0000 +vt 0.6446 0.1649 0.0000 +vt 0.6397 0.2053 0.0000 +vt 0.6394 0.2172 0.0000 +vt 0.6844 0.1441 0.0000 +vt 0.7033 0.1498 0.0000 +vt 0.6445 0.1708 0.0000 +vt 0.6755 0.1425 0.0000 +vt 0.6454 0.1528 0.0000 +vt 0.6875 0.1377 0.0000 +vt 0.5724 0.2532 0.0000 +vt 0.5865 0.1723 0.0000 +vt 0.5844 0.2452 0.0000 +vt 0.6193 0.2589 0.0000 +vt 0.5938 0.1674 0.0000 +vt 0.5889 0.2558 0.0000 +vt 0.6089 0.1691 0.0000 +vt 0.6164 0.2339 0.0000 +vt 0.5744 0.1790 0.0000 +vt 0.6422 0.2545 0.0000 +vt 0.6249 0.1363 0.0000 +vt 0.6428 0.2071 0.0000 +vt 0.6386 0.1578 0.0000 +vt 0.6426 0.2217 0.0000 +vt 0.5802 0.1377 0.0000 +vt 0.6382 0.1650 0.0000 +vt 0.6377 0.1431 0.0000 +vt 0.6080 0.1297 0.0000 +vt 0.5963 0.1236 0.0000 +vt 0.6815 0.1413 0.0000 +vt 0.6543 0.1378 0.0000 +vt 0.6421 0.1506 0.0000 +vt 0.6314 0.1701 0.0000 +vt 0.6307 0.1506 0.0000 +vt 0.7008 0.1472 0.0000 +vt 0.6414 0.1640 0.0000 +vt 0.6319 0.1642 0.0000 +vt 0.6366 0.2080 0.0000 +vt 0.6554 0.1451 0.0000 +vt 0.5723 0.1468 0.0000 +vt 0.6414 0.1701 0.0000 +vt 0.6362 0.2206 0.0000 +vt 0.6177 0.1450 0.0000 +vt 0.6726 0.1392 0.0000 +vt 0.1171 0.8175 0.0000 +vt 0.0996 0.8137 0.0000 +vt 0.1074 0.9276 0.0000 +vt 0.0971 0.9343 0.0000 +vt 0.0895 0.8288 0.0000 +vt 0.1582 0.8282 0.0000 +vt 0.1511 0.9341 0.0000 +vt 0.1676 0.9337 0.0000 +vt 0.1274 0.8172 0.0000 +vt 0.1151 0.8003 0.0000 +vt 0.1286 0.8000 0.0000 +vt 0.1449 0.8111 0.0000 +vt 0.1397 0.9273 0.0000 +vt 0.1232 0.9292 0.0000 +vt 0.0981 0.8030 0.0000 +vt 0.0894 0.8016 0.0000 +vt 0.1581 0.8009 0.0000 +vt 0.1460 0.8016 0.0000 +vt 0.8961 0.2518 0.0000 +vt 0.8864 0.1335 0.0000 +vt 0.8902 0.1363 0.0000 +vt 0.8510 0.2514 0.0000 +vt 0.8561 0.1236 0.0000 +vt 0.8322 0.1284 0.0000 +vt 0.8033 0.2053 0.0000 +vt 0.8046 0.1568 0.0000 +vt 0.8615 0.1271 0.0000 +vt 0.7586 0.2512 0.0000 +vt 0.8033 0.2515 0.0000 +vt 0.7682 0.1938 0.0000 +vt 0.7144 0.9075 0.0000 +vt 0.7152 0.9064 0.0000 +vt 0.7131 0.9080 0.0000 +vt 0.7135 0.9053 0.0000 +vt 0.9034 0.5146 0.0000 +vt 0.9377 0.5020 0.0000 +vt 0.9412 0.5360 0.0000 +vt 0.9496 0.5254 0.0000 +vt 0.9455 0.5426 0.0000 +vt 0.9465 0.5156 0.0000 +vt 0.9546 0.5330 0.0000 +vt 0.9510 0.5622 0.0000 +vt 0.9070 0.5309 0.0000 +vt 0.9021 0.5563 0.0000 +vt 0.9344 0.5805 0.0000 +vt 0.9309 0.5801 0.0000 +vt 0.9057 0.5775 0.0000 +vt 0.9081 0.5372 0.0000 +vt 0.9493 0.5614 0.0000 +vt 0.8939 0.5549 0.0000 +vt 0.9094 0.5780 0.0000 +vt 0.9499 0.5624 0.0000 +vt 0.9433 0.3160 0.0000 +vt 0.9536 0.3109 0.0000 +vt 0.9714 0.3317 0.0000 +vt 0.9377 0.3407 0.0000 +vt 0.9207 0.3279 0.0000 +vt 0.9700 0.3185 0.0000 +vt 0.9081 0.3108 0.0000 +# 298 texture coords + +g Regroup24 +usemtl Resources\Textures\YoungLink.bmp +f 1/1 2/2 3/3 +f 4/4 5/5 6/6 +f 7/7 8/8 9/9 +f 10/10 11/11 12/12 +f 11/11 10/10 8/8 +f 8/8 7/7 11/11 +f 11/11 13/13 6/6 +f 11/11 14/14 12/12 +f 15/15 16/16 9/9 +f 16/16 15/15 17/17 +f 9/9 16/16 18/18 +f 15/15 19/19 17/17 +f 20/20 17/17 19/19 +f 9/9 18/18 21/21 +f 14/14 5/5 22/22 +f 20/20 23/23 17/17 +f 24/24 16/16 17/17 +f 25/25 26/26 24/24 +f 27/27 28/28 23/23 +f 16/16 24/24 26/26 +f 29/29 30/30 31/31 +f 29/29 24/24 30/30 +f 16/16 26/26 18/18 +f 28/28 30/30 17/17 +f 32/32 30/30 28/28 +f 30/30 32/32 31/31 +f 30/30 24/24 17/17 +f 27/27 5/5 33/33 +f 23/23 28/28 17/17 +f 27/27 22/22 5/5 +f 27/27 32/32 28/28 +f 34/34 21/21 35/35 +f 34/34 35/35 7/7 +f 10/10 19/19 15/15 +f 27/27 33/33 32/32 +f 36/36 13/13 7/7 +f 10/10 15/15 9/9 +f 14/14 11/11 6/6 +f 6/6 5/5 14/14 +f 5/5 4/4 37/37 +f 4/4 38/38 37/37 +f 8/8 10/10 9/9 +f 13/13 11/11 7/7 +f 33/33 5/5 37/37 +f 1/1 37/37 2/2 +f 33/33 37/37 32/32 +f 29/29 25/25 24/24 +f 39/39 13/13 36/36 +f 40/40 4/4 41/41 +f 40/40 36/36 38/38 +f 42/42 4/4 6/6 +f 42/42 13/13 43/43 +f 39/39 36/36 40/40 +f 4/4 42/42 41/41 +f 13/13 42/42 6/6 +f 13/13 39/39 43/43 +f 4/4 40/40 38/38 +f 44/44 45/45 46/46 +f 47/47 45/48 48/49 +f 49/50 50/51 51/52 +f 52/53 48/49 44/44 +f 45/48 47/47 53/54 +f 45/48 44/44 48/49 +f 48/49 52/53 47/47 +f 45/48 51/52 50/51 +f 46/55 45/48 50/51 +f 50/51 49/50 46/55 +f 51/52 45/48 53/54 +f 54/56 55/57 56/58 +f 55/57 54/56 25/59 +f 55/57 29/60 57/61 +f 55/57 57/61 58/62 +f 59/63 58/62 57/61 +f 55/57 58/62 56/58 +f 60/64 59/63 61/65 +f 59/63 62/66 58/62 +f 3/67 2/68 31/69 +f 31/69 32/70 3/67 +f 60/64 2/68 59/63 +f 60/64 61/65 29/60 +f 56/58 58/62 62/66 +f 60/64 31/69 2/68 +f 59/63 2/68 62/66 +f 60/64 29/60 31/69 +f 59/63 57/61 61/65 +f 61/65 57/61 29/60 +f 55/57 25/59 29/60 +f 21/71 18/72 35/73 +f 63/74 64/75 35/73 +f 65/76 26/77 66/78 +f 65/76 18/72 26/77 +f 67/79 25/80 54/81 +f 63/74 65/76 64/75 +f 66/78 26/77 67/79 +f 67/79 26/77 25/80 +f 63/74 18/72 65/76 +f 54/81 68/82 67/79 +f 64/75 65/76 66/78 +f 64/75 66/78 69/83 +f 67/79 69/83 66/78 +f 67/79 68/82 69/83 +f 63/74 35/73 18/72 +f 64/75 69/83 35/73 +f 38/84 70/85 71/86 +f 37/87 38/84 71/86 +f 72/86 7/87 35/88 +f 71/86 2/88 37/87 +f 72/86 36/84 7/87 +f 36/84 70/85 38/84 +f 70/85 36/84 72/86 +f 41/89 42/89 73/89 +f 43/89 74/89 75/89 +f 40/89 74/89 39/89 +f 42/89 76/90 73/89 +f 41/89 77/89 40/89 +f 77/89 74/89 40/89 +f 43/89 75/89 42/89 +f 74/89 43/89 39/89 +f 75/89 76/90 42/89 +f 77/89 41/89 73/89 +f 21/91 7/92 9/93 +f 34/94 7/92 21/91 +f 3/95 32/93 37/92 +f 1/96 3/95 37/92 +f 27/97 23/98 22/99 +f 78/100 23/98 19/101 +f 14/102 22/99 78/100 +f 78/100 22/99 23/98 +f 12/103 19/101 10/104 +f 12/103 14/102 78/100 +f 12/103 78/100 19/101 +f 20/105 19/106 23/107 +f 79/108 80/108 77/108 +f 74/108 81/108 75/108 +f 82/108 74/108 77/108 +f 82/108 77/108 80/108 +f 73/108 76/108 79/108 +f 77/108 73/108 79/108 +f 82/108 81/108 74/108 +f 75/108 81/108 76/108 +f 68/109 83/110 84/111 +f 83/110 68/109 56/109 +f 54/112 56/109 68/109 +f 84/111 83/110 85/113 +f 86/111 56/109 62/114 +f 87/115 62/114 2/116 +f 86/111 87/115 85/113 +f 86/111 85/113 83/110 +f 86/111 62/114 87/115 +f 86/111 83/110 56/109 +f 69/117 84/111 88/115 +f 85/113 88/115 84/111 +f 35/116 88/115 89/118 +f 88/115 35/116 69/117 +f 90/118 71/119 70/120 +f 89/118 70/120 72/119 +f 90/118 2/116 71/119 +f 2/116 90/118 87/115 +f 35/116 89/118 72/119 +f 68/109 84/111 69/117 +f 91/121 74/122 92/123 +f 93/124 94/125 95/126 +f 96/127 97/128 98/129 +f 99/130 100/131 101/132 +f 102/133 103/127 104/134 +f 94/125 92/123 105/135 +f 100/131 106/136 107/137 +f 104/134 101/132 108/138 +f 109/124 99/130 110/139 +f 111/140 99/130 103/127 +f 112/141 95/126 106/136 +f 109/124 112/141 106/136 +f 76/142 111/140 73/143 +f 113/144 73/143 111/140 +f 76/142 110/139 99/130 +f 110/139 76/142 75/145 +f 114/146 115/147 108/138 +f 108/138 97/128 104/134 +f 105/135 98/129 94/125 +f 114/146 116/148 115/147 +f 107/137 116/148 114/146 +f 117/149 98/129 105/135 +f 118/150 98/129 117/149 +f 95/126 107/137 106/136 +f 95/126 94/125 116/148 +f 114/146 108/138 107/137 +f 92/123 74/122 105/135 +f 115/147 98/129 97/128 +f 74/122 117/149 105/135 +f 77/151 118/150 117/149 +f 101/132 107/137 108/138 +f 77/151 117/149 74/122 +f 115/147 94/125 98/129 +f 100/131 107/137 101/132 +f 97/128 102/133 104/134 +f 116/148 94/125 115/147 +f 73/143 113/144 77/151 +f 101/132 103/127 99/130 +f 74/122 91/121 75/145 +f 97/128 96/127 102/133 +f 112/141 93/124 95/126 +f 75/145 91/121 110/139 +f 99/130 111/140 76/142 +f 94/125 93/124 92/123 +f 103/127 101/132 104/134 +f 100/131 109/124 106/136 +f 107/137 95/126 116/148 +f 109/124 100/131 99/130 +f 118/150 77/151 113/144 +f 97/128 108/138 115/147 +f 98/129 118/150 96/127 +f 93/152 119/153 92/154 +f 119/153 93/152 112/155 +f 109/152 120/156 112/155 +f 120/156 119/153 112/155 +f 121/157 96/158 118/159 +f 96/158 121/157 102/160 +f 121/157 122/161 102/160 +f 122/161 103/158 102/160 +f 123/162 89/163 88/164 +f 87/164 124/162 125/165 +f 124/162 90/163 126/166 +f 88/164 127/165 123/162 +f 85/167 127/165 88/164 +f 125/165 85/167 87/164 +f 70/168 126/166 90/163 +f 85/167 125/165 128/169 +f 89/163 123/162 129/166 +f 127/165 85/167 128/169 +f 129/166 70/168 89/163 +f 90/163 124/162 87/164 +f 70/168 129/166 126/166 +f 130/170 126/166 131/171 +f 129/166 132/170 131/171 +f 133/172 131/171 132/170 +f 134/173 132/170 127/165 +f 130/170 125/165 124/162 +f 134/173 127/165 128/169 +f 130/170 134/173 125/165 +f 130/170 131/171 133/172 +f 132/170 134/173 133/172 +f 126/166 129/166 131/171 +f 125/165 134/173 128/169 +f 127/165 132/170 123/162 +f 126/166 130/170 124/162 +f 134/173 130/170 133/172 +f 132/170 129/166 123/162 +f 44/174 49/175 52/176 +f 49/175 44/174 46/177 +f 53/178 135/179 51/180 +f 136/181 53/178 47/182 +f 51/180 137/183 49/184 +f 135/179 53/178 138/185 +f 139/186 140/187 141/188 +f 142/189 143/190 144/191 +f 145/192 146/193 139/186 +f 146/193 140/187 139/186 +f 141/188 142/189 144/191 +f 147/194 146/193 145/192 +f 140/187 142/189 141/188 +f 148/195 149/196 150/197 +f 150/197 151/198 148/195 +f 152/199 147/194 145/192 +f 142/189 140/187 153/200 +f 153/200 140/187 154/201 +f 147/194 155/202 156/203 +f 156/203 155/202 157/204 +f 136/205 146/193 156/203 +f 156/203 146/193 147/194 +f 153/200 143/190 142/189 +f 140/187 136/205 154/201 +f 149/196 148/195 143/190 +f 149/196 143/190 153/200 +f 147/194 152/199 155/202 +f 136/205 140/187 146/193 +f 158/206 159/207 160/208 +f 161/209 162/210 163/211 +f 160/208 164/212 165/213 +f 166/214 159/207 158/206 +f 163/211 166/214 158/206 +f 159/207 164/212 160/208 +f 162/210 166/214 163/211 +f 167/215 168/216 161/209 +f 151/217 169/218 167/215 +f 164/212 152/219 165/213 +f 166/214 162/210 170/220 +f 170/220 162/210 137/113 +f 171/221 164/212 172/222 +f 172/222 164/212 138/223 +f 159/207 135/224 164/212 +f 164/212 135/224 138/223 +f 162/210 168/216 137/113 +f 135/224 166/214 170/220 +f 168/216 167/215 169/218 +f 161/209 168/216 162/210 +f 152/219 164/212 171/221 +f 166/214 135/224 159/207 +f 153/225 47/182 52/226 +f 157/227 171/228 172/229 +f 47/182 153/225 154/230 +f 53/178 172/229 138/185 +f 150/231 169/232 151/233 +f 47/182 154/230 136/181 +f 52/226 149/234 153/225 +f 137/183 51/180 170/235 +f 53/178 157/227 172/229 +f 171/228 155/236 152/237 +f 49/184 137/183 168/238 +f 53/178 156/239 157/227 +f 51/180 135/179 170/235 +f 49/184 149/234 52/226 +f 171/228 157/227 155/236 +f 168/238 150/231 149/234 +f 168/238 149/234 49/184 +f 169/232 150/231 168/238 +f 53/178 136/181 156/239 +f 51/180 135/179 53/178 +f 47/182 53/178 136/181 +f 49/184 137/183 51/180 +f 138/185 53/178 135/179 +f 141/188 140/187 139/186 +f 144/191 143/190 142/189 +f 139/186 146/193 145/192 +f 139/186 140/187 146/193 +f 144/191 142/189 141/188 +f 145/192 146/193 147/194 +f 141/188 142/189 140/187 +f 150/197 149/196 148/195 +f 148/195 151/198 150/197 +f 145/192 147/194 152/199 +f 153/200 140/187 142/189 +f 154/201 140/187 153/200 +f 156/203 155/202 147/194 +f 157/204 155/202 156/203 +f 156/203 146/193 136/205 +f 147/194 146/193 156/203 +f 142/189 143/190 153/200 +f 154/201 136/205 140/187 +f 143/190 148/195 149/196 +f 153/200 143/190 149/196 +f 155/202 152/199 147/194 +f 146/193 140/187 136/205 +f 160/208 159/207 158/206 +f 163/211 162/210 161/209 +f 165/213 164/212 160/208 +f 158/206 159/207 166/214 +f 158/206 166/214 163/211 +f 160/208 164/212 159/207 +f 163/211 166/214 162/210 +f 161/209 168/216 167/215 +f 167/215 169/218 151/217 +f 165/213 152/219 164/212 +f 170/220 162/210 166/214 +f 137/113 162/210 170/220 +f 172/222 164/212 171/221 +f 138/223 164/212 172/222 +f 164/212 135/224 159/207 +f 138/223 135/224 164/212 +f 137/113 168/216 162/210 +f 170/220 166/214 135/224 +f 169/218 167/215 168/216 +f 162/210 168/216 161/209 +f 171/221 164/212 152/219 +f 159/207 135/224 166/214 +f 52/226 47/182 153/225 +f 172/229 171/228 157/227 +f 154/230 153/225 47/182 +f 138/185 172/229 53/178 +f 151/233 169/232 150/231 +f 136/181 154/230 47/182 +f 153/225 149/234 52/226 +f 170/235 51/180 137/183 +f 172/229 157/227 53/178 +f 152/237 155/236 171/228 +f 168/238 137/183 49/184 +f 157/227 156/239 53/178 +f 170/235 135/179 51/180 +f 52/226 149/234 49/184 +f 155/236 157/227 171/228 +f 149/234 150/231 168/238 +f 49/184 149/234 168/238 +f 168/238 150/231 169/232 +f 156/239 136/181 53/178 +f 173/240 174/241 175/242 +f 176/243 175/242 174/241 +f 174/241 177/244 176/243 +f 177/245 178/246 176/247 +f 173/240 179/248 180/249 +f 180/249 179/248 181/250 +f 179/248 182/251 181/250 +f 182/251 183/252 178/246 +f 179/248 184/253 183/252 +f 184/253 173/240 175/242 +f 185/254 186/255 177/244 +f 179/248 173/240 184/253 +f 183/252 182/251 179/248 +f 186/256 187/257 177/245 +f 174/241 173/240 180/249 +f 177/245 182/251 178/246 +f 180/249 185/254 174/241 +f 187/257 181/250 182/251 +f 185/254 177/244 174/241 +f 177/245 187/257 182/251 +f 188/258 176/259 178/260 +f 189/261 175/262 176/259 +f 184/263 190/264 191/265 +f 192/258 176/259 188/258 +f 176/259 192/258 189/261 +f 175/262 190/264 184/263 +f 188/258 178/260 193/261 +f 183/266 193/261 178/260 +f 194/264 183/266 191/265 +f 191/265 183/266 184/263 +f 175/262 189/261 190/264 +f 193/261 183/266 194/264 +f 193/261 189/261 188/258 +f 188/258 189/261 192/258 +f 195/267 190/264 196/268 +f 193/261 194/264 197/268 +f 198/269 194/264 191/265 +f 198/269 190/264 195/267 +f 193/261 196/268 189/261 +f 197/268 196/268 193/261 +f 199/267 194/264 198/269 +f 198/269 195/267 199/267 +f 190/264 198/269 191/265 +f 194/264 199/267 197/268 +f 196/268 197/268 195/267 +f 195/267 197/268 199/267 +f 190/264 189/261 196/268 +f 200/270 180/270 201/270 +f 201/270 180/270 181/270 +f 187/271 202/271 203/271 +f 202/271 185/271 204/271 +f 203/271 201/270 181/270 +f 185/271 202/271 186/271 +f 185/271 180/270 204/271 +f 181/270 187/271 203/271 +f 200/270 204/271 180/270 +f 202/271 187/271 186/271 +f 204/271 205/270 206/271 +f 201/270 203/271 207/270 +f 207/270 208/270 201/270 +f 201/270 208/270 200/270 +f 205/270 204/271 208/270 +f 206/271 203/271 202/271 +f 203/271 209/270 207/270 +f 208/270 204/271 200/270 +f 209/270 203/271 206/271 +f 204/271 206/271 202/271 +f 210/89 207/270 209/270 +f 210/89 209/270 211/89 +f 211/89 205/270 212/89 +f 213/270 207/270 210/89 +f 211/89 209/270 206/271 +f 205/270 211/89 206/271 +f 212/89 205/270 214/270 +f 214/270 205/270 208/270 +f 214/270 208/270 213/270 +f 213/270 208/270 207/270 +f 215/89 216/90 217/90 +f 218/272 215/89 219/89 +f 215/89 218/272 220/89 +f 218/272 221/89 222/89 +f 217/90 223/89 224/89 +f 221/89 223/89 222/89 +f 221/89 218/272 219/89 +f 216/90 223/89 217/90 +f 225/273 215/89 220/89 +f 223/89 221/89 224/89 +f 216/90 215/89 225/273 +f 226/271 227/89 228/271 +f 228/271 227/89 225/273 +f 222/89 227/89 229/270 +f 229/270 227/89 226/271 +f 225/273 220/89 228/271 +f 228/271 220/89 230/270 +f 218/272 222/89 231/270 +f 231/270 222/89 229/270 +f 227/89 216/90 225/273 +f 222/89 223/89 227/89 +f 231/270 220/89 218/272 +f 223/89 216/90 227/89 +f 229/270 230/270 231/270 +f 230/270 220/89 231/270 +f 228/271 230/270 226/271 +f 226/271 230/270 229/270 +f 224/273 122/89 232/90 +f 219/89 233/89 234/89 +f 215/89 235/90 233/89 +f 217/273 235/90 215/89 +f 122/89 224/273 221/89 +f 233/89 219/89 215/89 +f 234/89 221/89 219/89 +f 217/273 232/90 235/90 +f 122/89 121/90 232/90 +f 121/90 235/90 232/90 +f 232/90 217/273 224/273 +f 221/89 234/89 122/89 +f 236/274 237/275 238/276 +f 236/274 239/277 237/275 +f 238/278 237/279 239/280 +f 240/281 238/278 239/280 +f 240/281 241/282 242/283 +f 242/283 243/284 240/281 +f 244/285 243/284 245/286 +f 239/277 241/282 240/281 +f 241/282 236/274 242/283 +f 239/277 236/274 241/282 +f 246/287 247/288 245/286 +f 248/289 245/286 242/283 +f 238/276 247/288 246/287 +f 248/289 246/287 245/286 +f 238/276 246/287 236/274 +f 236/274 246/287 248/289 +f 243/284 242/283 249/290 +f 242/283 236/274 248/289 +f 249/290 242/283 245/286 +f 243/284 249/290 245/286 +f 240/281 243/284 247/288 +f 238/278 240/281 247/291 +f 244/285 245/286 247/288 +f 243/284 244/285 247/288 +f 250/292 251/293 252/294 +f 103/158 122/161 234/295 +f 250/292 103/158 233/296 +f 233/296 103/158 234/295 +f 113/297 252/294 251/293 +f 251/293 118/159 113/297 +f 118/159 253/292 121/157 +f 118/159 251/293 253/292 +f 103/158 250/292 252/294 +f 254/298 250/292 233/296 +f 254/298 253/292 250/292 +f 233/296 235/296 254/298 +f 253/292 254/298 235/296 +f 251/293 250/292 253/292 +f 235/296 121/157 253/292 +f 255/90 256/90 257/89 +f 258/89 257/89 259/272 +f 260/89 259/272 257/89 +f 261/89 262/89 259/272 +f 263/89 264/89 255/90 +f 261/89 264/89 262/89 +f 258/89 259/272 262/89 +f 255/90 264/89 256/90 +f 260/89 257/89 265/273 +f 263/89 262/89 264/89 +f 265/273 257/89 256/90 +f 266/271 267/89 268/271 +f 265/273 267/89 266/271 +f 269/270 267/89 261/89 +f 268/271 267/89 269/270 +f 266/271 260/89 265/273 +f 270/270 260/89 266/271 +f 271/270 261/89 259/272 +f 269/270 261/89 271/270 +f 265/273 256/90 267/89 +f 267/89 264/89 261/89 +f 259/272 260/89 271/270 +f 267/89 256/90 264/89 +f 271/270 270/270 269/270 +f 271/270 260/89 270/270 +f 268/271 270/270 266/271 +f 269/270 270/270 268/271 +f 272/90 120/89 263/273 +f 273/89 274/89 258/89 +f 274/89 275/90 257/89 +f 257/89 275/90 255/273 +f 262/89 263/273 120/89 +f 257/89 258/89 274/89 +f 258/89 262/89 273/89 +f 275/90 272/90 255/273 +f 272/90 119/90 120/89 +f 272/90 275/90 119/90 +f 263/273 255/273 272/90 +f 120/89 273/89 262/89 +f 276/276 277/275 278/274 +f 277/275 279/277 278/274 +f 279/280 277/279 276/278 +f 279/280 276/278 280/281 +f 281/283 282/282 280/281 +f 280/281 283/284 281/283 +f 284/286 283/284 285/285 +f 280/281 282/282 279/277 +f 281/283 278/274 282/282 +f 282/282 278/274 279/277 +f 284/286 286/288 287/287 +f 281/283 284/286 288/289 +f 287/287 286/288 276/276 +f 284/286 287/287 288/289 +f 278/274 287/287 276/276 +f 288/289 287/287 278/274 +f 289/290 281/283 283/284 +f 288/289 278/274 281/283 +f 284/286 281/283 289/290 +f 284/286 289/290 283/284 +f 286/288 283/284 280/281 +f 286/291 280/281 276/278 +f 286/288 284/286 285/285 +f 286/288 285/285 283/284 +f 110/294 290/293 291/292 +f 273/295 120/161 109/158 +f 274/296 109/158 291/292 +f 273/295 109/158 274/296 +f 290/293 110/294 91/297 +f 91/297 92/159 290/293 +f 119/157 292/292 92/159 +f 292/292 290/293 92/159 +f 110/294 291/292 109/158 +f 274/296 291/292 293/298 +f 291/292 292/292 293/298 +f 293/298 275/296 274/296 +f 275/296 293/298 292/292 +f 292/292 291/292 290/293 +f 292/292 119/157 275/296 +f 294/242 295/241 296/240 +f 295/241 294/242 297/243 +f 297/243 298/244 295/241 +f 297/247 299/246 298/245 +f 300/249 301/248 296/240 +f 302/250 301/248 300/249 +f 302/250 303/251 301/248 +f 299/246 304/252 303/251 +f 304/252 305/253 301/248 +f 294/242 296/240 305/253 +f 298/244 306/255 307/254 +f 305/253 296/240 301/248 +f 301/248 303/251 304/252 +f 298/245 308/257 306/256 +f 300/249 296/240 295/241 +f 299/246 303/251 298/245 +f 295/241 307/254 300/249 +f 303/251 302/250 308/257 +f 295/241 298/244 307/254 +f 303/251 308/257 298/245 +f 299/260 297/259 309/258 +f 297/259 294/262 310/261 +f 311/265 312/264 305/263 +f 309/258 297/259 313/258 +f 310/261 313/258 297/259 +f 305/263 312/264 294/262 +f 314/261 299/260 309/258 +f 299/260 314/261 304/266 +f 311/265 304/266 315/264 +f 305/263 304/266 311/265 +f 312/264 310/261 294/262 +f 315/264 304/266 314/261 +f 309/258 310/261 314/261 +f 313/258 310/261 309/258 +f 316/268 312/264 317/267 +f 318/268 315/264 314/261 +f 311/265 315/264 319/269 +f 317/267 312/264 319/269 +f 310/261 316/268 314/261 +f 314/261 316/268 318/268 +f 319/269 315/264 320/267 +f 320/267 317/267 319/269 +f 311/265 319/269 312/264 +f 318/268 320/267 315/264 +f 317/267 318/268 316/268 +f 320/267 318/268 317/267 +f 316/268 310/261 312/264 +f 321/270 300/270 322/270 +f 302/270 300/270 321/270 +f 323/271 324/271 308/271 +f 325/271 307/271 324/271 +f 302/270 321/270 323/271 +f 306/271 324/271 307/271 +f 325/271 300/270 307/271 +f 323/271 308/271 302/270 +f 300/270 325/271 322/270 +f 306/271 308/271 324/271 +f 326/271 327/270 325/271 +f 328/270 323/271 321/270 +f 321/270 329/270 328/270 +f 322/270 329/270 321/270 +f 329/270 325/271 327/270 +f 324/271 323/271 326/271 +f 328/270 330/270 323/271 +f 322/270 325/271 329/270 +f 326/271 323/271 330/270 +f 324/271 326/271 325/271 +f 330/270 328/270 331/89 +f 332/89 330/270 331/89 +f 333/89 327/270 332/89 +f 331/89 328/270 334/270 +f 326/271 330/270 332/89 +f 326/271 332/89 327/270 +f 335/270 327/270 333/89 +f 329/270 327/270 335/270 +f 334/270 329/270 335/270 +f 328/270 329/270 334/270 +# 693 faces