void genNoiseMap()
    {
        float ang, x, y, c, s;
        int   ii;

        for (float i = 0; i < segments; i++)
        {
            ii = (int)i;

            ang = 360 * (i / segments);

            c = Mathf.Cos(ang);
            s = Mathf.Sin(ang);

            x         = radius * c;
            y         = radius * s;
            noise[ii] = fbm(x, y, seed, iterations);
            //Debug.Log(noise[ii]);

            x        = (radius + maxVariance * noise[ii]) * c;
            y        = (radius + maxVariance * noise[ii]) * s;
            vex[ii]  = new Vector2z(x, y);
            vex2[ii] = new Vector2(x, y);
            //Debug.Log(vex[ii]);
        }
    }
    private static void GenerateFloorPlan(BuildrData data)
    {
        RandomGen rgen = constraints.rgen;

        BuildrPlan      plan   = ScriptableObject.CreateInstance <BuildrPlan>();
        List <Vector2z> bounds = new List <Vector2z>();

        bounds.Add(new Vector2z(rgen.OutputRange(-5, -15), rgen.OutputRange(-5, -15)));
        bounds.Add(new Vector2z(rgen.OutputRange(5, 15), rgen.OutputRange(-5, -15)));
        bounds.Add(new Vector2z(rgen.OutputRange(5, 15), rgen.OutputRange(5, 15)));
        bounds.Add(new Vector2z(rgen.OutputRange(-5, -15), rgen.OutputRange(5, 15)));

        if (rgen.output < 0.25f)//should we split the volume?
        {
            float ratio = rgen.OutputRange(0.25f, 0.75f);
            bounds.Insert(1, Vector2z.Lerp(bounds[0], bounds[1], ratio));
            bounds.Insert(4, Vector2z.Lerp(bounds[3], bounds[4], ratio));

            plan.AddVolume(new [] { bounds[0], bounds[1], bounds[4], bounds[5] });
            plan.AddVolume(1, 2, new [] { bounds[2], bounds[3] });
        }
        else
        {
            plan.AddVolume(bounds.ToArray());
        }

        data.plan = plan;
    }
    private static void GenerateFloorPlan(BuildrData data)
    {
        BuildrGenerateConstraints constraints = data.generatorConstraints;
        RandomGen rgen = constraints.rgen;

        BuildrPlan      plan            = ScriptableObject.CreateInstance <BuildrPlan>();
        List <Vector2z> bounds          = new List <Vector2z>();
        Rect            floorplanBounds = new Rect(-15, -15, 30, 30);

        if (constraints.constrainPlanByArea)
        {
            floorplanBounds = constraints.area;
        }
        bounds.Add(new Vector2z(rgen.OutputRange(-5, floorplanBounds.xMin), rgen.OutputRange(-5, floorplanBounds.yMin)));
        bounds.Add(new Vector2z(rgen.OutputRange(5, floorplanBounds.xMax), rgen.OutputRange(-5, floorplanBounds.yMin)));
        bounds.Add(new Vector2z(rgen.OutputRange(5, floorplanBounds.xMax), rgen.OutputRange(5, floorplanBounds.yMax)));
        bounds.Add(new Vector2z(rgen.OutputRange(-5, floorplanBounds.xMin), rgen.OutputRange(5, floorplanBounds.yMax)));

        if (rgen.output < 0.25f)//should we split the volume?
        {
            float ratio = rgen.OutputRange(0.25f, 0.75f);
            bounds.Insert(1, Vector2z.Lerp(bounds[0], bounds[1], ratio));
            bounds.Insert(4, Vector2z.Lerp(bounds[3], bounds[4], ratio));

            plan.AddVolume(new [] { bounds[0], bounds[1], bounds[4], bounds[5] });
            plan.AddVolume(1, 2, new [] { bounds[2], bounds[3] });
        }
        else
        {
            plan.AddVolume(bounds.ToArray());
        }

        data.plan = plan;
    }
    public static bool Check(Vector2z[] points)
    {
        int numberOfPoints = points.Length;
        int i, j, k;
        int count = 0;
        float z;

        if (numberOfPoints < 3)
            return (false);

        for (i = 0; i < numberOfPoints; i++)
        {
            j = (i + 1) % numberOfPoints;
            k = (i + 2) % numberOfPoints;

            Vector2z pointA = points[i];
            Vector2z pointB = points[j];
            Vector2z pointC = points[k];

            z = (pointB.x - pointA.x) * (pointC.y - pointA.y);
            z -= (pointB.y - pointA.y) * (pointC.x - pointA.x);

            if (z < 0)
                count--;
            else if (z > 0)
                count++;
        }

        if (count > 0)
            return (true);
        else if (count < 0)
            return (false);
        else
            return (false);
    }
Exemple #5
0
    public static float SqrMag(Vector2z a, Vector2z b)
    {
        float x = Mathf.Abs(b.x - a.x);
        float z = Mathf.Abs(b.z - a.z);

        return(x * x + z * z);
    }
Exemple #6
0
    public static Vector2z Lerp(Vector2z a, Vector2z b, float val)
    {
        Vector2z lerped = new Vector2z();

        lerped.vector2 = Vector2.Lerp(a.vector2, b.vector2, val);
        return(lerped);
    }
    public static bool PointInsidePoly(Vector2z point, Vector2z[] poly)
    {
        Rect polyBounds = new Rect(0,0,0,0);
        foreach(Vector2z polyPoint in poly)
        {
            if(polyBounds.xMin > polyPoint.x)
                polyBounds.xMin = polyPoint.x;
            if(polyBounds.xMax < polyPoint.x)
                polyBounds.xMax = polyPoint.x;
            if(polyBounds.yMin > polyPoint.z)
                polyBounds.yMin = polyPoint.z;
            if(polyBounds.yMax < polyPoint.z)
                polyBounds.yMax = polyPoint.z;
        }
        if(!polyBounds.Contains(point.vector2))
            return false;

        Vector2z pointRight = point + new Vector2z(polyBounds.width, 0);

        int numberOfPolyPoints = poly.Length;
        int numberOfCrossOvers = 0;
        for(int i = 0; i < numberOfPolyPoints; i++)
        {
            Vector2z p0 = poly[i];
            Vector2z p1 = poly[(i + 1) % numberOfPolyPoints];
            if (FastLineIntersection(point, pointRight, p0, p1))
                numberOfCrossOvers++;
        }

        return numberOfCrossOvers % 2 != 0;
    }
Exemple #8
0
    private static bool IntersectsTriangle2(Vector2z A, Vector2z B, Vector2z C, Vector2z P)
    {
        float planeAB = (A.x - P.x) * (B.y - P.y) - (B.x - P.x) * (A.y - P.y);
        float planeBC = (B.x - P.x) * (C.y - P.y) - (C.x - P.x) * (B.y - P.y);
        float planeCA = (C.x - P.x) * (A.y - P.y) - (A.x - P.x) * (C.y - P.y);

        return(Sign(planeAB) == Sign(planeBC) && Sign(planeBC) == Sign(planeCA));
    }
Exemple #9
0
 public static bool FastLineIntersection(Vector2z a1, Vector2z a2, Vector2z b1, Vector2z b2)
 {
     if (a1 == b1 || a1 == b2 || a2 == b1 || a2 == b2)
     {
         return(false);
     }
     return((CCW(a1, b1, b2) != CCW(a2, b1, b2)) && (CCW(a1, a2, b1) != CCW(a1, a2, b2)));
 }
Exemple #10
0
    /// <summary>
    /// Adds the wall point by vector2z.
    /// </summary>
    /// <returns>
    /// The wall point index.
    /// </returns>
    /// <param name='volumeIndex'>
    /// volume index.
    /// </param>
    /// <param name='volumeWallIndex'>
    /// At point.
    /// </param>
    /// <param name='newPoint'>
    /// New point.
    /// </param>
    public int AddWallPoint(int volumeIndex, int volumeWallIndex, Vector2z newPoint)
    {
        int newPointIndex = points.Count;

        points.Add(newPoint);

        return(AddWallPoint(volumeIndex, volumeWallIndex, newPointIndex));
    }
Exemple #11
0
    private static bool IntersectsTriangle(Vector2z A, Vector2z B, Vector2z C, Vector2z P)
    {
        bool b1, b2, b3;

        b1 = Sign(P, A, B) < 0.0f;
        b2 = Sign(P, B, C) < 0.0f;
        b3 = Sign(P, C, A) < 0.0f;

        return((b1 == b2) && (b2 == b3));
    }
Exemple #12
0
    public void AddVolume(Vector3[] newPoints, Vector3 offset)
    {
        int numberOfnewPoints = newPoints.Length;

        Vector2z[] new2VzPoints = new Vector2z[numberOfnewPoints];
        for (int p = 0; p < numberOfnewPoints; p++)
        {
            new2VzPoints[p] = new Vector2z(newPoints[p] + offset);
        }
        AddVolume(new2VzPoints);
    }
Exemple #13
0
    public static bool Check(Vector2z[] points)
    {
        int   numberOfPoints = points.Length;
        int   i, j, k;
        int   count = 0;
        float z;

        if (numberOfPoints < 3)
        {
            return(false);
        }

        for (i = 0; i < numberOfPoints; i++)
        {
            j = (i + 1) % numberOfPoints;
            k = (i + 2) % numberOfPoints;

            Vector2z pointA = points[i];
            Vector2z pointB = points[j];
            Vector2z pointC = points[k];

            z  = (pointB.x - pointA.x) * (pointC.y - pointA.y);
            z -= (pointB.y - pointA.y) * (pointC.x - pointA.x);

            if (z < 0)
            {
                count--;
            }
            else if (z > 0)
            {
                count++;
            }
        }

        if (count > 0)
        {
            return(true);
        }
        else if (count < 0)
        {
            return(false);
        }
        else
        {
            return(false);
        }
    }
Exemple #14
0
    public static bool PointInsidePoly(Vector2z point, Vector2z[] poly)
    {
        Rect polyBounds = new Rect(0, 0, 0, 0);

        foreach (Vector2z polyPoint in poly)
        {
            if (polyBounds.xMin > polyPoint.x)
            {
                polyBounds.xMin = polyPoint.x;
            }
            if (polyBounds.xMax < polyPoint.x)
            {
                polyBounds.xMax = polyPoint.x;
            }
            if (polyBounds.yMin > polyPoint.z)
            {
                polyBounds.yMin = polyPoint.z;
            }
            if (polyBounds.yMax < polyPoint.z)
            {
                polyBounds.yMax = polyPoint.z;
            }
        }
        if (!polyBounds.Contains(point.vector2))
        {
            return(false);
        }

        Vector2z pointRight = point + new Vector2z(polyBounds.width, 0);

        int numberOfPolyPoints = poly.Length;
        int numberOfCrossOvers = 0;

        for (int i = 0; i < numberOfPolyPoints; i++)
        {
            Vector2z p0 = poly[i];
            Vector2z p1 = poly[(i + 1) % numberOfPolyPoints];
            if (FastLineIntersection(point, pointRight, p0, p1))
            {
                numberOfCrossOvers++;
            }
        }

        return(numberOfCrossOvers % 2 != 0);
    }
Exemple #15
0
 public EarClipTriangle(Vector2z a, Vector2z b, Vector2z c)
 {
     bounds = new Rect(a.x, a.z, 0, 0);
     Vector2z[] points = new Vector2z[] { a, b, c };
     for (int i = 1; i < 3; i++)
     {
         if (bounds.xMin < points[i].x)
         {
             bounds.xMin = points[i].x;
         }
         if (bounds.xMax < points[i].x)
         {
             bounds.xMax = points[i].x;
         }
         if (bounds.yMin < points[i].z)
         {
             bounds.yMin = points[i].z;
         }
         if (bounds.yMax < points[i].z)
         {
             bounds.yMax = points[i].z;
         }
     }
 }
Exemple #16
0
    private static void FlatRoof(BuildrVolume volume, BuildrRoofDesign design)
    {
        BuildrPlan area = data.plan;
        int volumeIndex = area.volumes.IndexOf(volume);
        int numberOfVolumePoints = volume.points.Count;
        int numberOfFloors = volume.numberOfFloors;
        float floorHeight = data.floorHeight;
        Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight);

        //add top base of the flat roof
        Vector3[] newEndVerts = new Vector3[numberOfVolumePoints];
        Vector2[] newEndUVs = new Vector2[numberOfVolumePoints];
        int[] tris = new List<int>(area.GetTrianglesBySectorBase(volumeIndex)).ToArray();
        int roofTextureID = design.GetTexture(BuildrRoofDesign.textureNames.floor);
        BuildrTexture texture = data.textures[roofTextureID];
        for (int i = 0; i < numberOfVolumePoints; i++)
        {
            Vector2z point = area.points[volume.points[i]];
            newEndVerts[i] = point.vector3 + volumeFloorHeight;
            newEndUVs[i] = new Vector2(point.vector2.x / texture.textureUnitSize.x, point.vector2.y / texture.textureUnitSize.y);
        }

        AddData(newEndVerts, newEndUVs, tris, design.GetTexture(BuildrRoofDesign.textureNames.floor));
    }
Exemple #17
0
    private static void Mansard(BuildrVolume volume, BuildrRoofDesign design)
    {
        BuildrPlan area = data.plan;
        int numberOfVolumePoints = volume.points.Count;
        int numberOfFloors = volume.numberOfFloors;
        float floorHeight = data.floorHeight;
        Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight);

        //add top base of the flat roof
        Vector3[] topVerts = new Vector3[numberOfVolumePoints];
        Vector2[] topUVs = new Vector2[numberOfVolumePoints];
        int topTextureID = design.GetTexture(BuildrRoofDesign.textureNames.floorB);
        BuildrTexture texture = textures[topTextureID];

        for (int l = 0; l < numberOfVolumePoints; l++)
        {
            int indexA, indexB, indexA0, indexB0;
            Vector3 p0, p1, p00, p10;
            indexA = l;
            indexB = (l < numberOfVolumePoints - 1) ? l + 1 : 0;
            indexA0 = (l > 0) ? l - 1 : numberOfVolumePoints - 1;
            indexB0 = (l < numberOfVolumePoints - 2) ? l + 2 : l + 2 - numberOfVolumePoints;

            p0 = area.points[volume.points[indexA]].vector3;
            p1 = area.points[volume.points[indexB]].vector3;
            p00 = area.points[volume.points[indexA0]].vector3;
            p10 = area.points[volume.points[indexB0]].vector3;

            float facadeWidth = Vector3.Distance(p0, p1);
            Vector3 facadeDirection = (p1 - p0).normalized;
            Vector3 facadeDirectionLeft = (p0 - p00).normalized;
            Vector3 facadeDirectionRight = (p10 - p1).normalized;
            Vector3 facadeNormal = Vector3.Cross(facadeDirection, Vector3.up);
            Vector3 facadeNormalLeft = Vector3.Cross(facadeDirectionLeft, Vector3.up);
            Vector3 facadeNormalRight = Vector3.Cross(facadeDirectionRight, Vector3.up);

            float roofHeight = design.height;
            float baseDepth = design.floorDepth;
            float cornerLeftRad = Vector3.Angle(facadeDirection, -facadeDirectionLeft) * Mathf.Deg2Rad / 2;
            float cornerRightRad = Vector3.Angle(-facadeDirection, facadeDirectionRight) * Mathf.Deg2Rad / 2;
            float cornerDepthLeft = baseDepth / Mathf.Sin(cornerLeftRad);
            float cornerDepthRight = baseDepth / Mathf.Sin(cornerRightRad);
            float topDepth = design.depth;
            float cornerTopDepthLeft = topDepth / Mathf.Sin(cornerLeftRad);
            float cornerTopDepthRight = topDepth / Mathf.Sin(cornerRightRad);

            Vector3 pr = facadeDirection * facadeWidth;

            Vector3 leftDir = (facadeNormal + facadeNormalLeft).normalized;
            Vector3 rightDir = (facadeNormal + facadeNormalRight).normalized;

            p0 += volumeFloorHeight;
            p1 += volumeFloorHeight;

            Vector3 w0, w1, w2, w3, w4, w5;
            w0 = p0;
            w1 = p0 + pr;
            w2 = w0 + leftDir * cornerDepthLeft;
            w3 = w1 + rightDir * cornerDepthRight;
            w4 = w2 + leftDir * cornerTopDepthLeft + Vector3.up * roofHeight;
            w5 = w3 + rightDir * cornerTopDepthRight + Vector3.up * roofHeight;

            Vector3[] verts = new Vector3[6] { w0, w1, w2, w3, w4, w5 };
//            List<Vector2> uvs = new List<Vector2>();

            Vector2[] uvsFloor = BuildrProjectUVs.Project(new Vector3[4] { w0, w1, w2, w3 }, Vector2.zero, facadeNormal);
            if(baseDepth == 0)
                uvsFloor[3].x = facadeWidth;
            Vector2[] uvsMansard = BuildrProjectUVs.Project(new Vector3[3] { w2, w4, w5 }, uvsFloor[2], facadeNormal);

            Vector3[] vertsA = new Vector3[4] { verts[0], verts[1], verts[2], verts[3] };
            Vector2[] uvsA = new Vector2[4] { uvsFloor[0], uvsFloor[1], uvsFloor[2], uvsFloor[3] };
            int[] trisA = new int[6] { 1, 0, 2, 1, 2, 3 };
            int subMeshA = design.GetTexture(BuildrRoofDesign.textureNames.floor);
            mesh.AddData(vertsA, uvsA, trisA, subMeshA);

            Vector3[] vertsB = new Vector3[4] { verts[2], verts[3], verts[4], verts[5] };
            Vector2[] uvsB = new Vector2[4] { uvsFloor[2], uvsFloor[3], uvsMansard[1], uvsMansard[2] };
            int[] trisB = new int[6] { 0, 2, 1, 1, 2, 3 };
            int subMeshB = design.GetTexture(BuildrRoofDesign.textureNames.tiles);
            mesh.AddData(vertsB, uvsB, trisB, subMeshB);

            //modify point for the top geometry
            Vector2z point = area.points[volume.points[l]];
            topVerts[l] = point.vector3 + volumeFloorHeight + Vector3.up * roofHeight + leftDir * (cornerDepthLeft + cornerTopDepthLeft);
            topUVs[l] = new Vector2(topVerts[l].x / texture.textureUnitSize.x, topVerts[l].z / texture.textureUnitSize.y);
        }

        Vector2z[] topVertV2z = new Vector2z[topVerts.Length];
        for (int i = 0; i < topVerts.Length; i++)
            topVertV2z[i] = new Vector2z(topVerts[i]);
        int[] topTris = EarClipper.Triangulate(topVertV2z);
        AddData(topVerts, topUVs, topTris, topTextureID);//top
    }
