Skip to content

Commit

Permalink
Extended ResourceLocation for better atlas handling
Browse files Browse the repository at this point in the history
  • Loading branch information
NessieHax committed Jun 30, 2024
1 parent 94e5fbf commit b057cb3
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 113 deletions.
40 changes: 21 additions & 19 deletions PCK-Studio/Forms/Editor/TextureAtlasEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
using OMI.Workers.Color;

using PckStudio.Extensions;
using PckStudio.Internal;
using PckStudio.Internal.Deserializer;
using PckStudio.Internal.Json;
using PckStudio.Internal.Serializer;
Expand All @@ -54,7 +55,7 @@ public Image FinalTexture
private readonly Size _areaSize;
private readonly int _rowCount;
private readonly int _columnCount;
private readonly string _atlasType;
private readonly ResourceLocation _atlasType;
private readonly List<AtlasTile> _tiles;

private AtlasTile _selectedTile;
Expand Down Expand Up @@ -93,31 +94,32 @@ private int SelectedIndex

private const ImageLayoutDirection _imageLayout = ImageLayoutDirection.Horizontal;

public TextureAtlasEditor(PckFile pckFile, string path, Image atlas, Size areaSize)
public TextureAtlasEditor(PckFile pckFile, ResourceLocation resourceLocation, Image atlas)
{
InitializeComponent();

AcquireColorTable(pckFile);

_workingTexture = atlas;

_areaSize = areaSize;
_areaSize = resourceLocation.GetTileArea(atlas.Size);
_pckFile = pckFile;
_rowCount = atlas.Width / areaSize.Width;
_columnCount = atlas.Height / areaSize.Height;
(var tileInfos, _atlasType) = Path.GetFileNameWithoutExtension(path) switch
_rowCount = atlas.Width / _areaSize.Width;
_columnCount = atlas.Height / _areaSize.Height;
_atlasType = resourceLocation;
var tileInfos = resourceLocation.Category switch
{
"terrain" => (Tiles.BlockTileInfos, "blocks"),
"items" => (Tiles.ItemTileInfos, "items"),
"particles" => (Tiles.ParticleTileInfos, "particles"),
"mapicons" => (Tiles.MapIconTileInfos, "map_icons"),
"additionalmapicons" => (Tiles.AdditionalMapIconTileInfos, "additional_map_icons"),
"moon_phases" => (Tiles.MoonPhaseTileInfos, "moon_phases"),
"xporb" => (Tiles.ExperienceOrbTileInfos, "experience_orbs"),
"explosion" => (Tiles.ExplosionTileInfos, "explosions"),
"kz" => (Tiles.PaintingTileInfos, "paintings"),
"Banner_Atlas" => (Tiles.BannerTileInfos, "banners"),
_ => (null, null),
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,
};

originalPictureBox.Image = atlas.GetArea(new Rectangle(0, 0, atlas.Width, atlas.Height));
Expand Down Expand Up @@ -156,7 +158,7 @@ public TextureAtlasEditor(PckFile pckFile, string path, Image atlas, Size areaSi

SelectedIndex = 0;

bool isParticles = _atlasType == "particles";
bool isParticles = _atlasType.Category == ResourceCategory.ParticleAtlas;

// this is directly based on Java's source code for handling enchanted hits
// the particle is assigned a random grayscale color between roughly 154 and 230
Expand Down Expand Up @@ -239,7 +241,7 @@ private void SetImageDisplayed(int index)
selectTilePictureBox.BlendColor = GetBlendColor();
selectTilePictureBox.UseBlendColor = applyColorMaskToolStripMenuItem.Checked;

if (animationButton.Enabled = _atlasType == "blocks" || _atlasType == "items")
if (animationButton.Enabled = _atlasType.Category == ResourceCategory.BlockAtlas || _atlasType.Category == ResourceCategory.ItemAtlas)
{
PckAsset animationAsset;

Expand Down
12 changes: 11 additions & 1 deletion PCK-Studio/Internal/ResourceCategory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ internal enum ResourceCategory
{
Unknown = -1,
ItemAnimation,
BlockAnimation
BlockAnimation,
ItemAtlas,
BlockAtlas,
ParticleAtlas,
BannerAtlas,
PaintingAtlas,
ExplosionAtlas,
ExperienceOrbAtlas,
MoonPhaseAtlas,
MapIconAtlas,
AdditionalMapIconsAtlas,
}
}
93 changes: 89 additions & 4 deletions PCK-Studio/Internal/ResourceLocation.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,46 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PckStudio.Internal
{
internal class ResourceLocation
internal sealed class ResourceLocation
{
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),
["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.Custom),
["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),
};

public static string GetPathFromCategory(ResourceCategory category)
{
return category switch
{
ResourceCategory.ItemAnimation => "res/textures/items",
ResourceCategory.BlockAnimation => "res/textures/blocks",
ResourceCategory.ItemAnimation => "res/textures/items",
ResourceCategory.BlockAnimation => "res/textures/blocks",
ResourceCategory.BlockAtlas => "res/terrain.png",
ResourceCategory.ItemAtlas => "res/items.png",
ResourceCategory.ParticleAtlas => "res/particles.png",
ResourceCategory.BannerAtlas => "res/item/banner/Banner_Atlas.png",
ResourceCategory.PaintingAtlas => "res/art/kz.png",
ResourceCategory.ExplosionAtlas => "res/misc/explosion.png",
ResourceCategory.ExperienceOrbAtlas => "res/item/xporb.png",
ResourceCategory.MoonPhaseAtlas => "res/terrain/moon_phases.png",
ResourceCategory.MapIconAtlas => "res/misc/mapicons.png",
ResourceCategory.AdditionalMapIconsAtlas => "res/misc/additionalmapicons.png",
_ => string.Empty
};
}
Expand All @@ -29,7 +56,65 @@ public static ResourceCategory GetCategoryFromPath(string path)
if (path.StartsWith("res/textures/blocks"))
return ResourceCategory.BlockAnimation;

return ResourceCategory.Unknown;
string categoryPath = path.Substring("res/".Length);
return _categoryLookUp.ContainsKey(categoryPath) ? _categoryLookUp[categoryPath].Category : ResourceCategory.Unknown;
}

public static ResourceLocation GetFromPath(string path)
{
if (string.IsNullOrWhiteSpace(path) || !path.StartsWith("res/"))
return null;
string categoryPath = path.Substring("res/".Length);
if (categoryPath.StartsWith("textures/items"))
categoryPath = "textures/items";
if (categoryPath.StartsWith("textures/blocks"))
categoryPath = "textures/blocks";
return _categoryLookUp.ContainsKey(categoryPath) ? _categoryLookUp[categoryPath] : null;
}

public enum TillingMode
{
Width,
Height,
Custom
}

public readonly string Path;
public readonly ResourceCategory Category;
public readonly Size TillingFactor;
public readonly TillingMode TillingResolution;
public readonly bool IsGroup;

public Size GetTileArea(Size imgSize)
{
int tileFactorWidth = Math.Max(1, TillingFactor.Width);
int tileFactorHeight = Math.Max(1, TillingFactor.Height);
return TillingResolution switch
{
TillingMode.Width => new Size(imgSize.Width / tileFactorWidth, imgSize.Width / tileFactorHeight),
TillingMode.Height => new Size(imgSize.Height / tileFactorWidth, imgSize.Height / tileFactorHeight),
TillingMode.Custom => new Size(imgSize.Width / tileFactorWidth, imgSize.Height / tileFactorHeight),
_ => Size.Empty,
};
}

private ResourceLocation(string path, ResourceCategory category, int tillingFactor, TillingMode tillingResolution = TillingMode.Width, bool isGroup = false)
: this(path, category, new Size(tillingFactor, tillingFactor), tillingResolution, isGroup)
{
}

private ResourceLocation(string path, ResourceCategory category, Size tillingFactor, TillingMode tillingResolution = TillingMode.Width, bool isGroup = false)
{
Path = path;
Category = category;
TillingFactor = tillingFactor;
TillingResolution = tillingResolution;
IsGroup = isGroup;
}

public override string ToString()
{
return "res/" + Path;
}
}
}
116 changes: 27 additions & 89 deletions PCK-Studio/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -457,96 +457,44 @@ private void HandleTextureFile(PckAsset asset)
return;
}

