Skip to content

Commit

Permalink
First cut at bitmap sets.
Browse files Browse the repository at this point in the history
  • Loading branch information
BorisTheBrave committed Oct 20, 2018
1 parent 72922a5 commit f730a5f
Show file tree
Hide file tree
Showing 19 changed files with 531 additions and 70 deletions.
202 changes: 194 additions & 8 deletions DeBroglie.Console/BitmapSaver.cs
@@ -1,27 +1,63 @@
using DeBroglie.Models;
using DeBroglie.Console.Export;
using DeBroglie.Models;
using DeBroglie.Topo;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

namespace DeBroglie.Console
{

public class BitmapSaver : ISampleSetSaver
{
public void Save(TileModel model, TilePropagator propagator, string filename, DeBroglieConfig config, object template)
public void Save(TileModel model, TilePropagator propagator, string filename, DeBroglieConfig config, ExportOptions exportOptions)
{
if (config.Animate)
{
if (exportOptions is BitmapExportOptions)
{
var topoArray = propagator.ToValueSets<Color>().Map(BitmapUtils.ColorAverage);
var bitmap = BitmapUtils.ToBitmap(topoArray.ToArray2d());
bitmap.Save(filename);
}
else if (exportOptions is BitmapSetExportOptions)
{
throw new Exception("Animate not supported with bitmap sets yet");
}
else
{
throw new System.Exception($"Cannot export from {exportOptions.TypeDescription} to bitmap.");
}

var topoArray = propagator.ToArraySets().Map(BitmapUtils.ColorAverage);
var bitmap = BitmapUtils.ToBitmap(topoArray.ToArray2d());
bitmap.Save(filename);
}
else
{
var topoArray = propagator.ToValueArray(Color.Gray, Color.Magenta);
var bitmap = BitmapUtils.ToBitmap(topoArray.ToArray2d());
bitmap.Save(filename);
if (exportOptions is BitmapExportOptions)
{
var topoArray = propagator.ToValueArray(Color.Gray, Color.Magenta);
var bitmap = BitmapUtils.ToBitmap(topoArray.ToArray2d());
bitmap.Save(filename);
}
else if (exportOptions is BitmapSetExportOptions bseo)
{
var undecided = new Tile(new object());
var contradiction = new Tile(new object());
var topoArray = propagator.ToArray(undecided, contradiction);

var tileTopology = topoArray.Topology.WithSize(bseo.TileWidth, bseo.TileHeight, 1);
var tiles = bseo.Bitmaps.ToDictionary(x => x.Key, x => TopoArray.Create(BitmapUtils.ToColorArray(x.Value), tileTopology));
tiles[undecided] = TopoArray.FromConstant(Color.Gray, tileTopology);
tiles[contradiction] = TopoArray.FromConstant(Color.Magenta, tileTopology);

var exploded = ExplodeTiles(topoArray, tiles, bseo.TileWidth, bseo.TileHeight, 1);
var bitmap = BitmapUtils.ToBitmap(exploded.ToArray2d());
bitmap.Save(filename);
}
else
{
throw new System.Exception($"Cannot export from {exportOptions.TypeDescription} to bitmap.");
}
}
}

Expand Down Expand Up @@ -54,5 +90,155 @@ private static ITopoArray<T> Scale<T>(ITopoArray<T> topoArray, int scale)
var resultTopology = topology.WithSize(topology.Width * scale, topology.Height * scale, topology.Depth * scale);
return TopoArray.Create(result, resultTopology);
}

private static ITopoArray<V> ExplodeTiles<V>(ITopoArray<Tile> topoArray, IDictionary<Tile, ITopoArray<V>> subTiles, int tileWidth, int tileHeight, int tileDepth)
{
return Explode(topoArray, tile => GetSubTile(tile, subTiles), tileWidth, tileHeight, tileDepth);
}

private static ITopoArray<IEnumerable<V>> ExplodeTileSets<V>(ITopoArray<ISet<Tile>> topoArray, IDictionary<Tile, ITopoArray<V>> subTiles, int tileWidth, int tileHeight, int tileDepth)
{
return ExplodeSets(topoArray, tile => GetSubTile(tile, subTiles), tileWidth, tileHeight, tileDepth);

}

private static ITopoArray<V> GetSubTile<V>(Tile tile, IDictionary<Tile, ITopoArray<V>> subTiles)
{
if(tile.Value is RotatedTile rt)
{
subTiles.TryGetValue(rt.Tile, out var subTile);
return TopoArrayUtils.Rotate(subTile, rt.RotateCw, rt.ReflectX);
}
else
{
subTiles.TryGetValue(tile, out var result);
return result;
}
}

private static ITopoArray<V> Explode<U, V>(ITopoArray<U> topoArray, Func<U, ITopoArray<V>> getSubTile, int tileWidth, int tileHeight, int tileDepth)
{
if (topoArray.Topology.Directions.Type != DirectionsType.Cartesian2d && topoArray.Topology.Directions.Type != DirectionsType.Cartesian3d)
throw new NotImplementedException();

var inTopology = topoArray.Topology;
var inWidth = inTopology.Width;
var inHeight = inTopology.Height;
var inDepth = inTopology.Depth;

var resultTopology = inTopology.WithSize(
inWidth * tileWidth,
inHeight * tileHeight,
inDepth * tileDepth
);
var result = new V[resultTopology.Width, resultTopology.Height, resultTopology.Depth];
var mask = new bool[resultTopology.Width * resultTopology.Height * resultTopology.Depth];

for (var z = 0; z < inDepth; z++)
{
for (var y = 0; y < inHeight; y++)
{
for (var x = 0; x < inWidth; x++)
{
if(inTopology.Mask != null)
{
var index = inTopology.GetIndex(x, y, z);
if (!inTopology.Mask[index])
continue;
}
var inTile = topoArray.Get(x, y, z);
var subTile = getSubTile(inTile);
if (subTile == null)
continue;
for (var tz = 0; tz < tileDepth; tz++)
{
for (var ty = 0; ty < tileHeight; ty++)
{
for (var tx = 0; tx < tileWidth; tx++)
{
if(subTile.Topology.Mask != null)
{
var index = subTile.Topology.GetIndex(tx, ty, tz);
if (!subTile.Topology.Mask[index])
continue;
}
result[x * tileWidth + tx, y * tileHeight + ty, z * tileDepth * tz]
= subTile.Get(tx, ty, tz);
mask[resultTopology.GetIndex(x * tileWidth + tx, y * tileHeight + ty, z * tileDepth * tz)] = true;
}
}
}
}
}
}

return TopoArray.Create(result, resultTopology);
}

private static ITopoArray<IEnumerable<V>> ExplodeSets<U, V>(ITopoArray<ISet<U>> topoArray, Func<U, ITopoArray<V>> getSubTile, int tileWidth, int tileHeight, int tileDepth)
{
if (topoArray.Topology.Directions.Type != DirectionsType.Cartesian2d && topoArray.Topology.Directions.Type != DirectionsType.Cartesian3d)
throw new NotImplementedException();

var inTopology = topoArray.Topology;
var inWidth = inTopology.Width;
var inHeight = inTopology.Height;
var inDepth = inTopology.Depth;

var resultTopology = inTopology.WithSize(
inWidth * tileWidth,
inHeight * tileHeight,
inDepth * tileDepth
);
var result = new IEnumerable<V>[resultTopology.Width, resultTopology.Height, resultTopology.Depth];
var mask = new bool[resultTopology.Width * resultTopology.Height * resultTopology.Depth];

for (var z = 0; z < inDepth; z++)
{
for (var y = 0; y < inHeight; y++)
{
for (var x = 0; x < inWidth; x++)
{
if (inTopology.Mask != null)
{
var index = inTopology.GetIndex(x, y, z);
if (!inTopology.Mask[index])
continue;
}
var inTileSet = topoArray.Get(x, y, z);
if (inTileSet.Count == 0)
continue;
for (var tz = 0; tz < tileDepth; tz++)
{
for (var ty = 0; ty < tileHeight; ty++)
{
for (var tx = 0; tx < tileWidth; tx++)
{
var outSet = new List<V>();
foreach (var inTile in inTileSet)
{
var subTile = getSubTile(inTile);
if (subTile == null)
continue;

if (subTile.Topology.Mask != null)
{
var index = subTile.Topology.GetIndex(tx, ty, tz);
if (!subTile.Topology.Mask[index])
continue;
}
outSet.Add(subTile.Get(tx, ty, tz));
mask[resultTopology.GetIndex(x * tileWidth + tx, y * tileHeight + ty, z * tileDepth * tz)] = true;
}
result[x * tileWidth + tx, y * tileHeight + ty, z * tileDepth * tz] = outSet;
}
}
}
}
}
}

return TopoArray.Create(result, resultTopology);
}
}
}
5 changes: 2 additions & 3 deletions DeBroglie.Console/BitmapUtils.cs
Expand Up @@ -31,16 +31,15 @@ public static Bitmap ToBitmap(Color[,] colorArray)
return bitmap;
}

