コード例 #1
0
ファイル: VolumeRuntime.cs プロジェクト: ishui/unity3DScripts
        public void CalculateSubmeshes(SubmeshLibrary submeshLibrary)
        {
            for (int p = 0; p < numberOfPoints; p++)
            {
                Facade facadeDesign = GetFacade(p);
                if (facadeDesign != null)
                {
                    submeshLibrary.Add(facadeDesign.stringCourseSurface);

                    List <WallSection> usedWallSections = facadeDesign.usedWallSections;
                    int sectionCount = usedWallSections.Count;
                    for (int u = 0; u < sectionCount; u++)
                    {
                        submeshLibrary.Add(usedWallSections[u]);
                    }
                }

                if (this[p].isGabled && this[p].gableStyle != null)
                {
                    submeshLibrary.Add(this[p].gableStyle.surface);
                }
            }

            submeshLibrary.Add(roof.mainSurface);
            submeshLibrary.Add(roof.wallSurface);
            submeshLibrary.Add(roof.floorSurface);

            submeshLibrary.Add(roof.wallSection);

            submeshLibrary.Add(_undersideSurafce);
        }
コード例 #2
0
        public void CalculateSubmeshes(SubmeshLibrary submeshLibrary)
        {
            for (int v = 0; v < numberOfVolumes; v++)
            {
                IVolume volume         = this[v];
                int     numberOfPoints = volume.numberOfPoints;
                for (int p = 0; p < numberOfPoints; p++)
                {
                    Facade facadeDesign = volume.GetFacade(p);
                    if (facadeDesign != null)
                    {
                        submeshLibrary.Add(facadeDesign.stringCourseSurface);

                        List <WallSection> usedWallSections = facadeDesign.usedWallSections;
                        int sectionCount = usedWallSections.Count;
                        for (int u = 0; u < sectionCount; u++)
                        {
                            submeshLibrary.Add(usedWallSections[u]);
                        }
                    }

                    if (volume[p].isGabled && volume[p].gableStyle != null)
                    {
                        submeshLibrary.Add(volume[p].gableStyle.surface);
                    }
                }

                submeshLibrary.Add(volume.roof.mainSurface);
                submeshLibrary.Add(volume.roof.wallSurface);
                submeshLibrary.Add(volume.roof.floorSurface);

                submeshLibrary.Add(volume.roof.wallSection);
            }
        }
コード例 #3
0
ファイル: PortalEditor.cs プロジェクト: ishui/unity3DScripts
        private void OnEnable()
        {
            _portal = (Portal)target;
            _plane  = Primitives.Plane(10);
            //            _mat = AssetDatabase.LoadAssetAtPath<Material>("Assets/BuildR2/Materials/Blueprint.mat");

            if (_submeshLibrary == null)
            {
                _submeshLibrary = new SubmeshLibrary();
            }
            _submeshLibrary.Clear();
            _submeshLibrary.Add(_portal);
            _portal.UpdatePreviewMesh(_submeshLibrary);
        }
