private static GSD.Roads.GSDRoadUtil.Construction2DRect SetDetailCoords(float param,ref Vector3 tVect1,ref Vector3 POS1,ref Vector3 tVect2,ref Vector3 POS2, float Sep, float TreeSep, ref GSD.Roads.GSDTerraforming.TempTerrainData TTD, ref GSDSplineC tSpline)
        {
            Vector3 lVect1far = default(Vector3);
            Vector3 rVect1far = default(Vector3);
            Vector3 lVect2far = default(Vector3);
            Vector3 rVect2far = default(Vector3);

            bool bIsInBridge = tSpline.IsInBridgeTerrain(param);
            bool bIsInTunnel = tSpline.IsInTunnelTerrain(param);
            int x2,y2,x3,y3;
            GetTempHeights_Coordinates(ref tVect1,ref TTD,out x2,out y2);
            if(x2 >= TTD.HM){ x2=-1; }
            if(y2 >= TTD.HM){ y2=-1; }
            if(x2 < 0){ x2=-1; }
            if(y2 < 0){ y2=-1; }
            if(x2 == -1){ return null; }
            if(y2 == -1){ return null; }

            float tDiff1 = ((TTD.heights[x2,y2]*(float)TTD.TerrainSize.y) - tVect1.y);
            GetTempHeights_Coordinates(ref tVect2,ref TTD,out x3,out y3);
            if(x3 >= TTD.HM){ x3=-1; }
            if(y3 >= TTD.HM){ y3=-1; }
            if(x3 < 0){ x3=-1; }
            if(y3 < 0){ y3=-1; }
            if(x3 == -1){ return null; }
            if(y3 == -1){ return null; }
            float tDiff2 = ((TTD.heights[x3,y3]*(float)TTD.TerrainSize.y) - tVect2.y);

            GSD.Roads.GSDRoadUtil.Construction2DRect tRect = null;
            if(tSpline.tRoad.opt_TreeModEnabled){
                bool bQuit = false;
                if(x2 == -1){ bQuit = true; }
                if(y2 == -1){ bQuit = true; }

                if(bIsInBridge && !bQuit){
                    if(tDiff1 < 0f){ tDiff1 *= -1f; }
                    if(tDiff2 < 0f){ tDiff2 *= -1f; }
                    if(tDiff1 > tSpline.tRoad.opt_ClearTreesDistanceHeight){
                        bQuit = true;
                    }
                    if(tDiff2 > tSpline.tRoad.opt_ClearTreesDistanceHeight){
                        bQuit = true;
                    }
                }
                if(bIsInTunnel && !bQuit){
                    if(tDiff1 < 0f){
                        if((tDiff1*-1f) > tSpline.tRoad.opt_ClearTreesDistanceHeight){
                            bQuit = true;
                        }
                    }else{
                        if(tDiff1 > (tSpline.tRoad.opt_ClearTreesDistanceHeight*0.1f)){
                            bQuit = true;
                        }
                    }
                    if(tDiff2 < 0f){
                        if((tDiff2*-1f) > tSpline.tRoad.opt_ClearTreesDistanceHeight){
                            bQuit = true;
                        }
                    }else{
                        if(tDiff2 > (tSpline.tRoad.opt_ClearTreesDistanceHeight*0.1f)){
                            bQuit = true;
                        }
                    }
                }

                if(!bQuit){
                    TreeSep = TreeSep * 0.5f;
                    lVect1far = (tVect1 + new Vector3(TreeSep*-POS1.normalized.z,0,TreeSep*POS1.normalized.x));
                    rVect1far = (tVect1 + new Vector3(TreeSep*POS1.normalized.z,0,TreeSep*-POS1.normalized.x));
                    lVect2far = (tVect2 + new Vector3(TreeSep*-POS2.normalized.z,0,TreeSep*POS2.normalized.x));
                    rVect2far = (tVect2 + new Vector3(TreeSep*POS2.normalized.z,0,TreeSep*-POS2.normalized.x));
                    tRect = new GSD.Roads.GSDRoadUtil.Construction2DRect(new Vector2(lVect1far.x,lVect1far.z),new Vector2(rVect1far.x,rVect1far.z),new Vector2(rVect2far.x,rVect2far.z),new Vector2(lVect2far.x,lVect2far.z),0f);
                }
            }

            if(tSpline.tRoad.opt_DetailModEnabled){
                if(bIsInBridge || bIsInTunnel){
                    if(tDiff1 < 0f){ tDiff1 *= -1f; }
                    if(tDiff2 < 0f){ tDiff2 *= -1f; }

                    bool bQuit = false;
                    if(x2 == -1){ bQuit = true; }
                    if(y2 == -1){ bQuit = true; }

                    if(tDiff1 > tSpline.tRoad.opt_ClearDetailsDistanceHeight){
                        bQuit = true;
                    }
                    if(tDiff2 > tSpline.tRoad.opt_ClearDetailsDistanceHeight){
                        bQuit = true;
                    }

                    if(bQuit){
                        return tRect;
                    }
                }

                Sep = Sep * 0.5f;

                lVect1far = (tVect1 + new Vector3(Sep*-POS1.normalized.z,0,Sep*POS1.normalized.x));
                rVect1far = (tVect1 + new Vector3(Sep*POS1.normalized.z,0,Sep*-POS1.normalized.x));
                lVect2far = (tVect2 + new Vector3(Sep*-POS2.normalized.z,0,Sep*POS2.normalized.x));
                rVect2far = (tVect2 + new Vector3(Sep*POS2.normalized.z,0,Sep*-POS2.normalized.x));

                int[] Xs = new int[4];
                int[] Ys = new int[4];

                int x1,y1;
                GetTempDetails_Coordinates(ref lVect1far,ref TTD,out x1, out y1);
                Xs[0] = x1;
                Ys[0] = y1;
                GetTempDetails_Coordinates(ref lVect2far,ref TTD,out x1, out y1);
                Xs[1] = x1;
                Ys[1] = y1;
                GetTempDetails_Coordinates(ref rVect1far,ref TTD,out x1, out y1);
                Xs[2] = x1;
                Ys[2] = y1;
                GetTempDetails_Coordinates(ref rVect2far,ref TTD,out x1, out y1);
                Xs[3] = x1;
                Ys[3] = y1;
            //
            //				if(TTD.DetailLayersCount == 1 && x1 > 0 && y1 > 0){
            //					Debug.Log(Xs[0]+","+Ys[0] + " " + Xs[1]+","+Ys[1]);
            //				}

                int MinX = Mathf.Min(Xs);
                int MinY = Mathf.Min(Ys);
                int MaxX = Mathf.Max(Xs);
                int MaxY = Mathf.Max(Ys);

                if(MinX >= TTD.DetailMaxIndex){ MinX = TTD.DetailMaxIndex-1; }
                if(MinY >= TTD.DetailMaxIndex){ MinY = TTD.DetailMaxIndex-1; }
                if(MaxX >= TTD.DetailMaxIndex){ MaxX = TTD.DetailMaxIndex-1; }
                if(MaxY >= TTD.DetailMaxIndex){ MaxY = TTD.DetailMaxIndex-1; }

                if(MinX < 0){ MinX = 0; }
                if(MinY < 0){ MinY = 0; }
                if(MaxX < 0){ MaxX = 0; }
                if(MaxY < 0){ MaxY = 0; }

            //				int DetailI = 0;
                if(tSpline.tRoad.bProfiling){ Profiler.BeginSample("Dorectsdetails"); }
                int tInt = 0;
                for(int i=MinX;i<=MaxX;i++){
                    for(int k=MinY;k<=MaxY;k++){
                        //Bitfield for identification:
                        tInt = k;
                        tInt = tInt << 16;
               			 		tInt = tInt | (ushort)i;
                        if(!TTD.DetailHasProcessed.Contains(tInt)){
            //							for(int h=0;h<TTD.DetailLayersCount;h++){
            //								if(TTD.DetailLayersSkip.Contains(h)){ continue; }
            //							if(!TTD.DetailHasProcessed[h][i,k]){// && TTD.DetailValues[h][i,k] > 0){

                            TTD.MainDetailsX.Add((ushort)i);
                            TTD.MainDetailsY.Add((ushort)k);

            //								DetailI = TTD.DetailsI[h];

            //								TTD.DetailsX[h].Add((ushort)i);
            //								TTD.DetailsY[h].Add((ushort)k);

            //								TTD.DetailsX[h][DetailI] = (ushort)i;
            //								TTD.DetailsY[h][DetailI] = (ushort)k;
            //								TTD.OldDetailsValue[h][DetailI] = (ushort)TTD.DetailValues[h][i,k];
            //								TTD.DetailValues[h][i,k] = 0;

            //								TTD.DetailsI[h]+=1;

            //							}
                            TTD.DetailHasProcessed.Add(tInt);
                        }
                    }
                }
                if(tSpline.tRoad.bProfiling){ Profiler.EndSample(); }
            }

            return tRect;
        }
        private static void DoRectsDo(ref GSDSplineC tSpline,ref GSD.Roads.GSDTerraforming.TempTerrainData TTD)
        {
            float Sep = tSpline.tRoad.RoadWidth()*0.5f;
            float HeightSep = Sep + (tSpline.tRoad.opt_MatchHeightsDistance * 0.5f);
            List<TerrainBoundsMaker> TBMList = new List<TerrainBoundsMaker>();
            //			List<GSD.Roads.GSDRoadUtil.Construction3DTri> triList = new List<GSD.Roads.GSDRoadUtil.Construction3DTri>();
            List<GSD.Roads.GSDRoadUtil.Construction2DRect> TreerectList = new List<GSD.Roads.GSDRoadUtil.Construction2DRect>();
            float tStep = tSpline.tRoad.opt_RoadDefinition / tSpline.distance;
            //			tStep *= 0.5f;

            //Start initializing the loop. Convuluted to handle special control nodes, so roads don't get rendered where they aren't supposed to, while still preserving the proper curvature.
            float FinalMax = 1f;
            float StartMin = 0f;
            if(tSpline.bSpecialEndControlNode){	//If control node, start after the control node:
                FinalMax = tSpline.mNodes[tSpline.GetNodeCount()-2].tTime;
            }
            if(tSpline.bSpecialStartControlNode){	//If ends in control node, end construction before the control node:
                StartMin = tSpline.mNodes[1].tTime;
            }
            //			bool bFinalEnd = false;
            //			float RoadConnection_StartMin1 = StartMin;	//Storage of incremental start values for the road connection mesh construction at the end of this function.
            //			float RoadConnection_FinalMax1 = FinalMax; 	//Storage of incremental end values for the road connection mesh construction at the end of this function.
            if(tSpline.bSpecialEndNode_IsStart_Delay){
                StartMin += (tSpline.SpecialEndNodeDelay_Start / tSpline.distance);	//If there's a start delay (in meters), delay the start of road construction: Due to special control nodes for road connections or 3 way intersections.
            }else if(tSpline.bSpecialEndNode_IsEnd_Delay){
                FinalMax -= (tSpline.SpecialEndNodeDelay_End / tSpline.distance);	//If there's a end delay (in meters), cut early the end of road construction: Due to special control nodes for road connections or 3 way intersections.
            }
            //			float RoadConnection_StartMin2 = StartMin;	//Storage of incremental start values for the road connection mesh construction at the end of this function.
            //			float RoadConnection_FinalMax2 = FinalMax; 	//Storage of incremental end values for the road connection mesh construction at the end of this function.

            FinalMax = FinalMax + tStep;

            Vector3 tVect1 = default(Vector3);
            Vector3 tVect2 = default(Vector3);
            Vector3 POS1 = default(Vector3);
            Vector3 POS2 = default(Vector3);
            if(FinalMax > 1f){ FinalMax = 1f; }

            float tNext = 0f;
            float fValue1,fValue2;
            float fValueMod = tSpline.tRoad.opt_RoadDefinition / tSpline.distance;
            bool bIsPastInter = false;
            float tIntStrength = 0f;
            float tIntStrength2 = 0f;
            //			bool bMaxIntersection = false;
            //			bool bFirstInterNode = false;
            GSDSplineN xNode = null;
            float tIntHeight = 0f;
            float tIntHeight2 = 0f;
            GSDRoadIntersection GSDRI = null;
            float T1SUB = 0f;
            float T2SUB = 0f;
            bool bIntStr1_Full = false;
            bool bIntStr1_FullPrev = false;
            bool bIntStr1_FullNext = false;
            bool bIntStr2_Full = false;
            bool bIntStr2_FullPrev = false;
            bool bIntStr2_FullNext = false;
            Vector3 tVect3 = default(Vector3);
            //			bool bStarted = false;
            //			bool T3Added = false;
            List<int[]> tXYs = new List<int[]>();
            float TreeClearDist = tSpline.tRoad.opt_ClearTreesDistance;
            if(TreeClearDist < tSpline.tRoad.RoadWidth()){ TreeClearDist = tSpline.tRoad.RoadWidth(); }
            GSD.Roads.GSDRoadUtil.Construction2DRect tRect = null;
            float tGrade = 0f;
            for(float i=StartMin;i<FinalMax;i+=tStep){
                if(tSpline.tRoad.opt_HeightModEnabled){
                    if(i > 1f){ break; }
                    tNext = i+tStep;
                    if(tNext > 1f){ break; }

                    tSpline.GetSplineValue_Both(i,out tVect1,out POS1);

                    if(tNext <= 1f){
                        tSpline.GetSplineValue_Both(tNext,out tVect2,out POS2);
                    }else{
                        tSpline.GetSplineValue_Both(1f,out tVect2,out POS2);
                    }

                    //Determine if intersection:
                    bIsPastInter = false;	//If past intersection
                    tIntStrength = tSpline.IntersectionStrength(ref tVect1,ref tIntHeight, ref GSDRI, ref bIsPastInter, ref i, ref xNode);
            //					if(IsApproximately(tIntStrength,1f,0.001f) || tIntStrength > 1f){
            //						bMaxIntersection = true;
            //					}else{
            //						bMaxIntersection = false;
            //					}
            //					bFirstInterNode = false;

                    tIntStrength2 = tSpline.IntersectionStrength(ref tVect2,ref tIntHeight2, ref GSDRI, ref bIsPastInter, ref i, ref xNode);
                    if(tIntStrength2 > 1f){ tIntStrength2 = 1f; }

                    T1SUB = tVect1.y;
                    T2SUB = tVect2.y;

                    if(tIntStrength > 1f){ tIntStrength = 1f; }
                    if(tIntStrength >= 0f){// || IsApproximately(tIntStrength,0f,0.01f)){
                        if(IsApproximately(tIntStrength,1f,0.01f)){
                            T1SUB = tIntHeight;
                            bIntStr1_Full = true;
                            bIntStr1_FullNext = false;
                        }else{
                         	bIntStr1_Full = false;
                            bIntStr1_FullNext = (tIntStrength2 >= 1f);
                            if(!IsApproximately(tIntStrength,0f,0.01f)){ T1SUB = (tIntStrength*tIntHeight) + ((1-tIntStrength)*tVect1.y); }
            //						if(tIntStrength <= 0f){ T1SUB = (tIntStrength*tIntHeight) + ((1-tIntStrength)*tVect1.y); }
                        }

                        if((bIntStr1_Full && !bIntStr1_FullPrev) || (!bIntStr1_Full && bIntStr1_FullNext)){
                            tGrade = tSpline.GetCurrentNode(i).GradeToPrevValue;
                            if(tGrade < 0f){
                                T1SUB -= Mathf.Lerp(0.02f,GSDRI.GradeMod,(tGrade/20f)*-1f);
                            }else{
                                T1SUB -= Mathf.Lerp(0.02f,GSDRI.GradeMod,tGrade/20f);
                            }

            //							if(tGrade < 0f){
            //								T1SUB *= -1f;
            //							}
                        }else if(bIntStr1_Full && !bIntStr1_FullNext){
                            tGrade = tSpline.GetCurrentNode(i).GradeToNextValue;
                            if(tGrade < 0f){
                                T1SUB -= Mathf.Lerp(0.02f,GSDRI.GradeMod,(tGrade/20f)*-1f);
                            }else{
                                T1SUB -= Mathf.Lerp(0.02f,GSDRI.GradeMod,tGrade/20f);
                            }
            //							if(tGrade < 0f){
            //								T1SUB *= -1f;
            //							}
                        }else{
                            T1SUB -= 0.02f;
                        }
                        bIntStr1_FullPrev = bIntStr1_Full;
                    }

                    if(tIntStrength2 >= 0f || IsApproximately(tIntStrength2,0f,0.01f)){
            //					if(!IsApproximately(tIntStrength,1f,0.01f)){
                        if(IsApproximately(tIntStrength,1f,0.01f)){
                            bIntStr2_Full = true;
                            T2SUB = tIntHeight2;
                        }else{
                         	bIntStr2_Full = false;
                            if(!IsApproximately(tIntStrength2,0f,0.01f)){ T2SUB = (tIntStrength2*tIntHeight) + ((1-tIntStrength2)*tVect2.y); }
            //						if(tIntStrength2 <= 0f){ T2SUB = (tIntStrength2*tIntHeight) + ((1-tIntStrength2)*tVect2.y); }
                        }

                        if((bIntStr2_Full && !bIntStr2_FullPrev)){
                            tGrade = tSpline.GetCurrentNode(i).GradeToPrevValue;
                            if(tGrade < 0f){
                                T2SUB -= Mathf.Lerp(0.02f,GSDRI.GradeMod,(tGrade/20f)*-1f);
                            }else{
                                T2SUB -= Mathf.Lerp(0.02f,GSDRI.GradeMod,tGrade/20f);
                            }
            //							T2SUB -= tIntHeight2 - tVect2.y;
                        }else if(bIntStr2_Full && !bIntStr2_FullNext){
                            tGrade = tSpline.GetCurrentNode(i).GradeToNextValue;
                            if(tGrade < 0f){
                                T2SUB -= Mathf.Lerp(0.02f,GSDRI.GradeMod,(tGrade/20f)*-1f);
                            }else{
                                T2SUB -= Mathf.Lerp(0.02f,GSDRI.GradeMod,tGrade/20f);
                            }
            //							if(tGrade < 0f){
            //								T2SUB *= -1f;
            //							}
            //							T2SUB -= tIntHeight2 - tVect2.y;
                        }else if(!bIntStr2_Full){
                            if(tNext+tStep < 1f){
                                tVect3 = tSpline.GetSplineValue(tNext+tStep,false);
                                tIntStrength2 = tSpline.IntersectionStrength(ref tVect3,ref tIntHeight2, ref GSDRI, ref bIsPastInter, ref i, ref xNode);
                            }else{
                                tIntStrength2 = 0f;
                            }

                            if(tIntStrength2 >= 1f){
                                T2SUB -= 0.06f;
                            }else{
                                T2SUB -= 0.02f;
                            }
                        }else{
                            T2SUB -= 0.02f;
                        }
                        bIntStr2_FullPrev = bIntStr2_Full;
                    }

                    fValue1=i - fValueMod;
                    fValue2=i + fValueMod;
                    if(fValue1 < 0){ fValue1 = 0; }
                    if(fValue2 > 1){ fValue2 = 1; }

                    tXYs.Add(CreateTris(fValue1,fValue2,ref tVect1,ref POS1,ref tVect2,ref POS2,Sep,ref TBMList,ref T1SUB, ref T2SUB, ref TTD, HeightSep));

                    //Details and trees:
                    tRect = SetDetailCoords(i,ref tVect1,ref POS1,ref tVect2, ref POS2,tSpline.tRoad.opt_ClearDetailsDistance,TreeClearDist, ref TTD, ref tSpline);
                    if(tSpline.tRoad.opt_TreeModEnabled && tRect != null){
                        TreerectList.Add(tRect);
                    }
                }else{
                    if(i > 1f){ break; }
                    tNext = i+tStep;
                    if(tNext > 1f){ break; }

                    tSpline.GetSplineValue_Both(i,out tVect1,out POS1);

                    if(tNext <= 1f){
                        tSpline.GetSplineValue_Both(tNext,out tVect2,out POS2);
                    }else{
                        tSpline.GetSplineValue_Both(1f,out tVect2,out POS2);
                    }

                    //Details and trees:
                    tRect = SetDetailCoords(i,ref tVect1,ref POS1,ref tVect2, ref POS2,tSpline.tRoad.opt_ClearDetailsDistance,TreeClearDist, ref TTD, ref tSpline);
                    if(tSpline.tRoad.opt_TreeModEnabled && tRect != null){
                        TreerectList.Add(tRect);
                    }
                }
            }

            if(tSpline.tRoad.bProfiling){
                Profiler.BeginSample("DoRectsTree");
            }
            if(tSpline.tRoad.opt_TreeModEnabled && TreerectList != null && TreerectList.Count > 0){
                int tCount = TTD.TreeSize;
                int jCount = TreerectList.Count;
                Vector3 tVect3D = default(Vector3);
                Vector2 tVect2D = default(Vector2);
                TreeInstance tTree;
                for(int i=0;i<tCount;i++){
                    tTree = TTD.TreesCurrent[i];

                    tVect3D = tTree.position;
                    tVect3D.x *= TTD.TerrainSize.z;
                    tVect3D.y *= TTD.TerrainSize.y;
                    tVect3D.z *= TTD.TerrainSize.x;
                    tVect3D += TTD.TerrainPos;
                    tVect2D.x = tVect3D.x;
                    tVect2D.y = tVect3D.z;

                    for(int j=0;j<jCount;j++){
                        if(TreerectList[j].Contains(ref tVect2D)){
                            TTD.TreesOld.Add(TTD.TreesCurrent[i]);
                            tTree = TTD.TreesCurrent[i];
                            tTree.prototypeIndex = -2;
                            TTD.TreesCurrent[i] = tTree;
                            TTD.TreesI+=1;
                            break;
                        }
                    }
                }
                TTD.TreesCurrent.RemoveAll(item => item.prototypeIndex < -1);
            }
            if(tSpline.tRoad.bProfiling){
                Profiler.EndSample();
            }

            if(!tSpline.tRoad.opt_HeightModEnabled){
                return;
            }

            //			//Temp testing:
            //			tSpline.mNodes[22].tTriList = new List<GSD.Roads.GSDRoadUtil.Construction3DTri>();
            //			int tCount = triList.Count;
            //			for(int i=0;i<tCount;i++){
            //				tSpline.mNodes[22].tTriList.Add(triList[i]);
            //			}
            //			tSpline.mNodes[22].tHMList = new List<Vector3>();

            float tFloat = -1f;
            Sep = tSpline.tRoad.RoadWidth()*1.5f;
            int k = 0;
            int[] tXY = null;
            int tXYsCount = tXYs.Count;
            bool bIsBridge = false;
            bool bIsTunnel = false;
            for(float i=StartMin;i<FinalMax;i+=tStep){
                if(TBMList.Count > 0){
                    if(TBMList[0].MaxI < i){
                        CleanupTris(i,ref TBMList);
                    }
                }else{
                    break;
                }

                //If in bridg mode:
                if(tSpline.IsInBridgeTerrain(i)){
                    bIsBridge = true;
                }else{
                    bIsBridge = false;
                }
                //If in tunnel mode:
                if(tSpline.IsInTunnelTerrain(i)){
                    bIsTunnel = true;
                }else{
                    bIsTunnel = false;
                }

                if(k < tXYsCount){
                    tXY = tXYs[k];
                    tFloat = ProcessCoordinateGrabber(ref i,ref tSpline,ref TTD, ref TBMList,ref tXY, bIsBridge, bIsTunnel);
                    if(!IsApproximately(tFloat,0f,0.0001f)){
                        tSpline.HeightHistory.Add(new KeyValuePair<float,float>(i,tFloat));
                    }
                }else{
                    break;
                }
                k+=1;
            }
        }