TilemapImporter.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. #region License
  2. // Copyright 2021 Kastellanos Nikolaos
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. #endregion
  16. using System;
  17. using System.Collections.Generic;
  18. using System.Globalization;
  19. using System.IO;
  20. using System.Xml;
  21. using Microsoft.Xna.Framework;
  22. using Microsoft.Xna.Framework.Content.Pipeline;
  23. using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
  24. using Microsoft.Xna.Framework.Graphics;
  25. namespace nkast.Aether.Content.Pipeline
  26. {
  27. [ContentImporter(".tmx", DisplayName = "Tilemap Importer - Aether", DefaultProcessor = "TilemapProcessor")]
  28. public class TilemapImporter : ContentImporter<TilemapContent>
  29. {
  30. public override TilemapContent Import(string filename, ContentImporterContext context)
  31. {
  32. TilemapContent output;
  33. if (Path.GetExtension(filename) == ".tmx")
  34. output = ImportTMX(filename, context);
  35. else
  36. throw new InvalidContentException("File type not supported");
  37. TilemapContent.PackTiles(output, output.TileWidth, output.TileHeight);
  38. TilemapContent.RenderAtlas(output);
  39. TilemapContent.RenderMap(output);
  40. return output;
  41. }
  42. private static TilemapContent ImportTMX(string filename, ContentImporterContext context)
  43. {
  44. TilemapContent output = new TilemapContent();
  45. output.Identity = new ContentIdentity(filename);
  46. XmlDocument xmlDoc = new XmlDocument();
  47. xmlDoc.Load(filename);
  48. XmlElement map = xmlDoc.DocumentElement;
  49. string orientation = map.GetAttribute("orientation");
  50. if (orientation != "orthogonal")
  51. throw new InvalidContentException("Invalid orientation. Only 'orthogonal' is supported for atlases.");
  52. output.Renderorder = map.GetAttribute("renderorder");
  53. output.MapColumns = map.GetAttributeAsInt("width").Value;
  54. output.MapRows = map.GetAttributeAsInt("height").Value;
  55. output.TileWidth = map.GetAttributeAsInt("tilewidth").Value;
  56. output.TileHeight = map.GetAttributeAsInt("tileheight").Value;
  57. output.Width = output.MapColumns * output.TileWidth;
  58. output.Height = output.MapRows * output.TileHeight;
  59. XmlNode tilesetNode = map["tileset"];
  60. output.Firstgid = tilesetNode.GetAttributeAsInt("firstgid").Value;
  61. if (tilesetNode.Attributes["source"] != null)
  62. {
  63. string tsxFilename = tilesetNode.Attributes["source"].Value;
  64. string baseDirectory = Path.GetDirectoryName(filename);
  65. tsxFilename = Path.Combine(baseDirectory, tsxFilename);
  66. TilesetContent tileset = ImportTSX(tsxFilename, context);
  67. output.Tileset = tileset;
  68. context.AddDependency(tsxFilename);
  69. }
  70. else
  71. {
  72. string rootDirectory = Path.GetDirectoryName(filename);
  73. TilesetContent tileset = ImportTileset(tilesetNode, context, rootDirectory);
  74. output.Tileset = tileset;
  75. }
  76. XmlNode layerNode = map["layer"];
  77. int layerColumns = Convert.ToInt32(map.Attributes["width"].Value, CultureInfo.InvariantCulture);
  78. int layerRows = Convert.ToInt32(map.Attributes["height"].Value, CultureInfo.InvariantCulture);
  79. output.LayerColumns = layerColumns;
  80. output.LayerRows = layerRows;
  81. XmlNode layerDataNode = layerNode["data"];
  82. string encoding = layerDataNode.Attributes["encoding"].Value;
  83. if (encoding != "csv")
  84. throw new InvalidContentException("Invalid encoding. Only 'csv' is supported for data.");
  85. string data = layerDataNode.InnerText;
  86. string[] dataStringList = data.Split(',');
  87. int[] mapData = new int[dataStringList.Length];
  88. for (int i = 0; i < dataStringList.Length; i++)
  89. mapData[i] = Convert.ToInt32(dataStringList[i].Trim(), CultureInfo.InvariantCulture);
  90. output.MapData = mapData;
  91. return output;
  92. }
  93. private static TilesetContent ImportTSX(string tsxFilename, ContentImporterContext context)
  94. {
  95. XmlDocument xmlDoc = new XmlDocument();
  96. xmlDoc.Load(tsxFilename);
  97. XmlNode tilesetNode = xmlDoc.DocumentElement;
  98. string baseDirectory = Path.GetDirectoryName(tsxFilename);
  99. return ImportTileset(tilesetNode, context, baseDirectory);
  100. }
  101. private static TilesetContent ImportTileset(XmlNode tilesetNode, ContentImporterContext context, string baseDirectory)
  102. {
  103. TilesetContent tileset = new TilesetContent();
  104. if (tilesetNode["tileoffset"] != null)
  105. throw new InvalidContentException("tileoffset is not supported.");
  106. tileset.TileWidth = tilesetNode.GetAttributeAsInt("tilewidth").Value;
  107. tileset.tileHeight = tilesetNode.GetAttributeAsInt("tileheight").Value;
  108. BitmapContent bm = new PixelBitmapContent<Color>(tileset.TileWidth, tileset.tileHeight);
  109. Texture2DContent mt = new Texture2DContent();
  110. mt.Faces[0].Add(bm);
  111. mt.Name = "null";
  112. TileContent nullTile = new TileContent();
  113. nullTile.Tileset = tileset;
  114. nullTile.Id = -1;
  115. nullTile.SrcTexture = mt;
  116. nullTile.SrcBounds.Location = Point.Zero;
  117. nullTile.SrcBounds.Width = mt.Mipmaps[0].Width;
  118. nullTile.SrcBounds.Height = mt.Mipmaps[0].Height;
  119. nullTile.DstBounds.Location = Point.Zero;
  120. nullTile.DstBounds.Width = tileset.TileWidth;
  121. nullTile.DstBounds.Height = tileset.tileHeight;
  122. tileset.SourceTiles.Add(nullTile);
  123. foreach (XmlNode tileNode in tilesetNode.ChildNodes)
  124. {
  125. if (tileNode.Name != "tile") continue;
  126. int tileId = tileNode.GetAttributeAsInt("id").Value;
  127. XmlNode imageNode = tileNode["image"];
  128. //string format = GetAttribute(imageNode, "format");
  129. string imageSource = imageNode.GetAttribute("source");
  130. string fullImageSource = Path.Combine(baseDirectory, imageSource);
  131. TextureImporter txImporter = new TextureImporter();
  132. Texture2DContent textureContent = (Texture2DContent)txImporter.Import(fullImageSource, context);
  133. textureContent.Name = Path.GetFileNameWithoutExtension(fullImageSource);
  134. TileContent source = new TileContent();
  135. source.Tileset = tileset;
  136. source.Id = tileId;
  137. source.SrcTexture = textureContent;
  138. source.SrcBounds.Location = Point.Zero;
  139. source.SrcBounds.Width = textureContent.Mipmaps[0].Width;
  140. source.SrcBounds.Height = textureContent.Mipmaps[0].Height;
  141. source.DstBounds.Location = Point.Zero;
  142. source.DstBounds.Width = textureContent.Mipmaps[0].Width;
  143. source.DstBounds.Height = textureContent.Mipmaps[0].Height;
  144. Color? transKeyColor = imageNode.GetAttributeAsColor("trans");
  145. if (transKeyColor != null)
  146. foreach (MipmapChain mips in textureContent.Faces)
  147. foreach (BitmapContent mip in mips)
  148. ((PixelBitmapContent<Color>)mip).ReplaceColor(transKeyColor.Value, Color.Transparent);
  149. if (tileId != tileset.SourceTiles.Count-1)
  150. throw new InvalidContentException("Invalid id");
  151. tileset.SourceTiles.Add(source);
  152. }
  153. return tileset;
  154. }
  155. }
  156. }