private Vector2 GetNeighbourPosition(Vector2 position, NeighbourIndex neighbour) { int evenY = Math.Abs((int)position.y) % 2; switch (neighbour) { case NeighbourIndex.NeighbourA: return(position + new Vector2(-1 + evenY, -1)); case NeighbourIndex.NeighbourB: return(position + new Vector2(0 + evenY, -1)); case NeighbourIndex.NeighbourC: return(position + new Vector2(1, 0)); case NeighbourIndex.NeighbourD: return(position + new Vector2(0 + evenY, 1)); case NeighbourIndex.NeighbourE: return(position + new Vector2(-1 + evenY, 1)); case NeighbourIndex.NeighbourF: return(position + new Vector2(-1, 0)); default: throw new ArgumentOutOfRangeException(nameof(neighbour), neighbour, null); } }
public List <IntPoint> GetHighlightFor(NeighbourIndex idx) { var points = new List <IntPoint>(); switch (idx) { case NeighbourIndex.North: points.Add(Top); points.Add(Right); break; case NeighbourIndex.NorthEast: points.Add(MidPoint(Right, Top)); points.Add(Right); points.Add(MidPoint(Right, Bottom)); break; case NeighbourIndex.East: points.Add(Right); points.Add(Bottom); break; case NeighbourIndex.SouthEast: points.Add(MidPoint(Right, Bottom)); points.Add(Bottom); points.Add(MidPoint(Left, Bottom)); break; case NeighbourIndex.South: points.Add(Bottom); points.Add(Left); break; case NeighbourIndex.SouthWest: points.Add(MidPoint(Left, Bottom)); points.Add(Left); points.Add(MidPoint(Left, Top)); break; case NeighbourIndex.West: points.Add(Left); points.Add(Top); break; case NeighbourIndex.NorthWest: points.Add(MidPoint(Left, Top)); points.Add(Top); points.Add(MidPoint(Right, Top)); break; default: throw new ArgumentOutOfRangeException(nameof(idx), idx, null); } return(points); }
protected override void DrawIndexedDirection(SKCanvas g, TextureTile tile, NeighbourIndex idx) { var points = CreateShape(GetTileArea(tile)).ToHighlight().GetHighlightFor(idx); var brush = Grid.TextureTileFormattingMetaData.TileHighlightColor ?? Preferences.DefaultTileHighlightColor; for (var pidx = 1; pidx < points.Count; pidx += 1) { var p1 = points[pidx - 1]; var p2 = points[pidx]; g.DrawRasterLine(brush, p1.X, p1.Y, p2.X, p2.Y); } }
public List <IntPoint> GetHighlightFor(NeighbourIndex idx) { var points = new List <IntPoint>(); switch (idx) { case NeighbourIndex.North: points.Add(new IntPoint(Top.X - 1, Top.Y)); points.Add(new IntPoint(Right.X - 1, Right.Y - 1)); break; case NeighbourIndex.NorthEast: points.Add(MidPoint(new IntPoint(Right.X - 1, Right.Y - 1), new IntPoint(Top.X - 1, Top.Y))); points.Add(new IntPoint(Right.X - 1, Right.Y - 1)); points.Add(new IntPoint(Right.X - 1, Right.Y)); points.Add(MidPoint(new IntPoint(Right.X - 1, Right.Y), new IntPoint(Bottom.X - 1, Bottom.Y))); break; case NeighbourIndex.East: points.Add(new IntPoint(Right.X - 1, Right.Y)); points.Add(new IntPoint(Bottom.X - 1, Bottom.Y)); break; case NeighbourIndex.SouthEast: points.Add(MidPoint(new IntPoint(Right.X - 1, Right.Y), new IntPoint(Bottom.X - 1, Bottom.Y))); points.Add(new IntPoint(Bottom.X - 1, Bottom.Y)); points.Add(new IntPoint(Bottom.X, Bottom.Y)); points.Add(MidPoint(new IntPoint(Left.X + 1, Left.Y), new IntPoint(Bottom.X, Bottom.Y))); break; case NeighbourIndex.South: points.Add(new IntPoint(Bottom.X, Bottom.Y)); points.Add(new IntPoint(Left.X + 1, Left.Y)); break; case NeighbourIndex.SouthWest: points.Add(MidPoint(new IntPoint(Left.X + 1, Left.Y), new IntPoint(Bottom.X, Bottom.Y))); points.Add(new IntPoint(Left.X + 1, Left.Y)); points.Add(new IntPoint(Left.X + 1, Left.Y - 1)); points.Add(MidPoint(new IntPoint(Left.X + 1, Left.Y - 1), new IntPoint(Top.X, Top.Y))); break; case NeighbourIndex.West: points.Add(new IntPoint(Left.X + 1, Left.Y - 1)); points.Add(new IntPoint(Top.X, Top.Y)); break; case NeighbourIndex.NorthWest: points.Add(MidPoint(new IntPoint(Left.X + 1, Left.Y - 1), new IntPoint(Top.X, Top.Y))); points.Add(new IntPoint(Top.X, Top.Y)); points.Add(new IntPoint(Top.X - 1, Top.Y)); points.Add(MidPoint(new IntPoint(Right.X - 1, Right.Y - 1), new IntPoint(Top.X - 1, Top.Y))); break; default: throw new ArgumentOutOfRangeException(nameof(idx), idx, null); } return(points); }
public static int AsInt(this NeighbourIndex c) { return((int)c); }
public void GetNeighbourPointOverflow( long x, long y, out NeighbourIndex outindex, out long outx, out long outy ) { outindex = NeighbourIndex.Count; if ( x < 0 ) { outx = x + this.mSize - 1; if ( y < 0 ) { outindex = NeighbourIndex.SouthWest; } else if ( y >= this.mSize ) { outindex = NeighbourIndex.NorthWest; } else { outindex = NeighbourIndex.West; } } else if ( x >= this.mSize ) { outx = x - this.mSize + 1; if ( y < 0 ) { outindex = NeighbourIndex.SouthEast; } else if ( y >= this.mSize ) { outindex = NeighbourIndex.NorthEast; } else { outindex = NeighbourIndex.East; } } else { outx = x; } if ( y < 0 ) { outy = y + this.mSize - 1; if ( x >= 0 && x < this.mSize ) { outindex = NeighbourIndex.South; } } else if ( y >= this.mSize ) { outy = y - this.mSize + 1; if ( x >= 0 && x < this.mSize ) { outindex = NeighbourIndex.North; } } else { outy = y; } System.Diagnostics.Debug.Assert( outindex != NeighbourIndex.Count ); }
public void GetNeighbourPoint( NeighbourIndex index, long x, long y, ref long outx, ref long outy ) { // Get the index of the point we should be looking at on a neighbour // in order to match up points System.Diagnostics.Debug.Assert( this.mSize == GetNeighbour( index ).Size, "Neighbour has not the same size as this instance" ); // left/right switch ( index ) { case NeighbourIndex.East: case NeighbourIndex.NorthEast: case NeighbourIndex.SouthEast: case NeighbourIndex.West: case NeighbourIndex.NorthWest: case NeighbourIndex.SouthWest: outx = this.mSize - x - 1; break; default: outx = x; break; } ; // top / bottom switch ( index ) { case NeighbourIndex.North: case NeighbourIndex.NorthEast: case NeighbourIndex.NorthWest: case NeighbourIndex.South: case NeighbourIndex.SouthWest: case NeighbourIndex.SouthEast: outy = this.mSize - y - 1; break; default: outy = y; break; } ; }
public void GetNeighbourEdgeRect( NeighbourIndex index, Rectangle inRect, ref Rectangle outRect ) { System.Diagnostics.Debug.Assert( this.mSize == GetNeighbour( index ).Size, "Neighbour has not the same size as this instance" ); // Basically just reflect the rect // remember index is neighbour relationship from OUR perspective so // arrangement is backwards to getEdgeRect // left/right switch ( index ) { case NeighbourIndex.East: case NeighbourIndex.NorthEast: case NeighbourIndex.SouthEast: case NeighbourIndex.West: case NeighbourIndex.NorthWest: case NeighbourIndex.SouthWest: outRect.Left = this.mSize - inRect.Right; outRect.Right = this.mSize - inRect.Left; break; default: outRect.Left = inRect.Left; outRect.Right = inRect.Right; break; } ; // top / bottom switch ( index ) { case NeighbourIndex.North: case NeighbourIndex.NorthEast: case NeighbourIndex.NorthWest: case NeighbourIndex.South: case NeighbourIndex.SouthWest: case NeighbourIndex.SouthEast: outRect.Top = this.mSize - inRect.Bottom; outRect.Bottom = this.mSize - inRect.Top; break; default: outRect.Top = inRect.Top; outRect.Bottom = inRect.Bottom; break; } ; }
public void GetEdgeRect( NeighbourIndex index, long range, ref Rectangle outRect ) { // We make the edge rectangle 2 rows / columns at the edge of the tile // 2 because this copes with normal changes and potentially filtered // shadows. // all right / bottom values are exclusive // terrain origin is bottom-left remember so north is highest value // set left/right switch ( index ) { case NeighbourIndex.East: case NeighbourIndex.NorthEast: case NeighbourIndex.SouthEast: outRect.Left = this.mSize - range; outRect.Right = this.mSize; break; case NeighbourIndex.West: case NeighbourIndex.NorthWest: case NeighbourIndex.SouthWest: outRect.Left = 0; outRect.Right = range; break; case NeighbourIndex.North: case NeighbourIndex.South: outRect.Left = 0; outRect.Right = this.mSize; break; case NeighbourIndex.Count: default: break; } ; // set top / bottom switch ( index ) { case NeighbourIndex.North: case NeighbourIndex.NorthEast: case NeighbourIndex.NorthWest: outRect.Top = this.mSize - range; outRect.Bottom = this.mSize; break; case NeighbourIndex.South: case NeighbourIndex.SouthWest: case NeighbourIndex.SouthEast: outRect.Top = 0; outRect.Bottom = range; break; case NeighbourIndex.East: case NeighbourIndex.West: outRect.Top = 0; outRect.Bottom = this.mSize; break; case NeighbourIndex.Count: default: break; } ; }
public static NeighbourIndex GetOppositeNeighbour( NeighbourIndex index ) { var intindex = (int)index; intindex += (int)( NeighbourIndex.Count )/2; intindex = intindex%(int)NeighbourIndex.Count; return (NeighbourIndex)intindex; }
/// <see cref="Terrain.SetNeighbour(NeighbourIndex, Terrain, bool, bool)"/> public void SetNeighbour( NeighbourIndex index, Terrain neighbour, bool recalculate ) { SetNeighbour( index, neighbour, recalculate, true ); }
/// <see cref="Terrain.SetNeighbour(NeighbourIndex, Terrain, bool, bool)"/> public void SetNeighbour( NeighbourIndex index, Terrain neighbour ) { SetNeighbour( index, neighbour, false, true ); }
public void SetNeighbour( NeighbourIndex index, Terrain neighbour, bool recalculate, bool notifyOther ) #endif { if ( this.mNeighbours[ (int)index ] != neighbour ) { System.Diagnostics.Debug.Assert( neighbour != this, "Can't set self as own neighbour!" ); // detach existing if ( this.mNeighbours[ (int)index ] != null && notifyOther ) { this.mNeighbours[ (int)index ].SetNeighbour( GetOppositeNeighbour( index ), null, false, false ); } this.mNeighbours[ (int)index ] = neighbour; if ( neighbour != null && notifyOther ) { this.mNeighbours[ (int)index ].SetNeighbour( GetOppositeNeighbour( index ), this, recalculate, false ); } if ( recalculate ) { //recalculate, pass OUR edge rect var edgerect = new Rectangle(); GetEdgeRect( index, 2, ref edgerect ); NeighbourModified( index, edgerect, edgerect ); } } }
public void SetNeighbour( NeighbourIndex index, Terrain neighbour, bool recalculate = false, bool notifyOther = true )
public Terrain GetNeighbour( NeighbourIndex index ) { return this.mNeighbours[ (int)index ]; }
protected override void DrawIndexedDirection(SKCanvas g, TextureTile tile, NeighbourIndex idx) { var points = new List <IntPoint>(); var rect = GetTileHighlightArea(tile); var left = rect.X; var top = rect.Y; var right = rect.X + rect.Width - 1; var bottom = rect.Y + rect.Height - 1; var centerX = MidPoint(rect.X, rect.X + rect.Width); var centerY = MidPoint(rect.Y, rect.Y + rect.Height); switch (idx) { case NeighbourIndex.North: points.Add(new IntPoint(left, top)); points.Add(new IntPoint(right, top)); break; case NeighbourIndex.NorthEast: points.Add(new IntPoint(centerX, top)); points.Add(new IntPoint(right, top)); points.Add(new IntPoint(right, centerY)); break; case NeighbourIndex.East: points.Add(new IntPoint(right, top)); points.Add(new IntPoint(right, bottom)); break; case NeighbourIndex.SouthEast: points.Add(new IntPoint(right, centerY)); points.Add(new IntPoint(right, bottom)); points.Add(new IntPoint(centerX, bottom)); break; case NeighbourIndex.South: points.Add(new IntPoint(left, bottom)); points.Add(new IntPoint(right, bottom)); break; case NeighbourIndex.SouthWest: points.Add(new IntPoint(centerX, bottom)); points.Add(new IntPoint(left, bottom)); points.Add(new IntPoint(left, centerY)); break; case NeighbourIndex.West: points.Add(new IntPoint(left, top)); points.Add(new IntPoint(left, bottom)); break; case NeighbourIndex.NorthWest: points.Add(new IntPoint(left, centerY)); points.Add(new IntPoint(left, top)); points.Add(new IntPoint(centerX, top)); break; default: throw new ArgumentOutOfRangeException(nameof(idx), idx, null); } var pen = Grid.TextureTileFormattingMetaData.TileHighlightColor ?? Preferences.DefaultTileHighlightColor; g.DrawGeometry(pen, points); }
public void NeighbourModified( NeighbourIndex index, Rectangle edgerect, Rectangle shadowrect ) { // We can safely assume that we would not have been contacted if it wasn't // important var neighbour = GetNeighbour( index ); if ( neighbour == null ) { return; // bogus request } var updateGeom = false; byte updateDerived = 0; if ( !edgerect.IsNull ) { // update edges; match heights first, then recalculate normals // reduce to just single line / corner var heightMatchRect = new Rectangle(); GetEdgeRect( index, 1, ref heightMatchRect ); heightMatchRect = heightMatchRect.Intersect( edgerect ); for ( var y = heightMatchRect.Top; y < heightMatchRect.Bottom; ++y ) { for ( var x = heightMatchRect.Left; x < heightMatchRect.Right; ++x ) { long nx = 0, ny = 0; GetNeighbourPoint( index, x, y, ref nx, ref ny ); var neighbourHeight = neighbour.GetHeightAtPoint( nx, ny ); if ( !Utility.RealEqual( neighbourHeight, GetHeightAtPoint( x, y ), 1e-3f ) ) { SetHeightAtPoint( x, y, neighbourHeight ); if ( !updateGeom ) { updateGeom = true; updateDerived |= DERIVED_DATA_ALL; } } } } // if we didn't need to update heights, we still need to update normals // because this was called only if neighbor changed if ( !updateGeom ) { // ideally we would deal with normal dirty rect separately (as we do with // lightmaps) because a dirty geom rectangle will actually grow by one // element in each direction for normals recalculation. However for // the sake of one row/column it's really not worth it. this.mDirtyDerivedDataRect.Merge( edgerect ); updateDerived |= DERIVED_DATA_NORMALS; } } if ( !shadowrect.IsNull ) { // update shadows // here we need to widen the rect passed in based on the min/max height // of the *neighbour* var lightVec = TerrainGlobalOptions.LightMapDirection; var widenedRect = new Rectangle(); WidenRectByVector( lightVec, shadowrect, neighbour.MinHeight, neighbour.MaxHeight, ref widenedRect ); // set the special-case lightmap dirty rectangle this.mDirtyLightmapFromNeighboursRect.Merge( widenedRect ); updateDerived |= DERIVED_DATA_LIGHTMAP; } if ( updateGeom ) { UpdateGeometry(); } if ( updateDerived != 0 ) { UpdateDerivedData( false, updateDerived ); } }