コード例 #4
0
        public static void Portal(ref BuildRMesh dynamicMesh, Portal portal, Vector2 size, Vector3 offset, bool interior = true, SubmeshLibrary submeshLibrary = null)
        {
            if (submeshLibrary == null)
            {
                submeshLibrary = new SubmeshLibrary();
                submeshLibrary.Add(portal);
            }

            Division root = portal.root;

            List <Panel> processNodes           = new List <Panel>();
            Dictionary <Panel, Panel[]> dataDic = new Dictionary <Panel, Panel[]>();
            List <Panel> data      = new List <Panel>();
            Panel        rootPanel = new Panel(root, new Rect(0, 0, size.x, size.y), 0);

            processNodes.Add(rootPanel);
            float totalDepth = 0;

            while (processNodes.Count > 0)
            {
                Panel           current    = processNodes[0];
                Division        division   = current.division;
                List <Division> children   = division.GetChildren;
                int             childCount = children.Count;

                data.Add(current);//dump processed node into data.
                dataDic.Add(current, new Panel[childCount]);
                if (current.recess > totalDepth)
                {
                    totalDepth = current.recess;
                }

                float childRatio = 0;
                for (int c = 0; c < childCount; c++)
                {
                    childRatio += children[c].size;
                }

                for (int c = 0; c < childCount; c++)
                {
                    Division child        = children[c];
                    Rect     newPanelrect = current.rect;
                    float    ratio        = children[c].size / childRatio;

                    if (division.divisionType == BuildR2.Portal.DivisionTypes.Horizontal)
                    {
                        newPanelrect.width  = Mathf.Max(newPanelrect.width - division.frame * 2 - division.frame * (childCount - 1), 0) * ratio;
                        newPanelrect.height = Mathf.Max(newPanelrect.height - division.frame * 2, 0);
                        if (c > 0)
                        {
                            Panel lastPanel = processNodes[processNodes.Count - 1];
                            newPanelrect.x = lastPanel.rect.xMax + division.frame;
                        }
                        else
                        {
                            newPanelrect.x = current.rect.xMin + division.frame;
                        }
                        newPanelrect.y = current.rect.yMin + division.frame;
                    }
                    else
                    {
                        newPanelrect.width  = Mathf.Max(newPanelrect.width - division.frame * 2, 0);
                        newPanelrect.height = Mathf.Max(newPanelrect.height - division.frame * 2 - division.frame * (childCount - 1), 0) * ratio;
                        if (c > 0)
                        {
                            Panel lastPanel = processNodes[processNodes.Count - 1];
                            newPanelrect.y = lastPanel.rect.y + lastPanel.rect.height + division.frame;
                        }
                        else
                        {
                            newPanelrect.y = current.rect.yMin + division.frame;
                        }
                        newPanelrect.x = current.rect.xMin + division.frame;
                    }

                    Panel childPanel = new Panel(child, newPanelrect, current.recess + division.recess);
                    dataDic[current][c] = childPanel;

                    processNodes.Add(childPanel);
                }

                processNodes.RemoveAt(0);
            }

            int     dataCount      = data.Count;
            Vector3 norm           = Vector3.back;
            Vector4 tangent        = BuildRMesh.CalculateTangent(Vector3.right);
            Vector4 tangentForward = BuildRMesh.CalculateTangent(Vector3.forward);
            Vector4 tangentBack    = BuildRMesh.CalculateTangent(Vector3.back);
            Vector4 tangentInvert  = BuildRMesh.CalculateTangent(Vector3.left);
            Vector3 useOffset      = size * 0.5f;

            useOffset  += offset;
            useOffset.y = -useOffset.y;//inverse - UX resaons
            for (int i = 0; i < dataCount; i++)
            {
                Panel    panel    = data[i];
                Division division = panel.division;

                Rect panelRect = panel.rect;

                if (panelRect.width == 0 || panelRect.height == 0)
                {
                    continue;
                }

                Vector3 v0 = new Vector3(panelRect.xMin, -panelRect.yMin, panel.recess) - useOffset;
                Vector3 v1 = new Vector3(panelRect.xMax, -panelRect.yMin, panel.recess) - useOffset;
                Vector3 v2 = new Vector3(panelRect.xMin, -panelRect.yMax, panel.recess) - useOffset;
                Vector3 v3 = new Vector3(panelRect.xMax, -panelRect.yMax, panel.recess) - useOffset;

                Surface usedSurface = GetSurface(portal, division);
                int     useSubmesh  = submeshLibrary.SubmeshAdd(usedSurface);
//                int useSubmesh = usedSurface != null ? Array.IndexOf(usedSurfaces, usedSurface) : 0;

                Vector2 uv0 = CalculateUV(usedSurface, v0);
                Vector2 uv1 = CalculateUV(usedSurface, v1);
                Vector2 uv2 = CalculateUV(usedSurface, v2);
                Vector2 uv3 = CalculateUV(usedSurface, v3);

                if (!division.hasChildren)//simple panel
                {
                    Vector3[] verts    = { v0, v1, v2, v3 };
                    Vector2[] uvs      = { uv0, uv1, uv2, uv3 };
                    int[]     tris     = { 0, 1, 2, 1, 3, 2 };
                    Vector3[] norms    = { norm, norm, norm, norm };
                    Vector4[] tangents = { tangent, tangent, tangent, tangent };
                    dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh);

                    if (interior)
                    {
                        Vector3 interiorOffset = new Vector3(0, 0, (totalDepth - panel.recess) * 2);
                        verts    = new[] { v0 + interiorOffset, v1 + interiorOffset, v2 + interiorOffset, v3 + interiorOffset };
                        uvs      = new[] { uv1, uv0, uv3, uv2 };
                        tris     = new[] { 0, 2, 1, 1, 2, 3 };
                        norms    = new[] { -norm, -norm, -norm, -norm };
                        tangents = new[] { tangentInvert, tangentInvert, tangentInvert, tangentInvert };

                        dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh);
                    }
                }
                else//build a frame
                {
                    Vector3 v0f = v0 + new Vector3(division.frame, -division.frame, 0);
                    Vector3 v1f = v1 + new Vector3(-division.frame, -division.frame, 0);
                    Vector3 v2f = v2 + new Vector3(division.frame, division.frame, 0);
                    Vector3 v3f = v3 + new Vector3(-division.frame, division.frame, 0);

                    Vector3 recessV = Vector3.forward * (division.recess);
                    Vector3 v0r     = v0f + recessV;
                    Vector3 v1r     = v1f + recessV;
                    Vector3 v2r     = v2f + recessV;
                    Vector3 v3r     = v3f + recessV;

                    Vector2 uv0f = CalculateUV(usedSurface, v0f);
                    Vector2 uv1f = CalculateUV(usedSurface, v1f);
                    Vector2 uv2f = CalculateUV(usedSurface, v2f);
                    Vector2 uv3f = CalculateUV(usedSurface, v3f);

//                    Vector2 uv0r = CalculateUV(usedSurface, v0r);
//                    Vector2 uv1r = CalculateUV(usedSurface, v1r);
//                    Vector2 uv2r = CalculateUV(usedSurface, v2r);
//                    Vector2 uv3r = CalculateUV(usedSurface, v3r);

                    Vector3[] verts =
                    {
                        v0,  v1,  v2,  v3,
                        v0f, v1f, v2f, v3f
                    };
                    Vector2[] uvs =
                    {
                        uv0,  uv1,  uv2,  uv3,
                        uv0f, uv1f, uv2f, uv3f
                    };
                    Vector3[] norms =
                    {
                        norm, norm, norm, norm,
                        norm, norm, norm, norm
                    };
                    Vector4[] tangents =
                    {
                        tangent, tangent, tangent, tangent,
                        tangent, tangent, tangent, tangent
                    };

                    int[] tris =
                    {
                        0, 4, 2, 4, 6, 2,            //left
                        0, 1, 4, 1, 5, 4,            //top
                        5, 1, 3, 5, 3, 7,            //right
                        2, 6, 3, 3, 6, 7,            //bottom
                    };

                    dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh);
                    Vector2 uvUp    = CalculateUV(usedSurface, new Vector2(0, division.recess));
                    Vector2 uvRight = CalculateUV(usedSurface, new Vector2(division.recess, 0));
                    dynamicMesh.AddPlaneComplex(v1f, v0f, v1r, v0r, uv1f, uv0f, uv1f + uvUp, uv0f + uvUp, Vector3.down, tangent, useSubmesh, usedSurface);               //top
                    dynamicMesh.AddPlaneComplex(v2f, v3f, v2r, v3r, uv2f, uv3f, uv2f + uvUp, uv3f + uvUp, Vector3.up, tangent, useSubmesh, usedSurface);                 //bottom
                    dynamicMesh.AddPlaneComplex(v0f, v2f, v0r, v2r, uv0f, uv2f, uv0f + uvRight, uv2f + uvRight, Vector3.right, tangentForward, useSubmesh, usedSurface); //left
                    dynamicMesh.AddPlaneComplex(v3f, v1f, v3r, v1r, uv3f, uv1f, uv3f + uvRight, uv1f + uvRight, Vector3.left, tangentBack, useSubmesh, usedSurface);     //right

                    if (interior)
                    {
                        Vector3 interiorOffset  = new Vector3(0, 0, (totalDepth - panel.recess) * 2);
                        Vector3 interiorOffsetr = new Vector3(0, 0, (totalDepth - panel.recess - division.recess) * 2);
                        verts = new[] { v0 + interiorOffset, v1 + interiorOffset, v2 + interiorOffset, v3 + interiorOffset, v0f + interiorOffset, v1f + interiorOffset, v2f + interiorOffset, v3f + interiorOffset };
                        uvs   = new [] { uv1, uv0, uv3, uv2, uv1f, uv0f, uv3f, uv2f };
                        Array.Reverse(tris);
                        norms    = new[] { -norm, -norm, -norm, -norm, -norm, -norm, -norm, -norm };
                        tangents = new[] { tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert };

                        dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh);
                        dynamicMesh.AddPlaneComplex(v0f + interiorOffset, v1f + interiorOffset, v0r + interiorOffsetr, v1r + interiorOffsetr, uv0f, uv1f, uv0f + uvUp, uv1f + uvUp, Vector3.down, tangentInvert, useSubmesh, usedSurface);        //top
                        dynamicMesh.AddPlaneComplex(v3f + interiorOffset, v2f + interiorOffset, v3r + interiorOffsetr, v2r + interiorOffsetr, uv3f, uv2f, uv3f + uvUp, uv2f + uvUp, Vector3.up, tangentInvert, useSubmesh, usedSurface);          //bottom
                        dynamicMesh.AddPlaneComplex(v2f + interiorOffset, v0f + interiorOffset, v2r + interiorOffsetr, v0r + interiorOffsetr, uv2f, uv0f, uv2f + uvRight, uv0f + uvRight, Vector3.right, tangentBack, useSubmesh, usedSurface);   //left
                        dynamicMesh.AddPlaneComplex(v3f + interiorOffset, v3f + interiorOffset, v3r + interiorOffsetr, v3r + interiorOffsetr, uv1f, uv3f, uv1f + uvRight, uv3f + uvRight, Vector3.left, tangentForward, useSubmesh, usedSurface); //right
                    }

                    List <Division> children   = division.GetChildren;
                    int             childCount = children.Count;
                    if (childCount > 1 && division.frame > 0)
                    {
                        for (int c = 0; c < childCount - 1; c++)
                        {
                            Panel childPanel = dataDic[panel][c];
                            if (division.divisionType == BuildR2.Portal.DivisionTypes.Horizontal)
                            {
                                Vector3 v0d = v0 + new Vector3(childPanel.rect.xMax - panelRect.xMin, -division.frame, 0);
                                Vector3 v1d = v0d + new Vector3(division.frame, 0, 0);
                                Vector3 v2d = v0d + new Vector3(0, -panelRect.height + division.frame * 2, 0);
                                Vector3 v3d = v1d + new Vector3(0, -panelRect.height + division.frame * 2, 0);

                                Vector2 uv0d = CalculateUV(usedSurface, v0d);
                                Vector2 uv1d = CalculateUV(usedSurface, v1d);
                                Vector2 uv2d = CalculateUV(usedSurface, v2d);
                                Vector2 uv3d = CalculateUV(usedSurface, v3d);

                                dynamicMesh.AddPlaneComplex(v1d, v0d, v3d, v2d, uv0d, uv1d, uv2d, uv3d, norm, tangent, useSubmesh, usedSurface);                                                      //divider face

                                dynamicMesh.AddPlaneComplex(v2d, v0d, v2d + recessV, v0d + recessV, uv2d, uv0d, uv2d + uvRight, uv0d + uvRight, Vector3.left, tangentBack, useSubmesh, usedSurface);  //divider left
                                dynamicMesh.AddPlaneComplex(v1d, v3d, v1d + recessV, v3d + recessV, uv1d, uv3d, uv1d - uvRight, uv3d - uvRight, Vector3.right, tangentBack, useSubmesh, usedSurface); //divider right

                                if (interior)
                                {
                                    Vector3 interiorOffset  = new Vector3(0, 0, (totalDepth - panel.recess) * 2);
                                    Vector3 interiorOffsetr = new Vector3(0, 0, (totalDepth - panel.recess - division.recess) * 2);
                                    dynamicMesh.AddPlaneComplex(v0d + interiorOffset, v1d + interiorOffset, v2d + interiorOffset, v3d + interiorOffset, uv1d, uv0d, uv3d, uv2d, -norm, tangentInvert, useSubmesh, usedSurface);                                                    //divider face
                                    dynamicMesh.AddPlaneComplex(v0d + interiorOffset, v2d + interiorOffset, v0d + recessV + interiorOffsetr, v2d + recessV + interiorOffsetr, uv0d, uv2d, uv0d + uvRight, uv2d + uvRight, Vector3.left, tangentForward, useSubmesh, usedSurface);  //divider left
                                    dynamicMesh.AddPlaneComplex(v3d + interiorOffset, v1d + interiorOffset, v3d + recessV + interiorOffsetr, v1d + recessV + interiorOffsetr, uv3d, uv1d, uv3d - uvRight, uv1d - uvRight, Vector3.right, tangentForward, useSubmesh, usedSurface); //divider right
                                }
                            }
                            else
                            {
                                Vector3 v0d = v0 + new Vector3(division.frame, -childPanel.rect.yMax + panelRect.yMin, 0);
                                Vector3 v1d = v0d + new Vector3(0, -division.frame, 0);
                                Vector3 v2d = v0d + new Vector3(panelRect.width - division.frame * 2, 0, 0);
                                Vector3 v3d = v1d + new Vector3(panelRect.width - division.frame * 2, 0, 0);

                                Vector2 uv0d = CalculateUV(usedSurface, v0d);
                                Vector2 uv1d = CalculateUV(usedSurface, v1d);
                                Vector2 uv2d = CalculateUV(usedSurface, v2d);
                                Vector2 uv3d = CalculateUV(usedSurface, v3d);

                                dynamicMesh.AddPlaneComplex(v0d, v1d, v2d, v3d, uv0d, uv1d, uv2d, uv3d, norm, tangent, useSubmesh, usedSurface);                                           //divider face

                                dynamicMesh.AddPlaneComplex(v0d, v2d, v0d + recessV, v2d + recessV, uv0d, uv2d, uv0d + uvUp, uv2d + uvUp, Vector3.up, tangent, useSubmesh, usedSurface);   //divider top
                                dynamicMesh.AddPlaneComplex(v3d, v1d, v3d + recessV, v1d + recessV, uv3d, uv1d, uv3d - uvUp, uv1d - uvUp, Vector3.down, tangent, useSubmesh, usedSurface); //divider bottom

                                if (interior)
                                {
                                    Vector3 interiorOffset  = new Vector3(0, 0, (totalDepth - panel.recess) * 2);
                                    Vector3 interiorOffsetr = new Vector3(0, 0, (totalDepth - panel.recess - division.recess) * 2);
                                    dynamicMesh.AddPlaneComplex(v1d + interiorOffset, v0d + interiorOffset, v3d + interiorOffset, v2d + interiorOffset, uv1d, uv0d, uv3d, uv2d, -norm, tangentInvert, useSubmesh, usedSurface);                                            //divider face
                                    dynamicMesh.AddPlaneComplex(v2d + interiorOffset, v0d + interiorOffset, v2d + recessV + interiorOffsetr, v0d + recessV + interiorOffsetr, uv2d, uv0d, uv2d + uvUp, uv0d + uvUp, Vector3.up, tangentInvert, useSubmesh, usedSurface);   //divider top
                                    dynamicMesh.AddPlaneComplex(v1d + interiorOffset, v3d + interiorOffset, v1d + recessV + interiorOffsetr, v3d + recessV + interiorOffsetr, uv1d, uv3d, uv1d - uvUp, uv3d - uvUp, Vector3.down, tangentInvert, useSubmesh, usedSurface); //divider bottom
                                }
                            }
                        }
                    }
                }
            }
        }