Exemple #18
0
 private static bool CCW(Vector2z p1, Vector2z p2, Vector2z p3)
 {
     return((p2.x - p1.x) * (p3.y - p1.y) > (p2.y - p1.y) * (p3.x - p1.x));
 }
 private static bool IntersectsTriangle2(Vector2z A, Vector2z B, Vector2z C, Vector2z P)
 {
     float planeAB = (A.x-P.x)*(B.y-P.y)-(B.x-P.x)*(A.y-P.y);
         float planeBC = (B.x-P.x)*(C.y-P.y)-(C.x - P.x)*(B.y-P.y);
         float planeCA = (C.x-P.x)*(A.y-P.y)-(A.x - P.x)*(C.y-P.y);
         return Sign(planeAB)==Sign(planeBC) && Sign(planeBC)==Sign(planeCA);
 }
 private static float Sign(Vector2z p1, Vector2z p2, Vector2z p3)
 {
     return (p1.x - p3.x) * (p2.z - p3.z) - (p2.x - p3.x) * (p1.z - p3.z);
 }
    public static void SceneGUI(BuildrEditMode editMode, BuildrPlan plan, bool shouldSnap, float handleSize)
    {
        Vector3 position = editMode.transform.position;
        Plane buildingPlane = new Plane(Vector3.up, position);
        float distance;
        Vector3 mousePlanePoint = Vector3.zero;
        Camera sceneCamera = Camera.current;
        Ray ray = sceneCamera.ScreenPointToRay(new Vector3(Event.current.mousePosition.x, Screen.height - Event.current.mousePosition.y - 30, 0));
        if (buildingPlane.Raycast(ray, out distance))
        {
            mousePlanePoint = ray.GetPoint(distance);
        }
        Quaternion mouseLookDirection = Quaternion.LookRotation(-ray.direction);

        //Draw the floorplan outline
        int numberOfVolumes = plan.numberOfVolumes;
        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volumeLinks = plan.volumes[s];
            int volumeSize = volumeLinks.Count;

            for (int l = 0; l < volumeSize; l++)
            {
                Handles.color = Color.white;
                Vector3[] wallPositions = plan.GetWallVectors(s, l);
                Handles.DrawLine(wallPositions[0] + position, wallPositions[1] + position);
            }
        }

        //draw outlines of building cores
        int numberOfCores = plan.cores.Count;
        for(int c = 0; c < numberOfCores; c++)
        {
            Rect coreOutline = plan.cores[c];
            Vector3 coreCenter = new Vector3(coreOutline.center.x,0,coreOutline.center.y);
            Handles.Label(coreCenter + position, "Core " + (c + 1));
            Vector3 coreBL = new Vector3(coreOutline.xMin,0, coreOutline.yMin) + position;
            Vector3 coreBR = new Vector3(coreOutline.xMax,0, coreOutline.yMin) + position;
            Vector3 coreTL = new Vector3(coreOutline.xMin,0, coreOutline.yMax) + position;
            Vector3 coreTR = new Vector3(coreOutline.xMax,0, coreOutline.yMax) + position;
            Handles.DrawLine(coreBL,coreBR);
            Handles.DrawLine(coreBR,coreTR);
            Handles.DrawLine(coreTR,coreTL);
            Handles.DrawLine(coreTL,coreBL);
        }

        //Draw red lines over illegal point/lines
        int numberOfIllegalPoints = plan.numberOfIllegalPoints;
        if (numberOfIllegalPoints > 0)
        {
            Handles.color = Color.red;
            Vector2z[] illegalPoints = plan.illegalPoints;
            for (int i = 0; i < numberOfIllegalPoints - 1; i += 2)
            {
                Vector3 a, b;
                a = illegalPoints[i].vector3 + position;
                b = illegalPoints[i + 1].vector3 + position;
                Handles.DrawLine(a, b);
            }
        }

        SceneView.focusedWindow.wantsMouseMove = false;
        Vector3 vertA;
        Vector3 vertB;
        int selectedPoint;
        switch (editMode.mode)
        {

            case BuildrEditMode.modes.floorplan:
                Vector3 sliderPos = Vector3.zero;
                int numberOfPoints = plan.points.Count;
                int numberOfSelectedPoints = editMode.selectedPoints.Count;

                //Per point scene gui
                for (int i = 0; i < numberOfPoints; i++)
                {
                    Vector2z point = plan.points[i];
                    Vector3 pointPos = point.vector3 + position;
                    float pointHandleSize = HandleUtility.GetHandleSize(pointPos);
                    bool selected = editMode.selectedPoints.Contains(i);
                    if (selected)
                    {
                        Handles.color = Color.green;
                        //Handles.Label(pointPos, "point "+i);
                        sliderPos += point.vector3;
                        if (Handles.Button(pointPos, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap))
                        {
                            editMode.selectedPoints.Remove(i);
                        }

                    }
                    else
                    {
                        Handles.color = Color.white;
                        if (Handles.Button(pointPos, Quaternion.identity, pointHandleSize * 0.05f, pointHandleSize * 0.05f, Handles.DotCap))
                        {
                            if (!shouldSnap)
                                editMode.selectedPoints.Clear();
                            editMode.selectedPoints.Add(i);
                        }
                    }

                    float pointDot = Vector3.Dot(sceneCamera.transform.forward, pointPos - sceneCamera.transform.position);
                    if(pointDot > 0.0f)
                    {
                        Handles.color = Color.white;
                        GUIStyle pointLabelStyle = new GUIStyle();
                        pointLabelStyle.normal.textColor = Color.white;
                        pointLabelStyle.fontStyle = FontStyle.Bold;
                        pointLabelStyle.alignment = TextAnchor.MiddleCenter;
                        pointLabelStyle.fixedWidth = 50.0f;
                        Handles.Label(pointPos + Vector3.up * 2, "point " + i, pointLabelStyle);
                    }
                }

                //draw plan dimensions
                if (editMode.showDimensionLines)
                {
                    Handles.color = Color.white;
                    for (int v = 0; v < numberOfVolumes; v++)
                    {
                        BuildrVolume volume = plan.volumes[v];
                        int volumeSize = volume.Count;
                        for (int l = 0; l < volumeSize; l++)
                        {
                            if (plan.GetConnectingVolumeIndex(v, volume.points[l], volume.points[(l + 1) % volumeSize]) != -1)
                                continue;
                            vertA = plan.points[volume.points[l]].vector3 + position;
                            vertB = plan.points[volume.points[(l + 1) % volumeSize]].vector3 + position;
                            float wallWidth = Vector3.Distance(vertA, vertB);
                            Vector3 facadeDirection = Vector3.Cross((vertA - vertB), Vector3.up).normalized;
                            Vector3 labelPos = (vertA + vertB) * 0.5f + facadeDirection;
                            GUIStyle widthStyle = new GUIStyle();
                            widthStyle.normal.textColor = Color.white;
                            widthStyle.alignment = TextAnchor.MiddleCenter;
                            widthStyle.fixedWidth = 50.0f;
                            Handles.Label(labelPos, wallWidth.ToString("F2") + "m", widthStyle);
                            if (wallWidth > 3)//draw guidelines
                            {
                                float gapSpace = (HandleUtility.GetHandleSize(labelPos) * 0.5f) / wallWidth;
                                Vector3 lineStopA = Vector3.Lerp(vertA, vertB, (0.5f - gapSpace)) + facadeDirection;
                                Vector3 lineStopB = Vector3.Lerp(vertA, vertB, (0.5f + gapSpace)) + facadeDirection;
                                Handles.DrawLine(vertA + facadeDirection, lineStopA);
                                Handles.DrawLine(vertA + facadeDirection, vertA);
                                Handles.DrawLine(vertB + facadeDirection, lineStopB);
                                Handles.DrawLine(vertB + facadeDirection, vertB);
                            }
                        }
                    }
                }

                //selected point scene gui
                if (numberOfSelectedPoints > 0)
                {
        //                    Undo.SetSnapshotTarget(plan, "Floorplan Node Moved");
                    sliderPos /= numberOfSelectedPoints;
                    Vector3 dirX = (sliderPos.x < 0) ? Vector3.right : Vector3.left;
                    Vector3 dirZ = (sliderPos.z < 0) ? Vector3.forward : Vector3.back;
                    sliderPos += position;
                    Vector3 newSliderPos;
                    Handles.color = Color.red;
                    newSliderPos = Handles.Slider(sliderPos, dirX, HandleUtility.GetHandleSize(sliderPos) * 0.666f, Handles.ArrowCap, 0.0f);
                    Handles.color = Color.blue;
                    newSliderPos = Handles.Slider(newSliderPos, dirZ, HandleUtility.GetHandleSize(newSliderPos) * 0.666f, Handles.ArrowCap, 0.0f);

                    Vector3 sliderDiff = newSliderPos - sliderPos;

                    for (int i = 0; i < numberOfPoints; i++)
                    {
                        if (editMode.selectedPoints.Contains(i))
                        {
                            if(sliderDiff != Vector3.zero)
                            {
                                Vector2z point = plan.points[i];
                                point.vector3 += sliderDiff;

                                if(editMode.snapFloorplanToGrid)
                                {
                                    Vector3 snappedPoint = point.vector3;
                                    snappedPoint.x -= snappedPoint.x % editMode.floorplanGridSize;
                                    snappedPoint.z -= snappedPoint.z % editMode.floorplanGridSize;
                                    point.vector3 = snappedPoint;
                                }
                            }
                        }
                    }
                }

                //core gui
                for(int c = 0; c < numberOfCores; c++)
                {
        //                    Undo.SetSnapshotTarget(plan, "Core Node Moved");
                    Rect coreOutline = plan.cores[c];

                    Vector3 coreLeft = new Vector3(coreOutline.xMin, 0, (coreOutline.yMin + coreOutline.yMax)/2);
                    Vector3 coreRight = new Vector3(coreOutline.xMax, 0, (coreOutline.yMin + coreOutline.yMax)/2);
                    Vector3 coreBottom = new Vector3((coreOutline.xMin + coreOutline.xMax) / 2, 0, coreOutline.yMin);
                    Vector3 coreTop = new Vector3((coreOutline.xMin + coreOutline.xMax) / 2, 0, coreOutline.yMax);

                    Vector3 newCoreLeft = Handles.Slider(coreLeft + position, Vector3.left, HandleUtility.GetHandleSize(coreLeft) * 0.666f, Handles.ArrowCap, 0.0f);
                    Vector3 newCoreRight = Handles.Slider(coreRight + position, Vector3.right, HandleUtility.GetHandleSize(coreLeft) * 0.666f, Handles.ArrowCap, 0.0f);
                    Vector3 newCoreBottom = Handles.Slider(coreBottom + position, Vector3.back, HandleUtility.GetHandleSize(coreLeft) * 0.666f, Handles.ArrowCap, 0.0f);
                    Vector3 newCoreTop = Handles.Slider(coreTop + position, Vector3.forward, HandleUtility.GetHandleSize(coreLeft) * 0.666f, Handles.ArrowCap, 0.0f);

                    newCoreLeft -= position;
                    newCoreRight -= position;
                    newCoreBottom -= position;
                    newCoreTop -= position;

                    if (coreLeft != newCoreLeft)
                        coreOutline.xMin = Mathf.Min(newCoreLeft.x, coreOutline.xMax - 1.0f);
                    if (coreRight != newCoreRight)
                        coreOutline.xMax = Mathf.Max(newCoreRight.x, coreOutline.xMin + 1.0f);
                    if (coreBottom != newCoreBottom)
                        coreOutline.yMin = Mathf.Min(newCoreBottom.z, coreOutline.yMax - 1.0f);
                    if (coreTop != newCoreTop)
                        coreOutline.yMax = Mathf.Max(newCoreTop.z, coreOutline.yMin + 1.0f);

                    plan.cores[c] = coreOutline;
                }

                break;

            case BuildrEditMode.modes.addNewVolume:
                Vector3 basePoint = mousePlanePoint;
                Vector3 width = Vector3.right * 10;
                Vector3 height = Vector3.forward * 10;
                Vector3[] verts = new Vector3[4] { basePoint - width - height, basePoint + width - height, basePoint + width + height, basePoint + height - width };

                Handles.DrawSolidRectangleWithOutline(verts, new Color(0.2f, 0.4f, 0.9f, 0.5f), new Color(0.1f, 0.2f, 1.0f, 0.85f));
                Handles.Label(mousePlanePoint, "Click to place a new volume");
                if (Handles.Button(basePoint, Quaternion.identity, 0, 10, Handles.CircleCap))
                {
        //                    Undo.RegisterUndo(plan.GetUndoObjects(), "Add new volume");
                    plan.AddVolume(verts, -position);
                    editMode.SetMode(BuildrEditMode.modes.floorplan);
                    EditorUtility.SetDirty(plan);
                }

                break;

            case BuildrEditMode.modes.addNewVolumeByDraw:

                if (editMode.startVolumeDraw == Vector3.zero)
                {
                    Handles.Label(mousePlanePoint, "Click to select the start point of this volume");
                    if (Handles.Button(mousePlanePoint, Quaternion.identity, handleSize * 0.1f, handleSize * 0.1f, Handles.CircleCap))
                    {
                        editMode.startVolumeDraw = mousePlanePoint;
                    }
                }
                else
                {
                    Vector3 baseDrawPoint = editMode.startVolumeDraw;
                    Vector3 finishDrawPoint = mousePlanePoint;
                    Vector3[] drawVerts = new Vector3[4];
                    drawVerts[0] = new Vector3(baseDrawPoint.x, 0, baseDrawPoint.z);
                    drawVerts[1] = new Vector3(finishDrawPoint.x, 0, baseDrawPoint.z);
                    drawVerts[2] = new Vector3(finishDrawPoint.x, 0, finishDrawPoint.z);
                    drawVerts[3] = new Vector3(baseDrawPoint.x, 0, finishDrawPoint.z);

                    Handles.DrawSolidRectangleWithOutline(drawVerts, new Color(0.2f, 0.4f, 0.9f, 0.5f), new Color(0.1f, 0.2f, 1.0f, 0.85f));
                    Handles.Label(mousePlanePoint, "Click to finish and add a new volume");
                    if (Handles.Button(mousePlanePoint, Quaternion.identity, 0, 10, Handles.CircleCap))
                    {
        //                        Undo.RegisterUndo(plan.GetUndoObjects(), "Add new volume");
                        plan.AddVolume(drawVerts, -position);
                        editMode.SetMode(BuildrEditMode.modes.floorplan);
                        EditorUtility.SetDirty(plan);
                    }
                }
                break;

            case BuildrEditMode.modes.addNewVolumeByPoints:

                int numberOfDrawnPoints = editMode.volumeDrawPoints.Count;
                bool allowNewPoint = true;
                for (int p = 0; p < numberOfDrawnPoints; p++)
                {
                    Vector3 point = editMode.volumeDrawPoints[p];
                    if (p == 0 && Vector3.Distance(point, mousePlanePoint) < 3 && numberOfDrawnPoints >= 3)
                    {
                        allowNewPoint = false;//hovering over the first point - don't add a new point - ready to complete the volume plan
                        Handles.color = Color.green;
                    }
                    Vector3 lookDirection = -(point - Camera.current.transform.position);

                    int p2 = (p + 1) % numberOfDrawnPoints;
                    if (p < numberOfDrawnPoints - 1 || !allowNewPoint)//don't draw last line
                        Handles.DrawLine(point, editMode.volumeDrawPoints[p2]);
                    float pointhandleSize = HandleUtility.GetHandleSize(point);
                    if (Handles.Button(point, Quaternion.LookRotation(lookDirection), pointhandleSize * 0.1f, pointhandleSize * 0.1f, Handles.DotCap))
                    {
                        if (p == 0 && numberOfDrawnPoints >= 3)
                        {
                            plan.AddVolume(editMode.volumeDrawPoints.ToArray(), -position);
                            editMode.SetMode(BuildrEditMode.modes.floorplan);
                            EditorUtility.SetDirty(plan);
                            GUI.changed = true;
                            return;
                        }
                    }
                }

                if (allowNewPoint)
                {

                    bool isLegal = true;
                    if (numberOfDrawnPoints >= 1)
                    {
                        Vector2z newPoint = new Vector2z(mousePlanePoint);
                        Vector2z lastPoint = new Vector2z(editMode.volumeDrawPoints[numberOfDrawnPoints - 1]);
                        for (int op = 0; op < numberOfDrawnPoints - 1; op++)//don't do the final line
                        {
                            int op2 = (op + 1) % numberOfDrawnPoints;

                            if (BuildrUtils.FastLineIntersection(newPoint, lastPoint, new Vector2z(editMode.volumeDrawPoints[op]), new Vector2z(editMode.volumeDrawPoints[op2])))
                                isLegal = false;
                        }
                        for (int v = 0; v < numberOfVolumes; v++)
                        {
                            BuildrVolume volume = plan.volumes[v];
                            int volumeSize = volume.Count;
                            for (int l = 0; l < volumeSize; l++)
                            {
                                int vp1 = l;
                                int vp2 = (l + 1) % volumeSize;

                                Vector2z v2zPos = new Vector2z(position);
                                Vector2z p1 = newPoint - v2zPos;
                                Vector2z p2 = lastPoint - v2zPos;
                                Vector2z p3 = plan.points[volume.points[vp1]];
                                Vector2z p4 = plan.points[volume.points[vp2]];

                                if (BuildrUtils.FastLineIntersection(p1, p2, p3, p4))
                                    isLegal = false;
                            }
                        }

                        Handles.Label(mousePlanePoint, "Click to add another point to the volume wall");

                        if (!isLegal)
                            Handles.color = Color.red;

                        Handles.DrawLine(lastPoint.vector3, newPoint.vector3);
                    }
                    else
                    {
                        Handles.Label(mousePlanePoint, "Click to add the first point in this volume wall");
                    }

                    Handles.color = Color.white;
                    if (Handles.Button(mousePlanePoint, mouseLookDirection, 0, 10, Handles.CircleCap))
                    {
                        if (isLegal)
                        {
        //                            Undo.RegisterUndo(plan.GetUndoObjects(), "Add new wall line for new volume");
                            editMode.volumeDrawPoints.Add(mousePlanePoint);
                            EditorUtility.SetDirty(plan);
                        }
                        else
                        {
                            EditorUtility.DisplayDialog("Error", "Wall lines cannot intersect other wall lines", "ok, sorry");
                        }
                    }
                }
                else
                {
                    Handles.Label(mousePlanePoint, "Click to complete the volume wall plan");
                }

                break;

            case BuildrEditMode.modes.removeVolume:

                for (int v = 0; v < numberOfVolumes; v++)
                {
                    BuildrVolume volume = plan.volumes[v];
                    int volumeSize = volume.Count;
                    Vector3 centerPoint = Vector3.zero;
                    for (int l = 0; l < volumeSize; l++)
                    {
                        centerPoint += plan.points[volume.points[l]].vector3;
                    }
                    centerPoint /= volumeSize;
                    centerPoint += position;

                    Handles.color = Color.red;
                    float centerPointHandleSize = HandleUtility.GetHandleSize(centerPoint);
                    if (Handles.Button(centerPoint, Quaternion.identity, centerPointHandleSize * 0.1f, centerPointHandleSize * 0.1f, Handles.DotCap))
                    {
        //                        Undo.RegisterUndo(plan.GetUndoObjects(), "Remove volume");
        //                        Undo.RegisterSceneUndo("Remove Volume");
                        plan.RemoveVolume(volume);
                        numberOfVolumes--;
                        v--;
                        editMode.SetMode(BuildrEditMode.modes.floorplan);
                        EditorUtility.SetDirty(plan);
                    }
                }

                break;

            case BuildrEditMode.modes.mergeVolumes:

                List<int> usedPointsA = new List<int>();
                List<int> usedPointsB = new List<int>();
                for (int v = 0; v < numberOfVolumes; v++)
                {
                    BuildrVolume volume = plan.volumes[v];
                    int volumeSize = volume.Count;
                    for (int p = 0; p < volumeSize; p++)
                    {
                        int a = volume.points[p];
                        int b = volume.points[(p + 1) % volumeSize];

                        bool alreadyDrawn = false;
                        foreach (int pa in usedPointsA)
                        {
                            if (pa == a || pa == b)
                            {
                                int pb = usedPointsB[usedPointsA.IndexOf(pa)];
                                if (pb == a || pb == b)
                                {
                                    alreadyDrawn = true;
                                    break;
                                }
                            }
                        }

                        if (!alreadyDrawn)
                        {

                            usedPointsA.Add(a);
                            usedPointsA.Add(b);
                            usedPointsB.Add(b);
                            usedPointsB.Add(a);

                            int otherV = plan.GetConnectingVolumeIndex(v, a, b);
                            if (otherV == -1)
                                continue;//it's not connected to another volume

                            vertA = plan.points[a].vector3 + position;
                            vertB = plan.points[b].vector3 + position;
                            Vector3 diff = vertA - vertB;
                            Vector3 facadeDirection = Vector3.Cross(diff, Vector3.up).normalized;
                            Vector3 midPoint = Vector3.Lerp(vertA, vertB, 0.5f);

                            float mergeHandleSize = HandleUtility.GetHandleSize(midPoint) * 0.1f;
                            Vector3 outPointA = midPoint + (facadeDirection * mergeHandleSize * 6);
                            Vector3 outPointB = midPoint - (facadeDirection * mergeHandleSize * 6);
                            Handles.ArrowCap(0, outPointA, Quaternion.LookRotation(-facadeDirection), mergeHandleSize * 4);
                            Handles.ArrowCap(0, outPointB, Quaternion.LookRotation(facadeDirection), mergeHandleSize * 4);

                            GUIStyle pointLabelStyle = new GUIStyle();
                            pointLabelStyle.normal.textColor = Color.white;
                            pointLabelStyle.fontStyle = FontStyle.Bold;
                            pointLabelStyle.alignment = TextAnchor.MiddleCenter;
                            pointLabelStyle.fixedWidth = 50.0f;
                            Handles.Label(midPoint + Vector3.up * mergeHandleSize * 3, "Merge", pointLabelStyle);

                            if (Handles.Button(midPoint, Quaternion.identity, mergeHandleSize, mergeHandleSize, Handles.DotCap))
                            {
        //                                Undo.RegisterSceneUndo("Merge Volume");
                                int otherVolume = plan.GetConnectingVolumeIndex(v, a, b);
                                plan.MergeVolumes(v, otherVolume);
                                numberOfVolumes--;
                                editMode.SetMode(BuildrEditMode.modes.floorplan);
                                EditorUtility.SetDirty(plan);
                            }
                        }
                    }
                }

                break;

            //SUB VOLUME FUNCTIONS

            case BuildrEditMode.modes.splitwall:

                SceneView.focusedWindow.wantsMouseMove = true;
                float pointDistance = 999;
                int wallIndex = -1;
                int volumeIndex = -1;
                Vector3 closestPoint = Vector3.zero;
                Vector3 usePoint = Vector3.zero;
                vertA = Vector3.zero;
                vertB = Vector3.zero;

                for (int s = 0; s < numberOfVolumes; s++)
                {
                    BuildrVolume volumeLinks = plan.volumes[s];
                    int volumeSize = volumeLinks.Count;

                    for (int l = 0; l < volumeSize; l++)
                    {
                        Vector3[] wallVectors = plan.GetWallVectors(s, l);
                        closestPoint = BuildrUtils.ClosestPointOnLine(wallVectors[0] + position, wallVectors[1] + position, mousePlanePoint);
                        float thisDist = Vector3.Distance(closestPoint, mousePlanePoint);
                        if (thisDist < pointDistance)
                        {
                            wallIndex = l;
                            volumeIndex = s;
                            vertA = wallVectors[0];
                            vertB = wallVectors[1];
                            usePoint = closestPoint;
                            pointDistance = thisDist;
                            editMode.selectedPoints.Clear();
                        }

                        Handles.color = Color.white;
                        float wallHandleSize = HandleUtility.GetHandleSize(wallVectors[0] + position);
                        Handles.DotCap(0, wallVectors[0] + position, Quaternion.identity, wallHandleSize * 0.05f);
                    }
                }

                if (wallIndex != -1 && pointDistance < 5 && volumeIndex != -1)
                {
                    float pointHandleSize = HandleUtility.GetHandleSize(usePoint);
                    if (Handles.Button(usePoint, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap))
                    {
        //                        Undo.RegisterUndo(plan.GetUndoObjects(), "Split Wall");
                        int newPointID = plan.AddWallPoint(usePoint - position, wallIndex, volumeIndex);
                        editMode.selectedPoints.Clear();
                        editMode.selectedPoints.Add(newPointID);
                        editMode.SetMode(BuildrEditMode.modes.floorplan);
                        EditorUtility.SetDirty(plan);
                    }

                    Handles.color = Color.white;
                    GUIStyle widthStyle = new GUIStyle();
                    widthStyle.normal.textColor = Color.white;
                    widthStyle.alignment = TextAnchor.MiddleCenter;
                    widthStyle.fixedWidth = 50.0f;
                    Vector3 facadeDirection = Vector3.Cross((vertA - vertB), Vector3.up).normalized;

                    float wallWidthA = Vector3.Distance(vertA, usePoint);
                    Vector3 labelPosA = (vertA + usePoint) * 0.5f + facadeDirection;
                    Handles.Label(labelPosA, wallWidthA.ToString("F2") + "m", widthStyle);
                    if (wallWidthA > 3)//draw guidelines
                    {
                        float gapSpace = (pointHandleSize * 0.5f) / wallWidthA;
                        Vector3 lineStopA = Vector3.Lerp(vertA, usePoint, (0.5f - gapSpace)) + facadeDirection;
                        Vector3 lineStopB = Vector3.Lerp(vertA, usePoint, (0.5f + gapSpace)) + facadeDirection;
                        Handles.DrawLine(vertA + facadeDirection, lineStopA);
                        Handles.DrawLine(vertA + facadeDirection, vertA);
                        Handles.DrawLine(usePoint + facadeDirection, lineStopB);
                        Handles.DrawLine(usePoint + facadeDirection, usePoint);
                    }

                    float wallWidthB = Vector3.Distance(usePoint, vertB);
                    Vector3 labelPosB = (usePoint + vertB) * 0.5f + facadeDirection;
                    Handles.Label(labelPosB, wallWidthB.ToString("F2") + "m", widthStyle);
                    if (wallWidthB > 3)//draw guidelines
                    {
                        float gapSpace = (pointHandleSize * 0.5f) / wallWidthB;
                        Vector3 lineStopA = Vector3.Lerp(vertB, usePoint, (0.5f - gapSpace)) + facadeDirection;
                        Vector3 lineStopB = Vector3.Lerp(vertB, usePoint, (0.5f + gapSpace)) + facadeDirection;
                        Handles.DrawLine(vertB + facadeDirection, lineStopA);
                        Handles.DrawLine(vertB + facadeDirection, vertB);
                        Handles.DrawLine(usePoint + facadeDirection, lineStopB);
                        Handles.DrawLine(usePoint + facadeDirection, usePoint);
                    }
                }
                Handles.color = Color.white;
                break;

            case BuildrEditMode.modes.removewall:

                int index = 0;
                foreach (Vector2z point in plan.points)
                {
                    Handles.color = Color.white;
                    Vector3 pointPos = point.vector3 + position;
                    float pointHandleSize = HandleUtility.GetHandleSize(pointPos);
                    if (Handles.Button(pointPos, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap))
                    {
        //                        Undo.RegisterSceneUndo("Delete Wall Point");
                        plan.RemovePoint(index);
                        editMode.SetMode(BuildrEditMode.modes.floorplan);
                        break;
                    }

                    index++;
                }

                break;

            case BuildrEditMode.modes.extrudewallselect:

                Handles.color = Color.blue;
                for (int s = 0; s < numberOfVolumes; s++)
                {
                    BuildrVolume volume = plan.volumes[s];
                    int volumeSize = volume.Count;

                    for (int l = 0; l < volumeSize; l++)
                    {
                        int a = volume.points[l];
                        int b = (l < volume.points.Count - 1) ? volume.points[l + 1] : volume.points[0];
                        if (plan.GetConnectingVolumeIndex(s, a, b) == -1)//if the volume wall has not been connected to two volumes yet...
                        {
                            Vector3[] pIndexes = plan.GetWallVectors(s, l);
                            Vector3 pA = pIndexes[0];
                            Vector3 pB = pIndexes[1];
                            Vector3 pC = (pA + pB) / 2 + position;
                            float pointHandleSize = HandleUtility.GetHandleSize(pC);

                            if (Handles.Button(pC, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap))
                            {
        //                                Undo.RegisterSceneUndo("Extrude wall");
                                int wallIndexA = l;
                                int newPointAIndex = plan.AddWallPoint(pA, wallIndexA, s);
                                int wallIndexB = l + 1;

                                int newPointBIndex = plan.AddWallPoint(pB, wallIndexB, s);

                                editMode.SetMode(BuildrEditMode.modes.floorplan);

                                editMode.selectedPoints.Clear();
                                editMode.selectedPoints.Add(newPointAIndex);
                                editMode.selectedPoints.Add(newPointBIndex);
                                break;
                            }
                        }
                    }
                }

                Handles.color = Color.white;

                break;

            case BuildrEditMode.modes.addVolumeByPoint:

                Handles.color = Color.blue;
                for (int s = 0; s < numberOfVolumes; s++)
                {
                    BuildrVolume volume = plan.volumes[s];
                    int volumeSize = volume.Count;

                    for (int l = 0; l < volumeSize; l++)
                    {
                        int a = volume.points[l];
                        int b = (l < volume.points.Count - 1) ? volume.points[l + 1] : volume.points[0];
                        if (plan.GetConnectingVolumeIndex(s, a, b) == -1)//if the volume wall has not been connected to two volumes yet...
                        {
                            Vector3[] pointVectors = plan.GetWallVectors(s, l);
                            Vector3 pA = pointVectors[0];
                            Vector3 pB = pointVectors[1];
                            Vector3 pC = (pA + pB) / 2 + position;
                            float pointHandleSize = HandleUtility.GetHandleSize(pC);
                            if (Handles.Button(pC, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap))
                            {
                                Vector2z[] newPoints = new Vector2z[1];
                                float pointDist = Vector3.Distance(pA, pB);
                                Vector3 newPointPos = Vector3.Cross(pA - pB, Vector3.up).normalized * pointDist;
                                newPoints[0] = new Vector2z(pC + newPointPos);
                                int indexa, indexb;
                                indexa = volume.points[l];
                                if (l < volumeSize - 1)
                                    indexb = volume.points[l + 1];
                                else
                                    indexb = volume.points[0];
                                plan.AddVolume(indexa, indexb, newPoints);

                                editMode.SetMode(BuildrEditMode.modes.floorplan);
                                break;
                            }
                        }
                    }
                }
                Handles.color = Color.white;
                break;

            case BuildrEditMode.modes.addVolumeByWall:

                Handles.color = Color.blue;
                for (int s = 0; s < numberOfVolumes; s++)
                {
                    BuildrVolume volume = plan.volumes[s];
                    int volumeSize = volume.Count;

                    for (int l = 0; l < volumeSize; l++)
                    {
                        int a = volume.points[l];
                        int b = (l < volume.points.Count - 1) ? volume.points[l + 1] : volume.points[0];
                        if (plan.GetConnectingVolumeIndex(s, a, b) == -1)
                        {
                            Vector3[] pIndexes = plan.GetWallVectors(s, l);
                            Vector3 pA = pIndexes[0];
                            Vector3 pB = pIndexes[1];
                            Vector3 pC = (pA + pB) / 2 + position;
                            float pointHandleSize = HandleUtility.GetHandleSize(pC);
                            if (Handles.Button(pC, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap))
                            {
        //                                Undo.RegisterSceneUndo("Add volume by wall");
                                Vector2z[] newPoints = new Vector2z[2];
                                float pointDist = Vector3.Distance(pA, pB);
                                Vector3 newPointPos = Vector3.Cross(pA - pB, Vector3.up).normalized * pointDist;
                                newPoints[0] = new Vector2z(pA + newPointPos);
                                newPoints[1] = new Vector2z(pB + newPointPos);
                                int indexa, indexb;
                                indexa = volume.points[l];
                                if (l < volumeSize - 1)
                                    indexb = volume.points[l + 1];
                                else
                                    indexb = volume.points[0];
                                plan.AddVolume(indexa, indexb, newPoints);

                                editMode.SetMode(BuildrEditMode.modes.floorplan);
                                break;
                            }
                        }
                    }
                }
                Handles.color = Color.white;
                break;

            case BuildrEditMode.modes.addPointToVolume:

                numberOfPoints = plan.numberOfPoints;
                if (editMode.selectedPoint == -1)
                {
                    for (int p = 0; p < numberOfPoints; p++)
                    {
                        Vector2z point = plan.points[p];
                        Handles.color = Color.white;
                        Vector3 pointPos = point.vector3 + position;
                        float pointhandleSize = HandleUtility.GetHandleSize(pointPos);
                        if (Handles.Button(pointPos, Quaternion.identity, pointhandleSize * 0.1f, pointhandleSize * 0.1f, Handles.DotCap))
                        {
        //                            Undo.RegisterSceneUndo("Select Wall Point");
                            editMode.selectedPoint = p;
                            break;
                        }
                    }
                }
                else
                {

                    selectedPoint = editMode.selectedPoint;
                    Vector2z startPoint = plan.points[selectedPoint];
                    Vector2z endPoint = new Vector2z(mousePlanePoint - position);

                    bool isLegal = true;
                    for (int s = 0; s < numberOfVolumes; s++)
                    {
                        BuildrVolume volume = plan.volumes[s];
                        if (!volume.Contains(selectedPoint))
                            continue;
                        int volumeSize = volume.Count;

                        for (int l = 0; l < volumeSize; l++)
                        {
                            int a = volume.points[l];
                            int b = volume.points[(l + 1) % volumeSize];

                            if (a == selectedPoint || b == selectedPoint)
                                continue;

                            if (BuildrUtils.FastLineIntersection(startPoint, endPoint, plan.points[a], plan.points[b]))
                                isLegal = false;
                        }
                    }

                    Handles.color = isLegal ? Color.white : Color.red;
                    Handles.DrawLine(startPoint.vector3 + position, endPoint.vector3 + position);

                }

                break;

            case BuildrEditMode.modes.splitVolume:

                numberOfPoints = plan.numberOfPoints;
                selectedPoint = editMode.selectedPoint;
                if (selectedPoint == -1)
                {
                    for (int p = 0; p < numberOfPoints; p++)
                    {
                        Vector2z point = plan.points[p];
                        Handles.color = Color.white;
                        Vector3 pointPos = point.vector3 + position;
                        float pointhandleSize = HandleUtility.GetHandleSize(pointPos);

                        if (Handles.Button(pointPos, Quaternion.identity, pointhandleSize * 0.1f, pointhandleSize * 0.1f, Handles.DotCap))
                        {
        //                            Undo.RegisterSceneUndo("Select Wall Point");
                            editMode.selectedPoint = p;
                            break;
                        }
                    }
                }
                else
                {

                    for (int s = 0; s < numberOfVolumes; s++)
                    {
                        BuildrVolume volume = plan.volumes[s];
                        if (!volume.Contains(selectedPoint))
                            continue;
                        int volumeSize = volume.Count;

                        for (int l = 0; l < volumeSize; l++)
                        {

                            int o = volume.points[l];
                            int a = selectedPoint;
                            int selectedVolumePoint = volume.IndexOf(selectedPoint);
                            int b = volume.points[(selectedVolumePoint + 1) % volumeSize];
                            int volb = (selectedVolumePoint - 1) % volumeSize;
                            if (volb == -1) volb = volumeSize - 1;
                            int c = volume.points[volb];

                            if (o == a || o == b || o == c)
                                continue;

                            Vector3 pointPos = plan.points[o].vector3 + position;

                            bool isLegal = true;
                            for (int j = 0; j < volumeSize; j++)
                            {
                                int ob = volume.points[j];
                                int oc = volume.points[(j + 1) % volumeSize];
                                if (ob == selectedPoint || oc == selectedPoint || ob == o || oc == o)
                                    continue;
                                if (BuildrUtils.FastLineIntersection(plan.points[selectedPoint], plan.points[o], plan.points[ob], plan.points[oc]))
                                    isLegal = false;
                            }

                            Vector2z pA = plan.points[a];
                            Vector2z pB = plan.points[b];
                            Vector2z pC = plan.points[c];
                            Vector2z pO = plan.points[o];

                            float startAng, endAng, mouseAng, ang;
                            Vector3 cross;
                            Vector2z diff;

                            diff = pC - pA;
                            ang = Vector2.Angle(Vector2.up, diff.vector2);
                            cross = Vector3.Cross(Vector3.forward, diff.vector3);
                            startAng = (cross.y > 0) ? ang : 360 - ang;

                            diff = pB - pA;
                            ang = Vector2.Angle(Vector2.up, diff.vector2);
                            cross = Vector3.Cross(Vector3.forward, diff.vector3);
                            endAng = (cross.y > 0) ? ang : 360 - ang;

                            diff = pO - pA;
                            ang = Vector2.Angle(Vector2.up, diff.vector2);
                            cross = Vector3.Cross(Vector3.forward, diff.vector3);
                            mouseAng = (cross.y > 0) ? ang : 360 - ang;

                            mouseAng = (360 + (mouseAng % 360)) % 360;
                            startAng = (3600000 + startAng) % 360;
                            endAng = (3600000 + endAng) % 360;

                            bool isBetween = false;
                            if (startAng < endAng)
                                isBetween = startAng <= mouseAng && mouseAng <= endAng;
                            else
                                isBetween = startAng <= mouseAng || mouseAng <= endAng;

                            if (isLegal && !isBetween)
                                isLegal = false;

                            if (isLegal)
                            {
                                Handles.color = Color.white;
                                float pointhandleSize = HandleUtility.GetHandleSize(pointPos);
                                if (Handles.Button(pointPos, Quaternion.identity, pointhandleSize * 0.1f, pointhandleSize * 0.1f, Handles.DotCap))
                                {
        //                                    Undo.RegisterSceneUndo("Split Volume");
                                    plan.SplitVolume(s, a, o);
                                    editMode.selectedPoint = -1;
                                    editMode.SetMode(BuildrEditMode.modes.floorplan);
                                    return;
                                }
                                Handles.color = new Color(1, 0, 0, 0.25f);
                                Handles.DrawLine(plan.points[selectedPoint].vector3 + position, plan.points[o].vector3 + position);
                            }
                        }
                    }
                }

                break;

                case BuildrEditMode.modes.addNewCore:

                SceneView.focusedWindow.wantsMouseMove = true;
                Vector3 coreBasePoint = mousePlanePoint;
                Vector3 coreWidth = Vector3.right * 2.5f;
                Vector3 coreHeight = Vector3.forward * 2.5f;
                Vector3[] coreVerts = new Vector3[4] { coreBasePoint - coreWidth - coreHeight, coreBasePoint + coreWidth - coreHeight, coreBasePoint + coreWidth + coreHeight, coreBasePoint + coreHeight - coreWidth };

                Color newCoreColour = BuildrColours.RED;
                newCoreColour.a = 0.5f;
                Handles.DrawSolidRectangleWithOutline(coreVerts, newCoreColour, BuildrColours.YELLOW);
                Handles.Label(mousePlanePoint, "Click to place a new core");
                if (Handles.Button(coreBasePoint, Quaternion.identity, 0, 10, Handles.CircleCap))
                {
        //                    Undo.RegisterSceneUndo("Add new core");
                    Vector3 coreBase = coreBasePoint - position;
                    Rect newCoreRect = new Rect(coreBase.x - 2.5f, coreBase.z - 2.5f, 5.0f, 5.0f);
                    plan.cores.Add(newCoreRect);
                    editMode.SetMode(BuildrEditMode.modes.floorplan);
                    EditorUtility.SetDirty(plan);
                }

                break;

                case BuildrEditMode.modes.removeCore:

                for (int c = 0; c < numberOfCores; c++)
                {
                    Rect core = plan.cores[c];
                    Vector3 centerPoint = new Vector3(core.center.x, 0, core.center.y) + position;

                    Handles.color = Color.red;
                    float centerPointHandleSize = HandleUtility.GetHandleSize(centerPoint);
                    if (Handles.Button(centerPoint, Quaternion.identity, centerPointHandleSize * 0.1f, centerPointHandleSize * 0.1f, Handles.DotCap))
                    {
        //                        Undo.RegisterSceneUndo("Remove Core");
                        plan.cores.RemoveAt(c);
                        numberOfCores--;
                        c--;
                        editMode.SetMode(BuildrEditMode.modes.floorplan);
                        EditorUtility.SetDirty(plan);
                    }
                }

                break;
        }

        bool clickedOutside = false;
        if (Event.current.isMouse)
        {
            RaycastHit hitInfo;
            clickedOutside = true;
            if (Physics.Raycast(ray, out hitInfo))
            {
                if (hitInfo.collider.gameObject == editMode.gameObject)
                    clickedOutside = false;
            }
        }

        if (clickedOutside)
            editMode.selectedPoints.Clear();

        if (GUI.changed)
        {
            plan.CheckPlan();
            EditorUtility.SetDirty(editMode);
            EditorUtility.SetDirty(plan);
            editMode.UpdateRender();
        }
    }
    private static bool IntersectsTriangle(Vector2z A, Vector2z B, Vector2z C, Vector2z P)
    {
        bool b1, b2, b3;

        b1 = Sign(P, A, B) < 0.0f;
        b2 = Sign(P, B, C) < 0.0f;
        b3 = Sign(P, C, A) < 0.0f;

        return ((b1 == b2) && (b2 == b3));
    }
