Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
stevemonaco committed Sep 29, 2020
2 parents 6db8d64 + ff142c9 commit 1be5537
Show file tree
Hide file tree
Showing 25 changed files with 2,650 additions and 2,454 deletions.
1 change: 1 addition & 0 deletions ImageMagitek.Services/ProjectService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Xml;
using System.Xml.Schema;
using ImageMagitek.Project;
using ImageMagitek.Project.Serialization;
using Monaco.PathTree;

namespace ImageMagitek.Services
Expand Down
10 changes: 7 additions & 3 deletions ImageMagitek/Arranger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public abstract class Arranger : IProjectResource
public abstract bool ShouldBeSerialized { get; set; }

public abstract void Resize(int arrangerWidth, int arrangerHeight);
public abstract void Resize(int arrangerWidth, int arrangerHeight, Func<int, int, ArrangerElement> elementFactory);

private readonly BlankDirectCodec _blankDirectCodec = new BlankDirectCodec();
private readonly BlankIndexedCodec _blankIndexedCodec = new BlankIndexedCodec();
Expand Down Expand Up @@ -139,10 +140,13 @@ public virtual void SetElement(in ArrangerElement element, int posX, int posY)
if (posX >= ArrangerElementSize.Width || posY >= ArrangerElementSize.Height)
throw new ArgumentOutOfRangeException($"{nameof(SetElement)} parameter was out of range: ({posX}, {posY})");

if (element.Codec != null)
if (element.Codec is object)
if (element.Codec.ColorType != ColorType)
throw new ArgumentException($"{nameof(SetElement)} parameter '{nameof(element)}' did not match the Arranger's {nameof(PixelColorType)}");

//if (ColorType == PixelColorType.Indexed && element.Palette is null && element.DataFile is object)
// throw new ArgumentException($"{nameof(SetElement)} parameter '{nameof(element)}' does not contain a palette");

var relocatedElement = element.WithLocation(posX * ElementPixelSize.Width, posY * ElementPixelSize.Height);
ElementGrid[posX, posY] = relocatedElement;
}
Expand All @@ -163,9 +167,9 @@ public virtual void ResetElement(int posX, int posY)
var el = GetElement(posX, posY);

if (ColorType == PixelColorType.Indexed)
el = new ArrangerElement(el.X1, el.Y1, null, 0, _blankIndexedCodec, null);
el = el.WithTarget(null, 0, _blankIndexedCodec, el.Palette);
else if (ColorType == PixelColorType.Direct)
el = new ArrangerElement(el.X1, el.Y1, null, 0, _blankDirectCodec, null);
el = el = el.WithTarget(null, 0, _blankDirectCodec, null);

SetElement(el, posX, posY);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Monaco.PathTree;

