Files
OpenRA/OpenRA.FileFormats/Map/TileSet.cs

204 lines
5.5 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
namespace OpenRA.FileFormats
{
public class TerrainTypeInfo
{
public string Type;
public string[] AcceptsSmudgeType = { };
public bool IsWater = false;
public Color Color;
public string CustomCursor;
public TerrainTypeInfo() {}
public TerrainTypeInfo(MiniYaml my) { FieldLoader.Load(this, my); }
public MiniYaml Save() { return FieldSaver.Save(this); }
}
public class TileTemplate
{
public ushort Id;
public string Image;
public int2 Size;
public bool PickAny;
public string Category;
[FieldLoader.LoadUsing( "LoadTiles" )]
public Dictionary<byte, string> Tiles = new Dictionary<byte, string>();
public TileTemplate() {}
public TileTemplate(MiniYaml my) { FieldLoader.Load( this, my ); }
static object LoadTiles( MiniYaml y )
{
return y.NodesDict["Tiles"].NodesDict.ToDictionary(
t => byte.Parse(t.Key),
t => t.Value.Value );
}
static readonly string[] Fields = { "Id", "Image", "Size", "PickAny" };
public MiniYaml Save()
{
var root = new List<MiniYamlNode>();
foreach (var field in Fields)
{
FieldInfo f = this.GetType().GetField(field);
if (f.GetValue(this) == null) continue;
root.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) );
}
root.Add( new MiniYamlNode( "Tiles", null,
Tiles.Select( x => new MiniYamlNode( x.Key.ToString(), x.Value ) ).ToList() ) );
return new MiniYaml(null, root);
}
public Terrain Data;
}
public class TileSet
{
public string Name;
public string Id;
public string Palette;
public string PlayerPalette;
public int TileSize = 24;
public string[] Extensions;
public int WaterPaletteRotationBase = 0x60;
public Dictionary<string, TerrainTypeInfo> Terrain = new Dictionary<string, TerrainTypeInfo>();
public Dictionary<ushort, TileTemplate> Templates = new Dictionary<ushort, TileTemplate>();
public string[] EditorTemplateOrder;
static readonly string[] fields = {"Name", "TileSize", "Id", "Palette", "Extensions"};
public TileSet() {}
public TileSet( string filepath )
{
var yaml = MiniYaml.DictFromFile( filepath );
// General info
FieldLoader.Load(this, yaml["General"]);
// TerrainTypes
Terrain = yaml["Terrain"].NodesDict.Values
.Select(y => new TerrainTypeInfo(y)).ToDictionary(t => t.Type);
// Templates
Templates = yaml["Templates"].NodesDict.Values
.Select(y => new TileTemplate(y)).ToDictionary(t => t.Id);
}
public void LoadTiles()
{
foreach (var t in Templates)
if (t.Value.Data == null)
using( var s = FileSystem.OpenWithExts(t.Value.Image, Extensions) )
t.Value.Data = new Terrain(s, TileSize);
}
public void Save(string filepath)
{
var root = new List<MiniYamlNode>();
var gen = new List<MiniYamlNode>();
foreach (var field in fields)
{
FieldInfo f = this.GetType().GetField(field);
if (f.GetValue(this) == null) continue;
gen.Add( new MiniYamlNode( field, FieldSaver.FormatValue( this, f ) ) );
}
root.Add( new MiniYamlNode( "General", null, gen ) );
root.Add( new MiniYamlNode( "Terrain", null,
Terrain.Select( t => new MiniYamlNode(
"TerrainType@{0}".F( t.Value.Type ),
t.Value.Save() ) ).ToList() ) );
root.Add( new MiniYamlNode( "Templates", null,
Templates.Select( t => new MiniYamlNode(
"Template@{0}".F( t.Value.Id ),
t.Value.Save() ) ).ToList() ) );
root.WriteToFile(filepath);
}
public byte[] GetBytes(TileReference<ushort,byte> r)
{
TileTemplate tile;
if( Templates.TryGetValue( r.type, out tile ) )
return tile.Data.TileBitmapBytes[ r.index ];
byte[] missingTile = new byte[ TileSize * TileSize ];
for( int i = 0 ; i < missingTile.Length ; i++ )
missingTile[ i ] = 0x36;
return missingTile;
}
public string GetTerrainType(TileReference<ushort, byte> r)
{
var tt = Templates[r.type].Tiles;
string ret;
if (!tt.TryGetValue(r.index, out ret))
return "Clear"; // Default walkable
return ret;
}
public Bitmap RenderTemplate(ushort n, Palette p)
{
var template = Templates[n];
var bitmap = new Bitmap(TileSize * template.Size.X, TileSize * template.Size.Y,
PixelFormat.Format8bppIndexed);
bitmap.Palette = p.AsSystemPalette();
var data = bitmap.LockBits(bitmap.Bounds(),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
unsafe
{
byte* q = (byte*)data.Scan0.ToPointer();
var stride = data.Stride;
for (var u = 0; u < template.Size.X; u++)
for (var v = 0; v < template.Size.Y; v++)
if (template.Data.TileBitmapBytes[u + v * template.Size.X] != null)
{
var rawImage = template.Data.TileBitmapBytes[u + v * template.Size.X];
for (var i = 0; i < TileSize; i++)
for (var j = 0; j < TileSize; j++)
q[(v * TileSize + j) * stride + u * TileSize + i] = rawImage[i + TileSize * j];
}
else
{
for (var i = 0; i < TileSize; i++)
for (var j = 0; j < TileSize; j++)
q[(v * TileSize + j) * stride + u * TileSize + i] = 0;
}
}
bitmap.UnlockBits(data);
return bitmap;
}
}
}