Exemple #23
0
    public bool CheckPlan()
    {
        List <Vector2z> lines       = new List <Vector2z>();//this will be a list of lines in sets of two vector points
        int             volumeCount = numberOfVolumes;

        for (int s = 0; s < volumeCount; s++)
        {
            int volumeLinkCount = volumes[s].Count;
            for (int l = 0; l < volumeLinkCount; l++)
            {
                int indexB = (l < volumeLinkCount - 1) ? l + 1 : 0;
                lines.Add(points[volumes[s].points[l]]);
                lines.Add(points[volumes[s].points[indexB]]);
            }
            int numberOfCores = cores.Count;
            for (int coreIndex = 0; coreIndex < numberOfCores; coreIndex++)
            {
                Rect     coreOutline = cores[coreIndex];
                Vector2z coreBL      = new Vector2z(coreOutline.xMin, coreOutline.yMin);
                Vector2z coreBR      = new Vector2z(coreOutline.xMax, coreOutline.yMin);
                Vector2z coreTL      = new Vector2z(coreOutline.xMin, coreOutline.yMax);
                Vector2z coreTR      = new Vector2z(coreOutline.xMax, coreOutline.yMax);
                lines.Add(coreBL);
                lines.Add(coreBR);
                lines.Add(coreBR);
                lines.Add(coreTR);
                lines.Add(coreTR);
                lines.Add(coreTL);
                lines.Add(coreTL);
                lines.Add(coreBL);
            }
        }
        _illegalPoints.Clear();
        int      numberOfLines = lines.Count;
        Vector2z a, b, c, d;

        while (numberOfLines > 2)
        {
            //get the first line
            a = lines[0];
            b = lines[1];
            for (int i = 2; i < numberOfLines; i += 2)
            {
                c = lines[i];
                d = lines[i + 1];
                if (a == c || a == d || b == c || b == d) //don't test lines that connect
                {
                    continue;
                }
                if (BuildrUtils.FastLineIntersection(a, b, c, d))
                {
                    _illegalPoints.Add(a);
                    _illegalPoints.Add(b);
                    _illegalPoints.Add(c);
                    _illegalPoints.Add(d);
                }
            }

            lines.RemoveRange(0, 2);           //remove the first linked line
            numberOfLines = lines.Count;
        }
        return(_illegalPoints.Count > 0);
    }
 public static float SqrMag(Vector2z a, Vector2z b)
 {
     float x = Mathf.Abs(b.x - a.x);
     float z = Mathf.Abs(b.z - a.z);
     return (x * x + z * z);
 }
 public static float Distance(Vector2z a, Vector2z b)
 {
     return Mathf.Sqrt(SqrMag(a,b));
 }
Exemple #26
0
 private static float Sign(Vector2z p1, Vector2z p2, Vector2z p3)
 {
     return((p1.x - p3.x) * (p2.z - p3.z) - (p2.x - p3.x) * (p1.z - p3.z));
 }
 public EarClipTriangle(Vector2z a, Vector2z b, Vector2z c)
 {
     bounds = new Rect(a.x,a.z,0,0);
     Vector2z[] points = new Vector2z[]{a,b,c};
     for(int i=1; i<3; i++)
     {
         if(bounds.xMin < points[i].x)
             bounds.xMin = points[i].x;
         if(bounds.xMax < points[i].x)
             bounds.xMax = points[i].x;
         if(bounds.yMin < points[i].z)
             bounds.yMin = points[i].z;
         if(bounds.yMax < points[i].z)
             bounds.yMax = points[i].z;
     }
 }
    public static int[] Triangulate( Vector2z[] points)
    {
        int numberOfPoints = points.Length;
        List<int> usePoints = new List<int>();
        for(int p=0; p<numberOfPoints; p++)
            usePoints.Add(p);
        int numberOfUsablePoints = usePoints.Count;
        List<int> indices = new List<int>();

        if (numberOfPoints < 3)
            return indices.ToArray();

        int it = 100;
        while(numberOfUsablePoints > 3)
        {
            for(int i=0; i<numberOfUsablePoints; i++)
            {
                int a,b,c;

                a=usePoints[i];

                if(i>=numberOfUsablePoints-1)
                    b=usePoints[0];
                else
                    b=usePoints[i+1];

                if(i>=numberOfUsablePoints-2)
                    c=usePoints[(i+2)-numberOfUsablePoints];
                else
                    c=usePoints[i+2];

                Vector2 pA = points[b].vector2;
                Vector2 pB = points[a].vector2;
                Vector2 pC = points[c].vector2;

                float dA = Vector2.Distance(pA,pB);
                float dB = Vector2.Distance(pB,pC);
                float dC = Vector2.Distance(pC,pA);

                float angle = Mathf.Acos((Mathf.Pow(dB,2)-Mathf.Pow(dA,2)-Mathf.Pow(dC,2))/(2*dA*dC))*Mathf.Rad2Deg * Mathf.Sign(Sign(points[a],points[b],points[c]));
                if(angle < 0)
                {
                    continue;//angle is not reflex
                }

                bool freeOfIntersections = true;
                for(int p=0; p<numberOfUsablePoints; p++)
                {
                    int pu = usePoints[p];
                    if(pu==a || pu==b || pu==c)
                        continue;

                    if(IntersectsTriangle2(points[a],points[b],points[c],points[pu]))
                    {
                        freeOfIntersections=false;
                        break;
                    }
                }

                if(freeOfIntersections)
                {
                    indices.Add(a);
                    indices.Add(b);
                    indices.Add(c);
                    usePoints.Remove(b);
                    it=100;
                    numberOfUsablePoints = usePoints.Count;
                    i--;
                    break;
                }
            }
            it--;
            if(it<0)
                break;
        }

        indices.Add(usePoints[0]);
        indices.Add(usePoints[1]);
        indices.Add(usePoints[2]);
        indices.Reverse();

        return indices.ToArray();
    }
