mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/PCK-Studio.git
synced 2026-06-12 16:12:14 +00:00
Add Altas class & refactored Atlas editor
This commit is contained in:
@@ -291,7 +291,7 @@ namespace PckStudio.Controls
|
||||
asset.SetSerializedData(animation, AnimationSerializer.DefaultSerializer);
|
||||
});
|
||||
|
||||
using (AnimationEditor animationEditor = new AnimationEditor(animation, saveContext, displayname, internalName.ToLower().EqualsAny(specialTileNames)))
|
||||
using (AnimationEditor animationEditor = new AnimationEditor(animation, saveContext, displayname, !internalName.ToLower().EqualsAny(specialTileNames)))
|
||||
{
|
||||
if (animationEditor.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
@@ -300,17 +300,17 @@ namespace PckStudio.Controls
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ResourceCategory.ParticleAtlas:
|
||||
case ResourceCategory.MoonPhaseAtlas:
|
||||
case ResourceCategory.ItemAtlas:
|
||||
case ResourceCategory.BlockAtlas:
|
||||
case ResourceCategory.ParticleAtlas:
|
||||
case ResourceCategory.BannerAtlas:
|
||||
case ResourceCategory.PaintingAtlas:
|
||||
case ResourceCategory.ExplosionAtlas:
|
||||
case ResourceCategory.ExperienceOrbAtlas:
|
||||
case ResourceCategory.MoonPhaseAtlas:
|
||||
case ResourceCategory.MapIconAtlas:
|
||||
case ResourceCategory.AdditionalMapIconsAtlas:
|
||||
Image atlas = asset.GetTexture();
|
||||
Atlas atlas = asset.GetDeserializedData(new AtlasDeserializer(resourceLocation));
|
||||
ColorContainer colorContainer = default;
|
||||
if (EditorValue.File.TryGetAsset("colours.col", PckAssetType.ColourTableFile, out PckAsset colAsset))
|
||||
colorContainer = colAsset.GetData(new COLFileReader());
|
||||
@@ -356,7 +356,7 @@ namespace PckStudio.Controls
|
||||
return true;
|
||||
});
|
||||
|
||||
ISaveContext<Image> textureAtlasSaveContext = new DelegatedSaveContext<Image>(Settings.Default.AutoSaveChanges, asset.SetTexture);
|
||||
ISaveContext<Atlas> textureAtlasSaveContext = new DelegatedSaveContext<Atlas>(Settings.Default.AutoSaveChanges, atlas => asset.SetTexture(atlas));
|
||||
|
||||
var viewer = new TextureAtlasEditor(atlas, textureAtlasSaveContext, resourceLocation, colorContainer, tryGetAnimation, tryGetAnimationSaveContext);
|
||||
if (viewer.ShowDialog(this) == DialogResult.OK)
|
||||
@@ -1293,7 +1293,7 @@ namespace PckStudio.Controls
|
||||
newAnimation = animation;
|
||||
});
|
||||
|
||||
using AnimationEditor animationEditor = new AnimationEditor(Animation.CreateEmpty(), saveContext, diag.SelectedTile.DisplayName, diag.SelectedTile.InternalName.EqualsAny("clock", "compass"));
|
||||
using AnimationEditor animationEditor = new AnimationEditor(Animation.CreateEmpty(), saveContext, diag.SelectedTile.DisplayName, !diag.SelectedTile.InternalName.EqualsAny("clock", "compass"));
|
||||
if (animationEditor.ShowDialog() == DialogResult.OK && newAnimation is not null)
|
||||
{
|
||||
_wasModified = true;
|
||||
|
||||
@@ -40,16 +40,16 @@ namespace PckStudio.Forms.Editor
|
||||
{
|
||||
public partial class AnimationEditor : EditorForm<Animation>
|
||||
{
|
||||
private bool _isSpecialTile;
|
||||
private bool _editable;
|
||||
|
||||
internal AnimationEditor(Animation animation, ISaveContext<Animation> saveContext, string displayName, bool isSpecialTile = false)
|
||||
internal AnimationEditor(Animation animation, ISaveContext<Animation> saveContext, string displayName, bool editable = true)
|
||||
: base(animation, saveContext)
|
||||
{
|
||||
InitializeComponent();
|
||||
saveToolStripMenuItem1.Available = !saveContext.AutoSave;
|
||||
toolStripSeparator1.Available = !saveContext.AutoSave;
|
||||
tileLabel.Text = displayName;
|
||||
_isSpecialTile = isSpecialTile;
|
||||
_editable = editable;
|
||||
animationPictureBox.Image = animation.CreateAnimationImage();
|
||||
}
|
||||
|
||||
@@ -62,10 +62,9 @@ namespace PckStudio.Forms.Editor
|
||||
|
||||
private void ValidateToolStrip()
|
||||
{
|
||||
bulkAnimationSpeedToolStripMenuItem.Enabled =
|
||||
importToolStripMenuItem.Enabled =
|
||||
exportAsToolStripMenuItem.Enabled =
|
||||
InterpolationCheckbox.Visible = !_isSpecialTile;
|
||||
editToolStripMenuItem.Visible =
|
||||
importToolStripMenuItem.Visible =
|
||||
InterpolationCheckbox.Visible = _editable;
|
||||
}
|
||||
|
||||
private void AnimationEditor_Load(object sender, EventArgs e)
|
||||
@@ -78,10 +77,10 @@ namespace PckStudio.Forms.Editor
|
||||
{
|
||||
if (EditorValue is null)
|
||||
{
|
||||
AnimationStartStopBtn.Enabled = false;
|
||||
AnimationStartStopBtn.Visible = false;
|
||||
return;
|
||||
}
|
||||
AnimationStartStopBtn.Enabled = true;
|
||||
AnimationStartStopBtn.Visible = true;
|
||||
InterpolationCheckbox.Checked = EditorValue.Interpolate;
|
||||
TextureIcons.Images.Clear();
|
||||
TextureIcons.Images.AddRange(EditorValue.GetTextures().ToArray());
|
||||
@@ -103,7 +102,7 @@ namespace PckStudio.Forms.Editor
|
||||
.Select(frame =>
|
||||
{
|
||||
var imageIndex = EditorValue.GetTextureIndex(frame.Texture);
|
||||
return new TreeNode($"for {frame.Ticks} ticks", imageIndex, imageIndex);
|
||||
return new TreeNode($"for {frame.Ticks} tick(s)", imageIndex, imageIndex);
|
||||
})
|
||||
.ToArray()
|
||||
);
|
||||
@@ -159,7 +158,7 @@ namespace PckStudio.Forms.Editor
|
||||
|
||||
private void saveToolStripMenuItem1_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!_isSpecialTile && EditorValue is not null && EditorValue.FrameCount > 0)
|
||||
if (_editable && EditorValue is not null && EditorValue.FrameCount > 0)
|
||||
{
|
||||
Save();
|
||||
DialogResult = DialogResult.OK;
|
||||
@@ -271,7 +270,7 @@ namespace PckStudio.Forms.Editor
|
||||
diag.SaveBtn.Text = "Add";
|
||||
if (diag.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
EditorValue.AddFrame(diag.FrameTextureIndex, _isSpecialTile ? Animation.MinimumFrameTime : diag.FrameTime);
|
||||
EditorValue.AddFrame(diag.FrameTextureIndex, _editable ? diag.FrameTime : Animation.MinimumFrameTime);
|
||||
UpdateTreeView();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
this.viewToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.applyColorMaskToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.playAnimationsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.allowGroupsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.originalPictureBox = new PckStudio.ToolboxItems.InterpolationPictureBox();
|
||||
this.selectTilePictureBox = new PckStudio.ToolboxItems.AnimationPictureBox();
|
||||
@@ -102,7 +103,8 @@
|
||||
//
|
||||
this.viewToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.applyColorMaskToolStripMenuItem,
|
||||
this.playAnimationsToolStripMenuItem});
|
||||
this.playAnimationsToolStripMenuItem,
|
||||
this.allowGroupsToolStripMenuItem});
|
||||
this.viewToolStripMenuItem.ForeColor = System.Drawing.SystemColors.Control;
|
||||
this.viewToolStripMenuItem.Name = "viewToolStripMenuItem";
|
||||
this.viewToolStripMenuItem.Size = new System.Drawing.Size(44, 20);
|
||||
@@ -114,7 +116,7 @@
|
||||
this.applyColorMaskToolStripMenuItem.CheckOnClick = true;
|
||||
this.applyColorMaskToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.applyColorMaskToolStripMenuItem.Name = "applyColorMaskToolStripMenuItem";
|
||||
this.applyColorMaskToolStripMenuItem.Size = new System.Drawing.Size(168, 22);
|
||||
this.applyColorMaskToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.applyColorMaskToolStripMenuItem.Text = "Apply Color Mask";
|
||||
this.applyColorMaskToolStripMenuItem.CheckedChanged += new System.EventHandler(this.applyColorMaskToolStripMenuItem_CheckedChanged);
|
||||
//
|
||||
@@ -124,10 +126,20 @@
|
||||
this.playAnimationsToolStripMenuItem.CheckOnClick = true;
|
||||
this.playAnimationsToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.playAnimationsToolStripMenuItem.Name = "playAnimationsToolStripMenuItem";
|
||||
this.playAnimationsToolStripMenuItem.Size = new System.Drawing.Size(168, 22);
|
||||
this.playAnimationsToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.playAnimationsToolStripMenuItem.Text = "Play Animations";
|
||||
this.playAnimationsToolStripMenuItem.CheckedChanged += new System.EventHandler(this.playAnimationsToolStripMenuItem_CheckedChanged);
|
||||
//
|
||||
// allowGroupsToolStripMenuItem
|
||||
//
|
||||
this.allowGroupsToolStripMenuItem.Checked = true;
|
||||
this.allowGroupsToolStripMenuItem.CheckOnClick = true;
|
||||
this.allowGroupsToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.allowGroupsToolStripMenuItem.Name = "allowGroupsToolStripMenuItem";
|
||||
this.allowGroupsToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.allowGroupsToolStripMenuItem.Text = "Allow Groups";
|
||||
this.allowGroupsToolStripMenuItem.CheckedChanged += new System.EventHandler(this.allowGroupsToolStripMenuItem_CheckedChanged);
|
||||
//
|
||||
// tableLayoutPanel1
|
||||
//
|
||||
this.tableLayoutPanel1.AutoSize = true;
|
||||
@@ -171,6 +183,7 @@
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.originalPictureBox.BackColor = System.Drawing.Color.Transparent;
|
||||
this.originalPictureBox.BackgroundInterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default;
|
||||
this.originalPictureBox.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
|
||||
this.originalPictureBox.Location = new System.Drawing.Point(217, 3);
|
||||
this.originalPictureBox.Name = "originalPictureBox";
|
||||
@@ -187,6 +200,7 @@
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.selectTilePictureBox.BackColor = System.Drawing.Color.Transparent;
|
||||
this.selectTilePictureBox.BackgroundInterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default;
|
||||
this.selectTilePictureBox.BlendColor = System.Drawing.Color.White;
|
||||
this.selectTilePictureBox.BlendMode = PckStudio.Core.Extensions.BlendMode.Multiply;
|
||||
this.tableLayoutPanel1.SetColumnSpan(this.selectTilePictureBox, 2);
|
||||
@@ -384,5 +398,6 @@
|
||||
private MetroFramework.Controls.MetroTrackBar colorSlider;
|
||||
private MetroFramework.Controls.MetroLabel colorSliderLabel;
|
||||
private MetroFramework.Controls.MetroButton extractButton;
|
||||
private System.Windows.Forms.ToolStripMenuItem allowGroupsToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
@@ -32,22 +32,17 @@ using PckStudio.Core.Json;
|
||||
|
||||
namespace PckStudio.Forms.Editor
|
||||
{
|
||||
internal partial class TextureAtlasEditor : EditorForm<Image>
|
||||
internal partial class TextureAtlasEditor : EditorForm<Atlas>
|
||||
{
|
||||
private readonly ITryGet<string, Animation> _tryGetAnimation;
|
||||
private readonly ITryGet<string, ISaveContext<Animation>> _tryGetAnimationSaveContext;
|
||||
private readonly ColorContainer _colourTable;
|
||||
private readonly Size _tileAreaSize;
|
||||
private readonly int _rowCount;
|
||||
private readonly int _columnCount;
|
||||
private readonly ResourceCategory _resourceLocationCategory;
|
||||
private readonly List<AtlasTile> _tiles;
|
||||
private readonly Atlas _atlas;
|
||||
|
||||
private AtlasTile _selectedTile;
|
||||
// the "parent" tile for tiles that share name; i.e. parts of water_flow
|
||||
private AtlasTile dataTile;
|
||||
|
||||
public TextureAtlasEditor(Image atlas, ISaveContext<Image> saveContext, ResourceLocation resourceLocation, ColorContainer colorContainer,
|
||||
public TextureAtlasEditor(Atlas atlas, ISaveContext<Atlas> saveContext, ResourceLocation resourceLocation, ColorContainer colorContainer,
|
||||
ITryGet<string, Animation> tryGetAnimation, ITryGet<string, ISaveContext<Animation>> tryGetAnimationSaveContext)
|
||||
: base(atlas, saveContext)
|
||||
{
|
||||
@@ -56,20 +51,17 @@ namespace PckStudio.Forms.Editor
|
||||
_ = atlas ?? throw new ArgumentNullException(nameof(atlas));
|
||||
_ = resourceLocation ?? throw new ArgumentNullException(nameof(resourceLocation));
|
||||
|
||||
originalPictureBox.Image = new Bitmap(atlas);
|
||||
originalPictureBox.Image = atlas;
|
||||
|
||||
_colourTable = colorContainer ?? new ColorContainer();
|
||||
_tileAreaSize = resourceLocation.GetTileArea(atlas.Size);
|
||||
_tryGetAnimation = tryGetAnimation;
|
||||
_tryGetAnimationSaveContext = tryGetAnimationSaveContext;
|
||||
_rowCount = atlas.Width / _tileAreaSize.Width;
|
||||
_columnCount = atlas.Height / _tileAreaSize.Height;
|
||||
_atlas = atlas;
|
||||
_resourceLocationCategory = resourceLocation.Category;
|
||||
|
||||
_tiles = new List<AtlasTile>(CreateAtlasTiles());
|
||||
_atlas.AllowGroups = allowGroupsToolStripMenuItem.Checked;
|
||||
SelectedIndex = 0;
|
||||
|
||||
|
||||
animationButton.Enabled =
|
||||
_resourceLocationCategory == ResourceCategory.BlockAtlas ||
|
||||
_resourceLocationCategory == ResourceCategory.ItemAtlas;
|
||||
@@ -85,85 +77,16 @@ namespace PckStudio.Forms.Editor
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<AtlasTile> CreateAtlasTiles()
|
||||
{
|
||||
List<JsonTileInfo> tileInfos = _resourceLocationCategory switch
|
||||
{
|
||||
ResourceCategory.BlockAtlas => Tiles.BlockTileInfos,
|
||||
ResourceCategory.ItemAtlas => Tiles.ItemTileInfos,
|
||||
ResourceCategory.ParticleAtlas => Tiles.ParticleTileInfos,
|
||||
ResourceCategory.MapIconAtlas => Tiles.MapIconTileInfos,
|
||||
ResourceCategory.AdditionalMapIconsAtlas => Tiles.AdditionalMapIconTileInfos,
|
||||
ResourceCategory.MoonPhaseAtlas => Tiles.MoonPhaseTileInfos,
|
||||
ResourceCategory.ExperienceOrbAtlas => Tiles.ExperienceOrbTileInfos,
|
||||
ResourceCategory.ExplosionAtlas => Tiles.ExplosionTileInfos,
|
||||
ResourceCategory.PaintingAtlas => Tiles.PaintingTileInfos,
|
||||
ResourceCategory.BannerAtlas => Tiles.BannerTileInfos,
|
||||
_ => null,
|
||||
};
|
||||
|
||||
IEnumerable<Image> images = EditorValue.Split(_tileAreaSize, _imageLayout);
|
||||
|
||||
AtlasTile MakeTile((int index, Image value) p)
|
||||
{
|
||||
int i = p.index;
|
||||
JsonTileInfo tileInfo = tileInfos.IndexInRange(i) ? tileInfos[i] : null;
|
||||
|
||||
int tileWidth = tileInfo?.TileWidth ?? 1;
|
||||
int tileHeight = tileInfo?.TileHeight ?? 1;
|
||||
|
||||
Rectangle atlasArea = GetAtlasArea(i, tileWidth, tileHeight, _rowCount, _columnCount, _tileAreaSize, _imageLayout);
|
||||
|
||||
// get texture for tiles that are not 1x1 tiles
|
||||
Point selectedPoint = GetSelectedPoint(i, _rowCount, _columnCount, _imageLayout);
|
||||
|
||||
var textureLocation = new Point(selectedPoint.X * _tileAreaSize.Width, selectedPoint.Y * _tileAreaSize.Height);
|
||||
var textureSize = new Size(tileWidth * _tileAreaSize.Width, tileHeight * _tileAreaSize.Height);
|
||||
var textureArea = new Rectangle(textureLocation, textureSize);
|
||||
|
||||
Image texture = tileInfos.IndexInRange(i) ? EditorValue.GetArea(textureArea) : p.value;
|
||||
return new AtlasTile(i, atlasArea, tileInfo, texture);
|
||||
}
|
||||
|
||||
return images.enumerate().Select(MakeTile);
|
||||
}
|
||||
|
||||
private sealed class AtlasTile
|
||||
{
|
||||
internal readonly int Index;
|
||||
internal readonly Rectangle Area;
|
||||
internal readonly JsonTileInfo Tile;
|
||||
internal readonly Image Texture;
|
||||
|
||||
public AtlasTile(int index, Rectangle area, JsonTileInfo tile, Image texture)
|
||||
{
|
||||
Index = index;
|
||||
Area = area;
|
||||
Tile = tile;
|
||||
Texture = texture;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is AtlasTile otherTile && Index == otherTile.Index && Area == otherTile.Area;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
private int SelectedIndex
|
||||
{
|
||||
set {
|
||||
if (value < 0)
|
||||
{
|
||||
value += _tiles.Count;
|
||||
value += _atlas.TileCount;
|
||||
}
|
||||
else if (value >= _tiles.Count)
|
||||
else if (value >= _atlas.TileCount)
|
||||
{
|
||||
value -= _tiles.Count;
|
||||
value -= _atlas.TileCount;
|
||||
}
|
||||
SetImageDisplayed(value);
|
||||
}
|
||||
@@ -183,12 +106,12 @@ namespace PckStudio.Forms.Editor
|
||||
{
|
||||
g.ApplyConfig(_graphicsConfig);
|
||||
g.Clear(Color.Transparent);
|
||||
g.DrawImage(EditorValue, 0, 0, EditorValue.Width, EditorValue.Height);
|
||||
Image image = EditorValue;
|
||||
g.DrawImage(image, 0, 0, image.Width, image.Height);
|
||||
|
||||
SolidBrush brush = new SolidBrush(Color.FromArgb(127, Color.White));
|
||||
g.FillRectangle(brush, _selectedTile.Area);
|
||||
g.FillRectangle(brush, _atlas.GetTileArea(_selectedTile));
|
||||
}
|
||||
|
||||
originalPictureBox.Invalidate();
|
||||
}
|
||||
|
||||
@@ -210,46 +133,42 @@ namespace PckStudio.Forms.Editor
|
||||
selectTilePictureBox.Stop();
|
||||
selectTilePictureBox.UseBlendColor = false;
|
||||
selectTilePictureBox.Image = null;
|
||||
_selectedTile = _atlas[index];
|
||||
|
||||
if (_tiles is null || !_tiles.IndexInRange(index) || (_selectedTile = _tiles[index]) is null)
|
||||
if (_selectedTile is null)
|
||||
return;
|
||||
|
||||
UpdateAtlasDisplay();
|
||||
|
||||
dataTile = _selectedTile;
|
||||
if (string.IsNullOrEmpty(dataTile.Tile.DisplayName) && !string.IsNullOrEmpty(dataTile.Tile.InternalName))
|
||||
{
|
||||
dataTile = _tiles.Find(t => t.Tile.InternalName == _selectedTile.Tile.InternalName);
|
||||
}
|
||||
|
||||
selectTilePictureBox.Image = dataTile.Texture;
|
||||
selectTilePictureBox.Image = _selectedTile.Texture;
|
||||
selectTilePictureBox.BlendColor = GetBlendColor();
|
||||
selectTilePictureBox.UseBlendColor = applyColorMaskToolStripMenuItem.Checked;
|
||||
|
||||
tileNameLabel.Text = $"{dataTile.Tile.DisplayName}";
|
||||
internalTileNameLabel.Text = $"{dataTile.Tile.InternalName}";
|
||||
JsonTileInfo tileInfo = _selectedTile.GetUserDataOfType<JsonTileInfo>();
|
||||
|
||||
if (animationButton.Enabled)
|
||||
tileNameLabel.Text = $"{tileInfo?.DisplayName}";
|
||||
internalTileNameLabel.Text = $"{tileInfo?.InternalName}";
|
||||
if (animationButton.Enabled && (_resourceLocationCategory == ResourceCategory.ItemAtlas || _resourceLocationCategory == ResourceCategory.BlockAtlas))
|
||||
{
|
||||
ResourceCategory animationResourceCategory = _resourceLocationCategory == ResourceCategory.ItemAtlas ? ResourceCategory.ItemAnimation : ResourceCategory.BlockAnimation;
|
||||
|
||||
string animationAssetPath = $"{ResourceLocation.GetPathFromCategory(animationResourceCategory)}/{dataTile.Tile.InternalName}";
|
||||
string animationAssetPath = $"{ResourceLocation.GetPathFromCategory(animationResourceCategory)}/{tileInfo.InternalName}";
|
||||
bool hasAnimation = _tryGetAnimation.TryGet(animationAssetPath, out Animation animation);
|
||||
animationButton.Text = hasAnimation ? "Edit Animation" : "Create Animation";
|
||||
|
||||
if (playAnimationsToolStripMenuItem.Checked && hasAnimation)
|
||||
{
|
||||
selectTilePictureBox.Image = animation.CreateAnimationImage();
|
||||
selectTilePictureBox.Image = animation.CreateAnimationImage(selectTilePictureBox.BlendColor);
|
||||
selectTilePictureBox.Start();
|
||||
}
|
||||
}
|
||||
|
||||
setColorButton.Enabled = dataTile.Tile.AllowCustomColour;
|
||||
setColorButton.Enabled = tileInfo.AllowCustomColour;
|
||||
|
||||
variantComboBox.Enabled = variantComboBox.Visible = dataTile.Tile.HasColourEntry && dataTile.Tile.ColourEntry?.Variants?.Length > 1;
|
||||
variantComboBox.Enabled = variantComboBox.Visible = tileInfo.HasColourEntry && tileInfo.ColourEntry?.Variants?.Length > 1;
|
||||
if (variantComboBox.Enabled)
|
||||
{
|
||||
if (dataTile.Tile.ColourEntry.IsWaterColour)
|
||||
if (tileInfo.ColourEntry.IsWaterColour)
|
||||
{
|
||||
foreach (ColorContainer.WaterColor col in _colourTable.WaterColors)
|
||||
{
|
||||
@@ -259,11 +178,34 @@ namespace PckStudio.Forms.Editor
|
||||
}
|
||||
|
||||
// TODO: only add variants that are available in the color table
|
||||
variantComboBox.Items.AddRange(dataTile.Tile.ColourEntry.Variants);
|
||||
variantComboBox.Items.AddRange(tileInfo.ColourEntry.Variants.Where(colorName => _colourTable.Colors.Any(c => c.Name == colorName) || _colourTable.WaterColors.Any(c => c.Name == colorName)).ToArray());
|
||||
|
||||
if (variantComboBox.Items.Count > 0)
|
||||
variantComboBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
if (_selectedTile.IsPartOfGroup && allowGroupsToolStripMenuItem.Checked)
|
||||
{
|
||||
AtlasGroup group = _selectedTile.GetGroup();
|
||||
tileNameLabel.Text = $"{group.Name}";
|
||||
internalTileNameLabel.Text = string.Empty;
|
||||
if (group.IsAnimation())
|
||||
{
|
||||
animationButton.Enabled = true;
|
||||
animationButton.Text = "Edit as Animation";
|
||||
if (playAnimationsToolStripMenuItem.Checked)
|
||||
{
|
||||
selectTilePictureBox.UseBlendColor = false;
|
||||
selectTilePictureBox.Image = _atlas.GetAnimationFromGroup(group).CreateAnimationImage(selectTilePictureBox.BlendColor);
|
||||
selectTilePictureBox.Start();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (group.IsLargeTile())
|
||||
{
|
||||
selectTilePictureBox.Image = _atlas.GetTileTexture(_selectedTile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetSelectedImageIndex(
|
||||
@@ -336,6 +278,7 @@ namespace PckStudio.Forms.Editor
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Debug.WriteLine(result);
|
||||
return GetSelectedIndex(result.X, result.Y, rowCount, columnCount, imageLayout);
|
||||
}
|
||||
|
||||
@@ -349,47 +292,22 @@ namespace PckStudio.Forms.Editor
|
||||
};
|
||||
}
|
||||
|
||||
private static Rectangle GetAtlasArea(int index, int tileWidth, int tileHeight, int rowCount, int columnCount, Size size, ImageLayoutDirection imageLayout)
|
||||
{
|
||||
Point p = GetSelectedPoint(index, rowCount, columnCount, imageLayout);
|
||||
var ap = new Point(p.X * size.Width, p.Y * size.Height);
|
||||
return new Rectangle(ap, new Size(size.Width * tileWidth, size.Height * tileHeight));
|
||||
}
|
||||
|
||||
private static Point GetSelectedPoint(int index, int rowCount, int columnCount, ImageLayoutDirection imageLayout)
|
||||
{
|
||||
int y = Math.DivRem(index, rowCount, out int x);
|
||||
if (imageLayout == ImageLayoutDirection.Vertical)
|
||||
x = Math.DivRem(index, columnCount, out y);
|
||||
return new Point(x, y);
|
||||
}
|
||||
|
||||
private void SetTile(Image texture)
|
||||
{
|
||||
if (texture.Size != _tileAreaSize)
|
||||
texture = texture.Resize(_tileAreaSize, _graphicsConfig);
|
||||
if (texture.Size != _atlas.TileSize)
|
||||
texture = texture.Resize(_atlas.TileSize, _graphicsConfig);
|
||||
|
||||
using (var g = Graphics.FromImage(EditorValue))
|
||||
{
|
||||
g.ApplyConfig(_graphicsConfig);
|
||||
g.Fill(dataTile.Area, Color.Transparent);
|
||||
g.DrawImage(texture, dataTile.Area);
|
||||
}
|
||||
|
||||
AtlasTile tile = _selectedTile != dataTile ? dataTile : _selectedTile;
|
||||
_tiles[tile.Index] = new AtlasTile(tile.Index, tile.Area, tile.Tile, texture);
|
||||
_selectedTile.Texture = texture;
|
||||
selectTilePictureBox.Image = texture;
|
||||
UpdateAtlasDisplay();
|
||||
}
|
||||
|
||||
private Color GetBlendColor()
|
||||
{
|
||||
if (dataTile.Tile.HasColourEntry && dataTile.Tile.ColourEntry is not null)
|
||||
if (_selectedTile.TryGetUserDataOfType(out JsonTileInfo tileInfo) && tileInfo.HasColourEntry)
|
||||
{
|
||||
Color col = FindBlendColorByKey(dataTile.Tile.ColourEntry.DefaultName);
|
||||
return col;
|
||||
return FindBlendColorByKey(tileInfo.ColourEntry.DefaultName);
|
||||
}
|
||||
|
||||
return Color.White;
|
||||
}
|
||||
|
||||
@@ -405,7 +323,7 @@ namespace PckStudio.Forms.Editor
|
||||
var final_color = Color.FromArgb(colorSlider.Value, colorSlider.Value, colorSlider.Value);
|
||||
|
||||
// Enchanted hits are modified critical hit particles
|
||||
if (dataTile.Tile.InternalName == "enchanted_hit")
|
||||
if (_selectedTile.TryGetUserDataOfType(out JsonTileInfo tileInfo) && tileInfo.InternalName == "enchanted_hit")
|
||||
{
|
||||
// This is directly based on Java's source code for handling enchanted hits
|
||||
// it just multiplies the red by 0.3 and green by .8 of the color assigned to the critical hit particle
|
||||
@@ -420,10 +338,10 @@ namespace PckStudio.Forms.Editor
|
||||
if (colorKey == "experience_orb" || colorKey == "critical_hit")
|
||||
return GetSpecificBlendColor(colorKey);
|
||||
|
||||
if (dataTile.Tile.HasColourEntry && dataTile.Tile.ColourEntry is not null)
|
||||
if (_selectedTile.TryGetUserDataOfType(out JsonTileInfo tileInfo) && tileInfo.HasColourEntry)
|
||||
{
|
||||
// basic way to check for classic water colors
|
||||
if(!dataTile.Tile.ColourEntry.IsWaterColour || colorKey.StartsWith("Water_"))
|
||||
if(!tileInfo.ColourEntry.IsWaterColour || colorKey.StartsWith("Water_"))
|
||||
{
|
||||
if (_colourTable.Colors.FirstOrDefault(entry => entry.Name == colorKey) is ColorContainer.Color color)
|
||||
{
|
||||
@@ -440,6 +358,7 @@ namespace PckStudio.Forms.Editor
|
||||
return Color.White;
|
||||
}
|
||||
|
||||
// TODO
|
||||
protected override bool ProcessDialogKey(Keys keyData)
|
||||
{
|
||||
switch (keyData)
|
||||
@@ -455,10 +374,10 @@ namespace PckStudio.Forms.Editor
|
||||
SelectedIndex = _selectedTile.Index + 1;
|
||||
return true;
|
||||
case Keys.Up:
|
||||
SelectedIndex = _selectedTile.Index - _rowCount;
|
||||
SelectedIndex = _selectedTile.Index - _atlas.Rows;
|
||||
return true;
|
||||
case Keys.Down:
|
||||
SelectedIndex = _selectedTile.Index + _rowCount;
|
||||
SelectedIndex = _selectedTile.Index + _atlas.Rows;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -474,8 +393,8 @@ namespace PckStudio.Forms.Editor
|
||||
|
||||
int index = GetSelectedImageIndex(
|
||||
originalPictureBox.Size,
|
||||
EditorValue.Size,
|
||||
_tileAreaSize,
|
||||
((Image)_atlas).Size,
|
||||
_atlas.TileSize,
|
||||
e.Location,
|
||||
originalPictureBox.SizeMode,
|
||||
_imageLayout);
|
||||
@@ -509,14 +428,28 @@ namespace PckStudio.Forms.Editor
|
||||
|
||||
private void animationButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (_selectedTile.IsPartOfGroup)
|
||||
{
|
||||
AtlasGroup group = _selectedTile.GetGroup();
|
||||
Animation anim = _atlas.GetAnimationFromGroup(group);
|
||||
ISaveContext<Animation> saveContext = new DelegatedSaveContext<Animation>(false, (animation) =>
|
||||
{
|
||||
// TODO
|
||||
_atlas.SetGroupTilesFromAnimation(group, animation);
|
||||
});
|
||||
var aEditor = new AnimationEditor(anim, saveContext, group.Name, false);
|
||||
aEditor.ShowDialog(this);
|
||||
return;
|
||||
}
|
||||
JsonTileInfo tileInfo = _selectedTile.GetUserDataOfType<JsonTileInfo>();
|
||||
ResourceCategory animationResourceCategory = _resourceLocationCategory == ResourceCategory.ItemAtlas ? ResourceCategory.ItemAnimation : ResourceCategory.BlockAnimation;
|
||||
string animationAssetPath = $"{ResourceLocation.GetPathFromCategory(animationResourceCategory)}/{_selectedTile.Tile.InternalName}";
|
||||
string animationAssetPath = $"{ResourceLocation.GetPathFromCategory(animationResourceCategory)}/{tileInfo.InternalName}";
|
||||
bool hasAnimation = _tryGetAnimation.TryGet(animationAssetPath, out Animation animation);
|
||||
bool isValidAnimationSaveContext = _tryGetAnimationSaveContext.TryGet(animationAssetPath, out ISaveContext<Animation> animationSaveContext);
|
||||
|
||||
Debug.Assert(isValidAnimationSaveContext, "Couldn't get valid animation save context.");
|
||||
|
||||
var animationEditor = new AnimationEditor(hasAnimation ? animation : Animation.CreateEmpty(), animationSaveContext, _selectedTile.Tile.DisplayName);
|
||||
var animationEditor = new AnimationEditor(hasAnimation ? animation : Animation.CreateEmpty(), animationSaveContext, tileInfo.DisplayName);
|
||||
if (animationEditor.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
// so animations can automatically update upon saving
|
||||
@@ -524,27 +457,34 @@ namespace PckStudio.Forms.Editor
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
private void extractTileToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
string filename = _selectedTile.TryGetUserDataOfType(out JsonTileInfo tileInfo) ? tileInfo.InternalName : "tile";
|
||||
SaveFileDialog saveFileDialog = new SaveFileDialog()
|
||||
{
|
||||
Filter = "Tile Texture|*.png",
|
||||
FileName = _selectedTile.Tile.InternalName
|
||||
FileName = filename
|
||||
};
|
||||
if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
dataTile.Texture.Save(saveFileDialog.FileName, ImageFormat.Png);
|
||||
_selectedTile.Texture.Save(saveFileDialog.FileName, ImageFormat.Png);
|
||||
}
|
||||
}
|
||||
|
||||
private void variantComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (dataTile.Tile.ColourEntry is not null && variantComboBox.SelectedItem is not null)
|
||||
if (_selectedTile.TryGetUserDataOfType(out JsonTileInfo tileInfo) && variantComboBox.SelectedItem is not null)
|
||||
{
|
||||
string colorKey = variantComboBox.SelectedItem.ToString();
|
||||
|
||||
selectTilePictureBox.BlendColor = FindBlendColorByKey(colorKey);
|
||||
selectTilePictureBox.Image = dataTile.Texture;
|
||||
Color blendColor = FindBlendColorByKey(colorKey);
|
||||
if (_selectedTile.IsPartOfGroup && _selectedTile.GetGroup().IsAnimation())
|
||||
{
|
||||
selectTilePictureBox.Image = _atlas.GetAnimationFromGroup(_selectedTile.GetGroup()).CreateAnimationImage(blendColor);
|
||||
selectTilePictureBox.Start();
|
||||
return;
|
||||
}
|
||||
selectTilePictureBox.BlendColor = blendColor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,13 +511,12 @@ namespace PckStudio.Forms.Editor
|
||||
colorPick.AnyColor = true;
|
||||
colorPick.SolidColorOnly = true;
|
||||
|
||||
colorPick.CustomColors = GameConstants.DyeColors.Select(c => c.ToBGR()).ToArray();
|
||||
colorPick.CustomColors = GameConstants.DyeColors.Select(ColorExtensions.ToBGR).ToArray();
|
||||
|
||||
if (colorPick.ShowDialog(this) != DialogResult.OK)
|
||||
return;
|
||||
|
||||
selectTilePictureBox.BlendColor = colorPick.Color;
|
||||
selectTilePictureBox.Image = dataTile.Texture;
|
||||
variantComboBox.Enabled = false;
|
||||
clearColorButton.Enabled = true;
|
||||
}
|
||||
@@ -594,7 +533,12 @@ namespace PckStudio.Forms.Editor
|
||||
private void colorSlider_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
selectTilePictureBox.BlendColor = GetBlendColor();
|
||||
selectTilePictureBox.Image = dataTile.Texture;
|
||||
}
|
||||
|
||||
private void allowGroupsToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
_atlas.AllowGroups = allowGroupsToolStripMenuItem.Checked;
|
||||
SelectedIndex = _selectedTile.Index;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,10 +35,10 @@ namespace PckStudio.ToolboxItems
|
||||
get => base.Image;
|
||||
set
|
||||
{
|
||||
base.Image = value;
|
||||
this.Animate(false);
|
||||
if (value is null)
|
||||
return;
|
||||
this.Animate(false);
|
||||
base.Image = value;
|
||||
value.SelectActiveFrame(new FrameDimension(value.FrameDimensionsList[0]), 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,13 @@ namespace PckStudio.ToolboxItems
|
||||
public Color BlendColor
|
||||
{
|
||||
get => _blendColor;
|
||||
set => _blendColor = value;
|
||||
set
|
||||
{
|
||||
_blendColor = value;
|
||||
Image = _image;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[DefaultValue(typeof(BlendMode), "BlendMode.Add")]
|
||||
[Category("Blending")]
|
||||
@@ -33,6 +38,7 @@ namespace PckStudio.ToolboxItems
|
||||
|
||||
private bool _useBlendColor = false;
|
||||
private Color _blendColor = Color.White;
|
||||
private Image _image;
|
||||
private BlendMode _blendMode = BlendMode.Add;
|
||||
|
||||
public new Image Image
|
||||
@@ -41,7 +47,9 @@ namespace PckStudio.ToolboxItems
|
||||
set {
|
||||
if (value is null)
|
||||
return;
|
||||
base.Image = UseBlendColor && BlendColor != Color.White ? value.Blend(BlendColor, BlendMode) : value;
|
||||
_image = value;
|
||||
base.Image = UseBlendColor && BlendColor != Color.White ? _image.Blend(BlendColor, BlendMode) : _image;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,11 +41,11 @@ namespace PckStudio.Core
|
||||
|
||||
private object _syncLock = new object();
|
||||
|
||||
public Animation(IEnumerable<Image> textures, bool initFramesFromTextures = false)
|
||||
public Animation(IEnumerable<Image> textures, bool initFramesFromTextures = false, int frameTime = MinimumFrameTime)
|
||||
{
|
||||
_textures = new List<Image>(textures);
|
||||
if (initFramesFromTextures)
|
||||
AddTexturesAsFrames(MinimumFrameTime);
|
||||
AddTexturesAsFrames(frameTime);
|
||||
}
|
||||
|
||||
public class Frame
|
||||
|
||||
227
PckStudio.Core/Atlas.cs
Normal file
227
PckStudio.Core/Atlas.cs
Normal file
@@ -0,0 +1,227 @@
|
||||
/* Copyright (c) 2025-present miku-666
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1.The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using PckStudio.Core.Extensions;
|
||||
|
||||
namespace PckStudio.Core
|
||||
{
|
||||
public sealed class Atlas
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Rows { get; }
|
||||
public int Columns { get; }
|
||||
|
||||
public Size TileSize { get; }
|
||||
public int TileCount => _tiles.Length;
|
||||
|
||||
public bool AllowGroups { get; set; } = default;
|
||||
|
||||
private readonly AtlasTile[] _tiles;
|
||||
private readonly ImageLayoutDirection _layoutDirection;
|
||||
private readonly List<AtlasGroup> _groups;
|
||||
|
||||
public static implicit operator Image(Atlas atlas) => atlas.BuildFinalImage();
|
||||
|
||||
private Atlas(string name, int rows, int columns)
|
||||
{
|
||||
Name = name;
|
||||
Rows = rows;
|
||||
Columns = columns;
|
||||
_tiles = new AtlasTile[rows * columns];
|
||||
_groups = new List<AtlasGroup>();
|
||||
}
|
||||
|
||||
private Atlas(string name, int rows, int columns, IEnumerable<AtlasTile> tiles, Size tileSize, ImageLayoutDirection layoutDirection)
|
||||
: this(name, rows, columns)
|
||||
{
|
||||
_tiles = tiles.Take(rows * columns).ToArray();
|
||||
TileSize = tileSize;
|
||||
_layoutDirection = layoutDirection;
|
||||
}
|
||||
|
||||
public static Atlas FromResourceLocation(Image source, ResourceLocation resourceLocation, ImageLayoutDirection imageLayout = default)
|
||||
{
|
||||
Json.JsonTileInfo[] tilesInfo = resourceLocation.TilesInfo.ToArray();
|
||||
Size tileArea = resourceLocation.GetTileArea(source.Size);
|
||||
int rows = source.Width / tileArea.Width;
|
||||
int columns = source.Height / tileArea.Height;
|
||||
IEnumerable<AtlasTile> tiles = source.Split(tileArea, imageLayout).enumerate().Select(((int index, Image img) data) => new AtlasTile(data.img, GetSelectedPoint(data.index, out int col, rows, columns, imageLayout), col, index: data.index, userData: tilesInfo.IndexInRange(data.index) ? tilesInfo[data.index] : default));
|
||||
var atlas = new Atlas(resourceLocation.Path, rows, columns, tiles, tileArea, imageLayout);
|
||||
atlas.AddGroups(resourceLocation.AtlasGroups);
|
||||
return atlas;
|
||||
}
|
||||
|
||||
private static int GetSelectedPoint(int index, out int col, int rows, int columns, ImageLayoutDirection layoutDirection)
|
||||
{
|
||||
int y = Math.DivRem(index, rows, out int x);
|
||||
if (layoutDirection == ImageLayoutDirection.Vertical)
|
||||
x = Math.DivRem(index, columns, out y);
|
||||
col = y;
|
||||
return x;
|
||||
}
|
||||
|
||||
public void AddGroups(IEnumerable<AtlasGroup> groups)
|
||||
{
|
||||
foreach (AtlasGroup group in groups)
|
||||
{
|
||||
AddGroup(group);
|
||||
}
|
||||
}
|
||||
|
||||
public AtlasTile this[int row, int col]
|
||||
{
|
||||
get => this[(col * Rows) + row];
|
||||
set => this[(col * Rows) + row] = value;
|
||||
}
|
||||
|
||||
public AtlasTile this[int index]
|
||||
{
|
||||
get => _tiles.IndexInRange(index) ? _tiles[index] : throw new IndexOutOfRangeException(index.ToString());
|
||||
set
|
||||
{
|
||||
if (_tiles.IndexInRange(index))
|
||||
_tiles[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<AtlasTile> GetRange(int row, int col, int count, ImageLayoutDirection direction)
|
||||
{
|
||||
return GetRange(row, col, direction == ImageLayoutDirection.Horizontal ? count : 1, direction == ImageLayoutDirection.Vertical ? count : 1);
|
||||
}
|
||||
|
||||
public IEnumerable<AtlasTile> GetRange(int row, int col, int rowCount, int columnCount)
|
||||
{
|
||||
for (int j = 0; j < columnCount; j++)
|
||||
{
|
||||
for (int i = 0; i < rowCount; i++)
|
||||
{
|
||||
if ((row + i) < Rows && (col + j) < Columns)
|
||||
{
|
||||
yield return this[row + i, col + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
yield break;
|
||||
}
|
||||
|
||||
private void SetRange(int row, int col, int count, IEnumerable<Image> tiles)
|
||||
{
|
||||
Image[] atlasTiles = tiles.ToArray();
|
||||
if (atlasTiles.Length < count)
|
||||
return;
|
||||
count = count < atlasTiles.Length ? count : atlasTiles.Length;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (row < Rows)
|
||||
{
|
||||
this[row++, col].Texture = atlasTiles[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
row %= Rows;
|
||||
this[row, col++].Texture = atlasTiles[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int AddGroup(AtlasGroup group)
|
||||
{
|
||||
IEnumerable<AtlasTile> tiles = InternalGetTilesFromGroup(group, out int _, out _);
|
||||
foreach (AtlasTile tile in tiles)
|
||||
{
|
||||
tile.SetGroup(group);
|
||||
}
|
||||
int groupId = _groups.Count;
|
||||
_groups.Add(group);
|
||||
return groupId;
|
||||
}
|
||||
|
||||
|
||||
public Animation GetAnimationFromGroup(AtlasGroup group)
|
||||
{
|
||||
if (!group.IsAnimation())
|
||||
return Animation.CreateEmpty();
|
||||
if (group is AtlasGroupLargeTileAnimation largeTileAnimation)
|
||||
return GetLargeAnimation(largeTileAnimation);
|
||||
return GetAnimation(group as AtlasGroupAnimation);
|
||||
}
|
||||
|
||||
private Animation GetLargeAnimation(AtlasGroupLargeTileAnimation group)
|
||||
{
|
||||
return new Animation(GetLargeAnimationTiles(group).Select(largeTileParts => largeTileParts.Select(t => t.Texture).Combine(group.RowSpan, group.ColumnSpan, _layoutDirection)), true, group.FrameTime);
|
||||
}
|
||||
|
||||
private IEnumerable<IEnumerable<AtlasTile>> GetLargeAnimationTiles(AtlasGroupLargeTileAnimation group) => group.GetLargeTiles().Select(GetLargeTile);
|
||||
|
||||
private Animation GetAnimation(AtlasGroupAnimation groupAnimation) => new Animation(GetRange(groupAnimation.Row, groupAnimation.Column, groupAnimation.Direction == ImageLayoutDirection.Horizontal ? groupAnimation.Count : 1, groupAnimation.Direction == ImageLayoutDirection.Vertical ? groupAnimation.Count : 1).Select(t => t.Texture), true, groupAnimation.FrameTime);
|
||||
|
||||
private Image BuildFinalImage() => _tiles.Select(t => t.Texture).Combine(Rows, Columns, _layoutDirection);
|
||||
|
||||
public IReadOnlyCollection<AtlasTile> GetTiles() => _tiles;
|
||||
|
||||
public void SetGroupTilesFromAnimation(AtlasGroup group, Animation animation)
|
||||
{
|
||||
SetRange(group.Row, group.Column, group.Count, animation.GetFrames().Select(f => f.Texture));
|
||||
}
|
||||
|
||||
private IEnumerable<AtlasTile> GetLargeTile(AtlasGroupLargeTile group) => GetRange(group.Row, group.Column, group.RowSpan, group.ColumnSpan);
|
||||
|
||||
public Image GetTileTexture(AtlasTile tile)
|
||||
{
|
||||
if (!tile.IsPartOfGroup)
|
||||
return tile;
|
||||
AtlasGroup atlasGroup = tile.GetGroup();
|
||||
|
||||
if (!atlasGroup.IsLargeTile())
|
||||
return tile;
|
||||
|
||||
AtlasGroupLargeTile largeTile = atlasGroup is AtlasGroupLargeTileAnimation largeTileAnimation ? largeTileAnimation.GetTile(tile.Row, tile.Column) : atlasGroup as AtlasGroupLargeTile;
|
||||
return GetLargeTile(largeTile).Select(t => t.Texture).Combine(largeTile.RowSpan, largeTile.ColumnSpan, _layoutDirection);
|
||||
}
|
||||
|
||||
private IEnumerable<AtlasTile> InternalGetTilesFromGroup(AtlasGroup atlasGroup, out int rowSpan, out int columnSpan)
|
||||
{
|
||||
if (atlasGroup is AtlasGroupLargeTileAnimation largeTileAnimation)
|
||||
{
|
||||
rowSpan = largeTileAnimation.RowSpan;
|
||||
columnSpan = largeTileAnimation.ColumnSpan;
|
||||
return largeTileAnimation.GetLargeTiles().SelectMany(GetLargeTile);
|
||||
}
|
||||
if (atlasGroup is AtlasGroupLargeTile largeTile)
|
||||
{
|
||||
rowSpan = largeTile.RowSpan;
|
||||
columnSpan = largeTile.ColumnSpan;
|
||||
return GetLargeTile(largeTile);
|
||||
}
|
||||
rowSpan = 1;
|
||||
columnSpan = 1;
|
||||
return GetRange(atlasGroup.Row, atlasGroup.Column, atlasGroup.Count, atlasGroup.Direction);
|
||||
}
|
||||
|
||||
public Rectangle GetTileArea(AtlasTile tile)
|
||||
{
|
||||
if (!tile.IsPartOfGroup || !AllowGroups)
|
||||
return new Rectangle(new Point(tile.Row * TileSize.Width, tile.Column * TileSize.Height), TileSize);
|
||||
AtlasGroup group = tile.GetGroup();
|
||||
return new Rectangle(new Point(group.Row * TileSize.Width, group.Column * TileSize.Height), group.GetSize(TileSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
48
PckStudio.Core/AtlasGroup.cs
Normal file
48
PckStudio.Core/AtlasGroup.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
/* Copyright (c) 2025-present miku-666
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1.The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace PckStudio.Core
|
||||
{
|
||||
public abstract class AtlasGroup
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int Row { get; }
|
||||
public int Column { get; }
|
||||
|
||||
public virtual int Count => 1;
|
||||
|
||||
protected abstract bool isAnimation { get; }
|
||||
protected abstract bool isLargeTile { get; }
|
||||
public virtual ImageLayoutDirection Direction => Column > Row ? ImageLayoutDirection.Vertical : ImageLayoutDirection.Horizontal;
|
||||
|
||||
public AtlasGroup(string name, int row, int column)
|
||||
{
|
||||
Name = name;
|
||||
Row = Math.Max(0, row);
|
||||
Column = Math.Max(0, column);
|
||||
}
|
||||
|
||||
public bool IsAnimation() => isAnimation;
|
||||
public bool IsLargeTile() => isLargeTile;
|
||||
|
||||
internal abstract Size GetSize(Size tileSize);
|
||||
|
||||
}
|
||||
}
|
||||
42
PckStudio.Core/AtlasGroupAnimation.cs
Normal file
42
PckStudio.Core/AtlasGroupAnimation.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
/* Copyright (c) 2025-present miku-666
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1.The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
using System.Drawing;
|
||||
|
||||
namespace PckStudio.Core
|
||||
{
|
||||
internal sealed class AtlasGroupAnimation : AtlasGroup
|
||||
{
|
||||
public int FrameTime { get; }
|
||||
public override int Count { get; }
|
||||
public override ImageLayoutDirection Direction { get; }
|
||||
|
||||
protected override bool isAnimation => true;
|
||||
|
||||
protected override bool isLargeTile => false;
|
||||
|
||||
internal override Size GetSize(Size tileSize) => new Size(tileSize.Width * (Direction == ImageLayoutDirection.Horizontal ? Count : 1), tileSize.Height * (Direction == ImageLayoutDirection.Vertical ? Count : 1));
|
||||
|
||||
public AtlasGroupAnimation(string name, int row, int column, int frameCount, ImageLayoutDirection direction, int frameTime = Animation.MinimumFrameTime)
|
||||
: base(name, row, column)
|
||||
{
|
||||
Count = frameCount;
|
||||
Direction = direction;
|
||||
FrameTime = frameTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
43
PckStudio.Core/AtlasGroupLargeTile.cs
Normal file
43
PckStudio.Core/AtlasGroupLargeTile.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
/* Copyright (c) 2025-present miku-666
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1.The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace PckStudio.Core
|
||||
{
|
||||
internal sealed class AtlasGroupLargeTile : AtlasGroup
|
||||
{
|
||||
public int RowSpan { get; }
|
||||
public int ColumnSpan { get; }
|
||||
|
||||
public override int Count => RowSpan * ColumnSpan;
|
||||
|
||||
protected override bool isAnimation => false;
|
||||
|
||||
protected override bool isLargeTile => true;
|
||||
|
||||
internal override Size GetSize(Size tileSize) => new Size(RowSpan * tileSize.Width, ColumnSpan * tileSize.Height);
|
||||
|
||||
public AtlasGroupLargeTile(string name, int row, int column, int rowSpan, int columnSpan)
|
||||
: base(name, row, column)
|
||||
{
|
||||
RowSpan = Math.Max(1, rowSpan);
|
||||
ColumnSpan = Math.Max(1, columnSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
79
PckStudio.Core/AtlasGroupLargeTileAnimation.cs
Normal file
79
PckStudio.Core/AtlasGroupLargeTileAnimation.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
/* Copyright (c) 2025-present miku-666
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1.The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace PckStudio.Core
|
||||
{
|
||||
internal sealed class AtlasGroupLargeTileAnimation : AtlasGroup
|
||||
{
|
||||
private AtlasGroupLargeTile[] _largeTiles;
|
||||
private int _frameCount;
|
||||
|
||||
public int RowSpan { get; }
|
||||
public int ColumnSpan { get; }
|
||||
public int FrameTime { get; }
|
||||
|
||||
public override int Count => RowSpan * ColumnSpan * _frameCount;
|
||||
|
||||
public override ImageLayoutDirection Direction { get; }
|
||||
|
||||
protected override bool isAnimation => true;
|
||||
|
||||
protected override bool isLargeTile => true;
|
||||
|
||||
internal override Size GetSize(Size tileSize) => new Size(RowSpan * tileSize.Width * (Direction == ImageLayoutDirection.Horizontal ? _frameCount : 1), ColumnSpan * tileSize.Height * (Direction == ImageLayoutDirection.Vertical ? _frameCount : 1));
|
||||
|
||||
public AtlasGroupLargeTileAnimation(string name, int row, int column, int rowSpan, int columnSpan, int frameCount, ImageLayoutDirection direction, int frameTime = Animation.MinimumFrameTime)
|
||||
: base(name, row, column)
|
||||
{
|
||||
_frameCount = Math.Abs(frameCount);
|
||||
RowSpan = Math.Max(1, rowSpan);
|
||||
ColumnSpan = Math.Max(1, columnSpan);
|
||||
Direction = direction;
|
||||
FrameTime = frameTime;
|
||||
_largeTiles = InternalGetLargeTiles().ToArray();
|
||||
}
|
||||
|
||||
private IEnumerable<AtlasGroupLargeTile> InternalGetLargeTiles()
|
||||
{
|
||||
for (int i = 0; i < _frameCount; i++)
|
||||
{
|
||||
yield return new AtlasGroupLargeTile($"{Name}_{i}", Row + (Direction == ImageLayoutDirection.Horizontal ? i * RowSpan : 0), Column + (Direction == ImageLayoutDirection.Vertical ? i * ColumnSpan : 0), RowSpan, ColumnSpan);
|
||||
}
|
||||
yield break;
|
||||
}
|
||||
|
||||
internal AtlasGroupLargeTile GetTile(int row, int col)
|
||||
{
|
||||
if (!IsInRange(row, col))
|
||||
return default;
|
||||
int i = (Direction == ImageLayoutDirection.Horizontal) ? Math.DivRem((row - Row), RowSpan, out _) : Math.DivRem((col - Column), ColumnSpan, out _);
|
||||
return (i >= 0 && i < _frameCount) ? _largeTiles[i] : _largeTiles[0];
|
||||
}
|
||||
|
||||
private bool IsInRange(int row, int col)
|
||||
{
|
||||
return Row <= row && row < (Row + (RowSpan * (Direction == ImageLayoutDirection.Horizontal ? _frameCount : 1))) && Column <= col && col < (Column + (ColumnSpan * (Direction == ImageLayoutDirection.Horizontal ? _frameCount : 1)));
|
||||
}
|
||||
|
||||
internal IEnumerable<AtlasGroupLargeTile> GetLargeTiles() => _largeTiles;
|
||||
}
|
||||
}
|
||||
68
PckStudio.Core/AtlasTile.cs
Normal file
68
PckStudio.Core/AtlasTile.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
/* Copyright (c) 2025-present miku-666, MattNL
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1.The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
using System.Drawing;
|
||||
|
||||
namespace PckStudio.Core
|
||||
{
|
||||
public sealed class AtlasTile
|
||||
{
|
||||
public int Index { get; }
|
||||
public int Row { get; }
|
||||
public int Column { get; }
|
||||
public object UserData;
|
||||
private Image texture;
|
||||
public bool IsPartOfGroup => _group != null;
|
||||
|
||||
public Image Texture { get => texture; set => texture = value; }
|
||||
|
||||
private AtlasGroup _group;
|
||||
|
||||
public AtlasTile(Image texture, int row, int column, int index, object userData)
|
||||
{
|
||||
Texture = texture;
|
||||
Row = row;
|
||||
Column = column;
|
||||
Index = index;
|
||||
UserData = userData;
|
||||
}
|
||||
|
||||
internal void SetGroup(AtlasGroup group)
|
||||
{
|
||||
_group = group;
|
||||
}
|
||||
|
||||
public AtlasGroup GetGroup() => _group;
|
||||
|
||||
public static implicit operator Image(AtlasTile tile) => tile.Texture;
|
||||
|
||||
public bool IsUserDataOfType<T>() where T : class => UserData is T _;
|
||||
|
||||
public T GetUserDataOfType<T>() where T : class => UserData as T;
|
||||
|
||||
public bool TryGetUserDataOfType<T>(out T value) where T : class
|
||||
{
|
||||
if (UserData is T val)
|
||||
{
|
||||
value = val;
|
||||
return true;
|
||||
}
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
PckStudio.Core/Deserializer/AtlasDeserializer.cs
Normal file
23
PckStudio.Core/Deserializer/AtlasDeserializer.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using OMI.Formats.Pck;
|
||||
using PckStudio.Core.Extensions;
|
||||
using PckStudio.Interfaces;
|
||||
|
||||
namespace PckStudio.Core.Deserializer
|
||||
{
|
||||
public sealed class AtlasDeserializer : IPckAssetDeserializer<Atlas>
|
||||
{
|
||||
private readonly ResourceLocation _resourceLocation;
|
||||
|
||||
public AtlasDeserializer(ResourceLocation resourceLocation)
|
||||
{
|
||||
_resourceLocation = resourceLocation;
|
||||
}
|
||||
|
||||
public Atlas Deserialize(PckAsset asset) => Atlas.FromResourceLocation(asset.GetTexture(), _resourceLocation);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,9 @@ namespace PckStudio.Core.Extensions
|
||||
{
|
||||
public static class AnimationExtensions
|
||||
{
|
||||
public static Image CreateAnimationImage(this Animation animation)
|
||||
public static Image CreateAnimationImage(this Animation animation) => animation.CreateAnimationImage(Color.Black);
|
||||
|
||||
public static Image CreateAnimationImage(this Animation animation, Color blendColor)
|
||||
{
|
||||
if (animation.FrameCount == 0)
|
||||
{
|
||||
@@ -15,7 +17,8 @@ namespace PckStudio.Core.Extensions
|
||||
var generateor = new AnimatedGifCreator(ms, GameConstants.GameTickInMilliseconds, 0);
|
||||
foreach (Animation.Frame frame in animation.GetInterpolatedFrames())
|
||||
{
|
||||
generateor.AddFrame(frame.Texture, frame.Ticks * GameConstants.GameTickInMilliseconds, GifQuality.Bit8);
|
||||
Image texture = (blendColor == Color.Black || blendColor == Color.White) ? frame.Texture : frame.Texture.Blend(blendColor, BlendMode.Multiply);
|
||||
generateor.AddFrame(texture, frame.Ticks * GameConstants.GameTickInMilliseconds, GifQuality.Bit8);
|
||||
}
|
||||
ms.Position = 0;
|
||||
return Image.FromStream(ms);
|
||||
|
||||
@@ -16,14 +16,15 @@
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PckStudio.Core.Extensions
|
||||
@@ -71,12 +72,13 @@ namespace PckStudio.Core.Extensions
|
||||
int rowCount = source.Width / size.Width;
|
||||
int columnCount = source.Height / size.Height;
|
||||
Debug.WriteLine($"Image size: {source.Size}, Area size: {size}, col num: {columnCount}, row num: {rowCount}");
|
||||
bool vertical = imageLayout == ImageLayoutDirection.Vertical;
|
||||
for (int i = 0; i < columnCount * rowCount; i++)
|
||||
{
|
||||
int row = Math.DivRem(i, rowCount, out int column);
|
||||
if (imageLayout == ImageLayoutDirection.Vertical)
|
||||
column = Math.DivRem(i, columnCount, out row);
|
||||
Rectangle tileArea = new Rectangle(new Point(column * size.Width, row * size.Height), size);
|
||||
int column = Math.DivRem(i, rowCount, out int row);
|
||||
if (vertical)
|
||||
row = Math.DivRem(i, columnCount, out column);
|
||||
Rectangle tileArea = new Rectangle(new Point(row * size.Width, column * size.Height), size);
|
||||
yield return source.GetArea(tileArea);
|
||||
}
|
||||
yield break;
|
||||
@@ -94,38 +96,48 @@ namespace PckStudio.Core.Extensions
|
||||
|
||||
public static Image Combine(this IEnumerable<Image> sources, ImageLayoutDirection layoutDirection)
|
||||
{
|
||||
Size imageSize = CalculateImageSize(sources, layoutDirection);
|
||||
bool horizontal = layoutDirection == ImageLayoutDirection.Horizontal;
|
||||
int imgCount = sources.Count();
|
||||
int rows = horizontal ? imgCount : 1;
|
||||
int columns = horizontal ? 1 : imgCount;
|
||||
return sources.Combine(rows, columns, layoutDirection);
|
||||
}
|
||||
|
||||
public static Image Combine(this IEnumerable<Image> sources, int rows, int columns, ImageLayoutDirection layoutDirection)
|
||||
{
|
||||
Size imageSize = CalculateImageSize(sources, rows, columns);
|
||||
var image = new Bitmap(imageSize.Width, imageSize.Height);
|
||||
bool horizontal = layoutDirection == ImageLayoutDirection.Horizontal;
|
||||
|
||||
using (var graphic = Graphics.FromImage(image))
|
||||
{
|
||||
foreach ((int i, Image texture) in sources.enumerate())
|
||||
{
|
||||
var info = new ImageSection(texture.Size, i, layoutDirection);
|
||||
graphic.DrawImage(texture, info.Point);
|
||||
int x = Math.DivRem(i, columns, out int y);
|
||||
if (horizontal)
|
||||
y = Math.DivRem(i, rows, out x);
|
||||
graphic.DrawImage(texture, new Point(x * texture.Width, y * texture.Height));
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
private static Size CalculateImageSize(IEnumerable<Image> sources, ImageLayoutDirection layoutDirection)
|
||||
private static Size CalculateImageSize(IEnumerable<Image> sources, int rows, int columns)
|
||||
{
|
||||
Size size = sources.First().Size;
|
||||
int count = sources.Count();
|
||||
if (sources == null)
|
||||
return Size.Empty;
|
||||
Image[] imgs = sources.ToArray();
|
||||
|
||||
if (count < 2)
|
||||
return count < 1 ? Size.Empty : size;
|
||||
if (imgs.Length < rows * columns)
|
||||
throw new ArgumentOutOfRangeException("Insufficent soure images provided.");
|
||||
|
||||
var horizontal = layoutDirection == ImageLayoutDirection.Horizontal;
|
||||
Size size = imgs[0].Size;
|
||||
|
||||
if (!sources.All(img => img.Size == size))
|
||||
if (!imgs.All(img => img.Size == size))
|
||||
throw new InvalidOperationException("Images must have the same width and height.");
|
||||
|
||||
if (horizontal)
|
||||
size.Width *= count;
|
||||
else
|
||||
size.Height *= count;
|
||||
|
||||
size.Width *= rows;
|
||||
size.Height *= columns;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,10 +52,17 @@
|
||||
<Compile Include="Animation.cs" />
|
||||
<Compile Include="App\SettingsManager.cs" />
|
||||
<Compile Include="App\Updater.cs" />
|
||||
<Compile Include="Atlas.cs" />
|
||||
<Compile Include="AtlasGroup.cs" />
|
||||
<Compile Include="AtlasGroupAnimation.cs" />
|
||||
<Compile Include="AtlasGroupLargeTile.cs" />
|
||||
<Compile Include="AtlasGroupLargeTileAnimation.cs" />
|
||||
<Compile Include="AtlasTile.cs" />
|
||||
<Compile Include="BoundingBox.cs" />
|
||||
<Compile Include="DelegatedFileSaveContext.cs" />
|
||||
<Compile Include="DelegatedSaveContext.cs" />
|
||||
<Compile Include="Deserializer\AnimationDeserializer.cs" />
|
||||
<Compile Include="Deserializer\AtlasDeserializer.cs" />
|
||||
<Compile Include="Deserializer\ImageDeserializer.cs" />
|
||||
<Compile Include="Extensions\AnimationExtensions.cs" />
|
||||
<Compile Include="Extensions\BlendMode.cs" />
|
||||
@@ -120,6 +127,7 @@
|
||||
<Compile Include="ResourceCategory.cs" />
|
||||
<Compile Include="ResourceLocation.cs" />
|
||||
<Compile Include="Serializer\AnimationSerializer.cs" />
|
||||
<Compile Include="Serializer\AtlasSerializer.cs" />
|
||||
<Compile Include="Serializer\ImageSerializer.cs" />
|
||||
<Compile Include="Skin\Skin.cs" />
|
||||
<Compile Include="Skin\SkinANIM.cs" />
|
||||
|
||||
@@ -19,6 +19,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using PckStudio.Core.Json;
|
||||
using PckStudio.Json;
|
||||
|
||||
namespace PckStudio.Core
|
||||
{
|
||||
@@ -27,42 +29,116 @@ namespace PckStudio.Core
|
||||
private static List<ResourceLocation> ResourceGroups = new List<ResourceLocation>();
|
||||
private static readonly ResourceLocation Unknown = new ResourceLocation(string.Empty, ResourceCategory.Unknown, -1);
|
||||
|
||||
private static AtlasGroup[] _particaleAtlasGroups =
|
||||
{
|
||||
new AtlasGroupAnimation("generic" , row: 0, column: 0, frameCount: 8, ImageLayoutDirection.Horizontal, 2),
|
||||
new AtlasGroupAnimation("splash" , row: 3, column: 1, frameCount: 4, ImageLayoutDirection.Horizontal, 2),
|
||||
new AtlasGroupAnimation("drip" , row: 0, column: 7, frameCount: 3, ImageLayoutDirection.Horizontal, 4),
|
||||
new AtlasGroupAnimation("effect" , row: 0, column: 8, frameCount: 8, ImageLayoutDirection.Horizontal, 2),
|
||||
new AtlasGroupAnimation("splash_effect" , row: 0, column: 9, frameCount: 8, ImageLayoutDirection.Horizontal, 2),
|
||||
new AtlasGroupAnimation("firework_spark" , row: 0, column: 10, frameCount: 8, ImageLayoutDirection.Horizontal, 2),
|
||||
new AtlasGroupAnimation("glitter" , row: 0, column: 11, frameCount: 8, ImageLayoutDirection.Horizontal, 2),
|
||||
new AtlasGroupAnimation("BE_explosion" , row: 0, column: 12, frameCount: 16, ImageLayoutDirection.Horizontal),
|
||||
new AtlasGroupLargeTile("flash" , row: 4, column: 2, rowSpan: 4, columnSpan: 4),
|
||||
new AtlasGroupLargeTileAnimation("bubble_pop", row: 6, column: 6, rowSpan: 2, columnSpan: 2, frameCount: 5, ImageLayoutDirection.Horizontal, 2),
|
||||
};
|
||||
|
||||
private static AtlasGroup[] _terrainAtlasGroups =
|
||||
{
|
||||
new AtlasGroupLargeTile("Oak Door" , row: 1, column: 5, rowSpan: 1, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Iron Door" , row: 2, column: 5, rowSpan: 1, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Acacia Door" , row: 0, column: 23, rowSpan: 1, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Birch Door" , row: 1, column: 23, rowSpan: 1, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Dark Oak Door", row: 2, column: 23, rowSpan: 1, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Jungle Door" , row: 3, column: 23, rowSpan: 1, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Spruce Door" , row: 4, column: 23, rowSpan: 1, columnSpan: 2),
|
||||
|
||||
new AtlasGroupLargeTile("Large Fern" , row: 0, column: 20, rowSpan: 1, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Double Tall Grass", row: 1, column: 20, rowSpan: 1, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Poeny" , row: 2, column: 20, rowSpan: 1, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Rose Bush" , row: 3, column: 20, rowSpan: 1, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Lilac" , row: 4, column: 20, rowSpan: 1, columnSpan: 2),
|
||||
|
||||
new AtlasGroupAnimation("Wheat" , row: 8, column: 5, frameCount: 8, ImageLayoutDirection.Horizontal, 5),
|
||||
new AtlasGroupAnimation("Potatoes" , row: 9, column: 16, frameCount: 4, ImageLayoutDirection.Horizontal, 5),
|
||||
new AtlasGroupAnimation("Carrots" , row: 8, column: 12, frameCount: 4, ImageLayoutDirection.Horizontal, 5),
|
||||
new AtlasGroupAnimation("Beetroots" , row: 0, column: 25, frameCount: 4, ImageLayoutDirection.Horizontal, 5),
|
||||
new AtlasGroupAnimation("Nether Wart", row: 2, column: 14, frameCount: 3, ImageLayoutDirection.Horizontal, 5),
|
||||
new AtlasGroupAnimation("Destroy" , row: 0, column: 15, frameCount: 10, ImageLayoutDirection.Horizontal, 3),
|
||||
};
|
||||
|
||||
private static AtlasGroup[] _itemsAtlasGroups =
|
||||
{
|
||||
new AtlasGroupAnimation("Bow Pulling", row: 5, column: 6, frameCount: 3, ImageLayoutDirection.Vertical, 6),
|
||||
};
|
||||
|
||||
private static AtlasGroup[] _paintingAtlasGroups =
|
||||
{
|
||||
new AtlasGroupLargeTile("The Pool" , row: 0, column: 2, rowSpan: 2, columnSpan: 1),
|
||||
new AtlasGroupLargeTile("Bonjour Monsiuer Courbet", row: 2, column: 2, rowSpan: 2, columnSpan: 1),
|
||||
new AtlasGroupLargeTile("Seaside" , row: 4, column: 2, rowSpan: 2, columnSpan: 1),
|
||||
new AtlasGroupLargeTile("sunset_dense" , row: 6, column: 2, rowSpan: 2, columnSpan: 1),
|
||||
new AtlasGroupLargeTile("Creebet" , row: 8, column: 2, rowSpan: 2, columnSpan: 1),
|
||||
|
||||
new AtlasGroupLargeTile("Wanderer" , row: 0, column: 4, rowSpan: 1, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Graham" , row: 1, column: 4, rowSpan: 1, columnSpan: 2),
|
||||
|
||||
new AtlasGroupLargeTile("Fighters" , row: 0, column: 6, rowSpan: 4, columnSpan: 2),
|
||||
|
||||
new AtlasGroupLargeTile("Match" , row: 0, column: 8, rowSpan: 2, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Bust" , row: 2, column: 8, rowSpan: 2, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("The stage is set" , row: 4, column: 8, rowSpan: 2, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("The Void" , row: 6, column: 8, rowSpan: 2, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Skull and Roses" , row: 8, column: 8, rowSpan: 2, columnSpan: 2),
|
||||
new AtlasGroupLargeTile("Wither" , row: 10, column: 8, rowSpan: 2, columnSpan: 2),
|
||||
|
||||
new AtlasGroupLargeTile("Mortal Coil" , row: 12, column: 4, rowSpan: 4, columnSpan: 3),
|
||||
new AtlasGroupLargeTile("Kong" , row: 12, column: 7, rowSpan: 4, columnSpan: 3),
|
||||
|
||||
new AtlasGroupLargeTile("Back Texture" , row: 12, column: 0, rowSpan: 4, columnSpan: 4),
|
||||
new AtlasGroupLargeTile("Pointer" , row: 0, column: 12, rowSpan: 4, columnSpan: 4),
|
||||
new AtlasGroupLargeTile("Pigscene" , row: 4, column: 12, rowSpan: 4, columnSpan: 4),
|
||||
new AtlasGroupLargeTile("Skull On Fire" , row: 8, column: 12, rowSpan: 4, columnSpan: 4),
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, ResourceLocation> _categoryLookUp = new Dictionary<string, ResourceLocation>()
|
||||
{
|
||||
["textures/items"] = new ResourceLocation("textures/items", ResourceCategory.ItemAnimation, 16, isGroup: true),
|
||||
["textures/blocks"] = new ResourceLocation("textures/blocks", ResourceCategory.BlockAnimation, 16, isGroup: true),
|
||||
["mob"] = new ResourceLocation("mob", ResourceCategory.MobEntityTextures, 1, isGroup: true),
|
||||
["item"] = new ResourceLocation("item", ResourceCategory.ItemEntityTextures, 1, isGroup: true),
|
||||
["terrain.png"] = new ResourceLocation("terrain.png", ResourceCategory.BlockAtlas, 16),
|
||||
["items.png"] = new ResourceLocation("items.png", ResourceCategory.ItemAtlas, 16),
|
||||
["particles.png"] = new ResourceLocation("particles.png", ResourceCategory.ParticleAtlas, 16),
|
||||
["item/banner/Banner_Atlas.png"] = new ResourceLocation("item/banner/Banner_Atlas.png", ResourceCategory.BannerAtlas, new Size(6, 7), TillingMode.WidthAndHeight),
|
||||
["art/kz.png"] = new ResourceLocation("art/kz.png", ResourceCategory.PaintingAtlas, 16),
|
||||
["misc/explosion.png"] = new ResourceLocation("misc/explosion.png", ResourceCategory.ExplosionAtlas, 4),
|
||||
["item/xporb.png"] = new ResourceLocation("item/xporb.png", ResourceCategory.ExperienceOrbAtlas, 4),
|
||||
["terrain/moon_phases.png"] = new ResourceLocation("terrain/moon_phases.png", ResourceCategory.MoonPhaseAtlas, 4),
|
||||
["misc/mapicons.png"] = new ResourceLocation("misc/mapicons.png", ResourceCategory.MapIconAtlas, 4),
|
||||
["misc/additionalmapicons.png"] = new ResourceLocation("misc/additionalmapicons.png", ResourceCategory.AdditionalMapIconsAtlas, 4),
|
||||
["textures/items"] = new ResourceLocation("textures/items", ResourceCategory.ItemAnimation, 16, isGroup: true),
|
||||
["textures/blocks"] = new ResourceLocation("textures/blocks", ResourceCategory.BlockAnimation, 16, isGroup: true),
|
||||
["mob"] = new ResourceLocation("mob", ResourceCategory.MobEntityTextures, 1, isGroup: true),
|
||||
["item"] = new ResourceLocation("item", ResourceCategory.ItemEntityTextures, 1, isGroup: true),
|
||||
["terrain.png"] = new ResourceLocation("terrain.png", ResourceCategory.BlockAtlas, 16, tilesInfo: Tiles.BlockTileInfos, atlasGroups: _terrainAtlasGroups),
|
||||
["items.png"] = new ResourceLocation("items.png", ResourceCategory.ItemAtlas, 16, tilesInfo: Tiles.ItemTileInfos, atlasGroups: _itemsAtlasGroups),
|
||||
["particles.png"] = new ResourceLocation("particles.png", ResourceCategory.ParticleAtlas, 16, tilesInfo: Tiles.ParticleTileInfos, atlasGroups: _particaleAtlasGroups),
|
||||
//============ TODO ============//
|
||||
["item/banner/Banner_Atlas.png"] = new ResourceLocation("item/banner/Banner_Atlas.png", ResourceCategory.BannerAtlas, new Size(6, 7), TillingMode.WidthAndHeight, tilesInfo: Tiles.BannerTileInfos),
|
||||
//==============================//
|
||||
["art/kz.png"] = new ResourceLocation("art/kz.png", ResourceCategory.PaintingAtlas, 16, tilesInfo: Tiles.PaintingTileInfos, atlasGroups: _paintingAtlasGroups),
|
||||
["misc/explosion.png"] = new ResourceLocation("misc/explosion.png", ResourceCategory.ExplosionAtlas, 16, tilesInfo: Tiles.ExplosionTileInfos),
|
||||
["item/xporb.png"] = new ResourceLocation("item/xporb.png", ResourceCategory.ExperienceOrbAtlas, 4, tilesInfo: Tiles.ExperienceOrbTileInfos),
|
||||
["terrain/moon_phases.png"] = new ResourceLocation("terrain/moon_phases.png", ResourceCategory.MoonPhaseAtlas, 4, tilesInfo: Tiles.MoonPhaseTileInfos),
|
||||
["misc/mapicons.png"] = new ResourceLocation("misc/mapicons.png", ResourceCategory.MapIconAtlas, 4, tilesInfo: Tiles.MapIconTileInfos),
|
||||
["misc/additionalmapicons.png"] = new ResourceLocation("misc/additionalmapicons.png", ResourceCategory.AdditionalMapIconsAtlas, 4, tilesInfo: Tiles.AdditionalMapIconTileInfos),
|
||||
};
|
||||
|
||||
public static string GetPathFromCategory(ResourceCategory category)
|
||||
{
|
||||
return category switch
|
||||
{
|
||||
ResourceCategory.ItemAnimation => _categoryLookUp["textures/items"].ToString(),
|
||||
ResourceCategory.BlockAnimation => _categoryLookUp["textures/blocks"].ToString(),
|
||||
ResourceCategory.MobEntityTextures => _categoryLookUp["mob"].ToString(),
|
||||
ResourceCategory.ItemEntityTextures => _categoryLookUp["item"].ToString(),
|
||||
ResourceCategory.BlockAtlas => _categoryLookUp["terrain.png"].ToString(),
|
||||
ResourceCategory.ItemAtlas => _categoryLookUp["items.png"].ToString(),
|
||||
ResourceCategory.ParticleAtlas => _categoryLookUp["particles.png"].ToString(),
|
||||
ResourceCategory.BannerAtlas => _categoryLookUp["item/banner/Banner_Atlas.png"].ToString(),
|
||||
ResourceCategory.PaintingAtlas => _categoryLookUp["art/kz.png"].ToString(),
|
||||
ResourceCategory.ExplosionAtlas => _categoryLookUp["misc/explosion.png"].ToString(),
|
||||
ResourceCategory.ExperienceOrbAtlas => _categoryLookUp["item/xporb.png"].ToString(),
|
||||
ResourceCategory.MoonPhaseAtlas => _categoryLookUp["terrain/moon_phases.png"].ToString(),
|
||||
ResourceCategory.MapIconAtlas => _categoryLookUp["misc/mapicons.png"].ToString(),
|
||||
ResourceCategory.AdditionalMapIconsAtlas => _categoryLookUp["misc/additionalmapicons.png"].ToString(),
|
||||
ResourceCategory.ItemAnimation => _categoryLookUp["textures/items"].ToString(),
|
||||
ResourceCategory.BlockAnimation => _categoryLookUp["textures/blocks"].ToString(),
|
||||
ResourceCategory.MobEntityTextures => _categoryLookUp["mob"].ToString(),
|
||||
ResourceCategory.ItemEntityTextures => _categoryLookUp["item"].ToString(),
|
||||
ResourceCategory.BlockAtlas => _categoryLookUp["terrain.png"].ToString(),
|
||||
ResourceCategory.ItemAtlas => _categoryLookUp["items.png"].ToString(),
|
||||
ResourceCategory.ParticleAtlas => _categoryLookUp["particles.png"].ToString(),
|
||||
ResourceCategory.BannerAtlas => _categoryLookUp["item/banner/Banner_Atlas.png"].ToString(),
|
||||
ResourceCategory.PaintingAtlas => _categoryLookUp["art/kz.png"].ToString(),
|
||||
ResourceCategory.ExplosionAtlas => _categoryLookUp["misc/explosion.png"].ToString(),
|
||||
ResourceCategory.ExperienceOrbAtlas => _categoryLookUp["item/xporb.png"].ToString(),
|
||||
ResourceCategory.MoonPhaseAtlas => _categoryLookUp["terrain/moon_phases.png"].ToString(),
|
||||
ResourceCategory.MapIconAtlas => _categoryLookUp["misc/mapicons.png"].ToString(),
|
||||
ResourceCategory.AdditionalMapIconsAtlas => _categoryLookUp["misc/additionalmapicons.png"].ToString(),
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
@@ -80,43 +156,46 @@ namespace PckStudio.Core
|
||||
}
|
||||
|
||||
public enum TillingMode
|
||||
{
|
||||
{
|
||||
Width,
|
||||
Height,
|
||||
WidthAndHeight
|
||||
}
|
||||
|
||||
public readonly string Path;
|
||||
public readonly ResourceCategory Category;
|
||||
public readonly Size TillingFactor;
|
||||
public readonly TillingMode Tilling;
|
||||
public readonly bool IsGroup;
|
||||
public string Path { get; }
|
||||
public ResourceCategory Category { get; }
|
||||
public Size TillingFactor { get; }
|
||||
public TillingMode Tilling { get; }
|
||||
public bool IsGroup { get; }
|
||||
public IEnumerable<JsonTileInfo> TilesInfo { get; }
|
||||
public IEnumerable<AtlasGroup> AtlasGroups { get; }
|
||||
|
||||
public Size GetTileArea(Size imgSize)
|
||||
{
|
||||
int tileFactorWidth = Math.Max(1, TillingFactor.Width);
|
||||
int tileFactorHeight = Math.Max(1, TillingFactor.Height);
|
||||
return Tilling switch
|
||||
{
|
||||
TillingMode.Width => new Size(imgSize.Width / tileFactorWidth, imgSize.Width / tileFactorHeight),
|
||||
TillingMode.Height => new Size(imgSize.Height / tileFactorWidth, imgSize.Height / tileFactorHeight),
|
||||
TillingMode.WidthAndHeight => new Size(imgSize.Width / tileFactorWidth, imgSize.Height / tileFactorHeight),
|
||||
TillingMode.Width => new Size(imgSize.Width / TillingFactor.Width, imgSize.Width / TillingFactor.Height),
|
||||
TillingMode.Height => new Size(imgSize.Height / TillingFactor.Width, imgSize.Height / TillingFactor.Height),
|
||||
TillingMode.WidthAndHeight => new Size(imgSize.Width / TillingFactor.Width, imgSize.Height / TillingFactor.Height),
|
||||
_ => Size.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
private ResourceLocation(string path, ResourceCategory category, int tillingFactor, TillingMode tilling = TillingMode.Width, bool isGroup = false)
|
||||
: this(path, category, new Size(tillingFactor, tillingFactor), tilling, isGroup)
|
||||
private ResourceLocation(string path, ResourceCategory category, int tillingFactor, TillingMode tilling = TillingMode.Width, bool isGroup = false, IEnumerable<JsonTileInfo> tilesInfo = default, IEnumerable<AtlasGroup> atlasGroups = default)
|
||||
: this(path, category, new Size(tillingFactor, tillingFactor), tilling, isGroup, tilesInfo, atlasGroups)
|
||||
{
|
||||
}
|
||||
|
||||
private ResourceLocation(string path, ResourceCategory category, Size tillingFactor, TillingMode tilling = TillingMode.Width, bool isGroup = false)
|
||||
|
||||
private ResourceLocation(string path, ResourceCategory category, Size tillingFactor, TillingMode tilling = TillingMode.Width, bool isGroup = false, IEnumerable<JsonTileInfo> tilesInfo = default, IEnumerable<AtlasGroup> atlasGroups = default)
|
||||
{
|
||||
Path = path;
|
||||
Category = category;
|
||||
TillingFactor = tillingFactor;
|
||||
TillingFactor = new Size(Math.Max(1, tillingFactor.Width), Math.Max(1, tillingFactor.Height));
|
||||
Tilling = tilling;
|
||||
IsGroup = isGroup;
|
||||
TilesInfo = tilesInfo ?? Enumerable.Empty<JsonTileInfo>();
|
||||
AtlasGroups = atlasGroups ?? Enumerable.Empty<AtlasGroup>();
|
||||
if (isGroup)
|
||||
ResourceGroups.Add(this);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
{
|
||||
"internalName": "base",
|
||||
"displayName": "Base",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -30,7 +30,7 @@
|
||||
{
|
||||
"internalName": "border",
|
||||
"displayName": "Bordure",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -56,7 +56,7 @@
|
||||
{
|
||||
"internalName": "bricks",
|
||||
"displayName": "Field Masoned",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -82,7 +82,7 @@
|
||||
{
|
||||
"internalName": "circle",
|
||||
"displayName": "Roundel",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -108,7 +108,7 @@
|
||||
{
|
||||
"internalName": "creeper",
|
||||
"displayName": "Creeper Charge",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -134,7 +134,7 @@
|
||||
{
|
||||
"internalName": "cross",
|
||||
"displayName": "Saltire",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -160,7 +160,7 @@
|
||||
{
|
||||
"internalName": "curly_border",
|
||||
"displayName": "Bordure Indented",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -186,7 +186,7 @@
|
||||
{
|
||||
"internalName": "diagonal_left",
|
||||
"displayName": "Per Bend Sinister",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -212,7 +212,7 @@
|
||||
{
|
||||
"internalName": "diagonal_right",
|
||||
"displayName": "Per Bend",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -238,7 +238,7 @@
|
||||
{
|
||||
"internalName": "diagonal_up_left",
|
||||
"displayName": "Per Bend Inverted",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -264,7 +264,7 @@
|
||||
{
|
||||
"internalName": "diagonal_up_right",
|
||||
"displayName": "Per Bend Sinister Inverted",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -290,7 +290,7 @@
|
||||
{
|
||||
"internalName": "flower",
|
||||
"displayName": "Flower Charge",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -316,7 +316,7 @@
|
||||
{
|
||||
"internalName": "gradient",
|
||||
"displayName": "Gradient",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -342,7 +342,7 @@
|
||||
{
|
||||
"internalName": "gradient_up",
|
||||
"displayName": "Base Gradient",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -368,7 +368,7 @@
|
||||
{
|
||||
"internalName": "half_horizontal",
|
||||
"displayName": "Per Fess",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -394,7 +394,7 @@
|
||||
{
|
||||
"internalName": "half_horizontal_bottom",
|
||||
"displayName": "Per Fess Inverted",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -420,7 +420,7 @@
|
||||
{
|
||||
"internalName": "half_vertical",
|
||||
"displayName": "Per Pale",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -446,7 +446,7 @@
|
||||
{
|
||||
"internalName": "half_vertical_right",
|
||||
"displayName": "Per Pale Inverted",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -472,7 +472,7 @@
|
||||
{
|
||||
"internalName": "mojang",
|
||||
"displayName": "Thing",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -498,7 +498,7 @@
|
||||
{
|
||||
"internalName": "rhombus",
|
||||
"displayName": "Lozenge",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -524,7 +524,7 @@
|
||||
{
|
||||
"internalName": "skull",
|
||||
"displayName": "Skull Charge",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -550,7 +550,7 @@
|
||||
{
|
||||
"internalName": "small_stripes",
|
||||
"displayName": "Paly",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -576,7 +576,7 @@
|
||||
{
|
||||
"internalName": "square_bottom_left",
|
||||
"displayName": "Base Dexter Canton",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -602,7 +602,7 @@
|
||||
{
|
||||
"internalName": "square_bottom_right",
|
||||
"displayName": "Base Sinister Canton",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -628,7 +628,7 @@
|
||||
{
|
||||
"internalName": "square_top_left",
|
||||
"displayName": "Chief Dexter Canton",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -654,7 +654,7 @@
|
||||
{
|
||||
"internalName": "square_top_right",
|
||||
"displayName": "Chief Sinister Canton",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -680,7 +680,7 @@
|
||||
{
|
||||
"internalName": "straight_cross",
|
||||
"displayName": "Cross",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -706,7 +706,7 @@
|
||||
{
|
||||
"internalName": "stripe_bottom",
|
||||
"displayName": "Base Fess",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -732,7 +732,7 @@
|
||||
{
|
||||
"internalName": "stripe_center",
|
||||
"displayName": "Pale",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -758,7 +758,7 @@
|
||||
{
|
||||
"internalName": "strip_downleft",
|
||||
"displayName": "Bend Sinister",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -784,7 +784,7 @@
|
||||
{
|
||||
"internalName": "stripe_downright",
|
||||
"displayName": "Bend",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -810,7 +810,7 @@
|
||||
{
|
||||
"internalName": "stripe_left",
|
||||
"displayName": "Pale Dexter",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -836,7 +836,7 @@
|
||||
{
|
||||
"internalName": "stripe_middle",
|
||||
"displayName": "Fess",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -862,7 +862,7 @@
|
||||
{
|
||||
"internalName": "stripe_right",
|
||||
"displayName": "Pale Sinister",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -888,7 +888,7 @@
|
||||
{
|
||||
"internalName": "stripe_top",
|
||||
"displayName": "Chief Fess",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -914,7 +914,7 @@
|
||||
{
|
||||
"internalName": "triangle_bottom",
|
||||
"displayName": "Chevron",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -940,7 +940,7 @@
|
||||
{
|
||||
"internalName": "triangle_top",
|
||||
"displayName": "Inverted Chevron",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -966,7 +966,7 @@
|
||||
{
|
||||
"internalName": "triangles_bottom",
|
||||
"displayName": "Base Indented",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -992,7 +992,7 @@
|
||||
{
|
||||
"internalName": "triangles_top",
|
||||
"displayName": "Chief Indented",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
@@ -1026,7 +1026,7 @@
|
||||
{
|
||||
"internalName": "globe",
|
||||
"displayName": "Globe [PS4 ONLY]",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Banner_White",
|
||||
"variants": [
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{
|
||||
"internalName": "grass_top",
|
||||
"displayName": "Grass Block (Top)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Grass_Common",
|
||||
"variants": [
|
||||
@@ -167,7 +167,7 @@
|
||||
{
|
||||
"internalName": "grass_side_overlay",
|
||||
"displayName": "Grass Side (Overlay)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Grass_Common",
|
||||
"variants": [
|
||||
@@ -181,7 +181,7 @@
|
||||
{
|
||||
"internalName": "tallgrass",
|
||||
"displayName": "Tall Grass",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Grass_Common",
|
||||
"variants": [
|
||||
@@ -243,7 +243,7 @@
|
||||
{
|
||||
"internalName": "leaves",
|
||||
"displayName": "Oak Leaves",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Foliage_Default",
|
||||
"variants": [
|
||||
@@ -258,7 +258,7 @@
|
||||
{
|
||||
"internalName": "leaves_opaque",
|
||||
"displayName": "Oak Leaves (Opaque)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Foliage_Default",
|
||||
"variants": [
|
||||
@@ -281,7 +281,7 @@
|
||||
{
|
||||
"internalName": "fern",
|
||||
"displayName": "Fern",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Grass_Common",
|
||||
"variants": [
|
||||
@@ -371,7 +371,7 @@
|
||||
{
|
||||
"internalName": "waterlily",
|
||||
"displayName": "Lily Pad",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Tile_WaterLily",
|
||||
"variants": [ "Tile_WaterLily" ]
|
||||
@@ -516,7 +516,7 @@
|
||||
{
|
||||
"internalName": "stem_straight",
|
||||
"displayName": "Stem",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Tile_StemMin",
|
||||
"variants": [
|
||||
@@ -588,7 +588,7 @@
|
||||
{
|
||||
"internalName": "stem_bent",
|
||||
"displayName": "Stem (Attached)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Tile_StemMin",
|
||||
"variants": [
|
||||
@@ -616,7 +616,7 @@
|
||||
{
|
||||
"internalName": "leaves_spruce",
|
||||
"displayName": "Spruce Leaves",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Foliage_Evergreen",
|
||||
"variants": [
|
||||
@@ -631,7 +631,7 @@
|
||||
{
|
||||
"internalName": "leaves_spruce_opaque",
|
||||
"displayName": "Spruce Leaves (Opaque)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Foliage_Evergreen",
|
||||
"variants": [
|
||||
@@ -682,7 +682,7 @@
|
||||
{
|
||||
"internalName": "vine",
|
||||
"displayName": "Vines",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Foliage_Default",
|
||||
"variants": [
|
||||
@@ -777,7 +777,7 @@
|
||||
{
|
||||
"internalName": "redstone_dust_cross",
|
||||
"displayName": "Redstone Dust (Cross)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Tile_RedstoneDust",
|
||||
"variants": [
|
||||
@@ -791,7 +791,7 @@
|
||||
{
|
||||
"internalName": "redstone_dust_line",
|
||||
"displayName": "Redstone Dust (Line)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Tile_RedstoneDust",
|
||||
"variants": [
|
||||
@@ -925,7 +925,7 @@
|
||||
{
|
||||
"internalName": "leaves_jungle",
|
||||
"displayName": "Jungle Leaves",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Foliage_Default",
|
||||
"variants": [
|
||||
@@ -940,7 +940,7 @@
|
||||
{
|
||||
"internalName": "leaves_jungle_opaque",
|
||||
"displayName": "Jungle Leaves (Opaque)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Foliage_Default",
|
||||
"variants": [
|
||||
@@ -983,7 +983,7 @@
|
||||
{
|
||||
"internalName": "water",
|
||||
"displayName": "Water",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"isWaterColour": true,
|
||||
"defaultName": "Water_Plains",
|
||||
@@ -1034,7 +1034,7 @@
|
||||
{
|
||||
"internalName": "water_flow",
|
||||
"displayName": "Flowing Water",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"width": 2,
|
||||
"height": 2,
|
||||
"colourEntry": {
|
||||
@@ -1541,7 +1541,7 @@
|
||||
{
|
||||
"internalName": "double_plant_fern_top",
|
||||
"displayName": "Large Fern (Top)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Grass_Common",
|
||||
"variants": [
|
||||
@@ -1555,7 +1555,7 @@
|
||||
{
|
||||
"internalName": "double_plant_grass_top",
|
||||
"displayName": "Double Tall Grass (Top)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Grass_Common",
|
||||
"variants": [
|
||||
@@ -1605,7 +1605,7 @@
|
||||
{
|
||||
"internalName": "leaves_acacia",
|
||||
"displayName": "Acacia Leaves",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Foliage_Default",
|
||||
"variants": [
|
||||
@@ -1620,7 +1620,7 @@
|
||||
{
|
||||
"internalName": "leaves_acacia_fast",
|
||||
"displayName": "Acacia Leaves (Opaque)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Foliage_Default",
|
||||
"variants": [
|
||||
@@ -1647,7 +1647,7 @@
|
||||
{
|
||||
"internalName": "double_plant_fern_bottom",
|
||||
"displayName": "Large Fern (Bottom)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Grass_Common",
|
||||
"variants": [
|
||||
@@ -1661,7 +1661,7 @@
|
||||
{
|
||||
"internalName": "double_plant_grass_bottom",
|
||||
"displayName": "Double Tall Grass (Bottom)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Grass_Common",
|
||||
"variants": [
|
||||
@@ -1711,7 +1711,7 @@
|
||||
{
|
||||
"internalName": "leaves_big_oak",
|
||||
"displayName": "Dark Oak Leaves",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Foliage_Default",
|
||||
"variants": [
|
||||
@@ -1726,7 +1726,7 @@
|
||||
{
|
||||
"internalName": "leaves_big_oak_fast",
|
||||
"displayName": "Dark Oak Leaves (Opaque)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Foliage_Default",
|
||||
"variants": [
|
||||
@@ -1797,7 +1797,7 @@
|
||||
{
|
||||
"internalName": "leaves_birch",
|
||||
"displayName": "Birch Leaves",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Foliage_Birch",
|
||||
"variants": [
|
||||
@@ -1812,7 +1812,7 @@
|
||||
{
|
||||
"internalName": "leaves_birch_fast",
|
||||
"displayName": "Birch Leaves (Opaque)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Foliage_Birch",
|
||||
"variants": [
|
||||
@@ -2287,7 +2287,7 @@
|
||||
{
|
||||
"internalName": "shulker_top",
|
||||
"displayName": "Shulker Box (Break Particles)",
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Shulker_Box_Purple",
|
||||
"variants": [
|
||||
@@ -2318,7 +2318,7 @@
|
||||
"internalName": "cauldron_water",
|
||||
"displayName": "Cauldron Water",
|
||||
"allowCustomColour": true,
|
||||
"hasColourEntry": true,
|
||||
|
||||
"colourEntry": {
|
||||
"defaultName": "Cauldron_Water",
|
||||
"variants": [
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
19
PckStudio.Core/Serializer/AtlasSerializer.cs
Normal file
19
PckStudio.Core/Serializer/AtlasSerializer.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using OMI.Formats.Pck;
|
||||
using PckStudio.Core.Extensions;
|
||||
using PckStudio.Interfaces;
|
||||
|
||||
namespace PckStudio.Core.Serializer
|
||||
{
|
||||
internal sealed class AtlasSerializer : IPckAssetSerializer<Atlas>
|
||||
{
|
||||
public void Serialize(Atlas atlas, ref PckAsset asset)
|
||||
{
|
||||
asset.SetTexture(atlas);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user