bool isTerrain = asset.Filename == "res/terrain.png";
bool isItems = asset.Filename == "res/items.png";
bool isParticles = asset.Filename == "res/particles.png";
bool isMoonPhases = asset.Filename == "res/terrain/moon_phases.png";
bool isMapIcons = asset.Filename == "res/misc/mapicons.png";
bool isAdditionalMapIcons = asset.Filename == "res/misc/additionalmapicons.png";
bool isXPOrbs = asset.Filename == "res/item/xporb.png";
bool isExplosions = asset.Filename == "res/misc/explosion.png";
bool isPaintings = asset.Filename == "res/art/kz.png";
bool isBanners = asset.Filename == "res/item/banner/Banner_Atlas.png";

if (
isTerrain || isItems || isParticles || isMoonPhases || isPaintings ||
isMapIcons || isAdditionalMapIcons || isXPOrbs || isExplosions || isBanners
)
ResourceLocation resourceLocation = ResourceLocation.GetFromPath(asset.Filename);
Debug.WriteLine("Handling Resource file: " + resourceLocation.ToString());
if (resourceLocation is null || resourceLocation.Category == ResourceCategory.Unknown)
return;

if (resourceLocation.Category != ResourceCategory.BlockAnimation &&
resourceLocation.Category != ResourceCategory.ItemAnimation)
{
Image img = asset.GetTexture();
var tile_size = new Size();

int banner_scale = img.Width / Resources.banners_atlas.Width;

if (isBanners)
{
// The banner atlas has extra space on it that has to be truncated for the editor
img = img.GetArea(new Rectangle(0, 0, img.Width - (4 * banner_scale), img.Height - (1 * banner_scale)));

// banners are 42x41 because of course they are
tile_size = new Size(42 * banner_scale, 41 * banner_scale);
}

// most atlases have 4 columns
int columnCount = isBanners ? 6 : 4;

if (isTerrain || isItems || isParticles || isPaintings) columnCount = 16;

if (!isBanners)
{
int resolution = img.Width / columnCount;
tile_size = new Size(resolution, resolution);
}

var viewer = new TextureAtlasEditor(currentPCK, asset.Filename, img, tile_size);
var viewer = new TextureAtlasEditor(currentPCK, resourceLocation, img);
if (viewer.ShowDialog(this) == DialogResult.OK)
{
Image texture = viewer.FinalTexture;
if(isBanners)
{
var graphicsConfig = new GraphicsConfig()
{
InterpolationMode = InterpolationMode.NearestNeighbor,
PixelOffsetMode = PixelOffsetMode.HighQuality
};

var _img = new Bitmap((Resources.banners_atlas.Width + 4) * banner_scale,
(Resources.banners_atlas.Height + 1) * banner_scale);

using (Graphics g = Graphics.FromImage(_img))
{
g.ApplyConfig(graphicsConfig);
g.DrawImage(texture, 0, 0, texture.Width, texture.Height);
}

texture = _img;
}

asset.SetTexture(texture);
wasModified = true;
BuildMainTreeView();
}
return;
}