Exemple #29
0
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data, int volumeIndex)
    {
        data      = _data;
        mesh      = _mesh;
        mesh.name = "Interior Mesh Volume " + volumeIndex;
        textures  = data.textures.ToArray();

        if (!data.renderInteriors)
        {
            return;
        }

        float largestDepthValue = 0;//deepest value of a bay design in the building
        float tallestBay        = 0;

        foreach (BuildrBay bay in data.bays)
        {
            largestDepthValue = Mathf.Max(largestDepthValue, bay.deepestValue);//get the deepest value
            tallestBay        = Mathf.Max(tallestBay, bay.openingHeight + (data.floorHeight - bay.openingHeight) * bay.openingHeightRatio);
        }
        foreach (BuildrFacadeDesign facade in data.facades)
        {
            if (facade.type != BuildrFacadeDesign.types.simple)
            {
                continue;
            }
            largestDepthValue = Mathf.Max(largestDepthValue, facade.simpleBay.deepestValue);//get the deepest value
            if (facade.simpleBay.isOpening)
            {
                tallestBay = Mathf.Max(tallestBay, facade.simpleBay.openingHeight + (data.floorHeight - facade.simpleBay.openingHeight) * facade.simpleBay.openingHeightRatio);
            }
        }


        BuildrFacadeDesign facadeDesign = data.facades[0];
        BuildrPlan         plan         = data.plan;
        BuildrVolume       volume       = plan.volumes[volumeIndex];
        int     numberOfFloors          = volume.numberOfFloors;
        float   floorHeight             = data.floorHeight;
        Vector3 floorHeightVector       = Vector3.up * floorHeight;
        float   ceilingHeight           = tallestBay + (floorHeight - tallestBay) * data.interiorCeilingHeight;

        //Calculate the internal floor plan points
        int numberOfVolumePoints = volume.points.Count;

        Vector2z[] interiorVolumePoints = new Vector2z[numberOfVolumePoints];
        for (int i = 0; i < numberOfVolumePoints; i++)
        {
            Vector3 lastPoint = plan.points[volume.points[(i > 0) ? i - 1 : numberOfVolumePoints - 1]].vector3;
            Vector3 thisPoint = plan.points[volume.points[i]].vector3;
            Vector3 nextPoint = plan.points[volume.points[(i + 1) % numberOfVolumePoints]].vector3;
            Vector3 normalA   = Vector3.Cross(thisPoint - lastPoint, Vector3.up).normalized;
            Vector3 normalB   = Vector3.Cross(nextPoint - thisPoint, Vector3.up).normalized;

            Vector2z facadeALine = new Vector2z(thisPoint - lastPoint);
            Vector2z facadeBLine = new Vector2z(thisPoint - nextPoint);
            //Calculate facade inner origins for floors
            Vector3  facadeOriginV3A        = lastPoint + normalA * largestDepthValue;
            Vector3  facadeOriginV3B        = nextPoint + normalB * largestDepthValue;
            Vector2z facadeOriginA          = new Vector2z(facadeOriginV3A);
            Vector2z facadeOriginB          = new Vector2z(facadeOriginV3B);
            Vector2z facadeLineIntersection = BuildrUtils.FindIntersection(facadeALine, facadeOriginA, facadeBLine, facadeOriginB);

            interiorVolumePoints[i] = facadeLineIntersection;
        }
        List <Vector2z> interiorVolumePointList = new List <Vector2z>(interiorVolumePoints);
        List <Rect>     volumeCores             = new List <Rect>();
        List <int>      linkedPoints            = new List <int>();

        foreach (Rect core in plan.cores)
        {
            Vector2z coreCenter = new Vector2z(core.center);
            if (BuildrUtils.PointInsidePoly(coreCenter, interiorVolumePoints))
            {
                volumeCores.Add(core);
            }
        }
        int  numberOfVolumeCores = volumeCores.Count;
        bool print = plan.volumes.IndexOf(volume) == 3;

        for (int c = 0; c < numberOfVolumeCores; c++)
        {
            int        numberOfInteriorPoints = interiorVolumePointList.Count;
            Rect       coreBounds             = volumeCores[c];
            Vector2z   coreCenter             = new Vector2z(coreBounds.center);
            Vector2z   coreBL = new Vector2z(coreBounds.xMin, coreBounds.yMin);
            Vector2z   coreBR = new Vector2z(coreBounds.xMax, coreBounds.yMin);
            Vector2z   coreTL = new Vector2z(coreBounds.xMin, coreBounds.yMax);
            Vector2z   coreTR = new Vector2z(coreBounds.xMax, coreBounds.yMax);
            Vector2z[] corePointArray;
            corePointArray = new[] { coreBL, coreBR, coreTR, coreTL };
            //Find the nearest legal cut we can make to join the core and interior point poly
            int   connectingPoint         = -1;
            float connectingPointDistance = Mathf.Infinity;
            for (int p = 0; p < numberOfInteriorPoints; p++)
            {
                if (linkedPoints.Contains(p))
                {
                    continue;
                }
                Vector2z thisPoint         = interiorVolumePointList[p];
                float    thisPointDistance = Vector2z.SqrMag(thisPoint, coreCenter);
                if (thisPointDistance < connectingPointDistance)
                {
                    bool legalCut = true;
                    for (int pc = 0; pc < numberOfInteriorPoints; pc++)
                    {
                        Vector2z p0 = interiorVolumePointList[pc];
                        Vector2z p1 = interiorVolumePointList[(pc + 1) % numberOfInteriorPoints];
                        if (BuildrUtils.FastLineIntersection(coreCenter, thisPoint, p0, p1))//check against all lines that this new cut doesn't intersect
                        {
                            if (print)
                            {
                                Debug.Log("FLI " + pc + " " + coreCenter + " " + thisPoint + " " + p0 + " " + p1);
                            }
                            legalCut = false;
                            break;
                        }
                    }
                    if (legalCut)
                    {
                        connectingPoint         = p;
                        connectingPointDistance = thisPointDistance;
                    }
                }
            }
            if (connectingPoint == -1)
            {
                Debug.Log("Buildr Could not place core");
                continue;
            }
            Vector2z chosenPoint                 = interiorVolumePointList[connectingPoint];
            int      connectingCorePoint         = 0;
            float    connectingCorePointDistance = Mathf.Infinity; // Vector2z.SqrMag(corePointArray[0], chosenPoint);
            for (int cp = 0; cp < 4; cp++)                         //find the core point to make the cut
            {
                float thisCorePointDistance = Vector2z.SqrMag(corePointArray[cp], chosenPoint);
                if (thisCorePointDistance < connectingCorePointDistance)
                {
                    connectingCorePoint         = cp;
                    connectingCorePointDistance = thisCorePointDistance;
                }
            }
            interiorVolumePointList.Insert(connectingPoint, chosenPoint); //loop back on the floorplan to close it
            for (int acp = 0; acp < 5; acp++)                             //loop back on itself to close the core
            {
                interiorVolumePointList.Insert(connectingPoint + 1, corePointArray[(connectingCorePoint + acp) % 4]);
            }
            for (int i = 0; i < linkedPoints.Count; i++)
            {
                if (linkedPoints[i] > connectingPoint)
                {
                    linkedPoints[i] += 7;
                }
            }
            linkedPoints.AddRange(new[] { connectingPoint, connectingPoint + 1, connectingPoint + 2, connectingPoint + 3, connectingPoint + 4, connectingPoint + 5, connectingPoint + 6 });
//            linkedPoints.AddRange(new []{connectingPoint,connectingPoint+6});
        }
//        if(linkedPoints.Count > 0)
//        Debug.Log(linkedPoints.Count+" "+linkedPoints[0]);
        Vector2z[] interiorPointListCore = interiorVolumePointList.ToArray();

        for (int f = 0; f < numberOfVolumePoints; f++)
        {
            ///WALLS

            int indexAM = Mathf.Abs((f - 1) % numberOfVolumePoints);
            int indexA  = f;
            int indexB  = (f + 1) % numberOfVolumePoints;
            int indexBP = (f + 2) % numberOfVolumePoints;

            Vector3 p0m        = plan.points[volume.points[indexAM]].vector3;
            Vector3 p0         = plan.points[volume.points[indexA]].vector3;
            Vector3 p1         = plan.points[volume.points[indexB]].vector3;
            Vector3 p1p        = plan.points[volume.points[indexBP]].vector3;
            Vector3 p0interior = interiorVolumePoints[indexA].vector3;
            Vector3 p1interior = interiorVolumePoints[indexB].vector3;

            float   facadeWidth         = Vector3.Distance(p0, p1) - largestDepthValue * 2.0f;
            Vector3 facadeDirection     = (p1 - p0).normalized;
            Vector3 facadeCross         = Vector3.Cross(facadeDirection, Vector3.up);
            Vector3 lastFacadeDirection = (p0 - p0m).normalized;
            Vector3 nextFacadeDirection = (p1p - p1).normalized;

            //only bother with facade directions when facade may intersect inverted geometry
            float facadeDirDotL   = Vector3.Dot(-facadeDirection, lastFacadeDirection);
            float facadeCrossDotL = Vector3.Dot(-facadeCross, lastFacadeDirection);
            if (facadeDirDotL <= 0 || facadeCrossDotL <= 0)
            {
                lastFacadeDirection = -facadeCross;
            }

            float facadeDirDotN   = Vector3.Dot(-facadeDirection, nextFacadeDirection);
            float facadeCrossDotN = Vector3.Dot(-facadeCross, nextFacadeDirection);
            if (facadeDirDotN <= 0 || facadeCrossDotN <= 0)
            {
                nextFacadeDirection = facadeCross;
            }


            int floorBase = plan.GetFacadeFloorHeight(volumeIndex, volume.points[indexA], volume.points[indexB]);
            BuildrVolumeStylesUnit[] styleUnits = volume.styles.GetContentsByFacade(volume.points[indexA]);
            int        floorPatternSize         = 0;
            List <int> facadePatternReference   = new List <int>();  //this contains a list of all the facade style indices to refence when looking for the appropriate style per floor
            int        patternCount             = 0;
            foreach (BuildrVolumeStylesUnit styleUnit in styleUnits) //need to knw how big all the styles are together so we can loop through them
            {
                floorPatternSize += styleUnit.floors;
                for (int i = 0; i < styleUnit.floors; i++)
                {
                    facadePatternReference.Add(patternCount);
                }
                patternCount++;
            }
            facadePatternReference.Reverse();

            int rows = numberOfFloors;


            Vector2 facadeUV = Vector2.zero;

            for (int r = 0; r < rows; r++)
            {
                float   currentFloorHeight       = floorHeight * r;
                Vector3 currentFloorHeightVector = Vector3.up * (data.floorHeight * r);
                Vector3 facadeFloorBaseVector    = p0 + Vector3.up * currentFloorHeight;
                Vector3 ceilingVector            = Vector3.up * ceilingHeight;
                if (r < floorBase)
                {
                    //no facade rendered
                    //facade gap filler

                    //interior gap points
                    Vector3 i0 = p1 - facadeDirection.normalized * largestDepthValue;
                    Vector3 i1 = p0 + facadeDirection.normalized * largestDepthValue;

                    Vector3 w0  = i0 + currentFloorHeightVector;
                    Vector3 w1  = i1 + currentFloorHeightVector;
                    Vector3 w2  = w0 + facadeCross * largestDepthValue;
                    Vector3 w3  = w1 + facadeCross * largestDepthValue;
                    Vector3 w4  = w0 + ceilingVector;
                    Vector3 w5  = w1 + ceilingVector;
                    Vector3 w6  = w2 + ceilingVector;
                    Vector3 w7  = w3 + ceilingVector;
                    Vector3 w8  = p1interior + currentFloorHeightVector;
                    Vector3 w9  = p0interior + currentFloorHeightVector;
                    Vector3 w10 = w8 + ceilingVector;
                    Vector3 w11 = w9 + ceilingVector;

                    //floor
                    AddData(new[] { w0, w1, w2, w3 }, new[] { 0, 1, 2, 1, 3, 2 }, volume.FloorTexture(r), false);

                    //ceiling
                    AddData(new[] { w5, w4, w7, w6 }, new[] { 0, 1, 2, 1, 3, 2 }, volume.CeilingTexture(r), false);

                    //sides
                    int wallSubmesh = volume.WallTexture(r);
                    AddPlane(w0, w2, w4, w6, wallSubmesh, false, Vector3.zero, new Vector2(largestDepthValue, floorHeight));
                    AddPlane(w3, w1, w7, w5, wallSubmesh, false, Vector3.zero, new Vector2(largestDepthValue, floorHeight));

                    //other gaps
                    float uvWidth1 = Vector3.Distance(w2, w8);
                    AddPlane(w2, w8, w6, w10, wallSubmesh, false, Vector3.zero, new Vector2(uvWidth1, floorHeight));
                    float uvWidth2 = Vector3.Distance(w3, w9);
                    AddPlane(w9, w3, w11, w7, wallSubmesh, false, Vector3.zero, new Vector2(uvWidth2, floorHeight));

                    continue;
                }

                //Get the facade style id
                //need to loop through the facade designs floor by floor until we get to the right one
                int modFloor = ((r - floorBase) % floorPatternSize);

                facadeDesign = data.facades[styleUnits[facadePatternReference[modFloor]].styleID];

                bool isBlankWall = !facadeDesign.hasWindows;
                if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                {
                    if (data.bays.Count == 0 || facadeDesign.bayPattern.Count == 0)
                    {
                        data.illegal = true;
                        return;
                    }

                    BuildrBay firstBay = data.bays[facadeDesign.bayPattern[0]];
                    if (firstBay.openingWidth > facadeWidth)
                    {
                        isBlankWall = true;
                    }
                    if (facadeDesign.bayPattern.Count == 0)
                    {
                        isBlankWall = true;
                    }
                }
                else
                {
                    if (facadeDesign.simpleBay.openingWidth + facadeDesign.simpleBay.minimumBayWidth > facadeWidth)
                    {
                        isBlankWall = true;
                    }
                }

                if (!isBlankWall)
                {
                    float       patternSize  = 0;//the space the pattern fills, there will be a gap that will be distributed to all bay styles
                    int         numberOfBays = 0;
                    BuildrBay[] bayDesignPattern;
                    int         numberOfBayDesigns;
                    if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                    {
                        numberOfBayDesigns = facadeDesign.bayPattern.Count;
                        bayDesignPattern   = new BuildrBay[numberOfBayDesigns];
                        for (int i = 0; i < numberOfBayDesigns; i++)
                        {
                            bayDesignPattern[i] = data.bays[facadeDesign.bayPattern[i]];
                        }
                    }
                    else
                    {
                        bayDesignPattern   = new[] { facadeDesign.simpleBay };
                        numberOfBayDesigns = 1;
                    }
                    //start with first window width - we'll be adding to this until we have filled the facade width
                    int it = 100;
                    while (true)
                    {
                        int   patternModIndex = numberOfBays % numberOfBayDesigns;
                        float patternAddition = bayDesignPattern[patternModIndex].openingWidth + bayDesignPattern[patternModIndex].minimumBayWidth;
                        if (patternSize + patternAddition < facadeWidth)
                        {
                            patternSize += patternAddition;
                            numberOfBays++;
                        }
                        else
                        {
                            break;
                        }
                        it--;
                        if (it < 0)
                        {
                            break;
                        }
                    }

                    Vector3 windowBase = facadeFloorBaseVector;
                    facadeUV.x  = 0;
                    facadeUV.y += floorHeight;
                    float perBayAdditionalSpacing = (facadeWidth - patternSize) / numberOfBays;
                    for (int c = 0; c < numberOfBays; c++)
                    {
                        BuildrBay bayStyle;
                        BuildrBay lastBay;
                        BuildrBay nextBay;
                        bool      firstColumn = c == 0;
                        bool      lastColumn  = c == numberOfBays - 1;
                        if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                        {
                            int numberOfBayStyles = facadeDesign.bayPattern.Count;
                            bayStyle = bayDesignPattern[c % numberOfBayStyles];
                            int lastBayIndex = (c > 0) ? (c - 1) % numberOfBayStyles : 0;
                            lastBay = bayDesignPattern[lastBayIndex];
                            nextBay = bayDesignPattern[(c + 1) % numberOfBayStyles];
                        }
                        else
                        {
                            bayStyle = facadeDesign.simpleBay;
                            lastBay  = facadeDesign.simpleBay;
                            nextBay  = facadeDesign.simpleBay;
                        }
                        float actualWindowSpacing = bayStyle.minimumBayWidth + perBayAdditionalSpacing;
                        float leftWidth           = actualWindowSpacing * bayStyle.openingWidthRatio;
                        float rightWidth          = actualWindowSpacing - leftWidth;
                        float openingWidth        = bayStyle.openingWidth;

                        if (firstColumn)
                        {
                            leftWidth += largestDepthValue;
                        }
                        if (lastColumn)
                        {
                            rightWidth += largestDepthValue;
                        }

                        BuildrTexture columnTexture = textures[bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture)];
                        Vector2       columnuvunits = columnTexture.tileUnitUV;
                        float         openingHeight = bayStyle.openingHeight;
                        if (columnTexture.patterned)
                        {
                            openingHeight = Mathf.Ceil(bayStyle.openingHeight / columnuvunits.y) * columnuvunits.y;
                        }
                        if (bayStyle.openingHeight == floorHeight)
                        {
                            bayStyle.openingHeight = floorHeight;
                        }

                        float rowBottomHeight = ((floorHeight - openingHeight) * bayStyle.openingHeightRatio);
                        if (columnTexture.patterned)
                        {
                            rowBottomHeight = Mathf.Ceil(rowBottomHeight / columnuvunits.y) * columnuvunits.y;
                        }

                        float rowTopHeight = (floorHeight - rowBottomHeight - openingHeight);

                        bool previousBayIdentical = bayStyle == lastBay;
                        bool nextBayIdentical     = bayStyle == nextBay;
                        if (previousBayIdentical && !firstColumn)
                        {
                            leftWidth = actualWindowSpacing;//if next design is identical - add the two parts together the reduce polycount
                        }
                        Vector3 w0, w1, w2, w3;

                        int  wallSubmesh = volume.WallTexture(r);
                        bool wallFlipped = false;
                        if (!bayStyle.isOpening)
                        {
                            float bayWidthSize = openingWidth + actualWindowSpacing;
                            if (firstColumn || lastColumn)
                            {
                                bayWidthSize += largestDepthValue;
                            }
                            Vector3 bayWidth  = facadeDirection * bayWidthSize;
                            Vector3 bayHeight = Vector3.up * floorHeight;
                            Vector3 bayDepth  = facadeCross * largestDepthValue;
                            w0 = windowBase + bayDepth;
                            w1 = windowBase + bayWidth + bayDepth;
                            w2 = windowBase + bayHeight + bayDepth;
                            w3 = windowBase + bayWidth + bayHeight + bayDepth;
                            Vector2 bayOpeningUVEnd = facadeUV + new Vector2(openingWidth + actualWindowSpacing, floorHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, facadeUV, bayOpeningUVEnd);

                            windowBase  = windowBase + bayWidth; //move base vertor to next bay
                            facadeUV.x += openingWidth + actualWindowSpacing;
                            continue;                            //bay filled - move onto next bay
                        }

                        var verts = new Vector3[16];
                        verts[0]    = windowBase;
                        verts[1]    = verts[0] + leftWidth * facadeDirection;
                        verts[2]    = verts[1] + openingWidth * facadeDirection;
                        verts[3]    = verts[2] + rightWidth * facadeDirection;
                        windowBase  = (nextBayIdentical) ? verts[2] : verts[3];//move to next window - if next design is identical - well add the two parts together the reduce polycount
                        facadeUV.x += (nextBayIdentical) ? openingWidth : openingWidth + rightWidth;

                        Vector3 rowBottomVector = Vector3.up * rowBottomHeight;
                        verts[4] = verts[0] + rowBottomVector;
                        verts[5] = verts[1] + rowBottomVector;
                        verts[6] = verts[2] + rowBottomVector;
                        verts[7] = verts[3] + rowBottomVector;

                        Vector3 openingVector = Vector3.up * openingHeight;
                        verts[8]  = verts[4] + openingVector;
                        verts[9]  = verts[5] + openingVector;
                        verts[10] = verts[6] + openingVector;
                        verts[11] = verts[7] + openingVector;

                        Vector3 rowTopVector = Vector3.up * rowTopHeight;
                        verts[12] = verts[8] + rowTopVector;
                        verts[13] = verts[9] + rowTopVector;
                        verts[14] = verts[10] + rowTopVector;
                        verts[15] = verts[11] + rowTopVector;

                        //Realign facade end points
                        if (firstColumn)
                        {
                            verts[0]  = p0interior - facadeCross * largestDepthValue + currentFloorHeightVector;
                            verts[4]  = verts[0] + rowBottomVector;
                            verts[8]  = verts[4] + openingVector;
                            verts[12] = verts[8] + rowTopVector;
                        }

                        if (lastColumn)
                        {
                            verts[3]  = p1interior - facadeCross * largestDepthValue + currentFloorHeightVector;
                            verts[7]  = verts[3] + rowBottomVector;
                            verts[11] = verts[7] + openingVector;
                            verts[15] = verts[11] + rowTopVector;
                        }

                        Vector3 openingDepthVector = facadeCross * bayStyle.openingDepth;
                        Vector3 wallDepthVecotr    = facadeCross * largestDepthValue;

                        ///WINDOWS
                        int  windowSubmesh = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningBackTexture);
                        bool windowFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningBackTexture);
                        w0 = verts[10] + openingDepthVector;
                        w1 = verts[9] + openingDepthVector;
                        w2 = verts[6] + openingDepthVector;
                        w3 = verts[5] + openingDepthVector;
                        Vector2 windowUVStart = new Vector2(0, 0);
                        Vector2 windowUVEnd   = new Vector2(openingWidth, openingHeight);
                        if (bayStyle.renderBack && !data.cullBays)
                        {
                            AddPlane(w0, w1, w2, w3, windowSubmesh, windowFlipped, windowUVStart, windowUVEnd);
                        }

                        ///COLUMNS
                        //Column Face
                        if (leftWidth > 0)//Column Face Left
                        {
                            w0 = verts[4] + wallDepthVecotr;
                            w1 = verts[5] + wallDepthVecotr;
                            w2 = verts[8] + wallDepthVecotr;
                            w3 = verts[9] + wallDepthVecotr;
                            Vector2 leftColumnUVStart = facadeUV + new Vector2(0, rowBottomHeight);
                            Vector2 leftColumnUVEnd   = leftColumnUVStart + new Vector2(leftWidth, openingHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, leftColumnUVStart, leftColumnUVEnd);
                        }
                        if ((!nextBayIdentical || lastColumn) && rightWidth > 0)//Column Right
                        {
                            w0 = verts[6] + wallDepthVecotr;
                            w1 = verts[7] + wallDepthVecotr;
                            w2 = verts[10] + wallDepthVecotr;
                            w3 = verts[11] + wallDepthVecotr;
                            Vector2 rightColumnUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight);
                            Vector2 rightColumnUVEnd   = rightColumnUVStart + new Vector2(rightWidth, openingHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, rightColumnUVStart, rightColumnUVEnd);
                        }
                        ///ROWS
                        //Row Bottom
                        if (rowBottomHeight > 0)
                        {
                            w0 = verts[1] + wallDepthVecotr;
                            w1 = verts[2] + wallDepthVecotr;
                            w2 = verts[5] + wallDepthVecotr;
                            w3 = verts[6] + wallDepthVecotr;
                            Vector2 bottomRowUVStart = facadeUV + new Vector2(leftWidth, 0);
                            Vector2 bottomRowUVEnd   = bottomRowUVStart + new Vector2(openingWidth, rowBottomHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, bottomRowUVStart, bottomRowUVEnd);
                        }
                        //Row Top
                        if (rowTopHeight > 0)
                        {
                            w0 = verts[9] + wallDepthVecotr;
                            w1 = verts[10] + wallDepthVecotr;
                            w2 = verts[13] + wallDepthVecotr;
                            w3 = verts[14] + wallDepthVecotr;
                            Vector2 topRowUVStart = facadeUV + new Vector2(leftWidth, rowBottomHeight + openingHeight);
                            Vector2 topRowUVEnd   = topRowUVStart + new Vector2(openingWidth, rowTopHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, topRowUVStart, topRowUVEnd);
                        }

                        //Cross Left Bottom
                        w0 = verts[0] + wallDepthVecotr;
                        w1 = verts[1] + wallDepthVecotr;
                        w2 = verts[4] + wallDepthVecotr;
                        w3 = verts[5] + wallDepthVecotr;
                        Vector2 crossLBUVStart = facadeUV + new Vector2(0, 0);
                        Vector2 crossLBUVEnd   = crossLBUVStart + new Vector2(leftWidth, rowBottomHeight);
                        AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossLBUVStart, crossLBUVEnd);

                        //Cross Left Top
                        w0 = verts[8] + wallDepthVecotr;
                        w1 = verts[9] + wallDepthVecotr;
                        w2 = verts[12] + wallDepthVecotr;
                        w3 = verts[13] + wallDepthVecotr;
                        Vector2 crossLTUVStart = facadeUV + new Vector2(0, rowBottomHeight + openingHeight);
                        Vector2 crossLTUVEnd   = crossLTUVStart + new Vector2(leftWidth, rowTopHeight);
                        AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossLTUVStart, crossLTUVEnd);

                        if ((!nextBayIdentical || lastColumn) && rightWidth > 0)
                        {
                            //Cross Right Bottom
                            w0 = verts[2] + wallDepthVecotr;
                            w1 = verts[3] + wallDepthVecotr;
                            w2 = verts[6] + wallDepthVecotr;
                            w3 = verts[7] + wallDepthVecotr;
                            Vector2 crossRBUVStart = facadeUV + new Vector2(leftWidth + openingWidth, 0);
                            Vector2 crossRBUVEnd   = crossRBUVStart + new Vector2(rightWidth, rowBottomHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossRBUVStart, crossRBUVEnd);

                            //Cross Right Top
                            w0 = verts[10] + wallDepthVecotr;
                            w1 = verts[11] + wallDepthVecotr;
                            w2 = verts[14] + wallDepthVecotr;
                            w3 = verts[15] + wallDepthVecotr;
                            Vector2 crossRTUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight + openingHeight);
                            Vector2 crossRTUVEnd   = crossRTUVStart + new Vector2(rightWidth, rowTopHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossRTUVStart, crossRTUVEnd);
                        }
                    }
                }
                else
                {
                    // windowless wall
                    Vector3 interiorStart = p0interior + currentFloorHeightVector;
                    Vector3 interiorEnd   = p1interior + currentFloorHeightVector;
                    //                        Vector3 wallVector = (facadeDirection * facadeWidth);
                    Vector3       wallHeightVector = Vector3.up * floorHeight;
                    Vector3       w0      = interiorStart;
                    Vector3       w1      = interiorEnd;
                    Vector3       w2      = interiorStart + wallHeightVector;
                    Vector3       w3      = interiorEnd + wallHeightVector;
                    BuildrTexture texture = textures[facadeDesign.simpleBay.GetTexture(BuildrBay.TextureNames.WallTexture)];
                    var           uvSize  = new Vector2(facadeWidth * (1.0f / texture.textureUnitSize.x), floorHeight * (1.0f / texture.textureUnitSize.y));
                    Vector2       uvunits = texture.tileUnitUV;
                    uvSize.x = Mathf.Ceil(uvSize.x / uvunits.x) * uvunits.x;
                    uvSize.y = Mathf.Ceil(uvSize.y / uvunits.y) * uvunits.y;
                    int     wallSubmesh = 0;
                    bool    flipped     = false;
                    Vector2 wallUVStart = facadeUV;
                    Vector2 wallUVEnd   = facadeUV + new Vector2(facadeWidth, floorHeight);
                    AddPlane(w0, w1, w2, w3, wallSubmesh, flipped, wallUVStart, wallUVEnd);
                }
            }
        }

        ///FLOORS AND CEILING
        int numberOfBasements   = volume.numberOfBasementFloors;
        int numberOfFloorPoints = interiorVolumePoints.Length;

        int[]   baseFloorPlanTriangles = EarClipper.Triangulate(interiorVolumePoints);
        int     baseFloorVectors       = interiorVolumePoints.Length;
        var     newEndVerts            = new Vector3[baseFloorVectors];
        Vector3 basementBaseDrop       = -floorHeightVector * numberOfBasements;

        for (int i = 0; i < baseFloorVectors; i++)
        {
            newEndVerts[i] = interiorVolumePoints[i].vector3 + basementBaseDrop;
        }
        var tris = new List <int>(baseFloorPlanTriangles);

        //Bottom Floor
        int floorSubmesh = volume.FloorTexture(-numberOfBasements);

        AddData(newEndVerts, baseFloorPlanTriangles, floorSubmesh, false);

        //Top Ceiling
        if (true)//Todo: add conditional for roof opening
        {
            Vector3 ceilingHeightVector = floorHeightVector * (numberOfFloors - 1 + numberOfBasements) + Vector3.up * ceilingHeight;
            for (int i = 0; i < baseFloorVectors; i++)
            {
                newEndVerts[i] += ceilingHeightVector;
            }
            tris.Reverse();
            AddData(newEndVerts, tris.ToArray(), volume.CeilingTexture(numberOfFloors - 1), false);
        }

        //inner floors
        int[] floorPlanTriangles   = EarClipper.Triangulate(interiorPointListCore);
        int   numberOfFloorVectors = interiorPointListCore.Length;

        for (int floorIndex = -numberOfBasements; floorIndex < numberOfFloors; floorIndex++)
        {
            Vector3 floorVectorHeight = floorHeightVector * floorIndex;
            newEndVerts = new Vector3[numberOfFloorVectors];
            for (int i = 0; i < numberOfFloorVectors; i++)
            {
                newEndVerts[i] = interiorPointListCore[i].vector3 + floorVectorHeight;
            }
            tris = new List <int>(floorPlanTriangles);

            //Floor
            if (floorIndex > -numberOfBasements)
            {
                AddData(newEndVerts, tris.ToArray(), volume.FloorTexture(floorIndex), false);
            }

            //Ceiling
            if (floorIndex < numberOfFloors - 1)
            {
                Vector3 ceilingHeightVector = Vector3.up * ceilingHeight;
                for (int i = 0; i < numberOfFloorVectors; i++)
                {
                    newEndVerts[i] += ceilingHeightVector;
                }
                tris.Reverse();
                AddData(newEndVerts, tris.ToArray(), volume.CeilingTexture(floorIndex), false);
            }

            //basement walls
            if (floorIndex < 0)
            {
                for (int f = 0; f < numberOfFloorPoints; f++)
                {
                    Vector3 basementVector = floorHeightVector * floorIndex;
                    int     indexA         = f;
                    int     indexB         = (f + 1) % numberOfFloorPoints;

                    Vector3 p0  = interiorVolumePoints[indexA].vector3 + basementVector;
                    Vector3 p1  = interiorVolumePoints[indexB].vector3 + basementVector;
                    Vector3 p2  = p0 + floorHeightVector;
                    Vector3 p3  = p1 + floorHeightVector;
                    Vector2 uv1 = new Vector2(Vector3.Distance(p0, p1), floorHeight);
                    AddPlane(p0, p1, p2, p3, volume.WallTexture(floorIndex), false, Vector2.zero, uv1);
                }
            }
        }

        //Core walls
        for (int c = 0; c < numberOfVolumeCores; c++)
        {
            Rect    coreBounds = volumeCores[c];
            Vector3 coreBL     = new Vector3(coreBounds.xMin, 0, coreBounds.yMin);
            Vector3 coreBR     = new Vector3(coreBounds.xMax, 0, coreBounds.yMin);
            Vector3 coreTL     = new Vector3(coreBounds.xMin, 0, coreBounds.yMax);
            Vector3 coreTR     = new Vector3(coreBounds.xMax, 0, coreBounds.yMax);

            for (int floorIndex = -numberOfBasements; floorIndex < numberOfFloors - 1; floorIndex++)
            {
                Vector3 c0        = floorHeightVector * floorIndex + Vector3.up * ceilingHeight;
                Vector3 f0        = floorHeightVector * floorIndex + Vector3.up * floorHeight;
                float   gapHeight = floorHeight - ceilingHeight;
                AddPlane(coreBL + c0, coreBR + c0, coreBL + f0, coreBR + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
                AddPlane(coreBR + c0, coreTR + c0, coreBR + f0, coreTR + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
                AddPlane(coreTR + c0, coreTL + c0, coreTR + f0, coreTL + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
                AddPlane(coreTL + c0, coreBL + c0, coreTL + f0, coreBL + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
            }
        }
    }
Exemple #30
0
    //TODO: functions to find out minimum footprint of stairwell for checking against cores?

    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data, int volumeIndex, StairModes stairMode, bool zeroMesh)
    {
        data = _data;
        mesh = _mesh;
        mesh.name = "Stairs Mesh Volume " + volumeIndex;
        textures = data.textures.ToArray();
        
//        BuildrFacadeDesign facadeDesign = data.facades[0];
        BuildrPlan plan = data.plan;
        BuildrVolume volume = plan.volumes[volumeIndex];
        float floorHeight = data.floorHeight;
//        Vector3 floorHeightVector = Vector3.up * floorHeight;

        if(!volume.generateStairs)
            return;
        
        //Calculate the internal floor plan points
        int numberOfVolumePoints = volume.points.Count;
        Vector2z[] volumePoints = new Vector2z[numberOfVolumePoints];
        for(int i = 0; i < numberOfVolumePoints; i++)
            volumePoints[i] = plan.points[volume.points[i]];
        List<Rect> volumeCores = new List<Rect>();
//        List<int> linkedPoints = new List<int>();
        foreach (Rect core in plan.cores)
        {
            Vector2z coreCenter = new Vector2z(core.center);
            if (BuildrUtils.PointInsidePoly(coreCenter, volumePoints))
                volumeCores.Add(core);
        }
        int numberOfVolumeCores = volumeCores.Count;
        int numberOfFloors = volume.numberOfFloors + volume.numberOfBasementFloors;
        float basementBaseHeight = (volume.numberOfBasementFloors) * floorHeight;//plus one for the initial floor
        float staircaseWidth = volume.staircaseWidth;
        float stairwellWidth = staircaseWidth * 2.5f;
        float stairwellDepth = staircaseWidth * 2 + Mathf.Sqrt(floorHeight+floorHeight);
        float staircaseThickness = Mathf.Sqrt(volume.stepHeight * volume.stepHeight + volume.stepHeight * volume.stepHeight);

        Vector3 flightVector = floorHeight * Vector3.up;
        Vector3 staircaseWidthVector = staircaseWidth * Vector3.right;
        Vector3 staircaseDepthVector = stairwellDepth * 0.5f * Vector3.forward;
        Vector3 stairHeightVector = staircaseThickness * Vector3.up;
        Vector3 landingDepthVector = staircaseWidth * Vector3.forward;

        //Texture submeshes
        int floorSubmesh = volume.stairwellFloorTexture;
        int stepSubmesh = volume.stairwellStepTexture;
        int wallSubmesh = volume.stairwellWallTexture;
        int ceilingSubmesh = volume.stairwellCeilingTexture;

        volume.stairBaseVector.Clear();
        for(int c = 0; c < numberOfVolumeCores; c++)
        {
            Rect coreBounds = volumeCores[c];
            Vector3 stairBaseVector = new Vector3(-stairwellWidth / 2, 0, -stairwellDepth/2);
            Vector3 stairPosition = new Vector3(coreBounds.xMin, -basementBaseHeight, coreBounds.yMin) - stairBaseVector;
            
            for(int f = 0; f < numberOfFloors; f++)
            {
                Vector3 flightBaseVector = stairBaseVector + (flightVector * f);
                if(!zeroMesh) flightBaseVector += stairPosition;

                Vector3 landingStart0 = flightBaseVector;
                Vector3 landingStart1 = landingStart0 + staircaseWidthVector*2.5f;
                Vector3 landingStart2 = landingStart0 + landingDepthVector;
                Vector3 landingStart3 = landingStart1 + landingDepthVector;
                Vector3 landingStart4 = landingStart0 - stairHeightVector;
                Vector3 landingStart5 = landingStart1 - stairHeightVector;
                Vector3 landingStart6 = landingStart2 - stairHeightVector;
                Vector3 landingStart7 = landingStart3 - stairHeightVector;
                if(f > 0)
                {
                    AddPlane(landingStart1, landingStart0, landingStart3, landingStart2, floorSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseWidth));//top
                    AddPlane(landingStart4, landingStart5, landingStart6, landingStart7, ceilingSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseWidth));//bottom
                    AddPlane(landingStart0, landingStart1, landingStart4, landingStart5, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseThickness));//frontside
                    AddPlane(landingStart3, landingStart2, landingStart7, landingStart6, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseThickness));//backside
                    AddPlane(landingStart0, landingStart4, landingStart2, landingStart6, wallSubmesh, false, Vector2.zero, new Vector2(staircaseThickness, staircaseWidth));//sideleft
                    AddPlane(landingStart5, landingStart1, landingStart7, landingStart3, wallSubmesh, false, Vector2.zero, new Vector2(staircaseThickness, staircaseWidth));//sideright
                }

                if(f < numberOfFloors - 1)
                {
                    Vector3 bottom0 = landingStart2;
                    Vector3 bottom1 = landingStart2 + staircaseWidthVector;
                    Vector3 bottom2 = bottom0 - stairHeightVector;
                    Vector3 bottom3 = bottom1 - stairHeightVector;

                    Vector3 top0 = bottom0 + (flightVector * 0.5f) + staircaseDepthVector;
                    Vector3 top1 = bottom1 + (flightVector * 0.5f) + staircaseDepthVector;
                    Vector3 top2 = top0 - stairHeightVector;
                    Vector3 top3 = top1 - stairHeightVector;

                    Vector3 bottomB0 = top1 + Vector3.right * staircaseWidth*0.5f;
                    Vector3 bottomB1 = bottomB0 + staircaseWidthVector;
                    Vector3 bottomB2 = bottomB0 - stairHeightVector;
                    Vector3 bottomB3 = bottomB1 - stairHeightVector;

                    Vector3 topB0 = bottomB0 + (flightVector * 0.5f) - staircaseDepthVector;
                    Vector3 topB1 = bottomB1 + (flightVector * 0.5f) - staircaseDepthVector;
                    Vector3 topB2 = topB0 - stairHeightVector;
                    Vector3 topB3 = topB1 - stairHeightVector;

                    float stairHypontenuse = Vector3.Distance(bottom0, top0);
                    int numberOfSteps = Mathf.CeilToInt((floorHeight / 2.0f) / volume.stepHeight);

                    switch(stairMode)
                    {
                        case StairModes.Flat:
                            //flight A
                            AddPlane(bottom1, bottom0, top1, top0, stepSubmesh, false, Vector2.zero, new Vector2(1, numberOfSteps));//step face
                            AddPlane(bottom3, bottom1, top3, top1, ceilingSubmesh, false, Vector2.zero, new Vector2(staircaseWidth, stairHypontenuse));//underside
                            AddPlane(bottom0, bottom2, top0, top2, wallSubmesh, false, new Vector2(bottom2.z, bottom2.y), new Vector2(top0.z, top0.y));//left side
                            AddPlane(bottom2, bottom3, top2, top3, wallSubmesh, false, new Vector2(bottom3.z, bottom3.y), new Vector2(top2.z, top2.y));//right side
                            //flight B
                            AddPlane(bottomB0, bottomB1, topB0, topB1, stepSubmesh, false, Vector2.zero, new Vector2(1, numberOfSteps));//step face
                            AddPlane(bottomB1, bottomB3, topB1, topB3, ceilingSubmesh, false, Vector2.zero, new Vector2(staircaseWidth, stairHypontenuse));//underside
                            AddPlane(bottomB2, bottomB0, topB2, topB0, wallSubmesh, false, Vector2.zero, Vector2.one);//left side
                            AddPlane(bottomB3, bottomB2, topB3, topB2, wallSubmesh, false, Vector2.zero, Vector2.one);//right side
                            break;

                        case StairModes.Stepped:

                            float stepHypontenuse = stairHypontenuse / numberOfSteps;
                            float stairAngle = Mathf.Atan2(floorHeight, stairwellDepth);
                            float stepDepth = Mathf.Cos(stairAngle) * stepHypontenuse;
                            float skipStep = (stepDepth / (numberOfSteps - 1));
                            stepDepth += skipStep;
                            float stepRiser = Mathf.Sin(stairAngle) * stepHypontenuse;

                            //flight one
                            float lerpIncrement = 1.0f / numberOfSteps;
                            float lerpIncrementB = 1.0f / (numberOfSteps-1);
                            for (int s = 0; s < numberOfSteps-1; s++)
                            {
                                float lerpValue = lerpIncrement * s;
                                Vector3 skipStepVector = Vector3.forward * (skipStep * s);
                                Vector3 s0 = Vector3.Lerp(bottom1, top1, lerpValue) + skipStepVector;
                                Vector3 s1 = Vector3.Lerp(bottom0, top0, lerpValue) + skipStepVector;
                                Vector3 s2 = s0 + Vector3.up * stepRiser;
                                Vector3 s3 = s1 + Vector3.up * stepRiser;
                                Vector3 s4 = s2 + Vector3.forward * stepDepth;
                                Vector3 s5 = s3 + Vector3.forward * stepDepth;
                                AddPlane(s0, s1, s2, s3, wallSubmesh, false, Vector2.zero, new Vector2(1,staircaseWidth));
                                AddPlane(s2, s3, s4, s5, stepSubmesh, false, Vector2.zero, new Vector2(1,staircaseWidth));
                                //sides
                                float lerpValueB = lerpIncrementB * s;
                                Vector3 s6 = Vector3.Lerp(bottom3, top3, lerpValueB);
                                Vector3 s7 = Vector3.Lerp(bottom3, top3, lerpValueB + lerpIncrementB);
                                AddPlane(s2, s4, s6, s7, wallSubmesh, false, Vector2.zero, new Vector2(stepDepth,staircaseThickness));

                                Vector3 s8 = Vector3.Lerp(bottom2, top2, lerpValueB);
                                Vector3 s9 = Vector3.Lerp(bottom2, top2, lerpValueB + lerpIncrementB);
                                AddPlane(s5, s3, s9, s8, wallSubmesh, false, Vector2.zero, new Vector2(stepDepth,staircaseThickness));
                            }
                            AddPlane(bottom2, bottom3, top2, top3, ceilingSubmesh, false, Vector2.zero, Vector2.one);

                            //flight two
                            for(int s = 0; s < numberOfSteps-1; s++)
                            {
                                float lerpValue = lerpIncrement * s;
                                Vector3 skipStepVector = -Vector3.forward * (skipStep * s);
                                Vector3 s0 = Vector3.Lerp(bottomB0, topB0, lerpValue) + skipStepVector;
                                Vector3 s1 = Vector3.Lerp(bottomB1, topB1, lerpValue) + skipStepVector;
                                Vector3 s2 = s0 + Vector3.up * stepRiser;
                                Vector3 s3 = s1 + Vector3.up * stepRiser;
                                Vector3 s4 = s2 - Vector3.forward * stepDepth;
                                Vector3 s5 = s3 - Vector3.forward * stepDepth;
                                AddPlane(s0, s1, s2, s3, wallSubmesh, false, Vector2.zero, new Vector2(1, staircaseWidth));
                                AddPlane(s2, s3, s4, s5, stepSubmesh, false, Vector2.zero, new Vector2(1, staircaseWidth));
                                float lerpValueB = lerpIncrementB * s;
                                //sides
                                Vector3 s6 = Vector3.Lerp(bottomB2, topB2, lerpValueB);
                                Vector3 s7 = Vector3.Lerp(bottomB2, topB2, lerpValueB + lerpIncrementB);
                                AddPlane(s2, s4, s6, s7, wallSubmesh, false, Vector2.zero, new Vector2(stepDepth, staircaseThickness));

                                Vector3 s8 = Vector3.Lerp(bottomB3, topB3, lerpValueB);
                                Vector3 s9 = Vector3.Lerp(bottomB3, topB3, lerpValueB + lerpIncrementB);
                                AddPlane(s5, s3, s9, s8, wallSubmesh, false, Vector2.zero, new Vector2(stepDepth, staircaseThickness));
                            }
                            AddPlane(bottomB3, bottomB2, topB3, topB2, ceilingSubmesh, false, Vector2.zero, Vector2.one);

                            break;
                    }

                    Vector3 landingEnd0 = top0 + landingDepthVector;
                    Vector3 landingEnd1 = bottomB1 + landingDepthVector;
                    Vector3 landingEnd2 = landingEnd0 - stairHeightVector;
                    Vector3 landingEnd3 = landingEnd1 - stairHeightVector;
                    Vector3 landingEnd4 = top0 - stairHeightVector;
                    Vector3 landingEnd5 = bottomB1 - stairHeightVector;

                    AddPlane(bottomB1, top0, landingEnd1, landingEnd0, floorSubmesh, false, Vector2.zero, new Vector2(staircaseWidth*2.5f, staircaseWidth));//top
                    AddPlane(landingEnd4, landingEnd5, landingEnd2, landingEnd3, ceilingSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseWidth));//bottom
                    AddPlane(top0, bottomB1, landingEnd4, landingEnd5, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseThickness));//frontside
                    AddPlane(landingEnd1, landingEnd0, landingEnd3, landingEnd2, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseThickness));//backside
                    AddPlane(landingEnd0, top0, landingEnd2, landingEnd4, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth, staircaseThickness));//sideleft
                    AddPlane(bottomB1, landingEnd1, landingEnd5, landingEnd3, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth, staircaseThickness));//sideright
                }
            }
            //Center wall
            float coreHeight = (numberOfFloors * floorHeight);
            Vector3 coreHeightVector = Vector3.up * coreHeight;
            Vector3 corePosition = (zeroMesh) ? Vector3.zero : stairPosition;
            Vector3 w0 = new Vector3(-staircaseWidth / 4.0f, 0, -(stairwellDepth - (staircaseWidth * 2)) / 2.0f) + corePosition;
            Vector3 w1 = w0 + Vector3.right * staircaseWidth/2;
            Vector3 w2 = w0 + staircaseDepthVector;
            Vector3 w3 = w1 + staircaseDepthVector;
            Vector3 w4 = w0 + coreHeightVector;
            Vector3 w5 = w1 + coreHeightVector;
            Vector3 w6 = w2 + coreHeightVector;
            Vector3 w7 = w3 + coreHeightVector;

            AddPlane(w1, w0, w5, w4, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth / 2, coreHeight));//
            AddPlane(w3, w1, w7, w5, wallSubmesh, false, Vector2.zero, new Vector2(stairwellDepth / 2, coreHeight));//
            AddPlane(w2, w3, w6, w7, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth / 2, coreHeight));//
            AddPlane(w0, w2, w4, w6, wallSubmesh, false, Vector2.zero, new Vector2(stairwellDepth / 2, coreHeight));//

            int it = 100;
            while(volume.stairBaseVector.Count < mesh.meshCount)
            {
                if (zeroMesh)
                    volume.stairBaseVector.Add(stairPosition);
                else
                    volume.stairBaseVector.Add(Vector3.zero);
                it--;
                if(it == 0)
                    break;
            }

            if(c<numberOfVolumeCores-1)
                mesh.ForceNewMesh();
        }

    }
 private static bool CCW(Vector2z p1,Vector2z p2, Vector2z p3)
 {
     return ((p2.x-p1.x)*(p3.y-p1.y) > (p2.y - p1.y) * (p3.x - p1.x));
 }
