Add height map support.

This commit is contained in:
Paul Chote
2014-10-30 18:33:59 +13:00
parent 3dd93c7ff6
commit 60420340fb
3 changed files with 141 additions and 59 deletions

View File

@@ -24,6 +24,38 @@ using OpenRA.Traits;
namespace OpenRA
{
struct BinaryDataHeader
{
public readonly byte Format;
public readonly uint TilesOffset;
public readonly uint HeightsOffset;
public readonly uint ResourcesOffset;
public BinaryDataHeader(Stream s, int2 expectedSize)
{
Format = s.ReadUInt8();
var width = s.ReadUInt16();
var height = s.ReadUInt16();
if (width != expectedSize.X || height != expectedSize.Y)
throw new InvalidDataException("Invalid tile data");
if (Format == 1)
{
TilesOffset = 5;
HeightsOffset = 0;
ResourcesOffset = (uint)(3 * width * height + 5);
}
else if (Format == 2)
{
TilesOffset = s.ReadUInt32();
HeightsOffset = s.ReadUInt32();
ResourcesOffset = s.ReadUInt32();
}
else
throw new InvalidDataException("Unknown binary map format '{0}'".F(Format));
}
}
public class MapOptions
{
public bool? Cheats;
@@ -118,11 +150,14 @@ namespace OpenRA
[FieldLoader.Ignore] public List<MiniYamlNode> TranslationDefinitions = new List<MiniYamlNode>();
// Binary map data
[FieldLoader.Ignore] public byte TileFormat = 1;
[FieldLoader.Ignore] public byte TileFormat = 2;
public int2 MapSize;
[FieldLoader.Ignore] public Lazy<CellLayer<TerrainTile>> MapTiles;
[FieldLoader.Ignore] public Lazy<CellLayer<ResourceTile>> MapResources;
[FieldLoader.Ignore] public Lazy<CellLayer<byte>> MapHeight;
[FieldLoader.Ignore] public CellLayer<byte> CustomTerrain;
[FieldLoader.Ignore] Lazy<TileSet> cachedTileSet;
@@ -145,6 +180,13 @@ namespace OpenRA
return ret;
});
var makeMapHeight = Exts.Lazy(() =>
{
var ret = new CellLayer<byte>(tileShape, size);
ret.Clear(0);
return ret;
});
var map = new Map()
{
Title = "Name your map here",
@@ -155,6 +197,7 @@ namespace OpenRA
Options = new MapOptions(),
MapResources = Exts.Lazy(() => new CellLayer<ResourceTile>(tileShape, size)),
MapTiles = makeMapTiles,
MapHeight = makeMapHeight,
Actors = Exts.Lazy(() => new Dictionary<string, ActorReference>()),
Smudges = Exts.Lazy(() => new List<SmudgeReference>())
};
@@ -253,6 +296,8 @@ namespace OpenRA
MapTiles = Exts.Lazy(() => LoadMapTiles());
MapResources = Exts.Lazy(() => LoadResourceTiles());
MapHeight = Exts.Lazy(() => LoadMapHeight());
TileShape = Game.modData.Manifest.TileShape;
SubCellOffsets = Game.modData.Manifest.SubCellOffsets;
LastSubCell = (SubCell)(SubCellOffsets.Length - 1);
@@ -395,33 +440,25 @@ namespace OpenRA
public CellLayer<TerrainTile> LoadMapTiles()
{
var tiles = new CellLayer<TerrainTile>(this);
using (var dataStream = Container.GetContent("map.bin"))
using (var s = Container.GetContent("map.bin"))
{
if (dataStream.ReadUInt8() != 1)
throw new InvalidDataException("Unknown binary map format");
// Load header info
var width = dataStream.ReadUInt16();
var height = dataStream.ReadUInt16();
if (width != MapSize.X || height != MapSize.Y)
throw new InvalidDataException("Invalid tile data");
// Load tile data
var data = dataStream.ReadBytes(MapSize.X * MapSize.Y * 3);
var d = 0;
for (var i = 0; i < MapSize.X; i++)
var header = new BinaryDataHeader(s, MapSize);
if (header.TilesOffset > 0)
{
for (var j = 0; j < MapSize.Y; j++)
s.Position = header.TilesOffset;
for (var i = 0; i < MapSize.X; i++)
{
var tile = BitConverter.ToUInt16(data, d);
d += 2;
for (var j = 0; j < MapSize.Y; j++)
{
var tile = s.ReadUInt16();
var index = s.ReadUInt8();
var index = data[d++];
if (index == byte.MaxValue)
index = (byte)(i % 4 + (j % 4) * 4);
// TODO: Remember to remove this when rewriting tile variants / PickAny
if (index == byte.MaxValue)
index = (byte)(i % 4 + (j % 4) * 4);
tiles[i, j] = new TerrainTile(tile, index);
tiles[i, j] = new TerrainTile(tile, index);
}
}
}
}
@@ -429,32 +466,45 @@ namespace OpenRA
return tiles;
}
public CellLayer<byte> LoadMapHeight()
{
var maxHeight = cachedTileSet.Value.MaxGroundHeight;
var tiles = new CellLayer<byte>(this);
using (var s = Container.GetContent("map.bin"))
{
var header = new BinaryDataHeader(s, MapSize);
if (header.HeightsOffset > 0)
{
s.Position = header.HeightsOffset;
for (var i = 0; i < MapSize.X; i++)
for (var j = 0; j < MapSize.Y; j++)
tiles[i, j] = s.ReadUInt8().Clamp((byte)0, maxHeight);
}
}
return tiles;
}
public CellLayer<ResourceTile> LoadResourceTiles()
{
var resources = new CellLayer<ResourceTile>(this);
using (var dataStream = Container.GetContent("map.bin"))
using (var s = Container.GetContent("map.bin"))
{
if (dataStream.ReadUInt8() != 1)
throw new InvalidDataException("Unknown binary map format");
// Load header info
var width = dataStream.ReadUInt16();
var height = dataStream.ReadUInt16();
if (width != MapSize.X || height != MapSize.Y)
throw new InvalidDataException("Invalid tile data");
// Skip past tile data
dataStream.Seek(3 * MapSize.X * MapSize.Y, SeekOrigin.Current);
var data = dataStream.ReadBytes(MapSize.X * MapSize.Y * 2);
var d = 0;
// Load resource data
for (var i = 0; i < MapSize.X; i++)
for (var j = 0; j < MapSize.Y; j++)
resources[i, j] = new ResourceTile(data[d++], data[d++]);
var header = new BinaryDataHeader(s, MapSize);
if (header.ResourcesOffset > 0)
{
s.Position = header.ResourcesOffset;
for (var i = 0; i < MapSize.X; i++)
{
for (var j = 0; j < MapSize.Y; j++)
{
var type = s.ReadUInt8();
var density = s.ReadUInt8();
resources[i, j] = new ResourceTile(type, density);
}
}
}
}
return resources;
@@ -465,28 +515,53 @@ namespace OpenRA
var dataStream = new MemoryStream();
using (var writer = new BinaryWriter(dataStream))
{
// File header consists of a version byte, followed by 2 ushorts for width and height
// Binary data version
writer.Write(TileFormat);
// Size
writer.Write((ushort)MapSize.X);
writer.Write((ushort)MapSize.Y);
// Data offsets
var tilesOffset = 17;
var heightsOffset = cachedTileSet.Value.MaxGroundHeight > 0 ? 3 * MapSize.X * MapSize.Y + 17 : 0;
var resourcesOffset = (cachedTileSet.Value.MaxGroundHeight > 0 ? 4 : 3) * MapSize.X * MapSize.Y + 17;
writer.Write((uint)tilesOffset);
writer.Write((uint)heightsOffset);
writer.Write((uint)resourcesOffset);
// Tile data
for (var i = 0; i < MapSize.X; i++)
for (var j = 0; j < MapSize.Y; j++)
if (tilesOffset != 0)
{
for (var i = 0; i < MapSize.X; i++)
{
var tile = MapTiles.Value[i, j];
writer.Write(tile.Type);
writer.Write(tile.Index);
for (var j = 0; j < MapSize.Y; j++)
{
var tile = MapTiles.Value[i, j];
writer.Write(tile.Type);
writer.Write(tile.Index);
}
}
}
// Height data
if (heightsOffset != 0)
for (var i = 0; i < MapSize.X; i++)
for (var j = 0; j < MapSize.Y; j++)
writer.Write(MapHeight.Value[i, j]);
// Resource data
for (var i = 0; i < MapSize.X; i++)
if (resourcesOffset != 0)
{
for (var j = 0; j < MapSize.Y; j++)
for (var i = 0; i < MapSize.X; i++)
{
var tile = MapResources.Value[i, j];
writer.Write(tile.Type);
writer.Write(tile.Index);
for (var j = 0; j < MapSize.Y; j++)
{
var tile = MapResources.Value[i, j];
writer.Write(tile.Type);
writer.Write(tile.Index);
}
}
}
}
@@ -513,7 +588,9 @@ namespace OpenRA
// (b) Therefore:
// - ax + by adds (a - b) * 512 + 512 to u
// - ax + by adds (a + b) * 512 + 512 to v
return new WPos(512 * (cell.X - cell.Y + 1), 512 * (cell.X + cell.Y + 1), 0);
var z = Contains(cell) ? 512 * MapHeight.Value[cell] : 0;
return new WPos(512 * (cell.X - cell.Y + 1), 512 * (cell.X + cell.Y + 1), z);
}
public WPos CenterOfSubCell(CPos cell, SubCell subCell)
@@ -588,10 +665,12 @@ namespace OpenRA
{
var oldMapTiles = MapTiles.Value;
var oldMapResources = MapResources.Value;
var oldMapHeight = MapHeight.Value;
var newSize = new Size(width, height);
MapTiles = Exts.Lazy(() => CellLayer.Resize(oldMapTiles, newSize, oldMapTiles[0, 0]));
MapResources = Exts.Lazy(() => CellLayer.Resize(oldMapResources, newSize, oldMapResources[0, 0]));
MapHeight = Exts.Lazy(() => CellLayer.Resize(oldMapHeight, newSize, oldMapHeight[0, 0]));
MapSize = new int2(newSize);
}