if (!asset.Filename.StartsWith(ResourceLocation.GetPathFromCategory(ResourceCategory.ItemAnimation)) &&
!asset.Filename.StartsWith(ResourceLocation.GetPathFromCategory(ResourceCategory.BlockAnimation)))
if (resourceLocation.Category != ResourceCategory.ItemAnimation &&
resourceLocation.Category != ResourceCategory.BlockAnimation)
return;

Animation animation = asset.GetDeserializedData(AnimationDeserializer.DefaultDeserializer);
string filename = Path.GetFileNameWithoutExtension(asset.Filename);
string internalName = Path.GetFileNameWithoutExtension(asset.Filename);

var textureInfos = ResourceLocation.GetCategoryFromPath(asset.Filename) switch
var textureInfos = resourceLocation.Category switch
{
ResourceCategory.BlockAnimation => Tiles.BlockTileInfos,
ResourceCategory.ItemAnimation => Tiles.ItemTileInfos,
_ => Array.Empty<JsonTileInfo>().ToList()
};
string displayname = textureInfos.FirstOrDefault(p => p.InternalName == filename)?.DisplayName ?? filename;
string displayname = textureInfos.FirstOrDefault(p => p.InternalName == internalName)?.DisplayName ?? internalName;

string[] specialTileNames = { "clock", "compass" };