Exemple #32
0
 public static float Dot(Vector2z a, Vector2z b)
 {
     return(Vector2.Dot(a.vector2, b.vector2));
 }
 public static Vector2z FindIntersection(Vector2z lineA, Vector2z originA, Vector2z lineB, Vector2z originB)
 {
     Vector2 returnPoint = FindIntersection(lineA.vector2, originA.vector2, lineB.vector2, originB.vector2);
     return new Vector2z(returnPoint);
 }
Exemple #34
0
    /// <summary>
    /// Adds the wall point by vector3.
    /// </summary>
    /// <returns>
    /// The new wall point index.
    /// </returns>
    /// <param name='point'>
    /// Point.
    /// </param>
    /// <param name='wallIndex'>
    /// Wall index.
    /// </param>
    /// <param name='volumeIndex'>
    /// volume.
    /// </param>
    public int AddWallPoint(Vector3 point, int wallIndex, int volumeIndex)
    {
        Vector2z V2Zpoint = new Vector2z(point);

        return(AddWallPoint(volumeIndex, wallIndex, V2Zpoint));
    }
Exemple #35
0
    public static int[] Triangulate(Vector2z[] points)
    {
        int        numberOfPoints = points.Length;
        List <int> usePoints      = new List <int>();

        for (int p = 0; p < numberOfPoints; p++)
        {
            usePoints.Add(p);
        }
        int        numberOfUsablePoints = usePoints.Count;
        List <int> indices = new List <int>();

        if (numberOfPoints < 3)
        {
            return(indices.ToArray());
        }

        bool freeOfIntersections;
        int  it = 100;

        while (numberOfUsablePoints > 2)
        {
            for (int i = 0; i < numberOfUsablePoints; i++)
            {
                int a, b, c;

                a = usePoints[i];
                b = usePoints[(i + 1) % numberOfUsablePoints];
                c = usePoints[(i + 2) % numberOfUsablePoints];

                Vector2 pA = points[a].vector2;
                Vector2 pB = points[b].vector2;
                Vector2 pC = points[c].vector2;

                float dA = Vector2.Distance(pA, pB);
                float dB = Vector2.Distance(pB, pC);
                float dC = Vector2.Distance(pC, pA);

                float angle = Mathf.Acos((Mathf.Pow(dB, 2) - Mathf.Pow(dA, 2) - Mathf.Pow(dC, 2)) / (2 * dA * dC)) * Mathf.Rad2Deg * Mathf.Sign(Sign(points[a], points[b], points[c]));
                if (angle < 0)
                {
                    continue;                    //angle is not reflex
                }

                freeOfIntersections = true;
                //check that no point is inside the new triangle
                for (int p = 0; p < numberOfUsablePoints; p++)
                {
                    int pu = usePoints[p];
                    if (pu == a || pu == b || pu == c)
                    {
                        continue;
                    }

                    if (IntersectsTriangle2(points[a], points[b], points[c], points[pu]))
                    {
                        freeOfIntersections = false;
                        break;
                    }
                }

                //check that no line midpoint is inside the new triangle
                for (int p = 0; p < numberOfUsablePoints; p++)
                {
                    int pa = usePoints[p];
                    if (pa == a || pa == b || pa == c)
                    {
                        continue;
                    }
                    int      pb  = (p + 1) % numberOfPoints;
                    Vector2z pab = Vector2z.Lerp(points[pa], points[pb], 0.5f);

                    if (IntersectsTriangle2(points[a], points[b], points[c], pab))
                    {
                        freeOfIntersections = false;
                        break;
                    }
                }

                if (freeOfIntersections)
                {
                    indices.Add(a);
                    indices.Add(b);
                    indices.Add(c);
                    usePoints.Remove(b);
                    numberOfUsablePoints = usePoints.Count;
                    i--;
                    it = 100;
                    break;
                }
            }
            it--;
            if (it < 0)
            {
                indices.Reverse();
                return(indices.ToArray());
            }
        }

        indices.Reverse();

        return(indices.ToArray());
    }