namespace ImageMagitek.Project
namespace ImageMagitek.Project.Serialization
{
public interface IGameDescriptorReader
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Monaco.PathTree;

namespace ImageMagitek.Project
namespace ImageMagitek.Project.Serialization
{
public interface IGameDescriptorWriter
{
Expand Down
189 changes: 189 additions & 0 deletions ImageMagitek/Project/Serialization/ProjectTreeBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ImageMagitek.Codec;
using ImageMagitek.Colors;
using Monaco.PathTree;

namespace ImageMagitek.Project.Serialization
{
/// <summary>
/// Builds a ProjectTree and resolves resources from Serialization Models
/// </summary>
class ProjectTreeBuilder
{
public PathTree<IProjectResource> Tree { get; } = new PathTree<IProjectResource>();
private readonly List<IProjectResource> _globalResources;
private readonly Palette _globalDefaultPalette;
private readonly ICodecFactory _codecFactory;

public ProjectTreeBuilder(ICodecFactory codecFactory, IEnumerable<IProjectResource> globalResources)
{
_codecFactory = codecFactory;
_globalResources = globalResources.ToList();
_globalDefaultPalette = _globalResources.OfType<Palette>().FirstOrDefault();
}

public MagitekResult AddProject(ImageProjectModel projectModel)
{
if (Tree.Root is object)
return new MagitekResult.Failed($"Attempted to add a new project '{projectModel?.Name}' to an existing project");

var project = new ImageProject(projectModel.Name);
project.Root = projectModel.Root;

Tree.Root = new ProjectNode(project.Name, project);
return MagitekResult.SuccessResult;
}

public MagitekResult AddFolder(ResourceFolderModel folderModel, string parentNodePath)
{
var folder = new ResourceFolder(folderModel.Name);

var folderNode = new FolderNode(folder.Name, folder);
Tree.TryGetNode(parentNodePath, out var parentNode);
parentNode.AttachChild(folderNode);

return MagitekResult.SuccessResult;
}

public MagitekResult AddDataFile(DataFileModel dfModel, string parentNodePath)
{
var df = new DataFile(dfModel.Name, dfModel.Location);

var dfNode = new DataFileNode(df.Name, df);
Tree.TryGetNode(parentNodePath, out var parentNode);
parentNode.AttachChild(dfNode);

if (!File.Exists(df.Location))
return new MagitekResult.Failed($"DataFile '{df.Name}' does not exist at location '{df.Location}'");

return MagitekResult.SuccessResult;
}

public MagitekResult AddPalette(PaletteModel paletteModel, string parentNodePath)
{
var pal = new Palette(paletteModel.Name, paletteModel.ColorModel, paletteModel.FileAddress, paletteModel.Entries, paletteModel.ZeroIndexTransparent, paletteModel.StorageSource);

if (!Tree.TryGetValue<DataFile>(paletteModel.DataFileKey, out var df))
return new MagitekResult.Failed($"Palette '{pal.Name}' could not locate DataFile with key '{paletteModel.DataFileKey}'");

pal.DataFile = df;
pal.LazyLoadPalette(pal.DataFile, pal.FileAddress, pal.ColorModel, pal.ZeroIndexTransparent, pal.Entries);

var palNode = new PaletteNode(pal.Name, pal);
Tree.TryGetNode(parentNodePath, out var parentNode);
parentNode.AttachChild(palNode);

return MagitekResult.SuccessResult;
}

public MagitekResult AddScatteredArranger(ScatteredArrangerModel arrangerModel, string parentNodePath)
{
var arranger = new ScatteredArranger(arrangerModel.Name, arrangerModel.ColorType, arrangerModel.Layout,
arrangerModel.ArrangerElementSize.Width, arrangerModel.ArrangerElementSize.Height, arrangerModel.ElementPixelSize.Width, arrangerModel.ElementPixelSize.Height);

for (int x = 0; x < arrangerModel.ElementGrid.GetLength(0); x++)
{
for (int y = 0; y < arrangerModel.ElementGrid.GetLength(1); y++)
{
var result = CreateElement(arrangerModel, x, y);

if (result.IsT0)
{
arranger.SetElement(result.AsT0.Result, x, y);
}
else if (result.IsT1)
{
return new MagitekResult.Failed(result.AsT1.Reason);
}
}
}

var arrangerNode = new ArrangerNode(arranger.Name, arranger);
Tree.TryGetNode(parentNodePath, out var parentNode);
parentNode.AttachChild(arrangerNode);

return MagitekResult.SuccessResult;
}

/// <summary>
/// Resolves a palette resource using the supplied project tree and falls back to a default palette if available
/// </summary>
/// <param name="tree"></param>
/// <param name="paletteKey"></param>
/// <returns></returns>
private Palette ResolvePalette(string paletteKey)
{
var pal = _globalDefaultPalette;

if (string.IsNullOrEmpty(paletteKey))
{
return _globalDefaultPalette;
}
else if (!Tree.TryGetValue<Palette>(paletteKey, out pal))
{
var name = paletteKey.Split(Tree.PathSeparators).Last();
pal = _globalResources.OfType<Palette>().FirstOrDefault(x => string.Equals(x.Name, name, StringComparison.OrdinalIgnoreCase));
}

return pal;
}

private MagitekResult<ArrangerElement> CreateElement(ScatteredArrangerModel arrangerModel, int x, int y)
{
var elementModel = arrangerModel.ElementGrid[x, y];
IGraphicsCodec codec = default;
Palette palette = default;
DataFile df = default;
FileBitAddress address = 0;

if (elementModel is null)
{
if (arrangerModel.ColorType == PixelColorType.Indexed)
{
codec = new BlankIndexedCodec();
palette = _globalDefaultPalette;
}
else if (arrangerModel.ColorType == PixelColorType.Direct)
{
codec = new BlankDirectCodec();
}
}
else if (arrangerModel.ColorType == PixelColorType.Indexed)
{
if (!string.IsNullOrWhiteSpace(arrangerModel.ElementGrid[x, y].DataFileKey))
Tree.TryGetValue<DataFile>(arrangerModel.ElementGrid[x, y].DataFileKey, out df);

address = elementModel.FileAddress;
var paletteKey = elementModel.PaletteKey;
palette = ResolvePalette(paletteKey);

if (palette is null)
{
return new MagitekResult<ArrangerElement>.Failed($"Could not resolve palette '{paletteKey}' referenced by arranger '{arrangerModel.Name}'");
}

codec = _codecFactory.GetCodec(arrangerModel.ElementGrid[x, y].CodecName, arrangerModel.ElementPixelSize.Width, arrangerModel.ElementPixelSize.Height);
}
else if (arrangerModel.ColorType == PixelColorType.Direct)
{
if (!string.IsNullOrWhiteSpace(arrangerModel.ElementGrid[x, y].DataFileKey))
Tree.TryGetValue<DataFile>(arrangerModel.ElementGrid[x, y].DataFileKey, out df);

address = elementModel.FileAddress;
codec = _codecFactory.GetCodec(arrangerModel.ElementGrid[x, y].CodecName, arrangerModel.ElementPixelSize.Width, arrangerModel.ElementPixelSize.Height);
}
else
{
throw new InvalidOperationException($"{nameof(CreateElement)}: Arranger '{arrangerModel.Name}' has invalid {nameof(PixelColorType)} '{arrangerModel.ColorType}'");
}

var pixelX = x * arrangerModel.ElementPixelSize.Width;
var pixelY = y * arrangerModel.ElementPixelSize.Height;
var el = new ArrangerElement(pixelX, pixelY, df, address, codec, palette);
return new MagitekResult<ArrangerElement>.Success(el);
}
}
}
Loading

0 comments on commit 1be5537

Please sign in to comment.