1- using FSO . Common . Utils ;
1+ using FSO . Common . Domain . Realestate ;
2+ using FSO . Common . Utils ;
23using FSO . Content . Model ;
34using Microsoft . Xna . Framework ;
45using Microsoft . Xna . Framework . Graphics ;
5- using System ;
6- using System . Collections . Generic ;
76using System . Runtime . CompilerServices ;
8- using System . Threading . Tasks ;
97
108namespace FSO . Client . Rendering . City
119{
10+ public readonly record struct CitySliceKey
11+ {
12+ public readonly int SliceID ;
13+ public readonly Rectangle ? FlattenRect ;
14+
15+ public CitySliceKey ( int sliceID , uint lotId )
16+ {
17+ SliceID = sliceID ;
18+ FlattenRect = null ;
19+
20+ if ( lotId != 0 )
21+ {
22+ // Try and build a flatten rect around the target lot.
23+ // If surrounding lots are disabled, it only affects the current lot.
24+ // If they're enabled, it affects the surrounding lots too.
25+
26+ var pos = MapCoordinates . Unpack ( lotId ) ;
27+
28+ FlattenRect = new Rectangle ( pos . ToPoint ( ) , new Point ( 1 ) ) ;
29+ }
30+ }
31+ }
32+
1233 public class CityGeometry
1334 {
1435 //draw order:
@@ -25,7 +46,7 @@ public class CityGeometry
2546 public int Width ;
2647 public int Height ;
2748 public int Ready = - 1 ;
28- public int CurrentSlice = - 1 ;
49+ public CitySliceKey ? CurrentSlice = null ;
2950
3051 private bool MeshRegenInProgress ;
3152 private bool MeshDirty ;
@@ -529,14 +550,42 @@ public void RegenMeshVerts(GraphicsDevice gd, bool async)
529550 }
530551
531552 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
532- private int O( int x , int y , int minx , int maxx )
553+ private static int O( int x , int y , int minx , int maxx )
533554 {
534555 return ( Math . Max ( 0 , Math . Min ( 511 , y ) ) * 512 + Math . Max ( minx , Math . Min ( maxx , x ) ) ) ;
535556 }
536557
537- public void SubRegenMeshVerts( GraphicsDevice gd , Rectangle ? range , int subdiv , int cpos )
558+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
559+ private static float GetContinuity( int x , int y , in Rectangle range , in Rectangle ? flattenRect )
538560 {
539- CurrentSlice = cpos;
561+ if ( x <= range . X || x >= range . Right || y <= range . Y || y >= range . Bottom )
562+ {
563+ return - 1 ;
564+ }
565+
566+ if ( flattenRect . HasValue )
567+ {
568+ Rectangle rect = flattenRect. Value ;
569+
570+ if ( x >= rect . X && x <= rect . Right && y >= rect . Y && y <= rect . Bottom )
571+ {
572+ return - 1 ;
573+ }
574+ }
575+
576+ return 0 ;
577+ }
578+
579+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
580+ private static float Lerp ( float a , float b , float t )
581+ {
582+ return a * ( 1 - t ) + b * t ;
583+ }
584+
585+ public void SubRegenMeshVerts ( GraphicsDevice gd , Rectangle range , int subdiv , CitySliceKey slice )
586+ {
587+ var cpos = slice. SliceID;
588+ CurrentSlice = slice;
540589 var indices = new List < int > [ 5 ] ;
541590 var vertices = new List < TLayerVertex > [ 5 ] ;
542591
@@ -560,11 +609,8 @@ public void SubRegenMeshVerts(GraphicsDevice gd, Rectangle? range, int subdiv, i
560609 float subd1f = 1f / subdiv ;
561610 int vertCount = subd1 * subd1 ;
562611
563- if ( range . HasValue )
564- {
565- yStart = range . Value . Y ;
566- yEnd = range . Value . Bottom ;
567- }
612+ yStart = range . Y ;
613+ yEnd = range . Bottom ;
568614
569615 Task . Run ( ( ) =>
570616 {
@@ -599,11 +645,8 @@ public void SubRegenMeshVerts(GraphicsDevice gd, Rectangle? range, int subdiv, i
599645 xStart -= fadeRange ;
600646 xEnd += fadeRange ;
601647
602- if ( range . HasValue )
603- {
604- xStart = Math . Max ( range . Value . X , xStart ) ;
605- xEnd = Math . Min ( range . Value . Right , xEnd ) ;
606- }
648+ xStart = Math . Max ( range . X , xStart ) ;
649+ xEnd = Math . Min ( range . Right , xEnd ) ;
607650
608651 for ( int j = xStart ; j < xEnd ; j ++ )
609652 { //where the magic happens
@@ -639,11 +682,12 @@ public void SubRegenMeshVerts(GraphicsDevice gd, Rectangle? range, int subdiv, i
639682 var normalRoad = roadByte & 15 ;
640683 var cornerRoad = roadByte >> 4 ;
641684
642- var yEdge = ( j == range . Value . X ) ? - 1f : 0f ;
643- var yEdge2 = ( j == range . Value . Right - 1 ) ? - 1f : 0f ;
685+ // Also enforce continuity when within the FlattenRect
644686
645- var xEdge = ( i == range . Value . Y ) ? - 1f : 0f ;
646- var xEdge2 = ( i == range . Value . Bottom - 1 ) ? - 1f : 0f ;
687+ var cont00 = GetContinuity ( j , i , range , in slice . FlattenRect ) ;
688+ var cont10 = GetContinuity ( j + 1 , i , range , in slice . FlattenRect ) ;
689+ var cont01 = GetContinuity ( j , i + 1 , range , in slice . FlattenRect ) ;
690+ var cont11 = GetContinuity ( j + 1 , i + 1 , range , in slice . FlattenRect ) ;
647691
648692 Span < float > d =
649693 [
@@ -658,15 +702,18 @@ public void SubRegenMeshVerts(GraphicsDevice gd, Rectangle? range, int subdiv, i
658702 var yi = 0f ;
659703 for ( int y = 0 ; y < subd1 ; y ++ )
660704 {
661- var lXE = ( yi * xEdge2 ) + ( ( 1 - yi ) * xEdge ) ;
662705 var xi = 0f ;
663706 for ( int x = 0 ; x < subd1 ; x ++ )
664707 {
708+ var yEdge = Lerp ( cont00 , cont01 , yi ) ;
709+ var yEdge2 = Lerp ( cont10 , cont11 , yi ) ;
710+
665711 float y1 = Cubic ( d [ 0 ] , d [ 1 ] , d [ 2 ] , d [ 3 ] , yi , yEdge ) ;
666712 float y2 = Cubic ( d [ 4 ] , d [ 5 ] , d [ 6 ] , d [ 7 ] , yi , yEdge ) ;
667713 float y3 = Cubic ( d [ 8 ] , d [ 9 ] , d [ 10 ] , d [ 11 ] , yi , yEdge2 ) ;
668714 float y4 = Cubic ( d [ 12 ] , d [ 13 ] , d [ 14 ] , d [ 15 ] , yi , yEdge2 ) ;
669715
716+ var lXE = Lerp ( yEdge , yEdge2 , xi ) ;
670717 var h = Cubic ( y1 , y2 , y3 , y4 , xi , lXE ) ;
671718
672719 var lerpNX = Vector3 . Lerp ( norm1 , norm2 , xi ) ;
0 commit comments