Exemple #36
0
 public static Vector2z Lerp(Vector2z a, Vector2z b, float val)
 {
     Vector2z lerped = new Vector2z();
     lerped.vector2 = Vector2.Lerp(a.vector2, b.vector2, val);
     return lerped;
 }
    void genNoiseMap()
    {
        float ang, x, y, c, s;
        int ii;

        for(float i = 0; i < segments; i++)
        {
            ii = (int)i;

            ang = 360 * (i / segments);

            c = Mathf.Cos(ang);
            s = Mathf.Sin(ang);

            x = radius * c;
            y = radius * s;
            noise[ii] = fbm(x, y, seed, iterations);
            //Debug.Log(noise[ii]);

            x = (radius + maxVariance * noise[ii]) * c;
            y = (radius + maxVariance * noise[ii]) * s;
            vex[ii] = new Vector2z(x, y);
            vex2[ii] = new Vector2(x, y);
            //Debug.Log(vex[ii]);
        }
    }
 public static float Dot(Vector2z a, Vector2z b)
 {
     return Vector2.Dot(a.vector2, b.vector2);
 }
Exemple #39
0
    private static void Mansard(BuildrVolume volume, BuildrRoofDesign design)
    {
        BuildrPlan area = data.plan;
        int numberOfVolumePoints = volume.points.Count;
        int numberOfFloors = volume.numberOfFloors;
        float floorHeight = data.floorHeight;
        Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight);

        //add top base of the flat roof
        Vector3[] topVerts = new Vector3[numberOfVolumePoints];
        Vector2[] topUVs = new Vector2[numberOfVolumePoints];
        int topTextureID = design.GetTexture(BuildrRoofDesign.textureNames.floorB);
        BuildrTexture texture = textures[topTextureID];

        for (int l = 0; l < numberOfVolumePoints; l++)
        {
            int indexA, indexB, indexA0, indexB0;
            Vector3 p0, p1, p00, p10;
            indexA = l;
            indexB = (l < numberOfVolumePoints - 1) ? l + 1 : 0;
            indexA0 = (l > 0) ? l - 1 : numberOfVolumePoints - 1;
            indexB0 = (l < numberOfVolumePoints - 2) ? l + 2 : l + 2 - numberOfVolumePoints;

            p0 = area.points[volume.points[indexA]].vector3;
            p1 = area.points[volume.points[indexB]].vector3;
            p00 = area.points[volume.points[indexA0]].vector3;
            p10 = area.points[volume.points[indexB0]].vector3;

            float facadeWidth = Vector3.Distance(p0, p1);
            Vector3 facadeDirection = (p1 - p0).normalized;
            Vector3 facadeDirectionLeft = (p0 - p00).normalized;
            Vector3 facadeDirectionRight = (p10 - p1).normalized;
            Vector3 facadeNormal = Vector3.Cross(facadeDirection, Vector3.up);
            Vector3 facadeNormalLeft = Vector3.Cross(facadeDirectionLeft, Vector3.up);
            Vector3 facadeNormalRight = Vector3.Cross(facadeDirectionRight, Vector3.up);

            float roofHeight = design.height;
            float baseDepth = design.floorDepth;
            float cornerLeftRad = Vector3.Angle(facadeDirection, -facadeDirectionLeft) * Mathf.Deg2Rad / 2;
            float cornerRightRad = Vector3.Angle(-facadeDirection, facadeDirectionRight) * Mathf.Deg2Rad / 2;
            float cornerDepthLeft = baseDepth / Mathf.Sin(cornerLeftRad);
            float cornerDepthRight = baseDepth / Mathf.Sin(cornerRightRad);
            float topDepth = design.depth;
            float cornerTopDepthLeft = topDepth / Mathf.Sin(cornerLeftRad);
            float cornerTopDepthRight = topDepth / Mathf.Sin(cornerRightRad);

            Vector3 pr = facadeDirection * facadeWidth;

            Vector3 leftDir = (facadeNormal + facadeNormalLeft).normalized;
            Vector3 rightDir = (facadeNormal + facadeNormalRight).normalized;

            p0 += volumeFloorHeight;
            p1 += volumeFloorHeight;

            Vector3 w0, w1, w2, w3, w4, w5;
            w0 = p0;
            w1 = p0 + pr;
            w2 = w0 + leftDir * cornerDepthLeft;
            w3 = w1 + rightDir * cornerDepthRight;
            w4 = w2 + leftDir * cornerTopDepthLeft + Vector3.up * roofHeight;
            w5 = w3 + rightDir * cornerTopDepthRight + Vector3.up * roofHeight;

            Vector3[] verts = new Vector3[6] { w0, w1, w2, w3, w4, w5 };
//            List<Vector2> uvs = new List<Vector2>();

            Vector2[] uvsFloor = BuildrProjectUVs.Project(new Vector3[4] { w0, w1, w2, w3 }, Vector2.zero, facadeNormal);
            if(baseDepth == 0)
                uvsFloor[3].x = facadeWidth;
            Vector2[] uvsMansard = BuildrProjectUVs.Project(new Vector3[3] { w2, w4, w5 }, uvsFloor[2], facadeNormal);

            Vector3[] vertsA = new Vector3[4] { verts[0], verts[1], verts[2], verts[3] };
            Vector2[] uvsA = new Vector2[4] { uvsFloor[0], uvsFloor[1], uvsFloor[2], uvsFloor[3] };
            int[] trisA = new int[6] { 1, 0, 2, 1, 2, 3 };
            int subMeshA = design.GetTexture(BuildrRoofDesign.textureNames.floor);
            mesh.AddData(vertsA, uvsA, trisA, subMeshA);

            Vector3[] vertsB = new Vector3[4] { verts[2], verts[3], verts[4], verts[5] };
            Vector2[] uvsB = new Vector2[4] { uvsFloor[2], uvsFloor[3], uvsMansard[1], uvsMansard[2] };
            int[] trisB = new int[6] { 0, 2, 1, 1, 2, 3 };
            int subMeshB = design.GetTexture(BuildrRoofDesign.textureNames.tiles);
            mesh.AddData(vertsB, uvsB, trisB, subMeshB);

            //modify point for the top geometry
            Vector2z point = area.points[volume.points[l]];
            topVerts[l] = point.vector3 + volumeFloorHeight + Vector3.up * roofHeight + leftDir * (cornerDepthLeft + cornerTopDepthLeft);
            topUVs[l] = new Vector2(topVerts[l].x / texture.textureUnitSize.x, topVerts[l].z / texture.textureUnitSize.y);
        }

        Vector2z[] topVertV2z = new Vector2z[topVerts.Length];
        for (int i = 0; i < topVerts.Length; i++)
            topVertV2z[i] = new Vector2z(topVerts[i]);
        int[] topTris = EarClipper.Triangulate(topVertV2z);
        AddData(topVerts, topUVs, topTris, topTextureID);//top
    }
 public bool Equals(Vector2z a)
 {
     return (Dot(this, a) > 0.999f);
 }
