Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Robust.Client/Graphics/Clyde/Clyde.GridRendering.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ private void _updateChunkEdges(Entity<MapGridComponent> grid, MapChunk chunk, Ma
continue;

var direction = new Vector2i(nx, ny).AsDirection().GetOpposite();
var regionMaybe = _tileDefinitionManager.TileAtlasRegion(neighborTile.TypeId, direction);
var regionMaybe = _tileDefinitionManager.TileAtlasRegion(neighborTile.TypeId, direction, neighborTile.IsEmpty);

if (regionMaybe == null)
continue;
Expand Down
148 changes: 81 additions & 67 deletions Robust.Client/Map/ClydeTileDefinitionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ internal sealed class ClydeTileDefinitionManager : TileDefinitionManager, IClyde

public Texture TileTextureAtlas => _tileTextureAtlas ?? Texture.Transparent;

private FrozenDictionary<(int Id, Direction Direction), Box2[]> _tileRegions = FrozenDictionary<(int Id, Direction Direction), Box2[]>.Empty;
/// <summary>
/// A dictionary that stores references to the textures of all tiles.
/// Id - tile id
/// Direction - if Invalid, tile texture itself. If not - tile edge sprite
/// Space - used only for tile edges sprite, allow use dirrerent sets of edge sprites, used in contact with empty space
/// </summary>
private FrozenDictionary<(int Id, Direction Direction, bool Space), Box2[]> _tileRegions = FrozenDictionary<(int Id, Direction Direction, bool Space), Box2[]>.Empty;

public Box2 ErrorTileRegion { get; private set; }

Expand All @@ -49,10 +55,10 @@ internal sealed class ClydeTileDefinitionManager : TileDefinitionManager, IClyde
}