コード例 #5
0
        public static void Generate(IBuilding building, IVolume volume, IFloorplan floorplan, int volumeFloor, VerticalOpening[] openings, BuildRMesh mesh, BuildRCollider collider)
        {
            SubmeshLibrary submeshLibrary = mesh.submeshLibrary;

            bool           generateColliders     = building.colliderType != BuildingColliderTypes.None;
            bool           generateMeshColliders = building.colliderType != BuildingColliderTypes.Primitive && generateColliders;
            BuildRCollider sendCollider          = (generateColliders) ? collider : null;

            collider.thickness = volume.wallThickness;
            if (!generateMeshColliders)
            {
                collider = null;
            }

            float   wallThickness = volume.wallThickness;
            float   wallUp        = volume.floorHeight - wallThickness;
            Vector3 wallUpV       = Vector3.up * wallUp;
            Vector3 floorBaseV    = Vector3.up * volume.baseHeight;

            int roomCount = floorplan.RoomCount;

            int actualFloor  = building.VolumeBaseFloor(volume) + volumeFloor;
            int openingCount = openings.Length;

            bool[]       openingBelow           = new bool[openingCount];
            bool[]       openingAbove           = new bool[openingCount];
            FlatBounds[] openingBounds          = new FlatBounds[openingCount];
            Vector2[][]  openingShapes          = new Vector2[openingCount][];
            bool[]       openingUsedInThisFloor = new bool[openingCount];
            for (int o = 0; o < openingCount; o++)
            {
                VerticalOpening opening = openings[o];
                if (!openings[o].FloorIsIncluded(actualFloor))
                {
                    continue;
                }
                openingBelow[o]  = opening.FloorIsIncluded(actualFloor - 1);
                openingAbove[o]  = opening.FloorIsIncluded(actualFloor + 1);
                openingShapes[o] = opening.PointsRotated();
                openingBounds[o] = new FlatBounds(openingShapes[o]);

                submeshLibrary.Add(opening.surfaceA);
                submeshLibrary.Add(opening.surfaceB);
                submeshLibrary.Add(opening.surfaceC);
                submeshLibrary.Add(opening.surfaceD);
            }

            Dictionary <int, List <Vector2Int> > externalWallAnchors = volume.facadeWallAnchors;

            Room[] rooms = floorplan.AllRooms();
            for (int r = 0; r < roomCount; r++)
            {
                Room room       = rooms[r];
                int  pointCount = room.numberOfPoints;

                Surface floorSurface   = null;
                Surface wallSurface    = null;
                Surface ceilingSurface = null;

                if (room.style != null)
                {
                    RoomStyle style = room.style;
                    floorSurface   = style.floorSurface;
                    wallSurface    = style.wallSurface;
                    ceilingSurface = style.ceilingSurface;
                }

                int floorSubmesh   = submeshLibrary.SubmeshAdd(floorSurface);
                int wallSubmesh    = submeshLibrary.SubmeshAdd(wallSurface);
                int ceilingSubmesh = submeshLibrary.SubmeshAdd(ceilingSurface);

                FloorplanUtil.RoomWall[] walls = FloorplanUtil.CalculatePoints(room, volume);
                Vector2[] roomArchorPoints     = FloorplanUtil.RoomArchorPoints(walls);

                Vector4 tangent = BuildRMesh.CalculateTangent(Vector3.right);

                Vector2[] offsetRoomAnchorPoints = QuickPolyOffset.Execute(roomArchorPoints, wallThickness);

                FlatBounds             roomBounds   = new FlatBounds(offsetRoomAnchorPoints);
                List <Vector2[]>       floorCuts    = new List <Vector2[]>();
                List <Vector2[]>       ceilingCuts  = new List <Vector2[]>();
                List <VerticalOpening> roomOpenings = new List <VerticalOpening>();
                for (int o = 0; o < openingCount; o++)
                {
                    if (openings[o].FloorIsIncluded(actualFloor))
                    {
                        if (roomBounds.Overlaps(openingBounds[o]))
                        {
                            if (CheckShapeWithinRoom(offsetRoomAnchorPoints, openingShapes[o]))
                            {
                                if (openingBelow[o])
                                {
                                    floorCuts.Add(openingShapes[o]);
                                }
                                if (openingAbove[o])
                                {
                                    ceilingCuts.Add(openingShapes[o]);
                                }
                                if (openingAbove[o] || openingBelow[o])
                                {
                                    roomOpenings.Add(openings[o]);
                                    openingUsedInThisFloor[o] = true;
                                }
                            }
                        }
                    }
                }

                int offsetPointBase = 0;
                for (int p = 0; p < pointCount; p++)//generate room walls
                {
                    FloorplanUtil.RoomWall wall = walls[p];
                    int wallPointCount          = wall.offsetPoints.Length;

                    List <RoomPortal> wallPortals = floorplan.GetWallPortals(room, p);
                    int wallPortalCount           = wallPortals.Count;

                    if (!wall.isExternal)
                    {
                        int     indexA    = offsetPointBase;
                        int     indexB    = (offsetPointBase + 1) % roomArchorPoints.Length;
                        Vector2 origBaseA = roomArchorPoints[indexA];
                        Vector2 origBaseB = roomArchorPoints[indexB];
                        Vector2 baseA     = offsetRoomAnchorPoints[indexA];
                        Vector2 baseB     = offsetRoomAnchorPoints[indexB];
                        Vector3 v0        = new Vector3(origBaseA.x, 0, origBaseA.y) + floorBaseV;
                        Vector3 v1        = new Vector3(origBaseB.x, 0, origBaseB.y) + floorBaseV;
                        Vector3 vOffset0  = new Vector3(baseA.x, 0, baseA.y) + floorBaseV;
                        Vector3 vOffset1  = new Vector3(baseB.x, 0, baseB.y) + floorBaseV;
                        if (wallPortalCount == 0)  //just draw the wall - no portals to cut

                        {
                            Vector3 v2 = vOffset1 + wallUpV;
                            Vector3 v3 = vOffset0 + wallUpV;

                            Vector2 minUV = Vector2.zero;
                            Vector2 maxUV = new Vector2(Vector2.Distance(baseA, baseB), wallUp);
                            if (wallSurface != null)
                            {
                                maxUV = wallSurface.CalculateUV(maxUV);
                            }
                            Vector3 wallDir     = (vOffset0 - vOffset1).normalized;
                            Vector3 wallNormal  = Vector3.Cross(Vector3.up, wallDir);
                            Vector4 wallTangent = BuildRMesh.CalculateTangent(wallDir);
                            mesh.AddPlane(vOffset1, vOffset0, v2, v3, minUV, maxUV, wallNormal, wallTangent, wallSubmesh, wallSurface);

                            if (generateColliders)
                            {
                                collider.AddPlane(vOffset1, vOffset0, v2, v3);
                            }
                        }
                        else
                        {
                            List <float> useLaterals = new List <float>();
                            List <bool>  hasPortals  = new List <bool>();
                            for (int wp = 0; wp < wallPortalCount; wp++)
                            {
                                RoomPortal portal    = wallPortals[wp];
                                bool       hasPortal = room.HasPortal(portal);
                                hasPortals.Add(hasPortal);
                                if (hasPortal)
                                {
                                    useLaterals.Add(portal.lateralPosition);
                                }
                                else
                                {
                                    useLaterals.Add(1 - portal.lateralPosition);//portal from other wall - wall orientation is flipped
                                }
                            }

                            Vector3 wallVector               = vOffset1 - vOffset0;
                            Vector3 wallDirection            = wallVector.normalized;
                            Vector3 wallStart                = vOffset0;
                            Vector4 wallTangent              = BuildRMesh.CalculateTangent(wallDirection);
                            Vector3 wallNormal               = Vector3.Cross(Vector3.up, wallDirection);
                            Vector4 wallNormalTangent        = BuildRMesh.CalculateTangent(wallNormal);
                            Vector4 wallNormalTangentReverse = BuildRMesh.CalculateTangent(-wallNormal);

                            while (wallPortalCount > 0)
                            {
                                int        portalIndex = 0;
                                RoomPortal usePortal   = wallPortals[0];
                                float      lowestLat   = useLaterals[0];
                                for (int wp = 1; wp < wallPortalCount; wp++)
                                {
                                    if (useLaterals[wp] < lowestLat)
                                    {
                                        portalIndex = wp;
                                        usePortal   = wallPortals[wp];
                                        lowestLat   = useLaterals[wp];
                                    }
                                }

                                wallPortals.RemoveAt(portalIndex);
                                useLaterals.RemoveAt(portalIndex);
                                wallPortalCount--;

                                Vector3 vl0 = v0 + (-wallNormal + wallDirection) * wallThickness;
                                Vector3 vl1 = v1 + (-wallNormal - wallDirection) * wallThickness;

                                Vector3 portalCenter     = Vector3.Lerp(vl0, vl1, lowestLat);
                                Vector3 portalHalfvector = wallDirection * (usePortal.width * 0.5f);
                                Vector3 portalBase       = Vector3.up * (volume.floorHeight - usePortal.height) * usePortal.verticalPosition;
                                Vector3 portalUp         = portalBase + Vector3.up * usePortal.height;
                                Vector3 portalStart      = portalCenter - portalHalfvector;
                                Vector3 portalEnd        = portalCenter + portalHalfvector;

                                Vector2 initalWallUVMin = new Vector2(Vector3.Dot(portalStart, wallDirection), 0);
                                Vector2 initalWallUVMax = new Vector2(Vector3.Dot(wallStart, wallDirection), wallUp);
                                mesh.AddPlane(portalStart, wallStart, portalStart + wallUpV, wallStart + wallUpV, initalWallUVMin, initalWallUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//initial wall
                                if (generateColliders)
                                {
                                    collider.AddPlane(portalStart, wallStart, portalStart + wallUpV, wallStart + wallUpV);
                                }
                                if (usePortal.verticalPosition > 0)
                                {
                                    Vector2 portalBaseUVMin = new Vector2(Vector3.Dot(portalEnd, wallDirection), 0);
                                    Vector2 portalBaseUVMax = new Vector2(Vector3.Dot(portalStart, wallDirection), portalBase.y);
                                    mesh.AddPlane(portalEnd, portalStart, portalEnd + portalBase, portalStart + portalBase, portalBaseUVMin, portalBaseUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//bottom
                                    if (generateColliders)
                                    {
                                        collider.AddPlane(portalEnd, portalStart, portalEnd + portalBase, portalStart + portalBase);
                                    }
                                }
                                if (usePortal.verticalPosition < 1)
                                {
                                    Vector2 portalBaseUVMin = new Vector2(Vector3.Dot(portalEnd, wallDirection), portalUp.y);
                                    Vector2 portalBaseUVMax = new Vector2(Vector3.Dot(portalStart, wallDirection), wallUp);
                                    mesh.AddPlane(portalEnd + portalUp, portalStart + portalUp, portalEnd + wallUpV, portalStart + wallUpV, portalBaseUVMin, portalBaseUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//top
                                    if (generateColliders)
                                    {
                                        collider.AddPlane(portalEnd + portalUp, portalStart + portalUp, portalEnd + wallUpV, portalStart + wallUpV);
                                    }
                                }

                                if (hasPortals[portalIndex])//only do this once - from the room it's attached to
                                {
                                    //portal interior frame
                                    Vector3 portalDepth = wallNormal * wallThickness * 2;

                                    //sides
                                    mesh.AddPlane(portalStart + portalDepth + portalBase, portalStart + portalBase, portalStart + portalDepth + portalUp, portalStart + portalUp, wallDirection, wallNormalTangentReverse, wallSubmesh);
                                    mesh.AddPlane(portalEnd + portalBase, portalEnd + portalDepth + portalBase, portalEnd + portalUp, portalEnd + portalDepth + portalUp, -wallDirection, wallNormalTangent, wallSubmesh);

                                    if (generateMeshColliders)
                                    {
                                        collider.AddPlane(portalStart + portalDepth + portalBase, portalStart + portalBase, portalStart + portalDepth + portalUp, portalStart + portalUp);
                                        collider.AddPlane(portalEnd + portalBase, portalEnd + portalDepth + portalBase, portalEnd + portalUp, portalEnd + portalDepth + portalUp);
                                    }

                                    //floor
                                    Vector2 minFloorUv = new Vector2((portalEnd + portalBase).z, (portalEnd + portalBase).x);
                                    Vector2 maxFloorUv = minFloorUv + new Vector2(wallThickness, usePortal.width);
                                    mesh.AddPlane(portalStart + portalBase, portalStart + portalDepth + portalBase, portalEnd + portalBase, portalEnd + portalDepth + portalBase, minFloorUv, maxFloorUv, Vector3.up, wallTangent, floorSubmesh, floorSurface);
                                    if (generateMeshColliders)
                                    {
                                        collider.AddPlane(portalStart + portalBase, portalStart + portalDepth + portalBase, portalEnd + portalBase, portalEnd + portalDepth + portalBase);
                                    }

                                    //ceiling
                                    mesh.AddPlane(portalEnd + portalUp, portalEnd + portalDepth + portalUp, portalStart + portalUp, portalStart + portalDepth + portalUp, Vector3.down, wallTangent, wallSubmesh);
                                    if (generateMeshColliders)
                                    {
                                        collider.AddPlane(portalEnd + portalUp, portalEnd + portalDepth + portalUp, portalStart + portalUp, portalStart + portalDepth + portalUp);
                                    }
                                }

                                wallStart = portalEnd;//move the start for the next calculation
                            }

                            Vector2 finalWallUVMin = new Vector2(Vector3.Dot(vOffset1, wallDirection), 0);
                            Vector2 finalWallUVMax = new Vector2(Vector3.Dot(wallStart, wallDirection), wallUp);
                            mesh.AddPlane(vOffset1, wallStart, vOffset1 + wallUpV, wallStart + wallUpV, finalWallUVMin, finalWallUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//final wall section
                            if (generateColliders)
                            {
                                collider.AddPlane(vOffset1, wallStart, vOffset1 + wallUpV, wallStart + wallUpV);
                            }
                        }
                        offsetPointBase += 1;
                    }
                    else//external anchored wall
                    {
                        int    facadeIndex  = wall.facadeIndex;
                        Facade facadeDesign = volume.GetFacade(facadeIndex);
                        int    currentFacadeWallSectionLength = externalWallAnchors[facadeIndex].Count - 1;
                        int    currentWallSectionIndex        = wall.offsetPointWallSection[0];
                        int    wallOffsetPoints = wall.offsetPoints.Length;
                        for (int w = 0; w < wallOffsetPoints - 1; w++)
                        {
                            int     roomPointIndex   = offsetPointBase + w;
                            Vector2 baseA            = offsetRoomAnchorPoints[roomPointIndex];
                            int     offsetIndexB     = (roomPointIndex + 1) % offsetRoomAnchorPoints.Length;
                            Vector2 baseB            = offsetRoomAnchorPoints[offsetIndexB];
                            Vector3 v0               = new Vector3(baseA.x, 0, baseA.y) + floorBaseV;
                            Vector3 v1               = new Vector3(baseB.x, 0, baseB.y) + floorBaseV;
                            int     wallSectionIndex = wall.offsetPointWallSection[w];

                            bool canGenerateWallSection = facadeDesign != null;

                            Vector3 wallVector = v0 - v1;
                            Vector3 wallDir    = wallVector.normalized;
                            float   wallLength = wallVector.magnitude;

                            if (!canGenerateWallSection)
                            {
                                if (wallSurface != null)
                                {
                                    submeshLibrary.Add(wallSurface);
                                }

                                Vector3 v2 = v1 + wallUpV;
                                Vector3 v3 = v0 + wallUpV;

                                Vector2 minUV       = Vector2.zero;
                                Vector2 maxUV       = new Vector2(Vector2.Distance(baseA, baseB), wallUp);
                                Vector3 wallNormal  = Vector3.Cross(Vector3.up, wallDir);
                                Vector4 wallTangent = BuildRMesh.CalculateTangent(wallDir);
                                mesh.AddPlane(v1, v0, v2, v3, minUV, maxUV, wallNormal, wallTangent, wallSubmesh, wallSurface);

                                if (generateMeshColliders)
                                {
                                    collider.AddPlane(v1, v0, v2, v3);
                                }
                            }
                            else
                            {
                                WallSection section = facadeDesign.GetWallSection(wallSectionIndex, volumeFloor, currentFacadeWallSectionLength, volume.floors);
                                if (section.model != null)
                                {
                                    continue;//cannot account for custom meshes assume custom mesh does include interior mesh or if does - will be generated with the exterior
                                }
                                GenerationOutput generatedSection = GenerationOutput.CreateRawOutput();
                                Vector2          wallSectionSize  = new Vector2(wallLength, wallUp + wallThickness);
                                bool             cullOpening      = building.cullDoors && section.isDoor;
                                SubmeshLibrary   sectionLib       = new SubmeshLibrary();

                                if (wallSurface != null)
                                {
                                    sectionLib.Add(wallSurface);//add interior wall surface
                                    submeshLibrary.Add(wallSurface);
                                }

                                sectionLib.Add(section.openingSurface);//add windows - the only surface we'll use in the interior room
                                submeshLibrary.Add(section.openingSurface);

                                float offset = 0;
                                if (w == 0)
                                {
                                    offset = wallThickness;
                                }
                                if (w == wallOffsetPoints - 2)
                                {
                                    offset = -wallThickness;
                                }
                                WallSectionGenerator.Generate(section, generatedSection, wallSectionSize, true, wallThickness, cullOpening, null, sectionLib, offset);
                                int[]   mapping     = submeshLibrary.MapSubmeshes(generatedSection.raw.materials);
                                Vector3 curveNormal = Vector3.Cross(wallDir, Vector3.up);

                                Quaternion meshRot = Quaternion.LookRotation(curveNormal, Vector3.up);
                                Vector3    meshPos = new Vector3(v1.x, volume.baseHeight, v1.z) + wallDir * wallSectionSize.x + Vector3.up * wallSectionSize.y;
                                meshPos += meshRot * -new Vector3(wallSectionSize.x, wallSectionSize.y, 0) * 0.5f;
                                mesh.AddData(generatedSection.raw, mapping, meshPos, meshRot, Vector3.one);
                            }


                            currentWallSectionIndex++;
                            if (currentWallSectionIndex >= currentFacadeWallSectionLength)
                            {
                                //reached the end of the facade - move to the next one and continue
                                currentFacadeWallSectionLength = externalWallAnchors[facadeIndex].Count;
                                currentWallSectionIndex        = 0;
                            }
                        }

                        offsetPointBase += wallPointCount - 1;
                    }
                }

                //FLOOR
                Vector2[]   mainShape      = offsetRoomAnchorPoints;
                Vector2[][] floorCutPoints = floorCuts.ToArray();
                int         floorVertCount = mainShape.Length;
                for (int flc = 0; flc < floorCutPoints.Length; flc++)
                {
                    floorVertCount += floorCutPoints[flc].Length;
                }

                Vector2[] allFloorPoints  = new Vector2[floorVertCount];
                int       mainShapeLength = mainShape.Length;
                for (int ms = 0; ms < mainShapeLength; ms++)
                {
                    allFloorPoints[ms] = mainShape[ms];
                }
                int cutPointIterator = mainShapeLength;
                for (int flc = 0; flc < floorCutPoints.Length; flc++)
                {
                    for (int flcp = 0; flcp < floorCutPoints[flc].Length; flcp++)
                    {
                        allFloorPoints[cutPointIterator] = floorCutPoints[flc][flcp];
                        cutPointIterator++;
                    }
                }

                Vector3[] floorPoints   = new Vector3[floorVertCount];
                Vector2[] floorUvs      = new Vector2[floorVertCount];
                Vector3[] floorNorms    = new Vector3[floorVertCount];
                Vector4[] floorTangents = new Vector4[floorVertCount];
                for (int rp = 0; rp < floorVertCount; rp++)
                {
                    floorPoints[rp] = new Vector3(allFloorPoints[rp].x, 0, allFloorPoints[rp].y) + floorBaseV;
                    Vector2 uv = allFloorPoints[rp];
                    if (floorSurface != null)
                    {
                        uv = floorSurface.CalculateUV(uv);
                    }
                    floorUvs[rp]      = uv;
                    floorNorms[rp]    = Vector3.up;
                    floorTangents[rp] = tangent;
                }

                int[] tris = Poly2TriWrapper.Triangulate(mainShape, true, floorCutPoints);

                mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, floorSubmesh);
                if (generateColliders)
                {
                    collider.mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, 0);
                }

                //CEILING!
                Vector2[][] ceilingCutPoints = ceilingCuts.ToArray();
                int         ceilingVertCount = mainShape.Length;
                for (int flc = 0; flc < ceilingCutPoints.Length; flc++)
                {
                    ceilingVertCount += ceilingCutPoints[flc].Length;
                }

                Vector2[] allCeilingPoints = new Vector2[ceilingVertCount];
                for (int ms = 0; ms < mainShapeLength; ms++)
                {
                    allCeilingPoints[ms] = mainShape[ms];
                }
                cutPointIterator = mainShapeLength;
                for (int flc = 0; flc < ceilingCutPoints.Length; flc++)
                {
                    for (int flcp = 0; flcp < ceilingCutPoints[flc].Length; flcp++)
                    {
                        allCeilingPoints[cutPointIterator] = ceilingCutPoints[flc][flcp];
                        cutPointIterator++;
                    }
                }

                Vector3[] ceilingPoints   = new Vector3[ceilingVertCount];
                Vector2[] ceilingUvs      = new Vector2[ceilingVertCount];
                Vector3[] ceilingNorms    = new Vector3[ceilingVertCount];
                Vector4[] ceilingTangents = new Vector4[ceilingVertCount];
                for (int rp = 0; rp < ceilingVertCount; rp++)
                {
                    ceilingPoints[rp] = new Vector3(allCeilingPoints[rp].x, wallUp, allCeilingPoints[rp].y) + floorBaseV;
                    Vector2 uv = allCeilingPoints[rp];
                    if (floorSurface != null)
                    {
                        uv = ceilingSurface.CalculateUV(uv);
                    }
                    ceilingUvs[rp]      = uv;
                    ceilingNorms[rp]    = Vector3.down;
                    ceilingTangents[rp] = tangent;
                }

                tris = Poly2TriWrapper.Triangulate(mainShape, false, ceilingCutPoints);
                mesh.AddData(ceilingPoints, ceilingUvs, tris, ceilingNorms, ceilingTangents, ceilingSubmesh);
                if (generateColliders)
                {
                    collider.mesh.AddData(ceilingPoints, ceilingUvs, tris, ceilingNorms, ceilingTangents, 0);
                }

                for (int ob = 0; ob < openingCount; ob++)
                {
                    VerticalOpening opening      = openings[ob];
                    int             openingIndex = Array.IndexOf(openings, opening);
                    Vector3         basePosition = openingBounds[openingIndex].center;
                    basePosition.z = basePosition.y;
                    basePosition.y = volume.baseHeight;

                    if (roomOpenings.Contains(opening))//opening used in this floorplan
                    {
                        int externalWallSubmesh = wallSubmesh != -1 ? wallSubmesh : -1;
                        switch (opening.usage)
                        {
                        case VerticalOpening.Usages.Space:
                            if (ceilingCutPoints.Length <= ob)
                            {
                                continue;
                            }
                            Vector3   ceilingCutUpV = Vector3.up * wallThickness;
                            Vector2[] ceilingCut    = ceilingCutPoints[ob];
                            int       custSize      = ceilingCut.Length;
                            for (int cp = 0; cp < custSize; cp++)
                            {
                                int     indexA = (cp + 1) % custSize;
                                int     indexB = cp;
                                Vector3 cp0    = new Vector3(ceilingCut[indexA].x, wallUp, ceilingCut[indexA].y) + floorBaseV;
                                Vector3 cp1    = new Vector3(ceilingCut[indexB].x, wallUp, ceilingCut[indexB].y) + floorBaseV;
                                Vector3 cp2    = cp0 + ceilingCutUpV;
                                Vector3 cp3    = cp1 + ceilingCutUpV;
                                mesh.AddPlane(cp0, cp1, cp2, cp3, ceilingSubmesh);
                                if (generateColliders)
                                {
                                    collider.AddPlane(cp0, cp1, cp2, cp3);
                                }
                            }
                            break;

                        case VerticalOpening.Usages.Stairwell:
                            StaircaseGenerator.Generate(mesh, opening, basePosition, volume.floorHeight, actualFloor, externalWallSubmesh, sendCollider);
                            if (volumeFloor == volume.floors - 1 && opening.baseFloor + opening.floors > building.VolumeBaseFloor(volume) + volume.floors - 1 && volume.abovePlanCount == 0)
                            {
                                StaircaseGenerator.GenerateRoofAccess(mesh, opening, basePosition, volume.floorHeight, actualFloor, externalWallSubmesh, sendCollider);
                            }
                            break;

                        case VerticalOpening.Usages.Elevator:
                            ElevatorShaftGenerator.Generate(ref mesh, opening, actualFloor, basePosition, volume.floorHeight, externalWallSubmesh, sendCollider);
                            break;
                        }
                    }
                }
            }

            for (int ob = 0; ob < openingCount; ob++)
            {
                Vector2[] openingShape = openingShapes[ob];
                if (openingShape == null)
                {
                    continue;                      //opening not used by this floorplan
                }
                if (openingUsedInThisFloor[ob])
                {
                    continue;                            //opening already generated
                }
                //seal this opening from the void
                VerticalOpening opening      = openings[ob];
                int             openingIndex = Array.IndexOf(openings, opening);
                Vector3         basePosition = openingBounds[openingIndex].center;
                basePosition.z = basePosition.y;
                basePosition.y = 0;

                int       cutSize            = openingShape.Length;
                Vector3   sealingWallUpV     = Vector3.up * volume.floorHeight;
                int       sealWallSubmesh    = submeshLibrary.SubmeshAdd(opening.surfaceB);
                Vector2[] offsetOpeningShape = QuickPolyOffset.Execute(openingShape, wallThickness);
                for (int cp = 0; cp < cutSize; cp++)
                {
                    int     indexA = (cp + 1) % cutSize;
                    int     indexB = cp;
                    Vector2 p0     = opening.usage == VerticalOpening.Usages.Space ? openingShape[indexA] : offsetOpeningShape[indexA];
                    Vector2 p1     = opening.usage == VerticalOpening.Usages.Space ? openingShape[indexB] : offsetOpeningShape[indexB];
                    Vector3 cp0    = new Vector3(p0.x, 0, p0.y) + floorBaseV;
                    Vector3 cp1    = new Vector3(p1.x, 0, p1.y) + floorBaseV;
                    Vector3 cp2    = cp0 + sealingWallUpV;
                    Vector3 cp3    = cp1 + sealingWallUpV;
                    mesh.AddPlane(cp0, cp1, cp2, cp3, sealWallSubmesh);
                    if (generateColliders)
                    {
                        collider.AddPlane(cp0, cp1, cp2, cp3);
                    }
                }

                switch (opening.usage)
                {
                case VerticalOpening.Usages.Space:
                    //nothing to implement
                    break;

                case VerticalOpening.Usages.Stairwell:
                    //need stairs to connect used floors
                    StaircaseGenerator.GenerateStairs(mesh, opening, basePosition, volume.floorHeight, actualFloor, -1, sendCollider);
                    if (volumeFloor == volume.floors - 1)
                    {
                        StaircaseGenerator.GenerateRoofAccess(mesh, opening, basePosition, volume.floorHeight, actualFloor, -1, sendCollider);
                    }
                    break;

                case VerticalOpening.Usages.Elevator:
                    //nothing to implement
                    break;
                }
            }
        }