Exemple #41
0
 public static float Distance(Vector2z a, Vector2z b)
 {
     return(Mathf.Sqrt(SqrMag(a, b)));
 }
 public static bool FastLineIntersection(Vector2z a1,Vector2z a2, Vector2z b1, Vector2z b2)
 {
     if (a1 == b1 || a1 == b2 || a2 == b1 || a2 == b2)
         return false;
     return (CCW(a1,b1,b2) != CCW(a2,b1,b2)) && (CCW(a1,a2,b1) != CCW(a1,a2,b2));
 }
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data, int volumeIndex)
    {
        data = _data;
        mesh = _mesh;
        mesh.name = "Interior Mesh Volume " + volumeIndex;
        textures = data.textures.ToArray();

        if(!data.renderInteriors)
            return;

        float largestDepthValue = 0;//deepest value of a bay design in the building
        float tallestBay = 0;
        foreach (BuildrBay bay in data.bays)
        {
            largestDepthValue = Mathf.Max(largestDepthValue, bay.deepestValue);//get the deepest value
            tallestBay = Mathf.Max(tallestBay, bay.openingHeight + (data.floorHeight - bay.openingHeight) * bay.openingHeightRatio);
        }
        foreach (BuildrFacadeDesign facade in data.facades)
        {
            if(facade.type != BuildrFacadeDesign.types.simple)
                continue;
            largestDepthValue = Mathf.Max(largestDepthValue, facade.simpleBay.deepestValue);//get the deepest value
            if(facade.simpleBay.isOpening)
                tallestBay = Mathf.Max(tallestBay, facade.simpleBay.openingHeight + (data.floorHeight - facade.simpleBay.openingHeight) * facade.simpleBay.openingHeightRatio);
        }


        BuildrFacadeDesign facadeDesign = data.facades[0];
        BuildrPlan plan = data.plan;
        BuildrVolume volume = plan.volumes[volumeIndex];
        int numberOfFloors = volume.numberOfFloors;
        float floorHeight = data.floorHeight;
        Vector3 floorHeightVector = Vector3.up * floorHeight;
        float ceilingHeight = tallestBay + (floorHeight - tallestBay) * data.interiorCeilingHeight;

        //Calculate the internal floor plan points
        int numberOfVolumePoints = volume.points.Count;
        Vector2z[] interiorVolumePoints = new Vector2z[numberOfVolumePoints];
        for (int i = 0; i < numberOfVolumePoints; i++)
        {
            Vector3 lastPoint = plan.points[volume.points[(i > 0) ? i - 1 : numberOfVolumePoints - 1]].vector3;
            Vector3 thisPoint = plan.points[volume.points[i]].vector3;
            Vector3 nextPoint = plan.points[volume.points[(i + 1) % numberOfVolumePoints]].vector3;
            Vector3 normalA = Vector3.Cross(thisPoint - lastPoint, Vector3.up).normalized;
            Vector3 normalB = Vector3.Cross(nextPoint - thisPoint, Vector3.up).normalized;

            Vector2z facadeALine = new Vector2z(thisPoint - lastPoint);
            Vector2z facadeBLine = new Vector2z(thisPoint - nextPoint);
            //Calculate facade inner origins for floors
            Vector3 facadeOriginV3A = lastPoint + normalA * largestDepthValue;
            Vector3 facadeOriginV3B = nextPoint + normalB * largestDepthValue;
            Vector2z facadeOriginA = new Vector2z(facadeOriginV3A);
            Vector2z facadeOriginB = new Vector2z(facadeOriginV3B);
            Vector2z facadeLineIntersection = BuildrUtils.FindIntersection(facadeALine, facadeOriginA, facadeBLine, facadeOriginB);

            interiorVolumePoints[i] = facadeLineIntersection;
        }
        List<Vector2z> interiorVolumePointList = new List<Vector2z>(interiorVolumePoints);
        List<Rect> volumeCores = new List<Rect>();
        List<int> linkedPoints = new List<int>();
        foreach (Rect core in plan.cores)
        {
            Vector2z coreCenter = new Vector2z(core.center);
            if (BuildrUtils.PointInsidePoly(coreCenter, interiorVolumePoints))
            {
                volumeCores.Add(core);
            }
        }
        int numberOfVolumeCores = volumeCores.Count;
        bool print = plan.volumes.IndexOf(volume) == 3;
        for (int c = 0; c < numberOfVolumeCores; c++)
        {
            int numberOfInteriorPoints = interiorVolumePointList.Count;
            Rect coreBounds = volumeCores[c];
            Vector2z coreCenter = new Vector2z(coreBounds.center);
            Vector2z coreBL = new Vector2z(coreBounds.xMin, coreBounds.yMin);
            Vector2z coreBR = new Vector2z(coreBounds.xMax, coreBounds.yMin);
            Vector2z coreTL = new Vector2z(coreBounds.xMin, coreBounds.yMax);
            Vector2z coreTR = new Vector2z(coreBounds.xMax, coreBounds.yMax);
            Vector2z[] corePointArray;
                corePointArray = new[] { coreBL, coreBR, coreTR, coreTL };
            //Find the nearest legal cut we can make to join the core and interior point poly
            int connectingPoint = -1;
            float connectingPointDistance = Mathf.Infinity;
            for (int p = 0; p < numberOfInteriorPoints; p++)
            {
                if(linkedPoints.Contains(p))
                    continue;
                Vector2z thisPoint = interiorVolumePointList[p];
                float thisPointDistance = Vector2z.SqrMag(thisPoint, coreCenter);
                if (thisPointDistance < connectingPointDistance)
                {
                    bool legalCut = true;
                    for (int pc = 0; pc < numberOfInteriorPoints; pc++)
                    {
                        Vector2z p0 = interiorVolumePointList[pc];
                        Vector2z p1 = interiorVolumePointList[(pc + 1) % numberOfInteriorPoints];
                        if (BuildrUtils.FastLineIntersection(coreCenter, thisPoint, p0, p1))//check against all lines that this new cut doesn't intersect
                        {
                            if (print)
                                Debug.Log("FLI "+pc+" "+coreCenter+" "+thisPoint+" "+p0+" "+p1);
                            legalCut = false;
                            break;
                        }
                    }
                    if (legalCut)
                    {
                        connectingPoint = p;
                        connectingPointDistance = thisPointDistance;
                    }
                }
            }
            if(connectingPoint==-1)
            {
                Debug.Log("Buildr Could not place core");
                continue;
            }
            Vector2z chosenPoint = interiorVolumePointList[connectingPoint];
            int connectingCorePoint = 0;
            float connectingCorePointDistance = Mathf.Infinity;// Vector2z.SqrMag(corePointArray[0], chosenPoint);
            for (int cp = 0; cp < 4; cp++)//find the core point to make the cut
            {
                float thisCorePointDistance = Vector2z.SqrMag(corePointArray[cp], chosenPoint);
                if (thisCorePointDistance < connectingCorePointDistance)
                {
                    connectingCorePoint = cp;
                    connectingCorePointDistance = thisCorePointDistance;
                }
            }
            interiorVolumePointList.Insert(connectingPoint, chosenPoint);//loop back on the floorplan to close it
            for (int acp = 0; acp < 5; acp++)//loop back on itself to close the core
            {
                interiorVolumePointList.Insert(connectingPoint + 1, corePointArray[(connectingCorePoint + acp) % 4]);
            }
            for(int i = 0; i < linkedPoints.Count; i++)
            {
                if (linkedPoints[i] > connectingPoint)
                    linkedPoints[i] += 7;
            }
            linkedPoints.AddRange(new[]{connectingPoint, connectingPoint + 1, connectingPoint + 2, connectingPoint + 3, connectingPoint + 4, connectingPoint + 5, connectingPoint + 6});
//            linkedPoints.AddRange(new []{connectingPoint,connectingPoint+6});
        }
//        if(linkedPoints.Count > 0)
//        Debug.Log(linkedPoints.Count+" "+linkedPoints[0]);
        Vector2z[] interiorPointListCore = interiorVolumePointList.ToArray();

        for (int f = 0; f < numberOfVolumePoints; f++)
        {
            ///WALLS

            int indexAM = Mathf.Abs((f - 1) % numberOfVolumePoints);
            int indexA = f;
            int indexB = (f + 1) % numberOfVolumePoints;
            int indexBP = (f + 2) % numberOfVolumePoints;

            Vector3 p0m = plan.points[volume.points[indexAM]].vector3;
            Vector3 p0 = plan.points[volume.points[indexA]].vector3;
            Vector3 p1 = plan.points[volume.points[indexB]].vector3;
            Vector3 p1p = plan.points[volume.points[indexBP]].vector3;
            Vector3 p0interior = interiorVolumePoints[indexA].vector3;
            Vector3 p1interior = interiorVolumePoints[indexB].vector3;

            float facadeWidth = Vector3.Distance(p0, p1) - largestDepthValue * 2.0f;
            Vector3 facadeDirection = (p1 - p0).normalized;
            Vector3 facadeCross = Vector3.Cross(facadeDirection, Vector3.up);
            Vector3 lastFacadeDirection = (p0 - p0m).normalized;
            Vector3 nextFacadeDirection = (p1p - p1).normalized;

            //only bother with facade directions when facade may intersect inverted geometry
            float facadeDirDotL = Vector3.Dot(-facadeDirection, lastFacadeDirection);
            float facadeCrossDotL = Vector3.Dot(-facadeCross, lastFacadeDirection);
            if (facadeDirDotL <= 0 || facadeCrossDotL <= 0) lastFacadeDirection = -facadeCross;

            float facadeDirDotN = Vector3.Dot(-facadeDirection, nextFacadeDirection);
            float facadeCrossDotN = Vector3.Dot(-facadeCross, nextFacadeDirection);
            if (facadeDirDotN <= 0 || facadeCrossDotN <= 0) nextFacadeDirection = facadeCross;


            int floorBase = plan.GetFacadeFloorHeight(volumeIndex, volume.points[indexA], volume.points[indexB]);
            BuildrVolumeStylesUnit[] styleUnits = volume.styles.GetContentsByFacade(volume.points[indexA]);
            int floorPatternSize = 0;
            List<int> facadePatternReference = new List<int>();//this contains a list of all the facade style indices to refence when looking for the appropriate style per floor
            int patternCount = 0;
            foreach (BuildrVolumeStylesUnit styleUnit in styleUnits)//need to knw how big all the styles are together so we can loop through them
            {
                floorPatternSize += styleUnit.floors;
                for (int i = 0; i < styleUnit.floors; i++)
                    facadePatternReference.Add(patternCount);
                patternCount++;
            }
            facadePatternReference.Reverse();

            int rows = numberOfFloors;


            Vector2 facadeUV = Vector2.zero;

            for (int r = 0; r < rows; r++)
            {
                float currentFloorHeight = floorHeight * r;
                Vector3 currentFloorHeightVector = Vector3.up * (data.floorHeight * r);
                Vector3 facadeFloorBaseVector = p0 + Vector3.up * currentFloorHeight;
                Vector3 ceilingVector = Vector3.up * ceilingHeight;
                if (r < floorBase)
                {
                    //no facade rendered
                    //facade gap filler

                    //interior gap points
                    Vector3 i0 = p1 - facadeDirection.normalized * largestDepthValue;
                    Vector3 i1 = p0 + facadeDirection.normalized * largestDepthValue;

                    Vector3 w0 = i0 + currentFloorHeightVector;
                    Vector3 w1 = i1 + currentFloorHeightVector;
                    Vector3 w2 = w0 + facadeCross * largestDepthValue;
                    Vector3 w3 = w1 + facadeCross * largestDepthValue;
                    Vector3 w4 = w0 + ceilingVector;
                    Vector3 w5 = w1 + ceilingVector;
                    Vector3 w6 = w2 + ceilingVector;
                    Vector3 w7 = w3 + ceilingVector;
                    Vector3 w8 = p1interior + currentFloorHeightVector;
                    Vector3 w9 = p0interior + currentFloorHeightVector;
                    Vector3 w10 = w8 + ceilingVector;
                    Vector3 w11 = w9 + ceilingVector;

                    //floor
                    AddData(new[] { w0, w1, w2, w3 }, new[] { 0, 1, 2, 1, 3, 2 }, volume.FloorTexture(r), false);

                    //ceiling
                    AddData(new[] { w5, w4, w7, w6 }, new[] { 0, 1, 2, 1, 3, 2 }, volume.CeilingTexture(r), false);

                    //sides
                    int wallSubmesh = volume.WallTexture(r);
                    AddPlane(w0, w2, w4, w6, wallSubmesh, false, Vector3.zero, new Vector2(largestDepthValue, floorHeight));
                    AddPlane(w3, w1, w7, w5, wallSubmesh, false, Vector3.zero, new Vector2(largestDepthValue, floorHeight));

                    //other gaps
                    float uvWidth1 = Vector3.Distance(w2, w8);
                    AddPlane(w2, w8, w6, w10, wallSubmesh, false, Vector3.zero, new Vector2(uvWidth1, floorHeight));
                    float uvWidth2 = Vector3.Distance(w3, w9);
                    AddPlane(w9, w3, w11, w7, wallSubmesh, false, Vector3.zero, new Vector2(uvWidth2, floorHeight));

                    continue;
                }

                //Get the facade style id
                //need to loop through the facade designs floor by floor until we get to the right one
                int modFloor = ((r - floorBase) % floorPatternSize);

                facadeDesign = data.facades[styleUnits[facadePatternReference[modFloor]].styleID];

                bool isBlankWall = !facadeDesign.hasWindows;
                if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                {
                    if (data.bays.Count == 0 || facadeDesign.bayPattern.Count == 0)
                    {
                        data.illegal = true;
                        return;
                    }

                    BuildrBay firstBay = data.bays[facadeDesign.bayPattern[0]];
                    if (firstBay.openingWidth > facadeWidth) isBlankWall = true;
                    if (facadeDesign.bayPattern.Count == 0) isBlankWall = true;
                }
                else
                {
                    if (facadeDesign.simpleBay.openingWidth + facadeDesign.simpleBay.minimumBayWidth > facadeWidth)
                        isBlankWall = true;
                }

                if (!isBlankWall)
                {
                    float patternSize = 0;//the space the pattern fills, there will be a gap that will be distributed to all bay styles
                    int numberOfBays = 0;
                    BuildrBay[] bayDesignPattern;
                    int numberOfBayDesigns;
                    if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                    {
                        numberOfBayDesigns = facadeDesign.bayPattern.Count;
                        bayDesignPattern = new BuildrBay[numberOfBayDesigns];
                        for (int i = 0; i < numberOfBayDesigns; i++)
                        {
                            bayDesignPattern[i] = data.bays[facadeDesign.bayPattern[i]];
                        }
                    }
                    else
                    {
                        bayDesignPattern = new[] { facadeDesign.simpleBay };
                        numberOfBayDesigns = 1;
                    }
                    //start with first window width - we'll be adding to this until we have filled the facade width
                    int it = 100;
                    while (true)
                    {
                        int patternModIndex = numberOfBays % numberOfBayDesigns;
                        float patternAddition = bayDesignPattern[patternModIndex].openingWidth + bayDesignPattern[patternModIndex].minimumBayWidth;
                        if (patternSize + patternAddition < facadeWidth)
                        {
                            patternSize += patternAddition;
                            numberOfBays++;
                        }
                        else
                            break;
                        it--;
                        if (it < 0)
                            break;
                    }

                    Vector3 windowBase = facadeFloorBaseVector;
                    facadeUV.x = 0;
                    facadeUV.y += floorHeight;
                    float perBayAdditionalSpacing = (facadeWidth - patternSize) / numberOfBays;
                    for (int c = 0; c < numberOfBays; c++)
                    {
                        BuildrBay bayStyle;
                        BuildrBay lastBay;
                        BuildrBay nextBay;
                        bool firstColumn = c == 0;
                        bool lastColumn = c == numberOfBays - 1;
                        if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                        {
                            int numberOfBayStyles = facadeDesign.bayPattern.Count;
                            bayStyle = bayDesignPattern[c % numberOfBayStyles];
                            int lastBayIndex = (c > 0) ? (c - 1) % numberOfBayStyles : 0;
                            lastBay = bayDesignPattern[lastBayIndex];
                            nextBay = bayDesignPattern[(c + 1) % numberOfBayStyles];
                        }
                        else
                        {
                            bayStyle = facadeDesign.simpleBay;
                            lastBay = facadeDesign.simpleBay;
                            nextBay = facadeDesign.simpleBay;
                        }
                        float actualWindowSpacing = bayStyle.minimumBayWidth + perBayAdditionalSpacing;
                        float leftWidth = actualWindowSpacing * bayStyle.openingWidthRatio;
                        float rightWidth = actualWindowSpacing - leftWidth;
                        float openingWidth = bayStyle.openingWidth;

                        if (firstColumn) leftWidth += largestDepthValue;
                        if (lastColumn) rightWidth += largestDepthValue;

                        BuildrTexture columnTexture = textures[bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture)];
                        Vector2 columnuvunits = columnTexture.tileUnitUV;
                        float openingHeight = bayStyle.openingHeight;
                        if (columnTexture.patterned) openingHeight = Mathf.Ceil(bayStyle.openingHeight / columnuvunits.y) * columnuvunits.y;
                        if (bayStyle.openingHeight == floorHeight) bayStyle.openingHeight = floorHeight;

                        float rowBottomHeight = ((floorHeight - openingHeight) * bayStyle.openingHeightRatio);
                        if (columnTexture.patterned) rowBottomHeight = Mathf.Ceil(rowBottomHeight / columnuvunits.y) * columnuvunits.y;

                        float rowTopHeight = (floorHeight - rowBottomHeight - openingHeight);

                        bool previousBayIdentical = bayStyle == lastBay;
                        bool nextBayIdentical = bayStyle == nextBay;
                        if (previousBayIdentical && !firstColumn)
                            leftWidth = actualWindowSpacing;//if next design is identical - add the two parts together the reduce polycount

                        Vector3 w0, w1, w2, w3;

                        int wallSubmesh = volume.WallTexture(r);
                        bool wallFlipped = false;
                        if (!bayStyle.isOpening)
                        {

                            float bayWidthSize = openingWidth + actualWindowSpacing;
                            if (firstColumn || lastColumn) bayWidthSize += largestDepthValue;
                            Vector3 bayWidth = facadeDirection * bayWidthSize;
                            Vector3 bayHeight = Vector3.up * floorHeight;
                            Vector3 bayDepth = facadeCross * largestDepthValue;
                            w0 = windowBase + bayDepth;
                            w1 = windowBase + bayWidth + bayDepth;
                            w2 = windowBase + bayHeight + bayDepth;
                            w3 = windowBase + bayWidth + bayHeight + bayDepth;
                            Vector2 bayOpeningUVEnd = facadeUV + new Vector2(openingWidth + actualWindowSpacing, floorHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, facadeUV, bayOpeningUVEnd);

                            windowBase = windowBase + bayWidth;//move base vertor to next bay
                            facadeUV.x += openingWidth + actualWindowSpacing;
                            continue;//bay filled - move onto next bay
                        }

                        var verts = new Vector3[16];
                        verts[0] = windowBase;
                        verts[1] = verts[0] + leftWidth * facadeDirection;
                        verts[2] = verts[1] + openingWidth * facadeDirection;
                        verts[3] = verts[2] + rightWidth * facadeDirection;
                        windowBase = (nextBayIdentical) ? verts[2] : verts[3];//move to next window - if next design is identical - well add the two parts together the reduce polycount
                        facadeUV.x += (nextBayIdentical) ? openingWidth : openingWidth + rightWidth;

                        Vector3 rowBottomVector = Vector3.up * rowBottomHeight;
                        verts[4] = verts[0] + rowBottomVector;
                        verts[5] = verts[1] + rowBottomVector;
                        verts[6] = verts[2] + rowBottomVector;
                        verts[7] = verts[3] + rowBottomVector;

                        Vector3 openingVector = Vector3.up * openingHeight;
                        verts[8] = verts[4] + openingVector;
                        verts[9] = verts[5] + openingVector;
                        verts[10] = verts[6] + openingVector;
                        verts[11] = verts[7] + openingVector;

                        Vector3 rowTopVector = Vector3.up * rowTopHeight;
                        verts[12] = verts[8] + rowTopVector;
                        verts[13] = verts[9] + rowTopVector;
                        verts[14] = verts[10] + rowTopVector;
                        verts[15] = verts[11] + rowTopVector;

                        //Realign facade end points
                        if (firstColumn)
                        {
                            verts[0] = p0interior - facadeCross * largestDepthValue + currentFloorHeightVector;
                            verts[4] = verts[0] + rowBottomVector;
                            verts[8] = verts[4] + openingVector;
                            verts[12] = verts[8] + rowTopVector;
                        }

                        if (lastColumn)
                        {
                            verts[3] = p1interior - facadeCross * largestDepthValue + currentFloorHeightVector;
                            verts[7] = verts[3] + rowBottomVector;
                            verts[11] = verts[7] + openingVector;
                            verts[15] = verts[11] + rowTopVector;
                        }

                        Vector3 openingDepthVector = facadeCross * bayStyle.openingDepth;
                        Vector3 wallDepthVecotr = facadeCross * largestDepthValue;

                        ///WINDOWS
                        int windowSubmesh = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningBackTexture); 
                        bool windowFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningBackTexture);
                        w0 = verts[10] + openingDepthVector;
                        w1 = verts[9] + openingDepthVector;
                        w2 = verts[6] + openingDepthVector;
                        w3 = verts[5] + openingDepthVector;
                        Vector2 windowUVStart = new Vector2(0, 0);
                        Vector2 windowUVEnd = new Vector2(openingWidth, openingHeight);
                        if (bayStyle.renderBack && !data.cullBays)
                            AddPlane(w0, w1, w2, w3, windowSubmesh, windowFlipped, windowUVStart, windowUVEnd);

                        ///COLUMNS
                        //Column Face
                        if (leftWidth > 0)//Column Face Left
                        {
                            w0 = verts[4] + wallDepthVecotr;
                            w1 = verts[5] + wallDepthVecotr;
                            w2 = verts[8] + wallDepthVecotr;
                            w3 = verts[9] + wallDepthVecotr;
                            Vector2 leftColumnUVStart = facadeUV + new Vector2(0, rowBottomHeight);
                            Vector2 leftColumnUVEnd = leftColumnUVStart + new Vector2(leftWidth, openingHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, leftColumnUVStart, leftColumnUVEnd);
                        }
                        if ((!nextBayIdentical || lastColumn) && rightWidth > 0)//Column Right
                        {
                            w0 = verts[6] + wallDepthVecotr;
                            w1 = verts[7] + wallDepthVecotr;
                            w2 = verts[10] + wallDepthVecotr;
                            w3 = verts[11] + wallDepthVecotr;
                            Vector2 rightColumnUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight);
                            Vector2 rightColumnUVEnd = rightColumnUVStart + new Vector2(rightWidth, openingHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, rightColumnUVStart, rightColumnUVEnd);
                        }
                        ///ROWS
                        //Row Bottom
                        if (rowBottomHeight > 0)
                        {
                            w0 = verts[1] + wallDepthVecotr;
                            w1 = verts[2] + wallDepthVecotr;
                            w2 = verts[5] + wallDepthVecotr;
                            w3 = verts[6] + wallDepthVecotr;
                            Vector2 bottomRowUVStart = facadeUV + new Vector2(leftWidth, 0);
                            Vector2 bottomRowUVEnd = bottomRowUVStart + new Vector2(openingWidth, rowBottomHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, bottomRowUVStart, bottomRowUVEnd);
                        }
                        //Row Top
                        if (rowTopHeight > 0)
                        {
                            w0 = verts[9] + wallDepthVecotr;
                            w1 = verts[10] + wallDepthVecotr;
                            w2 = verts[13] + wallDepthVecotr;
                            w3 = verts[14] + wallDepthVecotr;
                            Vector2 topRowUVStart = facadeUV + new Vector2(leftWidth, rowBottomHeight + openingHeight);
                            Vector2 topRowUVEnd = topRowUVStart + new Vector2(openingWidth, rowTopHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, topRowUVStart, topRowUVEnd);
                        }

                        //Cross Left Bottom
                        w0 = verts[0] + wallDepthVecotr;
                        w1 = verts[1] + wallDepthVecotr;
                        w2 = verts[4] + wallDepthVecotr;
                        w3 = verts[5] + wallDepthVecotr;
                        Vector2 crossLBUVStart = facadeUV + new Vector2(0, 0);
                        Vector2 crossLBUVEnd = crossLBUVStart + new Vector2(leftWidth, rowBottomHeight);
                        AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossLBUVStart, crossLBUVEnd);

                        //Cross Left Top
                        w0 = verts[8] + wallDepthVecotr;
                        w1 = verts[9] + wallDepthVecotr;
                        w2 = verts[12] + wallDepthVecotr;
                        w3 = verts[13] + wallDepthVecotr;
                        Vector2 crossLTUVStart = facadeUV + new Vector2(0, rowBottomHeight + openingHeight);
                        Vector2 crossLTUVEnd = crossLTUVStart + new Vector2(leftWidth, rowTopHeight);
                        AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossLTUVStart, crossLTUVEnd);

                        if ((!nextBayIdentical || lastColumn) && rightWidth > 0)
                        {
                            //Cross Right Bottom
                            w0 = verts[2] + wallDepthVecotr;
                            w1 = verts[3] + wallDepthVecotr;
                            w2 = verts[6] + wallDepthVecotr;
                            w3 = verts[7] + wallDepthVecotr;
                            Vector2 crossRBUVStart = facadeUV + new Vector2(leftWidth + openingWidth, 0);
                            Vector2 crossRBUVEnd = crossRBUVStart + new Vector2(rightWidth, rowBottomHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossRBUVStart, crossRBUVEnd);

                            //Cross Right Top
                            w0 = verts[10] + wallDepthVecotr;
                            w1 = verts[11] + wallDepthVecotr;
                            w2 = verts[14] + wallDepthVecotr;
                            w3 = verts[15] + wallDepthVecotr;
                            Vector2 crossRTUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight + openingHeight);
                            Vector2 crossRTUVEnd = crossRTUVStart + new Vector2(rightWidth, rowTopHeight);
                            AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossRTUVStart, crossRTUVEnd);
                        }
                    }
                }
                else
                {
                    // windowless wall
                    Vector3 interiorStart = p0interior + currentFloorHeightVector;
                    Vector3 interiorEnd = p1interior + currentFloorHeightVector;
                    //                        Vector3 wallVector = (facadeDirection * facadeWidth);
                    Vector3 wallHeightVector = Vector3.up * floorHeight;
                    Vector3 w0 = interiorStart;
                    Vector3 w1 = interiorEnd;
                    Vector3 w2 = interiorStart + wallHeightVector;
                    Vector3 w3 = interiorEnd + wallHeightVector;
                    BuildrTexture texture = textures[facadeDesign.simpleBay.GetTexture(BuildrBay.TextureNames.WallTexture)];
                    var uvSize = new Vector2(facadeWidth * (1.0f / texture.textureUnitSize.x), floorHeight * (1.0f / texture.textureUnitSize.y));
                    Vector2 uvunits = texture.tileUnitUV;
                    uvSize.x = Mathf.Ceil(uvSize.x / uvunits.x) * uvunits.x;
                    uvSize.y = Mathf.Ceil(uvSize.y / uvunits.y) * uvunits.y;
                    int wallSubmesh = 0;
                    bool flipped = false;
                    Vector2 wallUVStart = facadeUV;
                    Vector2 wallUVEnd = facadeUV + new Vector2(facadeWidth, floorHeight);
                    AddPlane(w0, w1, w2, w3, wallSubmesh, flipped, wallUVStart, wallUVEnd);

                }
            }
        }

        ///FLOORS AND CEILING
        int numberOfBasements = volume.numberOfBasementFloors;
        int numberOfFloorPoints = interiorVolumePoints.Length;
        int[] baseFloorPlanTriangles = EarClipper.Triangulate(interiorVolumePoints);
        int baseFloorVectors = interiorVolumePoints.Length;
        var newEndVerts = new Vector3[baseFloorVectors];
        Vector3 basementBaseDrop = -floorHeightVector * numberOfBasements;
        for (int i = 0; i < baseFloorVectors; i++)
            newEndVerts[i] = interiorVolumePoints[i].vector3 + basementBaseDrop;
        var tris = new List<int>(baseFloorPlanTriangles);

        //Bottom Floor
        int floorSubmesh = volume.FloorTexture(-numberOfBasements);
        AddData(newEndVerts, baseFloorPlanTriangles, floorSubmesh, false);

        //Top Ceiling
        if (true)//Todo: add conditional for roof opening
        {
            Vector3 ceilingHeightVector = floorHeightVector * (numberOfFloors - 1 + numberOfBasements) + Vector3.up * ceilingHeight;
            for (int i = 0; i < baseFloorVectors; i++)
                newEndVerts[i] += ceilingHeightVector;
            tris.Reverse(); 
            AddData(newEndVerts, tris.ToArray(), volume.CeilingTexture(numberOfFloors-1), false);
        }

        //inner floors
        int[] floorPlanTriangles = EarClipper.Triangulate(interiorPointListCore);
        int numberOfFloorVectors = interiorPointListCore.Length;
        for (int floorIndex = -numberOfBasements; floorIndex < numberOfFloors; floorIndex++)
        {
            Vector3 floorVectorHeight = floorHeightVector * floorIndex;
            newEndVerts = new Vector3[numberOfFloorVectors];
            for (int i = 0; i < numberOfFloorVectors; i++)
            {
                newEndVerts[i] = interiorPointListCore[i].vector3 + floorVectorHeight;
            }
            tris = new List<int>(floorPlanTriangles);

            //Floor
            if (floorIndex > -numberOfBasements)
                AddData(newEndVerts, tris.ToArray(), volume.FloorTexture(floorIndex), false);

            //Ceiling
            if (floorIndex < numberOfFloors - 1)
            {
                Vector3 ceilingHeightVector = Vector3.up * ceilingHeight;
                for (int i = 0; i < numberOfFloorVectors; i++)
                {
                    newEndVerts[i] += ceilingHeightVector;
                }
                tris.Reverse();
                AddData(newEndVerts, tris.ToArray(), volume.CeilingTexture(floorIndex), false);
            }

            //basement walls
            if(floorIndex < 0)
            {
                for (int f = 0; f < numberOfFloorPoints; f++)
                {
                    Vector3 basementVector = floorHeightVector * floorIndex;
                    int indexA = f;
                    int indexB = (f + 1) % numberOfFloorPoints;

                    Vector3 p0 = interiorVolumePoints[indexA].vector3 + basementVector;
                    Vector3 p1 = interiorVolumePoints[indexB].vector3 + basementVector;
                    Vector3 p2 = p0 + floorHeightVector;
                    Vector3 p3 = p1 + floorHeightVector;
                    Vector2 uv1 = new Vector2(Vector3.Distance(p0,p1), floorHeight);
                    AddPlane(p0, p1, p2, p3, volume.WallTexture(floorIndex), false, Vector2.zero, uv1);
                }
            }
        }

        //Core walls
        for (int c = 0; c < numberOfVolumeCores; c++)
        {
            Rect coreBounds = volumeCores[c];
            Vector3 coreBL = new Vector3(coreBounds.xMin, 0, coreBounds.yMin);
            Vector3 coreBR = new Vector3(coreBounds.xMax, 0, coreBounds.yMin);
            Vector3 coreTL = new Vector3(coreBounds.xMin, 0, coreBounds.yMax);
            Vector3 coreTR = new Vector3(coreBounds.xMax, 0, coreBounds.yMax);

            for (int floorIndex = -numberOfBasements; floorIndex < numberOfFloors - 1; floorIndex++)
            {
                Vector3 c0 = floorHeightVector * floorIndex + Vector3.up * ceilingHeight;
                Vector3 f0 = floorHeightVector * floorIndex + Vector3.up * floorHeight;
                float gapHeight = floorHeight - ceilingHeight;
                AddPlane(coreBL + c0, coreBR + c0, coreBL + f0, coreBR + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
                AddPlane(coreBR + c0, coreTR + c0, coreBR + f0, coreTR + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
                AddPlane(coreTR + c0, coreTL + c0, coreTR + f0, coreTL + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
                AddPlane(coreTL + c0, coreBL + c0, coreTL + f0, coreBL + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight));
            }
        }
    }
Exemple #44
0
    public static Vector2z FindIntersection(Vector2z lineA, Vector2z originA, Vector2z lineB, Vector2z originB)
    {
        Vector2 returnPoint = FindIntersection(lineA.vector2, originA.vector2, lineB.vector2, originB.vector2);

        return(new Vector2z(returnPoint));
    }
Exemple #45
0
 public static bool FastLineIntersection(Vector2z a1, Vector2z a2, Vector2z b1, Vector2z b2)
 {
     return((CCW(a1, b1, b2) != CCW(a2, b1, b2)) && (CCW(a1, a2, b1) != CCW(a1, a2, b2)));
 }
Exemple #46
0
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data)
    {
        //        timestart = Time.realtimeSinceStartup;
        data     = _data;
        mesh     = _mesh;
        textures = data.textures.ToArray();
        BuildrPlan plan = data.plan;

//        int facadeIndex = 0;
        numberOfFacades = 0;
        int numberOfVolumes = data.plan.numberOfVolumes;

        //define rectangles that represent the facades
        packedTexturePositions.Clear();
        for (int v = 0; v < numberOfVolumes; v++)
        {
            BuildrVolume volume = plan.volumes[v];
            int          numberOfVolumePoints = volume.points.Count;

            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                {
                    continue;
                }
                int      indexA = f;
                int      indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0;
                Vector2z p0     = plan.points[volume.points[indexA]];
                Vector2z p1     = plan.points[volume.points[indexB]];

                float facadeWidth = Vector2z.Distance(p0, p1) * PIXELS_PER_METER;
                int   floorBase   = plan.GetFacadeFloorHeight(v, volume.points[indexA], volume.points[indexB]);

                int numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)//no facade - adjacent facade is taller and covers this one
                {
                    continue;
                }

                float floorHeight  = data.floorHeight;
                float facadeHeight = (volume.numberOfFloors - floorBase) * floorHeight * PIXELS_PER_METER;
                if (facadeHeight < 0)
                {
                    facadeWidth  = 0;
                    facadeHeight = 0;
                }

                Rect newFacadeRect = new Rect(0, 0, facadeWidth, facadeHeight);
                packedTexturePositions.Add(newFacadeRect);

                numberOfFacades++;
            }
        }

        //Build ROOF
        DynamicMeshGenericMultiMaterialMesh dynMeshRoof = new DynamicMeshGenericMultiMaterialMesh();

        dynMeshRoof.name         = "Roof Mesh";
        dynMeshRoof.subMeshCount = textures.Length;
        BuildrRoof.Build(dynMeshRoof, data, true);
        dynMeshRoof.CheckMaxTextureUVs(data);

        roofTextures.Clear();
        roofTextureIndex.Clear();
        foreach (BuildrRoofDesign roofDesign in data.roofs)
        {
            foreach (int textureIndex in roofDesign.textureValues)
            {
                if (!roofTextureIndex.Contains(textureIndex))
                {
                    BuildrTexture bTexture = data.textures[textureIndex];
                    Vector2       largestSubmeshPlaneSize = new Vector2(1, 1);
                    Vector2       minWorldUvSize          = dynMeshRoof.MinWorldUvSize(textureIndex);
                    Vector2       maxWorldUvSize          = dynMeshRoof.MaxWorldUvSize(textureIndex);
                    largestSubmeshPlaneSize.x = maxWorldUvSize.x - minWorldUvSize.x;
                    largestSubmeshPlaneSize.y = maxWorldUvSize.y - minWorldUvSize.y;
                    int  roofTextureWidth    = Mathf.RoundToInt(largestSubmeshPlaneSize.x * PIXELS_PER_METER);
                    int  roofTextureHeight   = Mathf.RoundToInt(largestSubmeshPlaneSize.y * PIXELS_PER_METER);
                    Rect newRoofTexutureRect = new Rect(0, 0, roofTextureWidth, roofTextureHeight);
                    packedTexturePositions.Add(newRoofTexutureRect);
                    roofTextures.Add(bTexture);
                    roofTextureIndex.Add(textureIndex);
                }
            }
        }

        //run a custom packer to define their postions
        textureWidth = RectanglePack.Pack(packedTexturePositions, ATLAS_PADDING);

        //determine the resize scale and apply that to the rects
        packedScale = 1;
        int numberOfRects = packedTexturePositions.Count;

        if (textureWidth > MAXIMUM_TEXTURESIZE)
        {
            packedScale = MAXIMUM_TEXTURESIZE / (float)textureWidth;
            for (int i = 0; i < numberOfRects; i++)
            {
                Rect thisRect = packedTexturePositions[i];
                thisRect.x               *= packedScale;
                thisRect.y               *= packedScale;
                thisRect.width           *= packedScale;
                thisRect.height          *= packedScale;
                packedTexturePositions[i] = thisRect;
                //Debug.Log("Rects "+roofTextures[i-+packedTexturePositions[i]);
            }
            textureWidth = Mathf.RoundToInt(packedScale * textureWidth);
        }
        else
        {
            textureWidth = (int)Mathf.Pow(2, (Mathf.FloorToInt(Mathf.Log(textureWidth - 1, 2)) + 1));//find the next power of two
        }

        textureSize = textureWidth * textureWidth;
        colourArray = new Color32[textureSize];
        //TestRectColours();//this test paints all the facades with rainbow colours - real pretty
        BuildTextures();

        Texture2D packedTexture = new Texture2D(textureWidth, textureWidth, TextureFormat.ARGB32, true);

        packedTexture.filterMode = FilterMode.Bilinear;
        packedTexture.SetPixels32(colourArray);
        packedTexture.Apply(true, false);

        if (data.OneDrawCallTexture != null)
        {
            Object.DestroyImmediate(data.OneDrawCallTexture);
        }
        data.OneDrawCallTexture      = packedTexture;
        data.OneDrawCallTexture.name = "One Draw Call Texture";

        int         numberOfRoofTextures   = roofTextures.Count - 1;
        List <Rect> facadeTexturePositions = new List <Rect>(packedTexturePositions);

        Debug.Log(numberOfRoofTextures);
        facadeTexturePositions.RemoveRange(packedTexturePositions.Count - numberOfRoofTextures, numberOfRoofTextures);

        BuildrBuilding.Build(mesh, data, facadeTexturePositions.ToArray());

        data     = null;
        mesh     = null;
        textures = null;


        System.GC.Collect();
    }
