//>>> _using
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.Windows;
//<<< _using
using System.Runtime.InteropServices;
using Buffer = SharpDX.Direct3D11.Buffer;

namespace Framefield.Core.ID489456c0_39b4_4476_a88d_c84c159a6678
{
    public class Class_Building : OperatorPart.Function,
                              Framefield.Core.OperatorPartTraits.IMeshSupplier
    {
        // IMeshSupplier
        public void AddMeshesTo(ICollection<Mesh> meshes)
        {
            UpdateMesh(new OperatorPartContext(), OperatorPart.Connections);
            meshes.Add(_blockWriter.Mesh);
        }

        public Class_Building(){
            //const int attributesSize = 76;
            //int numTriangles = numQuads * 2;
            //int streamSize = numTriangles * 3 * attributesSize;

            //_dataStream= new DataStream()
            _rand = new Random();
        }


        public override void Dispose() 
        {
            Utilities.DisposeObj(ref _blockWriter.Mesh);
        }

        //>>> _inputids
        private enum InputId
        {
            SizeWidth = 0,
            SizeHeight = 1,
            SizeDepth = 2,
            RandomSeed = 3,
            FloorOffsetMin = 4,
            FloorOffsetMax = 5,
            SubdivideX = 6,
            SubdivideY = 7,
            SubdivideZ = 8
        }
        //<<< _inputids


        public override OperatorPartContext Eval(OperatorPartContext context, List<OperatorPart> inputs, int outputIdx) 
        {
            //try 
            //{

            UpdateMesh(context, inputs);

            context.Renderer.SetupEffect(context);
            context.Renderer.Render(_blockWriter.Mesh, context);
            //}
            //catch (Exception) 
            //{
            //    Logger.Debug(this,"error");
            //}

            return context;
        }


        private void UpdateMesh(OperatorPartContext context, IList<OperatorPart> inputs)
        {
            if (_blockWriter.Mesh != null && !Changed) 
                return;
            
            //>>> _params
            var SizeWidth = inputs[(int)InputId.SizeWidth].Eval(context).Value;
            var SizeHeight = inputs[(int)InputId.SizeHeight].Eval(context).Value;
            var SizeDepth = inputs[(int)InputId.SizeDepth].Eval(context).Value;
            var Size = new Vector3(SizeWidth, SizeHeight, SizeDepth);
            var RandomSeed = inputs[(int)InputId.RandomSeed].Eval(context).Value;
            var FloorOffsetMin = inputs[(int)InputId.FloorOffsetMin].Eval(context).Value;
            var FloorOffsetMax = inputs[(int)InputId.FloorOffsetMax].Eval(context).Value;
            var FloorOffset = new Vector2(FloorOffsetMin, FloorOffsetMax);
            var SubdivideX = inputs[(int)InputId.SubdivideX].Eval(context).Value;
            var SubdivideY = inputs[(int)InputId.SubdivideY].Eval(context).Value;
            var SubdivideZ = inputs[(int)InputId.SubdivideZ].Eval(context).Value;
            var Subdivide = new Vector3(SubdivideX, SubdivideY, SubdivideZ);
            //<<< _params
            
            
                _Width = SizeWidth;
                _Height = SizeHeight;
                _Depth = SizeDepth;
                _floorOffsetMin = FloorOffsetMin;
                _floorOffsetMax = FloorOffsetMax;
                _rand = new Random((int)RandomSeed);
                _tessX = (int)Subdivide.X;
                _tessY = (int)Subdivide.Y;
                _tessZ = (int)Subdivide.Z;
                ConstructBuilding();
                Changed = false;
                
            
            _blockWriter.BuildVertexBuffer(context);
            //Logger.Info("Rebuild");
            
        }
        
        BlockWriter _blockWriter = new BlockWriter();




        #region constucting the building

        public class FloorSection
        {
            public float FloorCount { get; set; }
            public float OffsetX { get; set; }
            public float OffsetZ { get; set; }
            public float Thickness { get; set; }
            public float Spacing { get; set; }
            public float Width { get; set; }
            public float Depth { get; set; }

            public float MinX { get; set; }
            public float MaxX { get; set; }

            public float MinZ { get; set; }
            public float MaxZ { get; set; }
            int _tessX;
            int _tessY;
            int _tessZ;
            //Vector3 _subdi

            public FloorSection(Random rand, float buildingWidth, float buildingHeight, float buildingDepth, float floorOffsetMin, float floorOffsetMax, int tessX=2, int tessY=2, int tessZ=2)
            {
                FloorCount = (int)DistributedRandomValue(rand, 1, -1.4, 10, -1.4);
                OffsetX = (float)DistributedRandomValue(rand, floorOffsetMin, -0.2, floorOffsetMax, -2.4);
                OffsetZ = (float)DistributedRandomValue(rand, floorOffsetMin, -0.2, floorOffsetMax, -2.4);
                Thickness = (float)DistributedRandomValue(rand, 0.4, 1, 6.0, -1.4);
                Spacing = (float)DistributedRandomValue(rand, 1, -0.4, 5.0, -1.4);

                MinX = -buildingWidth / 2 - OffsetX;
                MaxX = buildingWidth / 2 + OffsetX;

                MinZ = -buildingDepth / 2 - OffsetZ;
                MaxZ = buildingDepth / 2 - OffsetZ;
                _tessX = tessX;
                _tessY = tessY;
                _tessZ = tessZ;                
            }

            public void AddBlock(float _ConstructedHeight, BlockWriter writer)
            {
                writer.AddBlock(MinX, MaxX,
                           _ConstructedHeight + Spacing, _ConstructedHeight + Spacing + Thickness,
                            MinZ, MaxZ,
                            _tessX, _tessY, _tessZ
                );
            }
        }

        public class Fassade
        {
            float SequenceWidth { get; set; }
            public int SequenceCount { get; set; }
            
            int PrimaryCount { get; set; }
            float PrimaryOffset { get; set; }
            float PrimaryDepth { get; set; }
            float PrimaryDensity { get; set; }

            int SecondaryCount { get; set; }
            float SecondaryOffset { get; set; }
            float SecondaryDepth { get; set; }
            float SecondaryDensity { get; set; }

            float PosX { get; set; }
            float PosZ { get; set; }
            int _tessX;
            int _tessY;
            int _tessZ;
            
            bool _sideWays;
            
            public Fassade(Random rand, float length, float posX, float posZ, bool sideWays= false, int tessX=2, int tessY=2, int tessZ=2)
            {
                PosX = posX;
                PosZ = posZ;
                _sideWays = sideWays;
                _tessX= tessX;
                _tessY= tessY;
                _tessZ= tessZ;

                PrimaryCount = (int)DistributedRandomValue(rand, 1, 1.4, 3, -1.5);
                PrimaryOffset = (float)DistributedRandomValue(rand, -3.5, -1.0, 0.6, -1.0);
                PrimaryDepth = (float)DistributedRandomValue(rand, 0.2, -1.0, 4, -1.0);
                PrimaryDensity = (float)DistributedRandomValue(rand, 0.1, -1.0, 0.4, -1.0);

                SecondaryCount = (int)DistributedRandomValue(rand, 1, 3, 10, -1.4);
                SecondaryOffset = (float)DistributedRandomValue(rand, -1.0, -1.4, 0, -1.0);
                SecondaryDepth = (float)DistributedRandomValue(rand, 0.2, -1.0, 0.4, -1.0);
                SecondaryDensity = (float)DistributedRandomValue(rand, 0.1, -1.0, 0.9, -1.0);

                var someWidth = (float)DistributedRandomValue(rand, 2, -1.4, 20, -1.4);

                SequenceCount = (int)(length / someWidth)+1;

                SequenceWidth = length / (SequenceCount + PrimaryDensity);

            }


            public void Build(FloorSection floorSection, float constructionHeight, BlockWriter writer)
            {
                float x = PosX;
                float z = PosZ;

                var width2 = SequenceWidth * (1-PrimaryDensity)/ (SecondaryCount + SecondaryDensity);

                for (var sequenceIndex = 0; sequenceIndex < SequenceCount +1; ++sequenceIndex)
                {
                    var xp = x + SequenceWidth * PrimaryDensity;
                    for (var primaryIndex = 0; primaryIndex < PrimaryCount; ++primaryIndex)
                    {
                        var xpp= (SequenceWidth * PrimaryDensity + 0.5f)*primaryIndex;
                        //var xpp= primaryIndex *3;
                        // Primary
                        if(! _sideWays) {
                            writer.AddBlock(x+xpp, xp+xpp,
                                constructionHeight, constructionHeight + floorSection.Thickness + floorSection.Spacing,
                                z + PrimaryOffset, z + PrimaryOffset + PrimaryDepth,
                                _tessX, _tessY, _tessZ
                            );
    
                            writer.AddBlock(x+xpp, xp+xpp,
                                constructionHeight, constructionHeight + floorSection.Thickness + floorSection.Spacing,
                                -z - PrimaryOffset, -z - PrimaryOffset - PrimaryDepth,
                                _tessX, _tessY, _tessZ
                            );
                        }
                        else {
                            writer.AddBlock(z + PrimaryOffset, z + PrimaryOffset + PrimaryDepth,
                                constructionHeight, constructionHeight + floorSection.Thickness + floorSection.Spacing,
                                x+xpp, xp+xpp,
                                _tessX, _tessY, _tessZ
                            );
    
                            writer.AddBlock(-z - PrimaryOffset, -z - PrimaryOffset - PrimaryDepth,
                                constructionHeight, constructionHeight + floorSection.Thickness + floorSection.Spacing,
                                x+xpp, xp+xpp,
                                _tessX, _tessY, _tessZ
                            );                        
                        }
                    }

                    // Secondary Structure
                    
                    if( sequenceIndex < SequenceCount )
                    {
                        for (var secondaryIndex = 0; secondaryIndex < SecondaryCount; ++secondaryIndex)
                        {
                            var x2 = xp+ width2 * secondaryIndex;
    
                            if(!_sideWays) {
                                writer.AddBlock(
                                    x2 + width2 * SecondaryDensity, x2 + width2,
                                    constructionHeight, constructionHeight + floorSection.Thickness + floorSection.Spacing,
                                    z + SecondaryOffset, z + SecondaryOffset + SecondaryDepth,
                                    2, _tessY, 2
                                    
                                );
                                writer.AddBlock(
                                    x2 + width2 * SecondaryDensity, x2 + width2,
                                    constructionHeight, constructionHeight + floorSection.Thickness + floorSection.Spacing,
                                    -z - SecondaryOffset, -z - SecondaryOffset - SecondaryDepth,
                                    2, _tessY, 2
                                );
                            }
                            else {
                            }
                        }
                    }                        
                    x += SequenceWidth;
                }
            }
        }


        private void ConstructBuilding()
        {
            _blockWriter.ClearVertices();
            var fassadeX = new Fassade(_rand, _Width, -_Width/2, _Depth/2, false, _tessX, _tessY, _tessZ);
            var fassadeZ = new Fassade(_rand, _Depth, -_Depth/2, _Width/2, true, _tessX, _tessY, _tessZ);

            int MAX_FLOORS = 100;
            // Floors
            float constructedHeight = 0;
            int constructedFloors = 0;

            var floorSection = new FloorSection(_rand, _Width, _Height, _Depth, _floorOffsetMin, _floorOffsetMax, (fassadeX.SequenceCount+1)*_tessX, _tessY+1, (fassadeZ.SequenceCount+1) * _tessZ);

            while (constructedHeight < _Height && constructedFloors < MAX_FLOORS)
            {
                floorSection.AddBlock(constructedHeight, _blockWriter);
                constructedFloors++;

                fassadeX.Build(floorSection, constructedHeight, _blockWriter);
                fassadeZ.Build(floorSection, constructedHeight, _blockWriter);
                constructedHeight += floorSection.Thickness + floorSection.Spacing;

                //fassadeXMin.Build(floorSequence, constructedHeight, blockWriter);
                //fassadeXMin.Build(floorSequence, constructedHeight, blockWriter);
                //fassadeXMin.Build(floorSequence, constructedHeight, blockWriter);

                floorSection.FloorCount--;
                if (floorSection.FloorCount <= 0) 
                    floorSection = new FloorSection(_rand, _Width, _Height, _Depth, _floorOffsetMin, _floorOffsetMax,  (fassadeX.SequenceCount+1)*_tessX, _tessY+1, (fassadeZ.SequenceCount+1) * _tessZ);

            }
        }
        #endregion

        #region writing cubes
        public class BlockWriter
        {

            [StructLayout(LayoutKind.Sequential)]
            struct Vertex
            {
                public Vector4 Position;
                public Vector3 Normal;
                public Color4 Color;
                public Vector2 TexCoord;
                public Vector3 Tangent;
                public Vector3 Binormal;
            }

            public BlockWriter()
            {
                _generatedVertices = new List<Vertex>();
            }

            List<Vertex> _generatedVertices;

            public void ClearVertices()
            {
                _generatedVertices.Clear();
            }
            
            
            public void AddBlock(float minX, float maxX, float minY, float maxY, float minZ, float maxZ, int tessX = 2, int tessY = 2, int tessZ = 2)
            {
                int numQuads = (tessY - 1) * (tessX - 1) * 2 + (tessY - 1) * (tessZ - 1) * 2 + (tessZ - 1) * (tessX - 1) * 2;
                Color4 Color = new Color4(1, 1, 1, 1);

                Vector3 size = new Vector3(  Math.Abs(maxX - minX), Math.Abs( maxY - minY), Math.Abs( maxZ - minZ));
                Vector3 position = new Vector3((maxX + minX) / 2, (maxY + minY) / 2, (maxZ + minZ) / 2);

                Vector3 start = position - size * 0.5f;
                Vector3 end = position + size * 0.5f;

                float uPart = 0.25f;
                float uPart2 = 0.5f;
                float uPart3 = 0.75f;
                float vPart = 0.33333f;
                
                float uBottom = minY;
                float uTop = maxY;
                float uLeft = minZ;
                float uRight = maxZ;
                float uFront = minX;
                float uBack = maxX;

                // texture coord layout : 1 - front, 2 - right, 3 - back, 4 - left, 5 - top, 6 - bottom, X - not used
                // 
                //   v^
                //    |
                //    |5XXX
                //    |1234  <- Texture
                //    |6XXX
                //     ------> 
                //           u

                for (int y = 0; y < (tessY - 1); ++y)
                {
                    float normalizedBottom = (float)y / (float)(tessY - 1);
                    float bottom = start.Y + (size.Y * normalizedBottom);
                    float normalizedTop = (float)(y + 1) / (float)(tessY - 1);
                    float top = start.Y + (size.Y * normalizedTop);

                    //float lowerV = vPart + normalizedBottom * vPart;
                    //float upperV = vPart + normalizedTop * vPart;
                    float lowerV = uBottom + normalizedBottom * (uTop-uBottom)/(tessY-1);
                    float upperV = uBottom + normalizedTop * (uTop-uBottom)/(tessY-1);;

                    for (int x = 0; x < (tessX - 1); ++x)
                    {
                        float normalizedLeft = (float)x / (float)(tessX - 1);
                        float left = start.X + (size.X * normalizedLeft);
                        float normalizedRight = (float)(x + 1) / (float)(tessX - 1);
                        float right = start.X + (size.X * normalizedRight);
                        // front
                        //float leftU = normalizedLeft * uPart;
                        //float rightU = normalizedRight * uPart;
                        float leftU = uLeft + normalizedLeft *   (uRight-uLeft)/(tessY-1);
                        float rightU = uLeft + normalizedRight * (uRight-uLeft)/(tessY-1);
                        AddQuad(Color,
                                new Vector3(left, bottom, end.Z), new Vector2(leftU, lowerV),
                                new Vector3(right, bottom, end.Z), new Vector2(rightU, lowerV),
                                new Vector3(right, top, end.Z), new Vector2(rightU, upperV),
                                new Vector3(left, top, end.Z), new Vector2(leftU, upperV));

                        // back
                        //leftU = uLeft + normalizedLeft *   (uRight-uLeft)/(tessY-1);
                        //rightU = uLeft + normalizedRight * (uRight-uLeft)/(tessY-1);
                        leftU = uFront + normalizedLeft *   (uFront-uBack)/(tessY-1);
                        rightU = uFront + normalizedRight * (uFront-uBack)/(tessY-1);
                        AddQuad(Color,
                                new Vector3(right, bottom, start.Z), new Vector2(leftU, lowerV),
                                new Vector3(left, bottom, start.Z), new Vector2(rightU, lowerV),
                                new Vector3(left, top, start.Z), new Vector2(rightU, upperV),
                                new Vector3(right, top, start.Z), new Vector2(leftU, upperV));
                    }

                    for (int z = 0; z < (tessZ - 1); ++z)
                    {
                        float normalizedBack = (float)(z) / (float)(tessZ - 1);
                        float back = start.Z + (size.Z * normalizedBack);
                        float normalizedFront = (float)(z + 1) / (float)(tessZ - 1);
                        float front = start.Z + (size.Z * normalizedFront);

                        // left side
                        float leftU = uLeft + normalizedFront *   (uRight-uLeft)/(tessY-1);
                        float rightU = uLeft + normalizedBack * (uRight-uLeft)/(tessY-1);
                        AddQuad(Color,
                                new Vector3(start.X, bottom, front), new Vector2(rightU, lowerV),
                                new Vector3(start.X, top, front), new Vector2(rightU, upperV),
                                new Vector3(start.X, top, back), new Vector2(leftU, upperV),
                                new Vector3(start.X, bottom, back), new Vector2(leftU, lowerV));

                        // right side
                        leftU = uLeft + normalizedFront * (uRight-uLeft)/(tessY-1);
                        rightU = uLeft + normalizedBack * (uRight-uLeft)/(tessY-1);
                        AddQuad(Color,
                                new Vector3(end.X, bottom, front), new Vector2(leftU, lowerV),
                                new Vector3(end.X, bottom, back), new Vector2(rightU, lowerV),
                                new Vector3(end.X, top, back), new Vector2(rightU, upperV),
                                new Vector3(end.X, top, front), new Vector2(leftU, upperV));
                    }
                }

                for (int z = 0; z < (tessZ - 1); ++z)
                {
                    float normalizedBack = (float)(z) / (float)(tessZ - 1);
                    float back = start.Z + (size.Z * normalizedBack);
                    float normalizedFront = (float)(z + 1) / (float)(tessZ - 1);
                    float front = start.Z + (size.Z * normalizedFront);

                    for (int x = 0; x < (tessX - 1); ++x)
                    {
                        float normalizedLeft = (float)(x) / (float)(tessX - 1);
                        float left = start.X + (size.X * normalizedLeft);
                        float normalizedRight = (float)(x + 1) / (float)(tessX - 1);
                        float right = start.X + (size.X * normalizedRight);

                        //float leftU = normalizedLeft * uPart;
                        //float rightU = normalizedRight * uPart;

                        // bottom
                        //float lowerV = normalizedBack * vPart;
                        //float upperV = normalizedFront * vPart;

                        float leftU  = uBack - normalizedLeft *   (uBack-uFront)/(tessY-1);
                        float rightU = uBack - normalizedRight * (uBack-uFront)/(tessY-1);

                        float lowerV = uLeft + normalizedBack * (uRight-uLeft)/(tessY-1);
                        float upperV = uLeft + normalizedFront * (uRight-uLeft)/(tessY-1);;


                        AddQuad(Color,
                                new Vector3(right, start.Y, front), new Vector2(rightU, upperV),
                                new Vector3(left, start.Y, front), new Vector2(leftU, upperV),
                                new Vector3(left, start.Y, back), new Vector2(leftU, lowerV),
                                new Vector3(right, start.Y, back), new Vector2(rightU, lowerV));

                        // top
                        //upperV = 1.0f - normalizedBack * vPart;
                        //lowerV = 1.0f - normalizedFront * vPart;
                        AddQuad(Color,
                                new Vector3(left, end.Y, front), new Vector2(leftU, lowerV),
                                new Vector3(right, end.Y, front), new Vector2(rightU, lowerV),
                                new Vector3(right, end.Y, back), new Vector2(rightU, upperV),
                                new Vector3(left, end.Y, back), new Vector2(leftU, upperV));
                    }
                }

            }

            private void AddQuad(Color4 color,
                                 Vector3 p0, Vector2 tx0,
                                 Vector3 p1, Vector2 tx1,
                                 Vector3 p2, Vector2 tx2,
                                 Vector3 p3, Vector2 tx3)
            {
                var tangent = new Vector3(1.0f, 0.0f, 0.0f);
                var binormal = new Vector3(0.0f, -1.0f, 0.0f);

                //triangle 0, 1, 2
                var normal = Vector3.Cross(p1 - p0, p2 - p0);
                normal.Normalize();

                _generatedVertices.Add(new Vertex() { Position = new Vector4(p0.X, p0.Y, p0.Z, 1), Normal = normal, Color = color, TexCoord = tx0, Tangent = tangent, Binormal = binormal });
                _generatedVertices.Add(new Vertex() { Position = new Vector4(p1.X, p1.Y, p1.Z, 1), Normal = normal, Color = color, TexCoord = tx1, Tangent = tangent, Binormal = binormal });
                _generatedVertices.Add(new Vertex() { Position = new Vector4(p2.X, p2.Y, p2.Z, 1), Normal = normal, Color = color, TexCoord = tx2, Tangent = tangent, Binormal = binormal });

                //triangle 0, 2, 3
                _generatedVertices.Add(new Vertex() { Position = new Vector4(p0.X, p0.Y, p0.Z, 1), Normal = normal, Color = color, TexCoord = tx0, Tangent = tangent, Binormal = binormal });
                _generatedVertices.Add(new Vertex() { Position = new Vector4(p2.X, p2.Y, p2.Z, 1), Normal = normal, Color = color, TexCoord = tx2, Tangent = tangent, Binormal = binormal });
                _generatedVertices.Add(new Vertex() { Position = new Vector4(p3.X, p3.Y, p3.Z, 1), Normal = normal, Color = color, TexCoord = tx3, Tangent = tangent, Binormal = binormal });
            }


            public void BuildVertexBuffer(OperatorPartContext context)
            {
                var inputElements = new[]
                                    {
                                        new InputElement("POSITION", 0, SharpDX.DXGI.Format.R32G32B32A32_Float, 0, 0),
                                        new InputElement("NORMAL", 0, SharpDX.DXGI.Format.R32G32B32_Float, 16, 0),
                                        new InputElement("COLOR", 0, SharpDX.DXGI.Format.R32G32B32A32_Float, 28, 0),
                                        new InputElement("TEXCOORD", 0, SharpDX.DXGI.Format.R32G32_Float, 44, 0),
                                        new InputElement("TANGENT", 0, SharpDX.DXGI.Format.R32G32B32_Float, 52, 0),
                                        new InputElement("BINORMAL", 0, SharpDX.DXGI.Format.R32G32B32_Float, 64, 0)
                                    };
                
                const int attributesSize = 76;
                //int numTriangles = numQuads * 2;
                //int streamSize = numTriangles * 3 * attributesSize;
                int streamSize = _generatedVertices.Count();

//                if (Mesh == null || streamSize != Mesh.NumTriangles * 3 * Mesh.AttributesSize)
                {
                    Utilities.DisposeObj(ref Mesh);
//                    using (var stream = new DataStream(streamSize, true, true))
                    {
                        var vertices = Buffer.Create<Vertex>(context.D3DDevice, _generatedVertices.ToArray(), new BufferDescription()
                        {
                            BindFlags = BindFlags.VertexBuffer,
                            CpuAccessFlags = CpuAccessFlags.Write,
                            OptionFlags = ResourceOptionFlags.None,
//                            SizeInBytes = streamSize,
                            Usage = ResourceUsage.Dynamic
                        });

                        Mesh = new Mesh
                        {
                            InputElements = inputElements,
                            Vertices = vertices,
                            NumTriangles = _generatedVertices.Count()/3,
                            AttributesSize = attributesSize
                        };
                    }
                }
                //DataStream vertexStream;
                //DataBox box = context.D3DDevice.ImmediateContext.MapSubresource(Mesh.Vertices, MapMode.WriteDiscard, MapFlags.None, out vertexStream);
                //using (vertexStream)
                //{
                //    vertexStream.Position = 0;
                //}
                //context.D3DDevice.ImmediateContext.UnmapSubresource(Mesh.Vertices, 0);
            }
            public Mesh Mesh;
        }
        #endregion

        #region internal helper methods
        /**
         * Returns random values between A...B . The distribution can be adjusted with the weight paramaters.
         */
        static double DistributedRandomValue(Random rand, double A, double weightA, double B, double weightB)
        {
            var t = rand.NextDouble();
            var fadeA = Math.Pow(t, Math.Pow(0.5, -weightA));
            var fadeB = Math.Pow(1 - t, Math.Pow(0.5, -weightB));
            var v = fadeA * (1 - t) + t * (1 - fadeB);
            return (B - A) * v + A;
        }

        #endregion

        
//        private DataStream _dataStream;
        private float _Height;
        private Random _rand;

        float _Width;
        float _Depth;
        float _floorOffsetMin;
        float _floorOffsetMax;
        int _tessX;
        int _tessY;
        int _tessZ;
        
        public float _ConstructedHeight;




    }
}