public override List<CustomBlockData> GenerateModel(byte metadata, BlockData me, BlockData Xpos, BlockData Xneg, BlockData Ypos, BlockData Yneg, BlockData Zpos, BlockData Zneg, BlockSource source, Point3 blockPosition)
        {
            bool upsideDown = IsUpsideDown(metadata);

            List<BoundingBox> boxesToExport = new List<BoundingBox>();

            byte direction = GetType(metadata);

            float bottomBasePos = (upsideDown ? 0.5f : 0f);
            float topBasePos = (upsideDown ? 0f : 0.5f);

            boxesToExport.Add(new BoundingBox(new Vector3(0, bottomBasePos, 0), new Vector3(1, bottomBasePos + 0.5f, 1)));

            //Collect data from environment
            Vector3 descendingDir = MetaToDirection(direction);
            Vector3 rightFloatDir = Vector3.TransformNormal(descendingDir, Matrix.CreateRotationY((float)Math.PI / 2));
            rightFloatDir.X = (float)Math.Round(rightFloatDir.X, 4); rightFloatDir.Z = (float)Math.Round(rightFloatDir.Z, 4); //Fix small numbers

            Point3 facingDir = descendingDir.ToPoint3();
            Point3 rightDir = rightFloatDir.ToPoint3();

            BlockData frontBlock = source.GetData(blockPosition + facingDir);
            BlockData backBlock = source.GetData(blockPosition - facingDir);
            BlockData rightBlock = source.GetData(blockPosition + rightDir);
            BlockData leftBlock = source.GetData(blockPosition - rightDir);

            bool renderBaseStep = true;

            int littleCornerModel = -1;

            //Check if we need to make a corner
            {
                if (IsStairs(frontBlock))
                {
                    if (IsLeft(me.Metadata, frontBlock.Metadata))
                    {
                        bool leftOk = (IsStairs(leftBlock) && me.Metadata == leftBlock.Metadata);
                        bool rightOk = (IsStairs(rightBlock) && me.Metadata == rightBlock.Metadata);

                        if ((leftOk && !rightOk) || (!leftOk && rightOk))
                        {
                            int frontLittleStep = -1;
                            {
                                Point3 frontPos = blockPosition + facingDir;

                                BlockData me2 = source.GetData(frontPos);
                                byte direction2 = GetType(me2.Metadata);

                                Vector3 descendingDir2 = MetaToDirection(direction2);
                                Vector3 rightFloatDir2 = Vector3.TransformNormal(descendingDir2, Matrix.CreateRotationY((float)Math.PI / 2));
                                rightFloatDir2.X = (float)Math.Round(rightFloatDir2.X, 4); rightFloatDir2.Z = (float)Math.Round(rightFloatDir2.Z, 4); //Fix small numbers

                                Point3 facingDir2 = descendingDir2.ToPoint3();
                                Point3 rightDir2 = rightFloatDir2.ToPoint3();

                                BlockData backBlock2 = source.GetData(frontPos - facingDir2);
                                BlockData rightBlock2 = source.GetData(frontPos + rightDir2);
                                BlockData leftBlock2 = source.GetData(frontPos - rightDir2);

                                frontLittleStep = CheckLittleCorner(me2, backBlock2, leftBlock2, rightBlock2, direction2);

                            }

                            if (frontLittleStep == -1)
                            {
                                switch (direction)
                                {
                                    case 0:
                                        if (leftOk)
                                            littleCornerModel = 2;
                                        else
                                            littleCornerModel = 1;
                                        break;

                                    case 1:
                                        if (leftOk)
                                            littleCornerModel = 0;
                                        else
                                            littleCornerModel = 3;
                                        break;

                                    case 2:
                                        if (leftOk)
                                            littleCornerModel = 1;
                                        else
                                            littleCornerModel = 0;
                                        break;

                                    case 3:
                                        if (leftOk)
                                            littleCornerModel = 3;
                                        else
                                            littleCornerModel = 2;
                                        break;
                                }
                            }
                        }
                    }
                }
            }

            //Check if we need to make a small corner
            if (littleCornerModel == -1)  //It's not a corner so maybe..
            {
                littleCornerModel = CheckLittleCorner(me, backBlock, leftBlock, rightBlock, direction);
                renderBaseStep = (littleCornerModel == -1);
            }

            if (littleCornerModel != -1)
            {
                switch (littleCornerModel)
                {
                    case 0:
                        boxesToExport.Add(new BoundingBox(new Vector3(.5f, topBasePos, 0), new Vector3(1f, topBasePos + 0.5f, .5f)));
                        break;
                    case 1:
                        boxesToExport.Add(new BoundingBox(new Vector3(0, topBasePos, 0), new Vector3(.5f, topBasePos + 0.5f, .5f)));
                        break;

                    case 2:
                        boxesToExport.Add(new BoundingBox(new Vector3(0, topBasePos, 0.5f), new Vector3(.5f, topBasePos + 0.5f, 1)));
                        break;
                    case 3:
                        boxesToExport.Add(new BoundingBox(new Vector3(.5f, topBasePos, .5f), new Vector3(1f, topBasePos + 0.5f, 1f)));
                        break;
                }
            }

            if (renderBaseStep)
            {
                switch (direction) //Ascending...
                {
                    case 0: //east = +X
                        boxesToExport.Add(new BoundingBox(new Vector3(.5f, topBasePos, 0), new Vector3(1f, topBasePos + 0.5f, 1)));
                        break;
                    case 1: //west = -X
                        boxesToExport.Add(new BoundingBox(new Vector3(0, topBasePos, 0), new Vector3(.5f, topBasePos + 0.5f, 1)));
                        break;

                    case 2: //south = +Z
                        boxesToExport.Add(new BoundingBox(new Vector3(0, topBasePos, 0.5f), new Vector3(1f, topBasePos + 0.5f, 1)));
                        break;
                    case 3: //north = -Z
                        boxesToExport.Add(new BoundingBox(new Vector3(0, topBasePos, 0), new Vector3(1f, topBasePos + 0.5f, .5f)));
                        break;
                }
            }

            return GeometryGenerator.GenerateModel(boxesToExport, source, blockPosition, true, this);
        }
        /// <summary>
        /// Can build side: Input1: Block at side, Input2: Base block
        /// </summary>
        public static List<CustomBlockData> GenerateModel(List<BoundingBox> boxes, BlockSource source, Point3 blockPos, bool removeCoveredFaces, IGeometryGeneratorSource i)
        {
            BlockData currentBlock = source.GetData(blockPos);

            Vector3[] norms = new Vector3[] { new Vector3(1, 0, 0), new Vector3(-1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, -1, 0), new Vector3(0, 0, 1), new Vector3(0, 0, -1) };

            Dictionary<Vector3, Dictionary<float, List<Face>>> faces = new Dictionary<Vector3, Dictionary<float, List<Face>>>();
            //Vector3 key: normal
            //float key: value of normal component

            //Foreach bounding box
            foreach (BoundingBox bb in boxes)
            {
                //Foreach normal (Minecraft normals)
                foreach (Vector3 normal in norms)
                {
                    //Get the face for the normal
                    Face face = GetFace(bb, normal);
                    face.TextureTag = bb.TextureTag;

                    //Store it using the important Normal component
                    float val = face.GetNormalValue();

                    if (float.IsNaN(val))
                        continue;

                    Dictionary<float, List<Face>> dict;
                    if (faces.ContainsKey(normal))
                    {
                        dict = faces[normal];
                    }
                    else
                    {
                        dict = new Dictionary<float, List<Face>>();
                        faces.Add(normal, dict);
                    }

                    if (dict.ContainsKey(val))
                        dict[val].Add(face);
                    else
                        dict.Add(val, new List<Face>() { face });
                }
            }

            List<CustomBlockData> datas = new List<CustomBlockData>();

            //Foreach normal
            foreach (KeyValuePair<Vector3, Dictionary<float, List<Face>>> pair in faces)
            {
                //Foreach normal component
                foreach (KeyValuePair<float, List<Face>> pair2 in pair.Value)
                {
                    //Check if we should build the side
                    if(pair2.Key == 0 && (pair.Key.X == -1 || pair.Key.Y == -1 || pair.Key.Z == -1)) //- sides
                    {
                        Point3 dir3 = pair.Key.ToPoint3();
                        Point3 atSide = blockPos + dir3;

                        BlockData atSideBlock = source.GetData(atSide);
                        if (!i.CanBuildSide(currentBlock, atSideBlock, blockPos, atSide))
                        {
                            continue;
                        }
                    }

                    if (pair2.Key == 1 && (pair.Key.X == 1 || pair.Key.Y == 1 || pair.Key.Z == 1)) //+ sides
                    {
                        Point3 dir3 = pair.Key.ToPoint3();
                        Point3 atSide = blockPos + dir3;

                        BlockData atSideBlock = source.GetData(atSide);
                        if (!i.CanBuildSide(currentBlock, atSideBlock, blockPos, atSide))
                        {
                            continue;
                        }
                    }

                    //pair2.Value contains the faces of the current Normal and Normal component value
                    //Let's calculate what we can see:
                    GpcPolygon polygon = new GpcPolygon();
                    foreach(Face face in pair2.Value)
                    {
                        GpcPolygon addPoly = new GpcPolygon();
                        addPoly.AddContour(new GpcVertexList(face.ConvertToPointList()), false);

                        polygon = polygon.Clip(GpcOperation.Union, addPoly);
                    }

                    //Remove the invisible parts
                    Vector3 inverseNormal = -pair.Key;
                    if (faces.ContainsKey(inverseNormal) && removeCoveredFaces)
                    {
                        if (faces[inverseNormal].ContainsKey(pair2.Key)) //There are faces, which make this face invisible
                        {
                            GpcPolygon invisible = new GpcPolygon();
                            foreach (Face face2 in faces[inverseNormal][pair2.Key])
                            {
                                GpcPolygon addPoly = new GpcPolygon();
                                addPoly.AddContour(new GpcVertexList(face2.ConvertToPointList()), false);

                                invisible = invisible.Clip(GpcOperation.Union, addPoly);
                            }

                            polygon = polygon.Clip(GpcOperation.Difference, invisible); //Remove the invisible parts
                        }
                    }

                    //Create the face
                    if (polygon.NofContours == 0)
                        continue;

                    foreach (GpcVertexList polys in polygon.Contour)
                    {
                        List<PolygonPoint> points = new List<PolygonPoint>();
                        foreach (GpcVertex vert in polys.Vertex)
                        {
                            points.Add(new PolygonPoint(vert.X, vert.Y));
                        }
                        Polygon triangulatorPoly = new Polygon(points);

                        //MAGIC :D
                        Triangulator.Triangulate(triangulatorPoly);

                        foreach (DelaunayTriangle tri in triangulatorPoly.Triangles)
                        {
                            CustomBlockData bd = new CustomBlockData();

                            bd.IsOneTriangle = true;
                            bd.Texture = i.GetTexture(pair2.Value[0]);

                            bd.Vertex1 = ConvertToVertexPosition(tri.Points[0], pair.Key, pair2.Key);
                            bd.Vertex2 = ConvertToVertexPosition(tri.Points[1], pair.Key, pair2.Key);
                            bd.Vertex3 = ConvertToVertexPosition(tri.Points[2], pair.Key, pair2.Key);

                            Vector2[] uvs = new Vector2[]{
                                new Vector2(tri.Points[0].Xf, tri.Points[0].Yf),
                                new Vector2(tri.Points[1].Xf, tri.Points[1].Yf),
                                new Vector2(tri.Points[2].Xf, tri.Points[2].Yf)
                            };

                            uvs = i.GetUVsForTriangle(uvs, pair2.Value[0]);

                            bd.UV1 = uvs[0];
                            bd.UV2 = uvs[1];
                            bd.UV3 = uvs[2];

                            bd.Normal = pair.Key;

                            datas.Add(bd);
                        }
                    }
                }
            }

            return datas;
        }
        public override List<CustomBlockData> GenerateModel(byte metadata, BlockData me, BlockData Xpos, BlockData Xneg, BlockData Ypos, BlockData Yneg, BlockData Zpos, BlockData Zneg, BlockSource source, Point3 blockPosition)
        {
            List<CustomBlockData> mdl = new List<CustomBlockData>();

            bool zPos = Zpos.IsSolid || Zpos.ID == me.ID;
            bool zNeg = Zneg.IsSolid || Zneg.ID == me.ID;
            bool xPos = Xpos.IsSolid || Xpos.ID == me.ID;
            bool xNeg = Xneg.IsSolid || Xneg.ID == me.ID;

            float xStart = 0;
            float xEnd = 1;
            float zStart = 0;
            float zEnd = 1;

            if (!xPos && xNeg)
            {
                xStart = 0;
                xEnd = 0.5f;
            }
            else if (xPos && !xNeg)
            {
                xStart = .5f;
                xEnd = 1;
            }
            else if (xPos && xNeg)
            {
                xStart = 0;
                xEnd = 1;
            }
            else if (!xPos && !xNeg)
            {
                xStart = 0;
                xEnd = 0;
            }

            if (!zPos && zNeg)
            {
                zStart = 0;
                zEnd = 0.5f;
            }
            else if (zPos && !zNeg)
            {
                zStart = .5f;
                zEnd = 1;
            }
            else if (zPos && zNeg)
            {
                zStart = 0;
                zEnd = 1;
            }
            else if (!zPos && !zNeg)
            {
                zStart = 0;
                zEnd = 0;
            }

            if (!zPos && !zNeg && !xPos && !xNeg)
            {
                xStart = 0;
                xEnd = 1;
                zStart = 0;
                zEnd = 1;
            }

            #region X sides
            if (xStart != 0 || xEnd != 0)
            {
                mdl.Add(new CustomBlockData()
                {
                    Vertex1 = new Vector3(xStart, 0, .5f),
                    Vertex2 = new Vector3(xStart, 1, .5f),
                    Vertex3 = new Vector3(xEnd, 1, .5f),
                    Vertex4 = new Vector3(xEnd, 0, .5f),

                    Normal = new Vector3(1, 0, 0),

                    Texture = _tex
                }.CreateUVsRotated90(xStart, 0, xEnd, 1));
                mdl.Add(new CustomBlockData()
                {
                    Vertex1 = new Vector3(xStart, 0, .5f),
                    Vertex2 = new Vector3(xStart, 1, .5f),
                    Vertex3 = new Vector3(xEnd, 1, .5f),
                    Vertex4 = new Vector3(xEnd, 0, .5f),

                    Normal = new Vector3(1, 0, 0),

                    TriFlip = true,

                    Texture = _tex
                }.CreateUVsRotated90(xStart, 0, xEnd, 1));

                if (!source.GetData(new Point3(blockPosition.X, blockPosition.Y + 1, blockPosition.Z)).EqualsID(me))
                {
                    mdl.Add(new CustomBlockData()
                           {
                               Vertex1 = new Vector3(xStart, 0.99f, 0.45f),
                               Vertex2 = new Vector3(xEnd, 0.99f, 0.45f),
                               Vertex3 = new Vector3(xEnd, 0.99f, .55f),
                               Vertex4 = new Vector3(xStart, 0.99f, .55f),

                               Normal = new Vector3(0, 1, 0),

                               UV1 = new Vector2(.45f, 0),
                               UV2 = new Vector2(.45f, 1),
                               UV3 = new Vector2(.55f, 1),
                               UV4 = new Vector2(.55f, 0),

                               Texture = _tex

                           });
                }

                if (!source.GetData(new Point3(blockPosition.X, blockPosition.Y - 1, blockPosition.Z)).EqualsID(me))
                {
                    mdl.Add(new CustomBlockData()
                        {
                            Vertex1 = new Vector3(xStart, 0.01f, 0.45f),
                            Vertex2 = new Vector3(xEnd, 0.01f, 0.45f),
                            Vertex3 = new Vector3(xEnd, 0.01f, .55f),
                            Vertex4 = new Vector3(xStart, 0.01f, .55f),

                            Normal = new Vector3(0, 1, 0),

                            UV1 = new Vector2(.45f, 0),
                            UV2 = new Vector2(.45f, 1),
                            UV3 = new Vector2(.55f, 1),
                            UV4 = new Vector2(.55f, 0),

                            Texture = _tex

                        });
                }

                if (xPos && !xNeg)
                {
                    mdl.Add(new CustomBlockData()
                    {
                        Vertex1 = new Vector3(.5f, 0, .45f),
                        Vertex2 = new Vector3(.5f, .99f, .45f),
                        Vertex3 = new Vector3(.5f, .99f, .55f),
                        Vertex4 = new Vector3(.5f, 0, .55f),

                        Normal = new Vector3(1, 0, 0),

                        UV1 = new Vector2(.45f, 0),
                        UV2 = new Vector2(.45f, 1),
                        UV3 = new Vector2(.55f, 1),
                        UV4 = new Vector2(.55f, 0),

                        Texture = _texY
                    });
                }
                else if (!xPos && xNeg)
                {
                    mdl.Add(new CustomBlockData()
                    {
                        Vertex1 = new Vector3(.5f, 0, .45f),
                        Vertex2 = new Vector3(.5f, .99f, .45f),
                        Vertex3 = new Vector3(.5f, .99f, .55f),
                        Vertex4 = new Vector3(.5f, 0, .55f),

                        Normal = new Vector3(1, 0, 0),

                        UV1 = new Vector2(.45f, 0),
                        UV2 = new Vector2(.45f, 1),
                        UV3 = new Vector2(.55f, 1),
                        UV4 = new Vector2(.55f, 0),

                        Texture = _texY
                    });
                }
            }
            #endregion

            #region Z sides
            if (zStart != 0 || zEnd != 0)
            {
                mdl.Add(new CustomBlockData()
                {
                    Vertex1 = new Vector3(.5f, 0, zStart),
                    Vertex2 = new Vector3(.5f, 1, zStart),
                    Vertex3 = new Vector3(.5f, 1, zEnd),
                    Vertex4 = new Vector3(.5f, 0, zEnd),

                    Normal = new Vector3(0, 0, 1),

                    Texture = _tex
                }.CreateUVsRotated90(zStart, 0, zEnd, 1));
                mdl.Add(new CustomBlockData()
                {
                    Vertex1 = new Vector3(.5f, 0, zStart),
                    Vertex2 = new Vector3(.5f, 1, zStart),
                    Vertex3 = new Vector3(.5f, 1, zEnd),
                    Vertex4 = new Vector3(.5f, 0, zEnd),

                    Normal = new Vector3(0, 0, 1),

                    TriFlip = true,

                    Texture = _tex
                }.CreateUVsRotated90(zStart, 0, zEnd, 1));

                if (!source.GetData(new Point3(blockPosition.X, blockPosition.Y + 1, blockPosition.Z)).EqualsID(me))
                {
                    mdl.Add(new CustomBlockData()
                    {
                        Vertex1 = new Vector3(.45f, 1, zStart),
                        Vertex2 = new Vector3(.45f, 1, zEnd),
                        Vertex3 = new Vector3(.55f, 1, zEnd),
                        Vertex4 = new Vector3(.55f, 1, zStart),

                        Normal = new Vector3(0, 1, 0),

                        UV1 = new Vector2(.45f, zStart),
                        UV2 = new Vector2(.45f, zEnd),
                        UV3 = new Vector2(.55f, zEnd),
                        UV4 = new Vector2(.55f, zStart),

                        Texture = _tex
                    });
                }

                if (!source.GetData(new Point3(blockPosition.X, blockPosition.Y - 1, blockPosition.Z)).EqualsID(me))
                {
                    mdl.Add(new CustomBlockData()
                    {
                        Vertex1 = new Vector3(.45f, 0, zStart),
                        Vertex2 = new Vector3(.45f, 0, zEnd),
                        Vertex3 = new Vector3(.55f, 0, zEnd),
                        Vertex4 = new Vector3(.55f, 0, zStart),

                        Normal = new Vector3(0, 1, 0),

                        UV1 = new Vector2(.45f, zStart),
                        UV2 = new Vector2(.45f, zEnd),
                        UV3 = new Vector2(.55f, zEnd),
                        UV4 = new Vector2(.55f, zStart),

                        Texture = _tex
                    });
                }

                if (zPos && !zNeg)
                {
                    mdl.Add(new CustomBlockData()
                    {
                        Vertex1 = new Vector3(.45f, 0, .5f),
                        Vertex2 = new Vector3(.45f, 1, .5f),
                        Vertex3 = new Vector3(.55f, 1, .5f),
                        Vertex4 = new Vector3(.55f, 0, .5f),

                        Normal = new Vector3(1, 0, 0),

                        UV1 = new Vector2(.45f, 0),
                        UV2 = new Vector2(.45f, 1),
                        UV3 = new Vector2(.55f, 1),
                        UV4 = new Vector2(.55f, 0),

                        Texture = _texY
                    });
                }
                else if (!zPos && zNeg)
                {
                    mdl.Add(new CustomBlockData()
                    {
                        Vertex1 = new Vector3(.45f, 0, .5f),
                        Vertex2 = new Vector3(.45f, 1, .5f),
                        Vertex3 = new Vector3(.55f, 1, .5f),
                        Vertex4 = new Vector3(.55f, 0, .5f),

                        Normal = new Vector3(1, 0, 0),

                        UV1 = new Vector2(.45f, 0),
                        UV2 = new Vector2(.45f, 1),
                        UV3 = new Vector2(.55f, 1),
                        UV4 = new Vector2(.55f, 0),

                        Texture = _texY
                    });
                }
            }
            #endregion

            return mdl;
        }