Skip to content

Commit

Permalink
Merge pull request #827 from craftworkgames/fix_tiled_bigobject_tileset
Browse files Browse the repository at this point in the history
Add support of "Collection of Images" tileset type.
  • Loading branch information
Gandifil authored Dec 25, 2023
2 parents cedf863 + 0222eed commit 6fe961f
Show file tree
Hide file tree
Showing 15 changed files with 131 additions and 76 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>3.9.0</Version>
<Version>3.9.0.9145</Version>
<Authors>craftworkgames</Authors>
<PackageProjectUrl>https://github.com/craftworkgames/MonoGame.Extended</PackageProjectUrl>
<RepositoryUrl>https://github.com/craftworkgames/MonoGame.Extended</RepositoryUrl>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.IO;
using Microsoft.Xna.Framework.Content.Pipeline;

namespace MonoGame.Extended.Content.Pipeline;

public static class ContentImporterContextExtensions
{
public static string AddDependencyWithLogging(this ContentImporterContext context, string filePath, string source)
{
source = Path.Combine(Path.GetDirectoryName(filePath), source);
ContentLogger.Log($"Adding dependency '{source}'");
context.AddDependency(source);
return source;
}
}
4 changes: 2 additions & 2 deletions src/cs/MonoGame.Extended.Content.Pipeline/ContentItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ public void BuildExternalReference<TInput>(ContentProcessorContext context, stri

public ExternalReference<TInput> GetExternalReference<TInput>(string source)
{
if (_externalReferences.TryGetValue(source, out var contentItem))
if (source is not null && _externalReferences.TryGetValue(source, out var contentItem))
return contentItem as ExternalReference<TInput>;

return null;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using MonoGame.Extended.Tiled.Serialization;

namespace MonoGame.Extended.Content.Pipeline.Tiled;

public class TiledContentItem<T>: ContentItem<T>
{
public TiledContentItem(T data) : base(data)
{
}

public void BuildExternalReference<T>(ContentProcessorContext context, TiledMapImageContent image)
{
var parameters = new OpaqueDataDictionary
{
{ "ColorKeyColor", image.TransparentColor },
{ "ColorKeyEnabled", true }
};
BuildExternalReference<Texture2DContent>(context, image.Source, parameters);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

namespace MonoGame.Extended.Content.Pipeline.Tiled
{
public class TiledMapContentItem : ContentItem<TiledMapContent>
public class TiledMapContentItem : TiledContentItem<TiledMapContent>
{
public TiledMapContentItem(TiledMapContent data)
public TiledMapContentItem(TiledMapContent data)
: base(data)
{
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public static void Process(TiledMapObjectContent obj, ContentProcessorContext co
}
}
}


[ContentProcessor(DisplayName = "Tiled Map Processor - MonoGame.Extended")]
public class TiledMapProcessor : ContentProcessor<TiledMapContentItem, TiledMapContentItem>
Expand All @@ -95,14 +95,7 @@ public override TiledMapContentItem Process(TiledMapContentItem contentItem, Con
if (string.IsNullOrWhiteSpace(tileset.Source))
{
// Load the Texture2DContent for the tileset as it will be saved into the map content file.
//var externalReference = new ExternalReference<Texture2DContent>(tileset.Image.Source);
var parameters = new OpaqueDataDictionary
{
{ "ColorKeyColor", tileset.Image.TransparentColor },
{ "ColorKeyEnabled", true }
};
//tileset.Image.ContentRef = context.BuildAsset<Texture2DContent, Texture2DContent>(externalReference, "", parameters, "", "");
contentItem.BuildExternalReference<Texture2DContent>(context, tileset.Image.Source, parameters);
contentItem.BuildExternalReference<Texture2DContent>(context, tileset.Image);
}
else
{
Expand All @@ -114,7 +107,7 @@ public override TiledMapContentItem Process(TiledMapContentItem contentItem, Con
}

ProcessLayers(contentItem, map, context, map.Layers);

return contentItem;
}
catch (Exception ex)
Expand All @@ -132,14 +125,7 @@ private static void ProcessLayers(TiledMapContentItem contentItem, TiledMapConte
{
case TiledMapImageLayerContent imageLayer:
ContentLogger.Log($"Processing image layer '{imageLayer.Name}'");
//var externalReference = new ExternalReference<Texture2DContent>(imageLayer.Image.Source);
var parameters = new OpaqueDataDictionary
{
{ "ColorKeyColor", imageLayer.Image.TransparentColor },
{ "ColorKeyEnabled", true }
};
//imageLayer.Image.ContentRef = context.BuildAsset<Texture2DContent, Texture2DContent>(externalReference, "", parameters, "", "");
contentItem.BuildExternalReference<Texture2DContent>(context, imageLayer.Image.Source, parameters);
contentItem.BuildExternalReference<Texture2DContent>(context, imageLayer.Image);
ContentLogger.Log($"Processed image layer '{imageLayer.Name}'");
break;

Expand Down Expand Up @@ -335,4 +321,4 @@ private static Stream OpenStream(byte[] decodedData, string compressionMode)
};
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using MonoGame.Extended.Tiled.Serialization;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using MonoGame.Extended.Tiled.Serialization;

namespace MonoGame.Extended.Content.Pipeline.Tiled
{
public class TiledMapTilesetContentItem : ContentItem<TiledMapTilesetContent>
public class TiledMapTilesetContentItem : TiledContentItem<TiledMapTilesetContent>
{
public TiledMapTilesetContentItem(TiledMapTilesetContent data)
public TiledMapTilesetContentItem(TiledMapTilesetContent data)
: base(data)
{
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,18 @@ private TiledMapTilesetContent DeserializeTiledMapTilesetContent(string filePath
var tilesetSerializer = new XmlSerializer(typeof(TiledMapTilesetContent));
var tileset = (TiledMapTilesetContent)tilesetSerializer.Deserialize(reader);

tileset.Image.Source = Path.Combine(Path.GetDirectoryName(filePath), tileset.Image.Source);
ContentLogger.Log($"Adding dependency '{tileset.Image.Source}'");
context.AddDependency(tileset.Image.Source);
if (tileset.Image is not null)
tileset.Image.Source = context.AddDependencyWithLogging(filePath, tileset.Image.Source);

foreach (var tile in tileset.Tiles)
{
foreach (var obj in tile.Objects)
{
if (!string.IsNullOrWhiteSpace(obj.TemplateSource))
{
obj.TemplateSource = Path.Combine(Path.GetDirectoryName(filePath), obj.TemplateSource);
ContentLogger.Log($"Adding dependency '{obj.TemplateSource}'");

// We depend on the template.
context.AddDependency(obj.TemplateSource);
}
obj.TemplateSource = context.AddDependencyWithLogging(filePath, obj.TemplateSource);
}
if (tile.Image is not null)
tile.Image.Source = context.AddDependencyWithLogging(filePath, tile.Image.Source);
}

return tileset;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,19 @@ public override TiledMapTilesetContentItem Process(TiledMapTilesetContentItem co

ContentLogger.Logger = context.Logger;
ContentLogger.Log($"Processing tileset '{tileset.Name}'");

// Build the Texture2D asset and load it as it will be saved as part of this tileset file.
//var externalReference = new ExternalReference<Texture2DContent>(tileset.Image.Source);
var parameters = new OpaqueDataDictionary
{
{ "ColorKeyColor", tileset.Image.TransparentColor },
{ "ColorKeyEnabled", true }
};
//tileset.Image.ContentRef = context.BuildAsset<Texture2DContent, Texture2DContent>(externalReference, "", parameters, "", "");
contentItem.BuildExternalReference<Texture2DContent>(context, tileset.Image.Source, parameters);
if (tileset.Image is not null)
contentItem.BuildExternalReference<Texture2DContent>(context, tileset.Image);

foreach (var tile in tileset.Tiles)
{
foreach (var obj in tile.Objects)
{
TiledMapContentHelper.Process(obj, context);
}
if (tile.Image is not null)
contentItem.BuildExternalReference<Texture2DContent>(context, tile.Image);
}

ContentLogger.Log($"Processed tileset '{tileset.Name}'");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ protected override void Write(ContentWriter writer, TiledMapTilesetContentItem c

public static void WriteTileset(ContentWriter writer, TiledMapTilesetContent tileset, IExternalReferenceRepository externalReferenceRepository)
{
var externalReference = externalReferenceRepository.GetExternalReference<Texture2DContent>(tileset.Image.Source);

var externalReference = externalReferenceRepository.GetExternalReference<Texture2DContent>(tileset.Image?.Source);
writer.WriteExternalReference(externalReference);

writer.Write(tileset.TileWidth);
writer.Write(tileset.TileHeight);
writer.Write(tileset.TileCount);
Expand All @@ -42,13 +42,17 @@ public static void WriteTileset(ContentWriter writer, TiledMapTilesetContent til
writer.Write(tileset.Tiles.Count);

foreach (var tilesetTile in tileset.Tiles)
WriteTilesetTile(writer, tilesetTile);
WriteTilesetTile(writer, tilesetTile, externalReferenceRepository);

writer.WriteTiledMapProperties(tileset.Properties);
}

private static void WriteTilesetTile(ContentWriter writer, TiledMapTilesetTileContent tilesetTile)
private static void WriteTilesetTile(ContentWriter writer, TiledMapTilesetTileContent tilesetTile,
IExternalReferenceRepository externalReferenceRepository)
{
var externalReference = externalReferenceRepository.GetExternalReference<Texture2DContent>(tilesetTile.Image?.Source);
writer.WriteExternalReference(externalReference);

writer.Write(tilesetTile.LocalIdentifier);
writer.Write(tilesetTile.Type);
writer.Write(tilesetTile.Frames.Count);
Expand Down
10 changes: 7 additions & 3 deletions src/cs/MonoGame.Extended.Tiled/Renderers/TiledMapModelBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,16 @@ private IEnumerable<TiledMapLayerModel> CreateTileLayerModels(TiledMap map, Tile
var tileGid = tile.GlobalIdentifier;
var localTileIdentifier = tileGid - firstGlobalIdentifier;
var position = GetTilePosition(map, tile);
var tilesetColumns = tileset.Columns == 0 ? 1 : tileset.Columns; // fixes a problem (what problem exactly?)
var sourceRectangle = TiledMapHelper.GetTileSourceRectangle(localTileIdentifier, tileset.TileWidth, tileset.TileHeight, tilesetColumns, tileset.Margin, tileset.Spacing);
var sourceRectangle = tileset.GetTileRegion(localTileIdentifier);
var flipFlags = tile.Flags;

// animated tiles
var tilesetTile = tileset.Tiles.FirstOrDefault(x => x.LocalTileIdentifier == localTileIdentifier);
if (tilesetTile?.Texture is not null)
{
position.Y += map.TileHeight - sourceRectangle.Height;
texture = tilesetTile.Texture;
}

if (tilesetTile is TiledMapTilesetAnimatedTile animatedTilesetTile)
{
Expand Down Expand Up @@ -117,4 +121,4 @@ private static Point2 GetTilePosition(TiledMap map, TiledMapTile mapTile)
}
}
}
}
}
8 changes: 6 additions & 2 deletions src/cs/MonoGame.Extended.Tiled/TiledMapTileset.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MonoGame.Extended.TextureAtlases;
Expand Down Expand Up @@ -58,7 +59,10 @@ public TextureRegion2D GetRegion(int column, int row)

public Rectangle GetTileRegion(int localTileIdentifier)
{
return TiledMapHelper.GetTileSourceRectangle(localTileIdentifier, TileWidth, TileHeight, Columns, Margin, Spacing);
return Texture is not null
? TiledMapHelper.GetTileSourceRectangle(localTileIdentifier, TileWidth, TileHeight, Columns, Margin,
Spacing)
: Tiles.FirstOrDefault(x => x.LocalTileIdentifier == localTileIdentifier).Texture.Bounds;
}
}
}
}
8 changes: 5 additions & 3 deletions src/cs/MonoGame.Extended.Tiled/TiledMapTilesetAnimatedTile.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace MonoGame.Extended.Tiled
{
Expand All @@ -12,8 +13,9 @@ public class TiledMapTilesetAnimatedTile : TiledMapTilesetTile
public ReadOnlyCollection<TiledMapTilesetTileAnimationFrame> AnimationFrames { get; }
public TiledMapTilesetTileAnimationFrame CurrentAnimationFrame { get; private set; }

public TiledMapTilesetAnimatedTile(int localTileIdentifier, TiledMapTilesetTileAnimationFrame[] frames, string type = null, TiledMapObject[] objects = null)
: base(localTileIdentifier, type, objects)
public TiledMapTilesetAnimatedTile(int localTileIdentifier,
TiledMapTilesetTileAnimationFrame[] frames, string type = null, TiledMapObject[] objects = null, Texture2D texture = null)
: base(localTileIdentifier, type, objects, texture)
{
if (frames.Length == 0) throw new InvalidOperationException("There must be at least one tileset animation frame");

Expand All @@ -33,4 +35,4 @@ public void Update(GameTime gameTime)
CurrentAnimationFrame = AnimationFrames[_frameIndex];
}
}
}
}
39 changes: 25 additions & 14 deletions src/cs/MonoGame.Extended.Tiled/TiledMapTilesetReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,35 @@ public static TiledMapTileset ReadTileset(ContentReader reader)
var tileset = new TiledMapTileset(texture, tileWidth, tileHeight, tileCount, spacing, margin, columns);

for (var tileIndex = 0; tileIndex < explicitTileCount; tileIndex++)
{
var localTileIdentifier = reader.ReadInt32();
var type = reader.ReadString();
var animationFramesCount = reader.ReadInt32();
var tilesetTile = animationFramesCount <= 0
? ReadTiledMapTilesetTile(reader, tileset, objects =>
new TiledMapTilesetTile(localTileIdentifier, type, objects))
: ReadTiledMapTilesetTile(reader, tileset, objects =>
new TiledMapTilesetAnimatedTile(localTileIdentifier, ReadTiledMapTilesetAnimationFrames(reader, tileset, animationFramesCount), type, objects));

ReadProperties(reader, tilesetTile.Properties);
tileset.Tiles.Add(tilesetTile);
}
ReadTile(reader, tileset);

ReadProperties(reader, tileset.Properties);
return tileset;
}

private static TiledMapTilesetTileAnimationFrame[] ReadTiledMapTilesetAnimationFrames(ContentReader reader, TiledMapTileset tileset, int animationFramesCount)
private static void ReadTile(ContentReader reader, TiledMapTileset tileset)
{
var texture = reader.ReadExternalReference<Texture2D>();

var localTileIdentifier = reader.ReadInt32();
var type = reader.ReadString();
var animationFramesCount = reader.ReadInt32();
var objectCount = reader.ReadInt32();
var objects = new TiledMapObject[objectCount];

for (var i = 0; i < objectCount; i++)
objects[i] = ReadTiledMapObject(reader, tileset);

var tilesetTile = animationFramesCount <= 0
? new TiledMapTilesetTile(localTileIdentifier, type, objects, texture)
: new TiledMapTilesetAnimatedTile(localTileIdentifier,
ReadTiledMapTilesetAnimationFrames(reader, tileset, animationFramesCount), type, objects, texture);

ReadProperties(reader, tilesetTile.Properties);
tileset.Tiles.Add(tilesetTile);
}

private static TiledMapTilesetTileAnimationFrame[] ReadTiledMapTilesetAnimationFrames(ContentReader reader, TiledMapTileset tileset, int animationFramesCount)
{
var animationFrames = new TiledMapTilesetTileAnimationFrame[animationFramesCount];

Expand All @@ -64,6 +74,7 @@ private static TiledMapTilesetTileAnimationFrame[] ReadTiledMapTilesetAnimationF

private static TiledMapTilesetTile ReadTiledMapTilesetTile(ContentReader reader, TiledMapTileset tileset, Func<TiledMapObject[], TiledMapTilesetTile> createTile)
{
var texture = reader.ReadExternalReference<Texture2D>();
var objectCount = reader.ReadInt32();
var objects = new TiledMapObject[objectCount];

Expand Down
Loading

0 comments on commit 6fe961f

Please sign in to comment.