using (AnimationEditor animationEditor = new AnimationEditor(animation, displayname, filename.ToLower().EqualsAny(specialTileNames)))
using (AnimationEditor animationEditor = new AnimationEditor(animation, displayname, internalName.ToLower().EqualsAny(specialTileNames)))
{
if (animationEditor.ShowDialog(this) == DialogResult.OK)
{
Expand Down Expand Up @@ -708,34 +656,24 @@ private void treeViewMain_AfterSelect(object sender, TreeViewEventArgs e)
Debug.WriteLine(string.Format("An error occured of type: {0} with message: {1}", ex.GetType(), ex.Message), "Exception");
}

if ((asset.Filename.StartsWith(ResourceLocation.GetPathFromCategory(ResourceCategory.ItemAnimation)) ||
asset.Filename.StartsWith(ResourceLocation.GetPathFromCategory(ResourceCategory.BlockAnimation))) &&
asset.Type == PckAssetType.TextureFile
&& !asset.IsMipmappedFile())
if (asset.Type != PckAssetType.TextureFile)
break;

ResourceLocation resourceLocation = ResourceLocation.GetFromPath(asset.Filename);
if (resourceLocation is null || resourceLocation.Category == ResourceCategory.Unknown)
break;

if (resourceLocation.Category == ResourceCategory.ItemAnimation ||
resourceLocation.Category == ResourceCategory.BlockAnimation &&
!asset.IsMipmappedFile())
{
buttonEdit.Text = "EDIT TILE ANIMATION";
buttonEdit.Visible = true;
break;
}

bool isTerrain = asset.Filename == "res/terrain.png";
bool isItems = asset.Filename == "res/items.png";
bool isParticles = asset.Filename == "res/particles.png";
bool isMoonPhases = asset.Filename == "res/terrain/moon_phases.png";
bool isMapIcons = asset.Filename == "res/misc/mapicons.png";
bool isAdditionalMapIcons = asset.Filename == "res/misc/additionalmapicons.png";
bool isXPOrbs = asset.Filename == "res/item/xporb.png";
bool isExplosions = asset.Filename == "res/misc/explosion.png";
bool isPaintings = asset.Filename == "res/art/kz.png";
bool isBanners = asset.Filename == "res/item/banner/Banner_Atlas.png";

if ((
isTerrain || isItems || isParticles || isMoonPhases || isPaintings ||
isMapIcons || isAdditionalMapIcons || isXPOrbs || isExplosions || isBanners
) && asset.Type == PckAssetType.TextureFile)
{
buttonEdit.Text = "EDIT TEXTURE ATLAS";
buttonEdit.Visible = true;
}
buttonEdit.Text = "EDIT TEXTURE ATLAS";
buttonEdit.Visible = true;
}
break;

Expand Down

0 comments on commit b057cb3

Please sign in to comment.