diff --git a/MonoGame.Aseprite.sln b/MonoGame.Aseprite.sln index d8104ed2..7b065ba0 100644 --- a/MonoGame.Aseprite.sln +++ b/MonoGame.Aseprite.sln @@ -12,13 +12,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonoGame.Aseprite", "source EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonoGame.Aseprite.Content.Pipeline", "source\MonoGame.Aseprite.Content.Pipeline\MonoGame.Aseprite.Content.Pipeline.csproj", "{49903681-88CC-4B14-AD02-C475E78D4CE2}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{FFCB306E-00AB-4CCF-A88A-4FE52D1E9778}" - ProjectSection(SolutionItems) = preProject - tests\Directory.Build.props = tests\Directory.Build.props - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MonoGame.Aseprite.Tests", "tests\MonoGame.Aseprite.Tests\MonoGame.Aseprite.Tests.csproj", "{133DE9C3-4D1A-4FF1-8994-1174424B2223}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{78ECB0CA-72B0-4E08-BAB1-8BF2B98829D9}" ProjectSection(SolutionItems) = preProject build\Directory.Build.props = build\Directory.Build.props @@ -49,10 +42,6 @@ Global {49903681-88CC-4B14-AD02-C475E78D4CE2}.Debug|Any CPU.Build.0 = Debug|Any CPU {49903681-88CC-4B14-AD02-C475E78D4CE2}.Release|Any CPU.ActiveCfg = Release|Any CPU {49903681-88CC-4B14-AD02-C475E78D4CE2}.Release|Any CPU.Build.0 = Release|Any CPU - {133DE9C3-4D1A-4FF1-8994-1174424B2223}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {133DE9C3-4D1A-4FF1-8994-1174424B2223}.Debug|Any CPU.Build.0 = Debug|Any CPU - {133DE9C3-4D1A-4FF1-8994-1174424B2223}.Release|Any CPU.ActiveCfg = Release|Any CPU - {133DE9C3-4D1A-4FF1-8994-1174424B2223}.Release|Any CPU.Build.0 = Release|Any CPU {4E3BCA48-A076-4ECE-A80A-F254DAE2D18E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4E3BCA48-A076-4ECE-A80A-F254DAE2D18E}.Debug|Any CPU.Build.0 = Debug|Any CPU {4E3BCA48-A076-4ECE-A80A-F254DAE2D18E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -64,7 +53,6 @@ Global GlobalSection(NestedProjects) = preSolution {B5D9570E-E9BF-482B-BD73-8EA6EC4330F8} = {CF520A36-B1B8-4CFA-9835-C3345A65D57B} {49903681-88CC-4B14-AD02-C475E78D4CE2} = {CF520A36-B1B8-4CFA-9835-C3345A65D57B} - {133DE9C3-4D1A-4FF1-8994-1174424B2223} = {FFCB306E-00AB-4CCF-A88A-4FE52D1E9778} {4E3BCA48-A076-4ECE-A80A-F254DAE2D18E} = {78ECB0CA-72B0-4E08-BAB1-8BF2B98829D9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/source/MonoGame.Aseprite.Content.Pipeline/AsepriteFileImportResult.cs b/source/MonoGame.Aseprite.Content.Pipeline/AsepriteFileImportResult.cs index 7169eaf7..5216f4c4 100644 --- a/source/MonoGame.Aseprite.Content.Pipeline/AsepriteFileImportResult.cs +++ b/source/MonoGame.Aseprite.Content.Pipeline/AsepriteFileImportResult.cs @@ -24,4 +24,4 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE namespace MonoGame.Aseprite.Content.Pipeline; -internal record AsepriteFileImportResult(byte[] Data, AsepriteFile AsepriteFile); \ No newline at end of file +internal record AsepriteFileImportResult(string FilePath); \ No newline at end of file diff --git a/tests/MonoGame.Aseprite.Tests/FileUtils.cs b/source/MonoGame.Aseprite.Content.Pipeline/AsepriteFileProcessResult.cs similarity index 85% rename from tests/MonoGame.Aseprite.Tests/FileUtils.cs rename to source/MonoGame.Aseprite.Content.Pipeline/AsepriteFileProcessResult.cs index 7a837e09..47cefe86 100644 --- a/tests/MonoGame.Aseprite.Tests/FileUtils.cs +++ b/source/MonoGame.Aseprite.Content.Pipeline/AsepriteFileProcessResult.cs @@ -22,12 +22,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- */ -namespace MonoGame.Aseprite.Tests; +namespace MonoGame.Aseprite.Content.Pipeline; -internal static class FileUtils -{ - internal static string GetLocalPath(string fileName) - { - return Path.Combine(Environment.CurrentDirectory, "Files", fileName); - } -} +internal record AsepriteFileProcessResult(string Name, byte[] Data); \ No newline at end of file diff --git a/source/MonoGame.Aseprite.Content.Pipeline/ContentImportException.cs b/source/MonoGame.Aseprite.Content.Pipeline/ContentImportException.cs deleted file mode 100644 index bd06e2b1..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/ContentImportException.cs +++ /dev/null @@ -1,33 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ -namespace MonoGame.Aseprite.Content.Pipeline; - -internal sealed class ContentImportException : Exception -{ - public string? ContentPath { get; set; } = default; - public ContentImportException() { } - public ContentImportException(string message) : base(message) { } - public ContentImportException(string message, string contentPath) : base(message) => ContentPath = contentPath; - public ContentImportException(string message, string contentPath, Exception? innerException) : base(message, innerException) => ContentPath = contentPath; -} \ No newline at end of file diff --git a/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/AnimatedTilemapContent.cs b/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/AnimatedTilemapContent.cs deleted file mode 100644 index 7dd45f36..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/AnimatedTilemapContent.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.ContentTypes; - -internal record AnimatedTilemapContent(RawAnimatedTilemap RawAnimatedTilemap, Texture2DContent[] Texture2DContents); \ No newline at end of file diff --git a/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/SpriteContent.cs b/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/SpriteContent.cs deleted file mode 100644 index 57f78b8d..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/SpriteContent.cs +++ /dev/null @@ -1,29 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; - -namespace MonoGame.Aseprite.Content.Pipeline.ContentTypes; - -internal record SpriteContent(string Name, Texture2DContent Texture2DContent); \ No newline at end of file diff --git a/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/SpriteSheetContent.cs b/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/SpriteSheetContent.cs deleted file mode 100644 index 1ad47794..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/SpriteSheetContent.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.ContentTypes; - -internal record SpriteSheetContent(RawSpriteSheet RawSpriteSheet, Texture2DContent Texture2DContent); \ No newline at end of file diff --git a/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/TextureAtlasContent.cs b/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/TextureAtlasContent.cs deleted file mode 100644 index d16d4da8..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/TextureAtlasContent.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.ContentTypes; - -internal record TextureAtlasContent(RawTextureAtlas RawTextureAtlas, Texture2DContent Texture2DContent); \ No newline at end of file diff --git a/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/TilemapContent.cs b/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/TilemapContent.cs deleted file mode 100644 index 579b61d3..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/TilemapContent.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.ContentTypes; - -internal record TilemapContent(RawTilemap RawTilemap, Texture2DContent[] Texture2DContents); \ No newline at end of file diff --git a/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/TilesetContent.cs b/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/TilesetContent.cs deleted file mode 100644 index af2b70e2..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/ContentTypes/TilesetContent.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.ContentTypes; - -internal record TilesetContent(RawTileset RawTileset, Texture2DContent Texture2DContent); \ No newline at end of file diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Importers/AsepriteFileContentImporter.cs b/source/MonoGame.Aseprite.Content.Pipeline/Importers/AsepriteFileContentImporter.cs index 7d2e7c55..e2f163e5 100644 --- a/source/MonoGame.Aseprite.Content.Pipeline/Importers/AsepriteFileContentImporter.cs +++ b/source/MonoGame.Aseprite.Content.Pipeline/Importers/AsepriteFileContentImporter.cs @@ -33,18 +33,6 @@ internal class AsepriteFileContentImporter : ContentImporter - + - - + - - - + \ No newline at end of file diff --git a/source/MonoGame.Aseprite.Content.Pipeline/ProcessParamterException.cs b/source/MonoGame.Aseprite.Content.Pipeline/ProcessParamterException.cs deleted file mode 100644 index 24fd28b7..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/ProcessParamterException.cs +++ /dev/null @@ -1,34 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ -namespace MonoGame.Aseprite.Content.Pipeline; - -internal sealed class ProcessorParameterException : Exception -{ - public string? ProcessorName { get; set; } = default; - public string? ParameterName { get; set; } = default; - public ProcessorParameterException() { } - public ProcessorParameterException(string message) : base(message) { } - public ProcessorParameterException(string message, string processorName, string parameterName) : base(message) => (ProcessorName, ParameterName) = (processorName, parameterName); - public ProcessorParameterException(string message, string contentPath, string processorName, string parameterName, Exception? innerException) : base(message, innerException) => (ProcessorName, ParameterName) = (processorName, parameterName); -} \ No newline at end of file diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Processors/AnimatedTilemapContentProcessor.cs b/source/MonoGame.Aseprite.Content.Pipeline/Processors/AnimatedTilemapContentProcessor.cs deleted file mode 100644 index 74891cb1..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/Processors/AnimatedTilemapContentProcessor.cs +++ /dev/null @@ -1,70 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.ComponentModel; -using Microsoft.Xna.Framework.Content.Pipeline; -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using MonoGame.Aseprite.Content.Pipeline.ContentTypes; -using MonoGame.Aseprite.Content.Processors; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.Processors; - -[ContentProcessor(DisplayName = "Aseprite Animated Tilemap Processor - MonoGame.Aseprite")] -internal sealed class AnimatedTilemapContentProcessor : ContentProcessor -{ - [DisplayName("Only Visible Layers")] - public bool OnlyVisibleLayer { get; set; } = true; - - [DisplayName("Generate Mipmaps")] - public bool GenerateMipmaps { get; set; } = false; - - public override AnimatedTilemapContent Process(AsepriteFileImportResult content, ContentProcessorContext context) - { - RawAnimatedTilemap rawAnimatedTilemap = AnimatedTilemapProcessor.ProcessRaw(content.AsepriteFile, OnlyVisibleLayer); - - Texture2DContent[] texture2DContents = ProcessTilesetTexture(rawAnimatedTilemap.RawTilesets); - return new(rawAnimatedTilemap, texture2DContents); - } - - private Texture2DContent[] ProcessTilesetTexture(ReadOnlySpan rawTilesets) - { - Texture2DContent[] texture2DContents = new Texture2DContent[rawTilesets.Length]; - - for (int i = 0; i < rawTilesets.Length; i++) - { - RawTexture rawTexture = rawTilesets[i].RawTexture; - - Texture2DContent texture2DContent = ProcessorHelpers.CreateTexture2DContent(rawTexture.Pixels, rawTexture.Width, rawTexture.Height); - - if (GenerateMipmaps) - { - texture2DContent.GenerateMipmaps(true); - } - texture2DContents[i] = texture2DContent; - } - - return texture2DContents; - } -} diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Processors/AsepriteFileContentProcessor.cs b/source/MonoGame.Aseprite.Content.Pipeline/Processors/AsepriteFileContentProcessor.cs index f91aff24..a63537aa 100644 --- a/source/MonoGame.Aseprite.Content.Pipeline/Processors/AsepriteFileContentProcessor.cs +++ b/source/MonoGame.Aseprite.Content.Pipeline/Processors/AsepriteFileContentProcessor.cs @@ -27,11 +27,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE namespace MonoGame.Aseprite.Content.Pipeline.Processors; [ContentProcessor(DisplayName = "Aseprite File Processor - MonoGame.Aseprite")] -internal sealed class AsepriteFileContentProcessor : ContentProcessor +internal sealed class AsepriteFileContentProcessor : ContentProcessor { - public override AsepriteFileImportResult Process(AsepriteFileImportResult content, ContentProcessorContext context) + public override AsepriteFileProcessResult Process(AsepriteFileImportResult content, ContentProcessorContext context) { - // No processing needed since this is just for importing the file content itself. - return content; + string name = Path.GetFileNameWithoutExtension(content.FilePath); + byte[] data = File.ReadAllBytes(content.FilePath); + AsepriteFileProcessResult result = new AsepriteFileProcessResult(name, data); + return result; } } diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Processors/ProcessorHelpers.cs b/source/MonoGame.Aseprite.Content.Pipeline/Processors/ProcessorHelpers.cs deleted file mode 100644 index 9dd94348..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/Processors/ProcessorHelpers.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; - -namespace MonoGame.Aseprite.Content.Pipeline.Processors; - -internal static class ProcessorHelpers -{ - internal static Texture2DContent CreateTexture2DContent(ReadOnlySpan pixels, int width, int height) - { - PixelBitmapContent face = new(width, height); - - for (int i = 0; i < pixels.Length; i++) - { - int x = i % width; - int y = i / width; - - face.SetPixel(x, y, pixels[i]); - } - - Texture2DContent textureContent = new(); - textureContent.Faces[0].Add(face); - return textureContent; - } -} diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Processors/SpriteContentProcessor.cs b/source/MonoGame.Aseprite.Content.Pipeline/Processors/SpriteContentProcessor.cs deleted file mode 100644 index a09bcd56..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/Processors/SpriteContentProcessor.cs +++ /dev/null @@ -1,85 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.ComponentModel; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Content.Pipeline; -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.Content.Pipeline.ContentTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.Processors; - -[ContentProcessor(DisplayName = "Aseprite Sprite Processor - MonoGame.Aseprite")] -internal sealed class SpriteContentProcessor : ContentProcessor -{ - [DisplayName("Zero Indexed Frames")] - public bool ZeroIndexedFrames {get; set;} = true; - - [DisplayName("Frame Index")] - public int FrameIndex { get; set; } = 0; - - [DisplayName("Only Visible Layers")] - public bool OnlyVisibleLayers { get; set; } = true; - - [DisplayName("Include Background Layer")] - public bool IncludeBackgroundLayer { get; set; } = false; - - [DisplayName("Include Tilemap Layers")] - public bool IncludeTilemapLayers { get; set; } = true; - - [DisplayName("Generate Mipmaps")] - public bool GenerateMipmaps { get; set; } = false; - - public override SpriteContent Process(AsepriteFileImportResult content, ContentProcessorContext context) - { - FrameIndex = ZeroIndexedFrames ? FrameIndex : FrameIndex - 1; - - if (FrameIndex < 0 || FrameIndex >= content.AsepriteFile.FrameCount) - { - ProcessorParameterException ex; - if(ZeroIndexedFrames) - { - ex = new ($"The 'Frame Index' parameter cannot be less than zero or greater than or equal to the total number of frames in the Aseprite file", nameof(SpriteContentProcessor), nameof(FrameIndex)); - } - else - { - ex = new ($"The 'Frame Index' parameter cannot be less than one or greater than the total number of frames in the Aseprite file when {nameof(ZeroIndexedFrames)} is 'false'.", nameof(SpriteContentProcessor), nameof(FrameIndex)); - } - - throw ex; - } - - AsepriteFrame aseFrame = content.AsepriteFile.Frames[FrameIndex]; - Color[] pixels = aseFrame.FlattenFrame(OnlyVisibleLayers, IncludeBackgroundLayer, IncludeTilemapLayers); - Texture2DContent texture2DContent = ProcessorHelpers.CreateTexture2DContent(pixels, aseFrame.Width, aseFrame.Height); - - if (GenerateMipmaps) - { - texture2DContent.GenerateMipmaps(true); - } - - return new(aseFrame.Name, texture2DContent); - } -} diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Processors/SpriteSheetContentProcessor.cs b/source/MonoGame.Aseprite.Content.Pipeline/Processors/SpriteSheetContentProcessor.cs deleted file mode 100644 index 3feb6d99..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/Processors/SpriteSheetContentProcessor.cs +++ /dev/null @@ -1,78 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.ComponentModel; -using Microsoft.Xna.Framework.Content.Pipeline; -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using MonoGame.Aseprite.Content.Pipeline.ContentTypes; -using MonoGame.Aseprite.Content.Processors; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.Processors; - -[ContentProcessor(DisplayName = "Aseprite SpriteSheet Processor - MonoGame.Aseprite")] -internal sealed class SpriteSheetContentProcessor : ContentProcessor -{ - [DisplayName("Frame Index")] - public int FrameIndex { get; set; } = 0; - - [DisplayName("Only Visible Layers")] - public bool OnlyVisibleLayers { get; set; } = true; - - [DisplayName("Include Background Layer")] - public bool IncludeBackgroundLayer { get; set; } = false; - - [DisplayName("Include Tilemap Layers")] - public bool IncludeTilemapLayers { get; set; } = true; - - [DisplayName("Merge Duplicate Frames")] - public bool MergeDuplicateFrames { get; set; } = true; - - [DisplayName("Border Padding")] - public int BorderPadding { get; set; } = 0; - - [DisplayName("Spacing")] - public int Spacing { get; set; } = 0; - - [DisplayName("Inner Padding")] - public int InnerPadding { get; set; } = 0; - - [DisplayName("Generate Mipmaps")] - public bool GenerateMipmaps { get; set; } = false; - - public override SpriteSheetContent Process(AsepriteFileImportResult content, ContentProcessorContext context) - { - RawSpriteSheet rawSpriteSheet = SpriteSheetProcessor.ProcessRaw(content.AsepriteFile, OnlyVisibleLayers, IncludeBackgroundLayer, IncludeTilemapLayers, MergeDuplicateFrames, BorderPadding, Spacing, InnerPadding); - RawTexture rawTexture = rawSpriteSheet.RawTextureAtlas.RawTexture; - - Texture2DContent texture2DContent = ProcessorHelpers.CreateTexture2DContent(rawTexture.Pixels, rawTexture.Width, rawTexture.Height); - - if (GenerateMipmaps) - { - texture2DContent.GenerateMipmaps(true); - } - - return new(rawSpriteSheet, texture2DContent); - } -} diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Processors/TextureAtlasContentProcessor.cs b/source/MonoGame.Aseprite.Content.Pipeline/Processors/TextureAtlasContentProcessor.cs deleted file mode 100644 index 2fd2d824..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/Processors/TextureAtlasContentProcessor.cs +++ /dev/null @@ -1,75 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.ComponentModel; -using Microsoft.Xna.Framework.Content.Pipeline; -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using MonoGame.Aseprite.Content.Pipeline.ContentTypes; -using MonoGame.Aseprite.Content.Processors; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.Processors; - -[ContentProcessor(DisplayName = "Aseprite TextureAtlas Processor - MonoGame.Aseprite")] -internal sealed class TextureAtlasContentProcessor : ContentProcessor -{ - [DisplayName("Only Visible Layers")] - public bool OnlyVisibleLayers { get; set; } = true; - - [DisplayName("Include Background Layer")] - public bool IncludeBackgroundLayer { get; set; } = false; - - [DisplayName("Include Tilemap Layers")] - public bool IncludeTilemapLayers { get; set; } = true; - - [DisplayName("Merge Duplicate Frames")] - public bool MergeDuplicateFrames { get; set; } = true; - - [DisplayName("Border Padding")] - public int BorderPadding { get; set; } = 0; - - [DisplayName("Spacing")] - public int Spacing { get; set; } = 0; - - [DisplayName("Inner Padding")] - public int InnerPadding { get; set; } = 0; - - [DisplayName("Generate Mipmaps")] - public bool GenerateMipmaps { get; set; } = false; - - public override TextureAtlasContent Process(AsepriteFileImportResult content, ContentProcessorContext context) - { - RawTextureAtlas rawTextureAtlas = TextureAtlasProcessor.ProcessRaw(content.AsepriteFile, OnlyVisibleLayers, IncludeBackgroundLayer, IncludeTilemapLayers, MergeDuplicateFrames, BorderPadding, Spacing, InnerPadding); - RawTexture rawTexture = rawTextureAtlas.RawTexture; - - Texture2DContent texture2DContent = ProcessorHelpers.CreateTexture2DContent(rawTexture.Pixels, rawTexture.Width, rawTexture.Height); - - if (GenerateMipmaps) - { - texture2DContent.GenerateMipmaps(true); - } - - return new(rawTextureAtlas, texture2DContent); - } -} diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Processors/TilemapContentProcessor.cs b/source/MonoGame.Aseprite.Content.Pipeline/Processors/TilemapContentProcessor.cs deleted file mode 100644 index a741fcbc..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/Processors/TilemapContentProcessor.cs +++ /dev/null @@ -1,77 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.ComponentModel; -using Microsoft.Xna.Framework.Content.Pipeline; -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using MonoGame.Aseprite.Content.Pipeline.ContentTypes; -using MonoGame.Aseprite.Content.Processors; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.Processors; - -[ContentProcessor(DisplayName = "Aseprite Tilemap Processor - MonoGame.Aseprite")] -internal sealed class TilemapContentProcessor : ContentProcessor -{ - [DisplayName("Zero Indexed Frames")] - public bool ZeroIndexedFrames { get; set; } = true; - - [DisplayName("Frame Index")] - public int FrameIndex { get; set; } = 0; - - [DisplayName("Only Visible Layers")] - public bool OnlyVisibleLayer { get; set; } = true; - - [DisplayName("Generate Mipmaps")] - public bool GenerateMipmaps { get; set; } = false; - - public override TilemapContent Process(AsepriteFileImportResult content, ContentProcessorContext context) - { - content.AsepriteFile.ZeroIndexedFrames = ZeroIndexedFrames; - RawTilemap rawTilemap = TilemapProcessor.ProcessRaw(content.AsepriteFile, FrameIndex, OnlyVisibleLayer); - Texture2DContent[] texture2DContents = ProcessTilesetTexture(rawTilemap.RawTilesets); - return new(rawTilemap, texture2DContents); - } - - private Texture2DContent[] ProcessTilesetTexture(ReadOnlySpan rawTilesets) - { - Texture2DContent[] texture2DContents = new Texture2DContent[rawTilesets.Length]; - - for (int i = 0; i < rawTilesets.Length; i++) - { - RawTexture rawTexture = rawTilesets[i].RawTexture; - - Texture2DContent texture2DContent = ProcessorHelpers.CreateTexture2DContent(rawTexture.Pixels, rawTexture.Width, rawTexture.Height); - - if (GenerateMipmaps) - { - texture2DContent.GenerateMipmaps(true); - } - - texture2DContents[i] = texture2DContent; - } - - return texture2DContents; - } -} diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Processors/TilesetContentProcessor.cs b/source/MonoGame.Aseprite.Content.Pipeline/Processors/TilesetContentProcessor.cs deleted file mode 100644 index eb810abd..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/Processors/TilesetContentProcessor.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.ComponentModel; -using Microsoft.Xna.Framework.Content.Pipeline; -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using MonoGame.Aseprite.Content.Pipeline.ContentTypes; -using MonoGame.Aseprite.Content.Processors; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.Processors; - -[ContentProcessor(DisplayName = "Aseprite Tileset Processor - MonoGame.Aseprite")] -internal sealed class TilesetContentProcessor : ContentProcessor -{ - [DisplayName("Tileset Name")] - public string TilesetName { get; set; } = string.Empty; - - [DisplayName("Generate Mipmaps")] - public bool GenerateMipmaps { get; set; } = false; - - public override TilesetContent Process(AsepriteFileImportResult content, ContentProcessorContext context) - { - RawTileset rawTileset = TilesetProcessor.ProcessRaw(content.AsepriteFile, TilesetName); - RawTexture rawTexture = rawTileset.RawTexture; - - Texture2DContent texture2DContent = ProcessorHelpers.CreateTexture2DContent(rawTexture.Pixels, rawTexture.Width, rawTexture.Height); - - if (GenerateMipmaps) - { - texture2DContent.GenerateMipmaps(true); - } - - return new(rawTileset, texture2DContent); - } -} diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Writers/AnimatedTilemapContentTypeWriter.cs b/source/MonoGame.Aseprite.Content.Pipeline/Writers/AnimatedTilemapContentTypeWriter.cs deleted file mode 100644 index 61800578..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/Writers/AnimatedTilemapContentTypeWriter.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content.Pipeline; -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler; -using MonoGame.Aseprite.Content.Pipeline.ContentTypes; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.Writers; - -[ContentTypeWriter] -internal sealed class AnimatedTilemapContentTypeWriter : ContentTypeWriter -{ - protected override void Write(ContentWriter writer, AnimatedTilemapContent content) - { - RawAnimatedTilemap rawAnimated = content.RawAnimatedTilemap; - - writer.Write(rawAnimated.Name); - WriteTilesets(writer, rawAnimated.RawTilesets, content.Texture2DContents); - writer.Write(rawAnimated.RawTilemapFrames); - } - - private void WriteTilesets(ContentWriter writer, ReadOnlySpan rawTilesets, ReadOnlySpan tilesetTextures) - { - writer.Write(rawTilesets.Length); - - for (int i = 0; i < rawTilesets.Length; i++) - { - writer.Write(rawTilesets[i].Name); - writer.Write(rawTilesets[i].ID); - writer.Write(rawTilesets[i].TileWidth); - writer.Write(rawTilesets[i].TileHeight); - writer.WriteObject(tilesetTextures[i]); - } - } - - public override string GetRuntimeType(TargetPlatform targetPlatform) => - "MonoGame.Aseprite.Tilemaps.AnimatedTilemap, MonoGame.Aseprite"; - - public override string GetRuntimeReader(TargetPlatform targetPlatform) => - "MonoGame.Aseprite.Content.Pipeline.Readers.AnimatedTilemapContentTypeReader, MonoGame.Aseprite"; -} diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Writers/AsepriteFileContentTypeWriter.cs b/source/MonoGame.Aseprite.Content.Pipeline/Writers/AsepriteFileContentTypeWriter.cs index e457982a..c2024685 100644 --- a/source/MonoGame.Aseprite.Content.Pipeline/Writers/AsepriteFileContentTypeWriter.cs +++ b/source/MonoGame.Aseprite.Content.Pipeline/Writers/AsepriteFileContentTypeWriter.cs @@ -28,10 +28,11 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE namespace MonoGame.Aseprite.Content.Pipeline.Writers; [ContentTypeWriter] -internal sealed class AsepriteFileContentTypeWriter : ContentTypeWriter +internal sealed class AsepriteFileContentTypeWriter : ContentTypeWriter { - protected override void Write(ContentWriter writer, AsepriteFileImportResult content) + protected override void Write(ContentWriter writer, AsepriteFileProcessResult content) { + writer.Write(content.Name); writer.Write(content.Data.Length); writer.Write(content.Data); } diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Writers/SpriteContentTypeWriter.cs b/source/MonoGame.Aseprite.Content.Pipeline/Writers/SpriteContentTypeWriter.cs deleted file mode 100644 index d80bfc83..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/Writers/SpriteContentTypeWriter.cs +++ /dev/null @@ -1,45 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content.Pipeline; -using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler; -using MonoGame.Aseprite.Content.Pipeline.ContentTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.Writers; - -[ContentTypeWriter] -internal sealed class SpriteContentTypeWriter : ContentTypeWriter -{ - protected override void Write(ContentWriter writer, SpriteContent content) - { - writer.Write(content.Name); - writer.WriteObject(content.Texture2DContent); - } - - public override string GetRuntimeType(TargetPlatform targetPlatform) => - "MonoGame.Aseprite.Sprites.Sprite, MonoGame.Aseprite"; - - public override string GetRuntimeReader(TargetPlatform targetPlatform) => - "MonoGame.Aseprite.Content.Pipeline.Readers.SpriteContentTypeReader, MonoGame.Aseprite"; -} diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Writers/SpriteSheetContentTypeWriter.cs b/source/MonoGame.Aseprite.Content.Pipeline/Writers/SpriteSheetContentTypeWriter.cs deleted file mode 100644 index c55bbbc3..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/Writers/SpriteSheetContentTypeWriter.cs +++ /dev/null @@ -1,50 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content.Pipeline; -using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler; -using MonoGame.Aseprite.Content.Pipeline.ContentTypes; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.Writers; - -[ContentTypeWriter] -internal sealed class SpriteSheetContentTypeWriter : ContentTypeWriter -{ - protected override void Write(ContentWriter writer, SpriteSheetContent content) - { - RawSpriteSheet rawSpriteSheet = content.RawSpriteSheet; - writer.Write(rawSpriteSheet.Name); - writer.Write(rawSpriteSheet.RawTextureAtlas.Name); - writer.WriteObject(content.Texture2DContent); - writer.Write(rawSpriteSheet.RawTextureAtlas.RawTextureRegions); - writer.Write(rawSpriteSheet.RawAnimationTags); - } - - public override string GetRuntimeType(TargetPlatform targetPlatform) => - "MonoGame.Aseprite.Sprites.SpriteSheet, MonoGame.Aseprite"; - - public override string GetRuntimeReader(TargetPlatform targetPlatform) => - "MonoGame.Aseprite.Content.Pipeline.Readers.SpriteSheetContentTypeReader, MonoGame.Aseprite"; -} diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Writers/TextureAtlasContentTypeWriter.cs b/source/MonoGame.Aseprite.Content.Pipeline/Writers/TextureAtlasContentTypeWriter.cs deleted file mode 100644 index ba374e0e..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/Writers/TextureAtlasContentTypeWriter.cs +++ /dev/null @@ -1,48 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content.Pipeline; -using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler; -using MonoGame.Aseprite.Content.Pipeline.ContentTypes; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.Writers; - -[ContentTypeWriter] -internal sealed class TextureAtlasContentTypeWriter : ContentTypeWriter -{ - protected override void Write(ContentWriter writer, TextureAtlasContent content) - { - RawTextureAtlas rawTextureAtlas = content.RawTextureAtlas; - writer.Write(rawTextureAtlas.Name); - writer.WriteObject(content.Texture2DContent); - writer.Write(rawTextureAtlas.RawTextureRegions); - } - - public override string GetRuntimeType(TargetPlatform targetPlatform) => - "MonoGame.Aseprite.Sprites.TextureAtlas, MonoGame.Aseprite"; - - public override string GetRuntimeReader(TargetPlatform targetPlatform) => - "MonoGame.Aseprite.Content.Pipeline.Readers.TextureAtlasContentTypeReader, MonoGame.Aseprite"; -} diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Writers/TilemapContentTypeWriter.cs b/source/MonoGame.Aseprite.Content.Pipeline/Writers/TilemapContentTypeWriter.cs deleted file mode 100644 index 31b757fd..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/Writers/TilemapContentTypeWriter.cs +++ /dev/null @@ -1,63 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content.Pipeline; -using Microsoft.Xna.Framework.Content.Pipeline.Graphics; -using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler; -using MonoGame.Aseprite.Content.Pipeline.ContentTypes; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.Writers; - -[ContentTypeWriter] -internal sealed class TilemapContentTypeWriter : ContentTypeWriter -{ - protected override void Write(ContentWriter writer, TilemapContent content) - { - RawTilemap rawTilemap = content.RawTilemap; - - writer.Write(rawTilemap.Name); - WriteTilesets(writer, rawTilemap.RawTilesets, content.Texture2DContents); - writer.Write(rawTilemap.RawLayers); - } - - private void WriteTilesets(ContentWriter writer, ReadOnlySpan rawTilesets, ReadOnlySpan tilesetTextures) - { - writer.Write(rawTilesets.Length); - - for (int i = 0; i < rawTilesets.Length; i++) - { - writer.Write(rawTilesets[i].Name); - writer.Write(rawTilesets[i].ID); - writer.Write(rawTilesets[i].TileWidth); - writer.Write(rawTilesets[i].TileHeight); - writer.WriteObject(tilesetTextures[i]); - } - } - public override string GetRuntimeType(TargetPlatform targetPlatform) => - "MonoGame.Aseprite.Tilemaps.Tilemap, MonoGame.Aseprite"; - - public override string GetRuntimeReader(TargetPlatform targetPlatform) => - "MonoGame.Aseprite.Content.Pipeline.Readers.TilemapContentTypeReader, MonoGame.Aseprite"; -} diff --git a/source/MonoGame.Aseprite.Content.Pipeline/Writers/TilesetContentTypeWriter.cs b/source/MonoGame.Aseprite.Content.Pipeline/Writers/TilesetContentTypeWriter.cs deleted file mode 100644 index e1be0de2..00000000 --- a/source/MonoGame.Aseprite.Content.Pipeline/Writers/TilesetContentTypeWriter.cs +++ /dev/null @@ -1,49 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content.Pipeline; -using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler; -using MonoGame.Aseprite.Content.Pipeline.ContentTypes; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Content.Pipeline.Writers; - -[ContentTypeWriter] -internal sealed class TilesetContentTypeWriter : ContentTypeWriter -{ - protected override void Write(ContentWriter writer, TilesetContent content) - { - RawTileset rawTileset = content.RawTileset; - writer.Write(rawTileset.Name); - writer.Write(rawTileset.TileWidth); - writer.Write(rawTileset.TileHeight); - writer.WriteObject(content.Texture2DContent); - } - - public override string GetRuntimeType(TargetPlatform targetPlatform) => - "MonoGame.Aseprite.Tilemaps.Tileset, MonoGame.Aseprite"; - - public override string GetRuntimeReader(TargetPlatform targetPlatform) => - "MonoGame.Aseprite.Content.Pipeline.Readers.TilesetContentTypeReader, MonoGame.Aseprite"; -} diff --git a/source/MonoGame.Aseprite/Sprites/AnimatedSprite.cs b/source/MonoGame.Aseprite/AnimatedSprite.cs similarity index 93% rename from source/MonoGame.Aseprite/Sprites/AnimatedSprite.cs rename to source/MonoGame.Aseprite/AnimatedSprite.cs index 169c1a43..d45caa6f 100644 --- a/source/MonoGame.Aseprite/Sprites/AnimatedSprite.cs +++ b/source/MonoGame.Aseprite/AnimatedSprite.cs @@ -1,494 +1,494 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework; - -namespace MonoGame.Aseprite.Sprites; - -/// -/// Defines an animated sprite with methods to control the playing of the sprite animation. -/// -public sealed class AnimatedSprite : Sprite -{ - private int _currentIndex; - private int _direction; - private int _loopCount; - private int _loopsRemaining; - private bool _hasBegun = false; - private double _speed = 1.0f; - private AnimationTag _animationTag; - - /// - /// Gets a value that indicates if this is currently paused. - /// - public bool IsPaused { get; private set; } - - /// - /// Gets a value that indicates if this has completed its animation. - /// - public bool IsAnimating { get; private set; } - - /// - /// Gets or Sets a value that indicates if this plays it's frames in reverse order. - /// - public bool IsReversed - { - get => _direction == -1; - set => _direction = value ? -1 : 1; - } - - /// - /// Gets or Sets a value that indicates if this should ping-pong once reaching the - /// last frame of animation. - /// - public bool IsPingPong { get; set; } - - /// - /// Gets a value that indicates the total number of loops/cycles of the animation that should play for - /// this . - /// - /// - /// - /// 0 = infinite looping - /// - /// - /// If is equal to , each direction of the - /// ping-pong will count as a loop. - /// - /// - public int LoopCount => _loopCount; - - /// - /// Sets the rate at which the animation is played. - /// - /// - /// This value is clamped between 0.0d and - /// - /// - /// Default (normal) speed is 1.0d - /// - public double Speed - { - get => _speed; - set - { - _speed = Math.Clamp(value, 0, double.MaxValue); - } - } - - /// - /// Gets the total number of frames in this - /// - public int FrameCount => _animationTag.FrameCount; - - /// - /// Gets the source of the current frame of animation for this - /// . - /// - public AnimationFrame CurrentFrame => _animationTag.Frames[_currentIndex]; - - /// - /// Gets or Sets an method to invoke at the start of each frame of animation. - /// - public Action? OnFrameBegin { get; set; } = default; - - /// - /// Gets or Sets an method to invoke at the end of each frame of animation. - /// - public Action? OnFrameEnd { get; set; } = default; - - /// - /// Gets or Sets an method to invoke at the start of the animation. - /// - /// - /// This will trigger only once when the animation starts before the the first frame's - /// triggers. - /// - public Action? OnAnimationBegin { get; set; } = default; - - /// - /// Gets or Sets an to invoke each time the animation loops. - /// - /// - /// This will trigger each time the animation loops after the last frame's triggers. - /// - public Action? OnAnimationLoop { get; set; } = default; - - /// - /// Gets or Sets an method to invoke when the animation ends. - /// - /// - /// This will only trigger when the animation ends in a non-looping animation, or if a looping animation is - /// stopped by calling manually. - /// - public Action? OnAnimationEnd { get; set; } = default; - - /// - /// Gets the amount of time remaining for the before moving to the next frame. - /// - public TimeSpan CurrentFrameTimeRemaining { get; private set; } - - internal AnimatedSprite(AnimationTag tag) - : base(tag.Name, tag.Frames[0].TextureRegion) - { - _animationTag = tag; - Reset(); - } - - /// - /// Updates this . - /// - /// - /// This should only be called once per update cycle. - /// - /// - /// The amount of time, in seconds, that have elapsed since the last update cycle in the game. - /// - public void Update(double deltaTimeInSeconds) - { - Update(TimeSpan.FromSeconds(deltaTimeInSeconds)); - } - - /// - /// Updates this . - /// - /// - /// This should only be called once per update cycle. - /// - /// - /// A snapshot of the game timing values for the current update cycle. - /// - public void Update(GameTime gameTime) - { - Update(gameTime.ElapsedGameTime); - } - - /// - /// Updates this . - /// - /// - /// This should only be called once per update cycle. - /// - /// - /// The amount of time, that have elapsed since the last update cycle in the game. - /// - public void Update(in TimeSpan elapsedTime) - { - if (!IsAnimating || IsPaused) - { - return; - } - - if (!_hasBegun) - { - _hasBegun = true; - OnAnimationBegin?.Invoke(this); - } - - if (CurrentFrameTimeRemaining == CurrentFrame.Duration) - { - OnFrameBegin?.Invoke(this); - } - - CurrentFrameTimeRemaining -= elapsedTime * Speed; - - if (CurrentFrameTimeRemaining <= TimeSpan.Zero) - { - AdvanceFrame(); - } - } - - /// - /// Sets the current frame of animation for this . - /// - /// - /// The index of the frame to set. Value must be greater than zero and less than the total count of frames. You - /// can use to determine the total number of frames. - /// - /// - /// Thrown if the value provided is less than zero or is greater than or equal to - /// the total number of frames in this . - /// - public void SetFrame(int frameIndex) - { - if(frameIndex < 0 || frameIndex >= FrameCount) - { - throw new ArgumentOutOfRangeException(nameof(frameIndex), $"{nameof(frameIndex)} must be greater than zero and less than the total number of frames in this AnimatedSprite"); - } - - _currentIndex = frameIndex; - TextureRegion = CurrentFrame.TextureRegion; - CurrentFrameTimeRemaining = CurrentFrame.Duration; - } - - private void AdvanceFrame() - { - OnFrameEnd?.Invoke(this); - - _currentIndex += _direction; - - if (_currentIndex >= _animationTag.FrameCount || _currentIndex < 0) - { - bool shouldLoop = _loopCount == 0 || _loopsRemaining > 1; - - if (shouldLoop) - { - ReduceLoopsRemaining(); - - if (IsPingPong) - { - _direction = -_direction; - - // Adjust the current index again after ping ponging so we don't repeat the - // same frame twice in a row - _currentIndex += _direction * 2; - - } - else - { - _currentIndex = IsReversed ? _animationTag.FrameCount - 1 : 0; - } - OnAnimationLoop?.Invoke(this); - } - else - { - _currentIndex += -_direction; - Stop(); - } - } - - TextureRegion = CurrentFrame.TextureRegion; - CurrentFrameTimeRemaining = CurrentFrame.Duration; - } - - private void ReduceLoopsRemaining() - { - _loopsRemaining = Math.Max(--_loopsRemaining, 0); - } - - /// - /// Starts the animation for this - /// - /// - /// - /// When a value is provided, specifies the total number of loop/cycles to perform before stopping the - /// animation. - /// - /// - /// When is provided, loop count will default to the value defined in the - /// used to create this - /// - /// - /// 0 = infinite looping - /// - /// - /// If is equal to , each direction of the - /// ping-pong will count as a loop. - /// - /// - /// - /// - /// When this value is provided, specifies the frame to start the animation at - /// - /// - /// When is provided, play will start at frame 0 of the animation. - /// - /// - /// - /// if animation play was successfully started for this ; - /// otherwise, . This method returns if the animation is already - /// playing (when equals ). - /// - /// - /// Thrown if the value provided is less than zero or is greater than or equal to - /// the total number of frames in this . - /// - public bool Play(int? loopCount = default, int? startingFrame = 0) - { - if(startingFrame < 0 || startingFrame >= FrameCount) - { - throw new ArgumentOutOfRangeException(nameof(startingFrame), $"{nameof(startingFrame)} must be greater than zero and less than the total number of frames in this AnimatedSprite"); - } - - // Cannot play something that's already playing - if (IsAnimating) - { - return false; - } - - if (loopCount is null) - { - loopCount = _animationTag.LoopCount; - } - - _loopCount = loopCount.Value; - _loopsRemaining = _loopCount; - - IsAnimating = true; - IsPaused = false; - - _currentIndex = startingFrame ?? 0; - - if (IsReversed) - { - _currentIndex = _animationTag.Frames.Length - 1; - } - - TextureRegion = CurrentFrame.TextureRegion; - CurrentFrameTimeRemaining = CurrentFrame.Duration; - _hasBegun = false; - - return true; - } - - - /// - /// Paused this and prevents it from being updated until it is unpaused. - /// - /// - /// A value that indicates whether the should be reset. When this - /// method returns , this indicates the was not - /// reset even if this was specified as . - /// - /// - /// if this was successfully paused; otherwise, - /// . This method returns if this - /// is not currently animating or if it is already paused. - /// - public bool Pause(bool resetFrameDuration = false) - { - // We can only pause something that is animating and is not already paused. This is to prevent improper usage - // that could accidentally reset frame duration if it was set to true. - if (!IsAnimating || IsPaused) - { - return false; - } - - IsPaused = true; - - if (resetFrameDuration) - { - CurrentFrameTimeRemaining = CurrentFrame.Duration; - } - - return true; - } - - /// - /// Unpaused this . - /// - /// - /// A value that indicates whether this should immediately advance to the next - /// frame after unpausing. When this method returns , this - /// will -not- be advanced to the next frame, even if this was specified as . - /// - /// - /// if this was successfully unpaused; otherwise, - /// . This method returns if this - /// is not currently animating or if it is not paused. - /// - public bool Unpause(bool advanceToNextFrame = false) - { - // We can't unpause something that's not animating and also isn't paused. This is to prevent improper usage - // that could accidentally advance to the next frame if it was set to true. - if (!IsAnimating || !IsPaused) - { - return false; - } - - IsPaused = false; - - if (advanceToNextFrame) - { - AdvanceFrame(); - } - - return true; - } - - /// - /// Stops this on the current frame. - /// - /// - /// This will trigger the action if one was set. - /// - /// - /// if this was successfully stopped; otherwise, - /// . This method returns if this - /// is not currently animating. If this method returns , this also indicates that the - /// was not triggered. - /// - public bool Stop() - { - // We can't stop something that's not animating. This is to prevent - // accidentally invoking the OnAnimationEnd action - if (!IsAnimating) - { - return false; - } - - IsAnimating = false; - IsPaused = true; - OnAnimationEnd?.Invoke(this); - return true; - } - - /// - /// Resets this back to its initial state as defined by the - /// used to create it. You will need to call - /// after resetting to start the playback of the animation. - /// - /// - /// - /// This is useful if you've adjusted the or - /// properties, or specified a override to the loop count when - /// initially playing the animation. - /// - /// - /// This also resets the to 1.0d. - /// - /// - public void Reset() - { - IsReversed = _animationTag.IsReversed; - IsPingPong = _animationTag.IsPingPong; - _loopCount = _animationTag.LoopCount; - _loopsRemaining = _loopCount; - - IsAnimating = false; - IsPaused = true; - - Speed = 1.0d; - - _currentIndex = 0; - if(IsReversed) - { - _currentIndex = _animationTag.Frames.Length - 1; - } - - TextureRegion = CurrentFrame.TextureRegion; - CurrentFrameTimeRemaining = CurrentFrame.Duration; - _hasBegun = false; - } -} +/* ---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2018-2023 Christopher Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------------------------------------------------- */ + +using Microsoft.Xna.Framework; + +namespace MonoGame.Aseprite; + +/// +/// Defines an animated sprite with methods to control the playing of the sprite animation. +/// +public sealed class AnimatedSprite : Sprite +{ + private int _currentIndex; + private int _direction; + private int _loopCount; + private int _loopsRemaining; + private bool _hasBegun = false; + private double _speed = 1.0f; + private AnimationTag _animationTag; + + /// + /// Gets a value that indicates if this is currently paused. + /// + public bool IsPaused { get; private set; } + + /// + /// Gets a value that indicates if this has completed its animation. + /// + public bool IsAnimating { get; private set; } + + /// + /// Gets or Sets a value that indicates if this plays it's frames in reverse order. + /// + public bool IsReversed + { + get => _direction == -1; + set => _direction = value ? -1 : 1; + } + + /// + /// Gets or Sets a value that indicates if this should ping-pong once reaching the + /// last frame of animation. + /// + public bool IsPingPong { get; set; } + + /// + /// Gets a value that indicates the total number of loops/cycles of the animation that should play for + /// this . + /// + /// + /// + /// 0 = infinite looping + /// + /// + /// If is equal to , each direction of the + /// ping-pong will count as a loop. + /// + /// + public int LoopCount => _loopCount; + + /// + /// Sets the rate at which the animation is played. + /// + /// + /// This value is clamped between 0.0d and + /// + /// + /// Default (normal) speed is 1.0d + /// + public double Speed + { + get => _speed; + set + { + _speed = Math.Clamp(value, 0, double.MaxValue); + } + } + + /// + /// Gets the total number of frames in this + /// + public int FrameCount => _animationTag.FrameCount; + + /// + /// Gets the source of the current frame of animation for this + /// . + /// + public AnimationFrame CurrentFrame => _animationTag.Frames[_currentIndex]; + + /// + /// Gets or Sets an method to invoke at the start of each frame of animation. + /// + public Action? OnFrameBegin { get; set; } = default; + + /// + /// Gets or Sets an method to invoke at the end of each frame of animation. + /// + public Action? OnFrameEnd { get; set; } = default; + + /// + /// Gets or Sets an method to invoke at the start of the animation. + /// + /// + /// This will trigger only once when the animation starts before the the first frame's + /// triggers. + /// + public Action? OnAnimationBegin { get; set; } = default; + + /// + /// Gets or Sets an to invoke each time the animation loops. + /// + /// + /// This will trigger each time the animation loops after the last frame's triggers. + /// + public Action? OnAnimationLoop { get; set; } = default; + + /// + /// Gets or Sets an method to invoke when the animation ends. + /// + /// + /// This will only trigger when the animation ends in a non-looping animation, or if a looping animation is + /// stopped by calling manually. + /// + public Action? OnAnimationEnd { get; set; } = default; + + /// + /// Gets the amount of time remaining for the before moving to the next frame. + /// + public TimeSpan CurrentFrameTimeRemaining { get; private set; } + + internal AnimatedSprite(AnimationTag tag) + : base(tag.Name, tag.Frames[0].TextureRegion) + { + _animationTag = tag; + Reset(); + } + + /// + /// Updates this . + /// + /// + /// This should only be called once per update cycle. + /// + /// + /// The amount of time, in seconds, that have elapsed since the last update cycle in the game. + /// + public void Update(double deltaTimeInSeconds) + { + Update(TimeSpan.FromSeconds(deltaTimeInSeconds)); + } + + /// + /// Updates this . + /// + /// + /// This should only be called once per update cycle. + /// + /// + /// A snapshot of the game timing values for the current update cycle. + /// + public void Update(GameTime gameTime) + { + Update(gameTime.ElapsedGameTime); + } + + /// + /// Updates this . + /// + /// + /// This should only be called once per update cycle. + /// + /// + /// The amount of time, that have elapsed since the last update cycle in the game. + /// + public void Update(in TimeSpan elapsedTime) + { + if (!IsAnimating || IsPaused) + { + return; + } + + if (!_hasBegun) + { + _hasBegun = true; + OnAnimationBegin?.Invoke(this); + } + + if (CurrentFrameTimeRemaining == CurrentFrame.Duration) + { + OnFrameBegin?.Invoke(this); + } + + CurrentFrameTimeRemaining -= elapsedTime * Speed; + + if (CurrentFrameTimeRemaining <= TimeSpan.Zero) + { + AdvanceFrame(); + } + } + + /// + /// Sets the current frame of animation for this . + /// + /// + /// The index of the frame to set. Value must be greater than zero and less than the total count of frames. You + /// can use to determine the total number of frames. + /// + /// + /// Thrown if the value provided is less than zero or is greater than or equal to + /// the total number of frames in this . + /// + public void SetFrame(int frameIndex) + { + if (frameIndex < 0 || frameIndex >= FrameCount) + { + throw new ArgumentOutOfRangeException(nameof(frameIndex), $"{nameof(frameIndex)} must be greater than zero and less than the total number of frames in this AnimatedSprite"); + } + + _currentIndex = frameIndex; + TextureRegion = CurrentFrame.TextureRegion; + CurrentFrameTimeRemaining = CurrentFrame.Duration; + } + + private void AdvanceFrame() + { + OnFrameEnd?.Invoke(this); + + _currentIndex += _direction; + + if (_currentIndex >= _animationTag.FrameCount || _currentIndex < 0) + { + bool shouldLoop = _loopCount == 0 || _loopsRemaining > 1; + + if (shouldLoop) + { + ReduceLoopsRemaining(); + + if (IsPingPong) + { + _direction = -_direction; + + // Adjust the current index again after ping ponging so we don't repeat the + // same frame twice in a row + _currentIndex += _direction * 2; + + } + else + { + _currentIndex = IsReversed ? _animationTag.FrameCount - 1 : 0; + } + OnAnimationLoop?.Invoke(this); + } + else + { + _currentIndex += -_direction; + Stop(); + } + } + + TextureRegion = CurrentFrame.TextureRegion; + CurrentFrameTimeRemaining = CurrentFrame.Duration; + } + + private void ReduceLoopsRemaining() + { + _loopsRemaining = Math.Max(--_loopsRemaining, 0); + } + + /// + /// Starts the animation for this + /// + /// + /// + /// When a value is provided, specifies the total number of loop/cycles to perform before stopping the + /// animation. + /// + /// + /// When is provided, loop count will default to the value defined in the + /// used to create this + /// + /// + /// 0 = infinite looping + /// + /// + /// If is equal to , each direction of the + /// ping-pong will count as a loop. + /// + /// + /// + /// + /// When this value is provided, specifies the frame to start the animation at + /// + /// + /// When is provided, play will start at frame 0 of the animation. + /// + /// + /// + /// if animation play was successfully started for this ; + /// otherwise, . This method returns if the animation is already + /// playing (when equals ). + /// + /// + /// Thrown if the value provided is less than zero or is greater than or equal to + /// the total number of frames in this . + /// + public bool Play(int? loopCount = default, int? startingFrame = 0) + { + if (startingFrame < 0 || startingFrame >= FrameCount) + { + throw new ArgumentOutOfRangeException(nameof(startingFrame), $"{nameof(startingFrame)} must be greater than zero and less than the total number of frames in this AnimatedSprite"); + } + + // Cannot play something that's already playing + if (IsAnimating) + { + return false; + } + + if (loopCount is null) + { + loopCount = _animationTag.LoopCount; + } + + _loopCount = loopCount.Value; + _loopsRemaining = _loopCount; + + IsAnimating = true; + IsPaused = false; + + _currentIndex = startingFrame ?? 0; + + if (IsReversed) + { + _currentIndex = _animationTag.Frames.Length - 1; + } + + TextureRegion = CurrentFrame.TextureRegion; + CurrentFrameTimeRemaining = CurrentFrame.Duration; + _hasBegun = false; + + return true; + } + + + /// + /// Paused this and prevents it from being updated until it is unpaused. + /// + /// + /// A value that indicates whether the should be reset. When this + /// method returns , this indicates the was not + /// reset even if this was specified as . + /// + /// + /// if this was successfully paused; otherwise, + /// . This method returns if this + /// is not currently animating or if it is already paused. + /// + public bool Pause(bool resetFrameDuration = false) + { + // We can only pause something that is animating and is not already paused. This is to prevent improper usage + // that could accidentally reset frame duration if it was set to true. + if (!IsAnimating || IsPaused) + { + return false; + } + + IsPaused = true; + + if (resetFrameDuration) + { + CurrentFrameTimeRemaining = CurrentFrame.Duration; + } + + return true; + } + + /// + /// Unpaused this . + /// + /// + /// A value that indicates whether this should immediately advance to the next + /// frame after unpausing. When this method returns , this + /// will -not- be advanced to the next frame, even if this was specified as . + /// + /// + /// if this was successfully unpaused; otherwise, + /// . This method returns if this + /// is not currently animating or if it is not paused. + /// + public bool Unpause(bool advanceToNextFrame = false) + { + // We can't unpause something that's not animating and also isn't paused. This is to prevent improper usage + // that could accidentally advance to the next frame if it was set to true. + if (!IsAnimating || !IsPaused) + { + return false; + } + + IsPaused = false; + + if (advanceToNextFrame) + { + AdvanceFrame(); + } + + return true; + } + + /// + /// Stops this on the current frame. + /// + /// + /// This will trigger the action if one was set. + /// + /// + /// if this was successfully stopped; otherwise, + /// . This method returns if this + /// is not currently animating. If this method returns , this also indicates that the + /// was not triggered. + /// + public bool Stop() + { + // We can't stop something that's not animating. This is to prevent + // accidentally invoking the OnAnimationEnd action + if (!IsAnimating) + { + return false; + } + + IsAnimating = false; + IsPaused = true; + OnAnimationEnd?.Invoke(this); + return true; + } + + /// + /// Resets this back to its initial state as defined by the + /// used to create it. You will need to call + /// after resetting to start the playback of the animation. + /// + /// + /// + /// This is useful if you've adjusted the or + /// properties, or specified a override to the loop count when + /// initially playing the animation. + /// + /// + /// This also resets the to 1.0d. + /// + /// + public void Reset() + { + IsReversed = _animationTag.IsReversed; + IsPingPong = _animationTag.IsPingPong; + _loopCount = _animationTag.LoopCount; + _loopsRemaining = _loopCount; + + IsAnimating = false; + IsPaused = true; + + Speed = 1.0d; + + _currentIndex = 0; + if (IsReversed) + { + _currentIndex = _animationTag.Frames.Length - 1; + } + + TextureRegion = CurrentFrame.TextureRegion; + CurrentFrameTimeRemaining = CurrentFrame.Duration; + _hasBegun = false; + } +} diff --git a/source/MonoGame.Aseprite/Tilemaps/AnimatedTIlemapFrame.cs b/source/MonoGame.Aseprite/AnimatedTIlemapFrame.cs similarity index 97% rename from source/MonoGame.Aseprite/Tilemaps/AnimatedTIlemapFrame.cs rename to source/MonoGame.Aseprite/AnimatedTIlemapFrame.cs index 740c734c..b4a5f952 100644 --- a/source/MonoGame.Aseprite/Tilemaps/AnimatedTIlemapFrame.cs +++ b/source/MonoGame.Aseprite/AnimatedTIlemapFrame.cs @@ -1,330 +1,330 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.Collections; -using System.Diagnostics.CodeAnalysis; -using Microsoft.Xna.Framework; - -namespace MonoGame.Aseprite.Tilemaps; - -/// -/// Defines a frame of animation in an , containing zero or more -/// elements. -/// -public sealed class AnimatedTilemapFrame : IEnumerable -{ - private List _layers = new(); - private Dictionary _layerLookup = new(); - - /// - /// Gets the duration of this . - /// - public TimeSpan Duration { get; } - - /// - /// Gets the total number of elements in this . - /// - public int LayerCount => _layers.Count; - - /// - /// Gets the element at the specified index in this - /// . - /// - /// - /// The index of the element to locate. - /// - /// - /// The element located. - /// - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public TilemapLayer this[int layerIndex] => GetLayer(layerIndex); - - /// - /// Gets the element with the specified name in this - /// . - /// - /// - /// The name of the element to locate. - /// - /// - /// The element located. - /// - /// - /// Thrown if this does not contain a element with - /// the specified name. - /// - public TilemapLayer this[string layerName] => GetLayer(layerName); - - /// - /// Initializes a new instance of the class. - /// - /// - /// The duration to assign the . - /// - public AnimatedTilemapFrame(TimeSpan duration) => Duration = duration; - - /// - /// Creates a new element and adds it to this . - /// - /// - /// The name to assign the element created by this method. The name must be unique - /// across all elements in this . - /// - /// - /// The source to assign the element created by this method. - /// - /// - /// The total number of columns to assign the element created by this method. - /// - /// - /// The total of rows in the element created by this method. - /// - /// - /// The x- and y-position offset, relative to the location the is rendered, to - /// assign the element created by this method. - /// - /// - /// The created by this method. - /// - /// Thrown if this already contains a element with - /// the specified name. - /// - public TilemapLayer CreateLayer(string layerName, Tileset tileset, int columns, int rows, Vector2 offset) - { - TilemapLayer layer = new(layerName, tileset, columns, rows, offset); - AddLayer(layer); - return layer; - } - - /// - /// Adds the given element to this . - /// - /// The element to add. - /// - /// Thrown if this already contains a element with - /// the same name as the element given. - /// - public void AddLayer(TilemapLayer layer) - { - if (_layerLookup.ContainsKey(layer.Name)) - { - throw new InvalidOperationException($"This tileset frame already contains a tilemap layer element with the name '{layer.Name}'."); - } - - _layers.Add(layer); - _layerLookup.Add(layer.Name, layer); - } - - /// - /// Gets the element at the specified index in this - /// . - /// - /// - /// The index of the element to locate. - /// - /// - /// The element located. - /// - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public TilemapLayer GetLayer(int index) - { - if (index < 0 || index >= LayerCount) - { - throw new ArgumentOutOfRangeException(nameof(index), $"{nameof(index)} cannot be less than zero or greater than or equal to the total number of tilemap layer elements in this animated tilemap frame."); - } - - return _layers[index]; - } - - /// - /// Gets the element with the specified name in this - /// . - /// - /// - /// The name of the element to locate. - /// - /// - /// The element located. - /// - /// - /// Thrown if this does not contain a element with - /// the specified name. - /// - public TilemapLayer GetLayer(string name) - { - if (_layerLookup.TryGetValue(name, out TilemapLayer? layer)) - { - return layer; - } - - throw new KeyNotFoundException($"This animated tilemap frame does not contain a tilemap layer element with the name '{name}'."); - } - - /// - /// Get the element at the specified index in this - /// . - /// - /// - /// The index of the element to locate. - /// - /// - /// When this method returns , contains the element located; - /// otherwise, . - /// - /// - /// if a element was located at the specified index in this - /// ; otherwise, . This method return - /// when the specified index is less than zero or is greater than or equal to the total - /// number of elements in this . - /// - public bool TryGetLayer(int index, [NotNullWhen(true)] out TilemapLayer? layer) - { - layer = default; - - if (index < 0 || index >= LayerCount) - { - return false; - } - - layer = _layers[index]; - return true; - } - - /// - /// Gets the element with the specified name in this - /// . - /// - /// - /// The name of the element to locate. - /// - /// - /// When this method returns , contains the element located; - /// otherwise, . - /// - /// - /// if a element was located in this - /// with the specified name; otherwise . This method - /// returns if this does not contain a - /// element with the specified name. - /// - public bool TryGetLayer(string name, [NotNullWhen(true)] out TilemapLayer? layer) => - _layerLookup.TryGetValue(name, out layer); - - /// - /// Removes the element at the specified index in this - /// . - /// - /// - /// The index of the element to remove from this . - /// - /// - /// if the element was successfully removed; otherwise, - /// . This method returns if the specified index is less than - /// zero or is greater than or equal to the total number of elements in this tilemap - /// frame. - /// - public bool RemoveLayer(int index) - { - if (index < 0 || index >= LayerCount) - { - return false; - } - - TilemapLayer layer = _layers[index]; - return RemoveLayer(layer); - } - - /// - /// Removes the element with the specified name from this - /// . - /// - /// - /// The name of the element to remove from this - /// - /// - /// if the element was successfully removed; otherwise, - /// . This method returns if this tilemap frame does not - /// contain a element with the specified name. - /// - public bool RemoveLayer(string name) - { - if (_layerLookup.TryGetValue(name, out TilemapLayer? layer)) - { - return RemoveLayer(layer); - } - - return false; - } - - /// - /// Removes the given element from this . - /// - /// - /// The element to remove from this . - /// - /// - /// if the element was removed successfully; otherwise, - /// . This method returns if this tilemap frame does not contain - /// the element given. - /// - public bool RemoveLayer(TilemapLayer layer) => - _layers.Remove(layer) && _layerLookup.Remove(layer.Name); - - /// - /// Removes all elements from this . - /// - public void Clear() - { - _layerLookup.Clear(); - _layers.Clear(); - } - - /// - /// Returns an enumerator used to iterate through all of the elements in this - /// . The order of elements in the enumeration is from bottom layer to top - /// layer. - /// - /// - /// An enumerator used to iterate through all of the elements in this - /// . - /// - public IEnumerator GetEnumerator() => _layers.GetEnumerator(); - - /// - /// Returns an enumerator used to iterate through all of the elements in this - /// . The order of elements in the enumeration is from bottom layer to top - /// layer. - /// - /// - /// An enumerator used to iterate through all of the elements in this - /// . - /// - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} +/* ---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2018-2023 Christopher Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------------------------------------------------- */ + +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Xna.Framework; + +namespace MonoGame.Aseprite; + +/// +/// Defines a frame of animation in an , containing zero or more +/// elements. +/// +public sealed class AnimatedTilemapFrame : IEnumerable +{ + private List _layers = new(); + private Dictionary _layerLookup = new(); + + /// + /// Gets the duration of this . + /// + public TimeSpan Duration { get; } + + /// + /// Gets the total number of elements in this . + /// + public int LayerCount => _layers.Count; + + /// + /// Gets the element at the specified index in this + /// . + /// + /// + /// The index of the element to locate. + /// + /// + /// The element located. + /// + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public TilemapLayer this[int layerIndex] => GetLayer(layerIndex); + + /// + /// Gets the element with the specified name in this + /// . + /// + /// + /// The name of the element to locate. + /// + /// + /// The element located. + /// + /// + /// Thrown if this does not contain a element with + /// the specified name. + /// + public TilemapLayer this[string layerName] => GetLayer(layerName); + + /// + /// Initializes a new instance of the class. + /// + /// + /// The duration to assign the . + /// + public AnimatedTilemapFrame(TimeSpan duration) => Duration = duration; + + /// + /// Creates a new element and adds it to this . + /// + /// + /// The name to assign the element created by this method. The name must be unique + /// across all elements in this . + /// + /// + /// The source to assign the element created by this method. + /// + /// + /// The total number of columns to assign the element created by this method. + /// + /// + /// The total of rows in the element created by this method. + /// + /// + /// The x- and y-position offset, relative to the location the is rendered, to + /// assign the element created by this method. + /// + /// + /// The created by this method. + /// + /// Thrown if this already contains a element with + /// the specified name. + /// + public TilemapLayer CreateLayer(string layerName, Tileset tileset, int columns, int rows, Vector2 offset) + { + TilemapLayer layer = new(layerName, tileset, columns, rows, offset); + AddLayer(layer); + return layer; + } + + /// + /// Adds the given element to this . + /// + /// The element to add. + /// + /// Thrown if this already contains a element with + /// the same name as the element given. + /// + public void AddLayer(TilemapLayer layer) + { + if (_layerLookup.ContainsKey(layer.Name)) + { + throw new InvalidOperationException($"This tileset frame already contains a tilemap layer element with the name '{layer.Name}'."); + } + + _layers.Add(layer); + _layerLookup.Add(layer.Name, layer); + } + + /// + /// Gets the element at the specified index in this + /// . + /// + /// + /// The index of the element to locate. + /// + /// + /// The element located. + /// + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public TilemapLayer GetLayer(int index) + { + if (index < 0 || index >= LayerCount) + { + throw new ArgumentOutOfRangeException(nameof(index), $"{nameof(index)} cannot be less than zero or greater than or equal to the total number of tilemap layer elements in this animated tilemap frame."); + } + + return _layers[index]; + } + + /// + /// Gets the element with the specified name in this + /// . + /// + /// + /// The name of the element to locate. + /// + /// + /// The element located. + /// + /// + /// Thrown if this does not contain a element with + /// the specified name. + /// + public TilemapLayer GetLayer(string name) + { + if (_layerLookup.TryGetValue(name, out TilemapLayer? layer)) + { + return layer; + } + + throw new KeyNotFoundException($"This animated tilemap frame does not contain a tilemap layer element with the name '{name}'."); + } + + /// + /// Get the element at the specified index in this + /// . + /// + /// + /// The index of the element to locate. + /// + /// + /// When this method returns , contains the element located; + /// otherwise, . + /// + /// + /// if a element was located at the specified index in this + /// ; otherwise, . This method return + /// when the specified index is less than zero or is greater than or equal to the total + /// number of elements in this . + /// + public bool TryGetLayer(int index, [NotNullWhen(true)] out TilemapLayer? layer) + { + layer = default; + + if (index < 0 || index >= LayerCount) + { + return false; + } + + layer = _layers[index]; + return true; + } + + /// + /// Gets the element with the specified name in this + /// . + /// + /// + /// The name of the element to locate. + /// + /// + /// When this method returns , contains the element located; + /// otherwise, . + /// + /// + /// if a element was located in this + /// with the specified name; otherwise . This method + /// returns if this does not contain a + /// element with the specified name. + /// + public bool TryGetLayer(string name, [NotNullWhen(true)] out TilemapLayer? layer) => + _layerLookup.TryGetValue(name, out layer); + + /// + /// Removes the element at the specified index in this + /// . + /// + /// + /// The index of the element to remove from this . + /// + /// + /// if the element was successfully removed; otherwise, + /// . This method returns if the specified index is less than + /// zero or is greater than or equal to the total number of elements in this tilemap + /// frame. + /// + public bool RemoveLayer(int index) + { + if (index < 0 || index >= LayerCount) + { + return false; + } + + TilemapLayer layer = _layers[index]; + return RemoveLayer(layer); + } + + /// + /// Removes the element with the specified name from this + /// . + /// + /// + /// The name of the element to remove from this + /// + /// + /// if the element was successfully removed; otherwise, + /// . This method returns if this tilemap frame does not + /// contain a element with the specified name. + /// + public bool RemoveLayer(string name) + { + if (_layerLookup.TryGetValue(name, out TilemapLayer? layer)) + { + return RemoveLayer(layer); + } + + return false; + } + + /// + /// Removes the given element from this . + /// + /// + /// The element to remove from this . + /// + /// + /// if the element was removed successfully; otherwise, + /// . This method returns if this tilemap frame does not contain + /// the element given. + /// + public bool RemoveLayer(TilemapLayer layer) => + _layers.Remove(layer) && _layerLookup.Remove(layer.Name); + + /// + /// Removes all elements from this . + /// + public void Clear() + { + _layerLookup.Clear(); + _layers.Clear(); + } + + /// + /// Returns an enumerator used to iterate through all of the elements in this + /// . The order of elements in the enumeration is from bottom layer to top + /// layer. + /// + /// + /// An enumerator used to iterate through all of the elements in this + /// . + /// + public IEnumerator GetEnumerator() => _layers.GetEnumerator(); + + /// + /// Returns an enumerator used to iterate through all of the elements in this + /// . The order of elements in the enumeration is from bottom layer to top + /// layer. + /// + /// + /// An enumerator used to iterate through all of the elements in this + /// . + /// + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} diff --git a/source/MonoGame.Aseprite/Tilemaps/AnimatedTilemap.cs b/source/MonoGame.Aseprite/AnimatedTilemap.cs similarity index 88% rename from source/MonoGame.Aseprite/Tilemaps/AnimatedTilemap.cs rename to source/MonoGame.Aseprite/AnimatedTilemap.cs index 3cb6ab94..13a3fba2 100644 --- a/source/MonoGame.Aseprite/Tilemaps/AnimatedTilemap.cs +++ b/source/MonoGame.Aseprite/AnimatedTilemap.cs @@ -1,699 +1,654 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.Collections; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.Utils; - - -namespace MonoGame.Aseprite.Tilemaps; - -/// -/// Defines a consisting of elements -/// -public sealed class AnimatedTilemap : IEnumerable -{ - private bool _hasBegun; - private int _currentIndex; - private int _direction; - private List _frames = new(); - - /// - /// Gets the name assigned to this . - /// - public string Name { get; } - - /// - /// Gets the total number of elements in this . - /// - public int frameCount => _frames.Count; - - /// - /// Gets the element at the specified index in this - /// . - /// - /// - /// The index of the element to locate. - /// - /// - /// The element that was located at the specified index in this - /// . - /// - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public AnimatedTilemapFrame this[int frameIndex] => GetFrame(frameIndex); - - /// - /// Gets a value that indicates if this is currently paused. - /// - public bool IsPaused { get; private set; } - - /// - /// Gets a value that indicates if this is currently animating. - /// - public bool IsAnimating { get; private set; } - - /// - /// Gets a value that indicates whether the animation this should loop. - /// - public bool IsLooping { get; } - - /// - /// Gets a value that indicates whether the animation this should play frames - /// in reverse order. - /// - public bool IsReversed { get; } - - /// - /// Gets a value that indicates whether the animation for this should ping-pong - /// once reaching the last frame of animation. - /// - public bool IsPingPong { get; } - - /// - /// Gets the source element for the current animation frame. - /// - /// - /// Thrown if no elements have been added to this - /// prior to accessing this property. - /// - public AnimatedTilemapFrame CurrentFrame - { - get - { - if (_frames.Count == 0) - { - throw new InvalidOperationException($"Unable to get current frame as no frames have been added to this animated tilemap."); - } - - return this[_currentIndex]; - } - } - - /// - /// Gets or Sets an method to invoke at the start of each animation frame. - /// - public Action? OnFrameBegin { get; set; } = default; - - /// - /// Gets or Sets an method to invoke at the end of each animation frame. - /// - public Action? OnFrameEnd { get; set; } = default; - - /// - /// Gets or Sets an method to invoke at the start of the animation. This will trigger only - /// once when the animation starts before the first frame's triggers. - /// - public Action? OnAnimationBegin { get; set; } = default; - - /// - /// Gets or Sets an method to invoke each time the animation loops. This will trigger each - /// time the animation loops after the last frame's triggers. - /// - public Action? OnAnimationLoop { get; set; } = default; - - /// - /// Gets or Sets an method to invoke when the animation ends. This will only trigger when - /// the animation ends in a non-looping animation, or if a looping animation is stopped by calling the - /// method manually. - /// - public Action? OnAnimationEnd { get; set; } = default; - - /// - /// Gets the amount of time remaining for the before moving to the next frame. - /// - public TimeSpan CurrentFrameTimeRemaining { get; private set; } - - - /// - /// Initializes a new instance of the class. - /// - /// - /// The name to assign the . - /// - /// - /// Indicates whether the animation for the should loop - /// - /// - /// Indicates whether the frames for the should play in reverse order. - /// - /// - /// Indicates whether the animation for this should ping-pong once reaching the - /// last frame of animation - /// - public AnimatedTilemap(string name, bool isLooping = true, bool isReversed = false, bool isPingPong = false) - { - Name = name; - IsLooping = isLooping; - IsReversed = isReversed; - IsPingPong = isPingPong; - Reset(); - } - - /// - /// Updates this . - /// - /// - /// This should only be called once per game update cycle. - /// - /// - /// The amount of time, in seconds, that have elapsed since the last update cycle in the game. - /// - public void Update(double deltaTimeInSeconds) - { - Update(TimeSpan.FromSeconds(deltaTimeInSeconds)); - } - - /// - /// Updates this . - /// - /// - /// This should only be called once per game update cycle. - /// - /// - /// A snapshot of the game timing values for the current update cycle. - /// - public void Update(GameTime gameTime) - { - Update(gameTime.ElapsedGameTime); - } - - /// - /// Updates this . - /// - /// - /// This should only be called once per game update cycle. - /// - /// - /// The amount of time, that have elapsed since the last update cycle in the game. - /// - public void Update(in TimeSpan elapsedTime) - { - if (!IsAnimating || IsPaused) - { - return; - } - - if (!_hasBegun) - { - _hasBegun = true; - OnAnimationBegin?.Invoke(this); - } - - if (CurrentFrameTimeRemaining == CurrentFrame.Duration) - { - OnFrameBegin?.Invoke(this); - } - - CurrentFrameTimeRemaining -= elapsedTime; - - if (CurrentFrameTimeRemaining <= TimeSpan.Zero) - { - AdvanceFrame(); - } - } - - private void AdvanceFrame() - { - OnFrameEnd?.Invoke(this); - - _currentIndex += _direction; - - switch (IsReversed, IsPingPong) - { - case (true, true): - ReversePingPongLoopCheck(); - break; - case (true, false): - ReverseLoopCheck(); - break; - case (false, true): - PingPongLoopCheck(); - break; - case (false, false): - LoopCheck(); - break; - } - - CurrentFrameTimeRemaining = CurrentFrame.Duration; - } - - private void LoopCheck() - { - if (_currentIndex >= _frames.Count) - { - if (IsLooping) - { - _currentIndex = 0; - OnAnimationLoop?.Invoke(this); - } - else - { - _currentIndex = _frames.Count - 1; - Stop(); - } - } - } - - private void ReverseLoopCheck() - { - if (_currentIndex < 0) - { - if (IsLooping) - { - _currentIndex = _frames.Count - 1; - OnAnimationLoop?.Invoke(this); - } - else - { - _currentIndex = 0; - Stop(); - } - } - } - - private void PingPongLoopCheck() - { - if (_currentIndex < 0 || _currentIndex >= _frames.Count) - { - _direction = -_direction; - - if (_direction == -1) - { - _currentIndex = _frames.Count - 2; - } - else - { - if (IsLooping) - { - _currentIndex = 1; - OnAnimationLoop?.Invoke(this); - } - else - { - _currentIndex = 0; - Stop(); - } - } - } - } - - private void ReversePingPongLoopCheck() - { - if (_currentIndex < 0 || _currentIndex >= _frames.Count) - { - _direction = -_direction; - - if (_direction == 1) - { - _currentIndex = 1; - } - else - { - if (IsLooping) - { - _currentIndex = _frames.Count - 2; - OnAnimationLoop?.Invoke(this); - } - else - { - _currentIndex = _frames.Count - 1; - Stop(); - } - } - } - } - - /// - /// Pauses this and prevents it from being updated until it is unpaused. - /// - /// - /// A value that indicates whether the the duration of the should be reset. When - /// this method returns , the duration will not be reset even if this is specified as - /// . - /// - /// - /// this was successfully paused; otherwise, - /// . This method returns this - /// is not currently animating or if it is already paused. - /// - public bool Pause(bool resetFrameDuration = false) - { - // We can only pause something that is animating and is not already paused. This is to prevent improper usage - // that could accidentally reset frame duration if it was set to true. - if (!IsAnimating || IsPaused) - { - return false; - } - - IsPaused = true; - - if (resetFrameDuration) - { - CurrentFrameTimeRemaining = CurrentFrame.Duration; - } - - return true; - } - - /// - /// Unpauses this . - /// - /// - /// A value that indicates whether this should immediately be advanced to the next - /// frame after unpausing. When this method returns , this - /// will -not- be advanced to the next frame, even if this was specified as . - /// - /// - /// if this was successfully unpaused; otherwise, - /// . This method return this is - /// not currently animating or if it has not already been paused. - /// - public bool Unpause(bool advanceToNextFrame = false) - { - // We can't unpause something that's not animating and also isn't paused. This is to prevent improper usage - // that could accidentally advance to the next frame if it was set to true. - if (!IsAnimating || !IsPaused) - { - return false; - } - - IsPaused = false; - - if (advanceToNextFrame) - { - AdvanceFrame(); - } - - return true; - } - - /// - /// Stops this on the . This will trigger the - /// if one was set. - /// - /// - /// this was successfully stopped; otherwise, - /// . This method returns this is - /// not currently animating. If this method returns , this indicates that the - /// action method was not invoked. - /// - public bool Stop() - { - // We can't stop something that's not animating. This is to prevent accidentally invoking the OnAnimationEnd - // action - if (!IsAnimating) - { - return false; - } - - IsAnimating = false; - OnAnimationEnd?.Invoke(this); - return true; - } - - /// - /// Resets this back to its first frame of animation. - /// - /// - /// A value that indicates whether his should be paused after it is reset. - /// - public void Reset(bool paused = false) - { - IsAnimating = true; - IsPaused = paused; - - if (IsReversed) - { - _direction = -1; - _currentIndex = _frames.Count; - } - else - { - _direction = 1; - _currentIndex = 0; - } - - _hasBegun = false; - } - - /// - /// Creates and adds a new element as the next frame of animation in this - /// . - /// - /// - /// The duration to assign the created. - /// - /// - /// The created. - /// - public AnimatedTilemapFrame CreateFrame(TimeSpan duration) - { - AnimatedTilemapFrame frame = new(duration); - AddFrame(frame); - return frame; - } - - /// - /// Adds the given as the next frame of animation in this - /// . - /// - /// - /// The to add - /// - public void AddFrame(AnimatedTilemapFrame frame) => _frames.Add(frame); - - /// - /// Gets the element at the specified index in this - /// . - /// - /// - /// The index of the element to locate. - /// - /// - /// The element that was located. - /// - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public AnimatedTilemapFrame GetFrame(int frameIndex) - { - if (frameIndex < 0 || frameIndex >= frameCount) - { - throw new ArgumentOutOfRangeException(nameof(frameIndex), $"{nameof(frameIndex)} cannot be less than zero or greater than or equal to the total number of animated tilemap frame elements in this animated tilemap."); - } - - return _frames[frameIndex]; - } - - /// - /// Gets the element at the specified index in this - /// . - /// - /// - /// The index of the element to locate. - /// - /// - /// When this method returns , contains the located; - /// otherwise, . - /// - /// - /// if the element was located; otherwise, - /// . This method returns when the specified index is less than - /// zero or is greater than or equal to the total number of elements in this - /// . - /// - public bool TryGetFrame(int index, out AnimatedTilemapFrame? frame) - { - if (index < 0 || index >= frameCount) - { - frame = default; - return false; - } - - frame = _frames[index]; - return true; - } - - /// - /// Removes the element at the specified index from this - /// . - /// - /// - /// The index of the element to remove. - /// - /// - /// if the was removed successfully; otherwise, - /// . This method returns when the specified index is less than - /// zero or is greater that or equal to the total number of elements in this - /// . - /// - public bool RemoveFrame(int index) - { - if (index < 0 || index >= frameCount) - { - return false; - } - - _frames.RemoveAt(index); - return true; - } - - /// - /// Removes all elements from this . - /// - public void Clear() => _frames.Clear(); - - - /// - /// Draws this using the - /// . - /// - /// - /// The to use for rendering this - /// . - /// - /// - /// The x- and y-coordinate location to render this at. - /// - /// - /// The color mask to apply when rendering this . - /// - public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color) => - Draw(spriteBatch, position, color, Vector2.One, 0.0f); - - /// - /// Draws this using the - /// . - /// - /// - /// The to use for rendering this - /// . - /// - /// - /// The x- and y-coordinate location to render this at. - /// - /// - /// The color mask to apply when rendering this . - /// - /// - /// The amount of scaling to apply when rendering this . - /// - /// - /// The layer depth to apply when rendering this . - /// - public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, float scale, float layerDepth) => - Draw(spriteBatch, position, color, new Vector2(scale, scale), layerDepth); - - /// - /// Draws this using the - /// . - /// - /// - /// The to use for rendering the - /// . - /// - /// - /// The x- and y-coordinate location to render the at. - /// - /// - /// The color mask to apply when rendering the . - /// - /// - /// The amount of scaling to apply when rendering the . - /// - /// - /// The layer depth to apply when rendering the . - /// - public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, Vector2 scale, float layerDepth) => - spriteBatch.Draw(this, position, color, scale, layerDepth); - - /// - /// Returns an enumerator used to iterate through all of the elements in this - /// . The order of elements in the enumeration is from first frame to last frame. - /// - /// - /// An enumerator used to iterate through all of the elements in this - /// . - /// - public IEnumerator GetEnumerator() => _frames.GetEnumerator(); - - /// - /// Returns an enumerator used to iterate through all of the elements in this - /// . The order of elements in the enumeration is from first frame to last frame. - /// - /// - /// An enumerator used to iterate through all of the elements in this - /// . - /// - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - public static AnimatedTilemap FromFile(GraphicsDevice device, AseFile file, AseProcessorOptions options) - { - options ??= AseProcessorOptions.Default; - AseAnimatedTilemap aseAnimatedTilemap = AseAnimatedTilemapProcessor.Process(file, options); - AnimatedTilemap animatedTilemap = new AnimatedTilemap(aseAnimatedTilemap.Name); - - Dictionary tilesetLookup = new Dictionary(); - for (int i = 0; i < aseAnimatedTilemap.Tilesets.Length; i++) - { - AseTileset aseTileset = aseAnimatedTilemap.Tilesets[i]; - Texture2D texture = aseTileset.Texture.ToTexture2D(device); - Tileset tileset = new Tileset(aseTileset.Name, texture, aseTileset.TileSize.Width, aseTileset.TileSize.Height); - tilesetLookup.Add(aseTileset.ID, tileset); - } - - for(int f = 0; f < aseAnimatedTilemap.Frames.Length; f++) - { - AseTilemapFrame aseTilemapFrame = aseAnimatedTilemap.Frames[f]; - AnimatedTilemapFrame animatedTilemapFrame = animatedTilemap.CreateFrame(aseTilemapFrame.Duration); - - for(int l = 0; l < aseTilemapFrame.Layers.Length; l++) - { - AseTilemapLayer aseTilemapLayer = aseTilemapFrame.Layers[l]; - TilemapLayer tilemapLayer = animatedTilemapFrame.CreateLayer(aseTilemapLayer.Name, - tilesetLookup[aseTilemapLayer.TilesetID], - aseTilemapLayer.Columns, - aseTilemapLayer.Rows, - aseTilemapLayer.Offset.ToXnaVector2()); - - for (int t = 0; t < aseTilemapLayer.Tiles.Length; t++) - { - AseTilemapTile aseTilemapTile = aseTilemapLayer.Tiles[t]; - tilemapLayer.SetTile(t, - aseTilemapTile.TilesetTileID, - aseTilemapTile.FlipVertically, - aseTilemapTile.FlipHorizontally, - aseTilemapTile.FlipDiagonally); - } - } - } - - return animatedTilemap; - } -} +/* ---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2018-2023 Christopher Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------------------------------------------------- */ + +using System.Collections; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + + +namespace MonoGame.Aseprite; + +/// +/// Defines a consisting of elements +/// +public sealed class AnimatedTilemap : IEnumerable +{ + private bool _hasBegun; + private int _currentIndex; + private int _direction; + private List _frames = new(); + + /// + /// Gets the name assigned to this . + /// + public string Name { get; } + + /// + /// Gets the total number of elements in this . + /// + public int frameCount => _frames.Count; + + /// + /// Gets the element at the specified index in this + /// . + /// + /// + /// The index of the element to locate. + /// + /// + /// The element that was located at the specified index in this + /// . + /// + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public AnimatedTilemapFrame this[int frameIndex] => GetFrame(frameIndex); + + /// + /// Gets a value that indicates if this is currently paused. + /// + public bool IsPaused { get; private set; } + + /// + /// Gets a value that indicates if this is currently animating. + /// + public bool IsAnimating { get; private set; } + + /// + /// Gets a value that indicates whether the animation this should loop. + /// + public bool IsLooping { get; } + + /// + /// Gets a value that indicates whether the animation this should play frames + /// in reverse order. + /// + public bool IsReversed { get; } + + /// + /// Gets a value that indicates whether the animation for this should ping-pong + /// once reaching the last frame of animation. + /// + public bool IsPingPong { get; } + + /// + /// Gets the source element for the current animation frame. + /// + /// + /// Thrown if no elements have been added to this + /// prior to accessing this property. + /// + public AnimatedTilemapFrame CurrentFrame + { + get + { + if (_frames.Count == 0) + { + throw new InvalidOperationException($"Unable to get current frame as no frames have been added to this animated tilemap."); + } + + return this[_currentIndex]; + } + } + + /// + /// Gets or Sets an method to invoke at the start of each animation frame. + /// + public Action? OnFrameBegin { get; set; } = default; + + /// + /// Gets or Sets an method to invoke at the end of each animation frame. + /// + public Action? OnFrameEnd { get; set; } = default; + + /// + /// Gets or Sets an method to invoke at the start of the animation. This will trigger only + /// once when the animation starts before the first frame's triggers. + /// + public Action? OnAnimationBegin { get; set; } = default; + + /// + /// Gets or Sets an method to invoke each time the animation loops. This will trigger each + /// time the animation loops after the last frame's triggers. + /// + public Action? OnAnimationLoop { get; set; } = default; + + /// + /// Gets or Sets an method to invoke when the animation ends. This will only trigger when + /// the animation ends in a non-looping animation, or if a looping animation is stopped by calling the + /// method manually. + /// + public Action? OnAnimationEnd { get; set; } = default; + + /// + /// Gets the amount of time remaining for the before moving to the next frame. + /// + public TimeSpan CurrentFrameTimeRemaining { get; private set; } + + + /// + /// Initializes a new instance of the class. + /// + /// + /// The name to assign the . + /// + /// + /// Indicates whether the animation for the should loop + /// + /// + /// Indicates whether the frames for the should play in reverse order. + /// + /// + /// Indicates whether the animation for this should ping-pong once reaching the + /// last frame of animation + /// + public AnimatedTilemap(string name, bool isLooping = true, bool isReversed = false, bool isPingPong = false) + { + Name = name; + IsLooping = isLooping; + IsReversed = isReversed; + IsPingPong = isPingPong; + Reset(); + } + + /// + /// Updates this . + /// + /// + /// This should only be called once per game update cycle. + /// + /// + /// The amount of time, in seconds, that have elapsed since the last update cycle in the game. + /// + public void Update(double deltaTimeInSeconds) + { + Update(TimeSpan.FromSeconds(deltaTimeInSeconds)); + } + + /// + /// Updates this . + /// + /// + /// This should only be called once per game update cycle. + /// + /// + /// A snapshot of the game timing values for the current update cycle. + /// + public void Update(GameTime gameTime) + { + Update(gameTime.ElapsedGameTime); + } + + /// + /// Updates this . + /// + /// + /// This should only be called once per game update cycle. + /// + /// + /// The amount of time, that have elapsed since the last update cycle in the game. + /// + public void Update(in TimeSpan elapsedTime) + { + if (!IsAnimating || IsPaused) + { + return; + } + + if (!_hasBegun) + { + _hasBegun = true; + OnAnimationBegin?.Invoke(this); + } + + if (CurrentFrameTimeRemaining == CurrentFrame.Duration) + { + OnFrameBegin?.Invoke(this); + } + + CurrentFrameTimeRemaining -= elapsedTime; + + if (CurrentFrameTimeRemaining <= TimeSpan.Zero) + { + AdvanceFrame(); + } + } + + private void AdvanceFrame() + { + OnFrameEnd?.Invoke(this); + + _currentIndex += _direction; + + switch (IsReversed, IsPingPong) + { + case (true, true): + ReversePingPongLoopCheck(); + break; + case (true, false): + ReverseLoopCheck(); + break; + case (false, true): + PingPongLoopCheck(); + break; + case (false, false): + LoopCheck(); + break; + } + + CurrentFrameTimeRemaining = CurrentFrame.Duration; + } + + private void LoopCheck() + { + if (_currentIndex >= _frames.Count) + { + if (IsLooping) + { + _currentIndex = 0; + OnAnimationLoop?.Invoke(this); + } + else + { + _currentIndex = _frames.Count - 1; + Stop(); + } + } + } + + private void ReverseLoopCheck() + { + if (_currentIndex < 0) + { + if (IsLooping) + { + _currentIndex = _frames.Count - 1; + OnAnimationLoop?.Invoke(this); + } + else + { + _currentIndex = 0; + Stop(); + } + } + } + + private void PingPongLoopCheck() + { + if (_currentIndex < 0 || _currentIndex >= _frames.Count) + { + _direction = -_direction; + + if (_direction == -1) + { + _currentIndex = _frames.Count - 2; + } + else + { + if (IsLooping) + { + _currentIndex = 1; + OnAnimationLoop?.Invoke(this); + } + else + { + _currentIndex = 0; + Stop(); + } + } + } + } + + private void ReversePingPongLoopCheck() + { + if (_currentIndex < 0 || _currentIndex >= _frames.Count) + { + _direction = -_direction; + + if (_direction == 1) + { + _currentIndex = 1; + } + else + { + if (IsLooping) + { + _currentIndex = _frames.Count - 2; + OnAnimationLoop?.Invoke(this); + } + else + { + _currentIndex = _frames.Count - 1; + Stop(); + } + } + } + } + + /// + /// Pauses this and prevents it from being updated until it is unpaused. + /// + /// + /// A value that indicates whether the the duration of the should be reset. When + /// this method returns , the duration will not be reset even if this is specified as + /// . + /// + /// + /// this was successfully paused; otherwise, + /// . This method returns this + /// is not currently animating or if it is already paused. + /// + public bool Pause(bool resetFrameDuration = false) + { + // We can only pause something that is animating and is not already paused. This is to prevent improper usage + // that could accidentally reset frame duration if it was set to true. + if (!IsAnimating || IsPaused) + { + return false; + } + + IsPaused = true; + + if (resetFrameDuration) + { + CurrentFrameTimeRemaining = CurrentFrame.Duration; + } + + return true; + } + + /// + /// Unpauses this . + /// + /// + /// A value that indicates whether this should immediately be advanced to the next + /// frame after unpausing. When this method returns , this + /// will -not- be advanced to the next frame, even if this was specified as . + /// + /// + /// if this was successfully unpaused; otherwise, + /// . This method return this is + /// not currently animating or if it has not already been paused. + /// + public bool Unpause(bool advanceToNextFrame = false) + { + // We can't unpause something that's not animating and also isn't paused. This is to prevent improper usage + // that could accidentally advance to the next frame if it was set to true. + if (!IsAnimating || !IsPaused) + { + return false; + } + + IsPaused = false; + + if (advanceToNextFrame) + { + AdvanceFrame(); + } + + return true; + } + + /// + /// Stops this on the . This will trigger the + /// if one was set. + /// + /// + /// this was successfully stopped; otherwise, + /// . This method returns this is + /// not currently animating. If this method returns , this indicates that the + /// action method was not invoked. + /// + public bool Stop() + { + // We can't stop something that's not animating. This is to prevent accidentally invoking the OnAnimationEnd + // action + if (!IsAnimating) + { + return false; + } + + IsAnimating = false; + OnAnimationEnd?.Invoke(this); + return true; + } + + /// + /// Resets this back to its first frame of animation. + /// + /// + /// A value that indicates whether his should be paused after it is reset. + /// + public void Reset(bool paused = false) + { + IsAnimating = true; + IsPaused = paused; + + if (IsReversed) + { + _direction = -1; + _currentIndex = _frames.Count; + } + else + { + _direction = 1; + _currentIndex = 0; + } + + _hasBegun = false; + } + + /// + /// Creates and adds a new element as the next frame of animation in this + /// . + /// + /// + /// The duration to assign the created. + /// + /// + /// The created. + /// + public AnimatedTilemapFrame CreateFrame(TimeSpan duration) + { + AnimatedTilemapFrame frame = new(duration); + AddFrame(frame); + return frame; + } + + /// + /// Adds the given as the next frame of animation in this + /// . + /// + /// + /// The to add + /// + public void AddFrame(AnimatedTilemapFrame frame) => _frames.Add(frame); + + /// + /// Gets the element at the specified index in this + /// . + /// + /// + /// The index of the element to locate. + /// + /// + /// The element that was located. + /// + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public AnimatedTilemapFrame GetFrame(int frameIndex) + { + if (frameIndex < 0 || frameIndex >= frameCount) + { + throw new ArgumentOutOfRangeException(nameof(frameIndex), $"{nameof(frameIndex)} cannot be less than zero or greater than or equal to the total number of animated tilemap frame elements in this animated tilemap."); + } + + return _frames[frameIndex]; + } + + /// + /// Gets the element at the specified index in this + /// . + /// + /// + /// The index of the element to locate. + /// + /// + /// When this method returns , contains the located; + /// otherwise, . + /// + /// + /// if the element was located; otherwise, + /// . This method returns when the specified index is less than + /// zero or is greater than or equal to the total number of elements in this + /// . + /// + public bool TryGetFrame(int index, out AnimatedTilemapFrame? frame) + { + if (index < 0 || index >= frameCount) + { + frame = default; + return false; + } + + frame = _frames[index]; + return true; + } + + /// + /// Removes the element at the specified index from this + /// . + /// + /// + /// The index of the element to remove. + /// + /// + /// if the was removed successfully; otherwise, + /// . This method returns when the specified index is less than + /// zero or is greater that or equal to the total number of elements in this + /// . + /// + public bool RemoveFrame(int index) + { + if (index < 0 || index >= frameCount) + { + return false; + } + + _frames.RemoveAt(index); + return true; + } + + /// + /// Removes all elements from this . + /// + public void Clear() => _frames.Clear(); + + + /// + /// Draws this using the + /// . + /// + /// + /// The to use for rendering this + /// . + /// + /// + /// The x- and y-coordinate location to render this at. + /// + /// + /// The color mask to apply when rendering this . + /// + public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color) => + Draw(spriteBatch, position, color, Vector2.One, 0.0f); + + /// + /// Draws this using the + /// . + /// + /// + /// The to use for rendering this + /// . + /// + /// + /// The x- and y-coordinate location to render this at. + /// + /// + /// The color mask to apply when rendering this . + /// + /// + /// The amount of scaling to apply when rendering this . + /// + /// + /// The layer depth to apply when rendering this . + /// + public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, float scale, float layerDepth) => + Draw(spriteBatch, position, color, new Vector2(scale, scale), layerDepth); + + /// + /// Draws this using the + /// . + /// + /// + /// The to use for rendering the + /// . + /// + /// + /// The x- and y-coordinate location to render the at. + /// + /// + /// The color mask to apply when rendering the . + /// + /// + /// The amount of scaling to apply when rendering the . + /// + /// + /// The layer depth to apply when rendering the . + /// + public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, Vector2 scale, float layerDepth) => + spriteBatch.Draw(this, position, color, scale, layerDepth); + + /// + /// Returns an enumerator used to iterate through all of the elements in this + /// . The order of elements in the enumeration is from first frame to last frame. + /// + /// + /// An enumerator used to iterate through all of the elements in this + /// . + /// + public IEnumerator GetEnumerator() => _frames.GetEnumerator(); + + /// + /// Returns an enumerator used to iterate through all of the elements in this + /// . The order of elements in the enumeration is from first frame to last frame. + /// + /// + /// An enumerator used to iterate through all of the elements in this + /// . + /// + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} diff --git a/source/MonoGame.Aseprite/Sprites/AnimationFrame.cs b/source/MonoGame.Aseprite/AnimationFrame.cs similarity index 96% rename from source/MonoGame.Aseprite/Sprites/AnimationFrame.cs rename to source/MonoGame.Aseprite/AnimationFrame.cs index a870bd3c..b91bf06b 100644 --- a/source/MonoGame.Aseprite/Sprites/AnimationFrame.cs +++ b/source/MonoGame.Aseprite/AnimationFrame.cs @@ -1,51 +1,51 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -namespace MonoGame.Aseprite.Sprites; - -/// -/// Defines the source and duration of a single frame of animation in an -/// . -/// -public sealed class AnimationFrame -{ - /// - /// Gets the index of the source in the of the - /// . - /// - public int FrameIndex { get; } - - /// - /// Gets the source for this . - /// - public TextureRegion TextureRegion { get; } - - /// - /// Gets the duration of this . - /// - public TimeSpan Duration { get; } - - internal AnimationFrame(int frameIndex, TextureRegion textureRegion, TimeSpan duration) => - (FrameIndex, TextureRegion, Duration) = (frameIndex, textureRegion, duration); -} +/* ---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2018-2023 Christopher Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------------------------------------------------- */ + +namespace MonoGame.Aseprite; + +/// +/// Defines the source and duration of a single frame of animation in an +/// . +/// +public sealed class AnimationFrame +{ + /// + /// Gets the index of the source in the of the + /// . + /// + public int FrameIndex { get; } + + /// + /// Gets the source for this . + /// + public TextureRegion TextureRegion { get; } + + /// + /// Gets the duration of this . + /// + public TimeSpan Duration { get; } + + internal AnimationFrame(int frameIndex, TextureRegion textureRegion, TimeSpan duration) => + (FrameIndex, TextureRegion, Duration) = (frameIndex, textureRegion, duration); +} diff --git a/source/MonoGame.Aseprite/Sprites/AnimationTag.cs b/source/MonoGame.Aseprite/AnimationTag.cs similarity index 94% rename from source/MonoGame.Aseprite/Sprites/AnimationTag.cs rename to source/MonoGame.Aseprite/AnimationTag.cs index 0fd9ca91..21770b28 100644 --- a/source/MonoGame.Aseprite/Sprites/AnimationTag.cs +++ b/source/MonoGame.Aseprite/AnimationTag.cs @@ -1,123 +1,123 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -namespace MonoGame.Aseprite.Sprites; - -/// -/// Defines the definition of an animation. -/// -public sealed class AnimationTag -{ - private AnimationFrame[] _frames; - - /// - /// Gets the name of the animation - /// - public string Name { get; } - - /// - /// Gets a read-only span of the elements that make up the animation. The order of - /// elements is from first frame to last frame in non-reverse order. - /// - public ReadOnlySpan Frames => _frames; - - /// - /// Gets the total number of , elements. - /// - public int FrameCount => _frames.Length; - - /// - /// Gets the element at the specified index from this . - /// - /// - /// The index of the to locate. - /// - /// - /// The located. - /// - /// - /// Thrown if the specified is less than zero or is greater than or equal to the total - /// number of elements in this . - /// - public AnimationFrame this[int index] => GetFrame(index); - - /// - /// Gets a value that indicates whether the animation should loop. - /// - public bool IsLooping => LoopCount == 0; - - /// - /// Gets or Sets a value that indicates whether the animation should play in reverse. - /// - public bool IsReversed { get; set; } - - /// - /// Gets or Sets a value that indicates whether the animation should ping-pong once reaching the last frame of - /// animation. - /// - public bool IsPingPong { get; set; } - - /// - /// Gets or Sets a value that indicates the total number of loops/cycles of this animation that should play. - /// - /// - /// - /// 0 = infinite looping - /// - /// - /// If is equal to , each direction of the - /// ping-pong will count as a loop. - /// - /// - public int LoopCount { get; set; } - - internal AnimationTag(string name, AnimationFrame[] frames, int loopCount, bool isReversed, bool isPingPong) => - (Name, _frames, LoopCount, IsReversed, IsPingPong) = (name, frames, loopCount, isReversed, isPingPong); - - /// - /// Gets the element at the specified index from this . - /// - /// - /// The index of the to locate. - /// - /// - /// The located. - /// - /// - /// Thrown if the specified is less than zero or is greater than or equal to the total - /// number of elements in this . - /// - public AnimationFrame GetFrame(int index) - { - if (index < 0 || index >= FrameCount) - { - ArgumentOutOfRangeException ex = new(nameof(index), $"{nameof(index)} cannot be less than zero or greater than or equal to the total number of animation frames in this animation tag."); - ex.Data.Add(nameof(index), index); - ex.Data.Add(nameof(FrameCount), FrameCount); - throw ex; - } - - return _frames[index]; - } -} +/* ---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2018-2023 Christopher Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------------------------------------------------- */ + +namespace MonoGame.Aseprite; + +/// +/// Defines the definition of an animation. +/// +public sealed class AnimationTag +{ + private AnimationFrame[] _frames; + + /// + /// Gets the name of the animation + /// + public string Name { get; } + + /// + /// Gets a read-only span of the elements that make up the animation. The order of + /// elements is from first frame to last frame in non-reverse order. + /// + public ReadOnlySpan Frames => _frames; + + /// + /// Gets the total number of , elements. + /// + public int FrameCount => _frames.Length; + + /// + /// Gets the element at the specified index from this . + /// + /// + /// The index of the to locate. + /// + /// + /// The located. + /// + /// + /// Thrown if the specified is less than zero or is greater than or equal to the total + /// number of elements in this . + /// + public AnimationFrame this[int index] => GetFrame(index); + + /// + /// Gets a value that indicates whether the animation should loop. + /// + public bool IsLooping => LoopCount == 0; + + /// + /// Gets or Sets a value that indicates whether the animation should play in reverse. + /// + public bool IsReversed { get; set; } + + /// + /// Gets or Sets a value that indicates whether the animation should ping-pong once reaching the last frame of + /// animation. + /// + public bool IsPingPong { get; set; } + + /// + /// Gets or Sets a value that indicates the total number of loops/cycles of this animation that should play. + /// + /// + /// + /// 0 = infinite looping + /// + /// + /// If is equal to , each direction of the + /// ping-pong will count as a loop. + /// + /// + public int LoopCount { get; set; } + + internal AnimationTag(string name, AnimationFrame[] frames, int loopCount, bool isReversed, bool isPingPong) => + (Name, _frames, LoopCount, IsReversed, IsPingPong) = (name, frames, loopCount, isReversed, isPingPong); + + /// + /// Gets the element at the specified index from this . + /// + /// + /// The index of the to locate. + /// + /// + /// The located. + /// + /// + /// Thrown if the specified is less than zero or is greater than or equal to the total + /// number of elements in this . + /// + public AnimationFrame GetFrame(int index) + { + if (index < 0 || index >= FrameCount) + { + ArgumentOutOfRangeException ex = new(nameof(index), $"{nameof(index)} cannot be less than zero or greater than or equal to the total number of animation frames in this animation tag."); + ex.Data.Add(nameof(index), index); + ex.Data.Add(nameof(FrameCount), FrameCount); + throw ex; + } + + return _frames[index]; + } +} diff --git a/source/MonoGame.Aseprite/Sprites/AnimationTagBuilder.cs b/source/MonoGame.Aseprite/AnimationTagBuilder.cs similarity index 97% rename from source/MonoGame.Aseprite/Sprites/AnimationTagBuilder.cs rename to source/MonoGame.Aseprite/AnimationTagBuilder.cs index 959aabfa..7ed3b81f 100644 --- a/source/MonoGame.Aseprite/Sprites/AnimationTagBuilder.cs +++ b/source/MonoGame.Aseprite/AnimationTagBuilder.cs @@ -1,156 +1,156 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -namespace MonoGame.Aseprite.Sprites; - -/// -/// Defines a builder building an for a . -/// -public sealed class AnimationTagBuilder -{ - private string _name; - private List _frames = new(); - private SpriteSheet _spriteSheet; - private int _loopCount = 0; - private bool _isReversed = false; - private bool _isPingPong = false; - - internal AnimationTagBuilder(string name, SpriteSheet spriteSheet) => - (_name, _spriteSheet) = (name, spriteSheet); - - /// - /// Adds a new frame of animation to the using the - /// located at the specified index in the of the and with - /// the specified duration. - /// - /// - /// The index of the source in the of the - /// . - /// - /// - /// The duration of the frame of animation. - /// - /// - /// This instance of the class. - /// - /// - /// Throw if the specified index is less than zero or is greater than or equal to the total number of regions in - /// the . - /// - public AnimationTagBuilder AddFrame(int regionIndex, TimeSpan duration) - { - TextureRegion region = _spriteSheet.TextureAtlas.GetRegion(regionIndex); - AnimationFrame frame = new(regionIndex, region, duration); - _frames.Add(frame); - return this; - } - - /// - /// Adds a new frame of animation to the using the with - /// the specified name in the of the and with the specified - /// duration. - /// - /// - /// The name of the source in the of the - /// . - /// - /// - /// The duration of the frame of animation. - /// - /// - /// This instance of the class. - /// - /// - /// Thrown if the of the does not contain a - /// with the specified name. - /// - public AnimationTagBuilder AddFrame(string regionName, TimeSpan duration) - { - TextureRegion region = _spriteSheet.TextureAtlas.GetRegion(regionName); - int index = _spriteSheet.TextureAtlas.GetIndexOfRegion(regionName); - AnimationFrame frame = new(index, region, duration); - _frames.Add(frame); - return this; - } - - /// - /// Sets the total number of loops/cycles of the animation that should play. - /// - /// - /// - /// 0 = infinite looping - /// - /// - /// If is equal to , each direction of the - /// ping-pong will count as a loop. - /// - /// - /// - /// A value that indicates the total number of loops/cycles of the animation that should play. - /// - /// - /// This instance of the class. - /// - public AnimationTagBuilder LoopCount(int count) - { - _loopCount = count; - return this; - } - - /// - /// Sets whether the animation should play in reverse. - /// - /// - /// A value that indicates whether the animation should play in reverse - /// - /// - /// This instance of the class. - /// - public AnimationTagBuilder IsReversed(bool isReversed) - { - _isReversed = isReversed; - return this; - } - - /// - /// Sets whether the animation should ping-pong once reaching the last frame of animation. - /// - /// - /// A value that indicates whether the animation should ping-pong. - /// - /// - /// This instance of the class. - /// - public AnimationTagBuilder IsPingPong(bool isPingPong) - { - _isPingPong = isPingPong; - return this; - } - - internal AnimationTag Build() - { - AnimationTag tag = new(_name, _frames.ToArray(), _loopCount, _isReversed, _isPingPong); - return tag; - } -} +/* ---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2018-2023 Christopher Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------------------------------------------------- */ + +namespace MonoGame.Aseprite; + +/// +/// Defines a builder building an for a . +/// +public sealed class AnimationTagBuilder +{ + private string _name; + private List _frames = new(); + private SpriteSheet _spriteSheet; + private int _loopCount = 0; + private bool _isReversed = false; + private bool _isPingPong = false; + + internal AnimationTagBuilder(string name, SpriteSheet spriteSheet) => + (_name, _spriteSheet) = (name, spriteSheet); + + /// + /// Adds a new frame of animation to the using the + /// located at the specified index in the of the and with + /// the specified duration. + /// + /// + /// The index of the source in the of the + /// . + /// + /// + /// The duration of the frame of animation. + /// + /// + /// This instance of the class. + /// + /// + /// Throw if the specified index is less than zero or is greater than or equal to the total number of regions in + /// the . + /// + public AnimationTagBuilder AddFrame(int regionIndex, TimeSpan duration) + { + TextureRegion region = _spriteSheet.TextureAtlas.GetRegion(regionIndex); + AnimationFrame frame = new(regionIndex, region, duration); + _frames.Add(frame); + return this; + } + + /// + /// Adds a new frame of animation to the using the with + /// the specified name in the of the and with the specified + /// duration. + /// + /// + /// The name of the source in the of the + /// . + /// + /// + /// The duration of the frame of animation. + /// + /// + /// This instance of the class. + /// + /// + /// Thrown if the of the does not contain a + /// with the specified name. + /// + public AnimationTagBuilder AddFrame(string regionName, TimeSpan duration) + { + TextureRegion region = _spriteSheet.TextureAtlas.GetRegion(regionName); + int index = _spriteSheet.TextureAtlas.GetIndexOfRegion(regionName); + AnimationFrame frame = new(index, region, duration); + _frames.Add(frame); + return this; + } + + /// + /// Sets the total number of loops/cycles of the animation that should play. + /// + /// + /// + /// 0 = infinite looping + /// + /// + /// If is equal to , each direction of the + /// ping-pong will count as a loop. + /// + /// + /// + /// A value that indicates the total number of loops/cycles of the animation that should play. + /// + /// + /// This instance of the class. + /// + public AnimationTagBuilder LoopCount(int count) + { + _loopCount = count; + return this; + } + + /// + /// Sets whether the animation should play in reverse. + /// + /// + /// A value that indicates whether the animation should play in reverse + /// + /// + /// This instance of the class. + /// + public AnimationTagBuilder IsReversed(bool isReversed) + { + _isReversed = isReversed; + return this; + } + + /// + /// Sets whether the animation should ping-pong once reaching the last frame of animation. + /// + /// + /// A value that indicates whether the animation should ping-pong. + /// + /// + /// This instance of the class. + /// + public AnimationTagBuilder IsPingPong(bool isPingPong) + { + _isPingPong = isPingPong; + return this; + } + + internal AnimationTag Build() + { + AnimationTag tag = new(_name, _frames.ToArray(), _loopCount, _isReversed, _isPingPong); + return tag; + } +} diff --git a/source/MonoGame.Aseprite/AsepriteDotNetUsings.cs b/source/MonoGame.Aseprite/AsepriteDotNetUsings.cs deleted file mode 100644 index 2863f776..00000000 --- a/source/MonoGame.Aseprite/AsepriteDotNetUsings.cs +++ /dev/null @@ -1,27 +0,0 @@ -global using Ase = AsepriteDotNet.Aseprite; -global using AseAnimatedTilemap = AsepriteDotNet.AnimatedTilemap; -global using AseAnimatedTilemapProcessor = AsepriteDotNet.Processors.AnimatedTilemapProcessor; -global using AseAnimationFrame = AsepriteDotNet.AnimationFrame; -global using AseFile = AsepriteDotNet.Aseprite.AsepriteFile; -global using AseColor = AsepriteDotNet.Common.Rgba32; -global using AseNinepatchSlice = AsepriteDotNet.NinePatchSlice; -global using AsePoint = AsepriteDotNet.Common.Point; -global using AseProcessorOptions = AsepriteDotNet.Processors.ProcessorOptions; -global using AseRectangle = AsepriteDotNet.Common.Rectangle; -global using AseSlice = AsepriteDotNet.Slice; -global using AseSprite = AsepriteDotNet.Sprite; -global using AseSpriteProcessor = AsepriteDotNet.Processors.SpriteProcessor; -global using AseSpriteSheet = AsepriteDotNet.SpriteSheet; -global using AseSpriteSheetProcessor = AsepriteDotNet.Processors.SpriteSheetProcessor; -global using AseTag = AsepriteDotNet.AnimationTag; -global using AseTexture = AsepriteDotNet.Texture; -global using AseTextureAtlas = AsepriteDotNet.TextureAtlas; -global using AseTextureAtlasProcessor = AsepriteDotNet.Processors.TextureAtlasProcessor; -global using AseTextureRegion = AsepriteDotNet.TextureRegion; -global using AseTileset = AsepriteDotNet.Tileset; -global using AseTilesetProcessor = AsepriteDotNet.Processors.TilesetProcessor; -global using AseTilemap = AsepriteDotNet.Tilemap; -global using AseTilemapFrame = AsepriteDotNet.TilemapFrame; -global using AseTilemapLayer = AsepriteDotNet.TilemapLayer; -global using AseTilemapProcessor = AsepriteDotNet.Processors.TilemapProcessor; -global using AseTilemapTile = AsepriteDotNet.TilemapTile; diff --git a/source/MonoGame.Aseprite/AsepriteFileExtensions.cs b/source/MonoGame.Aseprite/AsepriteFileExtensions.cs new file mode 100644 index 00000000..a41c514e --- /dev/null +++ b/source/MonoGame.Aseprite/AsepriteFileExtensions.cs @@ -0,0 +1,382 @@ +using AsepriteDotNet.Aseprite; +using AsepriteDotNet.Processors; +using Microsoft.Xna.Framework.Graphics; +using MonoGame.Aseprite.Utils; +using AseAnimatedTilemap = AsepriteDotNet.AnimatedTilemap; +using AseAnimationFrame = AsepriteDotNet.AnimationFrame; +using AseNinepatchSlice = AsepriteDotNet.NinePatchSlice; +using AseSlice = AsepriteDotNet.Slice; +using AseSprite = AsepriteDotNet.Sprite; +using AseSpriteSheet = AsepriteDotNet.SpriteSheet; +using AseTag = AsepriteDotNet.AnimationTag; +using AseTextureAtlas = AsepriteDotNet.TextureAtlas; +using AseTextureRegion = AsepriteDotNet.TextureRegion; +using AseTilemap = AsepriteDotNet.Tilemap; +using AseTilemapFrame = AsepriteDotNet.TilemapFrame; +using AseTilemapLayer = AsepriteDotNet.TilemapLayer; +using AseTilemapTile = AsepriteDotNet.TilemapTile; +using AseTileset = AsepriteDotNet.Tileset; + + +namespace MonoGame.Aseprite; + +/// +/// Extension methods for working with an Aseprite File loaded by the AsepriteDotNet library. +/// +public static class AsepriteFileExtensions +{ + /// + /// Creates a new from the specified frame index of the provided aseprite file instance. + /// + /// The aseprite file instance. + /// The graphics device used to create graphical resources. + /// The index of the frame in the aseprite file to create the sprite from. + /// The options to use when processing the sprite. + /// The created by this method. + /// + /// Thrown if the parameter is . + /// + /// -or- + /// + /// Thrown if the parameter is . + /// + /// + /// Thrown if is less than zero or greater than or equal to the total number of + /// frames in the aseprite file. + /// + public static Sprite CreateSprite(this AsepriteFile aseFile, GraphicsDevice device, int frameIndex, ProcessorOptions options) + { + ArgumentNullException.ThrowIfNull(aseFile); + ArgumentNullException.ThrowIfNull(device); + + options ??= ProcessorOptions.Default; + AseSprite aseSprite = SpriteProcessor.Process(aseFile, frameIndex, options); + Texture2D texture = aseSprite.Texture.ToTexture2D(device); + TextureRegion region = new TextureRegion(texture.Name, texture, texture.Bounds); + + Parallel.For(0, aseSprite.Slices.Length, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, i => + { + AddSliceToRegion(region, aseSprite.Slices[i]); + }); + + return new Sprite(aseSprite.Name, region); + } + + /// + /// Creates a new from the provided aseprite file. + /// + /// The aseprite file instance. + /// The graphics device used to create graphical resources. + /// The options to use when processing the texture atlas.. + /// The created by this method. + /// + /// Thrown if the parameter is . + /// + /// -or- + /// + /// Thrown if the parameter is . + /// + public static TextureAtlas CreateTextureAtlas(this AsepriteFile aseFile, GraphicsDevice device, ProcessorOptions options) + { + ArgumentNullException.ThrowIfNull(aseFile); + ArgumentNullException.ThrowIfNull(device); + + options ??= ProcessorOptions.Default; + AseTextureAtlas aseAtlas = TextureAtlasProcessor.Process(aseFile, options); + Texture2D texture = aseAtlas.Texture.ToTexture2D(device); + TextureAtlas atlas = new TextureAtlas(texture.Name, texture); + GenerateRegions(atlas, aseAtlas); + return atlas; + } + + /// + /// Creates a new from the provided aseprite file. + /// + /// The aseprite file instance. + /// The graphics device used to create graphical resources. + /// The options to use when processing the sprite sheet.. + /// The created by this method. + /// + /// Thrown if the parameter is . + /// + /// -or- + /// + /// Thrown if the parameter is . + /// + public static SpriteSheet CreateSpriteSheet(this AsepriteFile aseFile, GraphicsDevice device, ProcessorOptions options) + { + ArgumentNullException.ThrowIfNull(aseFile); + ArgumentNullException.ThrowIfNull(device); + + options ??= ProcessorOptions.Default; + AseSpriteSheet aseSheet = SpriteSheetProcessor.Process(aseFile, options); + Texture2D texture = aseSheet.TextureAtlas.Texture.ToTexture2D(device); + TextureAtlas atlas = new TextureAtlas(texture.Name, texture); + GenerateRegions(atlas, aseSheet.TextureAtlas); + SpriteSheet sheet = new SpriteSheet(atlas.Name, atlas); + + Parallel.For(0, aseSheet.Tags.Length, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, i => + { + AseTag aseTag = aseSheet.Tags[i]; + sheet.CreateAnimationTag(aseTag.Name, builder => + { + builder.LoopCount(aseTag.LoopCount) + .IsReversed(aseTag.IsReversed) + .IsPingPong(aseTag.IsPingPong); + + Parallel.For(0, aseTag.Frames.Length, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, j => + { + AseAnimationFrame aseAnimationFrame = aseTag.Frames[j]; + builder.AddFrame(aseAnimationFrame.FrameIndex, aseAnimationFrame.Duration); + }); + }); + }); + + return sheet; + } + + /// + /// Creates a new from the frame at the specified index in provided aseprite file. + /// + /// The aseprite file instance. + /// The graphics device used to create graphical resources. + /// The index of the frame that contains the tileset. + /// The created by this method. + /// + /// Thrown if the parameter is . + /// + /// -or- + /// + /// Throw if the is less than zero or greater than or equal to the total number of + /// frames in the aseprite file + /// + /// -or- + /// + /// Thrown if the parameter is . + /// + public static Tileset CreateTileset(this AsepriteFile aseFile, GraphicsDevice device, int frameIndex) + { + ArgumentNullException.ThrowIfNull(aseFile); + ArgumentNullException.ThrowIfNull(device); + + AseTileset aseTileset = TilesetProcessor.Process(aseFile, frameIndex); + return aseTileset.CreateTileset(device); + } + + /// + /// Creates a new with the specified name in provided aseprite file. + /// + /// The aseprite file instance. + /// The graphics device used to create graphical resources. + /// The name of the tileset. + /// The created by this method. + /// + /// Thrown if the parameter is . + /// + /// -or- + /// + /// Thrown if the parameter is . + /// + /// + /// Throw if no tileset with the specified exists in the aseprite file. + /// + public static Tileset CreateTileset(this AsepriteFile aseFile, GraphicsDevice device, string tilesetName) + { + ArgumentNullException.ThrowIfNull(aseFile); + ArgumentNullException.ThrowIfNull(device); + + AseTileset aseTileset = TilesetProcessor.Process(aseFile, tilesetName); + return aseTileset.CreateTileset(device); + } + + /// + /// Creates a new from the specified aseprite tileset. + /// + /// The Aseprite tileset to create the tileset from.. + /// The graphics device used to create graphical resources. + /// The created by this method. + /// + /// Thrown if the parameter is . + /// + /// -or- + /// + /// Thrown if the parameter is . + /// + public static Tileset CreateTileset(this AseTileset aseTileset, GraphicsDevice device) + { + ArgumentNullException.ThrowIfNull(aseTileset); + ArgumentNullException.ThrowIfNull(device); + + Texture2D texture = aseTileset.Texture.ToTexture2D(device); + return new Tileset(aseTileset.Name, + texture, + aseTileset.TileSize.Width, + aseTileset.TileSize.Height); + } + + /// + /// Creates a new from a specified frame in the provided aseprite file. + /// + /// The aseprite file instance. + /// The graphics device used to create graphical resources. + /// The index of the frame with the tilemap. + /// The options to use when processing the tilemap. + /// The created by this method. + /// + /// Thrown if is . + /// + /// -or- + /// + /// throw if is . + /// + public static Tilemap CreateTilemap(this AsepriteFile aseFile, GraphicsDevice device, int frameIndex, ProcessorOptions options) + { + ArgumentNullException.ThrowIfNull(aseFile); + ArgumentNullException.ThrowIfNull(device); + + options ??= ProcessorOptions.Default; + AseTilemap aseTilemap = TilemapProcessor.Process(aseFile, frameIndex, options); + Tilemap tilemap = new Tilemap(aseTilemap.Name); + Dictionary tilesets = GenereateTilesets(device, aseTilemap); + + Parallel.For(0, aseTilemap.Layers.Length, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, i => + { + AseTilemapLayer aseTilemapLayer = aseTilemap.Layers[i]; + Tileset tileset = tilesets[aseTilemapLayer.TilesetID]; + TilemapLayer tilemapLayer = tilemap.CreateLayer(aseTilemapLayer.Name, + tileset, + aseTilemapLayer.Columns, + aseTilemapLayer.Rows, + aseTilemapLayer.Offset.ToXnaVector2()); + + Parallel.For(0, aseTilemapLayer.Tiles.Length, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, t => + { + AseTilemapTile aseTilemapTile = aseTilemapLayer.Tiles[t]; + tilemapLayer.SetTile(t, + aseTilemapTile.TilesetTileID, + aseTilemapTile.FlipHorizontally, + aseTilemapTile.FlipVertically, + aseTilemapTile.FlipDiagonally); + }); + }); + + return tilemap; + } + + /// + /// Creates a new from the all frames in the provided aseprite file. + /// + /// The aseprite file instance. + /// The graphics device used to create graphical resources. + /// The options to use when processing the animated tilemap. + /// the created by this method. + /// + /// Thrown if is . + /// + /// -or- + /// + /// throw if is . + /// + public static AnimatedTilemap CreateAnimatedTilemap(this AsepriteFile aseFile, GraphicsDevice device, ProcessorOptions options) + { + ArgumentNullException.ThrowIfNull(aseFile); + ArgumentNullException.ThrowIfNull(device); + + options ??= ProcessorOptions.Default; + AseAnimatedTilemap aseAnimatedTilemap = AnimatedTilemapProcessor.Process(aseFile, options); + AnimatedTilemap animatedTilemap = new AnimatedTilemap(aseAnimatedTilemap.Name); + Dictionary tilesets = new Dictionary(); + + ParallelOptions parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }; + Parallel.For(0, aseAnimatedTilemap.Tilesets.Length, parallelOptions, i => + { + AseTileset aseTileset = aseAnimatedTilemap.Tilesets[i]; + Texture2D texture = aseTileset.Texture.ToTexture2D(device); + Tileset tileset = new Tileset(aseTileset.Name, + texture, + aseTileset.TileSize.Width, + aseTileset.TileSize.Height); + tilesets.Add(aseTileset.ID, tileset); + }); + + Parallel.For(0, aseAnimatedTilemap.Frames.Length, parallelOptions, i => + { + AseTilemapFrame aseTilemapFrame = aseAnimatedTilemap.Frames[i]; + AnimatedTilemapFrame animatedTilemapFrame = animatedTilemap.CreateFrame(aseTilemapFrame.Duration); + + Parallel.For(0, aseTilemapFrame.Layers.Length, parallelOptions, l => + { + AseTilemapLayer aseTilemapLayer = aseTilemapFrame.Layers[l]; + TilemapLayer tilemapLayer = animatedTilemapFrame.CreateLayer(aseTilemapLayer.Name, + tilesets[aseTilemapLayer.TilesetID], + aseTilemapLayer.Columns, + aseTilemapLayer.Rows, + aseTilemapLayer.Offset.ToXnaVector2()); + + Parallel.For(0, aseTilemapLayer.Tiles.Length, parallelOptions, t => + { + AseTilemapTile aseTilemapTile = aseTilemapLayer.Tiles[t]; + tilemapLayer.SetTile(t, + aseTilemapTile.TilesetTileID, + aseTilemapTile.FlipHorizontally, + aseTilemapTile.FlipVertically, + aseTilemapTile.FlipDiagonally); + }); + }); + }); + + return animatedTilemap; + } + + + private static void GenerateRegions(TextureAtlas atlas, AseTextureAtlas aseAtlas) + { + ParallelOptions options = new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }; + + Parallel.For(0, aseAtlas.Regions.Length, options, i => + { + AseTextureRegion aseRegion = aseAtlas.Regions[i]; + TextureRegion region = atlas.CreateRegion(aseRegion.Name, aseRegion.Bounds.ToXnaRectangle()); + + Parallel.For(0, aseRegion.Slices.Length, options, i => + { + AddSliceToRegion(region, aseRegion.Slices[i]); + }); + }); + } + + private static void AddSliceToRegion(TextureRegion region, AseSlice aseSlice) + { + if (aseSlice is AseNinepatchSlice aseNinePatchSlice) + { + region.CreateNinePatchSlice(aseNinePatchSlice.Name, + aseNinePatchSlice.Bounds.ToXnaRectangle(), + aseNinePatchSlice.CenterBounds.ToXnaRectangle(), + aseNinePatchSlice.Origin.ToXnaVector2(), + aseNinePatchSlice.Color.ToXnaColor()); + } + else + { + region.CreateSlice(aseSlice.Name, + aseSlice.Bounds.ToXnaRectangle(), + aseSlice.Origin.ToXnaVector2(), + aseSlice.Color.ToXnaColor()); + } + } + + private static Dictionary GenereateTilesets(GraphicsDevice device, AseTilemap aseTilemap) + { + Dictionary result = new Dictionary(); + Parallel.For(0, aseTilemap.Tilesets.Length, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, i => + { + AseTileset aseTileset = aseTilemap.Tilesets[i]; + Texture2D texture = aseTileset.Texture.ToTexture2D(device); + Tileset tileset = new Tileset(aseTileset.Name, + texture, + aseTileset.TileSize.Width, + aseTileset.TileSize.Height); + result.Add(aseTileset.ID, tileset); + }); + return result; + } +} diff --git a/source/MonoGame.Aseprite/Content/Pipeline/Readers/AnimatedTilemapContentTypeReader.cs b/source/MonoGame.Aseprite/Content/Pipeline/Readers/AnimatedTilemapContentTypeReader.cs deleted file mode 100644 index acd0c439..00000000 --- a/source/MonoGame.Aseprite/Content/Pipeline/Readers/AnimatedTilemapContentTypeReader.cs +++ /dev/null @@ -1,86 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content; -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.RawTypes; -using MonoGame.Aseprite.Tilemaps; - -namespace MonoGame.Aseprite.Content.Pipeline.Readers; - -internal sealed class AnimatedTilemapContentTypeReader : ContentTypeReader -{ - protected override AnimatedTilemap Read(ContentReader reader, AnimatedTilemap? existingInstance) - { - if (existingInstance is not null) - { - return existingInstance; - } - - string name = reader.ReadString(); - AnimatedTilemap animatedTilemap = new(name); - Dictionary tilesets = ReadTilesets(reader); - RawTilemapFrame[] rawFrames = reader.ReadRawTilemapFrames(); - - for (int f = 0; f < rawFrames.Length; f++) - { - RawTilemapFrame rawFrame = rawFrames[f]; - TimeSpan duration = TimeSpan.FromMilliseconds(rawFrame.DurationInMilliseconds); - AnimatedTilemapFrame animatedTilemapFrame = animatedTilemap.CreateFrame(duration); - - for (int l = 0; l < rawFrame.RawTilemapLayers.Length; l++) - { - RawTilemapLayer rawLayer = rawFrame.RawTilemapLayers[l]; - TilemapLayer tilemapLayer = animatedTilemapFrame.CreateLayer(rawLayer.Name, tilesets[rawLayer.TilesetID], rawLayer.Columns, rawLayer.Rows, rawLayer.Offset.ToVector2()); - - for (int t = 0; t < rawLayer.RawTilemapTiles.Length; t++) - { - RawTilemapTile rawTile = rawLayer.RawTilemapTiles[t]; - tilemapLayer.SetTile(t, rawTile.TilesetTileID, rawTile.FlipVertically, rawTile.FlipHorizontally, rawTile.FlipDiagonally); - } - } - } - - return animatedTilemap; - } - - private Dictionary ReadTilesets(ContentReader reader) - { - Dictionary tilesets = new(); - - int count = reader.ReadInt32(); - for (int i = 0; i < count; i++) - { - string name = reader.ReadString(); - int id = reader.ReadInt32(); - int tileWidth = reader.ReadInt32(); - int tileHeight = reader.ReadInt32(); - Texture2D texture = reader.ReadObject(); - Tileset tileset = new(name, texture, tileWidth, tileHeight); - tilesets.Add(id, tileset); - } - - return tilesets; - } -} diff --git a/source/MonoGame.Aseprite/Content/Pipeline/Readers/AsepriteFileContentTypeReader.cs b/source/MonoGame.Aseprite/Content/Pipeline/Readers/AsepriteFileContentTypeReader.cs index bef1d92c..3a42cce0 100644 --- a/source/MonoGame.Aseprite/Content/Pipeline/Readers/AsepriteFileContentTypeReader.cs +++ b/source/MonoGame.Aseprite/Content/Pipeline/Readers/AsepriteFileContentTypeReader.cs @@ -22,8 +22,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- */ +using AsepriteDotNet.Aseprite; +using AsepriteDotNet.IO; using Microsoft.Xna.Framework.Content; -using MonoGame.Aseprite.Content.Readers; namespace MonoGame.Aseprite.Content.Pipeline.Readers; @@ -37,10 +38,11 @@ protected override AsepriteFile Read(ContentReader reader, AsepriteFile? existin return existingInstance; } + string name = reader.ReadString(); int len = reader.ReadInt32(); byte[] data = reader.ReadBytes(len); using MemoryStream stream = new(data); - return AsepriteFileReader.ReadStream(reader.AssetName, stream); + return AsepriteFileLoader.FromStream(name, stream); } } diff --git a/source/MonoGame.Aseprite/Content/Pipeline/Readers/SpriteContentTypeReader.cs b/source/MonoGame.Aseprite/Content/Pipeline/Readers/SpriteContentTypeReader.cs deleted file mode 100644 index 0ff06e9b..00000000 --- a/source/MonoGame.Aseprite/Content/Pipeline/Readers/SpriteContentTypeReader.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content; -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.Sprites; - -namespace MonoGame.Aseprite.Content.Pipeline.Readers; - -internal sealed class SpriteContentTypeReader : ContentTypeReader -{ - protected override Sprite Read(ContentReader reader, Sprite? existingInstance) - { - if (existingInstance is not null) - { - return existingInstance; - } - - string name = reader.ReadString(); - Texture2D texture = reader.ReadObject(); - return new(name, texture); - } -} diff --git a/source/MonoGame.Aseprite/Content/Pipeline/Readers/SpriteSheetContentTypeReader.cs b/source/MonoGame.Aseprite/Content/Pipeline/Readers/SpriteSheetContentTypeReader.cs deleted file mode 100644 index fa88349e..00000000 --- a/source/MonoGame.Aseprite/Content/Pipeline/Readers/SpriteSheetContentTypeReader.cs +++ /dev/null @@ -1,91 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content; -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.RawTypes; -using MonoGame.Aseprite.Sprites; - -namespace MonoGame.Aseprite.Content.Pipeline.Readers; - -internal sealed class SpriteSheetContentTypeReader : ContentTypeReader -{ - protected override SpriteSheet Read(ContentReader reader, SpriteSheet? existingInstance) - { - if (existingInstance is not null) - { - return existingInstance; - } - - string spriteSheetName = reader.ReadString(); - string textureAtlasName = reader.ReadString(); - - Texture2D texture = reader.ReadObject(); - TextureAtlas textureAtlas = new(textureAtlasName, texture); - - RawTextureRegion[] rawTextureRegions = reader.ReadRawTextureRegions(); - - for (int i = 0; i < rawTextureRegions.Length; i++) - { - RawTextureRegion rawTextureRegion = rawTextureRegions[i]; - - TextureRegion textureRegion = textureAtlas.CreateRegion(rawTextureRegion.Name, rawTextureRegion.Bounds); - - foreach (RawSlice rawSlice in rawTextureRegion.Slices) - { - if (rawSlice is RawNinePatchSlice rawNinePatchSlice) - { - textureRegion.CreateNinePatchSlice(rawNinePatchSlice.Name, rawNinePatchSlice.Bounds, rawNinePatchSlice.CenterBounds, rawNinePatchSlice.Origin, rawNinePatchSlice.Color); - } - else - { - textureRegion.CreateSlice(rawSlice.Name, rawSlice.Bounds, rawSlice.Origin, rawSlice.Color); - } - } - } - - SpriteSheet spriteSheet = new(spriteSheetName, textureAtlas); - RawAnimationTag[] tags = reader.ReadRawAnimationTags(); - for (int i = 0; i < tags.Length; i++) - { - RawAnimationTag tag = tags[i]; - - spriteSheet.CreateAnimationTag(tag.Name, builder => - { - builder.LoopCount(tag.LoopCount) - .IsReversed(tag.IsReversed) - .IsPingPong(tag.IsPingPong); - - for (int j = 0; j < tag.RawAnimationFrames.Length; j++) - { - RawAnimationFrame rawAnimationFrame = tag.RawAnimationFrames[j]; - TimeSpan duration = TimeSpan.FromMilliseconds(rawAnimationFrame.DurationInMilliseconds); - builder.AddFrame(rawAnimationFrame.FrameIndex, duration); - } - }); - } - - return spriteSheet; - } -} diff --git a/source/MonoGame.Aseprite/Content/Pipeline/Readers/TextureAtlasContentTypeReader.cs b/source/MonoGame.Aseprite/Content/Pipeline/Readers/TextureAtlasContentTypeReader.cs deleted file mode 100644 index 2158d4c1..00000000 --- a/source/MonoGame.Aseprite/Content/Pipeline/Readers/TextureAtlasContentTypeReader.cs +++ /dev/null @@ -1,68 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content; -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.RawTypes; -using MonoGame.Aseprite.Sprites; - -namespace MonoGame.Aseprite.Content.Pipeline.Readers; - -internal sealed class TextureAtlasContentTypeReader : ContentTypeReader -{ - protected override TextureAtlas Read(ContentReader reader, TextureAtlas? existingInstance) - { - if (existingInstance is not null) - { - return existingInstance; - } - - string name = reader.ReadString(); - Texture2D texture = reader.ReadObject(); - TextureAtlas textureAtlas = new(name, texture); - - RawTextureRegion[] rawTextureRegions = reader.ReadRawTextureRegions(); - - for (int i = 0; i < rawTextureRegions.Length; i++) - { - RawTextureRegion rawTextureRegion = rawTextureRegions[i]; - - TextureRegion textureRegion = textureAtlas.CreateRegion(rawTextureRegion.Name, rawTextureRegion.Bounds); - - foreach (RawSlice rawSlice in rawTextureRegion.Slices) - { - if (rawSlice is RawNinePatchSlice rawNinePatchSlice) - { - textureRegion.CreateNinePatchSlice(rawNinePatchSlice.Name, rawNinePatchSlice.Bounds, rawNinePatchSlice.CenterBounds, rawNinePatchSlice.Origin, rawNinePatchSlice.Color); - } - else - { - textureRegion.CreateSlice(rawSlice.Name, rawSlice.Bounds, rawSlice.Origin, rawSlice.Color); - } - } - } - - return textureAtlas; - } -} diff --git a/source/MonoGame.Aseprite/Content/Pipeline/Readers/TilemapContentTypeReader.cs b/source/MonoGame.Aseprite/Content/Pipeline/Readers/TilemapContentTypeReader.cs deleted file mode 100644 index 36636a36..00000000 --- a/source/MonoGame.Aseprite/Content/Pipeline/Readers/TilemapContentTypeReader.cs +++ /dev/null @@ -1,81 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content; -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.RawTypes; -using MonoGame.Aseprite.Tilemaps; - -namespace MonoGame.Aseprite.Content.Pipeline.Readers; - -internal sealed class TilemapContentTypeReader : ContentTypeReader -{ - protected override Tilemap Read(ContentReader reader, Tilemap? existingInstance) - { - if (existingInstance is not null) - { - return existingInstance; - } - - string name = reader.ReadString(); - Tilemap tilemap = new(name); - - Dictionary tilesets = ReadTilesets(reader); - RawTilemapLayer[] layers = reader.ReadRawTilemapLayers(); - - for (int i = 0; i < layers.Length; i++) - { - RawTilemapLayer rawLayer = layers[i]; - Tileset tileset = tilesets[rawLayer.TilesetID]; - - TilemapLayer layer = tilemap.CreateLayer(rawLayer.Name, tileset, rawLayer.Columns, rawLayer.Rows, rawLayer.Offset.ToVector2()); - for (int j = 0; j < rawLayer.RawTilemapTiles.Length; j++) - { - RawTilemapTile rawTile = rawLayer.RawTilemapTiles[j]; - layer.SetTile(j, rawTile.TilesetTileID, rawTile.FlipVertically, rawTile.FlipHorizontally, rawTile.FlipDiagonally); - } - } - - return tilemap; - } - - private Dictionary ReadTilesets(ContentReader reader) - { - Dictionary tilesets = new(); - - int count = reader.ReadInt32(); - for (int i = 0; i < count; i++) - { - string name = reader.ReadString(); - int id = reader.ReadInt32(); - int tileWidth = reader.ReadInt32(); - int tileHeight = reader.ReadInt32(); - Texture2D texture = reader.ReadObject(); - Tileset tileset = new(name, texture, tileWidth, tileHeight); - tilesets.Add(id, tileset); - } - - return tilesets; - } -} diff --git a/source/MonoGame.Aseprite/Content/Pipeline/Readers/TilesetContentTypeReader.cs b/source/MonoGame.Aseprite/Content/Pipeline/Readers/TilesetContentTypeReader.cs deleted file mode 100644 index 50dd0695..00000000 --- a/source/MonoGame.Aseprite/Content/Pipeline/Readers/TilesetContentTypeReader.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Content; -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.Tilemaps; - -namespace MonoGame.Aseprite.Content.Pipeline.Readers; - -internal sealed class TilesetContentTypeReader : ContentTypeReader -{ - protected override Tileset Read(ContentReader reader, Tileset? existingInstance) - { - if (existingInstance is not null) - { - return existingInstance; - } - - string name = reader.ReadString(); - int tileWidth = reader.ReadInt32(); - int tileHeight = reader.ReadInt32(); - Texture2D texture = reader.ReadObject(); - return new(name, texture, tileWidth, tileHeight); - } -} diff --git a/source/MonoGame.Aseprite/Content/Processors/AnimatedTilemapProcessor.cs b/source/MonoGame.Aseprite/Content/Processors/AnimatedTilemapProcessor.cs deleted file mode 100644 index ffde632f..00000000 --- a/source/MonoGame.Aseprite/Content/Processors/AnimatedTilemapProcessor.cs +++ /dev/null @@ -1,70 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.RawTypes; -using MonoGame.Aseprite.Tilemaps; - -namespace MonoGame.Aseprite.Content.Processors; - -/// -/// Defines a processor that processes an from an . -/// -/// -public static partial class AnimatedTilemapProcessor -{ - /// - /// Processes an from the given . - /// - /// - /// When using this processor, all elements from the - /// are processed. elements - /// are ignored at this time (though may be implemented to support tags in the future). Only - /// elements in each frame are processed to - /// generate the tile data. - /// - /// - /// The used to create graphical resources. - /// - /// - /// The to processed the from. - /// - /// - /// Indicates if only layers that are visible should be processed. - /// - /// - /// The created by this method. - /// - /// - /// Thrown if layers are found in the with duplicate names. Tilemaps must contain - /// layers with unique names even though Aseprite does not enforce unique names for layers. - /// - /// - /// - public static AnimatedTilemap Process(GraphicsDevice device, AsepriteFile aseFile, bool onlyVisibleLayers = true) - { - RawAnimatedTilemap rawTilemap = ProcessRaw(aseFile, onlyVisibleLayers); - return AnimatedTilemap.FromRaw(device, rawTilemap); - } -} diff --git a/source/MonoGame.Aseprite/Content/Processors/SpriteProcessor.cs b/source/MonoGame.Aseprite/Content/Processors/SpriteProcessor.cs deleted file mode 100644 index 101a32c8..00000000 --- a/source/MonoGame.Aseprite/Content/Processors/SpriteProcessor.cs +++ /dev/null @@ -1,76 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.RawTypes; -using MonoGame.Aseprite.Sprites; - -namespace MonoGame.Aseprite.Content.Processors; - -/// -/// Defines a processor that processes a from an frame in an -/// -/// -public static partial class SpriteProcessor -{ - /// - /// Processes a from the at the specified index in the given - /// - /// - /// - /// The used to create graphical resources. - /// - /// - /// The that contains the to processes. - /// - /// - /// The index of the in the to process. - /// - /// - /// Indicates if only elements on visible elements should - /// be included. - /// - /// - /// Indicates if on the marked as the background layer - /// should be included. - /// - /// - /// Indicates if on a should be included. - /// - /// - /// The created by this method. - /// - /// - /// Thrown if the specified frame index is less than zero or is greater than or equal to the total number - /// elements in the given . - /// - /// - /// - public static Sprite Process(GraphicsDevice device, AsepriteFile aseFile, int aseFrameIndex, bool onlyVisibleLayers = true, bool includeBackgroundLayer = false, bool includeTilemapLayers = true) - { - RawSprite rawSprite = ProcessRaw(aseFile, aseFrameIndex, onlyVisibleLayers, includeBackgroundLayer, includeTilemapLayers); - return Sprite.FromRaw(device, rawSprite); - } -} diff --git a/source/MonoGame.Aseprite/Content/Processors/SpriteSheetProcessor.cs b/source/MonoGame.Aseprite/Content/Processors/SpriteSheetProcessor.cs deleted file mode 100644 index 1ff1d55a..00000000 --- a/source/MonoGame.Aseprite/Content/Processors/SpriteSheetProcessor.cs +++ /dev/null @@ -1,86 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.RawTypes; -using MonoGame.Aseprite.Sprites; - -namespace MonoGame.Aseprite.Content.Processors; - -/// -/// Defines a processor that processes a from an . -/// -/// -public static partial class SpriteSheetProcessor -{ - /// - /// Processes a from the given . - /// - /// - /// The used to create graphical resources. - /// - /// - /// The to process the from. - /// - /// - /// Indicates if only elements on visible elements should - /// be included. - /// - /// - /// Indicates if elements on the elements marked as the - /// background layer should be included. - /// - /// - /// Indicates if elements on a element should be - /// included. - /// - /// Indicates if duplicate elements should be merged into one. - /// - /// - /// The amount of transparent pixels to add between the edge of the generated image - /// - /// - /// The amount of transparent pixels to add between each texture region in the generated image. - /// - /// - /// The amount of transparent pixels to add around the edge of each texture region in the generated image. - /// - /// - /// The created by this method. - /// - /// - /// Thrown if elements are found in the with duplicate - /// names. A must contain tags with unique names even though aseprite does not - /// enforce unique names for elements. - /// - /// - /// - public static SpriteSheet Process(GraphicsDevice device, AsepriteFile aseFile, bool onlyVisibleLayers = true, bool includeBackgroundLayer = false, bool includeTilemapLayers = true, bool mergeDuplicates = true, int borderPadding = 0, int spacing = 0, int innerPadding = 0) - { - RawSpriteSheet rawSpritSheet = ProcessRaw(aseFile, onlyVisibleLayers, includeBackgroundLayer, includeTilemapLayers, mergeDuplicates, borderPadding, spacing, innerPadding); - return SpriteSheet.FromRaw(device, rawSpritSheet); - } -} - diff --git a/source/MonoGame.Aseprite/Content/Processors/TextureAtlasProcessor.cs b/source/MonoGame.Aseprite/Content/Processors/TextureAtlasProcessor.cs deleted file mode 100644 index eeb3c1d8..00000000 --- a/source/MonoGame.Aseprite/Content/Processors/TextureAtlasProcessor.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.RawTypes; -using MonoGame.Aseprite.Sprites; - -namespace MonoGame.Aseprite.Content.Processors; - -/// -/// Defines a processor that processes a from an aseprite file. -/// -/// -public static partial class TextureAtlasProcessor -{ - /// - /// Processes a from the given . - /// - /// - /// The used to create graphical resources. - /// - /// - /// The to process the from. - /// - /// - /// Indicates if only elements on visible elements should - /// be included. - /// - /// - /// Indicates if elements on the elements marked as the - /// background layer should be included. - /// - /// - /// Indicates if elements on a element should be - /// included. - /// - /// Indicates if duplicate elements should be merged into one. - /// - /// - /// The amount of transparent pixels to add between the edge of the generated image - /// - /// - /// The amount of transparent pixels to add between each texture region in the generated image. - /// - /// - /// The amount of transparent pixels to add around the edge of each texture region in the generated image. - /// - /// - /// The created by this method. - /// - /// - /// - public static Sprites.TextureAtlas Process(GraphicsDevice device, AsepriteFile aseFile, bool onlyVisibleLayers = true, bool includeBackgroundLayer = false, bool includeTilemapLayers = true, bool mergeDuplicates = true, int borderPadding = 0, int spacing = 0, int innerPadding = 0) - { - RawTextureAtlas rawAtlas = ProcessRaw(aseFile, onlyVisibleLayers, includeBackgroundLayer, includeTilemapLayers, mergeDuplicates, borderPadding, spacing, innerPadding); - return TextureAtlas.FromRaw(device, rawAtlas); - } -} diff --git a/source/MonoGame.Aseprite/Content/Processors/TilemapProcessor.cs b/source/MonoGame.Aseprite/Content/Processors/TilemapProcessor.cs deleted file mode 100644 index ed242090..00000000 --- a/source/MonoGame.Aseprite/Content/Processors/TilemapProcessor.cs +++ /dev/null @@ -1,73 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.RawTypes; -using MonoGame.Aseprite.Tilemaps; - -namespace MonoGame.Aseprite.Content.Processors; - -/// -/// Defines a processor that processes a from an . -/// -/// -public static partial class TilemapProcessor -{ - /// - /// Processes a from the at the specified index in the given - /// . - /// - /// - /// The used to create graphical resources. - /// - /// - /// The that contains the animated to process. - /// - /// - /// The index of the element in the to process. - /// - /// - /// Indicates if only elements that are visible should be processed. - /// - /// - /// The created by this method. - /// - /// - /// Thrown if the frame index specified is less than zero or is greater than or equal to the total number of - /// elements in the given . - /// - /// - /// Thrown if elements are found in the with duplicate - /// names. A must contain layers with unique names even though aseprite does not enforce - /// unique names for elements. - /// - /// - /// - public static Tilemap Process(GraphicsDevice device, AsepriteFile aseFile, int frameIndex, bool onlyVisibleLayers = true) - { - RawTilemap rawTilemap = ProcessRaw(aseFile, frameIndex, onlyVisibleLayers); - return Tilemap.FromRaw(device, rawTilemap); - } -} diff --git a/source/MonoGame.Aseprite/Content/Processors/TilesetProcessor.cs b/source/MonoGame.Aseprite/Content/Processors/TilesetProcessor.cs deleted file mode 100644 index 9a54790c..00000000 --- a/source/MonoGame.Aseprite/Content/Processors/TilesetProcessor.cs +++ /dev/null @@ -1,114 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.RawTypes; -using MonoGame.Aseprite.Tilemaps; - -namespace MonoGame.Aseprite.Content.Processors; - -/// -/// Defines a processor that processes a from an . -/// -/// -public static partial class TilesetProcessor -{ - /// - /// Processes a from the element at the specified index in the - /// given . - /// - /// - /// The used to create graphical resources. - /// - /// - /// The that contains the to processes. - /// - /// - /// The index of the element in the to processes. - /// - /// - /// The created by this method. - /// - /// - /// Thrown if the index specified is less than zero or is greater than or equal to the total number of - /// elements in the given . - /// - /// - /// - public static Tileset Process(GraphicsDevice device, AsepriteFile aseFile, int tilesetIndex) - { - AsepriteTileset aseTileset = aseFile.GetTileset(tilesetIndex); - return Process(device, aseTileset); - } - - /// - /// Processes a from the with the specified name in the - /// given . - /// - /// - /// The used to create graphical resources. - /// - /// - /// The that contains the to process. - /// - /// - /// The name of the element in the to process. - /// - /// - /// The created by this method. - /// - /// - /// Thrown if the given does not contain an element - /// with the specified name. - /// - /// - /// - public static Tileset Process(GraphicsDevice device, AsepriteFile aseFile, string tilesetName) - { - AsepriteTileset aseTileset = aseFile.GetTileset(tilesetName); - return Process(device, aseTileset); - } - - /// - /// Processes a from an . - /// - /// - /// The used to create graphical resources. - /// - /// - /// The to process. - /// - /// - /// The created by this method. - /// - /// - /// - /// - public static Tileset Process(GraphicsDevice device, AsepriteTileset aseTileset) - { - RawTileset rawTileset = ProcessRaw(aseTileset); - return Tileset.FromRaw(device, rawTileset); - } -} diff --git a/source/MonoGame.Aseprite/MonoGame.Aseprite.csproj b/source/MonoGame.Aseprite/MonoGame.Aseprite.csproj index c5f28c21..c350ac13 100644 --- a/source/MonoGame.Aseprite/MonoGame.Aseprite.csproj +++ b/source/MonoGame.Aseprite/MonoGame.Aseprite.csproj @@ -25,7 +25,7 @@ - + diff --git a/source/MonoGame.Aseprite/Sprites/Sprite.cs b/source/MonoGame.Aseprite/Sprite.cs similarity index 76% rename from source/MonoGame.Aseprite/Sprites/Sprite.cs rename to source/MonoGame.Aseprite/Sprite.cs index 09a8176c..05f2993e 100644 --- a/source/MonoGame.Aseprite/Sprites/Sprite.cs +++ b/source/MonoGame.Aseprite/Sprite.cs @@ -1,343 +1,311 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.Utils; - -namespace MonoGame.Aseprite.Sprites; - -/// -/// -/// Defines a named sprite -/// -/// -/// The class is a general purpose wrapper around a -/// with properties to control how it is rendered. When creating -/// a from an , it represents the image of the frame used to -/// create it. -/// -/// -/// The most common methods for creating a will be either by using the -/// to create an instance from a frame in -/// your Aseprite File, or by using a to create a from one of -/// the regions in the atlas. An instance can also be created manually using the constructor for a more general -/// purpose use. -/// -/// -/// -/// -/// The , , , -/// , and are passed automatically to the -/// when rendering this sprite. For one-off rendering -/// where you can override the parameter values passed to the -/// , you can render the -/// instead. -/// -/// -/// ### Performance Considerations -/// -/// -/// If you plan to create multiple instances from various frames in your Aseprite file, -/// consider first creating a , then creating each instance -/// using the . By doing this, you will be generating a single source -/// for the . Each -/// that is then created from the will be references the single -/// source instead of separate instances per -/// . -/// -/// -/// This is beneficial because it reduces the amount of texture swapping done on the -/// when rendering the -/// instances. -/// -/// -/// -/// -/// The following examples demonstrate various ways to create a : -/// -/// -/// // Load an Aseprite file -/// AsepriteFile aseFile = AsepriteFile.Load("path-to-file"); -/// -/// // Use the SpriteProcessor to create a Sprite -/// Sprite sprite = SpriteProcessor.Process(GraphicsDevice, aseFile, frameIndex: 0); -/// -/// -/// -/// // Load an Aseprite File -/// AsepriteFile aseFile = AsepriteFile.Load("path-to-file") -/// -/// // Create a TextureAtlas from the AsepriteFile using the TextureAtlasProcessor -/// TextureAtlas atlas = TextureAtlasProcessor.Process(GraphicsDevice, aseFile); -/// -/// // Create a Sprite from region 0 in the TextureAtlas -/// Sprite sprite = atlas.CreateSprite(regionIndex: 0); -/// -/// -/// -/// // Load an Aseprite File -/// AsepriteFile aseFile = AsepriteFile.Load("path-to-file") -/// -/// // Create a SpriteSheet from the AsepriteFile using the SpriteSheetProcessor -/// SpriteSheet spriteSheet = SpriteSheetProcessor.Process(GraphicsDevice, aseFile); -/// -/// // Create a Sprite from region 0 in the SpriteSheet -/// Sprite sprite = spriteSheet.CreateSprite(regionIndex: 0); -/// -/// -/// -/// -/// -/// -/// -/// -public class Sprite -{ - private TextureRegion _textureRegion; - - private Vector2 _origin; - private Vector2 _scale; - private float _transparency; - - /// - /// Gets the name assigned to this . - /// - public string Name { get; } - - /// - /// Gets the source of this . - /// - public TextureRegion TextureRegion - { - get => _textureRegion; - protected set => _textureRegion = value; - } - - /// - /// Gets the width, in pixels, of this - /// - /// - /// The width, in pixels, of this . - /// - public int Width => _textureRegion.Bounds.Width; - - /// - /// Gets the height, in pixels, of this - /// - /// - /// The height, in pixels, of this . - /// - public int Height => _textureRegion.Bounds.Height; - - /// - /// Gets or Sets the color mask to apply when rendering this . - /// - /// - /// The color mask to apply when rendering this . - /// - public Color Color { get; set; } - - /// - /// Gets or Sets the level of transparency, between 0.0f, and 1.0f, to apply when rendering this - /// . - /// - public float Transparency - { - get => _transparency; - set => _transparency = MathHelper.Clamp(value, 0.0f, 1.0f); - } - - /// - /// Gets or Sets the rotation, in radians, to apply when rendering this . - /// - public float Rotation { get; set; } - - /// - /// Gets or Sets the x- and y-coordinate point of origin to apply when rendering this . - /// - public Vector2 Origin - { - get => _origin; - set => _origin = value; - } - - /// - /// Gets or Sets the x-coordinate point of origin to apply when rendering this . - /// - public float OriginX - { - get => _origin.X; - set => _origin.X = value; - } - - /// - /// Gets or Sets the y-coordinate point of origin to apply when rendering this . - /// - public float OriginY - { - get => _origin.Y; - set => _origin.Y = value; - } - - /// - /// Gets or Sets the x- and y-axis scale factor to use when rendering this . - /// - public Vector2 Scale - { - get => _scale; - set => _scale = value; - } - - /// - /// Gets or Sets the x-axis scale factor to use when rendering this . - /// - public float ScaleX - { - get => _scale.X; - set => _scale.X = value; - } - - /// - /// Gets or Sets the y-axis scale factor to use when rendering this . - /// - public float ScaleY - { - get => _scale.Y; - set => _scale.Y = value; - } - - /// - /// Gets or Sets the to apply for vertical and - /// horizontal flipping when rendering this . - /// - public SpriteEffects SpriteEffects { get; set; } - - /// - /// Gets or Sets a value that indicates whether to flip this horizontally when rendering. - /// - public bool FlipHorizontally - { - get => SpriteEffects.HasFlag(SpriteEffects.FlipHorizontally); - set => SpriteEffects = value ? (SpriteEffects | SpriteEffects.FlipHorizontally) : (SpriteEffects & ~SpriteEffects.FlipHorizontally); - } - - /// - /// Gets or Sets a value that indicates whether to flip this vertically when rendering. - /// - public bool FlipVertically - { - get => SpriteEffects.HasFlag(SpriteEffects.FlipVertically); - set => SpriteEffects = value ? (SpriteEffects | SpriteEffects.FlipVertically) : (SpriteEffects & ~SpriteEffects.FlipVertically); - } - - /// - /// Gets or Sets the layer depth to render this at. - /// - public float LayerDepth { get; set; } - - /// - /// Gets or Sets a value that indicates if this is visible and can be rendered. - /// - public bool IsVisible { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The name to assign the . - /// - /// - /// The source to assign the . - /// - public Sprite(string name, TextureRegion textureRegion) - { - _textureRegion = textureRegion; - Color = Color.White; - _transparency = 1.0f; - Rotation = 0.0f; - _origin = Vector2.Zero; - _scale = Vector2.One; - SpriteEffects = SpriteEffects.None; - LayerDepth = 0.0f; - IsVisible = true; - Name = name; - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The name to assign the . - /// - /// - /// The source image for the . - /// - public Sprite(string name, Texture2D texture) - : this(name, new TextureRegion(name, texture, texture.Bounds)) { } - - /// - /// Renders this . - /// - /// - /// The to use for rendering this - /// . - /// - /// - /// The x- and y-coordinate location to render this at. - /// - public void Draw(SpriteBatch spriteBatch, Vector2 position) => spriteBatch.Draw(this, position); - - public static Sprite FromFile(GraphicsDevice device, AseFile file, int frameNumber, AseProcessorOptions options) - { - options ??= AseProcessorOptions.Default; - AseSprite aseSprite = AseSpriteProcessor.Process(file, frameNumber, options); - Texture2D texture = aseSprite.Texture.ToTexture2D(device); - texture.Name = aseSprite.Name; - texture.SetData(aseSprite.Texture.Pixels.ToArray()); - - TextureRegion textureRegion = new TextureRegion(texture.Name, texture, texture.Bounds); - for(int i = 0; i < aseSprite.Slices.Length; i++) - { - AseSlice aseSlice = aseSprite.Slices[i]; - if (aseSlice is AseNinepatchSlice aseNinePatchSlice) - { - textureRegion.CreateNinePatchSlice(aseNinePatchSlice.Name, - aseNinePatchSlice.Bounds.ToXnaRectangle(), - aseNinePatchSlice.CenterBounds.ToXnaRectangle(), - aseNinePatchSlice.Origin.ToXnaVector2(), - aseNinePatchSlice.Color.ToXnaColor()); - } - else - { - textureRegion.CreateSlice(aseSlice.Name, - aseSlice.Bounds.ToXnaRectangle(), - aseSlice.Origin.ToXnaVector2(), - aseSlice.Color.ToXnaColor()); - } - } - - return new Sprite(aseSprite.Name, textureRegion); - } -} +/* ---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2018-2023 Christopher Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------------------------------------------------- */ + +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using MonoGame.Aseprite.Utils; + +namespace MonoGame.Aseprite; + +/// +/// +/// Defines a named sprite +/// +/// +/// The class is a general purpose wrapper around a +/// with properties to control how it is rendered. When creating +/// a from an , it represents the image of the frame used to +/// create it. +/// +/// +/// The most common methods for creating a will be either by using the +/// to create an instance from a frame in +/// your Aseprite File, or by using a to create a from one of +/// the regions in the atlas. An instance can also be created manually using the constructor for a more general +/// purpose use. +/// +/// +/// +/// +/// The , , , +/// , and are passed automatically to the +/// when rendering this sprite. For one-off rendering +/// where you can override the parameter values passed to the +/// , you can render the +/// instead. +/// +/// +/// ### Performance Considerations +/// +/// +/// If you plan to create multiple instances from various frames in your Aseprite file, +/// consider first creating a , then creating each instance +/// using the . By doing this, you will be generating a single source +/// for the . Each +/// that is then created from the will be references the single +/// source instead of separate instances per +/// . +/// +/// +/// This is beneficial because it reduces the amount of texture swapping done on the +/// when rendering the +/// instances. +/// +/// +/// +/// +/// The following examples demonstrate various ways to create a : +/// +/// +/// // Load an Aseprite file +/// AsepriteFile aseFile = AsepriteFile.Load("path-to-file"); +/// +/// // Use the SpriteProcessor to create a Sprite +/// Sprite sprite = SpriteProcessor.Process(GraphicsDevice, aseFile, frameIndex: 0); +/// +/// +/// +/// // Load an Aseprite File +/// AsepriteFile aseFile = AsepriteFile.Load("path-to-file") +/// +/// // Create a TextureAtlas from the AsepriteFile using the TextureAtlasProcessor +/// TextureAtlas atlas = TextureAtlasProcessor.Process(GraphicsDevice, aseFile); +/// +/// // Create a Sprite from region 0 in the TextureAtlas +/// Sprite sprite = atlas.CreateSprite(regionIndex: 0); +/// +/// +/// +/// // Load an Aseprite File +/// AsepriteFile aseFile = AsepriteFile.Load("path-to-file") +/// +/// // Create a SpriteSheet from the AsepriteFile using the SpriteSheetProcessor +/// SpriteSheet spriteSheet = SpriteSheetProcessor.Process(GraphicsDevice, aseFile); +/// +/// // Create a Sprite from region 0 in the SpriteSheet +/// Sprite sprite = spriteSheet.CreateSprite(regionIndex: 0); +/// +/// +/// +/// +/// +/// +/// +/// +public class Sprite +{ + private TextureRegion _textureRegion; + + private Vector2 _origin; + private Vector2 _scale; + private float _transparency; + + /// + /// Gets the name assigned to this . + /// + public string Name { get; } + + /// + /// Gets the source of this . + /// + public TextureRegion TextureRegion + { + get => _textureRegion; + protected set => _textureRegion = value; + } + + /// + /// Gets the width, in pixels, of this + /// + /// + /// The width, in pixels, of this . + /// + public int Width => _textureRegion.Bounds.Width; + + /// + /// Gets the height, in pixels, of this + /// + /// + /// The height, in pixels, of this . + /// + public int Height => _textureRegion.Bounds.Height; + + /// + /// Gets or Sets the color mask to apply when rendering this . + /// + /// + /// The color mask to apply when rendering this . + /// + public Color Color { get; set; } + + /// + /// Gets or Sets the level of transparency, between 0.0f, and 1.0f, to apply when rendering this + /// . + /// + public float Transparency + { + get => _transparency; + set => _transparency = MathHelper.Clamp(value, 0.0f, 1.0f); + } + + /// + /// Gets or Sets the rotation, in radians, to apply when rendering this . + /// + public float Rotation { get; set; } + + /// + /// Gets or Sets the x- and y-coordinate point of origin to apply when rendering this . + /// + public Vector2 Origin + { + get => _origin; + set => _origin = value; + } + + /// + /// Gets or Sets the x-coordinate point of origin to apply when rendering this . + /// + public float OriginX + { + get => _origin.X; + set => _origin.X = value; + } + + /// + /// Gets or Sets the y-coordinate point of origin to apply when rendering this . + /// + public float OriginY + { + get => _origin.Y; + set => _origin.Y = value; + } + + /// + /// Gets or Sets the x- and y-axis scale factor to use when rendering this . + /// + public Vector2 Scale + { + get => _scale; + set => _scale = value; + } + + /// + /// Gets or Sets the x-axis scale factor to use when rendering this . + /// + public float ScaleX + { + get => _scale.X; + set => _scale.X = value; + } + + /// + /// Gets or Sets the y-axis scale factor to use when rendering this . + /// + public float ScaleY + { + get => _scale.Y; + set => _scale.Y = value; + } + + /// + /// Gets or Sets the to apply for vertical and + /// horizontal flipping when rendering this . + /// + public SpriteEffects SpriteEffects { get; set; } + + /// + /// Gets or Sets a value that indicates whether to flip this horizontally when rendering. + /// + public bool FlipHorizontally + { + get => SpriteEffects.HasFlag(SpriteEffects.FlipHorizontally); + set => SpriteEffects = value ? SpriteEffects | SpriteEffects.FlipHorizontally : SpriteEffects & ~SpriteEffects.FlipHorizontally; + } + + /// + /// Gets or Sets a value that indicates whether to flip this vertically when rendering. + /// + public bool FlipVertically + { + get => SpriteEffects.HasFlag(SpriteEffects.FlipVertically); + set => SpriteEffects = value ? SpriteEffects | SpriteEffects.FlipVertically : SpriteEffects & ~SpriteEffects.FlipVertically; + } + + /// + /// Gets or Sets the layer depth to render this at. + /// + public float LayerDepth { get; set; } + + /// + /// Gets or Sets a value that indicates if this is visible and can be rendered. + /// + public bool IsVisible { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The name to assign the . + /// + /// + /// The source to assign the . + /// + public Sprite(string name, TextureRegion textureRegion) + { + _textureRegion = textureRegion; + Color = Color.White; + _transparency = 1.0f; + Rotation = 0.0f; + _origin = Vector2.Zero; + _scale = Vector2.One; + SpriteEffects = SpriteEffects.None; + LayerDepth = 0.0f; + IsVisible = true; + Name = name; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The name to assign the . + /// + /// + /// The source image for the . + /// + public Sprite(string name, Texture2D texture) + : this(name, new TextureRegion(name, texture, texture.Bounds)) { } + + /// + /// Renders this . + /// + /// + /// The to use for rendering this + /// . + /// + /// + /// The x- and y-coordinate location to render this at. + /// + public void Draw(SpriteBatch spriteBatch, Vector2 position) => spriteBatch.Draw(this, position); +} diff --git a/source/MonoGame.Aseprite/SpriteBatchExtensions.cs b/source/MonoGame.Aseprite/SpriteBatchExtensions.cs index c44c2db7..9e8d0bfd 100644 --- a/source/MonoGame.Aseprite/SpriteBatchExtensions.cs +++ b/source/MonoGame.Aseprite/SpriteBatchExtensions.cs @@ -24,8 +24,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.Sprites; -using MonoGame.Aseprite.Tilemaps; namespace MonoGame.Aseprite; diff --git a/source/MonoGame.Aseprite/Sprites/SpriteSheet.cs b/source/MonoGame.Aseprite/SpriteSheet.cs similarity index 81% rename from source/MonoGame.Aseprite/Sprites/SpriteSheet.cs rename to source/MonoGame.Aseprite/SpriteSheet.cs index 599ec799..b5e504ad 100644 --- a/source/MonoGame.Aseprite/Sprites/SpriteSheet.cs +++ b/source/MonoGame.Aseprite/SpriteSheet.cs @@ -1,357 +1,299 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.Diagnostics.CodeAnalysis; -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.Utils; - -namespace MonoGame.Aseprite.Sprites; - -/// -/// Defines a spritesheet with a source and methods for creating -/// and elements. -/// -public sealed class SpriteSheet -{ - private static readonly TimeSpan s_defaultDuration = TimeSpan.FromMilliseconds(100); - - private Dictionary _animationTagLookup = new(); - - /// - /// Gets the total number of elements that have been defined for this - /// . - /// - public int AnimationTagCount => _animationTagLookup.Count; - - /// - /// Gets the name assigned to this . - /// - public string Name { get; } - - /// - /// Gets the source of this . - /// - public TextureAtlas TextureAtlas { get; } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The name assign the . - /// - /// - /// The source to give the . - /// - public SpriteSheet(string name, TextureAtlas atlas) => (Name, TextureAtlas) = (name, atlas); - - /// - /// Creates a new from the at the specified index in the - /// of this . - /// - /// - /// The name to assign the that is created. - /// - /// - /// The index of the element in the assign the - /// that is created. - /// - /// - /// The that is created by this method. - /// - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of - /// elements in the . - /// - public Sprite CreateSprite(string spriteName, int regionIndex) - { - TextureRegion region = TextureAtlas.GetRegion(regionIndex); - Sprite sprite = new(spriteName, region); - return sprite; - } - - /// - /// Creates a new from the at the specified index in the - /// of this . - /// - /// - /// The index of the element to assign the that is created. - /// - /// The that is created by this method. - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of - /// elements in the . - /// - public Sprite CreateSprite(int regionIndex) - { - TextureRegion region = TextureAtlas.GetRegion(regionIndex); - Sprite sprite = new(region.Name, region); - return sprite; - } - - /// - /// Creates a new from the at the specified index in the - /// of this . - /// - /// - /// The name to assign the that is created. - /// - /// - /// The name of the element in the assign the - /// that is created. - /// - /// - /// The that is created by this method. - /// - /// - /// Thrown if the does not contain a with the name - /// specified. - /// - public Sprite CreateSprite(string spriteName, string regionName) - { - TextureRegion region = TextureAtlas.GetRegion(regionName); - Sprite sprite = new(spriteName, region); - return sprite; - } - - /// - /// Creates a new from the at the specified index in the - /// of this . - /// - /// - /// The name of the element in the assign the - /// that is created. - /// - /// The that is created by this method. - /// - /// Thrown if the does not contain a with the name - /// specified. - /// - public Sprite CreateSprite(string regionName) - { - TextureRegion region = TextureAtlas.GetRegion(regionName); - Sprite sprite = new(region.Name, region); - return sprite; - } - - #region Animations - - internal void AddAnimationTag(AnimationTag tag) - { - if (_animationTagLookup.ContainsKey(tag.Name)) - { - throw new InvalidOperationException($"{nameof(SpriteSheet)} '{Name}' already contains an {nameof(AnimationTag)} with the name '{tag.Name}'"); - } - - _animationTagLookup.Add(tag.Name, tag); - } - - /// - /// Creates a new and adds it to this . - /// - /// - /// The name to assign the that is created by this method. This name must be unique - /// across all elements defined in this . - /// - /// - /// An method used to build the with an - /// . - /// - /// - /// The that is created by this method. - /// - /// - /// Thrown if this already contains an element with the - /// name specified. - /// - public AnimationTag CreateAnimationTag(string name, Action builder) - { - AnimationTagBuilder localBuilder = new(name, this); - builder(localBuilder); - - AnimationTag tag = localBuilder.Build(); - AddAnimationTag(tag); - - return tag; - } - - /// - /// Gets the element with the specified name in this . - /// - /// - /// The name of the to locate. - /// - /// - /// The that was located. - /// - /// - /// Thrown if this does not contain an element with the - /// specified name. - /// - public AnimationTag GetAnimationTag(string name) - { - if (TryGetAnimationTag(name, out AnimationTag? tag)) - { - return tag; - } - - throw new KeyNotFoundException($"{nameof(SpriteSheet)} '{Name}' does not contain an {nameof(AnimationTag)} with the name '{name}'"); - } - - /// - /// Gets the element with the specified name in this . - /// - /// - /// The name of the to locate. - /// - /// - /// When this method returns , contains the located; otherwise, - /// - /// - /// - /// if the was located; otherwise, . - /// This method returns if this does not contain an - /// element with the specified name. - /// - public bool TryGetAnimationTag(string name, [NotNullWhen(true)] out AnimationTag? tag) => - _animationTagLookup.TryGetValue(name, out tag); - - /// - /// Returns a new containing the name of all elements that - /// have been defined in this . - /// - /// - /// A new containing the name of all elements that have been - /// defined in this . - /// - public List GetAnimationTagNames() => _animationTagLookup.Keys.ToList(); - - /// - /// Returns a value that indicates whether this contains an - /// with the specified name. - /// - /// - /// The name fo the element to locate. - /// - /// - /// if this contains an with the - /// specified name; otherwise, . - /// - public bool ContainsAnimationTag(string name) => _animationTagLookup.ContainsKey(name); - - /// - /// Removes the element with the specified name from this . - /// - /// - /// The name of the element to remove from this . - /// - /// - /// if the element was successfully removed from this - /// ; otherwise, . This method returns - /// if this does not contain an element with the specified - /// name. - /// - public bool RemoveAnimationTag(string name) => _animationTagLookup.Remove(name); - - /// - /// Creates a new using the element with the specified - /// name in this . - /// - /// - /// The name of the element in this to create the - /// with. - /// - /// - /// The that is created by this method. - /// - /// - /// Thrown if this does not contain an element with the - /// specified name. - /// - public AnimatedSprite CreateAnimatedSprite(string tagName) - { - AnimationTag tag = GetAnimationTag(tagName); - AnimatedSprite sprite = new(tag); - return sprite; - } - - #endregion Animations - - public static SpriteSheet FromFile(GraphicsDevice device, AseFile file, AseProcessorOptions options) - { - options ??= AseProcessorOptions.Default; - AseSpriteSheet aseSpriteSheet = AseSpriteSheetProcessor.Process(file, options); - Texture2D texture = aseSpriteSheet.TextureAtlas.Texture.ToTexture2D(device); - TextureAtlas atlas = new TextureAtlas(texture.Name, texture); - - for (int i = 0; i < aseSpriteSheet.TextureAtlas.Regions.Length; i++) - { - AseTextureRegion aseTextureRegion = aseSpriteSheet.TextureAtlas.Regions[i]; - TextureRegion textureRegion = atlas.CreateRegion(aseTextureRegion.Name, aseTextureRegion.Bounds.ToXnaRectangle()); - - for (int s = 0; s < aseTextureRegion.Slices.Length; s++) - { - AseSlice aseSlice = aseTextureRegion.Slices[i]; - - if (aseSlice is AseNinepatchSlice aseNinePatchSlice) - { - textureRegion.CreateNinePatchSlice(aseNinePatchSlice.Name, - aseNinePatchSlice.Bounds.ToXnaRectangle(), - aseNinePatchSlice.CenterBounds.ToXnaRectangle(), - aseNinePatchSlice.Origin.ToXnaVector2(), - aseNinePatchSlice.Color.ToXnaColor()); - } - else - { - textureRegion.CreateSlice(aseSlice.Name, - aseSlice.Bounds.ToXnaRectangle(), - aseSlice.Origin.ToXnaVector2(), - aseSlice.Color.ToXnaColor()); - } - } - } - - SpriteSheet spriteSheet = new SpriteSheet(atlas.Name, atlas); - - - for (int i = 0; i < aseSpriteSheet.Tags.Length; i++) - { - AseTag aseTag = aseSpriteSheet.Tags[i]; - - spriteSheet.CreateAnimationTag(aseTag.Name, builder => - { - builder.LoopCount(aseTag.LoopCount) - .IsReversed(aseTag.IsReversed) - .IsPingPong(aseTag.IsPingPong); - - for (int j = 0; j < aseTag.Frames.Length; j++) - { - AseAnimationFrame aseAnimationFrame = aseTag.Frames[j]; - builder.AddFrame(aseAnimationFrame.FrameIndex, aseAnimationFrame.Duration); - } - }); - } - - return spriteSheet; - } -} +/* ---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2018-2023 Christopher Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------------------------------------------------- */ + +using System.Diagnostics.CodeAnalysis; +using Microsoft.Xna.Framework.Graphics; +using MonoGame.Aseprite.Utils; + +namespace MonoGame.Aseprite; + +/// +/// Defines a spritesheet with a source and methods for creating +/// and elements. +/// +public sealed class SpriteSheet +{ + private static readonly TimeSpan s_defaultDuration = TimeSpan.FromMilliseconds(100); + + private Dictionary _animationTagLookup = new(); + + /// + /// Gets the total number of elements that have been defined for this + /// . + /// + public int AnimationTagCount => _animationTagLookup.Count; + + /// + /// Gets the name assigned to this . + /// + public string Name { get; } + + /// + /// Gets the source of this . + /// + public TextureAtlas TextureAtlas { get; } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The name assign the . + /// + /// + /// The source to give the . + /// + public SpriteSheet(string name, TextureAtlas atlas) => (Name, TextureAtlas) = (name, atlas); + + /// + /// Creates a new from the at the specified index in the + /// of this . + /// + /// + /// The name to assign the that is created. + /// + /// + /// The index of the element in the assign the + /// that is created. + /// + /// + /// The that is created by this method. + /// + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of + /// elements in the . + /// + public Sprite CreateSprite(string spriteName, int regionIndex) + { + TextureRegion region = TextureAtlas.GetRegion(regionIndex); + Sprite sprite = new(spriteName, region); + return sprite; + } + + /// + /// Creates a new from the at the specified index in the + /// of this . + /// + /// + /// The index of the element to assign the that is created. + /// + /// The that is created by this method. + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of + /// elements in the . + /// + public Sprite CreateSprite(int regionIndex) + { + TextureRegion region = TextureAtlas.GetRegion(regionIndex); + Sprite sprite = new(region.Name, region); + return sprite; + } + + /// + /// Creates a new from the at the specified index in the + /// of this . + /// + /// + /// The name to assign the that is created. + /// + /// + /// The name of the element in the assign the + /// that is created. + /// + /// + /// The that is created by this method. + /// + /// + /// Thrown if the does not contain a with the name + /// specified. + /// + public Sprite CreateSprite(string spriteName, string regionName) + { + TextureRegion region = TextureAtlas.GetRegion(regionName); + Sprite sprite = new(spriteName, region); + return sprite; + } + + /// + /// Creates a new from the at the specified index in the + /// of this . + /// + /// + /// The name of the element in the assign the + /// that is created. + /// + /// The that is created by this method. + /// + /// Thrown if the does not contain a with the name + /// specified. + /// + public Sprite CreateSprite(string regionName) + { + TextureRegion region = TextureAtlas.GetRegion(regionName); + Sprite sprite = new(region.Name, region); + return sprite; + } + + #region Animations + + internal void AddAnimationTag(AnimationTag tag) + { + if (_animationTagLookup.ContainsKey(tag.Name)) + { + throw new InvalidOperationException($"{nameof(SpriteSheet)} '{Name}' already contains an {nameof(AnimationTag)} with the name '{tag.Name}'"); + } + + _animationTagLookup.Add(tag.Name, tag); + } + + /// + /// Creates a new and adds it to this . + /// + /// + /// The name to assign the that is created by this method. This name must be unique + /// across all elements defined in this . + /// + /// + /// An method used to build the with an + /// . + /// + /// + /// The that is created by this method. + /// + /// + /// Thrown if this already contains an element with the + /// name specified. + /// + public AnimationTag CreateAnimationTag(string name, Action builder) + { + AnimationTagBuilder localBuilder = new(name, this); + builder(localBuilder); + + AnimationTag tag = localBuilder.Build(); + AddAnimationTag(tag); + + return tag; + } + + /// + /// Gets the element with the specified name in this . + /// + /// + /// The name of the to locate. + /// + /// + /// The that was located. + /// + /// + /// Thrown if this does not contain an element with the + /// specified name. + /// + public AnimationTag GetAnimationTag(string name) + { + if (TryGetAnimationTag(name, out AnimationTag? tag)) + { + return tag; + } + + throw new KeyNotFoundException($"{nameof(SpriteSheet)} '{Name}' does not contain an {nameof(AnimationTag)} with the name '{name}'"); + } + + /// + /// Gets the element with the specified name in this . + /// + /// + /// The name of the to locate. + /// + /// + /// When this method returns , contains the located; otherwise, + /// + /// + /// + /// if the was located; otherwise, . + /// This method returns if this does not contain an + /// element with the specified name. + /// + public bool TryGetAnimationTag(string name, [NotNullWhen(true)] out AnimationTag? tag) => + _animationTagLookup.TryGetValue(name, out tag); + + /// + /// Returns a new containing the name of all elements that + /// have been defined in this . + /// + /// + /// A new containing the name of all elements that have been + /// defined in this . + /// + public List GetAnimationTagNames() => _animationTagLookup.Keys.ToList(); + + /// + /// Returns a value that indicates whether this contains an + /// with the specified name. + /// + /// + /// The name fo the element to locate. + /// + /// + /// if this contains an with the + /// specified name; otherwise, . + /// + public bool ContainsAnimationTag(string name) => _animationTagLookup.ContainsKey(name); + + /// + /// Removes the element with the specified name from this . + /// + /// + /// The name of the element to remove from this . + /// + /// + /// if the element was successfully removed from this + /// ; otherwise, . This method returns + /// if this does not contain an element with the specified + /// name. + /// + public bool RemoveAnimationTag(string name) => _animationTagLookup.Remove(name); + + /// + /// Creates a new using the element with the specified + /// name in this . + /// + /// + /// The name of the element in this to create the + /// with. + /// + /// + /// The that is created by this method. + /// + /// + /// Thrown if this does not contain an element with the + /// specified name. + /// + public AnimatedSprite CreateAnimatedSprite(string tagName) + { + AnimationTag tag = GetAnimationTag(tagName); + AnimatedSprite sprite = new(tag); + return sprite; + } + + #endregion Animations +} diff --git a/source/MonoGame.Aseprite/Sprites/TextureAtlas.cs b/source/MonoGame.Aseprite/TextureAtlas.cs similarity index 90% rename from source/MonoGame.Aseprite/Sprites/TextureAtlas.cs rename to source/MonoGame.Aseprite/TextureAtlas.cs index 1e737e9c..7643975e 100644 --- a/source/MonoGame.Aseprite/Sprites/TextureAtlas.cs +++ b/source/MonoGame.Aseprite/TextureAtlas.cs @@ -1,586 +1,549 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.Collections; -using System.Data.Common; -using System.Diagnostics.CodeAnalysis; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.Utils; - - -namespace MonoGame.Aseprite.Sprites; - -/// -/// Defines a with a source image and zero or more elements. -/// -public class TextureAtlas : IEnumerable -{ - private List _regions = new(); - private Dictionary _regionLookup = new(); - - /// - /// G ets the name assigned to this . - /// - public string Name { get; } - - /// - /// Gets the source image of this . - /// - public Texture2D Texture { get; } - - /// - /// Gets the total number of elements in this . - /// - public int RegionCount => _regions.Count; - - /// - /// Gets the element at the specified index in this . - /// - /// - /// The index of the element in this to locate. - /// - /// - /// The element that was located at the specified index in this - /// . - /// - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public TextureRegion this[int index] => GetRegion(index); - - /// - /// Gets the element with the specified name in this . - /// - /// - /// The name of the element in this to locate. - /// - /// - /// The element that was located with the specified name in this - /// . - /// - /// - /// Thrown if this does not contain a with the specified - /// name. - /// - public TextureRegion this[string name] => GetRegion(name); - - /// - /// Initializes a new instance of the class. - /// - /// - /// The name to assign the . - /// - /// T - /// he source image to give the . - /// - public TextureAtlas(string name, Texture2D texture) => (Name, Texture) = (name, texture); - - private void AddRegion(TextureRegion region) - { - if (_regionLookup.ContainsKey(region.Name)) - { - throw new InvalidOperationException($"This {nameof(TextureAtlas)} already contains a {nameof(TextureRegion)} with the name '{region.Name}'."); - } - - _regions.Add(region); - _regionLookup.Add(region.Name, region); - } - - private bool RemoveRegion(TextureRegion region) => - _regions.Remove(region) && _regionLookup.Remove(region.Name); - - /// - /// Creates a new and adds it to this . - /// - /// - /// The name to assign the that is created. The name must be unique across all - /// in this . - /// - /// - /// The x-coordinate location of the upper-left corner of the within the source - /// image of this . - /// - /// - /// The y-coordinate location of the upper-left corner of the within the source - /// image of this . - /// - /// - /// The width, in pixels, of the . - /// - /// - /// The height, in pixels, of the . - /// - /// - /// Thrown if this already contains a element with the - /// specified name. - /// - /// - /// The created by this method. - /// - public TextureRegion CreateRegion(string name, int x, int y, int width, int height) => - CreateRegion(name, new Rectangle(x, y, width, height)); - - /// - /// Creates a new and adds it to this . - /// - /// - /// The name to assign the that is created. The name must be unique across all - /// in this . - /// - /// - /// The x- and y-coordinate location of the upper-left corner of the within the - /// source image of this . - /// - /// The width and height extents, in pixels, of the . - /// - /// Thrown if this already contains a element with the - /// specified name. - /// - /// - /// The created by this method. - /// - public TextureRegion CreateRegion(string name, Point location, Point size) => - CreateRegion(name, new Rectangle(location, size)); - - /// - /// Creates a new and adds it to this . - /// - /// - /// The name to assign the that is created. The name must be unique across all - /// in this . - /// - /// - /// The rectangular bounds of the within the source image of this - /// . - /// - /// - /// Thrown if this already contains a element with the - /// specified name. - /// - /// - /// The created by this method. - /// - public TextureRegion CreateRegion(string name, Rectangle bounds) - { - TextureRegion region = new(name, Texture, bounds); - AddRegion(region); - return region; - } - - /// - /// Returns a value that indicates whether this contains a - /// element with the specified name. - /// - /// - /// The name of the to locate. - /// - /// - /// if this contains a element - /// with the specified name; otherwise, . - /// - public bool ContainsRegion(string name) => _regionLookup.ContainsKey(name); - - /// - /// Returns the index of the element with the specified name in this - /// . - /// - /// - /// The name of the to locate. - /// - /// - /// The index of the located. - /// - /// - /// if this contains a element - /// with the specified name; otherwise, . - /// - public int GetIndexOfRegion(string name) - { - for (int i = 0; i < _regions.Count; i++) - { - if (_regions[i].Name == name) - { - return i; - } - } - - KeyNotFoundException ex = new($"This texture atlas does not contain a texture region with the name '{name}'."); - ex.Data.Add("TextureRegions", _regions); - throw ex; - } - - /// - /// Gets the element at the specified index in this . - /// - /// - /// The index of the element to locate. - /// - /// - /// The element that was located. - /// - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public TextureRegion GetRegion(int index) - { - if (index < 0 || index >= _regions.Count) - { - throw new ArgumentOutOfRangeException(nameof(index), $"{nameof(index)} cannot be less than zero or greater than or equal to the total number of {nameof(TextureRegion)} elements in this {nameof(TextureAtlas)}."); - } - - return _regions[index]; - } - - /// - /// Gets the element with the specified name in this . - /// - /// - /// The name of the element to locate. - /// - /// - /// The element that was located. - /// - /// - /// Thrown if this does not contain a element with the - /// specified name. - /// - public TextureRegion GetRegion(string name) - { - if (_regionLookup.TryGetValue(name, out TextureRegion? frame)) - { - return frame; - } - - KeyNotFoundException ex = new($"This texture atlas does not contain a texture region with the name '{name}'."); - ex.Data.Add("TextureRegions", _regions); - throw ex; - } - - /// - /// Gets a new of all elements at the specified indexes in - /// this . Order of the elements in the collection returned is the same as the order - /// of the indexes specified. - /// - /// - /// The indexes of the elements to locate. - /// - /// - /// A new containing the elements located. - /// - /// - /// Thrown if any of the specified indexes are less than zero or if any are greater than or equal to the total - /// number of elements in this . - /// - public List GetRegions(params int[] indexes) - { - List regions = new(); - for (int i = 0; i < indexes.Length; i++) - { - regions.Add(GetRegion(indexes[i])); - } - - return regions; - } - - /// - /// Gets a new of all elements with the specified names in - /// this . Order of the elements in the collection returned is the same as the order - /// of names specified. - /// - /// - /// The names of the elements to locate. - /// - /// - /// A new containing the elements located. - /// - /// - /// Thrown if any of the specified names do not match a element in this - /// . - /// - public List GetRegions(params string[] names) - { - List regions = new(); - - for (int i = 0; i < names.Length; i++) - { - regions.Add(GetRegion(names[i])); - } - - return regions; - } - - /// - /// Gets the element at the specified index in this . - /// - /// - /// The index of the element to locate. - /// - /// - /// When this method returns , contains the located; - /// otherwise, . - /// - /// - /// if a element was located; otherwise, - /// . This method returns if the index specified is less than - /// zero or is greater than or equal to the total number of elements in this - /// . - /// - public bool TryGetRegion(int index, [NotNullWhen(true)] out TextureRegion? region) - { - region = default; - - if (index < 0 || index >= _regions.Count) - { - return false; - } - - region = _regions[index]; - return true; - } - - /// - /// Gets the element with the specified name in this . - /// - /// - /// The name of the element to locate. - /// - /// - /// When this method returns , contains the located; - /// otherwise, . - /// - /// - /// if a element was located; otherwise, - /// . This method returns if this - /// does not contain a element with the specified name. - /// - public bool TryGetRegion(string name, [NotNullWhen(true)] out TextureRegion? region) => - _regionLookup.TryGetValue(name, out region); - - /// - /// Removes the element at the specified index from this . - /// - /// - /// The index of the element to remove. - /// - /// - /// if the element was successfully removed; otherwise, - /// . This method returns if the specified index is less than - /// zero or is greater than or equal to the total number of element in this - /// . - /// - public bool RemoveRegion(int index) - { - if (TryGetRegion(index, out TextureRegion? region)) - { - return RemoveRegion(region); - } - - return false; - } - - /// - /// Removes the element with the specified name from this - /// . - /// - /// - /// The name of the element to remove. - /// - /// - /// if the element was successfully removed; otherwise, - /// . This method returns if this - /// does not contain a element with the specified name. - /// - public bool RemoveRegion(string name) - { - if (TryGetRegion(name, out TextureRegion? region)) - { - return RemoveRegion(region); - } - - return false; - } - - /// - /// Creates a new from the at the specified index in this - /// . - /// - /// - /// The name to assign the that is created. - /// - /// - /// The index of the element in this assign the - /// that is created. - /// - /// - /// The that is created by this method. - /// - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public Sprite CreateSprite(string spriteName, int regionIndex) - { - TextureRegion region = GetRegion(regionIndex); - Sprite sprite = new(spriteName, region); - return sprite; - } - - /// - /// Creates a new from the at the specified index in this - /// . - /// - /// - /// The index of the element to assign the that is created. - /// - /// - /// The that is created by this method. - /// - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public Sprite CreateSprite(int regionIndex) - { - TextureRegion region = GetRegion(regionIndex); - Sprite sprite = new(region.Name, region); - return sprite; - } - - /// - /// Creates a new from the with the specified name in this - /// . - /// - /// - /// The name to assign the that is created. - /// - /// - /// The name of the element in this assign the - /// that is created. - /// - /// - /// The that is created by this method. - /// - /// - /// Thrown if this does not contain a with the name - /// specified. - /// - public Sprite CreateSprite(string spriteName, string regionName) - { - TextureRegion region = GetRegion(regionName); - Sprite sprite = new(spriteName, region); - return sprite; - } - - /// - /// Creates a new from the with the specified name in this - /// . - /// - /// - /// The name of the element in this assign the - /// that is created. - /// - /// - /// The that is created by this method. - /// - /// - /// Thrown if this does not contain a with the name - /// specified. - /// - public Sprite CreateSprite(string regionName) - { - TextureRegion region = GetRegion(regionName); - Sprite sprite = new(region.Name, region); - return sprite; - } - - /// - /// Removes all elements from this . - /// - public void Clear() - { - // Remove them in a foreach so that each region is disposed of properly as it's removed - foreach (TextureRegion region in this) - { - RemoveRegion(region); - } - } - - /// - /// Returns an enumerator that iterates each element in this - /// . - /// - /// - /// An enumerator that iterates each elements in this . - /// - public IEnumerator GetEnumerator() => _regions.GetEnumerator(); - - /// - /// Returns an enumerator that iterates each element in this - /// . - /// - /// - /// An enumerator that iterates each elements in this . - /// - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - public static TextureAtlas FromFile(GraphicsDevice device, AseFile file, AseProcessorOptions options) - { - options ??= AseProcessorOptions.Default; - AseTextureAtlas aseTextureAtlas = AseTextureAtlasProcessor.Process(file, options); - Texture2D texture = aseTextureAtlas.Texture.ToTexture2D(device); - TextureAtlas atlas = new TextureAtlas(texture.Name, texture); - - for(int i = 0; i < aseTextureAtlas.Regions.Length; i++) - { - AseTextureRegion aseTextureRegion = aseTextureAtlas.Regions[i]; - TextureRegion textureRegion = atlas.CreateRegion(aseTextureRegion.Name, aseTextureRegion.Bounds.ToXnaRectangle()); - - for(int s = 0; s < aseTextureRegion.Slices.Length; s++) - { - AseSlice aseSlice = aseTextureRegion.Slices[i]; - - if(aseSlice is AseNinepatchSlice aseNinePatchSlice) - { - textureRegion.CreateNinePatchSlice(aseNinePatchSlice.Name, - aseNinePatchSlice.Bounds.ToXnaRectangle(), - aseNinePatchSlice.CenterBounds.ToXnaRectangle(), - aseNinePatchSlice.Origin.ToXnaVector2(), - aseNinePatchSlice.Color.ToXnaColor()); - } - else - { - textureRegion.CreateSlice(aseSlice.Name, - aseSlice.Bounds.ToXnaRectangle(), - aseSlice.Origin.ToXnaVector2(), - aseSlice.Color.ToXnaColor()); - } - } - } - - return atlas; - } -} +/* ---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2018-2023 Christopher Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------------------------------------------------- */ + +using System.Collections; +using System.Data.Common; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using MonoGame.Aseprite.Utils; + + +namespace MonoGame.Aseprite; + +/// +/// Defines a with a source image and zero or more elements. +/// +public class TextureAtlas : IEnumerable +{ + private List _regions = new(); + private Dictionary _regionLookup = new(); + + /// + /// G ets the name assigned to this . + /// + public string Name { get; } + + /// + /// Gets the source image of this . + /// + public Texture2D Texture { get; } + + /// + /// Gets the total number of elements in this . + /// + public int RegionCount => _regions.Count; + + /// + /// Gets the element at the specified index in this . + /// + /// + /// The index of the element in this to locate. + /// + /// + /// The element that was located at the specified index in this + /// . + /// + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public TextureRegion this[int index] => GetRegion(index); + + /// + /// Gets the element with the specified name in this . + /// + /// + /// The name of the element in this to locate. + /// + /// + /// The element that was located with the specified name in this + /// . + /// + /// + /// Thrown if this does not contain a with the specified + /// name. + /// + public TextureRegion this[string name] => GetRegion(name); + + /// + /// Initializes a new instance of the class. + /// + /// + /// The name to assign the . + /// + /// T + /// he source image to give the . + /// + public TextureAtlas(string name, Texture2D texture) => (Name, Texture) = (name, texture); + + private void AddRegion(TextureRegion region) + { + if (_regionLookup.ContainsKey(region.Name)) + { + throw new InvalidOperationException($"This {nameof(TextureAtlas)} already contains a {nameof(TextureRegion)} with the name '{region.Name}'."); + } + + _regions.Add(region); + _regionLookup.Add(region.Name, region); + } + + private bool RemoveRegion(TextureRegion region) => + _regions.Remove(region) && _regionLookup.Remove(region.Name); + + /// + /// Creates a new and adds it to this . + /// + /// + /// The name to assign the that is created. The name must be unique across all + /// in this . + /// + /// + /// The x-coordinate location of the upper-left corner of the within the source + /// image of this . + /// + /// + /// The y-coordinate location of the upper-left corner of the within the source + /// image of this . + /// + /// + /// The width, in pixels, of the . + /// + /// + /// The height, in pixels, of the . + /// + /// + /// Thrown if this already contains a element with the + /// specified name. + /// + /// + /// The created by this method. + /// + public TextureRegion CreateRegion(string name, int x, int y, int width, int height) => + CreateRegion(name, new Rectangle(x, y, width, height)); + + /// + /// Creates a new and adds it to this . + /// + /// + /// The name to assign the that is created. The name must be unique across all + /// in this . + /// + /// + /// The x- and y-coordinate location of the upper-left corner of the within the + /// source image of this . + /// + /// The width and height extents, in pixels, of the . + /// + /// Thrown if this already contains a element with the + /// specified name. + /// + /// + /// The created by this method. + /// + public TextureRegion CreateRegion(string name, Point location, Point size) => + CreateRegion(name, new Rectangle(location, size)); + + /// + /// Creates a new and adds it to this . + /// + /// + /// The name to assign the that is created. The name must be unique across all + /// in this . + /// + /// + /// The rectangular bounds of the within the source image of this + /// . + /// + /// + /// Thrown if this already contains a element with the + /// specified name. + /// + /// + /// The created by this method. + /// + public TextureRegion CreateRegion(string name, Rectangle bounds) + { + TextureRegion region = new(name, Texture, bounds); + AddRegion(region); + return region; + } + + /// + /// Returns a value that indicates whether this contains a + /// element with the specified name. + /// + /// + /// The name of the to locate. + /// + /// + /// if this contains a element + /// with the specified name; otherwise, . + /// + public bool ContainsRegion(string name) => _regionLookup.ContainsKey(name); + + /// + /// Returns the index of the element with the specified name in this + /// . + /// + /// + /// The name of the to locate. + /// + /// + /// The index of the located. + /// + /// + /// if this contains a element + /// with the specified name; otherwise, . + /// + public int GetIndexOfRegion(string name) + { + for (int i = 0; i < _regions.Count; i++) + { + if (_regions[i].Name == name) + { + return i; + } + } + + KeyNotFoundException ex = new($"This texture atlas does not contain a texture region with the name '{name}'."); + ex.Data.Add("TextureRegions", _regions); + throw ex; + } + + /// + /// Gets the element at the specified index in this . + /// + /// + /// The index of the element to locate. + /// + /// + /// The element that was located. + /// + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public TextureRegion GetRegion(int index) + { + if (index < 0 || index >= _regions.Count) + { + throw new ArgumentOutOfRangeException(nameof(index), $"{nameof(index)} cannot be less than zero or greater than or equal to the total number of {nameof(TextureRegion)} elements in this {nameof(TextureAtlas)}."); + } + + return _regions[index]; + } + + /// + /// Gets the element with the specified name in this . + /// + /// + /// The name of the element to locate. + /// + /// + /// The element that was located. + /// + /// + /// Thrown if this does not contain a element with the + /// specified name. + /// + public TextureRegion GetRegion(string name) + { + if (_regionLookup.TryGetValue(name, out TextureRegion? frame)) + { + return frame; + } + + KeyNotFoundException ex = new($"This texture atlas does not contain a texture region with the name '{name}'."); + ex.Data.Add("TextureRegions", _regions); + throw ex; + } + + /// + /// Gets a new of all elements at the specified indexes in + /// this . Order of the elements in the collection returned is the same as the order + /// of the indexes specified. + /// + /// + /// The indexes of the elements to locate. + /// + /// + /// A new containing the elements located. + /// + /// + /// Thrown if any of the specified indexes are less than zero or if any are greater than or equal to the total + /// number of elements in this . + /// + public List GetRegions(params int[] indexes) + { + List regions = new(); + for (int i = 0; i < indexes.Length; i++) + { + regions.Add(GetRegion(indexes[i])); + } + + return regions; + } + + /// + /// Gets a new of all elements with the specified names in + /// this . Order of the elements in the collection returned is the same as the order + /// of names specified. + /// + /// + /// The names of the elements to locate. + /// + /// + /// A new containing the elements located. + /// + /// + /// Thrown if any of the specified names do not match a element in this + /// . + /// + public List GetRegions(params string[] names) + { + List regions = new(); + + for (int i = 0; i < names.Length; i++) + { + regions.Add(GetRegion(names[i])); + } + + return regions; + } + + /// + /// Gets the element at the specified index in this . + /// + /// + /// The index of the element to locate. + /// + /// + /// When this method returns , contains the located; + /// otherwise, . + /// + /// + /// if a element was located; otherwise, + /// . This method returns if the index specified is less than + /// zero or is greater than or equal to the total number of elements in this + /// . + /// + public bool TryGetRegion(int index, [NotNullWhen(true)] out TextureRegion? region) + { + region = default; + + if (index < 0 || index >= _regions.Count) + { + return false; + } + + region = _regions[index]; + return true; + } + + /// + /// Gets the element with the specified name in this . + /// + /// + /// The name of the element to locate. + /// + /// + /// When this method returns , contains the located; + /// otherwise, . + /// + /// + /// if a element was located; otherwise, + /// . This method returns if this + /// does not contain a element with the specified name. + /// + public bool TryGetRegion(string name, [NotNullWhen(true)] out TextureRegion? region) => + _regionLookup.TryGetValue(name, out region); + + /// + /// Removes the element at the specified index from this . + /// + /// + /// The index of the element to remove. + /// + /// + /// if the element was successfully removed; otherwise, + /// . This method returns if the specified index is less than + /// zero or is greater than or equal to the total number of element in this + /// . + /// + public bool RemoveRegion(int index) + { + if (TryGetRegion(index, out TextureRegion? region)) + { + return RemoveRegion(region); + } + + return false; + } + + /// + /// Removes the element with the specified name from this + /// . + /// + /// + /// The name of the element to remove. + /// + /// + /// if the element was successfully removed; otherwise, + /// . This method returns if this + /// does not contain a element with the specified name. + /// + public bool RemoveRegion(string name) + { + if (TryGetRegion(name, out TextureRegion? region)) + { + return RemoveRegion(region); + } + + return false; + } + + /// + /// Creates a new from the at the specified index in this + /// . + /// + /// + /// The name to assign the that is created. + /// + /// + /// The index of the element in this assign the + /// that is created. + /// + /// + /// The that is created by this method. + /// + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public Sprite CreateSprite(string spriteName, int regionIndex) + { + TextureRegion region = GetRegion(regionIndex); + Sprite sprite = new(spriteName, region); + return sprite; + } + + /// + /// Creates a new from the at the specified index in this + /// . + /// + /// + /// The index of the element to assign the that is created. + /// + /// + /// The that is created by this method. + /// + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public Sprite CreateSprite(int regionIndex) + { + TextureRegion region = GetRegion(regionIndex); + Sprite sprite = new(region.Name, region); + return sprite; + } + + /// + /// Creates a new from the with the specified name in this + /// . + /// + /// + /// The name to assign the that is created. + /// + /// + /// The name of the element in this assign the + /// that is created. + /// + /// + /// The that is created by this method. + /// + /// + /// Thrown if this does not contain a with the name + /// specified. + /// + public Sprite CreateSprite(string spriteName, string regionName) + { + TextureRegion region = GetRegion(regionName); + Sprite sprite = new(spriteName, region); + return sprite; + } + + /// + /// Creates a new from the with the specified name in this + /// . + /// + /// + /// The name of the element in this assign the + /// that is created. + /// + /// + /// The that is created by this method. + /// + /// + /// Thrown if this does not contain a with the name + /// specified. + /// + public Sprite CreateSprite(string regionName) + { + TextureRegion region = GetRegion(regionName); + Sprite sprite = new(region.Name, region); + return sprite; + } + + /// + /// Removes all elements from this . + /// + public void Clear() + { + // Remove them in a foreach so that each region is disposed of properly as it's removed + foreach (TextureRegion region in this) + { + RemoveRegion(region); + } + } + + /// + /// Returns an enumerator that iterates each element in this + /// . + /// + /// + /// An enumerator that iterates each elements in this . + /// + public IEnumerator GetEnumerator() => _regions.GetEnumerator(); + + /// + /// Returns an enumerator that iterates each element in this + /// . + /// + /// + /// An enumerator that iterates each elements in this . + /// + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} diff --git a/source/MonoGame.Aseprite/Tilemaps/Tile.cs b/source/MonoGame.Aseprite/Tile.cs similarity index 96% rename from source/MonoGame.Aseprite/Tilemaps/Tile.cs rename to source/MonoGame.Aseprite/Tile.cs index acfe31f4..1f9fa339 100644 --- a/source/MonoGame.Aseprite/Tilemaps/Tile.cs +++ b/source/MonoGame.Aseprite/Tile.cs @@ -1,98 +1,98 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -namespace MonoGame.Aseprite.Tilemaps; - -/// -/// Defines a tile value in a . -/// -public struct Tile -{ - /// - /// Represents a with its properties left uninitialized. - /// - public static readonly Tile Empty; - - /// - /// The ID (or index) of the source tile in the that represents the - /// to render for this . - /// - public int TilesetTileID = 0; - - /// - /// Indicates whether this should be flipped horizontally rendered. - /// - public bool FlipHorizontally = false; - - /// - /// Indicates whether this should be flipped vertically rendered. - /// - public bool FlipVertically = false; - - /// - /// Indicates whether this should be flipped diagonally when rendered. - /// - public bool FlipDiagonally = false; - - /// - /// Gets a value that indicates if this is an empty . - /// - /// - /// Empty tiles have a equal to zero. - /// - public bool IsEmpty => TilesetTileID == 0; - - /// - /// Initializes a new instance of the class. - /// - public Tile() { } - - /// - /// Initializes a new value. - /// - /// - /// The ID (or index) of the source tile in the that represents the - /// to assign for this . - /// - public Tile(int tilesetTileID) => TilesetTileID = tilesetTileID; - - /// - /// Initializes a new value. - /// - /// - /// The ID (or index) of the source tile in the that represents the - /// to assign for this . - /// - /// - /// Indicates whether the should be flipped horizontally when rendered. - /// - /// - /// Indicates whether the should be flipped vertically when rendered. - /// - /// - /// Indicates whether the should be flipped diagonally when rendered. - /// - public Tile(int tilesetTileID, bool flipHorizontally, bool flipVertically, bool flipDiagonally) => - (TilesetTileID, FlipHorizontally, FlipVertically, FlipDiagonally) = (tilesetTileID, flipHorizontally, flipVertically, flipDiagonally); -} +/* ---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2018-2023 Christopher Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------------------------------------------------- */ + +namespace MonoGame.Aseprite; + +/// +/// Defines a tile value in a . +/// +public struct Tile +{ + /// + /// Represents a with its properties left uninitialized. + /// + public static readonly Tile Empty; + + /// + /// The ID (or index) of the source tile in the that represents the + /// to render for this . + /// + public int TilesetTileID = 0; + + /// + /// Indicates whether this should be flipped horizontally rendered. + /// + public bool FlipHorizontally = false; + + /// + /// Indicates whether this should be flipped vertically rendered. + /// + public bool FlipVertically = false; + + /// + /// Indicates whether this should be flipped diagonally when rendered. + /// + public bool FlipDiagonally = false; + + /// + /// Gets a value that indicates if this is an empty . + /// + /// + /// Empty tiles have a equal to zero. + /// + public bool IsEmpty => TilesetTileID == 0; + + /// + /// Initializes a new instance of the class. + /// + public Tile() { } + + /// + /// Initializes a new value. + /// + /// + /// The ID (or index) of the source tile in the that represents the + /// to assign for this . + /// + public Tile(int tilesetTileID) => TilesetTileID = tilesetTileID; + + /// + /// Initializes a new value. + /// + /// + /// The ID (or index) of the source tile in the that represents the + /// to assign for this . + /// + /// + /// Indicates whether the should be flipped horizontally when rendered. + /// + /// + /// Indicates whether the should be flipped vertically when rendered. + /// + /// + /// Indicates whether the should be flipped diagonally when rendered. + /// + public Tile(int tilesetTileID, bool flipHorizontally, bool flipVertically, bool flipDiagonally) => + (TilesetTileID, FlipHorizontally, FlipVertically, FlipDiagonally) = (tilesetTileID, flipHorizontally, flipVertically, flipDiagonally); +} diff --git a/source/MonoGame.Aseprite/Tilemaps/Tilemap.cs b/source/MonoGame.Aseprite/Tilemap.cs similarity index 87% rename from source/MonoGame.Aseprite/Tilemaps/Tilemap.cs rename to source/MonoGame.Aseprite/Tilemap.cs index ce22fdcf..a19a5b0b 100644 --- a/source/MonoGame.Aseprite/Tilemaps/Tilemap.cs +++ b/source/MonoGame.Aseprite/Tilemap.cs @@ -1,421 +1,380 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.Collections; -using System.Diagnostics.CodeAnalysis; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.Utils; - - -namespace MonoGame.Aseprite.Tilemaps; - -/// -/// Defines a with zero or more elements. -/// -public sealed class Tilemap : IEnumerable -{ - private List _layers = new(); - private Dictionary _layerLookup = new(); - - /// - /// Gets the name assigned to this . - /// - public string Name { get; } - - /// - /// Gets the total number of elements in this . - /// - public int LayerCount => _layers.Count; - - /// - /// Gets the element at the specified index in this . - /// - /// - /// The index of the element to locate. - /// - /// - /// The element located. - /// - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public TilemapLayer this[int layerIndex] => GetLayer(layerIndex); - - /// - /// Gets the element with the specified name in this . - /// - /// - /// The name of the element to locate. - /// - /// - /// The element located. - /// - /// - /// Thrown if this does not contain a element with the - /// specified name. - /// - public TilemapLayer this[string layerName] => GetLayer(layerName); - - /// - /// Initializes a new instance of the class. - /// - /// - /// The name to assign . - /// - public Tilemap(string name) => Name = name; - - /// - /// Creates a new element and adds it to this . - /// - /// - /// The name to give the element created by this method. The name must be unique - /// across all elements in this . - /// - /// - /// The source tileset to assign the element created by this method. - /// - /// - /// The total number of columns to assign the element created by this method. - /// - /// - /// The total of rows to assign the element created by this method. - /// - /// - /// The x- and y-position offset, relative to the location the is rendered, to - /// assign the element created by this method. - /// - /// - /// The created by this method. - /// - /// - /// Thrown if this already contains a element with the - /// specified name. - /// - public TilemapLayer CreateLayer(string layerName, Tileset tileset, int columns, int rows, Vector2 offset) - { - TilemapLayer layer = new(layerName, tileset, columns, rows, offset); - AddLayer(layer); - return layer; - } - - /// - /// Adds the given element to this . - /// - /// - /// The element to add. - /// - /// - /// Thrown if this already contains a element with the same - /// name as the element given. - /// - public void AddLayer(TilemapLayer layer) - { - if (_layerLookup.ContainsKey(layer.Name)) - { - throw new InvalidOperationException($"This tileset already contains a tilemap layer element with the name '{layer.Name}'."); - } - - _layers.Add(layer); - _layerLookup.Add(layer.Name, layer); - } - - /// - /// Get the element at the specified index in this . - /// - /// - /// The index of the element to locate. - /// - /// - /// The element located. - /// - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public TilemapLayer GetLayer(int index) - { - if (index < 0 || index >= LayerCount) - { - throw new ArgumentOutOfRangeException(nameof(index), $"{nameof(index)} cannot be less than zero or greater than or equal to the total number of tilemap layer elements in this tilemap."); - } - - return _layers[index]; - } - - /// - /// Gets the element with the specified name in this . - /// - /// - /// The name of the element to locate. - /// - /// - /// The located. - /// - /// - /// Thrown if this does not contain a element with the - /// specified name. - /// - public TilemapLayer GetLayer(string name) - { - if (_layerLookup.TryGetValue(name, out TilemapLayer? layer)) - { - return layer; - } - - throw new KeyNotFoundException($"This tilemap does not contain a tilemap layer element with the name '{name}'."); - } - - /// - /// Get the element at the specified index in this . - /// - /// - /// The index of the element to locate. - /// - /// - /// When this method returns , contains the element located; - /// otherwise, . - /// - /// - /// if a element was located at the specified index in this - /// ; otherwise, . This method return when - /// the specified index is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public bool TryGetLayer(int index, [NotNullWhen(true)] out TilemapLayer? layer) - { - layer = default; - - if (index < 0 || index >= LayerCount) - { - return false; - } - - layer = _layers[index]; - return true; - } - - /// - /// Gets the element with the specified name in this . - /// - /// - /// The name of the element to locate. - /// - /// - /// When this method returns , contains the element located; - /// otherwise, . - /// - /// - /// if a element was located in this - /// with the specified name; otherwise . This method returns if - /// this does not contain a element with the specified name. - /// - public bool TryGetLayer(string name, [NotNullWhen(true)] out TilemapLayer? layer) => - _layerLookup.TryGetValue(name, out layer); - - /// - /// Removes the element at the specified index in this . - /// - /// - /// The index of the element to remove from this . - /// - /// - /// if the element was successfully removed; otherwise, - /// . This method returns if the specified index is less than - /// zero or is greater than or equal to the total number of elements in this - /// . - /// - public bool RemoveLayer(int index) - { - if (index < 0 || index >= LayerCount) - { - return false; - } - - TilemapLayer layer = _layers[index]; - return RemoveLayer(layer); - } - - /// - /// Removes the element with the specified name from this . - /// - /// - /// The name of the element to remove from this - /// - /// - /// if the element was successfully removed; otherwise, - /// . This method returns if this does not - /// contain a element with the specified name. - /// - public bool RemoveLayer(string name) - { - if (_layerLookup.TryGetValue(name, out TilemapLayer? layer)) - { - return RemoveLayer(layer); - } - - return false; - } - - /// - /// Removes the given element from this . - /// - /// - /// The element to remove from this . - /// - /// - /// if the element was removed successfully; otherwise, - /// . This method returns false if this does not contain the - /// element given. - /// - public bool RemoveLayer(TilemapLayer layer) => - _layers.Remove(layer) && _layerLookup.Remove(layer.Name); - - /// - /// Removes all elements from this . - /// - public void Clear() - { - _layerLookup.Clear(); - _layers.Clear(); - } - - /// - /// Draws this using the . - /// - /// - /// The to use for rendering this . - /// - /// - /// The x- and y-coordinate location to render this at. - /// - /// - /// The color mask to apply when rendering this . - /// - public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color) => - Draw(spriteBatch, position, color, Vector2.One, 0.0f); - - /// - /// Draws this using the . - /// - /// - /// The to use for rendering this . - /// - /// - /// The x- and y-coordinate location to render this at. - /// - /// - /// The color mask to apply when rendering this . - /// - /// - /// The amount of scaling to apply when rendering this . - /// - /// - /// The layer depth to apply when rendering this . - /// - public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, float scale, float layerDepth) => - Draw(spriteBatch, position, color, new Vector2(scale, scale), layerDepth); - - /// - /// Draws a using this . - /// - /// - /// The to use for rendering this . - /// - /// - /// The x- and y-coordinate location to render this at. - /// - /// - /// The color mask to apply when rendering this . - /// - /// - /// The amount of scaling to apply when rendering this . - /// - /// - /// The layer depth to apply when rendering this . - /// - public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, Vector2 scale, float layerDepth) => - spriteBatch.Draw(this, position, color, scale, layerDepth); - - /// - /// Returns an enumerator used to iterate through all of the elements in this - /// . The order of elements in the enumeration is from bottom layer to top layer. - /// - /// - /// An enumerator used to iterate through all of the elements in this - /// . - /// - public IEnumerator GetEnumerator() => _layers.GetEnumerator(); - - /// - /// Returns an enumerator used to iterate through all of the elements in this - /// . The order of elements in the enumeration is from bottom layer to top layer. - /// - /// - /// An enumerator used to iterate through all of the elements in this - /// . - /// - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - public static Tilemap FromFile(GraphicsDevice device, AseFile file, int frameIndex, AseProcessorOptions options) - { - options ??= AseProcessorOptions.Default; - - AseTilemap aseTilemap = AseTilemapProcessor.Process(file, frameIndex, options); - Tilemap tilemap = new Tilemap(aseTilemap.Name); - - Dictionary tilesetLookup = new Dictionary(); - for(int i = 0; i < aseTilemap.Tilesets.Length; i++) - { - AseTileset aseTileset = aseTilemap.Tilesets[i]; - Texture2D texture = aseTileset.Texture.ToTexture2D(device); - Tileset tileset = new Tileset(aseTileset.Name, texture, aseTileset.TileSize.Width, aseTileset.TileSize.Height); - tilesetLookup.Add(aseTileset.ID, tileset); - } - - for(int l = 0; l < aseTilemap.Layers.Length; l++) - { - AseTilemapLayer aseTilemapLayer = aseTilemap.Layers[l]; - Tileset tileset = tilesetLookup[aseTilemapLayer.TilesetID]; - TilemapLayer tilemapLayer = tilemap.CreateLayer(aseTilemapLayer.Name, - tileset, - aseTilemapLayer.Columns, - aseTilemapLayer.Rows, - aseTilemapLayer.Offset.ToXnaVector2()); - - for(int t = 0; t < aseTilemapLayer.Tiles.Length; t++) - { - AseTilemapTile aseTilemapTile = aseTilemapLayer.Tiles[t]; - tilemapLayer.SetTile(t, - aseTilemapTile.TilesetTileID, - aseTilemapTile.FlipVertically, - aseTilemapTile.FlipHorizontally, - aseTilemapTile.FlipDiagonally); - } - } - - return tilemap; - } -} +/* ---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2018-2023 Christopher Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------------------------------------------------- */ + +using System.Collections; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + + +namespace MonoGame.Aseprite; + +/// +/// Defines a with zero or more elements. +/// +public sealed class Tilemap : IEnumerable +{ + private List _layers = new(); + private Dictionary _layerLookup = new(); + + /// + /// Gets the name assigned to this . + /// + public string Name { get; } + + /// + /// Gets the total number of elements in this . + /// + public int LayerCount => _layers.Count; + + /// + /// Gets the element at the specified index in this . + /// + /// + /// The index of the element to locate. + /// + /// + /// The element located. + /// + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public TilemapLayer this[int layerIndex] => GetLayer(layerIndex); + + /// + /// Gets the element with the specified name in this . + /// + /// + /// The name of the element to locate. + /// + /// + /// The element located. + /// + /// + /// Thrown if this does not contain a element with the + /// specified name. + /// + public TilemapLayer this[string layerName] => GetLayer(layerName); + + /// + /// Initializes a new instance of the class. + /// + /// + /// The name to assign . + /// + public Tilemap(string name) => Name = name; + + /// + /// Creates a new element and adds it to this . + /// + /// + /// The name to give the element created by this method. The name must be unique + /// across all elements in this . + /// + /// + /// The source tileset to assign the element created by this method. + /// + /// + /// The total number of columns to assign the element created by this method. + /// + /// + /// The total of rows to assign the element created by this method. + /// + /// + /// The x- and y-position offset, relative to the location the is rendered, to + /// assign the element created by this method. + /// + /// + /// The created by this method. + /// + /// + /// Thrown if this already contains a element with the + /// specified name. + /// + public TilemapLayer CreateLayer(string layerName, Tileset tileset, int columns, int rows, Vector2 offset) + { + TilemapLayer layer = new(layerName, tileset, columns, rows, offset); + AddLayer(layer); + return layer; + } + + /// + /// Adds the given element to this . + /// + /// + /// The element to add. + /// + /// + /// Thrown if this already contains a element with the same + /// name as the element given. + /// + public void AddLayer(TilemapLayer layer) + { + if (_layerLookup.ContainsKey(layer.Name)) + { + throw new InvalidOperationException($"This tileset already contains a tilemap layer element with the name '{layer.Name}'."); + } + + _layers.Add(layer); + _layerLookup.Add(layer.Name, layer); + } + + /// + /// Get the element at the specified index in this . + /// + /// + /// The index of the element to locate. + /// + /// + /// The element located. + /// + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public TilemapLayer GetLayer(int index) + { + if (index < 0 || index >= LayerCount) + { + throw new ArgumentOutOfRangeException(nameof(index), $"{nameof(index)} cannot be less than zero or greater than or equal to the total number of tilemap layer elements in this tilemap."); + } + + return _layers[index]; + } + + /// + /// Gets the element with the specified name in this . + /// + /// + /// The name of the element to locate. + /// + /// + /// The located. + /// + /// + /// Thrown if this does not contain a element with the + /// specified name. + /// + public TilemapLayer GetLayer(string name) + { + if (_layerLookup.TryGetValue(name, out TilemapLayer? layer)) + { + return layer; + } + + throw new KeyNotFoundException($"This tilemap does not contain a tilemap layer element with the name '{name}'."); + } + + /// + /// Get the element at the specified index in this . + /// + /// + /// The index of the element to locate. + /// + /// + /// When this method returns , contains the element located; + /// otherwise, . + /// + /// + /// if a element was located at the specified index in this + /// ; otherwise, . This method return when + /// the specified index is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public bool TryGetLayer(int index, [NotNullWhen(true)] out TilemapLayer? layer) + { + layer = default; + + if (index < 0 || index >= LayerCount) + { + return false; + } + + layer = _layers[index]; + return true; + } + + /// + /// Gets the element with the specified name in this . + /// + /// + /// The name of the element to locate. + /// + /// + /// When this method returns , contains the element located; + /// otherwise, . + /// + /// + /// if a element was located in this + /// with the specified name; otherwise . This method returns if + /// this does not contain a element with the specified name. + /// + public bool TryGetLayer(string name, [NotNullWhen(true)] out TilemapLayer? layer) => + _layerLookup.TryGetValue(name, out layer); + + /// + /// Removes the element at the specified index in this . + /// + /// + /// The index of the element to remove from this . + /// + /// + /// if the element was successfully removed; otherwise, + /// . This method returns if the specified index is less than + /// zero or is greater than or equal to the total number of elements in this + /// . + /// + public bool RemoveLayer(int index) + { + if (index < 0 || index >= LayerCount) + { + return false; + } + + TilemapLayer layer = _layers[index]; + return RemoveLayer(layer); + } + + /// + /// Removes the element with the specified name from this . + /// + /// + /// The name of the element to remove from this + /// + /// + /// if the element was successfully removed; otherwise, + /// . This method returns if this does not + /// contain a element with the specified name. + /// + public bool RemoveLayer(string name) + { + if (_layerLookup.TryGetValue(name, out TilemapLayer? layer)) + { + return RemoveLayer(layer); + } + + return false; + } + + /// + /// Removes the given element from this . + /// + /// + /// The element to remove from this . + /// + /// + /// if the element was removed successfully; otherwise, + /// . This method returns false if this does not contain the + /// element given. + /// + public bool RemoveLayer(TilemapLayer layer) => + _layers.Remove(layer) && _layerLookup.Remove(layer.Name); + + /// + /// Removes all elements from this . + /// + public void Clear() + { + _layerLookup.Clear(); + _layers.Clear(); + } + + /// + /// Draws this using the . + /// + /// + /// The to use for rendering this . + /// + /// + /// The x- and y-coordinate location to render this at. + /// + /// + /// The color mask to apply when rendering this . + /// + public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color) => + Draw(spriteBatch, position, color, Vector2.One, 0.0f); + + /// + /// Draws this using the . + /// + /// + /// The to use for rendering this . + /// + /// + /// The x- and y-coordinate location to render this at. + /// + /// + /// The color mask to apply when rendering this . + /// + /// + /// The amount of scaling to apply when rendering this . + /// + /// + /// The layer depth to apply when rendering this . + /// + public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, float scale, float layerDepth) => + Draw(spriteBatch, position, color, new Vector2(scale, scale), layerDepth); + + /// + /// Draws a using this . + /// + /// + /// The to use for rendering this . + /// + /// + /// The x- and y-coordinate location to render this at. + /// + /// + /// The color mask to apply when rendering this . + /// + /// + /// The amount of scaling to apply when rendering this . + /// + /// + /// The layer depth to apply when rendering this . + /// + public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, Vector2 scale, float layerDepth) => + spriteBatch.Draw(this, position, color, scale, layerDepth); + + /// + /// Returns an enumerator used to iterate through all of the elements in this + /// . The order of elements in the enumeration is from bottom layer to top layer. + /// + /// + /// An enumerator used to iterate through all of the elements in this + /// . + /// + public IEnumerator GetEnumerator() => _layers.GetEnumerator(); + + /// + /// Returns an enumerator used to iterate through all of the elements in this + /// . The order of elements in the enumeration is from bottom layer to top layer. + /// + /// + /// An enumerator used to iterate through all of the elements in this + /// . + /// + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); +} diff --git a/source/MonoGame.Aseprite/Tilemaps/TilemapLayer.cs b/source/MonoGame.Aseprite/TilemapLayer.cs similarity index 95% rename from source/MonoGame.Aseprite/Tilemaps/TilemapLayer.cs rename to source/MonoGame.Aseprite/TilemapLayer.cs index ba2648ae..b1990927 100644 --- a/source/MonoGame.Aseprite/Tilemaps/TilemapLayer.cs +++ b/source/MonoGame.Aseprite/TilemapLayer.cs @@ -1,645 +1,645 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.Collections; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; - -namespace MonoGame.Aseprite.Tilemaps; - -/// -/// Defines a grid-like layer in a tilemap that contains a collection of tiles. -/// -public sealed class TilemapLayer : IEnumerable -{ - private Tile[] _tiles; - private Vector2 _offset = Vector2.Zero; - - /// - /// Gets a read-only span of the elements in this . - /// - public ReadOnlySpan Tiles => _tiles; - - /// - /// Gets the name assigned to this . - /// - public string Name { get; } - - /// - /// Gets or Sets the source referenced by the elements in this - /// . - /// - public Tileset Tileset { get; set; } - - /// - /// Gets the total number of columns in this . - /// - public int Columns { get; } - - /// - /// Gets the total number of rows in this . - /// - public int Rows { get; } - - /// - /// Gets the width, in pixels, of this . - /// Width = Tileset.TileWidth * Columns - /// - public int Width => Tileset.TileWidth * Columns; - - /// - /// Gets the height, in pixels, of this . - /// Height = Tileset.TileHeight * Rows - /// - public int Height => Tileset.TileHeight * Rows; - - /// - /// Gets or Sets the transparency of this . - /// - public float Transparency { get; set; } = 1.0f; - - /// - /// Gets or Sets a value that indicates whether this is visible and should be - /// rendered. - /// - public bool IsVisible { get; set; } = true; - - /// - /// Gets or Sets the x- and y-coordinate position offset, relative to the position of the , - /// to render this at - /// - public Vector2 Offset - { - get => _offset; - set => _offset = value; - } - - /// - /// Gets or Sets the x-position offset, relative to the position of the , to render this - /// at - /// - public float OffsetX - { - get => _offset.X; - set => _offset.X = value; - } - - /// - /// Gets or Sets the y-position offset, relative to the position of the , to render this - /// at - /// - public float OffsetY - { - get => _offset.Y; - set => _offset.Y = value; - } - - /// - /// Gets the total number of elements in this . - /// - public int TileCount => _tiles.Length; - - /// - /// Gets the element at the specified index in this - /// - /// - /// The index of the element to locate. - /// - /// - /// The element located. - /// - /// - /// Thrown if the index specified is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public Tile this[int tileIndex] => GetTile(tileIndex); - - /// - /// Gets the element located at the specified column and row in this - /// . - /// - /// - /// The column of the element to locate. - /// - /// - /// The row of the element to locate. - /// - /// - /// The element located. - /// - /// - /// Thrown if either the column or rows specified is less than zero or if either is greater than or equal to the - /// total number of columns or rows in this . - /// - public Tile this[int column, int row] => GetTile(column, row); - - /// - /// Gets the element located at the specified column and row location in this - /// . - /// - /// - /// The column and row location of the element to locate. - /// - /// - /// The element located. - /// - /// - /// Thrown if either the column or rows specified in the location is less than zero or if either is greater - /// than or equal to the total number of columns or rows in this . - /// - public Tile this[Point location] => GetTile(location); - - /// - /// Initializes a new instance of the class. - /// - /// - /// The name assign the . - /// - /// - /// The source tileset used by the tiles in this . - /// - /// - /// The total number of columns to assign the . - /// - /// - /// The total number of rows to assign the . - /// - /// - /// The x- and y-coordinate position offset, relative to the position of the to assign the - /// . - /// - public TilemapLayer(string name, Tileset tileset, int columns, int rows, Vector2 offset) - { - Tileset = tileset; - Name = name; - _offset = offset; - Columns = columns; - Rows = rows; - _tiles = new Tile[columns * rows]; - } - - /// - /// Returns a value that indicates whether the element at the specified index in this - /// is empty. - /// - /// - /// The index of the element to check. - /// - /// - /// if the element at the specified index is empty; otherwise, - /// . - /// - /// - /// Thrown if the index specified is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public bool IsEmpty(int index) => GetTile(index).IsEmpty; - - /// - /// Returns a value that indicates whether the element at the specified column and row in - /// this is empty. - /// - /// - /// The column of the element to check. - /// - /// - /// The row of the element to check. - /// - /// - /// if the element at the specified column and row in this - /// is empty; otherwise, . - /// - /// - /// Thrown if either the column or row specified is less than zero or if either is greater than or equal to the - /// total number of columns or rows in this . - /// - public bool IsEmpty(int column, int row) => GetTile(column, row).IsEmpty; - - /// - /// Returns a value that indicates whether the element at the specified column and row - /// location in this is empty. - /// - /// - /// The column and row location of the element to check. - /// - /// - /// if the element at the specified column and row location in this - /// is empty; otherwise, . - /// - /// - /// Thrown if either the column or row in the specified location is less than zero or if either is greater - /// than or equal to the total number of columns or rows in this . - /// - public bool IsEmpty(Point location) => GetTile(location).IsEmpty; - - /// - /// Sets the element at the specified index in this using the - /// values provided. - /// - /// - /// The index of the element in this to set. - /// - /// - /// The ID of the source tile in the that represents the to - /// render for the element being set. - /// - /// - /// Indicates whether the element being set should be flipped horizontally when rendered. - /// - /// - /// Indicates if the element being set should be flipped vertically when rendered. - /// - /// - /// Indicates if the element being set should be flipped diagonally when rendered. - /// - /// - /// Thrown if the index specified is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public void SetTile(int index, int tilesetTileID, bool flipHorizontally = false, bool flipVertically = false, bool flipDiagonally = false) - { - Tile tile; - tile.TilesetTileID = tilesetTileID; - tile.FlipHorizontally = flipHorizontally; - tile.FlipVertically = flipVertically; - tile.FlipDiagonally = flipDiagonally; - SetTile(index, tile); - } - - /// - /// Sets the element at the specified column and row in this - /// using the values provided. - /// - /// - /// The column in this to set the element at. - /// - /// - /// The row in this to set the element at. - /// - /// - /// The ID of the source tile in the that represents the to - /// render for the element being set. - /// - /// - /// Indicates whether the element being set should be flipped horizontally when rendered. - /// - /// - /// Indicates if the element being set should be flipped vertically when rendered. - /// - /// - /// Indicates if the element being set should be flipped diagonally when rendered. - /// - /// - /// Thrown if either the column or row specified is less than zero or are greater than or equal to the total - /// number of columns or rows in this . - /// - public void SetTile(int column, int row, int tilesetTileID, bool flipHorizontally = false, bool flipVertically = false, bool flipDiagonally = false) - { - Tile tile; - tile.TilesetTileID = tilesetTileID; - tile.FlipHorizontally = flipHorizontally; - tile.FlipVertically = flipVertically; - tile.FlipDiagonally = flipDiagonally; - SetTile(column, row, tile); - } - - /// - /// Sets the element at the specified column and row location in this - /// using the values provided. - /// - /// - /// The column and row location in this to set the element at. - /// - /// - /// The ID of the source tile in the that represents the to - /// render for the element being set. - /// - /// - /// Indicates whether the element being set should be flipped horizontally when rendered. - /// - /// - /// Indicates if the element being set should be flipped vertically when rendered. - /// - /// - /// Indicates if the element being set should be flipped diagonally when rendered. - /// - /// - /// Thrown if either the column or row in the specified location is less than zero or are greater than or equal - /// to the total number of columns or rows in this . - /// - public void SetTile(Point location, int tilesetTileID, bool flipHorizontally = false, bool flipVertically = false, bool flipDiagonally = false) - { - Tile tile; - tile.TilesetTileID = tilesetTileID; - tile.FlipHorizontally = flipHorizontally; - tile.FlipVertically = flipVertically; - tile.FlipDiagonally = flipDiagonally; - SetTile(location, tile); - } - - /// - /// Sets the specified index in this to the element given. - /// - /// - /// The index in this to set. - /// - /// - /// The element to set at the index. - /// - /// - /// Thrown if the index specified is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public void SetTile(int index, Tile tile) - { - CheckIndex(index); - _tiles[index] = tile; - } - - /// - /// Sets the specified column and row in this to the element - /// given. - /// - /// - /// The column in this to set. - /// - /// - /// The row in this to set. - /// - /// - /// The element to set at the column and row. - /// - /// - /// Thrown if either the column or row specified are less than zero or are greater than or equal to the total - /// number of columns or rows in this . - /// - public void SetTile(int column, int row, Tile tile) - { - CheckColumn(column); - CheckRow(row); - int index = ToIndex(column, row); - _tiles[index] = tile; - } - - /// - /// Sets the specified column and row location in this to the - /// element given. - /// - /// - /// The column and row location in this to set. - /// - /// - /// The element to set at the column and row location. - /// - /// - /// Thrown if either the column or row in the specified location are less than zero or are greater than or equal - /// to the total number of columns or rows in this . - /// - public void SetTile(Point location, Tile tile) - { - CheckLocation(location); - int index = ToIndex(location.X, location.Y); - _tiles[index] = tile; - } - - /// - /// Gets the element located at the specified index in this . - /// - /// - /// The index of the element in this to locate. - /// - /// - /// The element located - /// - /// - /// Thrown if the index specified is less than zero or is greater than or equal to the total number of - /// elements in this . - /// - public Tile GetTile(int index) - { - CheckIndex(index); - return _tiles[index]; - } - - /// - /// Gets the element located at the specified column and row in this - /// . - /// - /// - /// The column of the element to locate. - /// - /// - /// The row of the element to locate. - /// - /// - /// The element located. - /// - /// - /// Thrown if either the column or rows specified are less than zero or are greater than or equal to the total - /// number of columns or rows in this . - /// - public Tile GetTile(int column, int row) - { - CheckColumn(column); - CheckRow(row); - int index = ToIndex(column, row); - return _tiles[index]; - } - - /// - /// Gets the element located at the specified column and row location in this - /// . - /// - /// - /// The column and row location of the element to locate. - /// - /// - /// The element located. - /// - /// - /// Thrown if either the column or rows in the specified location are less than zero or are greater than or - /// equal to the total number of columns or rows in this . - /// - public Tile GetTile(Point location) - { - CheckLocation(location); - int index = ToIndex(location.X, location.Y); - return _tiles[index]; - } - - - /// - /// Clears all elements in this by resetting them to an empty - /// value. - /// - public void Clear() - { - Array.Clear(_tiles); - } - - /// - /// Draws this layer using the - /// . - /// - /// - /// The to use for rendering this - /// . - /// - /// - /// The x- and y-coordinate location to draw this at. Drawing this - /// using this method ignores the . - /// - /// - /// The color mask to apply when rendering this . - /// - public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color) => - Draw(spriteBatch, position, color, Vector2.One, 0.0f); - - /// - /// Draws this layer using the - /// . - /// - /// - /// The to use for rendering this - /// . - /// - /// - /// The x- and y-coordinate location to draw this at. Drawing this - /// using this method ignores the . - /// - /// - /// The color mask to apply when rendering this . - /// - /// - /// The amount of scaling to apply when rendering this . - /// - /// - /// The layer depth to apply when rendering this . - /// - public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, float scale, float layerDepth) => - Draw(spriteBatch, position, color, new Vector2(scale, scale), layerDepth); - - /// - /// Draws this layer using the - /// . - /// - /// - /// The to use for rendering this - /// . - /// - /// - /// The x- and y-coordinate location to draw this at. Drawing this - /// using this method ignores the . - /// - /// - /// The color mask to apply when rendering this . - /// - /// - /// The amount of scaling to apply when rendering this . - /// - /// - /// The layer depth to apply when rendering this . - /// - public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, Vector2 scale, float layerDepth) => - spriteBatch.Draw(this, position, color, scale, layerDepth); - - - /// - /// Returns an enumerator that iterates through all elements in this - /// . The order tiles in the enumeration is from top-to-bottom, read left-to-right. - /// - /// - /// An enumerator that iterates through all elements in this . - /// - public IEnumerator GetEnumerator() - { - for (int i = 0; i < _tiles.Length; i++) - { - yield return _tiles[i]; - } - } - - /// - /// Returns an enumerator that iterates through all elements in this - /// . The order tiles in the enumeration is from top-to-bottom, read left-to-right. - /// - /// - /// An enumerator that iterates through all elements in this . - /// - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - private int ToIndex(int column, int row) => row * Columns + column; - - private void CheckIndex(int index) - { - if (index < 0 || index >= TileCount) - { - ArgumentOutOfRangeException ex = new(nameof(index), $"{nameof(index)} cannot be less than zero or greater than or equal to the total number of tiles in this tilemap layer."); - ex.Data.Add(nameof(index), index); - ex.Data.Add(nameof(TileCount), TileCount); - throw ex; - } - } - - private void CheckRow(int row) - { - if (row < 0 || row >= Rows) - { - ArgumentOutOfRangeException ex = new(nameof(row), $"{nameof(row)} cannot be less than zero or greater than or equal to the total number of rows in this tilemap layer."); - ex.Data.Add(nameof(row), row); - ex.Data.Add(nameof(Rows), Rows); - throw ex; - } - } - - private void CheckColumn(int column) - { - if (column < 0 || column >= Columns) - { - ArgumentOutOfRangeException ex = new(nameof(column), $"{nameof(column)} cannot be less than zero or greater than or equal to the total number of columns in this tilemap layer."); - ex.Data.Add(nameof(column), column); - ex.Data.Add(nameof(Columns), Columns); - throw ex; - } - } - - private void CheckLocation(Point location) - { - if (location.X < 0 || location.X >= Columns) - { - ArgumentOutOfRangeException ex = new(nameof(location), $"The column in the location cannot be less than zero or greater than or equal to the total number of columns in this tilemap layer."); - ex.Data.Add(nameof(location), location); - ex.Data.Add(nameof(Columns), Columns); - throw ex; - } - - if (location.Y < 0 || location.Y >= Rows) - { - ArgumentOutOfRangeException ex = new(nameof(location), $"The row in the location cannot be less than zero or greater than or equal to the total number of rows in this tilemap layer."); - ex.Data.Add(nameof(location), location); - ex.Data.Add(nameof(Rows), Rows); - throw ex; - } - } -} +/* ---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2018-2023 Christopher Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------------------------------------------------- */ + +using System.Collections; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace MonoGame.Aseprite; + +/// +/// Defines a grid-like layer in a tilemap that contains a collection of tiles. +/// +public sealed class TilemapLayer : IEnumerable +{ + private Tile[] _tiles; + private Vector2 _offset = Vector2.Zero; + + /// + /// Gets a read-only span of the elements in this . + /// + public ReadOnlySpan Tiles => _tiles; + + /// + /// Gets the name assigned to this . + /// + public string Name { get; } + + /// + /// Gets or Sets the source referenced by the elements in this + /// . + /// + public Tileset Tileset { get; set; } + + /// + /// Gets the total number of columns in this . + /// + public int Columns { get; } + + /// + /// Gets the total number of rows in this . + /// + public int Rows { get; } + + /// + /// Gets the width, in pixels, of this . + /// Width = Tileset.TileWidth * Columns + /// + public int Width => Tileset.TileWidth * Columns; + + /// + /// Gets the height, in pixels, of this . + /// Height = Tileset.TileHeight * Rows + /// + public int Height => Tileset.TileHeight * Rows; + + /// + /// Gets or Sets the transparency of this . + /// + public float Transparency { get; set; } = 1.0f; + + /// + /// Gets or Sets a value that indicates whether this is visible and should be + /// rendered. + /// + public bool IsVisible { get; set; } = true; + + /// + /// Gets or Sets the x- and y-coordinate position offset, relative to the position of the , + /// to render this at + /// + public Vector2 Offset + { + get => _offset; + set => _offset = value; + } + + /// + /// Gets or Sets the x-position offset, relative to the position of the , to render this + /// at + /// + public float OffsetX + { + get => _offset.X; + set => _offset.X = value; + } + + /// + /// Gets or Sets the y-position offset, relative to the position of the , to render this + /// at + /// + public float OffsetY + { + get => _offset.Y; + set => _offset.Y = value; + } + + /// + /// Gets the total number of elements in this . + /// + public int TileCount => _tiles.Length; + + /// + /// Gets the element at the specified index in this + /// + /// + /// The index of the element to locate. + /// + /// + /// The element located. + /// + /// + /// Thrown if the index specified is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public Tile this[int tileIndex] => GetTile(tileIndex); + + /// + /// Gets the element located at the specified column and row in this + /// . + /// + /// + /// The column of the element to locate. + /// + /// + /// The row of the element to locate. + /// + /// + /// The element located. + /// + /// + /// Thrown if either the column or rows specified is less than zero or if either is greater than or equal to the + /// total number of columns or rows in this . + /// + public Tile this[int column, int row] => GetTile(column, row); + + /// + /// Gets the element located at the specified column and row location in this + /// . + /// + /// + /// The column and row location of the element to locate. + /// + /// + /// The element located. + /// + /// + /// Thrown if either the column or rows specified in the location is less than zero or if either is greater + /// than or equal to the total number of columns or rows in this . + /// + public Tile this[Point location] => GetTile(location); + + /// + /// Initializes a new instance of the class. + /// + /// + /// The name assign the . + /// + /// + /// The source tileset used by the tiles in this . + /// + /// + /// The total number of columns to assign the . + /// + /// + /// The total number of rows to assign the . + /// + /// + /// The x- and y-coordinate position offset, relative to the position of the to assign the + /// . + /// + public TilemapLayer(string name, Tileset tileset, int columns, int rows, Vector2 offset) + { + Tileset = tileset; + Name = name; + _offset = offset; + Columns = columns; + Rows = rows; + _tiles = new Tile[columns * rows]; + } + + /// + /// Returns a value that indicates whether the element at the specified index in this + /// is empty. + /// + /// + /// The index of the element to check. + /// + /// + /// if the element at the specified index is empty; otherwise, + /// . + /// + /// + /// Thrown if the index specified is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public bool IsEmpty(int index) => GetTile(index).IsEmpty; + + /// + /// Returns a value that indicates whether the element at the specified column and row in + /// this is empty. + /// + /// + /// The column of the element to check. + /// + /// + /// The row of the element to check. + /// + /// + /// if the element at the specified column and row in this + /// is empty; otherwise, . + /// + /// + /// Thrown if either the column or row specified is less than zero or if either is greater than or equal to the + /// total number of columns or rows in this . + /// + public bool IsEmpty(int column, int row) => GetTile(column, row).IsEmpty; + + /// + /// Returns a value that indicates whether the element at the specified column and row + /// location in this is empty. + /// + /// + /// The column and row location of the element to check. + /// + /// + /// if the element at the specified column and row location in this + /// is empty; otherwise, . + /// + /// + /// Thrown if either the column or row in the specified location is less than zero or if either is greater + /// than or equal to the total number of columns or rows in this . + /// + public bool IsEmpty(Point location) => GetTile(location).IsEmpty; + + /// + /// Sets the element at the specified index in this using the + /// values provided. + /// + /// + /// The index of the element in this to set. + /// + /// + /// The ID of the source tile in the that represents the to + /// render for the element being set. + /// + /// + /// Indicates whether the element being set should be flipped horizontally when rendered. + /// + /// + /// Indicates if the element being set should be flipped vertically when rendered. + /// + /// + /// Indicates if the element being set should be flipped diagonally when rendered. + /// + /// + /// Thrown if the index specified is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public void SetTile(int index, int tilesetTileID, bool flipHorizontally = false, bool flipVertically = false, bool flipDiagonally = false) + { + Tile tile; + tile.TilesetTileID = tilesetTileID; + tile.FlipHorizontally = flipHorizontally; + tile.FlipVertically = flipVertically; + tile.FlipDiagonally = flipDiagonally; + SetTile(index, tile); + } + + /// + /// Sets the element at the specified column and row in this + /// using the values provided. + /// + /// + /// The column in this to set the element at. + /// + /// + /// The row in this to set the element at. + /// + /// + /// The ID of the source tile in the that represents the to + /// render for the element being set. + /// + /// + /// Indicates whether the element being set should be flipped horizontally when rendered. + /// + /// + /// Indicates if the element being set should be flipped vertically when rendered. + /// + /// + /// Indicates if the element being set should be flipped diagonally when rendered. + /// + /// + /// Thrown if either the column or row specified is less than zero or are greater than or equal to the total + /// number of columns or rows in this . + /// + public void SetTile(int column, int row, int tilesetTileID, bool flipHorizontally = false, bool flipVertically = false, bool flipDiagonally = false) + { + Tile tile; + tile.TilesetTileID = tilesetTileID; + tile.FlipHorizontally = flipHorizontally; + tile.FlipVertically = flipVertically; + tile.FlipDiagonally = flipDiagonally; + SetTile(column, row, tile); + } + + /// + /// Sets the element at the specified column and row location in this + /// using the values provided. + /// + /// + /// The column and row location in this to set the element at. + /// + /// + /// The ID of the source tile in the that represents the to + /// render for the element being set. + /// + /// + /// Indicates whether the element being set should be flipped horizontally when rendered. + /// + /// + /// Indicates if the element being set should be flipped vertically when rendered. + /// + /// + /// Indicates if the element being set should be flipped diagonally when rendered. + /// + /// + /// Thrown if either the column or row in the specified location is less than zero or are greater than or equal + /// to the total number of columns or rows in this . + /// + public void SetTile(Point location, int tilesetTileID, bool flipHorizontally = false, bool flipVertically = false, bool flipDiagonally = false) + { + Tile tile; + tile.TilesetTileID = tilesetTileID; + tile.FlipHorizontally = flipHorizontally; + tile.FlipVertically = flipVertically; + tile.FlipDiagonally = flipDiagonally; + SetTile(location, tile); + } + + /// + /// Sets the specified index in this to the element given. + /// + /// + /// The index in this to set. + /// + /// + /// The element to set at the index. + /// + /// + /// Thrown if the index specified is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public void SetTile(int index, Tile tile) + { + CheckIndex(index); + _tiles[index] = tile; + } + + /// + /// Sets the specified column and row in this to the element + /// given. + /// + /// + /// The column in this to set. + /// + /// + /// The row in this to set. + /// + /// + /// The element to set at the column and row. + /// + /// + /// Thrown if either the column or row specified are less than zero or are greater than or equal to the total + /// number of columns or rows in this . + /// + public void SetTile(int column, int row, Tile tile) + { + CheckColumn(column); + CheckRow(row); + int index = ToIndex(column, row); + _tiles[index] = tile; + } + + /// + /// Sets the specified column and row location in this to the + /// element given. + /// + /// + /// The column and row location in this to set. + /// + /// + /// The element to set at the column and row location. + /// + /// + /// Thrown if either the column or row in the specified location are less than zero or are greater than or equal + /// to the total number of columns or rows in this . + /// + public void SetTile(Point location, Tile tile) + { + CheckLocation(location); + int index = ToIndex(location.X, location.Y); + _tiles[index] = tile; + } + + /// + /// Gets the element located at the specified index in this . + /// + /// + /// The index of the element in this to locate. + /// + /// + /// The element located + /// + /// + /// Thrown if the index specified is less than zero or is greater than or equal to the total number of + /// elements in this . + /// + public Tile GetTile(int index) + { + CheckIndex(index); + return _tiles[index]; + } + + /// + /// Gets the element located at the specified column and row in this + /// . + /// + /// + /// The column of the element to locate. + /// + /// + /// The row of the element to locate. + /// + /// + /// The element located. + /// + /// + /// Thrown if either the column or rows specified are less than zero or are greater than or equal to the total + /// number of columns or rows in this . + /// + public Tile GetTile(int column, int row) + { + CheckColumn(column); + CheckRow(row); + int index = ToIndex(column, row); + return _tiles[index]; + } + + /// + /// Gets the element located at the specified column and row location in this + /// . + /// + /// + /// The column and row location of the element to locate. + /// + /// + /// The element located. + /// + /// + /// Thrown if either the column or rows in the specified location are less than zero or are greater than or + /// equal to the total number of columns or rows in this . + /// + public Tile GetTile(Point location) + { + CheckLocation(location); + int index = ToIndex(location.X, location.Y); + return _tiles[index]; + } + + + /// + /// Clears all elements in this by resetting them to an empty + /// value. + /// + public void Clear() + { + Array.Clear(_tiles); + } + + /// + /// Draws this layer using the + /// . + /// + /// + /// The to use for rendering this + /// . + /// + /// + /// The x- and y-coordinate location to draw this at. Drawing this + /// using this method ignores the . + /// + /// + /// The color mask to apply when rendering this . + /// + public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color) => + Draw(spriteBatch, position, color, Vector2.One, 0.0f); + + /// + /// Draws this layer using the + /// . + /// + /// + /// The to use for rendering this + /// . + /// + /// + /// The x- and y-coordinate location to draw this at. Drawing this + /// using this method ignores the . + /// + /// + /// The color mask to apply when rendering this . + /// + /// + /// The amount of scaling to apply when rendering this . + /// + /// + /// The layer depth to apply when rendering this . + /// + public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, float scale, float layerDepth) => + Draw(spriteBatch, position, color, new Vector2(scale, scale), layerDepth); + + /// + /// Draws this layer using the + /// . + /// + /// + /// The to use for rendering this + /// . + /// + /// + /// The x- and y-coordinate location to draw this at. Drawing this + /// using this method ignores the . + /// + /// + /// The color mask to apply when rendering this . + /// + /// + /// The amount of scaling to apply when rendering this . + /// + /// + /// The layer depth to apply when rendering this . + /// + public void Draw(SpriteBatch spriteBatch, Vector2 position, Color color, Vector2 scale, float layerDepth) => + spriteBatch.Draw(this, position, color, scale, layerDepth); + + + /// + /// Returns an enumerator that iterates through all elements in this + /// . The order tiles in the enumeration is from top-to-bottom, read left-to-right. + /// + /// + /// An enumerator that iterates through all elements in this . + /// + public IEnumerator GetEnumerator() + { + for (int i = 0; i < _tiles.Length; i++) + { + yield return _tiles[i]; + } + } + + /// + /// Returns an enumerator that iterates through all elements in this + /// . The order tiles in the enumeration is from top-to-bottom, read left-to-right. + /// + /// + /// An enumerator that iterates through all elements in this . + /// + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + private int ToIndex(int column, int row) => row * Columns + column; + + private void CheckIndex(int index) + { + if (index < 0 || index >= TileCount) + { + ArgumentOutOfRangeException ex = new(nameof(index), $"{nameof(index)} cannot be less than zero or greater than or equal to the total number of tiles in this tilemap layer."); + ex.Data.Add(nameof(index), index); + ex.Data.Add(nameof(TileCount), TileCount); + throw ex; + } + } + + private void CheckRow(int row) + { + if (row < 0 || row >= Rows) + { + ArgumentOutOfRangeException ex = new(nameof(row), $"{nameof(row)} cannot be less than zero or greater than or equal to the total number of rows in this tilemap layer."); + ex.Data.Add(nameof(row), row); + ex.Data.Add(nameof(Rows), Rows); + throw ex; + } + } + + private void CheckColumn(int column) + { + if (column < 0 || column >= Columns) + { + ArgumentOutOfRangeException ex = new(nameof(column), $"{nameof(column)} cannot be less than zero or greater than or equal to the total number of columns in this tilemap layer."); + ex.Data.Add(nameof(column), column); + ex.Data.Add(nameof(Columns), Columns); + throw ex; + } + } + + private void CheckLocation(Point location) + { + if (location.X < 0 || location.X >= Columns) + { + ArgumentOutOfRangeException ex = new(nameof(location), $"The column in the location cannot be less than zero or greater than or equal to the total number of columns in this tilemap layer."); + ex.Data.Add(nameof(location), location); + ex.Data.Add(nameof(Columns), Columns); + throw ex; + } + + if (location.Y < 0 || location.Y >= Rows) + { + ArgumentOutOfRangeException ex = new(nameof(location), $"The row in the location cannot be less than zero or greater than or equal to the total number of rows in this tilemap layer."); + ex.Data.Add(nameof(location), location); + ex.Data.Add(nameof(Rows), Rows); + throw ex; + } + } +} diff --git a/source/MonoGame.Aseprite/Tilemaps/Tileset.cs b/source/MonoGame.Aseprite/Tileset.cs similarity index 91% rename from source/MonoGame.Aseprite/Tilemaps/Tileset.cs rename to source/MonoGame.Aseprite/Tileset.cs index 10e5886b..e14c5b03 100644 --- a/source/MonoGame.Aseprite/Tilemaps/Tileset.cs +++ b/source/MonoGame.Aseprite/Tileset.cs @@ -1,369 +1,350 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.Diagnostics.CodeAnalysis; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using MonoGame.Aseprite.Utils; - - -namespace MonoGame.Aseprite.Tilemaps; - -/// -/// Defines a with a source image and named elements that -/// represent the tiles. -/// -/// -/// A is similar in function to a in that it uses a single -/// source image and has named for sections within that image. The difference is that -/// a autogenerates the elements into a grid like structure and -/// the accessor for each is by location id or column and row only. -/// -public sealed class Tileset -{ - private TextureRegion[] _regions; - - /// - /// Gets the name assigned to this . - /// - public string Name { get; } - - /// - /// Gets the source texture image used by this . - /// - public Texture2D Texture { get; } - - /// - /// Gets the width, in pixels, of each tile in this . - /// - public int TileWidth { get; } - - /// - /// Gets the height, in pixels of each tile in this . - /// - public int TileHeight { get; } - - /// - /// Gets the total number of rows in this . - /// - public int RowCount { get; } - - /// - /// Gets the total number of columns in this . - /// - public int ColumnCount { get; } - - /// - /// G ets the total number of tiles in this . - /// - public int TileCount { get; } - - /// - /// Gets a read-only span of the elements that represent the tiles in this - /// . - /// - public ReadOnlySpan Tiles => _regions; - - /// - /// Gets the of the tile at the specified index in this . - /// - /// - /// The index of the tile to locate. - /// - /// - /// The for the tile located. - /// - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of tiles in - /// this . - /// - public TextureRegion this[int index] => GetTile(index); - - /// - /// Gets the for the tile at the specified column and row in this - /// . - /// - /// - /// The column of the tile to locate in this . - /// - /// - /// The row of the tile to locate in this . - /// - /// - /// The for the tile located. - /// - /// - /// Thrown if either the column or row specified are less than zero or if either are greater than or equal to - /// the total number of columns or rows in this . - /// - public TextureRegion this[int column, int row] => GetTile(column, row); - - /// - /// Gets the for the tile at the specified column and row location in this - /// . - /// - /// - /// The column and row location of the tile to locate in this . - /// - /// - /// The for the tile located. - /// - /// - /// Thrown if either the column or row in the location specified are less than zero or if either are greater - /// than or equal to the total number of columns or rows in this . - /// - public TextureRegion this[Point location] => GetTile(location); - - /// - /// Initializes a new instance of the class. - /// - /// - /// The elements for each tile in this are auto-generated - /// based on the and specified. Both of these values - /// must be greater than zero and the width of the must divide evenly by - /// the and the height of the must divide evenly by the - /// - /// - /// - /// The name to assign the . - /// - /// - /// The source texture used by this . - /// - /// - /// The width, in pixels, of each tile in this . - /// - /// - /// The height, in pixels, of each tile in this . - /// - /// - /// Thrown if the or values are less than one. - /// - /// - /// Thrown if the width of the does not divide evenly by the - /// specified or if the height of the does not divide - /// evenly by the specified. - /// - public Tileset(string name, Texture2D texture, int tileWidth, int tileHeight) - { - if (tileWidth < 1) - { - throw new ArgumentOutOfRangeException(nameof(tileWidth), $"{nameof(tileWidth)} must be greater than zero"); - } - - if (tileHeight < 1) - { - throw new ArgumentOutOfRangeException(nameof(tileHeight), $"{nameof(tileHeight)} must be greater than zero"); - } - - if (texture.Width % tileWidth != 0) - { - throw new ArgumentException($"The texture width ({texture.Width}) does not divide evenly by the tile width ({tileWidth} given."); - } - - if (texture.Height % tileHeight != 0) - { - throw new ArgumentException($"The texture height ({texture.Height}) does not divide evenly by the tile height ({tileHeight}) given."); - } - - Name = name; - Texture = texture; - TileWidth = tileWidth; - TileHeight = tileHeight; - ColumnCount = texture.Width / tileWidth; - RowCount = texture.Height / tileHeight; - TileCount = ColumnCount * RowCount; - CreateTextureRegions(); - } - - [MemberNotNull(nameof(_regions))] - private void CreateTextureRegions() - { - _regions = new TextureRegion[TileCount]; - - for (int i = 0; i < TileCount; i++) - { - int x = (i % ColumnCount) * TileWidth; - int y = (i / ColumnCount) * TileHeight; - - Rectangle bounds = new(x, y, TileWidth, TileHeight); - _regions[i] = new TextureRegion($"{Name}_{i}", Texture, bounds); - } - } - - /// - /// Gets the of the tile at the specified index in this . - /// - /// - /// The index of the tile to locate. - /// - /// - /// The for the tile located. - /// - /// - /// Thrown if the specified index is less than zero or is greater than or equal to the total number of tiles in - /// this . - /// - public TextureRegion GetTile(int index) - { - if (index < 0 || index >= TileCount) - { - throw new ArgumentOutOfRangeException(); - } - - return _regions[index]; - } - - /// - /// Gets the for the tile at the specified column and row in this - /// . - /// - /// - /// The column and row location of the tile to locate in this . - /// - /// - /// The for the tile located. - /// - /// - /// Thrown if either the column or row in the specified location are less than zero or if either are greater - /// than or equal to the total number of columns or rows respectively. - /// - public TextureRegion GetTile(Point location) => GetTile(location.X, location.Y); - - /// - /// Gets the for the tile at the specified column and row in this - /// . - /// - /// - /// The column of the tile to locate in this . - /// - /// - /// The row of the tile to locate in this . - /// - /// - /// The for the tile located. - /// - /// - /// Thrown if either the column or row specified are less than zero or if either are greater than or equal to - /// the total number of columns or rows in this . - /// - public TextureRegion GetTile(int column, int row) - { - int index = row * ColumnCount + column; - return GetTile(index); - } - - /// - /// Gets the of the tile at the specified index in this - /// . - /// - /// - /// The index of the tile to locate. - /// - /// - /// When this method returns , contains the of the tile - /// located; otherwise, . - /// - /// - /// if a tile was located at the specified index; otherwise, . - /// This method returns if the specified index is less than zero or is greater than or - /// equal to the total number of tiles in this . - /// - public bool TryGetTile(int index, [NotNullWhen(true)] out TextureRegion? tile) - { - tile = default; - - if (index < 0 || index >= TileCount) - { - return false; - } - - tile = _regions[index]; - return true; - } - - /// - /// Gets the for the tile at the specified column and row in this - /// . - /// - /// - /// The column and row location of the tile to locate in this . - /// - /// - /// When this method returns , contains the of the tile - /// located; otherwise, . - /// - /// - /// if a tile was located at the specified column and row location; otherwise - /// . This method return if the column or row in the location - /// specified is less than zero or if either are greater than or equal to the total number of columns or rows - /// in this . - /// - public bool TryGetTile(Point location, [NotNullWhen(true)] out TextureRegion? tile) => - TryGetTile(location.X, location.Y, out tile); - - /// - /// Gets the for the tile at the specified column and row in this - /// . - /// - /// - /// The column of the tile to locate in this . - /// - /// - /// The row of the tile to locate in this . - /// - /// - /// When this method returns , contains the of the tile - /// located; otherwise, . - /// - /// - /// if a tile was located at the specified column and row; otherwise - /// . This method return if the column or row in the location - /// specified is less than zero or if either are greater than or equal to the total number of columns or rows - /// in this . - /// - public bool TryGetTile(int column, int row, [NotNullWhen(true)] out TextureRegion? tile) - { - int index = row * ColumnCount + column; - return TryGetTile(index, out tile); - } - - public static Tileset FromFile(GraphicsDevice device, AseFile file, int index) - { - AseTileset aseTileset = AseTilesetProcessor.Process(file, index); - return FromAseTileset(device, aseTileset); - } - - public static Tileset FromFile(GraphicsDevice device, AseFile file, string name) - { - AseTileset aseTileset = AseTilesetProcessor.Process(file, name); - return FromAseTileset(device, aseTileset); - } - - private static Tileset FromAseTileset(GraphicsDevice device, AseTileset aseTileset) - { - Texture2D texture = aseTileset.Texture.ToTexture2D(device); - return new Tileset(aseTileset.Name, texture, aseTileset.TileSize.Width, aseTileset.TileSize.Height); - } -} +/* ---------------------------------------------------------------------------- +MIT License + +Copyright (c) 2018-2023 Christopher Whitley + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +---------------------------------------------------------------------------- */ + +using System.Diagnostics.CodeAnalysis; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + + +namespace MonoGame.Aseprite; + +/// +/// Defines a with a source image and named elements that +/// represent the tiles. +/// +/// +/// A is similar in function to a in that it uses a single +/// source image and has named for sections within that image. The difference is that +/// a auto generates the elements into a grid like structure and +/// the accessor for each is by location id or column and row only. +/// +public sealed class Tileset +{ + private TextureRegion[] _regions; + + /// + /// Gets the name assigned to this . + /// + public string Name { get; } + + /// + /// Gets the source texture image used by this . + /// + public Texture2D Texture { get; } + + /// + /// Gets the width, in pixels, of each tile in this . + /// + public int TileWidth { get; } + + /// + /// Gets the height, in pixels of each tile in this . + /// + public int TileHeight { get; } + + /// + /// Gets the total number of rows in this . + /// + public int RowCount { get; } + + /// + /// Gets the total number of columns in this . + /// + public int ColumnCount { get; } + + /// + /// G ets the total number of tiles in this . + /// + public int TileCount { get; } + + /// + /// Gets a read-only span of the elements that represent the tiles in this + /// . + /// + public ReadOnlySpan Tiles => _regions; + + /// + /// Gets the of the tile at the specified index in this . + /// + /// + /// The index of the tile to locate. + /// + /// + /// The for the tile located. + /// + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of tiles in + /// this . + /// + public TextureRegion this[int index] => GetTile(index); + + /// + /// Gets the for the tile at the specified column and row in this + /// . + /// + /// + /// The column of the tile to locate in this . + /// + /// + /// The row of the tile to locate in this . + /// + /// + /// The for the tile located. + /// + /// + /// Thrown if either the column or row specified are less than zero or if either are greater than or equal to + /// the total number of columns or rows in this . + /// + public TextureRegion this[int column, int row] => GetTile(column, row); + + /// + /// Gets the for the tile at the specified column and row location in this + /// . + /// + /// + /// The column and row location of the tile to locate in this . + /// + /// + /// The for the tile located. + /// + /// + /// Thrown if either the column or row in the location specified are less than zero or if either are greater + /// than or equal to the total number of columns or rows in this . + /// + public TextureRegion this[Point location] => GetTile(location); + + /// + /// Initializes a new instance of the class. + /// + /// + /// The elements for each tile in this are auto-generated + /// based on the and specified. Both of these values + /// must be greater than zero and the width of the must divide evenly by + /// the and the height of the must divide evenly by the + /// + /// + /// + /// The name to assign the . + /// + /// + /// The source texture used by this . + /// + /// + /// The width, in pixels, of each tile in this . + /// + /// + /// The height, in pixels, of each tile in this . + /// + /// + /// Thrown if the or values are less than one. + /// + /// + /// Thrown if the width of the does not divide evenly by the + /// specified or if the height of the does not divide + /// evenly by the specified. + /// + public Tileset(string name, Texture2D texture, int tileWidth, int tileHeight) + { + if (tileWidth < 1) + { + throw new ArgumentOutOfRangeException(nameof(tileWidth), $"{nameof(tileWidth)} must be greater than zero"); + } + + if (tileHeight < 1) + { + throw new ArgumentOutOfRangeException(nameof(tileHeight), $"{nameof(tileHeight)} must be greater than zero"); + } + + if (texture.Width % tileWidth != 0) + { + throw new ArgumentException($"The texture width ({texture.Width}) does not divide evenly by the tile width ({tileWidth} given."); + } + + if (texture.Height % tileHeight != 0) + { + throw new ArgumentException($"The texture height ({texture.Height}) does not divide evenly by the tile height ({tileHeight}) given."); + } + + Name = name; + Texture = texture; + TileWidth = tileWidth; + TileHeight = tileHeight; + ColumnCount = texture.Width / tileWidth; + RowCount = texture.Height / tileHeight; + TileCount = ColumnCount * RowCount; + CreateTextureRegions(); + } + + [MemberNotNull(nameof(_regions))] + private void CreateTextureRegions() + { + _regions = new TextureRegion[TileCount]; + + for (int i = 0; i < TileCount; i++) + { + int x = i % ColumnCount * TileWidth; + int y = i / ColumnCount * TileHeight; + + Rectangle bounds = new(x, y, TileWidth, TileHeight); + _regions[i] = new TextureRegion($"{Name}_{i}", Texture, bounds); + } + } + + /// + /// Gets the of the tile at the specified index in this . + /// + /// + /// The index of the tile to locate. + /// + /// + /// The for the tile located. + /// + /// + /// Thrown if the specified index is less than zero or is greater than or equal to the total number of tiles in + /// this . + /// + public TextureRegion GetTile(int index) + { + if (index < 0 || index >= TileCount) + { + throw new ArgumentOutOfRangeException(); + } + + return _regions[index]; + } + + /// + /// Gets the for the tile at the specified column and row in this + /// . + /// + /// + /// The column and row location of the tile to locate in this . + /// + /// + /// The for the tile located. + /// + /// + /// Thrown if either the column or row in the specified location are less than zero or if either are greater + /// than or equal to the total number of columns or rows respectively. + /// + public TextureRegion GetTile(Point location) => GetTile(location.X, location.Y); + + /// + /// Gets the for the tile at the specified column and row in this + /// . + /// + /// + /// The column of the tile to locate in this . + /// + /// + /// The row of the tile to locate in this . + /// + /// + /// The for the tile located. + /// + /// + /// Thrown if either the column or row specified are less than zero or if either are greater than or equal to + /// the total number of columns or rows in this . + /// + public TextureRegion GetTile(int column, int row) + { + int index = row * ColumnCount + column; + return GetTile(index); + } + + /// + /// Gets the of the tile at the specified index in this + /// . + /// + /// + /// The index of the tile to locate. + /// + /// + /// When this method returns , contains the of the tile + /// located; otherwise, . + /// + /// + /// if a tile was located at the specified index; otherwise, . + /// This method returns if the specified index is less than zero or is greater than or + /// equal to the total number of tiles in this . + /// + public bool TryGetTile(int index, [NotNullWhen(true)] out TextureRegion? tile) + { + tile = default; + + if (index < 0 || index >= TileCount) + { + return false; + } + + tile = _regions[index]; + return true; + } + + /// + /// Gets the for the tile at the specified column and row in this + /// . + /// + /// + /// The column and row location of the tile to locate in this . + /// + /// + /// When this method returns , contains the of the tile + /// located; otherwise, . + /// + /// + /// if a tile was located at the specified column and row location; otherwise + /// . This method return if the column or row in the location + /// specified is less than zero or if either are greater than or equal to the total number of columns or rows + /// in this . + /// + public bool TryGetTile(Point location, [NotNullWhen(true)] out TextureRegion? tile) => + TryGetTile(location.X, location.Y, out tile); + + /// + /// Gets the for the tile at the specified column and row in this + /// . + /// + /// + /// The column of the tile to locate in this . + /// + /// + /// The row of the tile to locate in this . + /// + /// + /// When this method returns , contains the of the tile + /// located; otherwise, . + /// + /// + /// if a tile was located at the specified column and row; otherwise + /// . This method return if the column or row in the location + /// specified is less than zero or if either are greater than or equal to the total number of columns or rows + /// in this . + /// + public bool TryGetTile(int column, int row, [NotNullWhen(true)] out TextureRegion? tile) + { + int index = row * ColumnCount + column; + return TryGetTile(index, out tile); + } +} diff --git a/source/MonoGame.Aseprite/Utils/AsepriteDotNetExtensions.cs b/source/MonoGame.Aseprite/Utils/AsepriteDotNetExtensions.cs index 2bbc429e..421e0cd3 100644 --- a/source/MonoGame.Aseprite/Utils/AsepriteDotNetExtensions.cs +++ b/source/MonoGame.Aseprite/Utils/AsepriteDotNetExtensions.cs @@ -1,11 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; +using System.Runtime.CompilerServices; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using AseColor = AsepriteDotNet.Common.Rgba32; +using AsePoint = AsepriteDotNet.Common.Point; +using AseRectangle = AsepriteDotNet.Common.Rectangle; +using AseTexture = AsepriteDotNet.Texture; namespace MonoGame.Aseprite.Utils; diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props deleted file mode 100644 index c36f368d..00000000 --- a/tests/Directory.Build.props +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - test - - - - - - false - - - - - true - false - - - - - - - - - - - - - - - - - - - - - - - - CA1707 - - - \ No newline at end of file diff --git a/tests/MonoGame.Aseprite.Tests/AsepriteTypeTests/AsepriteFileTests.cs b/tests/MonoGame.Aseprite.Tests/AsepriteTypeTests/AsepriteFileTests.cs deleted file mode 100644 index 6679c650..00000000 --- a/tests/MonoGame.Aseprite.Tests/AsepriteTypeTests/AsepriteFileTests.cs +++ /dev/null @@ -1,80 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework; -using MonoGame.Aseprite.AsepriteTypes; - -namespace MonoGame.Aseprite.Tests; - -public sealed class AsepriteFileTests -{ - // https://github.com/AristurtleDev/monogame-aseprite/issues/93 - [Fact] - public void TryGetSlice_True_When_Slice_Exists() - { - Color[] palette = Array.Empty(); - AsepriteFrame[] frames = Array.Empty(); - AsepriteLayer[] layers = Array.Empty(); - AsepriteTag[] tags = Array.Empty(); - AsepriteTileset[] tilesets = Array.Empty(); - AsepriteUserData userData = new AsepriteUserData(); - - string expectedSliceName = "TestSlice"; - - AsepriteSlice[] slices = new AsepriteSlice[] - { - new AsepriteSlice(expectedSliceName, false, false, Array.Empty()) - }; - - AsepriteFile aseFile = new AsepriteFile("Test", 1, 1, palette, frames, layers, tags, slices, tilesets, userData); - - Assert.True(aseFile.TryGetSlice(expectedSliceName, out AsepriteSlice? slice)); - } - - [Fact] - public void Get_Frame_When_ZeroIndexed_False() - { - Color[] palette = Array.Empty(); - AsepriteFrame frame = new AsepriteFrame("Frame0", 1, 1, 1, Array.Empty()); - AsepriteFrame[] frames = new AsepriteFrame[] - { - new AsepriteFrame("Frame0", 1, 1, 1, Array.Empty()), - new AsepriteFrame("Frame1", 1, 1, 1, Array.Empty()) - }; - - AsepriteLayer[] layers = Array.Empty(); - AsepriteTag[] tags = Array.Empty(); - AsepriteTileset[] tilesets = Array.Empty(); - AsepriteUserData userData = new AsepriteUserData(); - - AsepriteSlice[] slices = Array.Empty(); - AsepriteFile aseFile = new AsepriteFile("Test", 1, 1, palette, frames, layers, tags, slices, tilesets, userData); - - aseFile.ZeroIndexedFrames = false; - - AsepriteFrame expected = frames[0]; - AsepriteFrame actual = aseFile.GetFrame(1); - Assert.Equal(expected, actual); - } -} diff --git a/tests/MonoGame.Aseprite.Tests/AsepriteTypeTests/AsepriteFrameTests.cs b/tests/MonoGame.Aseprite.Tests/AsepriteTypeTests/AsepriteFrameTests.cs deleted file mode 100644 index 077d4888..00000000 --- a/tests/MonoGame.Aseprite.Tests/AsepriteTypeTests/AsepriteFrameTests.cs +++ /dev/null @@ -1,165 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework; -using MonoGame.Aseprite.AsepriteTypes; - -namespace MonoGame.Aseprite.Tests; - -public sealed class AsepriteFrameTestsFixture -{ - public string Name { get; } - public AsepriteFrame Frame { get; } - - public AsepriteFrameTestsFixture() - { - Name = "aseprite-frame-test"; - - AsepriteTileset[] tilesets = new AsepriteTileset[] - { - new(0, 4, 1, 1, "tileset", new Color[] {Color.Transparent, Color.Yellow, Color.Purple, Color.Teal}) - }; - - AsepriteLayer[] layers = new AsepriteLayer[] - { - new(AsepriteLayerFlags.Visible | AsepriteLayerFlags.Background, AsepriteBlendMode.Normal, 255, "background"), - new(AsepriteLayerFlags.Visible, AsepriteBlendMode.Normal, 255, "visible"), - new AsepriteTilemapLayer(tilesets[0], AsepriteLayerFlags.Visible, AsepriteBlendMode.Normal, 255, "tilemap"), - new(AsepriteLayerFlags.None, AsepriteBlendMode.Normal, 255, "hidden") - }; - - AsepriteTile[] tiles = new AsepriteTile[] - { - new AsepriteTile(1, false, false, false), - new AsepriteTile(2, false, false, false), - new AsepriteTile(3, false, false, false), - new AsepriteTile(0, false, false, false) - }; - - AsepriteCel[] cels = new AsepriteCel[] - { - new AsepriteImageCel(2, 2, new Color[]{Color.Black, Color.Black, Color.Black, Color.Black}, layers[0], Point.Zero, 255), - new AsepriteImageCel(2, 2, new Color[]{Color.Red, Color.Transparent, Color.Transparent, Color.Red}, layers[1], Point.Zero, 255), - new AsepriteTilemapCel(2, 2, tiles, layers[2], Point.Zero, 255), - new AsepriteImageCel(2, 1, new Color[] {Color.White, Color.White}, layers[3], new Point(0, 1), 255) - }; - - Frame = new($"{Name} 0", 2, 2, 100, cels); - } -} - -public sealed class AsepriteFrameTests : IClassFixture -{ - private readonly AsepriteFrameTestsFixture _fixture; - - public AsepriteFrameTests(AsepriteFrameTestsFixture fixture) => _fixture = fixture; - - [Fact] - public void Flatten_OnlyVisible_True_IncludeBackground_True_IncludeTilemap_True() - { - Color[] expected = new Color[] { Color.Yellow, Color.Purple, Color.Teal, Color.Red }; - Color[] actual = _fixture.Frame.FlattenFrame(onlyVisibleLayers: true, - includeBackgroundLayer: true, - includeTilemapCel: true); - - Assert.Equal(expected, actual); - } - - [Fact] - public void Flatten_OnlyVisible_True_IncludeBackground_True_IncludeTilemap_False() - { - Color[] expected = new Color[] { Color.Red, Color.Black, Color.Black, Color.Red }; - Color[] actual = _fixture.Frame.FlattenFrame(onlyVisibleLayers: true, - includeBackgroundLayer: true, - includeTilemapCel: false); - - Assert.Equal(expected, actual); - } - - [Fact] - public void Flatten_OnlyVisible_True_IncludeBackground_False_IncludeTilemap_True() - { - Color[] expected = new Color[] { Color.Yellow, Color.Purple, Color.Teal, Color.Red }; - Color[] actual = _fixture.Frame.FlattenFrame(onlyVisibleLayers: true, - includeBackgroundLayer: false, - includeTilemapCel: true); - - Assert.Equal(expected, actual); - } - - [Fact] - public void Flatten_OnlyVisible_True_IncludeBackground_False_IncludeTilemap_False() - { - Color[] expected = new Color[] { Color.Red, Color.Transparent, Color.Transparent, Color.Red }; - Color[] actual = _fixture.Frame.FlattenFrame(onlyVisibleLayers: true, - includeBackgroundLayer: false, - includeTilemapCel: false); - - Assert.Equal(expected, actual); - } - - [Fact] - public void Flatten_OnlyVisible_False_IncludeBackground_True_IncludeTilemap_True() - { - Color[] expected = new Color[] { Color.Yellow, Color.Purple, Color.White, Color.White }; - Color[] actual = _fixture.Frame.FlattenFrame(onlyVisibleLayers: false, - includeBackgroundLayer: true, - includeTilemapCel: true); - - Assert.Equal(expected, actual); - } - - [Fact] - public void Flatten_OnlyVisible_False_IncludeBackground_True_IncludeTilemap_False() - { - Color[] expected = new Color[] { Color.Red, Color.Black, Color.White, Color.White }; - Color[] actual = _fixture.Frame.FlattenFrame(onlyVisibleLayers: false, - includeBackgroundLayer: true, - includeTilemapCel: false); - - Assert.Equal(expected, actual); - } - - [Fact] - public void Flatten_OnlyVisible_False_IncludeBackground_False_IncludeTilemap_True() - { - Color[] expected = new Color[] { Color.Yellow, Color.Purple, Color.White, Color.White }; - Color[] actual = _fixture.Frame.FlattenFrame(onlyVisibleLayers: false, - includeBackgroundLayer: false, - includeTilemapCel: true); - - Assert.Equal(expected, actual); - } - - [Fact] - public void Flatten_OnlyVisible_False_IncludeBackground_False_IncludeTilemap_False() - { - Color[] expected = new Color[] { Color.Red, Color.Transparent, Color.White, Color.White }; - Color[] actual = _fixture.Frame.FlattenFrame(onlyVisibleLayers: false, - includeBackgroundLayer: false, - includeTilemapCel: false); - - Assert.Equal(expected, actual); - } -} diff --git a/tests/MonoGame.Aseprite.Tests/ContentTests/AnimatedTilemapProcessorTests.cs b/tests/MonoGame.Aseprite.Tests/ContentTests/AnimatedTilemapProcessorTests.cs deleted file mode 100644 index 3f9f397a..00000000 --- a/tests/MonoGame.Aseprite.Tests/ContentTests/AnimatedTilemapProcessorTests.cs +++ /dev/null @@ -1,265 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework; - -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.Content.Processors; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Tests; - - -public sealed class AnimatedTilemapProcessorTestFixture -{ - public AsepriteFile AsepriteFile { get; } - - public AnimatedTilemapProcessorTestFixture() - { - string fileName = "raw-animated-tilemap-processor-tests"; - - Color[] palette = Array.Empty(); - AsepriteTag[] tags = Array.Empty(); - AsepriteSlice[] slices = Array.Empty(); - AsepriteUserData userData = new(); - - AsepriteTileset[] tilesets = new AsepriteTileset[] - { - new(0, 4, 1, 1, "tileset-0", new Color[] {Color.Transparent, Color.Red, Color.Green, Color.Blue}), - new(1, 4, 1, 1, "tileset-1", new Color[] {Color.Transparent, Color.White, Color.Gray, Color.Black}), - }; - - AsepriteLayer[] layers = new AsepriteLayer[] - { - new AsepriteTilemapLayer(tilesets[0], AsepriteLayerFlags.Visible, AsepriteBlendMode.Normal, 255, "visible"), - new AsepriteTilemapLayer(tilesets[1], AsepriteLayerFlags.None, AsepriteBlendMode.Normal, 255, "hidden") - }; - - AsepriteTile[] frame0Cel0Tiles = new AsepriteTile[] - { - new AsepriteTile(0, false, false, false), - new AsepriteTile(1, false, false, false), - new AsepriteTile(2, false, false, false), - new AsepriteTile(3, false, false, false) - }; - - AsepriteTile[] frame0Cel1Tiles = new AsepriteTile[] - { - new AsepriteTile(2, false, false, false), - new AsepriteTile(3, false, false, false) - }; - - AsepriteCel[] frame0Cels = new AsepriteCel[] - { - new AsepriteTilemapCel(2, 2, frame0Cel0Tiles, layers[0], Point.Zero, 255), - new AsepriteTilemapCel(2, 1, frame0Cel1Tiles, layers[1], new Point(0, 1), 255) - }; - - AsepriteTile[] frame1Cel0Tiles = new AsepriteTile[] - { - new AsepriteTile(3, false, false, false), - new AsepriteTile(2, false, false, false), - new AsepriteTile(1, false, false, false), - new AsepriteTile(0, false, false, false) - }; - - AsepriteTile[] frame1Cel1Tiles = new AsepriteTile[] - { - new AsepriteTile(3, false, false, false), - new AsepriteTile(2, false, false, false) - }; - - AsepriteCel[] frame1Cels = new AsepriteCel[] - { - new AsepriteTilemapCel(2, 2, frame1Cel0Tiles, layers[0], Point.Zero, 255), - new AsepriteTilemapCel(2, 1, frame1Cel1Tiles, layers[1], new Point(0, 1), 255) - }; - - AsepriteFrame[] frames = new AsepriteFrame[] - { - new($"{fileName} 0", 2, 2, 100, frame0Cels), - new($"{fileName} 1", 2, 2, 200, frame1Cels) - }; - - AsepriteFile = new(fileName, 0, 0, palette, frames, layers, tags, slices, tilesets, userData); - } -} - -public sealed class AnimatedTilemapProcessorTests : IClassFixture -{ - private readonly AnimatedTilemapProcessorTestFixture _fixture; - - public AnimatedTilemapProcessorTests(AnimatedTilemapProcessorTestFixture fixture) => _fixture = fixture; - - [Fact] - public void ProcessRaw_OnlyVisibleLayers_True_Processes_Only_Visible_Layers() - { - RawAnimatedTilemap tilemap = AnimatedTilemapProcessor.ProcessRaw(_fixture.AsepriteFile, onlyVisibleLayers: true); - - // Expect the name of the aseprite file to be the name of the tilemap. - Assert.Equal(_fixture.AsepriteFile.Name, tilemap.Name); - - // File has 2 layers, but one is hidden, so expect only 1 layer. - Assert.Equal(1, tilemap.RawTilesets.Length); - - // Each layer uses a different tileset, but again, one is hidden, so expect only one tileset. - Assert.Equal(1, tilemap.RawTilesets.Length); - - // Expect that the tileset was processed correctly - RawTileset tileset = TilesetProcessor.ProcessRaw(_fixture.AsepriteFile, 0); - Assert.Equal(tileset, tilemap.RawTilesets[0]); - - // The file has 2 frames, so expect 2 frames - Assert.Equal(2, tilemap.RawTilemapFrames.Length); - - // Expect that the duration of the tilemap frames was taken from the frames in the file - Assert.Equal(_fixture.AsepriteFile.Frames[0].DurationInMilliseconds, tilemap.RawTilemapFrames[0].DurationInMilliseconds); - Assert.Equal(_fixture.AsepriteFile.Frames[1].DurationInMilliseconds, tilemap.RawTilemapFrames[1].DurationInMilliseconds); - - // Again, one of the layers is hidden, so expect only one layer processed for each frame. - Assert.Equal(1, tilemap.RawTilemapFrames[0].RawTilemapLayers.Length); - Assert.Equal(1, tilemap.RawTilemapFrames[1].RawTilemapLayers.Length); - - // Getting reference to the aseprite layers and cels used to construct the raw tilemap layers - AsepriteTilemapLayer aseLayer0 = (AsepriteTilemapLayer)_fixture.AsepriteFile.Layers[0]; - AsepriteTilemapCel aseFrame0Cel = (AsepriteTilemapCel)_fixture.AsepriteFile.Frames[0].Cels[0]; - AsepriteTilemapCel aseFrame1Cel = (AsepriteTilemapCel)_fixture.AsepriteFile.Frames[1].Cels[0]; - - // Expect that the single layer of each frame was constructed properly from the aseprite layer and cel data. - AssertRawLayer(tilemap.RawTilemapFrames[0].RawTilemapLayers[0], aseLayer0, aseFrame0Cel); - AssertRawLayer(tilemap.RawTilemapFrames[1].RawTilemapLayers[0], aseLayer0, aseFrame1Cel); - } - - [Fact] - public void ProcessRaw_OnlyVisibleLayers_False_Processes_All_Layers() - { - RawAnimatedTilemap tilemap = AnimatedTilemapProcessor.ProcessRaw(_fixture.AsepriteFile, onlyVisibleLayers: false); - - // Expect the name of the aseprite file to be the name of the tilemap. - Assert.Equal(_fixture.AsepriteFile.Name, tilemap.Name); - - // Since all layers were processed, and there are 2 layers, each with a different tileset, expect 2 tilesets - Assert.Equal(2, tilemap.RawTilesets.Length); - - // Each layer uses a different tileset, and since both were processed, expect two tilesets. - Assert.Equal(2, tilemap.RawTilesets.Length); - - // Expect that both of the tilesets were processed correctly - RawTileset tileset0 = TilesetProcessor.ProcessRaw(_fixture.AsepriteFile, 0); - RawTileset tileset1 = TilesetProcessor.ProcessRaw(_fixture.AsepriteFile, 1); - Assert.Equal(tileset0, tilemap.RawTilesets[0]); - Assert.Equal(tileset1, tilemap.RawTilesets[1]); - - // The file has 2 frames, so expect 2 frames - Assert.Equal(2, tilemap.RawTilemapFrames.Length); - - // Expect that the duration of the tilemap frames was taken from the frames in the file - Assert.Equal(_fixture.AsepriteFile.Frames[0].DurationInMilliseconds, tilemap.RawTilemapFrames[0].DurationInMilliseconds); - Assert.Equal(_fixture.AsepriteFile.Frames[1].DurationInMilliseconds, tilemap.RawTilemapFrames[1].DurationInMilliseconds); - - // Since all layers were processed, and there are 2 layers, expect that each frame has 2 layers. - Assert.Equal(2, tilemap.RawTilemapFrames[0].RawTilemapLayers.Length); - Assert.Equal(2, tilemap.RawTilemapFrames[1].RawTilemapLayers.Length); - - // Getting reference to the aseprite layers and cels used to construct the raw tilemap layers - AsepriteTilemapLayer aseLayer0 = (AsepriteTilemapLayer)_fixture.AsepriteFile.Layers[0]; - AsepriteTilemapLayer aseLayer1 = (AsepriteTilemapLayer)_fixture.AsepriteFile.Layers[1]; - AsepriteTilemapCel aseFrame0Cel0 = (AsepriteTilemapCel)_fixture.AsepriteFile.Frames[0].Cels[0]; - AsepriteTilemapCel aseFrame0Cel1 = (AsepriteTilemapCel)_fixture.AsepriteFile.Frames[0].Cels[1]; - AsepriteTilemapCel aseFrame1Cel0 = (AsepriteTilemapCel)_fixture.AsepriteFile.Frames[1].Cels[0]; - AsepriteTilemapCel aseFrame1Cel1 = (AsepriteTilemapCel)_fixture.AsepriteFile.Frames[1].Cels[1]; - - // Expect that the the layers on each frame were constructed properly from the aseprite layer and cel data - AssertRawLayer(tilemap.RawTilemapFrames[0].RawTilemapLayers[0], aseLayer0, aseFrame0Cel0); - AssertRawLayer(tilemap.RawTilemapFrames[0].RawTilemapLayers[1], aseLayer1, aseFrame0Cel1); - AssertRawLayer(tilemap.RawTilemapFrames[1].RawTilemapLayers[0], aseLayer0, aseFrame1Cel0); - AssertRawLayer(tilemap.RawTilemapFrames[1].RawTilemapLayers[1], aseLayer1, aseFrame1Cel1); - } - - [Fact] - public void ProcessRaw_Duplicate_AsepriteLayer_Names_Throws_Exception() - { - - AsepriteLayer[] layers = new AsepriteLayer[] - { - new AsepriteTilemapLayer(_fixture.AsepriteFile.Tilesets[0], AsepriteLayerFlags.Visible, AsepriteBlendMode.Normal, 255, "layer-0"), - new AsepriteTilemapLayer(_fixture.AsepriteFile.Tilesets[0], AsepriteLayerFlags.Visible, AsepriteBlendMode.Normal, 255, "layer-1"), - new AsepriteTilemapLayer(_fixture.AsepriteFile.Tilesets[0], AsepriteLayerFlags.Visible, AsepriteBlendMode.Normal, 255, "layer-0") - }; - - AsepriteTile[] tiles = new AsepriteTile[] - { - new AsepriteTile(0, false, false, false), - new AsepriteTile(1, false, false, false), - new AsepriteTile(2, false, false, false), - new AsepriteTile(3, false, false, false) - }; - - AsepriteCel[] cels = new AsepriteCel[] - { - new AsepriteTilemapCel(2, 2, tiles, layers[0], Point.Zero, 255), - new AsepriteTilemapCel(2, 2, tiles, layers[1], Point.Zero, 255), - new AsepriteTilemapCel(2, 2, tiles, layers[2], Point.Zero, 255) - }; - - AsepriteFrame[] frames = new AsepriteFrame[] - { - new($"{_fixture.AsepriteFile.Name} 0", 2, 2, 100, cels) - }; - - // Reuse the fixture, but use the layers array from above with duplicate layer names - AsepriteFile aseFile = new(_fixture.AsepriteFile.Name, - _fixture.AsepriteFile.CanvasWidth, - _fixture.AsepriteFile.CanvasHeight, - _fixture.AsepriteFile.Palette.ToArray(), - frames, - layers, - _fixture.AsepriteFile.Tags.ToArray(), - _fixture.AsepriteFile.Slices.ToArray(), - _fixture.AsepriteFile.Tilesets.ToArray(), - _fixture.AsepriteFile.UserData); - - Assert.Throws(() => AnimatedTilemapProcessor.ProcessRaw(aseFile)); - } - - private void AssertRawLayer(RawTilemapLayer tilemapLayer, AsepriteTilemapLayer aseLayer, AsepriteTilemapCel aseCel) - { - Assert.Equal(aseLayer.Name, tilemapLayer.Name); - Assert.Equal(aseLayer.Tileset.ID, tilemapLayer.TilesetID); - Assert.Equal(aseCel.Columns, tilemapLayer.Columns); - Assert.Equal(aseCel.Rows, tilemapLayer.Rows); - Assert.Equal(aseCel.Position, tilemapLayer.Offset); - - for (int i = 0; i < aseCel.Tiles.Length; i++) - { - AsepriteTile aseTile = aseCel.Tiles[i]; - RawTilemapTile tilemapTile = tilemapLayer.RawTilemapTiles[i]; - - Assert.Equal(aseTile.TilesetTileID, tilemapTile.TilesetTileID); - Assert.Equal(aseTile.XFlip, tilemapTile.FlipHorizontally); - Assert.Equal(aseTile.YFlip, tilemapTile.FlipVertically); - Assert.Equal(aseTile.DFlip, tilemapTile.FlipDiagonally); - } - } -} diff --git a/tests/MonoGame.Aseprite.Tests/ContentTests/RawTypeWriteReadTests.cs b/tests/MonoGame.Aseprite.Tests/ContentTests/RawTypeWriteReadTests.cs deleted file mode 100644 index 62a37c60..00000000 --- a/tests/MonoGame.Aseprite.Tests/ContentTests/RawTypeWriteReadTests.cs +++ /dev/null @@ -1,250 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using System.Text; -using Microsoft.Xna.Framework; -using MonoGame.Aseprite.Content.Readers; -using MonoGame.Aseprite.Content.Writers; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Tests; - -public sealed class RawTypeWriteReadTests -{ - [Fact] - public void Write_Then_Read_RawSprite() - { - RawTexture texture = new(nameof(RawTexture), new Color[] { Color.Transparent, Color.Red, Color.Green, Color.Blue }, 2, 2); - - RawSlice[] slices = new RawSlice[] - { - new RawSlice(nameof(RawSlice), new(0, 0, 0, 0), new(0, 0), Color.Red), - new RawNinePatchSlice(nameof(RawNinePatchSlice), new(1, 1, 1, 1), new(2, 2, 2, 2), new(3, 3), Color.Green) - }; - - RawSprite sprite = new(nameof(RawSprite), texture, slices); - - Write((writer) => RawSpriteWriter.Write(writer, sprite), out MemoryStream stream); - Read(stream, (reader) => RawSpriteReader.Read(reader), out RawSprite actual); - - Assert.Equal(sprite, actual); - } - - [Fact] - public void Write_Then_Read_RawSpriteSheet() - { - RawTexture texture = new(nameof(RawTexture), new Color[] { Color.Transparent, Color.Red, Color.Green, Color.Blue }, 2, 2); - - RawSlice[] region0Slices = new RawSlice[] - { - new RawSlice(nameof(RawSlice), new(0, 0, 0, 0), new(0, 0), Color.Red), - new RawNinePatchSlice(nameof(RawNinePatchSlice), new(0, 0, 0, 0), new(0, 0, 0, 0), new(0, 0), Color.Green) - }; - - RawSlice[] region1Slices = new RawSlice[] - { - new RawSlice(nameof(RawSlice), new(1, 1, 1, 1), new(1, 1), Color.Red), - new RawNinePatchSlice(nameof(RawNinePatchSlice), new(1, 1, 1, 1), new(1, 1, 1, 1), new(1, 1), Color.Green) - }; - - RawSlice[] region2Slices = new RawSlice[] - { - new RawSlice(nameof(RawSlice), new(2, 2, 2, 2), new(2, 2), Color.Red), - new RawNinePatchSlice(nameof(RawNinePatchSlice), new(2, 2, 2, 2), new(2, 2, 2, 2), new(2, 2), Color.Green) - }; - - RawSlice[] region3Slices = new RawSlice[] - { - new RawSlice(nameof(RawSlice), new(3, 3, 3, 3), new(3, 3), Color.Red), - new RawNinePatchSlice(nameof(RawNinePatchSlice), new(3, 3, 3, 3), new(3, 3, 3, 3), new(3, 3), Color.Green) - }; - - RawTextureRegion[] regions = new RawTextureRegion[] - { - new(nameof(RawTextureRegion), new Rectangle(0, 0, 0, 0), region0Slices), - new(nameof(RawTextureRegion), new Rectangle(1, 1, 1, 1), region1Slices), - new(nameof(RawTextureRegion), new Rectangle(2, 2, 2, 2), region2Slices), - new(nameof(RawTextureRegion), new Rectangle(3, 3, 3, 3), region3Slices) - }; - RawTextureAtlas atlas = new(nameof(RawTextureAtlas), texture, regions); - RawAnimationFrame[] frames = new RawAnimationFrame[] - { - new(0, 0), - new(1, 100), - new(2, 200), - new(3, 300) - }; - RawAnimationTag[] tags = new RawAnimationTag[] - { - new(nameof(RawAnimationTag), frames, 0, true, true), - new(nameof(RawAnimationTag), frames, 1, false, false), - new(nameof(RawAnimationTag), frames, 0, false, true), - new(nameof(RawAnimationTag), frames, 1, true, false), - }; - RawSpriteSheet sheet = new(nameof(RawSpriteSheet), atlas, tags); - - Write(writer => RawSpriteSheetWriter.Write(writer, sheet), out MemoryStream stream); - Read(stream, (reader) => RawSpriteSheetReader.Read(reader), out RawSpriteSheet actual); - - Assert.Equal(sheet, actual); - } - - [Fact] - public void Write_Then_Read_RawTextureAtlas() - { - RawTexture texture = new(nameof(RawTexture), new Color[] { Color.Transparent, Color.Red, Color.Green, Color.Blue }, 2, 2); - - RawSlice[] region0Slices = new RawSlice[] - { - new RawSlice(nameof(RawSlice), new(0, 0, 0, 0), new(0, 0), Color.Red), - new RawNinePatchSlice(nameof(RawNinePatchSlice), new(0, 0, 0, 0), new(0, 0, 0, 0), new(0, 0), Color.Green) - }; - - RawSlice[] region1Slices = new RawSlice[] - { - new RawSlice(nameof(RawSlice), new(1, 1, 1, 1), new(1, 1), Color.Red), - new RawNinePatchSlice(nameof(RawNinePatchSlice), new(1, 1, 1, 1), new(1, 1, 1, 1), new(1, 1), Color.Green) - }; - - RawSlice[] region2Slices = new RawSlice[] - { - new RawSlice(nameof(RawSlice), new(2, 2, 2, 2), new(2, 2), Color.Red), - new RawNinePatchSlice(nameof(RawNinePatchSlice), new(2, 2, 2, 2), new(2, 2, 2, 2), new(2, 2), Color.Green) - }; - - RawSlice[] region3Slices = new RawSlice[] - { - new RawSlice(nameof(RawSlice), new(3, 3, 3, 3), new(3, 3), Color.Red), - new RawNinePatchSlice(nameof(RawNinePatchSlice), new(3, 3, 3, 3), new(3, 3, 3, 3), new(3, 3), Color.Green) - }; - - RawTextureRegion[] regions = new RawTextureRegion[] - { - new(nameof(RawTextureRegion), new Rectangle(0, 0, 0, 0), region0Slices), - new(nameof(RawTextureRegion), new Rectangle(1, 1, 1, 1), region1Slices), - new(nameof(RawTextureRegion), new Rectangle(2, 2, 2, 2), region2Slices), - new(nameof(RawTextureRegion), new Rectangle(3, 3, 3, 3), region3Slices) - }; - RawTextureAtlas atlas = new(nameof(RawTextureAtlas), texture, regions); - - Write((writer) => RawTextureAtlasWriter.Write(writer, atlas), out MemoryStream stream); - Read(stream, (reader) => RawTextureAtlasReader.Read(reader), out RawTextureAtlas actual); - - Assert.Equal(atlas, actual); - } - - [Fact] - public void Write_Then_Read_RawTileset() - { - RawTexture texture = new(nameof(RawTexture), new Color[] { Color.Transparent, Color.Red, Color.Green, Color.Blue }, 2, 2); - RawTileset tileset = new(0, nameof(RawTileset), texture, 1, 1); - - Write((writer) => RawTilesetWriter.Write(writer, tileset), out MemoryStream stream); - Read(stream, (reader) => RawTilesetReader.Read(reader), out RawTileset actual); - - Assert.Equal(tileset, actual); - } - - [Fact] - public void Write_Then_Read_RawTilemap() - { - RawTexture texture = new(nameof(RawTexture), new Color[] { Color.Transparent, Color.Red, Color.Green, Color.Blue }, 2, 2); - - RawTileset[] tilesets = new RawTileset[] - { - new(0, nameof(RawTileset), texture, 1, 1) - }; - - RawTilemapTile[] tiles = new RawTilemapTile[] - { - new RawTilemapTile(0, true, true, false), - new RawTilemapTile(1, true, false, true), - new RawTilemapTile(2, false, true, false), - new RawTilemapTile(3, false, false, true) - }; - - RawTilemapLayer[] layers = new RawTilemapLayer[] - { - new(nameof(RawTilemapLayer), 0, 1, 2, tiles, new(1, 2)) - }; - - RawTilemap tilemap = new(nameof(RawTilemap), layers, tilesets); - - Write((writer) => RawTilemapWriter.Write(writer, tilemap), out MemoryStream stream); - Read(stream, (reader) => RawTilemapReader.Read(reader), out RawTilemap actual); - - Assert.Equal(tilemap, actual); - } - - [Fact] - public void Write_Then_Read_RawAnimatedTilemap() - { - RawTexture texture = new(nameof(RawTexture), new Color[] { Color.Transparent, Color.Red, Color.Green, Color.Blue }, 2, 2); - - RawTileset[] tilesets = new RawTileset[] - { - new(0, nameof(RawTileset), texture, 1, 1) - }; - - RawTilemapTile[] tiles = new RawTilemapTile[] - { - new RawTilemapTile(0, true, true, false), - new RawTilemapTile(1, true, false, true), - new RawTilemapTile(2, false, true, false), - new RawTilemapTile(3, false, false, true) - }; - - RawTilemapLayer[] layers = new RawTilemapLayer[] - { - new(nameof(RawTilemapLayer), 0, 1, 2, tiles, new(1, 2)) - }; - - RawTilemapFrame[] frames = new RawTilemapFrame[] - { - new(100, layers) - }; - - RawAnimatedTilemap tilemap = new(nameof(RawAnimatedTilemap), tilesets, frames); - - Write((writer) => RawAnimatedTilemapWriter.Write(writer, tilemap), out MemoryStream stream); - Read(stream, (reader) => RawAnimatedTilemapReader.Read(reader), out RawAnimatedTilemap actual); - - Assert.Equal(tilemap, actual); - } - private void Write(Action writeAction, out MemoryStream stream) - { - stream = new(); - using BinaryWriter writer = new(stream, Encoding.UTF8, leaveOpen: true); - writeAction(writer); - } - - private void Read(MemoryStream stream, Func readFunc, out T result) - { - stream.Position = 0; - using (BinaryReader reader = new(stream, Encoding.UTF8, leaveOpen: false)) - { - result = readFunc(reader); - } - } -} \ No newline at end of file diff --git a/tests/MonoGame.Aseprite.Tests/ContentTests/SpriteProcessorTests.cs b/tests/MonoGame.Aseprite.Tests/ContentTests/SpriteProcessorTests.cs deleted file mode 100644 index 2ac1ab98..00000000 --- a/tests/MonoGame.Aseprite.Tests/ContentTests/SpriteProcessorTests.cs +++ /dev/null @@ -1,117 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework; -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.Content.Processors; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Tests; - -public sealed class SpriteProcessorTestsFixture -{ - public string Name { get; } = "raw-sprite-processor-test"; - public AsepriteFile AsepriteFile { get; } - - public SpriteProcessorTestsFixture() - { - Color[] palette = new Color[] { Color.Black, Color.White }; - - AsepriteTileset[] tilesets = Array.Empty(); - - AsepriteLayer[] layers = new AsepriteLayer[] - { - new(AsepriteLayerFlags.Visible, AsepriteBlendMode.Normal, 255, "layer") - }; - - AsepriteCel[] frame0Cels = new AsepriteCel[] - { - new AsepriteImageCel(2, 2, new Color[] {Color.Black, Color.Black, Color.Black, Color.Black}, layers[0], Point.Zero, 255) - }; - - AsepriteCel[] frame1Cels = new AsepriteCel[] - { - new AsepriteImageCel(2, 2, new Color[] {Color.White, Color.White, Color.White, Color.White}, layers[0], Point.Zero, 255) - }; - - AsepriteFrame[] frames = new AsepriteFrame[] - { - new($"{Name} 0", 2, 2, 100, frame0Cels), - new($"{Name} 1", 2, 2, 100, frame1Cels) - }; - - AsepriteTag[] tags = Array.Empty(); - AsepriteSlice[] slices = Array.Empty(); - - - AsepriteUserData userData = new(); - AsepriteFile = new(Name, 2, 2, palette, frames, layers, tags, slices, tilesets, userData); - } -} - -public sealed class SpriteProcessorTests : IClassFixture -{ - private readonly SpriteProcessorTestsFixture _fixture; - - - public SpriteProcessorTests(SpriteProcessorTestsFixture fixture) => _fixture = fixture; - - [Theory] - [InlineData(0)] - [InlineData(1)] - public void ProcessRaw_Sprite_And_Texture_Name_Include_Correct_Index(int frame) - { - RawSprite sprite = SpriteProcessor.ProcessRaw(_fixture.AsepriteFile, frame); - - string name = $"{_fixture.Name} {frame}"; - - Assert.Equal(name, sprite.Name); - Assert.Equal(name, sprite.RawTexture.Name); - } - - [Theory] - [InlineData(-1)] - [InlineData(2)] - public void ProcessRaw_Throws_Exception_When_Frame_Index_Out_Of_Range(int frame) - { - Exception ex = Record.Exception(() => SpriteProcessor.ProcessRaw(_fixture.AsepriteFile, frame)); - Assert.IsType(ex); - } - - [Fact] - public void ProcessRaw_Processes_Given_Frame() - { - RawSprite frame0Sprite = SpriteProcessor.ProcessRaw(_fixture.AsepriteFile, 0); - RawSprite frame1Sprite = SpriteProcessor.ProcessRaw(_fixture.AsepriteFile, 1); - - Color[] frame0Expected= new Color[] { Color.Black, Color.Black, Color.Black, Color.Black }; - Color[] frame1Expected = new Color[] { Color.White, Color.White, Color.White, Color.White }; - - Color[] frame0Actual = frame0Sprite.RawTexture.Pixels.ToArray(); - Color[] frame1Actual = frame1Sprite.RawTexture.Pixels.ToArray(); - - Assert.Equal(frame0Expected, frame0Actual); - Assert.Equal(frame1Expected, frame1Actual); - } -} diff --git a/tests/MonoGame.Aseprite.Tests/ContentTests/SpriteSheetProcessorTests.cs b/tests/MonoGame.Aseprite.Tests/ContentTests/SpriteSheetProcessorTests.cs deleted file mode 100644 index 5e092e53..00000000 --- a/tests/MonoGame.Aseprite.Tests/ContentTests/SpriteSheetProcessorTests.cs +++ /dev/null @@ -1,158 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework; -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.Content.Processors; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Tests; - - -public sealed class SpriteSheetProcessorTestFixture -{ - public string Name { get; } = "raw-sprite-processor-test"; - public AsepriteFile AsepriteFile { get; } - - public SpriteSheetProcessorTestFixture() - { - int width = 2; - int height = 2; - - Color[] palette = new Color[] { Color.Red, Color.Green, Color.Blue, Color.Yellow }; - AsepriteTileset[] tilesets = Array.Empty(); - - AsepriteLayer[] layers = new AsepriteLayer[] - { - new(AsepriteLayerFlags.Visible, AsepriteBlendMode.Normal, 255, "layer") - }; - - AsepriteCel[] frame0Cels = new AsepriteCel[] - { - new AsepriteImageCel(width, height, new Color[]{Color.Red, Color.Red, Color.Red, Color.Red}, layers[0], Point.Zero, 255) - }; - - AsepriteCel[] frame1Cels = new AsepriteCel[] - { - new AsepriteImageCel(width, height, new Color[] {Color.Green, Color.Green, Color.Green, Color.Green}, layers[0], Point.Zero, 255) - }; - - AsepriteCel[] frame2Cels = new AsepriteCel[] - { - new AsepriteImageCel(width, height, new Color[] {Color.Blue, Color.Blue, Color.Blue, Color.Blue}, layers[0], Point.Zero, 255) - }; - - AsepriteCel[] frame3Cels = new AsepriteCel[] - { - new AsepriteImageCel(width, height, new Color[] {Color.Red, Color.Red, Color.Red, Color.Red}, layers[0], Point.Zero, 255) - }; - - AsepriteFrame[] frames = new AsepriteFrame[] - { - new($"{Name} 0", width, height, 100, frame0Cels), - new($"{Name} 1", width, height, 100, frame1Cels), - new($"{Name} 2", width, height, 100, frame2Cels), - new($"{Name} 3", width, height, 100, frame3Cels), - }; - - AsepriteTag[] tags = new AsepriteTag[] - { - new(0, 0, AsepriteLoopDirection.Forward, 0, Color.Red, "tag-0"), - new(0, 1, AsepriteLoopDirection.Forward, 0, Color.Green, "tag-1"), - new(1, 2, AsepriteLoopDirection.PingPong, 0, Color.Blue, "tag-2") - }; - - AsepriteSlice[] slices = Array.Empty(); - AsepriteUserData userData = new(); - AsepriteFile = new(Name, width, height, palette, frames, layers, tags, slices, tilesets, userData); - } -} - -public sealed class SpriteSheetProcessorTests : IClassFixture -{ - private readonly SpriteSheetProcessorTestFixture _fixture; - - public SpriteSheetProcessorTests(SpriteSheetProcessorTestFixture fixture) => _fixture = fixture; - - [Theory] - [InlineData(true, true, true, true, 1, 1, 1)] - [InlineData(true, false, true, true, 1, 0, 1)] - [InlineData(true, true, false, true, 1, 1, 0)] - [InlineData(true, true, true, false, 0, 1, 1)] - [InlineData(false, true, true, true, 0, 1, 0)] - [InlineData(false, false, true, true, 0, 0, 1)] - [InlineData(false, true, false, true, 0, 0, 0)] - [InlineData(false, true, true, false, 0, 0, 0)] - [InlineData(false, false, false, true, 0, 0, 0)] - [InlineData(false, false, true, false, 0, 0, 0)] - [InlineData(false, false, false, false, 0, 0, 0)] - public void ProcessRaw_asses_Parameters_To_TextureAtlasProcess_Correctly(bool onlyVisible, bool includeBackground, bool includeTilemap, bool mergeDuplicates, int borderPadding, int spacing, int innerPadding) - { - RawSpriteSheet sheet = SpriteSheetProcessor.ProcessRaw(_fixture.AsepriteFile, onlyVisible, includeBackground, includeTilemap, mergeDuplicates, borderPadding, spacing, innerPadding); - RawTextureAtlas expected = TextureAtlasProcessor.ProcessRaw(_fixture.AsepriteFile, onlyVisible, includeBackground, includeTilemap, mergeDuplicates, borderPadding, spacing, innerPadding); - - Assert.Equal(expected, sheet.RawTextureAtlas); - } - - [Fact] - public void ProcessRaw_SpriteSheet_Atlas_and_Texture_Names_Same_As_File_Name() - { - RawSpriteSheet sheet = SpriteSheetProcessor.ProcessRaw(_fixture.AsepriteFile); - Assert.Equal(_fixture.Name, sheet.Name); - Assert.Equal(_fixture.Name, sheet.RawTextureAtlas.Name); - Assert.Equal(_fixture.Name, sheet.RawTextureAtlas.RawTexture.Name); - } - - [Fact] - public void ProcessRaw_Processes_All_Tags() - { - RawSpriteSheet sheet = SpriteSheetProcessor.ProcessRaw(_fixture.AsepriteFile); - Assert.Equal(_fixture.AsepriteFile.Tags.Length, sheet.RawAnimationTags.Length); - } - - [Fact] - public void ProcessRaw_Duplicate_AsepriteTag_Names_Throws_Exception() - { - AsepriteTag[] tags = new AsepriteTag[] - { - new(0, 0, AsepriteLoopDirection.Forward, 0, Color.Red, "tag-0"), - new(0, 1, AsepriteLoopDirection.Forward, 0, Color.Green, "tag-1"), - new(1, 2, AsepriteLoopDirection.PingPong, 0, Color.Blue, "tag-0") - }; - - // Reuse the fixture, but use the tags array from above with duplicate tag names - AsepriteFile aseFile = new(_fixture.Name, - _fixture.AsepriteFile.CanvasWidth, - _fixture.AsepriteFile.CanvasHeight, - _fixture.AsepriteFile.Palette.ToArray(), - _fixture.AsepriteFile.Frames.ToArray(), - _fixture.AsepriteFile.Layers.ToArray(), - tags, - _fixture.AsepriteFile.Slices.ToArray(), - _fixture.AsepriteFile.Tilesets.ToArray(), - _fixture.AsepriteFile.UserData); - - Assert.Throws(() => SpriteSheetProcessor.ProcessRaw(aseFile)); - } -} diff --git a/tests/MonoGame.Aseprite.Tests/ContentTests/TextureAtlasProcessorTests.cs b/tests/MonoGame.Aseprite.Tests/ContentTests/TextureAtlasProcessorTests.cs deleted file mode 100644 index 8eb96cc6..00000000 --- a/tests/MonoGame.Aseprite.Tests/ContentTests/TextureAtlasProcessorTests.cs +++ /dev/null @@ -1,270 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework; -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.Content.Processors; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Tests; - -public sealed class TextureAtlasProcessorTestFixture -{ - public string Name { get; } = "raw-sprite-processor-test"; - public AsepriteFile AsepriteFile { get; } - - public TextureAtlasProcessorTestFixture() - { - int width = 2; - int height = 2; - - Color[] palette = new Color[] { Color.Red, Color.Green, Color.Blue, Color.Yellow }; - AsepriteTileset[] tilesets = Array.Empty(); - - AsepriteLayer[] layers = new AsepriteLayer[] - { - new(AsepriteLayerFlags.Visible, AsepriteBlendMode.Normal, 255, "layer") - }; - - AsepriteCel[] frame0Cels = new AsepriteCel[] - { - new AsepriteImageCel(width, height, new Color[]{Color.Red, Color.Red, Color.Red, Color.Red}, layers[0], Point.Zero, 255) - }; - - AsepriteCel[] frame1Cels = new AsepriteCel[] - { - new AsepriteImageCel(width, height, new Color[] {Color.Green, Color.Green, Color.Green, Color.Green}, layers[0], Point.Zero, 255) - }; - - AsepriteCel[] frame2Cels = new AsepriteCel[] - { - new AsepriteImageCel(width, height, new Color[] {Color.Blue, Color.Blue, Color.Blue, Color.Blue}, layers[0], Point.Zero, 255) - }; - - AsepriteCel[] frame3Cels = new AsepriteCel[] - { - new AsepriteImageCel(width, height, new Color[] {Color.Red, Color.Red, Color.Red, Color.Red}, layers[0], Point.Zero, 255) - }; - - AsepriteFrame[] frames = new AsepriteFrame[] - { - new($"{Name} 0", width, height, 100, frame0Cels), - new($"{Name} 1", width, height, 100, frame1Cels), - new($"{Name} 2", width, height, 100, frame2Cels), - new($"{Name} 3", width, height, 100, frame3Cels), - }; - - AsepriteTag[] tags = Array.Empty(); - AsepriteSlice[] slices = Array.Empty(); - AsepriteUserData userData = new(); - AsepriteFile = new(Name, width, height, palette, frames, layers, tags, slices, tilesets, userData); - } -} - -public sealed class TextureAtlasProcessorTests : IClassFixture -{ - private readonly TextureAtlasProcessorTestFixture _fixture; - - // These are the colors that will be expected in the raw texture created during each process. They are created - // here an named this way so that it's easier to visualize what the pixel array should be in the test below. - private readonly Color _ = Color.Transparent; // Represents a transparent pixel from padding/spacing, not source - private readonly Color r = Color.Red; // Represents a red pixel - private readonly Color g = Color.Green; // Represents a green pixel - private readonly Color b = Color.Blue; // Represents a blue pixel - private readonly Color t = Color.Transparent; // Represents a transparent pixel from source, not padding/spacing. - - public TextureAtlasProcessorTests(TextureAtlasProcessorTestFixture fixture) => _fixture = fixture; - - [Fact] - public void ProcessRaw_Atlas_And_Texture_Name_Same_As_File_Name() - { - RawTextureAtlas atlas = TextureAtlasProcessor.ProcessRaw(_fixture.AsepriteFile); - Assert.Equal(_fixture.Name, atlas.Name); - Assert.Equal(_fixture.Name, atlas.RawTexture.Name); - } - - [Fact] - public void ProcessRaw_One_Region_Per_Frame() - { - RawTextureAtlas atlas = TextureAtlasProcessor.ProcessRaw(_fixture.AsepriteFile); - Assert.Equal(_fixture.AsepriteFile.Frames.Length, atlas.RawTextureRegions.Length); - } - - [Fact] - public void ProcessRawRegion_Names_Are_Frame_Names() - { - RawTextureAtlas atlas = TextureAtlasProcessor.ProcessRaw(_fixture.AsepriteFile); - - Assert.Equal(_fixture.AsepriteFile.Frames[0].Name, atlas.RawTextureRegions[0].Name); - Assert.Equal(_fixture.AsepriteFile.Frames[1].Name, atlas.RawTextureRegions[1].Name); - Assert.Equal(_fixture.AsepriteFile.Frames[2].Name, atlas.RawTextureRegions[2].Name); - Assert.Equal(_fixture.AsepriteFile.Frames[3].Name, atlas.RawTextureRegions[3].Name); - } - - [Fact] - public void ProcessRaw_Duplicate_Frame_Is_Merged() - { - RawTextureAtlas atlas = TextureAtlasProcessor.ProcessRaw(_fixture.AsepriteFile, mergeDuplicates: true); - - Color[] expected = new Color[] - { - r, r, g, g, - r, r, g, g, - b, b, t, t, - b, b, t, t - }; - - Color[] actual = atlas.RawTexture.Pixels.ToArray(); - - Assert.Equal(expected, actual); - Assert.Equal(new Rectangle(0, 0, 2, 2), atlas.RawTextureRegions[0].Bounds); - Assert.Equal(new Rectangle(2, 0, 2, 2), atlas.RawTextureRegions[1].Bounds); - Assert.Equal(new Rectangle(0, 2, 2, 2), atlas.RawTextureRegions[2].Bounds); - Assert.Equal(new Rectangle(0, 0, 2, 2), atlas.RawTextureRegions[3].Bounds); - } - - [Fact] - public void ProcessRaw_Duplicate_Frame_Not_Merged() - { - RawTextureAtlas atlas = TextureAtlasProcessor.ProcessRaw(_fixture.AsepriteFile, mergeDuplicates: false); - - Color[] expected = new Color[] - { - r, r, g, g, - r, r, g, g, - b, b, r, r, - b, b, r, r, - }; - - Color[] actual = atlas.RawTexture.Pixels.ToArray(); - - Assert.Equal(expected, actual); - Assert.Equal(new Rectangle(0, 0, 2, 2), atlas.RawTextureRegions[0].Bounds); - Assert.Equal(new Rectangle(2, 0, 2, 2), atlas.RawTextureRegions[1].Bounds); - Assert.Equal(new Rectangle(0, 2, 2, 2), atlas.RawTextureRegions[2].Bounds); - Assert.Equal(new Rectangle(2, 2, 2, 2), atlas.RawTextureRegions[3].Bounds); - } - - [Fact] - public void ProcessRaw_Border_Padding_Added_Correctly() - { - RawTextureAtlas atlas = TextureAtlasProcessor.ProcessRaw(_fixture.AsepriteFile, borderPadding: 1); - - Color[] expected = new Color[] - { - _, _, _, _, _, _, - _, r, r, g, g, _, - _, r, r, g, g, _, - _, b, b, t, t, _, - _, b, b, t, t, _, - _, _, _, _, _, _ - }; - - Color[] actual = atlas.RawTexture.Pixels.ToArray(); - - Assert.Equal(expected, actual); - Assert.Equal(new Rectangle(1, 1, 2, 2), atlas.RawTextureRegions[0].Bounds); - Assert.Equal(new Rectangle(3, 1, 2, 2), atlas.RawTextureRegions[1].Bounds); - Assert.Equal(new Rectangle(1, 3, 2, 2), atlas.RawTextureRegions[2].Bounds); - Assert.Equal(new Rectangle(1, 1, 2, 2), atlas.RawTextureRegions[3].Bounds); - } - - [Fact] - public void ProcessRaw_Spacing_Added_Correctly() - { - RawTextureAtlas atlas = TextureAtlasProcessor.ProcessRaw(_fixture.AsepriteFile, spacing: 1); - - Color[] expected = new Color[] - { - r, r, _, g, g, - r, r, _, g, g, - _, _, _, _, _, - b, b, _, t, t, - b, b, _, t, t - }; - - Color[] actual = atlas.RawTexture.Pixels.ToArray(); - - Assert.Equal(expected, actual); - Assert.Equal(new Rectangle(0, 0, 2, 2), atlas.RawTextureRegions[0].Bounds); - Assert.Equal(new Rectangle(3, 0, 2, 2), atlas.RawTextureRegions[1].Bounds); - Assert.Equal(new Rectangle(0, 3, 2, 2), atlas.RawTextureRegions[2].Bounds); - Assert.Equal(new Rectangle(0, 0, 2, 2), atlas.RawTextureRegions[3].Bounds); - } - - [Fact] - public void ProcessRaw_InnerPadding_Added_Correctly() - { - RawTextureAtlas atlas = TextureAtlasProcessor.ProcessRaw(_fixture.AsepriteFile, innerPadding: 1); - - Color[] expected = new Color[] - { - _, _, _, _, _, _, _, _, - _, r, r, _, _, g, g, _, - _, r, r, _, _, g, g, _, - _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, - _, b, b, _, _, t, t, _, - _, b, b, _, _, t, t, _, - _, _, _, _, _, _, _, _, - }; - - Color[] actual = atlas.RawTexture.Pixels.ToArray(); - - Assert.Equal(expected, actual); - Assert.Equal(new Rectangle(1, 1, 2, 2), atlas.RawTextureRegions[0].Bounds); - Assert.Equal(new Rectangle(5, 1, 2, 2), atlas.RawTextureRegions[1].Bounds); - Assert.Equal(new Rectangle(1, 5, 2, 2), atlas.RawTextureRegions[2].Bounds); - Assert.Equal(new Rectangle(1, 1, 2, 2), atlas.RawTextureRegions[3].Bounds); - } - - [Fact] - public void ProcessRaw_Combined_Border_Padding_Spacing_Inner_Padding_Added_Correctly() - { - RawTextureAtlas atlas = TextureAtlasProcessor.ProcessRaw(_fixture.AsepriteFile, borderPadding: 1, spacing: 1, innerPadding: 1); - - Color[] expected = new Color[] - { - _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, - _, _, r, r, _, _, _, g, g, _, _, - _, _, r, r, _, _, _, g, g, _, _, - _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _, - _, _, b, b, _, _, _, t, t, _, _, - _, _, b, b, _, _, _, t, t, _, _, - _, _, _, _, _, _, _, _, _, _, _, - _, _, _, _, _, _, _, _, _, _, _ - }; - - Color[] actual = atlas.RawTexture.Pixels.ToArray(); - - Assert.Equal(expected, actual); - Assert.Equal(new Rectangle(2, 2, 2, 2), atlas.RawTextureRegions[0].Bounds); - Assert.Equal(new Rectangle(7, 2, 2, 2), atlas.RawTextureRegions[1].Bounds); - Assert.Equal(new Rectangle(2, 7, 2, 2), atlas.RawTextureRegions[2].Bounds); - Assert.Equal(new Rectangle(2, 2, 2, 2), atlas.RawTextureRegions[3].Bounds); - } -} diff --git a/tests/MonoGame.Aseprite.Tests/ContentTests/TilemapProcessorTests.cs b/tests/MonoGame.Aseprite.Tests/ContentTests/TilemapProcessorTests.cs deleted file mode 100644 index d97bb726..00000000 --- a/tests/MonoGame.Aseprite.Tests/ContentTests/TilemapProcessorTests.cs +++ /dev/null @@ -1,204 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework; -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.Content.Processors; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Tests; - - -public sealed class TilemapProcessorTestFixture -{ - public AsepriteFile AsepriteFile { get; } - - public TilemapProcessorTestFixture() - { - string fileName = "raw-tilemap-processor-tests"; - - Color[] palette = Array.Empty(); - AsepriteTag[] tags = Array.Empty(); - AsepriteSlice[] slices = Array.Empty(); - AsepriteUserData userData = new(); - - AsepriteTileset[] tilesets = new AsepriteTileset[] - { - new(0, 4, 1, 1, "tileset-0", new Color[] {Color.Transparent, Color.Red, Color.Green, Color.Blue}), - new(1, 4, 1, 1, "tileset-1", new Color[] {Color.Transparent, Color.White, Color.Gray, Color.Black}), - }; - - AsepriteLayer[] layers = new AsepriteLayer[] - { - new AsepriteTilemapLayer(tilesets[0], AsepriteLayerFlags.Visible, AsepriteBlendMode.Normal, 255, "visible"), - new AsepriteTilemapLayer(tilesets[1], AsepriteLayerFlags.None, AsepriteBlendMode.Normal, 255, "hidden") - }; - - AsepriteTile[] cel0Tiles = new AsepriteTile[] - { - new AsepriteTile(0, false, false, false), - new AsepriteTile(1, false, false, false), - new AsepriteTile(2, false, false, false), - new AsepriteTile(3, false, false, false) - }; - - AsepriteTile[] cel1Tiles = new AsepriteTile[] - { - new AsepriteTile(2, false, false, false), - new AsepriteTile(3, false, false, false) - }; - - AsepriteCel[] cels = new AsepriteCel[] - { - new AsepriteTilemapCel(2, 2, cel0Tiles, layers[0], Point.Zero, 255), - new AsepriteTilemapCel(2, 2, cel1Tiles, layers[1], new Point(0, 1), 255) - }; - - AsepriteFrame[] frames = new AsepriteFrame[] - { - new($"{fileName} 0", 2, 2, 100, cels) - }; - - AsepriteFile = new(fileName, 0, 0, palette, frames, layers, tags, slices, tilesets, userData); - } -} - -public sealed class TilemapProcessorTests : IClassFixture -{ - private readonly TilemapProcessorTestFixture _fixture; - - public TilemapProcessorTests(TilemapProcessorTestFixture fixture) => _fixture = fixture; - - [Fact] - public void ProcessRaw_OnlyVisibleLayers_True_Processes_Only_Visible_Layers() - { - RawTilemap tilemap = TilemapProcessor.ProcessRaw(_fixture.AsepriteFile, 0, onlyVisibleLayers: true); - - Assert.Equal(_fixture.AsepriteFile.Name, tilemap.Name); - - Assert.Equal(1, tilemap.RawTilesets.Length); - RawTileset rawTileset = TilesetProcessor.ProcessRaw(_fixture.AsepriteFile, 0); - Assert.Equal(rawTileset, tilemap.RawTilesets[0]); - - Assert.Equal(1, tilemap.RawLayers.Length); - AsepriteTilemapLayer aseLayer = (AsepriteTilemapLayer)_fixture.AsepriteFile.Layers[0]; - AsepriteTilemapCel aseCel = (AsepriteTilemapCel)_fixture.AsepriteFile.Frames[0].Cels[0]; - AssertRawLayer(tilemap.RawLayers[0], aseLayer.Name, aseLayer.Tileset.ID, aseCel.Columns, aseCel.Rows, aseCel.Position, aseCel.Tiles); - } - - [Fact] - public void ProcessRaw_OnlyVisibleLayers_False_Processes_All_Layers() - { - RawTilemap tilemap = TilemapProcessor.ProcessRaw(_fixture.AsepriteFile, 0, onlyVisibleLayers: false); - - Assert.Equal(_fixture.AsepriteFile.Name, tilemap.Name); - - Assert.Equal(2, tilemap.RawTilesets.Length); - RawTileset rawTileset0 = TilesetProcessor.ProcessRaw(_fixture.AsepriteFile, 0); - RawTileset rawTileset1 = TilesetProcessor.ProcessRaw(_fixture.AsepriteFile, 1); - Assert.Equal(rawTileset0, tilemap.RawTilesets[0]); - Assert.Equal(rawTileset1, tilemap.RawTilesets[1]); - - Assert.Equal(2, tilemap.RawLayers.Length); - - AsepriteTilemapLayer aseLayer0 = (AsepriteTilemapLayer)_fixture.AsepriteFile.Layers[0]; - AsepriteTilemapCel aseCel0 = (AsepriteTilemapCel)_fixture.AsepriteFile.Frames[0].Cels[0]; - AssertRawLayer(tilemap.RawLayers[0], aseLayer0.Name, aseLayer0.Tileset.ID, aseCel0.Columns, aseCel0.Rows, aseCel0.Position, aseCel0.Tiles); - - AsepriteTilemapLayer aseLayer1 = (AsepriteTilemapLayer)_fixture.AsepriteFile.Layers[1]; - AsepriteTilemapCel aseCel1 = (AsepriteTilemapCel)_fixture.AsepriteFile.Frames[0].Cels[1]; - AssertRawLayer(tilemap.RawLayers[1], aseLayer1.Name, aseLayer1.Tileset.ID, aseCel1.Columns, aseCel1.Rows, aseCel1.Position, aseCel1.Tiles); - } - - [Fact] - public void ProcessRaw_Index_Out_Of_Range_Throws_Exception() - { - Assert.Throws(() => TilemapProcessor.ProcessRaw(_fixture.AsepriteFile, -1)); - Assert.Throws(() => TilemapProcessor.ProcessRaw(_fixture.AsepriteFile, _fixture.AsepriteFile.Frames.Length)); - Assert.Throws(() => TilemapProcessor.ProcessRaw(_fixture.AsepriteFile, _fixture.AsepriteFile.Frames.Length + 1)); - } - - [Fact] - public void ProcessRaw_Duplicate_AsepriteLayer_Names_Throws_Exception() - { - - AsepriteLayer[] layers = new AsepriteLayer[] - { - new AsepriteTilemapLayer(_fixture.AsepriteFile.Tilesets[0], AsepriteLayerFlags.Visible, AsepriteBlendMode.Normal, 255, "layer-0"), - new AsepriteTilemapLayer(_fixture.AsepriteFile.Tilesets[0], AsepriteLayerFlags.Visible, AsepriteBlendMode.Normal, 255, "layer-1"), - new AsepriteTilemapLayer(_fixture.AsepriteFile.Tilesets[0], AsepriteLayerFlags.Visible, AsepriteBlendMode.Normal, 255, "layer-0") - }; - - AsepriteTile[] tiles = new AsepriteTile[] - { - new AsepriteTile(0, false, false, false), - new AsepriteTile(1, false, false, false), - new AsepriteTile(2, false, false, false), - new AsepriteTile(3, false, false, false) - }; - - AsepriteCel[] cels = new AsepriteCel[] - { - new AsepriteTilemapCel(2, 2, tiles, layers[0], Point.Zero, 255), - new AsepriteTilemapCel(2, 2, tiles, layers[1], Point.Zero, 255), - new AsepriteTilemapCel(2, 2, tiles, layers[2], Point.Zero, 255) - }; - - AsepriteFrame[] frames = new AsepriteFrame[] - { - new($"{_fixture.AsepriteFile.Name} 0", 2, 2, 100, cels) - }; - - // Reuse the fixture, but use the layers array from above with duplicate layer names - AsepriteFile aseFile = new(_fixture.AsepriteFile.Name, - _fixture.AsepriteFile.CanvasWidth, - _fixture.AsepriteFile.CanvasHeight, - _fixture.AsepriteFile.Palette.ToArray(), - frames, - layers, - _fixture.AsepriteFile.Tags.ToArray(), - _fixture.AsepriteFile.Slices.ToArray(), - _fixture.AsepriteFile.Tilesets.ToArray(), - _fixture.AsepriteFile.UserData); - - Assert.Throws(() => TilemapProcessor.ProcessRaw(aseFile, 0)); - } - - private void AssertRawLayer(RawTilemapLayer layer, string name, int tilesetID, int columns, int rows, Point offset, ReadOnlySpan tiles) - { - Assert.Equal(name, layer.Name); - Assert.Equal(tilesetID, layer.TilesetID); - Assert.Equal(columns, layer.Columns); - Assert.Equal(rows, layer.Rows); - Assert.Equal(offset, layer.Offset); - - for (int i = 0; i < tiles.Length; i++) - { - Assert.Equal(tiles[i].TilesetTileID, layer.RawTilemapTiles[i].TilesetTileID); - Assert.Equal(tiles[i].XFlip, layer.RawTilemapTiles[i].FlipHorizontally); - Assert.Equal(tiles[i].YFlip, layer.RawTilemapTiles[i].FlipVertically); - Assert.Equal(tiles[i].DFlip, layer.RawTilemapTiles[i].FlipDiagonally); - } - } -} diff --git a/tests/MonoGame.Aseprite.Tests/ContentTests/TilesetProcessorTests.cs b/tests/MonoGame.Aseprite.Tests/ContentTests/TilesetProcessorTests.cs deleted file mode 100644 index db8ea141..00000000 --- a/tests/MonoGame.Aseprite.Tests/ContentTests/TilesetProcessorTests.cs +++ /dev/null @@ -1,110 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework; -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.Content.Processors; -using MonoGame.Aseprite.RawTypes; - -namespace MonoGame.Aseprite.Tests; - - -public sealed class TilesetProcessorTestFixture -{ - public AsepriteFile AsepriteFile { get; } - - public TilesetProcessorTestFixture() - { - Color[] palette = Array.Empty(); - AsepriteFrame[] frames = Array.Empty(); - AsepriteLayer[] layers = Array.Empty(); - AsepriteTag[] tags = Array.Empty(); - AsepriteSlice[] slices = Array.Empty(); - AsepriteUserData userData = new(); - - AsepriteTileset[] tilesets = new AsepriteTileset[] - { - new(0, 4, 1, 1, "tileset-0", new Color[] {Color.Transparent, Color.Red, Color.Green, Color.Blue}), - new(1, 4, 1, 1, "tileset-1", new Color[] {Color.Transparent, Color.White, Color.Gray, Color.Black}), - }; - - AsepriteFile = new("file", 0, 0, palette, frames, layers, tags, slices, tilesets, userData); - } -} - -public sealed class TilesetProcessorTests : IClassFixture -{ - private readonly TilesetProcessorTestFixture _fixture; - - public TilesetProcessorTests(TilesetProcessorTestFixture fixture) => _fixture = fixture; - - [Fact] - public void ProcessRaw_By_Index() - { - int index = 0; - AsepriteTileset aseTileset = _fixture.AsepriteFile.Tilesets[index]; - - RawTileset rawTileset = TilesetProcessor.ProcessRaw(_fixture.AsepriteFile, index); - - Assert.Equal(aseTileset.ID, rawTileset.ID); - Assert.Equal(aseTileset.Name, rawTileset.Name); - Assert.Equal(aseTileset.TileWidth, rawTileset.TileWidth); - Assert.Equal(aseTileset.TileHeight, rawTileset.TileHeight); - Assert.Equal(aseTileset.Name, rawTileset.RawTexture.Name); - Assert.Equal(aseTileset.Width, rawTileset.RawTexture.Width); - Assert.Equal(aseTileset.Height, rawTileset.RawTexture.Height); - Assert.Equal(aseTileset.Pixels.ToArray(), rawTileset.RawTexture.Pixels.ToArray()); - } - - [Fact] - public void ProcessRaw_By_Name() - { - AsepriteTileset aseTileset = _fixture.AsepriteFile.Tilesets[0]; - - RawTileset rawTileset = TilesetProcessor.ProcessRaw(_fixture.AsepriteFile, aseTileset.Name); - - Assert.Equal(aseTileset.ID, rawTileset.ID); - Assert.Equal(aseTileset.Name, rawTileset.Name); - Assert.Equal(aseTileset.TileWidth, rawTileset.TileWidth); - Assert.Equal(aseTileset.TileHeight, rawTileset.TileHeight); - Assert.Equal(aseTileset.Name, rawTileset.RawTexture.Name); - Assert.Equal(aseTileset.Width, rawTileset.RawTexture.Width); - Assert.Equal(aseTileset.Height, rawTileset.RawTexture.Height); - Assert.Equal(aseTileset.Pixels.ToArray(), rawTileset.RawTexture.Pixels.ToArray()); - } - - [Fact] - public void ProcessRaw_Index_Out_Of_Range_Throws_Exception() - { - Assert.Throws(() => TilesetProcessor.ProcessRaw(_fixture.AsepriteFile, -1)); - Assert.Throws(() => TilesetProcessor.ProcessRaw(_fixture.AsepriteFile, _fixture.AsepriteFile.Tilesets.Length)); - Assert.Throws(() => TilesetProcessor.ProcessRaw(_fixture.AsepriteFile, _fixture.AsepriteFile.Tilesets.Length + 1)); - } - - [Fact] - public void ProcessRaw_Bad_Name_Throws_Exception() - { - Assert.Throws(() => TilesetProcessor.ProcessRaw(_fixture.AsepriteFile, string.Empty)); - } -} diff --git a/tests/MonoGame.Aseprite.Tests/Files/aseprite-1.2.9-file-reader-test.aseprite b/tests/MonoGame.Aseprite.Tests/Files/aseprite-1.2.9-file-reader-test.aseprite deleted file mode 100644 index d2ea6f70..00000000 Binary files a/tests/MonoGame.Aseprite.Tests/Files/aseprite-1.2.9-file-reader-test.aseprite and /dev/null differ diff --git a/tests/MonoGame.Aseprite.Tests/Files/aseprite-1.3.0-file-reader-test.aseprite b/tests/MonoGame.Aseprite.Tests/Files/aseprite-1.3.0-file-reader-test.aseprite deleted file mode 100644 index 3e565943..00000000 Binary files a/tests/MonoGame.Aseprite.Tests/Files/aseprite-1.3.0-file-reader-test.aseprite and /dev/null differ diff --git a/tests/MonoGame.Aseprite.Tests/Files/aseprite-1.3.0-rc1-file-reader-test.aseprite b/tests/MonoGame.Aseprite.Tests/Files/aseprite-1.3.0-rc1-file-reader-test.aseprite deleted file mode 100644 index 3a792070..00000000 Binary files a/tests/MonoGame.Aseprite.Tests/Files/aseprite-1.3.0-rc1-file-reader-test.aseprite and /dev/null differ diff --git a/tests/MonoGame.Aseprite.Tests/Files/raw-sprite-processor-test.aseprite b/tests/MonoGame.Aseprite.Tests/Files/raw-sprite-processor-test.aseprite deleted file mode 100644 index 96fce4b8..00000000 Binary files a/tests/MonoGame.Aseprite.Tests/Files/raw-sprite-processor-test.aseprite and /dev/null differ diff --git a/tests/MonoGame.Aseprite.Tests/IOTests/AsepriteFileReaderTests.cs b/tests/MonoGame.Aseprite.Tests/IOTests/AsepriteFileReaderTests.cs deleted file mode 100644 index 633c0004..00000000 --- a/tests/MonoGame.Aseprite.Tests/IOTests/AsepriteFileReaderTests.cs +++ /dev/null @@ -1,623 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework; -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.Content.Readers; - -namespace MonoGame.Aseprite.Tests; - -public sealed class AsepriteFileReaderTests -{ - private readonly Color _black = new Color(0, 0, 0, 255); - private readonly Color _white = new Color(255, 255, 255, 255); - private readonly Color _red = new Color(255, 0, 0, 255); - private readonly Color _green = new Color(0, 255, 0, 255); - private readonly Color _blue = new Color(0, 0, 255, 255); - private readonly Color _transparent = new Color(0, 0, 0, 0); - - - [Fact] - public void ReadsStream_Version_1_3_0_RC1_Expected_Values() - { - string path = FileUtils.GetLocalPath("aseprite-1.3.0-rc1-file-reader-test.aseprite"); - Stream fileStream = File.OpenRead(path); - AsepriteFile aseFile = AsepriteFileReader.ReadStream(Path.GetFileNameWithoutExtension(path), fileStream); - - Reads_Version_1_3_0_RC1_Assertions(aseFile); - } - - [Fact] - public void Reads_Version_1_3_0_RC1_Expected_Values() - { - string path = FileUtils.GetLocalPath("aseprite-1.3.0-rc1-file-reader-test.aseprite"); - AsepriteFile aseFile = AsepriteFileReader.ReadFile(path); - - Reads_Version_1_3_0_RC1_Assertions(aseFile); - } - - private void Reads_Version_1_3_0_RC1_Assertions(AsepriteFile aseFile) - { - // ************************************************************ - // File properties - // ************************************************************ - Assert.Equal("aseprite-1.3.0-rc1-file-reader-test", aseFile.Name); - Assert.Equal(2, aseFile.CanvasWidth); - Assert.Equal(2, aseFile.CanvasHeight); - AssertUserData(aseFile.UserData, "hello sprite", _blue); - - // ************************************************************ - // Layers - // ************************************************************ - Assert.Equal(9, aseFile.Layers.Length); - AssertLayer(aseFile.Layers[0], "background", true, true, false, AsepriteBlendMode.Normal, 255, null, null); - AssertLayer(aseFile.Layers[1], "hidden", false, false, false, AsepriteBlendMode.Normal, 255, null, null); - AssertLayer(aseFile.Layers[2], "100-opacity", true, false, false, AsepriteBlendMode.Normal, 100, null, null); - AssertLayer(aseFile.Layers[3], "userdata", true, false, false, AsepriteBlendMode.Normal, 255, "hello layer", _blue); - AssertLayer(aseFile.Layers[4], "group", true, false, false, AsepriteBlendMode.Normal, 0, null, null); - AssertLayer(aseFile.Layers[5], "child", true, false, false, AsepriteBlendMode.Normal, 255, null, null); - AssertLayer(aseFile.Layers[6], "tilemap", true, false, false, AsepriteBlendMode.Normal, 255, null, null); - AsepriteTilemapLayer tilemapLayer = Assert.IsType(aseFile.Layers[6]); - AssertTilemapLayer(tilemapLayer, "tileset"); - AssertLayer(aseFile.Layers[7], "eight-frames", true, false, false, AsepriteBlendMode.Normal, 255, null, null); - AssertLayer(aseFile.Layers[8], "blend-color-dodge", true, false, false, AsepriteBlendMode.ColorDodge, 255, null, null); - - - // ************************************************************ - // Tags - // ************************************************************ - Assert.Equal(6, aseFile.Tags.Length); - AssertTag(aseFile.Tags[0], "forward", 0, 0, AsepriteLoopDirection.Forward, 0, _black, null, _black); - AssertTag(aseFile.Tags[1], "reversed", 1, 1, AsepriteLoopDirection.Reverse, 0, _black, null, _black); - AssertTag(aseFile.Tags[2], "pingpong", 2, 2, AsepriteLoopDirection.PingPong, 0, _black, null, _black); - AssertTag(aseFile.Tags[3], "frames-4-to-6", 3, 5, AsepriteLoopDirection.Forward, 0, _black, null, _black); - AssertTag(aseFile.Tags[4], "userdata", 6, 6, AsepriteLoopDirection.Forward, 0, _green, "hello tag", _green); - AssertTag(aseFile.Tags[5], "repeat-x100", 7, 7, AsepriteLoopDirection.Forward, 100, _black, null, _black); - - // ************************************************************ - // Frames - // ************************************************************ - Assert.Equal(8, aseFile.Frames.Length); - AssertFrame(aseFile.Frames[0], 3, 2, 2, 100); - AssertFrame(aseFile.Frames[1], 2, 2, 2, 200); - AssertFrame(aseFile.Frames[2], 2, 2, 2, 300); - AssertFrame(aseFile.Frames[3], 2, 2, 2, 400); - AssertFrame(aseFile.Frames[4], 2, 2, 2, 500); - AssertFrame(aseFile.Frames[5], 2, 2, 2, 600); - AssertFrame(aseFile.Frames[6], 2, 2, 2, 700); - AssertFrame(aseFile.Frames[7], 2, 2, 2, 800); - - // ************************************************************ - // Cels - // ************************************************************ - // Frame 0 - Assert.Equal(3, aseFile.Frames[0].Cels.Length); - AssertCel(aseFile.Frames[0].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame0Cel0 = Assert.IsType(aseFile.Frames[0].Cels[0]); - AssertImageCel(frame0Cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[0].Cels[1], "tilemap", 0, 0, 255, null, null); - AsepriteTilemapCel frame0cel1 = Assert.IsType(aseFile.Frames[0].Cels[1]); - AssertTilemapCel(frame0cel1, 2, 2, 4, "tileset"); - AssertTile(frame0cel1.Tiles[0], 1, false, false, false); - AssertTile(frame0cel1.Tiles[1], 2, false, false, false); - AssertTile(frame0cel1.Tiles[2], 3, false, false, false); - AssertTile(frame0cel1.Tiles[3], 4, false, false, false); - - AssertCel(aseFile.Frames[0].Cels[2], "eight-frames", 0, 0, 255, null, null); - AsepriteImageCel frame0cel2 = Assert.IsType(aseFile.Frames[0].Cels[2]); - AssertImageCel(frame0cel2, 1, 1, new Color[] { _red }); - - // Frame 1 - AssertCel(aseFile.Frames[1].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame1Cel0 = Assert.IsType(aseFile.Frames[1].Cels[0]); - AssertImageCel(frame1Cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[1].Cels[1], "eight-frames", 1, 0, 255, null, null); - AsepriteImageCel frame1cel1 = Assert.IsType(aseFile.Frames[1].Cels[1]); - AssertImageCel(frame1cel1, 1, 1, new Color[] { _red }); - - // Frame 2 - AssertCel(aseFile.Frames[2].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame2Cel0 = Assert.IsType(aseFile.Frames[2].Cels[0]); - AssertImageCel(frame2Cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[2].Cels[1], "eight-frames", 0, 1, 255, null, null); - AsepriteImageCel frame2cel1 = Assert.IsType(aseFile.Frames[2].Cels[1]); - AssertImageCel(frame2cel1, 1, 1, new Color[] { _red }); - - // Frame 3 - AssertCel(aseFile.Frames[3].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame3cel0 = Assert.IsType(aseFile.Frames[3].Cels[0]); - AssertImageCel(frame3cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[3].Cels[1], "eight-frames", 1, 1, 255, null, null); - AsepriteImageCel frame3cel1 = Assert.IsType(aseFile.Frames[3].Cels[1]); - AssertImageCel(frame3cel1, 1, 1, new Color[] { _red }); - - // Frame 4 - AssertCel(aseFile.Frames[4].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame4cel0 = Assert.IsType(aseFile.Frames[4].Cels[0]); - AssertImageCel(frame4cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[4].Cels[1], "eight-frames", 0, 0, 255, null, null); - AsepriteImageCel frame4cel1 = Assert.IsType(aseFile.Frames[4].Cels[1]); - AssertImageCel(frame4cel1, 2, 1, new Color[] { _red, _red }); - - // Frame 5 - AssertCel(aseFile.Frames[5].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame5cel0 = Assert.IsType(aseFile.Frames[5].Cels[0]); - AssertImageCel(frame5cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[5].Cels[1], "eight-frames", 0, 1, 255, null, null); - AsepriteImageCel frame5cel1 = Assert.IsType(aseFile.Frames[5].Cels[1]); - AssertImageCel(frame5cel1, 2, 1, new Color[] { _red, _red }); - - // Frame 6 - AssertCel(aseFile.Frames[6].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame6cel0 = Assert.IsType(aseFile.Frames[6].Cels[0]); - AssertImageCel(frame6cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[6].Cels[1], "eight-frames", 0, 0, 255, null, null); - AsepriteImageCel frame6cel1 = Assert.IsType(aseFile.Frames[6].Cels[1]); - AssertImageCel(frame6cel1, 2, 2, new Color[] { _red, _red, _red, _transparent }); - - // Frame 7 - AssertCel(aseFile.Frames[7].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame7cel0 = Assert.IsType(aseFile.Frames[7].Cels[0]); - AssertImageCel(frame7cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[7].Cels[1], "eight-frames", 0, 0, 255, "hello cel", _red); - AsepriteImageCel frame7cel1 = Assert.IsType(aseFile.Frames[7].Cels[1]); - AssertImageCel(frame7cel1, 2, 2, new Color[] { _red, _red, _transparent, _red }); - - // ************************************************************ - // Slices - // ************************************************************ - Assert.Equal(1, aseFile.Slices.Length); - AssertSlice(aseFile.Slices[0], "slice", 1, true, true, "hello slice", _green); - AssertSliceKey(aseFile.Slices[0].Keys[0], 0, new Rectangle(0, 0, 2, 2), new Rectangle(0, 0, 1, 2), new Point(1, 2)); - - // ************************************************************ - // Tilesets - // ************************************************************ - Assert.Equal(1, aseFile.Tilesets.Length); - AssertTileset(aseFile.Tilesets[0], 0, "tileset", 5, 1, 1, 1, 5, new Color[] { _transparent, _white, _red, _green, _blue }); - } - - - - [Fact] - public void ReadsStream_Version_1_3_0_Expected_Values() - { - string path = FileUtils.GetLocalPath("aseprite-1.3.0-file-reader-test.aseprite"); - Stream fileStream = File.OpenRead(path); - AsepriteFile aseFile = AsepriteFileReader.ReadStream(Path.GetFileNameWithoutExtension(path), fileStream); - - Reads_Version_1_3_0_Assertions(aseFile); - } - - [Fact] - public void Reads_Version_1_3_0_Expected_Values() - { - string path = FileUtils.GetLocalPath("aseprite-1.3.0-file-reader-test.aseprite"); - AsepriteFile aseFile = AsepriteFileReader.ReadFile(path); - - Reads_Version_1_3_0_Assertions(aseFile); - } - - private void Reads_Version_1_3_0_Assertions(AsepriteFile aseFile) - { - // ************************************************************ - // File properties - // ************************************************************ - Assert.Equal("aseprite-1.3.0-file-reader-test", aseFile.Name); - Assert.Equal(2, aseFile.CanvasWidth); - Assert.Equal(2, aseFile.CanvasHeight); - AssertUserData(aseFile.UserData, "hello sprite", _blue); - - // ************************************************************ - // Layers - // ************************************************************ - Assert.Equal(9, aseFile.Layers.Length); - AssertLayer(aseFile.Layers[0], "background", true, true, false, AsepriteBlendMode.Normal, 255, null, null); - AssertLayer(aseFile.Layers[1], "hidden", false, false, false, AsepriteBlendMode.Normal, 255, null, null); - AssertLayer(aseFile.Layers[2], "100-opacity", true, false, false, AsepriteBlendMode.Normal, 100, null, null); - AssertLayer(aseFile.Layers[3], "userdata", true, false, false, AsepriteBlendMode.Normal, 255, "hello layer", _blue); - AssertLayer(aseFile.Layers[4], "group", true, false, false, AsepriteBlendMode.Normal, 0, null, null); - AssertLayer(aseFile.Layers[5], "child", true, false, false, AsepriteBlendMode.Normal, 255, null, null); - AssertLayer(aseFile.Layers[6], "tilemap", true, false, false, AsepriteBlendMode.Normal, 255, null, null); - AsepriteTilemapLayer tilemapLayer = Assert.IsType(aseFile.Layers[6]); - AssertTilemapLayer(tilemapLayer, "tileset"); - AssertLayer(aseFile.Layers[7], "eight-frames", true, false, false, AsepriteBlendMode.Normal, 255, null, null); - AssertLayer(aseFile.Layers[8], "blend-color-dodge", true, false, false, AsepriteBlendMode.ColorDodge, 255, null, null); - - - // ************************************************************ - // Tags - // ************************************************************ - Assert.Equal(5, aseFile.Tags.Length); - AssertTag(aseFile.Tags[0], "forward", 0, 0, AsepriteLoopDirection.Forward, 0, _black, null, _black); - AssertTag(aseFile.Tags[1], "reversed", 1, 1, AsepriteLoopDirection.Reverse, 0, _black, null, _black); - AssertTag(aseFile.Tags[2], "pingpong", 2, 2, AsepriteLoopDirection.PingPong, 0, _black, null, _black); - AssertTag(aseFile.Tags[3], "frames-4-to-6", 3, 5, AsepriteLoopDirection.Forward, 0, _black, null, _black); - AssertTag(aseFile.Tags[4], "userdata", 6, 6, AsepriteLoopDirection.Forward, 0, _green, "hello tag", _green); - - // ************************************************************ - // Frames - // ************************************************************ - Assert.Equal(8, aseFile.Frames.Length); - AssertFrame(aseFile.Frames[0], 3, 2, 2, 100); - AssertFrame(aseFile.Frames[1], 2, 2, 2, 200); - AssertFrame(aseFile.Frames[2], 2, 2, 2, 300); - AssertFrame(aseFile.Frames[3], 2, 2, 2, 400); - AssertFrame(aseFile.Frames[4], 2, 2, 2, 500); - AssertFrame(aseFile.Frames[5], 2, 2, 2, 600); - AssertFrame(aseFile.Frames[6], 2, 2, 2, 700); - AssertFrame(aseFile.Frames[7], 2, 2, 2, 800); - - // ************************************************************ - // Cels - // ************************************************************ - // Frame 0 - Assert.Equal(3, aseFile.Frames[0].Cels.Length); - AssertCel(aseFile.Frames[0].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame0Cel0 = Assert.IsType(aseFile.Frames[0].Cels[0]); - AssertImageCel(frame0Cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[0].Cels[1], "tilemap", 0, 0, 255, null, null); - AsepriteTilemapCel frame0cel1 = Assert.IsType(aseFile.Frames[0].Cels[1]); - AssertTilemapCel(frame0cel1, 2, 2, 4, "tileset"); - AssertTile(frame0cel1.Tiles[0], 1, false, false, false); - AssertTile(frame0cel1.Tiles[1], 2, false, false, false); - AssertTile(frame0cel1.Tiles[2], 3, false, false, false); - AssertTile(frame0cel1.Tiles[3], 4, false, false, false); - - AssertCel(aseFile.Frames[0].Cels[2], "eight-frames", 0, 0, 255, null, null); - AsepriteImageCel frame0cel2 = Assert.IsType(aseFile.Frames[0].Cels[2]); - AssertImageCel(frame0cel2, 1, 1, new Color[] { _red }); - - // Frame 1 - AssertCel(aseFile.Frames[1].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame1Cel0 = Assert.IsType(aseFile.Frames[1].Cels[0]); - AssertImageCel(frame1Cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[1].Cels[1], "eight-frames", 1, 0, 255, null, null); - AsepriteImageCel frame1cel1 = Assert.IsType(aseFile.Frames[1].Cels[1]); - AssertImageCel(frame1cel1, 1, 1, new Color[] { _red }); - - // Frame 2 - AssertCel(aseFile.Frames[2].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame2Cel0 = Assert.IsType(aseFile.Frames[2].Cels[0]); - AssertImageCel(frame2Cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[2].Cels[1], "eight-frames", 0, 1, 255, null, null); - AsepriteImageCel frame2cel1 = Assert.IsType(aseFile.Frames[2].Cels[1]); - AssertImageCel(frame2cel1, 1, 1, new Color[] { _red }); - - // Frame 3 - AssertCel(aseFile.Frames[3].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame3cel0 = Assert.IsType(aseFile.Frames[3].Cels[0]); - AssertImageCel(frame3cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[3].Cels[1], "eight-frames", 1, 1, 255, null, null); - AsepriteImageCel frame3cel1 = Assert.IsType(aseFile.Frames[3].Cels[1]); - AssertImageCel(frame3cel1, 1, 1, new Color[] { _red }); - - // Frame 4 - AssertCel(aseFile.Frames[4].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame4cel0 = Assert.IsType(aseFile.Frames[4].Cels[0]); - AssertImageCel(frame4cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[4].Cels[1], "eight-frames", 0, 0, 255, null, null); - AsepriteImageCel frame4cel1 = Assert.IsType(aseFile.Frames[4].Cels[1]); - AssertImageCel(frame4cel1, 2, 1, new Color[] { _red, _red }); - - // Frame 5 - AssertCel(aseFile.Frames[5].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame5cel0 = Assert.IsType(aseFile.Frames[5].Cels[0]); - AssertImageCel(frame5cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[5].Cels[1], "eight-frames", 0, 1, 255, null, null); - AsepriteImageCel frame5cel1 = Assert.IsType(aseFile.Frames[5].Cels[1]); - AssertImageCel(frame5cel1, 2, 1, new Color[] { _red, _red }); - - // Frame 6 - AssertCel(aseFile.Frames[6].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame6cel0 = Assert.IsType(aseFile.Frames[6].Cels[0]); - AssertImageCel(frame6cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[6].Cels[1], "eight-frames", 0, 0, 255, null, null); - AsepriteImageCel frame6cel1 = Assert.IsType(aseFile.Frames[6].Cels[1]); - AssertImageCel(frame6cel1, 2, 2, new Color[] { _red, _red, _red, _transparent }); - - // Frame 7 - AssertCel(aseFile.Frames[7].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame7cel0 = Assert.IsType(aseFile.Frames[7].Cels[0]); - AssertImageCel(frame7cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[7].Cels[1], "eight-frames", 0, 0, 255, "hello cel", _red); - AsepriteImageCel frame7cel1 = Assert.IsType(aseFile.Frames[7].Cels[1]); - AssertImageCel(frame7cel1, 2, 2, new Color[] { _red, _red, _transparent, _red }); - - // ************************************************************ - // Slices - // ************************************************************ - Assert.Equal(1, aseFile.Slices.Length); - AssertSlice(aseFile.Slices[0], "slice", 1, true, true, "hello slice", _green); - AssertSliceKey(aseFile.Slices[0].Keys[0], 0, new Rectangle(0, 0, 2, 2), new Rectangle(0, 0, 1, 2), new Point(1, 2)); - - // ************************************************************ - // Tilesets - // ************************************************************ - Assert.Equal(1, aseFile.Tilesets.Length); - AssertTileset(aseFile.Tilesets[0], 0, "tileset", 5, 1, 1, 1, 5, new Color[] { _transparent, _white, _red, _green, _blue }); - } - - [Fact] - public void Reads_Version_1_2_9_Expected_Values() - { - string path = FileUtils.GetLocalPath("aseprite-1.2.9-file-reader-test.aseprite"); - AsepriteFile aseFile = AsepriteFileReader.ReadFile(path); - - // ************************************************************ - // File properties - // ************************************************************ - Assert.Equal("aseprite-1.2.9-file-reader-test", aseFile.Name); - Assert.Equal(2, aseFile.CanvasWidth); - Assert.Equal(2, aseFile.CanvasHeight); - AssertUserData(aseFile.UserData, default, default); - - // ************************************************************ - // Layers - // ************************************************************ - Assert.Equal(8, aseFile.Layers.Length); - AssertLayer(aseFile.Layers[0], "background", true, true, false, AsepriteBlendMode.Normal, 255, null, null); - AssertLayer(aseFile.Layers[1], "hidden", false, false, false, AsepriteBlendMode.Normal, 255, null, null); - AssertLayer(aseFile.Layers[2], "100-opacity", true, false, false, AsepriteBlendMode.Normal, 100, null, null); - AssertLayer(aseFile.Layers[3], "userdata", true, false, false, AsepriteBlendMode.Normal, 255, "hello layer", _blue); - AssertLayer(aseFile.Layers[4], "group", true, false, false, AsepriteBlendMode.Normal, 0, null, null); - AssertLayer(aseFile.Layers[5], "child", true, false, false, AsepriteBlendMode.Normal, 255, null, null); - AssertLayer(aseFile.Layers[6], "eight-frames", true, false, false, AsepriteBlendMode.Normal, 255, null, null); - AssertLayer(aseFile.Layers[7], "blend-color-dodge", true, false, false, AsepriteBlendMode.ColorDodge, 255, null, null); - - - // ************************************************************ - // Tags - // ************************************************************ - Assert.Equal(5, aseFile.Tags.Length); - AssertTag(aseFile.Tags[0], "forward", 0, 0, AsepriteLoopDirection.Forward, 0, _black, null, null); - AssertTag(aseFile.Tags[1], "reversed", 1, 1, AsepriteLoopDirection.Reverse, 0, _black, null, null); - AssertTag(aseFile.Tags[2], "pingpong", 2, 2, AsepriteLoopDirection.PingPong, 0, _black, null, null); - AssertTag(aseFile.Tags[3], "frames-4-to-6", 3, 5, AsepriteLoopDirection.Forward, 0, _black, null, null); - AssertTag(aseFile.Tags[4], "userdata", 6, 6, AsepriteLoopDirection.Forward, 0, _green, null, null); - - // ************************************************************ - // Frames - // ************************************************************ - Assert.Equal(8, aseFile.Frames.Length); - AssertFrame(aseFile.Frames[0], 2, 2, 2, 100); - AssertFrame(aseFile.Frames[1], 2, 2, 2, 200); - AssertFrame(aseFile.Frames[2], 2, 2, 2, 300); - AssertFrame(aseFile.Frames[3], 2, 2, 2, 400); - AssertFrame(aseFile.Frames[4], 2, 2, 2, 500); - AssertFrame(aseFile.Frames[5], 2, 2, 2, 600); - AssertFrame(aseFile.Frames[6], 2, 2, 2, 700); - AssertFrame(aseFile.Frames[7], 2, 2, 2, 800); - - // ************************************************************ - // Cels - // ************************************************************ - // Frame 0 - Assert.Equal(2, aseFile.Frames[0].Cels.Length); - AssertCel(aseFile.Frames[0].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame0Cel0 = Assert.IsType(aseFile.Frames[0].Cels[0]); - AssertImageCel(frame0Cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[0].Cels[1], "eight-frames", 0, 0, 255, null, null); - AsepriteImageCel frame0cel1 = Assert.IsType(aseFile.Frames[0].Cels[1]); - AssertImageCel(frame0cel1, 1, 1, new Color[] { _red }); - - // Frame 1 - AssertCel(aseFile.Frames[1].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame1Cel0 = Assert.IsType(aseFile.Frames[1].Cels[0]); - AssertImageCel(frame1Cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[1].Cels[1], "eight-frames", 1, 0, 255, null, null); - AsepriteImageCel frame1cel1 = Assert.IsType(aseFile.Frames[1].Cels[1]); - AssertImageCel(frame1cel1, 1, 1, new Color[] { _red }); - - // Frame 2 - AssertCel(aseFile.Frames[2].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame2Cel0 = Assert.IsType(aseFile.Frames[2].Cels[0]); - AssertImageCel(frame2Cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[2].Cels[1], "eight-frames", 0, 1, 255, null, null); - AsepriteImageCel frame2cel1 = Assert.IsType(aseFile.Frames[2].Cels[1]); - AssertImageCel(frame2cel1, 1, 1, new Color[] { _red }); - - // Frame 3 - AssertCel(aseFile.Frames[3].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame3cel0 = Assert.IsType(aseFile.Frames[3].Cels[0]); - AssertImageCel(frame3cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[3].Cels[1], "eight-frames", 1, 1, 255, null, null); - AsepriteImageCel frame3cel1 = Assert.IsType(aseFile.Frames[3].Cels[1]); - AssertImageCel(frame3cel1, 1, 1, new Color[] { _red }); - - // Frame 4 - AssertCel(aseFile.Frames[4].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame4cel0 = Assert.IsType(aseFile.Frames[4].Cels[0]); - AssertImageCel(frame4cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[4].Cels[1], "eight-frames", 0, 0, 255, null, null); - AsepriteImageCel frame4cel1 = Assert.IsType(aseFile.Frames[4].Cels[1]); - AssertImageCel(frame4cel1, 2, 1, new Color[] { _red, _red }); - - // Frame 5 - AssertCel(aseFile.Frames[5].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame5cel0 = Assert.IsType(aseFile.Frames[5].Cels[0]); - AssertImageCel(frame5cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[5].Cels[1], "eight-frames", 0, 1, 255, null, null); - AsepriteImageCel frame5cel1 = Assert.IsType(aseFile.Frames[5].Cels[1]); - AssertImageCel(frame5cel1, 2, 1, new Color[] { _red, _red }); - - // Frame 6 - AssertCel(aseFile.Frames[6].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame6cel0 = Assert.IsType(aseFile.Frames[6].Cels[0]); - AssertImageCel(frame6cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[6].Cels[1], "eight-frames", 0, 0, 255, null, null); - AsepriteImageCel frame6cel1 = Assert.IsType(aseFile.Frames[6].Cels[1]); - AssertImageCel(frame6cel1, 2, 2, new Color[] { _red, _red, _red, _transparent }); - - // Frame 7 - AssertCel(aseFile.Frames[7].Cels[0], "background", 0, 0, 255, null, null); - AsepriteImageCel frame7cel0 = Assert.IsType(aseFile.Frames[7].Cels[0]); - AssertImageCel(frame7cel0, 2, 2, new Color[] { _black, _black, _black, _black }); - - AssertCel(aseFile.Frames[7].Cels[1], "eight-frames", 0, 0, 255, "hello cel", _red); - AsepriteImageCel frame7cel1 = Assert.IsType(aseFile.Frames[7].Cels[1]); - AssertImageCel(frame7cel1, 2, 2, new Color[] { _red, _red, _transparent, _red }); - - // ************************************************************ - // Slices - // ************************************************************ - Assert.Equal(1, aseFile.Slices.Length); - AssertSlice(aseFile.Slices[0], "slice", 1, true, true, "hello slice", _green); - AssertSliceKey(aseFile.Slices[0].Keys[0], 0, new Rectangle(0, 0, 2, 2), new Rectangle(0, 0, 1, 2), new Point(1, 2)); - - // ************************************************************ - // Tilesets - // ************************************************************ - Assert.Equal(0, aseFile.Tilesets.Length); - } - - private void AssertLayer(AsepriteLayer layer, string name, bool isVisible, bool isBackground, bool isReference, AsepriteBlendMode blendMode, int opacity, string? userDataText, Color? userDataColor) - { - Assert.Equal(name, layer.Name); - Assert.Equal(isVisible, layer.IsVisible); - Assert.Equal(isBackground, layer.IsBackground); - Assert.Equal(isReference, layer.IsReference); - Assert.Equal(blendMode, layer.BlendMode); - Assert.Equal(opacity, layer.Opacity); - AssertUserData(layer.UserData, userDataText, userDataColor); - } - - private void AssertTilemapLayer(AsepriteTilemapLayer tilemapLayer, string tilesetName) - { - Assert.Equal(tilesetName, tilemapLayer.Tileset.Name); - } - - private void AssertTag(AsepriteTag tag, string name, int from, int to, AsepriteLoopDirection direction, int repeat, Color color, string? userDataText, Color? userDataColor) - { - Assert.Equal(name, tag.Name); - Assert.Equal(from, tag.From); - Assert.Equal(to, tag.To); - Assert.Equal(repeat, tag.Repeat); - Assert.Equal(direction, tag.Direction); - Assert.Equal(color, tag.Color); - AssertUserData(tag.UserData, userDataText, userDataColor); - } - - private void AssertFrame(AsepriteFrame frame, int celCount, int width, int height, int duration) - { - Assert.Equal(celCount, frame.Cels.Length); - Assert.Equal(width, frame.Width); - Assert.Equal(height, frame.Height); - Assert.Equal(duration, frame.DurationInMilliseconds); - } - - private void AssertCel(AsepriteCel cel, string layerName, int x, int y, int opacity, string? userDataText, Color? userDataColor) - { - Assert.Equal(layerName, cel.Layer.Name); - Assert.Equal(x, cel.Position.X); - Assert.Equal(y, cel.Position.Y); - Assert.Equal(opacity, cel.Opacity); - AssertUserData(cel.UserData, userDataText, userDataColor); - } - - private void AssertImageCel(AsepriteImageCel imageCel, int width, int height, Color[] pixels) - { - Assert.Equal(width, imageCel.Width); - Assert.Equal(height, imageCel.Height); - Assert.Equal(pixels, imageCel.Pixels.ToArray()); - } - - private void AssertTilemapCel(AsepriteTilemapCel tilemapCel, int columns, int rows, int tileCount, string tilesetName) - { - Assert.Equal(columns, tilemapCel.Columns); - Assert.Equal(rows, tilemapCel.Rows); - Assert.Equal(tileCount, tilemapCel.Tiles.Length); - Assert.Equal(tileCount, tilemapCel.TileCount); - Assert.Equal(tilesetName, tilemapCel.Tileset.Name); - } - - private void AssertTile(AsepriteTile tile, int tilesetTileID, bool xFlip, bool yFlip, bool dFlip) - { - Assert.Equal(tilesetTileID, tile.TilesetTileID); - Assert.Equal(xFlip, tile.XFlip); - Assert.Equal(yFlip, tile.YFlip); - Assert.Equal(dFlip, tile.DFlip); - } - - private void AssertSlice(AsepriteSlice slice, string name, int keyCount, bool isNine, bool hasPivot, string? userDataText, Color? userDataColor) - { - Assert.Equal(name, slice.Name); - Assert.Equal(isNine, slice.IsNinePatch); - Assert.Equal(hasPivot, slice.HasPivot); - Assert.Equal(keyCount, slice.Keys.Length); - Assert.Equal(keyCount, slice.KeyCount); - AssertUserData(slice.UserData, userDataText, userDataColor); - } - - private void AssertSliceKey(AsepriteSliceKey key, int frame, Rectangle bounds, Rectangle? center, Point? pivot) - { - Assert.Equal(frame, key.FrameIndex); - Assert.Equal(bounds, key.Bounds); - Assert.Equal(center, key.CenterBounds); - Assert.Equal(center is not null, key.IsNinePatch); - Assert.Equal(pivot, key.Pivot); - Assert.Equal(pivot is not null, key.HasPivot); - } - - private void AssertTileset(AsepriteTileset tileset, int id, string name, int tileCount, int tileWidth, int tileHeight, int width, int height, Color[] pixels) - { - Assert.Equal(id, tileset.ID); - Assert.Equal(name, tileset.Name); - Assert.Equal(tileCount, tileset.TileCount); - Assert.Equal(tileWidth, tileset.TileWidth); - Assert.Equal(tileHeight, tileset.TileHeight); - Assert.Equal(width, tileset.Width); - Assert.Equal(height, tileset.Height); - Assert.Equal(pixels, tileset.Pixels.ToArray()); - } - - private void AssertUserData(AsepriteUserData userData, string? text, Color? color) - { - Assert.Equal(text, userData.Text); - Assert.Equal(color, userData.Color); - } -} diff --git a/tests/MonoGame.Aseprite.Tests/MonoGame.Aseprite.Tests.csproj b/tests/MonoGame.Aseprite.Tests/MonoGame.Aseprite.Tests.csproj deleted file mode 100644 index a3bdc521..00000000 --- a/tests/MonoGame.Aseprite.Tests/MonoGame.Aseprite.Tests.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - net8.0 - - - - - - - - - - - All - - - - - - diff --git a/tests/MonoGame.Aseprite.Tests/Usings.cs b/tests/MonoGame.Aseprite.Tests/Usings.cs deleted file mode 100644 index 8c927eb7..00000000 --- a/tests/MonoGame.Aseprite.Tests/Usings.cs +++ /dev/null @@ -1 +0,0 @@ -global using Xunit; \ No newline at end of file diff --git a/tests/MonoGame.Aseprite.Tests/UtilityTests/BlendFunctionsTests.cs b/tests/MonoGame.Aseprite.Tests/UtilityTests/BlendFunctionsTests.cs deleted file mode 100644 index 6e61c4bc..00000000 --- a/tests/MonoGame.Aseprite.Tests/UtilityTests/BlendFunctionsTests.cs +++ /dev/null @@ -1,723 +0,0 @@ -/* ---------------------------------------------------------------------------- -MIT License - -Copyright (c) 2018-2023 Christopher Whitley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ----------------------------------------------------------------------------- */ - -using Microsoft.Xna.Framework; -using MonoGame.Aseprite.AsepriteTypes; -using MonoGame.Aseprite.Utilities; - -namespace MonoGame.Aseprite.Tests; - -/* - In order to test the blend modes, I needed to have hard factual values to assert as the expected values after - performing a blend. Since the blend functions were ported form Aseprite, we'll use Aseprite itself as the source - of truth for what the values should be. - - To get these values, a 4x4 sprite was created with the following colors - - * orange = argb(255, 223, 113, 38) - * green = argb(255, 106, 190, 48) - * purple = argb(255, 63, 63, 116) - * pink = argb(255, 215, 123, 186) - * red = argb(255, 172, 50, 50) - * transparent = argb(0, 0, 0, 0) - - Next two layers were added to the sprite. The bottom layer consists of the following pixels, in order from - top-to-bottom, read left-to-right - - [Layer 1] - green, green, purple, purple, - green, green, purple, purple, - pink, pink, red, red, - pink, pink, red, red, - - The top layers consists fo the following pixels, in order from top-to-bottom, read left-to-right - - [Layer 2] - transparent, transparent, transparent, transparent, - transparent, orange, orange, transparent, - transparent, orange, orange, transparent, - transparent, transparent, transparent, transparent, - - There is much simpler ways of doing this (like making it a 2x2 image and trimming off the transparent border), but - this is what i did. Anyway, the next steps was to set the Blend Mode used by the top layer, then copy the RGBA value - of each pixel where it overlapped one of the base layer colors into the test for that blend mode. - - It was a manual process, but the point of the tests is to ensure that the ported code blends colors the same way - that Aseprite does to match it 1:1. -*/ -public sealed class BlendFunctionsTests -{ - private static readonly Color _green = new Color(106, 190, 48, 255); - private static readonly Color _purple = new Color(63, 63, 116, 255); - private static readonly Color _pink = new Color(215, 123, 186, 255); - private static readonly Color _red = new Color(172, 50, 50, 255); - private static readonly Color _orange = new Color(223, 113, 38, 255); - private static readonly Color _transparent = new Color(0, 0, 0, 0); - - [Fact] - public void BlendFunctions_Blend_Normal_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Normal; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(_orange, BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(_orange, BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(_orange, BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Normal_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Normal; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Normal_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Normal; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Normal_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Normal; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Darken_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Darken; - Assert.Equal(new Color(106, 113, 38, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(63, 63, 38, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(215, 113, 38, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(172, 50, 38, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Darken_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Darken; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Darken_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Darken; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Darken_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Darken; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Multiply_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Multiply; - Assert.Equal(new Color(93, 84, 7, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(55, 28, 17, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(188, 55, 28, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(150, 22, 7, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Multiply_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Multiply; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Multiply_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Multiply; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Multiply_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Multiply; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_ColorBurn_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.ColorBurn; - Assert.Equal(new Color(85, 108, 0, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(35, 0, 0, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(209, 0, 0, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(160, 0, 0, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_ColorBurn_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.ColorBurn; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_ColorBurn_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.ColorBurn; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_ColorBurn_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.ColorBurn; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Lighten_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Lighten; - Assert.Equal(new Color(223, 190, 48, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(223, 113, 116, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(223, 123, 186, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(223, 113, 50, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Lighten_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Lighten; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Lighten_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Lighten; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Lighten_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Lighten; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Screen_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Screen; - Assert.Equal(new Color(236, 219, 79, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(231, 148, 137, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(250, 181, 196, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(245, 141, 81, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Screen_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Screen; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Screen_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Screen; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Screen_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Screen; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_ColorDodge_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.ColorDodge; - Assert.Equal(new Color(255, 255, 56, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(255, 113, 136, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(255, 221, 219, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(255, 90, 59, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_ColorDodge_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.ColorDodge; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_ColorDodge_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.ColorDodge; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_ColorDodge_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.ColorDodge; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Addition_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Addition; - Assert.Equal(new Color(255, 255, 86, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(255, 176, 154, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(255, 236, 224, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(255, 163, 88, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Addition_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Addition; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Addition_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Addition; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Addition_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Addition; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Overlay_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Overlay; - Assert.Equal(new Color(185, 183, 14, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(110, 56, 35, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(245, 109, 138, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(234, 44, 15, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Overlay_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Overlay; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Overlay_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Overlay; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Overlay_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Overlay; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_SoftLight_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.SoftLight; - Assert.Equal(new Color(150, 184, 21, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(111, 58, 72, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(229, 116, 151, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(200, 45, 22, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_SoftLight_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.SoftLight; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_SoftLight_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.SoftLight; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_SoftLight_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.SoftLight; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_HardLight_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.HardLight; - Assert.Equal(new Color(218, 168, 14, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(207, 56, 35, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(245, 109, 55, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(234, 44, 15, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_HardLight_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.HardLight; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_HardLight_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.HardLight; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_HardLight_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.HardLight; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Difference_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Difference; - Assert.Equal(new Color(117, 77, 10, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(160, 50, 78, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(8, 10, 148, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(51, 63, 12, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Difference_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Difference; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Difference_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Difference; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Difference_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Difference; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Exclusion_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Exclusion; - Assert.Equal(new Color(143, 135, 72, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(176, 120, 120, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(62, 126, 168, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(95, 119, 74, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Exclusion_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Exclusion; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Exclusion_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Exclusion; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Exclusion_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Exclusion; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Subtract_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Subtract; - Assert.Equal(new Color(0, 77, 10, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(0, 0, 78, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(0, 10, 148, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(0, 0, 12, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Subtract_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Subtract; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Subtract_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Subtract; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Subtract_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Subtract; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Divide_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Divide; - Assert.Equal(new Color(121, 255, 255, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(72, 142, 255, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(246, 255, 255, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(197, 113, 255, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Divide_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Divide; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Divide_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Divide; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Divide_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Divide; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Hue_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Hue; - Assert.Equal(new Color(214, 130, 72, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(93, 61, 40, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(199, 145, 107, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(142, 70, 20, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Hue_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Hue; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Hue_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Hue; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Hue_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Hue; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Saturation_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Saturation; - Assert.Equal(new Color(92, 202, 17, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(92, 29, 214, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(255, 98, 205, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(186, 51, 1, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Saturation_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Saturation; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Saturation_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Saturation; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Saturation_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Saturation; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Color_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Color; - Assert.Equal(new Color(234, 124, 49, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(127, 51, 0, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(242, 132, 57, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(160, 65, 0, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Color_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Color; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Color_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Color; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Color_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Color; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Luminosity_ColorOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Luminosity; - Assert.Equal(new Color(94, 178, 36, 255), BlendFunctions.Blend(mode, _green, _orange, 255)); - Assert.Equal(new Color(131, 131, 184, 255), BlendFunctions.Blend(mode, _purple, _orange, 255)); - Assert.Equal(new Color(195, 103, 166, 255), BlendFunctions.Blend(mode, _pink, _orange, 255)); - Assert.Equal(new Color(223, 101, 101, 255), BlendFunctions.Blend(mode, _red, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Luminosity_ColorOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Luminosity; - Assert.Equal(_orange, BlendFunctions.Blend(mode, _transparent, _orange, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Luminosity_TransparentOnColorTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Luminosity; - Assert.Equal(_green, BlendFunctions.Blend(mode, _green, _transparent, 255)); - Assert.Equal(_purple, BlendFunctions.Blend(mode, _purple, _transparent, 255)); - Assert.Equal(_pink, BlendFunctions.Blend(mode, _pink, _transparent, 255)); - Assert.Equal(_red, BlendFunctions.Blend(mode, _red, _transparent, 255)); - } - - [Fact] - public void BlendFunctions_Blend_Luminosity_TransparentOnTransparentTest() - { - AsepriteBlendMode mode = AsepriteBlendMode.Luminosity; - Assert.Equal(_transparent, BlendFunctions.Blend(mode, _transparent, _transparent, 255)); - } -}