public static Color ColorAverage(ISet<Tile> tiles)
public static Color ColorAverage(IEnumerable<Color> colors)
{
int alpha = 0;
int red = 0;
int green = 0;
int blue = 0;
int n = 0;
foreach (var tile in tiles)
foreach (var color in colors)
{
var color = (Color)tile.Value;
alpha += color.A;
red += color.R;
green += color.G;
Expand Down
5 changes: 3 additions & 2 deletions DeBroglie.Console/CsvSaver.cs
@@ -1,11 +1,12 @@
using DeBroglie.Models;
using DeBroglie.Console.Export;
using DeBroglie.Models;
using System.IO;

namespace DeBroglie.Console
{
public class CsvSaver : ISampleSetSaver
{
public void Save(TileModel model, TilePropagator tilePropagator, string filename, DeBroglieConfig config, object template)
public void Save(TileModel model, TilePropagator tilePropagator, string filename, DeBroglieConfig config, ExportOptions exportOptions)
{
var array = tilePropagator.ToArray(new Tile("?"), new Tile("!"));
using (var s = File.OpenWrite(filename))
Expand Down
2 changes: 2 additions & 0 deletions DeBroglie.Console/DeBroglie.Console.csproj
Expand Up @@ -57,6 +57,8 @@
<Compile Include="ConstraintArrayConverter.cs" />
<Compile Include="CsvSaver.cs" />
<Compile Include="DeBroglieConfig.cs" />
<Compile Include="Export\ExportOptions.cs" />
<Compile Include="ISampleSetSaver.cs" />
<Compile Include="ItemsProcessor.cs" />
<Compile Include="MagicaVoxelLoader.cs" />
<Compile Include="MagicaVoxelSaver.cs" />
Expand Down
26 changes: 23 additions & 3 deletions DeBroglie.Console/DeBroglieConfig.cs
Expand Up @@ -7,18 +7,33 @@
namespace DeBroglie.Console
{

public enum SrcType
{
/// <summary>
/// Load a single file specified by
/// </summary>
Sample,
BitmapSet,
VoxSet,
}

public class DeBroglieConfig
{
/// <summary>
/// The file to load as the initial sample.
///
/// </summary>
public string Dest { get; set; }
public SrcType SrcType { get; set; }

/// <summary>
/// The file to write the result to. The file has the same format as Src.
/// The file to load as the initial sample. Use when SrcType is Sample.
/// </summary>
public string Src { get; set; }

/// <summary>
/// The file to write the result to. The file has the same format as Src.
/// </summary>
public string Dest { get; set; }

/// <summary>
/// The directory that Src and Dest are relative to.
/// BaseDirectory itself is relative to the directory of the config file, and defaults to that directory.
Expand Down Expand Up @@ -211,6 +226,11 @@ public class TileData
public string RotateCcw { get; set; }

public TileRotationTreatment? RotationTreatment { get; set; }

/// <summary>
/// The file to load representing this tile. Use when SrcType is BitmapSet or VoxSet.
/// </summary>
public string Src { get; set; }
}

public class AdjacencyData
Expand Down
59 changes: 59 additions & 0 deletions DeBroglie.Console/Export/ExportOptions.cs
@@ -0,0 +1,59 @@
using DeBroglie.MagicaVoxel;
using DeBroglie.Topo;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TiledLib;

namespace DeBroglie.Console.Export
{
public abstract class ExportOptions
{
public abstract string TypeDescription { get; }
}

public class TiledExportOptions : ExportOptions
{
public Map Template { get; set; }
public string SrcFileName { get; set; }

public override string TypeDescription => "Tiled";
}

public class VoxExportOptions : ExportOptions
{
public Vox Template { get; set; }

public override string TypeDescription => "Vox";
}

public class BitmapExportOptions : ExportOptions
{
public override string TypeDescription => "Bitmap";
}

public class BitmapSetExportOptions : ExportOptions
{
public override string TypeDescription => "Bitmap set";

public IDictionary<Tile, Bitmap> Bitmaps { get; set; }

public int TileWidth { get; set; }
public int TileHeight { get; set; }
}

public class VoxSetExportOptions : ExportOptions
{
public override string TypeDescription => "Bitmap set";

public IDictionary<Tile, Vox> SubTiles { get; set; }

public int TileWidth { get; set; }
public int TileHeight { get; set; }
public int TileDepth { get; set; }
}

}
11 changes: 11 additions & 0 deletions DeBroglie.Console/ISampleSetSaver.cs
@@ -0,0 +1,11 @@
using DeBroglie.Console.Export;
using DeBroglie.Models;

namespace DeBroglie.Console
{
public interface ISampleSetSaver
{
void Save(TileModel model, TilePropagator tilePropagator, string filename, DeBroglieConfig config, ExportOptions exportOptions);

}
}

0 comments on commit f730a5f

Please sign in to comment.