Exemple #47
0
    //TODO: functions to find out minimum footprint of stairwell for checking against cores?

    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data, int volumeIndex, StairModes stairMode, bool zeroMesh)
    {
        data      = _data;
        mesh      = _mesh;
        mesh.name = "Stairs Mesh Volume " + volumeIndex;
        textures  = data.textures.ToArray();

//        BuildrFacadeDesign facadeDesign = data.facades[0];
        BuildrPlan   plan        = data.plan;
        BuildrVolume volume      = plan.volumes[volumeIndex];
        float        floorHeight = data.floorHeight;

//        Vector3 floorHeightVector = Vector3.up * floorHeight;

        if (!volume.generateStairs)
        {
            return;
        }

        //Calculate the internal floor plan points
        int numberOfVolumePoints = volume.points.Count;

        Vector2z[] volumePoints = new Vector2z[numberOfVolumePoints];
        for (int i = 0; i < numberOfVolumePoints; i++)
        {
            volumePoints[i] = plan.points[volume.points[i]];
        }
        List <Rect> volumeCores = new List <Rect>();

//        List<int> linkedPoints = new List<int>();
        foreach (Rect core in plan.cores)
        {
            Vector2z coreCenter = new Vector2z(core.center);
            if (BuildrUtils.PointInsidePoly(coreCenter, volumePoints))
            {
                volumeCores.Add(core);
            }
        }
        int   numberOfVolumeCores = volumeCores.Count;
        int   numberOfFloors      = volume.numberOfFloors + volume.numberOfBasementFloors;
        float basementBaseHeight  = (volume.numberOfBasementFloors) * floorHeight;//plus one for the initial floor
        float staircaseWidth      = volume.staircaseWidth;
        float stairwellWidth      = staircaseWidth * 2.5f;
        float stairwellDepth      = staircaseWidth * 2 + Mathf.Sqrt(floorHeight + floorHeight);
        float staircaseThickness  = Mathf.Sqrt(volume.stepHeight * volume.stepHeight + volume.stepHeight * volume.stepHeight);

        Vector3 flightVector         = floorHeight * Vector3.up;
        Vector3 staircaseWidthVector = staircaseWidth * Vector3.right;
        Vector3 staircaseDepthVector = stairwellDepth * 0.5f * Vector3.forward;
        Vector3 stairHeightVector    = staircaseThickness * Vector3.up;
        Vector3 landingDepthVector   = staircaseWidth * Vector3.forward;

        //Texture submeshes
        int floorSubmesh   = volume.stairwellFloorTexture;
        int stepSubmesh    = volume.stairwellStepTexture;
        int wallSubmesh    = volume.stairwellWallTexture;
        int ceilingSubmesh = volume.stairwellCeilingTexture;

        volume.stairBaseVector.Clear();
        for (int c = 0; c < numberOfVolumeCores; c++)
        {
            Rect    coreBounds      = volumeCores[c];
            Vector3 stairBaseVector = new Vector3(-stairwellWidth / 2, 0, -stairwellDepth / 2);
            Vector3 stairPosition   = new Vector3(coreBounds.xMin, -basementBaseHeight, coreBounds.yMin) - stairBaseVector;

            for (int f = 0; f < numberOfFloors; f++)
            {
                Vector3 flightBaseVector = stairBaseVector + (flightVector * f);
                if (!zeroMesh)
                {
                    flightBaseVector += stairPosition;
                }

                Vector3 landingStart0 = flightBaseVector;
                Vector3 landingStart1 = landingStart0 + staircaseWidthVector * 2.5f;
                Vector3 landingStart2 = landingStart0 + landingDepthVector;
                Vector3 landingStart3 = landingStart1 + landingDepthVector;
                Vector3 landingStart4 = landingStart0 - stairHeightVector;
                Vector3 landingStart5 = landingStart1 - stairHeightVector;
                Vector3 landingStart6 = landingStart2 - stairHeightVector;
                Vector3 landingStart7 = landingStart3 - stairHeightVector;
                if (f > 0)
                {
                    AddPlane(landingStart1, landingStart0, landingStart3, landingStart2, floorSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseWidth));    //top
                    AddPlane(landingStart4, landingStart5, landingStart6, landingStart7, ceilingSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseWidth));  //bottom
                    AddPlane(landingStart0, landingStart1, landingStart4, landingStart5, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseThickness)); //frontside
                    AddPlane(landingStart3, landingStart2, landingStart7, landingStart6, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseThickness)); //backside
                    AddPlane(landingStart0, landingStart4, landingStart2, landingStart6, wallSubmesh, false, Vector2.zero, new Vector2(staircaseThickness, staircaseWidth));        //sideleft
                    AddPlane(landingStart5, landingStart1, landingStart7, landingStart3, wallSubmesh, false, Vector2.zero, new Vector2(staircaseThickness, staircaseWidth));        //sideright
                }

                if (f < numberOfFloors - 1)
                {
                    Vector3 bottom0 = landingStart2;
                    Vector3 bottom1 = landingStart2 + staircaseWidthVector;
                    Vector3 bottom2 = bottom0 - stairHeightVector;
                    Vector3 bottom3 = bottom1 - stairHeightVector;

                    Vector3 top0 = bottom0 + (flightVector * 0.5f) + staircaseDepthVector;
                    Vector3 top1 = bottom1 + (flightVector * 0.5f) + staircaseDepthVector;
                    Vector3 top2 = top0 - stairHeightVector;
                    Vector3 top3 = top1 - stairHeightVector;

                    Vector3 bottomB0 = top1 + Vector3.right * staircaseWidth * 0.5f;
                    Vector3 bottomB1 = bottomB0 + staircaseWidthVector;
                    Vector3 bottomB2 = bottomB0 - stairHeightVector;
                    Vector3 bottomB3 = bottomB1 - stairHeightVector;

                    Vector3 topB0 = bottomB0 + (flightVector * 0.5f) - staircaseDepthVector;
                    Vector3 topB1 = bottomB1 + (flightVector * 0.5f) - staircaseDepthVector;
                    Vector3 topB2 = topB0 - stairHeightVector;
                    Vector3 topB3 = topB1 - stairHeightVector;

                    float stairHypontenuse = Vector3.Distance(bottom0, top0);
                    int   numberOfSteps    = Mathf.CeilToInt((floorHeight / 2.0f) / volume.stepHeight);

                    switch (stairMode)
                    {
                    case StairModes.Flat:
                        //flight A
                        AddPlane(bottom1, bottom0, top1, top0, stepSubmesh, false, Vector2.zero, new Vector2(1, numberOfSteps));                        //step face
                        AddPlane(bottom3, bottom1, top3, top1, ceilingSubmesh, false, Vector2.zero, new Vector2(staircaseWidth, stairHypontenuse));     //underside
                        AddPlane(bottom0, bottom2, top0, top2, wallSubmesh, false, new Vector2(bottom2.z, bottom2.y), new Vector2(top0.z, top0.y));     //left side
                        AddPlane(bottom2, bottom3, top2, top3, wallSubmesh, false, new Vector2(bottom3.z, bottom3.y), new Vector2(top2.z, top2.y));     //right side
                        //flight B
                        AddPlane(bottomB0, bottomB1, topB0, topB1, stepSubmesh, false, Vector2.zero, new Vector2(1, numberOfSteps));                    //step face
                        AddPlane(bottomB1, bottomB3, topB1, topB3, ceilingSubmesh, false, Vector2.zero, new Vector2(staircaseWidth, stairHypontenuse)); //underside
                        AddPlane(bottomB2, bottomB0, topB2, topB0, wallSubmesh, false, Vector2.zero, Vector2.one);                                      //left side
                        AddPlane(bottomB3, bottomB2, topB3, topB2, wallSubmesh, false, Vector2.zero, Vector2.one);                                      //right side
                        break;

                    case StairModes.Stepped:

                        float stepHypontenuse = stairHypontenuse / numberOfSteps;
                        float stairAngle      = Mathf.Atan2(floorHeight, stairwellDepth);
                        float stepDepth       = Mathf.Cos(stairAngle) * stepHypontenuse;
                        float skipStep        = (stepDepth / (numberOfSteps - 1));
                        stepDepth += skipStep;
                        float stepRiser = Mathf.Sin(stairAngle) * stepHypontenuse;

                        //flight one
                        float lerpIncrement  = 1.0f / numberOfSteps;
                        float lerpIncrementB = 1.0f / (numberOfSteps - 1);
                        for (int s = 0; s < numberOfSteps - 1; s++)
                        {
                            float   lerpValue      = lerpIncrement * s;
                            Vector3 skipStepVector = Vector3.forward * (skipStep * s);
                            Vector3 s0             = Vector3.Lerp(bottom1, top1, lerpValue) + skipStepVector;
                            Vector3 s1             = Vector3.Lerp(bottom0, top0, lerpValue) + skipStepVector;
                            Vector3 s2             = s0 + Vector3.up * stepRiser;
                            Vector3 s3             = s1 + Vector3.up * stepRiser;
                            Vector3 s4             = s2 + Vector3.forward * stepDepth;
                            Vector3 s5             = s3 + Vector3.forward * stepDepth;
                            AddPlane(s0, s1, s2, s3, wallSubmesh, false, Vector2.zero, new Vector2(1, staircaseWidth));
                            AddPlane(s2, s3, s4, s5, stepSubmesh, false, Vector2.zero, new Vector2(1, staircaseWidth));
                            //sides
                            float   lerpValueB = lerpIncrementB * s;
                            Vector3 s6         = Vector3.Lerp(bottom3, top3, lerpValueB);
                            Vector3 s7         = Vector3.Lerp(bottom3, top3, lerpValueB + lerpIncrementB);
                            AddPlane(s2, s4, s6, s7, wallSubmesh, false, Vector2.zero, new Vector2(stepDepth, staircaseThickness));

                            Vector3 s8 = Vector3.Lerp(bottom2, top2, lerpValueB);
                            Vector3 s9 = Vector3.Lerp(bottom2, top2, lerpValueB + lerpIncrementB);
                            AddPlane(s5, s3, s9, s8, wallSubmesh, false, Vector2.zero, new Vector2(stepDepth, staircaseThickness));
                        }
                        AddPlane(bottom2, bottom3, top2, top3, ceilingSubmesh, false, Vector2.zero, Vector2.one);

                        //flight two
                        for (int s = 0; s < numberOfSteps - 1; s++)
                        {
                            float   lerpValue      = lerpIncrement * s;
                            Vector3 skipStepVector = -Vector3.forward * (skipStep * s);
                            Vector3 s0             = Vector3.Lerp(bottomB0, topB0, lerpValue) + skipStepVector;
                            Vector3 s1             = Vector3.Lerp(bottomB1, topB1, lerpValue) + skipStepVector;
                            Vector3 s2             = s0 + Vector3.up * stepRiser;
                            Vector3 s3             = s1 + Vector3.up * stepRiser;
                            Vector3 s4             = s2 - Vector3.forward * stepDepth;
                            Vector3 s5             = s3 - Vector3.forward * stepDepth;
                            AddPlane(s0, s1, s2, s3, wallSubmesh, false, Vector2.zero, new Vector2(1, staircaseWidth));
                            AddPlane(s2, s3, s4, s5, stepSubmesh, false, Vector2.zero, new Vector2(1, staircaseWidth));
                            float lerpValueB = lerpIncrementB * s;
                            //sides
                            Vector3 s6 = Vector3.Lerp(bottomB2, topB2, lerpValueB);
                            Vector3 s7 = Vector3.Lerp(bottomB2, topB2, lerpValueB + lerpIncrementB);
                            AddPlane(s2, s4, s6, s7, wallSubmesh, false, Vector2.zero, new Vector2(stepDepth, staircaseThickness));

                            Vector3 s8 = Vector3.Lerp(bottomB3, topB3, lerpValueB);
                            Vector3 s9 = Vector3.Lerp(bottomB3, topB3, lerpValueB + lerpIncrementB);
                            AddPlane(s5, s3, s9, s8, wallSubmesh, false, Vector2.zero, new Vector2(stepDepth, staircaseThickness));
                        }
                        AddPlane(bottomB3, bottomB2, topB3, topB2, ceilingSubmesh, false, Vector2.zero, Vector2.one);

                        break;
                    }

                    Vector3 landingEnd0 = top0 + landingDepthVector;
                    Vector3 landingEnd1 = bottomB1 + landingDepthVector;
                    Vector3 landingEnd2 = landingEnd0 - stairHeightVector;
                    Vector3 landingEnd3 = landingEnd1 - stairHeightVector;
                    Vector3 landingEnd4 = top0 - stairHeightVector;
                    Vector3 landingEnd5 = bottomB1 - stairHeightVector;

                    AddPlane(bottomB1, top0, landingEnd1, landingEnd0, floorSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseWidth));              //top
                    AddPlane(landingEnd4, landingEnd5, landingEnd2, landingEnd3, ceilingSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseWidth));  //bottom
                    AddPlane(top0, bottomB1, landingEnd4, landingEnd5, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseThickness));           //frontside
                    AddPlane(landingEnd1, landingEnd0, landingEnd3, landingEnd2, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseThickness)); //backside
                    AddPlane(landingEnd0, top0, landingEnd2, landingEnd4, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth, staircaseThickness));               //sideleft
                    AddPlane(bottomB1, landingEnd1, landingEnd5, landingEnd3, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth, staircaseThickness));           //sideright
                }
            }
            //Center wall
            float   coreHeight       = (numberOfFloors * floorHeight);
            Vector3 coreHeightVector = Vector3.up * coreHeight;
            Vector3 corePosition     = (zeroMesh) ? Vector3.zero : stairPosition;
            Vector3 w0 = new Vector3(-staircaseWidth / 4.0f, 0, -(stairwellDepth - (staircaseWidth * 2)) / 2.0f) + corePosition;
            Vector3 w1 = w0 + Vector3.right * staircaseWidth / 2;
            Vector3 w2 = w0 + staircaseDepthVector;
            Vector3 w3 = w1 + staircaseDepthVector;
            Vector3 w4 = w0 + coreHeightVector;
            Vector3 w5 = w1 + coreHeightVector;
            Vector3 w6 = w2 + coreHeightVector;
            Vector3 w7 = w3 + coreHeightVector;

            AddPlane(w1, w0, w5, w4, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth / 2, coreHeight)); //
            AddPlane(w3, w1, w7, w5, wallSubmesh, false, Vector2.zero, new Vector2(stairwellDepth / 2, coreHeight)); //
            AddPlane(w2, w3, w6, w7, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth / 2, coreHeight)); //
            AddPlane(w0, w2, w4, w6, wallSubmesh, false, Vector2.zero, new Vector2(stairwellDepth / 2, coreHeight)); //

            int it = 100;
            while (volume.stairBaseVector.Count < mesh.meshCount)
            {
                if (zeroMesh)
                {
                    volume.stairBaseVector.Add(stairPosition);
                }
                else
                {
                    volume.stairBaseVector.Add(Vector3.zero);
                }
                it--;
                if (it == 0)
                {
                    break;
                }
            }

            if (c < numberOfVolumeCores - 1)
            {
                mesh.ForceNewMesh();
            }
        }
    }
Exemple #48
0
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data)
    {
//        timestart = Time.realtimeSinceStartup;
        data     = _data;
        mesh     = _mesh;
        textures = data.textures.ToArray();
        BuildrPlan plan = data.plan;

        int facadeIndex = 0;

        numberOfFacades = 0;
        int numberOfVolumes = data.plan.numberOfVolumes;

        LogTimer("Start");

        //define rectangles that represent the facades
        packedTexturePositions.Clear();
        for (int v = 0; v < numberOfVolumes; v++)
        {
            BuildrVolume volume = plan.volumes[v];
            int          numberOfVolumePoints = volume.points.Count;

            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                {
                    continue;
                }
                int      indexA = f;
                int      indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0;
                Vector2z p0     = plan.points[volume.points[indexA]];
                Vector2z p1     = plan.points[volume.points[indexB]];

                float facadeWidth = Vector2z.Distance(p0, p1) * PIXELS_PER_METER;
                int   floorBase   = plan.GetFacadeFloorHeight(v, volume.points[indexA], volume.points[indexB]);

                int numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)//no facade - adjacent facade is taller and covers this one
                {
                    continue;
                }

                float floorHeight  = data.floorHeight;
                float facadeHeight = (volume.numberOfFloors - floorBase) * floorHeight * PIXELS_PER_METER;
                if (facadeHeight < 0)
                {
                    facadeWidth  = 0;
                    facadeHeight = 0;
                }

                Rect newFacadeRect = new Rect(0, 0, facadeWidth, facadeHeight);
                packedTexturePositions.Add(newFacadeRect);

                numberOfFacades++;
            }
        }

        //Build ROOF
        DynamicMeshGenericMultiMaterialMesh dynMeshRoof = new DynamicMeshGenericMultiMaterialMesh();

        dynMeshRoof.name         = "Roof Mesh";
        dynMeshRoof.subMeshCount = textures.Length;
        BuildrRoof.Build(dynMeshRoof, data, true);
        dynMeshRoof.CheckMaxTextureUVs(data);
        LogTimer("Roof A");

        roofTextures.Clear();
        roofTextureIndex.Clear();
        foreach (BuildrRoofDesign roofDesign in data.roofs)
        {
            foreach (int textureIndex in roofDesign.textureValues)
            {
                if (!roofTextureIndex.Contains(textureIndex))
                {
                    BuildrTexture bTexture = data.textures[textureIndex];
                    Vector2       largestSubmeshPlaneSize = new Vector2(1, 1);
                    Vector2       minWorldUvSize          = dynMeshRoof.MinWorldUvSize(textureIndex);
                    Vector2       maxWorldUvSize          = dynMeshRoof.MaxWorldUvSize(textureIndex);
                    largestSubmeshPlaneSize.x = maxWorldUvSize.x - minWorldUvSize.x;
                    largestSubmeshPlaneSize.y = maxWorldUvSize.y - minWorldUvSize.y;
                    int  roofTextureWidth    = Mathf.RoundToInt(largestSubmeshPlaneSize.x * PIXELS_PER_METER);
                    int  roofTextureHeight   = Mathf.RoundToInt(largestSubmeshPlaneSize.y * PIXELS_PER_METER);
                    Rect newRoofTexutureRect = new Rect(0, 0, roofTextureWidth, roofTextureHeight);
                    packedTexturePositions.Add(newRoofTexutureRect);
                    roofTextures.Add(bTexture);
                    roofTextureIndex.Add(textureIndex);
                }
            }
        }

        //run a custom packer to define their postions
        textureWidth = RectanglePack.Pack(packedTexturePositions, ATLAS_PADDING);

        //determine the resize scale and apply that to the rects
        packedScale = 1;
        int numberOfRects = packedTexturePositions.Count;

        if (textureWidth > MAXIMUM_TEXTURESIZE)
        {
            packedScale = MAXIMUM_TEXTURESIZE / (float)textureWidth;
            for (int i = 0; i < numberOfRects; i++)
            {
                Rect thisRect = packedTexturePositions[i];
                thisRect.x               *= packedScale;
                thisRect.y               *= packedScale;
                thisRect.width           *= packedScale;
                thisRect.height          *= packedScale;
                packedTexturePositions[i] = thisRect;
                //Debug.Log("Rects "+roofTextures[i-+packedTexturePositions[i]);
            }
            textureWidth = Mathf.RoundToInt(packedScale * textureWidth);
        }
        else
        {
            textureWidth = (int)Mathf.Pow(2, (Mathf.FloorToInt(Mathf.Log(textureWidth - 1, 2)) + 1));//find the next power of two
        }
        //Debug.Log("Texture Width "+textureWidth);
        //TODO: maybe restrict the resize to a power of two?
        LogTimer("Packed Rect Generated");

        textureSize = textureWidth * textureWidth;
        colourArray = new Color32[textureSize];
        //TestRectColours();//this test paints all the facades with rainbow colours - real pretty
        BuildTextures();

        LogTimer("texture created");
        Texture2D packedTexture = new Texture2D(textureWidth, textureWidth, TextureFormat.ARGB32, true);

        packedTexture.filterMode = FilterMode.Bilinear;
        packedTexture.SetPixels32(colourArray);
        packedTexture.Apply(true, false);
        LogTimer("apply");

        if (data.LODTextureAtlas != null)
        {
            Object.DestroyImmediate(data.LODTextureAtlas);
        }
        data.LODTextureAtlas      = packedTexture;
        data.LODTextureAtlas.name = "Low Detail Texture";

        //build the model with new uvs

        if (data.drawUnderside)
        {
            for (int s = 0; s < numberOfVolumes; s++)
            {
                BuildrVolume volume = plan.volumes[s];
                int          numberOfVolumePoints = volume.points.Count;
                Vector3[]    newEndVerts          = new Vector3[numberOfVolumePoints];
                Vector2[]    newEndUVs            = new Vector2[numberOfVolumePoints];
                for (int i = 0; i < numberOfVolumePoints; i++)
                {
                    newEndVerts[i] = plan.points[volume.points[i]].vector3;
                    newEndUVs[i]   = Vector2.zero;
                }

                List <int> tris = new List <int>(data.plan.GetTrianglesBySectorBase(s));
                tris.Reverse();
                mesh.AddData(newEndVerts, newEndUVs, tris.ToArray(), 0);
            }
        }
        LogTimer("Floor");

        //Build facades
        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volume = plan.volumes[s];
            int          numberOfVolumePoints = volume.points.Count;

            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                {
                    continue;
                }
                int     indexA = f;
                int     indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0;
                Vector3 p0     = plan.points[volume.points[indexA]].vector3;
                Vector3 p1     = plan.points[volume.points[indexB]].vector3;

                int floorBase      = plan.GetFacadeFloorHeight(s, volume.points[indexA], volume.points[indexB]);
                int numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)
                {
                    //no facade - adjacent facade is taller and covers this one
                    continue;
                }
                float floorHeight = data.floorHeight;

                Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight);
                Vector3 wallHeight       = Vector3.up * (volume.numberOfFloors * floorHeight) - floorHeightStart;

                p0 += floorHeightStart;
                p1 += floorHeightStart;

                Vector3 w0 = p0;
                Vector3 w1 = p1;
                Vector3 w2 = w0 + wallHeight;
                Vector3 w3 = w1 + wallHeight;

                Rect facadeRect = packedTexturePositions[facadeIndex];

                float   imageSize = textureWidth;
                Vector2 uvMin     = new Vector2(facadeRect.xMin / imageSize, facadeRect.yMin / imageSize);
                Vector2 uvMax     = new Vector2(facadeRect.xMax / imageSize, facadeRect.yMax / imageSize);

                mesh.AddPlane(w0, w1, w2, w3, uvMin, uvMax, 0);
                facadeIndex++;
            }
        }
        LogTimer("Facades");

        //ROOF Textures
        int         roofRectBase  = numberOfFacades;
        List <Rect> newAtlasRects = new List <Rect>();

        for (int i = roofRectBase; i < packedTexturePositions.Count; i++)
        {
            Rect uvRect = new Rect();//generate a UV based rectangle off the packed one
            uvRect.x      = packedTexturePositions[i].x / textureWidth;
            uvRect.y      = packedTexturePositions[i].y / textureWidth;
            uvRect.width  = packedTexturePositions[i].width / textureWidth;
            uvRect.height = packedTexturePositions[i].height / textureWidth;
            newAtlasRects.Add(uvRect);
        }
        dynMeshRoof.Atlas(roofTextureIndex.ToArray(), newAtlasRects.ToArray(), data.textures.ToArray());
        //Add the atlased mesh data to the main model data at submesh 0
        mesh.AddData(dynMeshRoof.vertices, dynMeshRoof.uv, dynMeshRoof.triangles, 0);

        LogTimer("Roof B");

        data     = null;
        mesh     = null;
        textures = null;
        //atlasRects = null;

        LogTimer("Done");

        System.GC.Collect();
    }
Exemple #49
0
 public bool Equals(Vector2z a)
 {
     return(Dot(this, a) > 0.999f);
 }