/// <inheritdoc />
public Box2[]? TileAtlasRegion(int tileType, Direction direction)
public Box2[]? TileAtlasRegion(int tileType, Direction direction, bool space = false)
{
// ReSharper disable once CanSimplifyDictionaryTryGetValueWithGetValueOrDefault
if (_tileRegions.TryGetValue((tileType, direction), out var region))
if (_tileRegions.TryGetValue((tileType, direction, space), out var region))
{
return region;
}
Expand Down Expand Up @@ -94,7 +100,7 @@ private void OnReload(ResPath obj)
internal void _genTextureAtlas()
{
var sw = RStopwatch.StartNew();
var tileRegs = new Dictionary<(int Id, Direction Direction), Box2[]>();
var tileRegs = new Dictionary<(int Id, Direction Direction, bool Space), Box2[]>();
_tileTextureAtlas = null;

var defList = TileDefs.Where(t => t.Sprite != null).ToList();
Expand All @@ -105,7 +111,7 @@ internal void _genTextureAtlas()

const int tileSize = EyeManager.PixelsPerMeter;

var tileCount = defList.Select(x => x.Variants + x.EdgeSprites.Count).Sum() + 1;
var tileCount = defList.Select(x => x.Variants + x.EdgeSprites.Count + x.EdgeSpaceSprites.Count).Sum() + 1;

var dimensionX = (int) Math.Ceiling(Math.Sqrt(tileCount));
var dimensionY = (int) Math.Ceiling((float) tileCount / dimensionX);
Expand Down Expand Up @@ -171,76 +177,84 @@ internal void _genTextureAtlas()
BumpColumn(ref row, ref column, dimensionX);
}

tileRegs.Add((def.TileId, Direction.Invalid), regionList);
tileRegs.Add((def.TileId, Direction.Invalid, false), regionList);

// Edges
if (def.EdgeSprites.Count <= 0)
if (def.EdgeSprites.Count <= 0 && def.EdgeSpaceSprites.Count <= 0)
continue;

foreach (var direction in DirectionExtensions.AllDirections)
// Helper method to process edge set
void ProcessEdgeSet(Dictionary<Direction, ResPath> edges, bool isSpace)
{
if (!def.EdgeSprites.TryGetValue(direction, out var edge))
continue;

using (var stream = _manager.ContentFileRead(edge))
{
image = Image.Load<Rgba32>(stream);
}

if (image.Width != tileSize || image.Height != tileSize)
{
throw new NotSupportedException(
$"Unable to load {path}, due to being unable to use tile textures with a dimension other than {tileSize}x{tileSize}.");
}

Angle angle = Angle.Zero;

switch (direction)
{
// Corner sprites
case Direction.SouthEast:
break;
case Direction.NorthEast:
angle = new Angle(MathF.PI / 2f);
break;
case Direction.NorthWest:
angle = new Angle(MathF.PI);
break;
case Direction.SouthWest:
angle = new Angle(MathF.PI * 1.5f);
break;
// Edge sprites
case Direction.South:
break;
case Direction.East:
angle = new Angle(MathF.PI / 2f);
break;
case Direction.North:
angle = new Angle(MathF.PI);
break;
case Direction.West:
angle = new Angle(MathF.PI * 1.5f);
break;
}

if (angle != Angle.Zero)
foreach (var direction in DirectionExtensions.AllDirections)
{
image.Mutate(o => o.Rotate((float)-angle.Degrees));
if (!edges.TryGetValue(direction, out var edge))
continue;

using (var stream = _manager.ContentFileRead(edge))
{
image = Image.Load<Rgba32>(stream);
}

if (image.Width != tileSize || image.Height != tileSize)
{
throw new NotSupportedException(
$"Unable to load {edge}, due to being unable to use tile textures with a dimension other than {tileSize}x{tileSize}.");
}

Angle angle = Angle.Zero;
switch (direction)
{
// Corner sprites
case Direction.SouthEast:
break;
case Direction.NorthEast:
angle = new Angle(MathF.PI / 2f);
break;
case Direction.NorthWest:
angle = new Angle(MathF.PI);
break;
case Direction.SouthWest:
angle = new Angle(MathF.PI * 1.5f);
break;
// Edge sprites
case Direction.South:
break;
case Direction.East:
angle = new Angle(MathF.PI / 2f);
break;
case Direction.North:
angle = new Angle(MathF.PI);
break;
case Direction.West:
angle = new Angle(MathF.PI * 1.5f);
break;
}

if (angle != Angle.Zero)
{
image.Mutate(o => o.Rotate((float)-angle.Degrees));
}

var point = new Vector2i(column * tileSize, row * tileSize);
var box = new UIBox2i(0, 0, tileSize, tileSize);
image.Blit(box, sheet, point);

// If you ever need edge variants then you could just bump this.
var edgeList = new Box2[1];
edgeList[0] = Box2.FromDimensions(
point.X / w, (h - point.Y - EyeManager.PixelsPerMeter) / h,
tileSize / w, tileSize / h);

var key2 = (def.TileId, direction, IsSpace: isSpace);
tileRegs.Add(key2, edgeList);
BumpColumn(ref row, ref column, dimensionX);
}

var point = new Vector2i(column * tileSize, row * tileSize);
var box = new UIBox2i(0, 0, tileSize, tileSize);
image.Blit(box, sheet, point);

// If you ever need edge variants then you could just bump this.
var edgeList = new Box2[1];
edgeList[0] = Box2.FromDimensions(
point.X / w, (h - point.Y - EyeManager.PixelsPerMeter) / h,
tileSize / w, tileSize / h);

tileRegs.Add((def.TileId, direction), edgeList);
BumpColumn(ref row, ref column, dimensionX);
}

// process both sets
ProcessEdgeSet(def.EdgeSprites, false);
ProcessEdgeSet(def.EdgeSpaceSprites, true);
}

_tileRegions = tileRegs.ToFrozenDictionary();
Expand Down
4 changes: 2 additions & 2 deletions Robust.Client/Map/IClydeTileDefinitionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ internal interface IClydeTileDefinitionManager : ITileDefinitionManager

/// <summary>
/// Gets the region inside the texture atlas to use to draw a tile type.
/// Also handles edge sprites.
/// Also handles edge sprites, both those touching space and those touching other tiles
/// </summary>
/// <returns>If null, do not draw the tile at all.</returns>
public Box2[]? TileAtlasRegion(int tileType, Direction direction);
public Box2[]? TileAtlasRegion(int tileType, Direction direction, bool space);
}
}
5 changes: 5 additions & 0 deletions Robust.Shared/Map/ITileDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ public interface ITileDefinition : IPrototype
/// Possible sprites to use if we're neighboring another tile.
/// </summary>
Dictionary<Direction, ResPath> EdgeSprites { get; }

/// <summary>
/// Possible sprites to use if we're neighboring empty tile.
/// </summary>
Dictionary<Direction, ResPath> EdgeSpaceSprites { get; }
Comment on lines +33 to +36
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this have a default implementation so there's no backwards-compat break, please.


/// <summary>
/// When drawing adjacent tiles that both specify edge sprites, the one with the higher priority
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public sealed partial class TileDef : ITileDefinition
public string ID { get; private set; } = default!;
public ResPath? Sprite => null;
public Dictionary<Direction, ResPath> EdgeSprites => new();
public Dictionary<Direction, ResPath> EdgeSpaceSprites => new();
public int EdgeSpritePriority => 0;
public float Friction => 0;
public byte Variants => 0;
Expand Down
Loading