@@ -17,12 +17,10 @@ public BuildingRenderer(RenderDependencies renderDependencies) : base(renderDepe
1717
1818 private AnimRenderer buildingAnimRenderer ;
1919
20- Rectangle lowestDrawRectangle ;
2120 DepthRectangle cachedDepth ;
2221
2322 public override void InitDrawForObject ( Structure gameObject )
2423 {
25- lowestDrawRectangle = Rectangle . Empty ;
2624 cachedDepth = new DepthRectangle ( - 1f , - 1f ) ;
2725 }
2826
@@ -135,29 +133,49 @@ private DepthRectangle GetDepthForAnimation(Structure gameObject, Rectangle draw
135133 bottom += heightReferenceCell . Level * Constants . CellHeight ;
136134 }
137135
138- int yReference = CellMath . CellTopLeftPointFromCellCoords ( southernmostFoundationCellCoords , Map ) . Y ;
136+ int yReference = CellMath . CellBottomPointFromCellCoords ( southernmostFoundationCellCoords , Map ) ;
139137
140138 float topDepth = CellMath . GetDepthForPixelInCube ( y , 0 , yReference , heightReferenceCell , Map ) ;
141139 float bottomDepth = CellMath . GetDepthForPixelInCube ( bottom , 0 , yReference , heightReferenceCell , Map ) ;
142140
143141 return new DepthRectangle ( topDepth , bottomDepth ) ;
144142 }
145143
144+ protected override DepthRectangle GetShadowDepthFromPosition ( Structure gameObject , Rectangle drawingBounds )
145+ {
146+ // The default behaviour for shadows is to call GetDepthFromPosition,
147+ // but the adjusted behaviour of GetDepthFromPosition intended for the rendering
148+ // of turrets and other on-top-of-the-building objects results in shadows
149+ // being too close to the "camera".
150+
151+ // This implementation fixes the issue by calculating depth from the building's
152+ // lowest pixel (at the building's base), not from its highest pixel.
153+
154+ var southernmostFoundationCellCoords = gameObject . GetSouthernmostFoundationCell ( ) ;
155+ var heightReferenceCell = Map . GetTile ( gameObject . Position ) ;
156+
157+ // drawingBounds includes effect of height, which is undesirable for depth rendering
158+ int bottom = drawingBounds . Bottom ;
159+
160+ if ( heightReferenceCell != null && ! RenderDependencies . EditorState . Is2DMode )
161+ {
162+ bottom += heightReferenceCell . Level * Constants . CellHeight ;
163+ }
164+
165+ int yReference = CellMath . CellBottomPointFromCellCoords ( southernmostFoundationCellCoords , Map ) ;
166+
167+ float depthAtBottom = CellMath . GetDepthForPixelInCube ( bottom , 0 , yReference , heightReferenceCell , Map ) ;
168+ return new DepthRectangle ( depthAtBottom , depthAtBottom ) ;
169+ }
170+
146171 protected override DepthRectangle GetDepthFromPosition ( Structure gameObject , Rectangle drawingBounds )
147172 {
148- // Because buildings can include turrets, the default implementation
173+ // Because buildings have a customized depth implementation and can layer several
174+ // sprites on top of each other, the default implementation
149175 // is not suitable. For example, bodies can be larger than turrets,
150176 // leading the bodies to have higher depth and overlapping turrets.
151177 //
152- // To fix this, we normalize everything to use the maximum depth based on the frame
153- // that is drawn southernmost.
154- if ( lowestDrawRectangle . Bottom >= drawingBounds . Bottom )
155- {
156- return cachedDepth ;
157- }
158-
159- float foundationCenterXPoint = GetFoundationCenterXPoint ( gameObject ) ;
160- int distRight = ( int ) ( drawingBounds . Width * ( 1.0f - foundationCenterXPoint ) ) ;
178+ // To fix this, we normalize everything to use the maximum depth.
161179
162180 var southernmostFoundationCellCoords = gameObject . GetSouthernmostFoundationCell ( ) ;
163181 var heightReferenceCell = Map . GetTile ( gameObject . Position ) ;
@@ -170,12 +188,15 @@ protected override DepthRectangle GetDepthFromPosition(Structure gameObject, Rec
170188 y += heightReferenceCell . Level * Constants . CellHeight ;
171189 }
172190
173- int yReference = CellMath . CellTopLeftPointFromCellCoords ( southernmostFoundationCellCoords , Map ) . Y ;
191+ int yReference = CellMath . CellBottomPointFromCellCoords ( southernmostFoundationCellCoords , Map ) ;
174192
175193 // Used for drawing turrets and stuff, just return maximum depth since they must be on top of the building
176194 float maxDepth = CellMath . GetDepthForPixelInCube ( y , 0 , yReference , heightReferenceCell , Map ) ;
195+
196+ if ( maxDepth < cachedDepth . TopLeft )
197+ return cachedDepth ;
198+
177199 cachedDepth = new DepthRectangle ( maxDepth , maxDepth ) ;
178- lowestDrawRectangle = drawingBounds ;
179200
180201 return cachedDepth ;
181202 }
@@ -198,7 +219,7 @@ protected override DepthRectangle GetDepthFromPosition(Structure gameObject, Rec
198219 bottom += heightReferenceCell . Level * Constants . CellHeight ;
199220 }
200221
201- int yReference = CellMath . CellTopLeftPointFromCellCoords ( southernmostFoundationCellCoords , Map ) . Y ;
222+ int yReference = CellMath . CellBottomPointFromCellCoords ( southernmostFoundationCellCoords , Map ) ;
202223
203224 float depthTopLeft = CellMath . GetDepthForPixelInCube ( y , distLeft , yReference , heightReferenceCell , Map ) ;
204225 float depthTopRight = CellMath . GetDepthForPixelInCube ( y , 0 , yReference , heightReferenceCell , Map ) ;
@@ -234,7 +255,7 @@ protected override DepthRectangle GetDepthFromPosition(Structure gameObject, Rec
234255 bottom += heightReferenceCell . Level * Constants . CellHeight ;
235256 }
236257
237- int yReference = CellMath . CellTopLeftPointFromCellCoords ( southernmostFoundationCellCoords , Map ) . Y ;
258+ int yReference = CellMath . CellBottomPointFromCellCoords ( southernmostFoundationCellCoords , Map ) ;
238259
239260 float depthTopLeft = CellMath . GetDepthForPixelInCube ( y , 0 , yReference , heightReferenceCell , Map ) ;
240261 float depthTopRight = CellMath . GetDepthForPixelInCube ( y , distRight , yReference , heightReferenceCell , Map ) ;
@@ -504,11 +525,11 @@ private void DrawVoxelTurret(Structure gameObject, Point2D drawPoint, in CommonD
504525 {
505526 DrawVoxelModel ( gameObject , drawParams . TurretVoxel ,
506527 gameObject . Facing , RampType . None , nonRemapColor , true , gameObject . GetRemapColor ( ) ,
507- affectedByLighting , turretDrawPoint , Constants . DepthEpsilon * 2 ) ;
528+ affectedByLighting , turretDrawPoint , Constants . DepthEpsilon ) ;
508529
509530 DrawVoxelModel ( gameObject , drawParams . BarrelVoxel ,
510531 gameObject . Facing , RampType . None , nonRemapColor , true , gameObject . GetRemapColor ( ) ,
511- affectedByLighting , turretDrawPoint , Constants . DepthEpsilon * 3 ) ;
532+ affectedByLighting , turretDrawPoint , Constants . DepthEpsilon * 3 ) ; // appears to need a 3x multiplier due to float imprecision
512533 }
513534 else
514535 {
0 commit comments