Skip to content

Commit

Permalink
Add editing for place names (#184)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonko0493 authored May 14, 2023
1 parent a190a5a commit 13ede7b
Show file tree
Hide file tree
Showing 11 changed files with 191 additions and 35 deletions.
28 changes: 28 additions & 0 deletions src/SerialLoops.Lib/Defaults/DefaultNames.json
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,34 @@
"CHIBI_CPB": "CHB_COMP_CLUB_MEMB",
"CHIBI_CPC": "CHB_COMP_CLUB_MEMC",
"CHIBI_CPD": "CHB_COMP_CLUB_MEMD",
"SYS_CMN_T_K15": "PLC_Main Building Classroom",
"SYS_CMN_T_ROU": "PLC_Main Building Hallway",
"SYS_CMN_T_SHO": "PLC_Shoe Lockers",
"SYS_CMN_T_ROF": "PLC_Staff Room Hallway",
"SYS_CMN_T_WR1": "PLC_Central-Gym Walkway",
"SYS_CMN_T_WR2": "PLC_Main-Central Walkway",
"SYS_CMN_T_KAI": "PLC_Old Building Stairs",
"SYS_CMN_T_ROK": "PLC_Old Building Hallway",
"SYS_CMN_T_BUN": "PLC_Literary Clubroom",
"SYS_CMN_T_COM": "PLC_Computer Clubroom",
"SYS_CMN_T_ODO": "PLC_Main Building Landing",
"SYS_CMN_T_TAI": "PLC_Gymnasium",
"SYS_CMN_T_TOI": "PLC_Outside the Bathrooms",
"SYS_CMN_T_ONG": "PLC_Music Room",
"SYS_CMN_T_HKA": "PLC_Main Building Stairs",
"SYS_CMN_T_GEN": "PLC_Genkotsu Square",
"SYS_CMN_T_NAK": "PLC_Courtyard",
"SYS_CMN_T_OKU": "PLC_Main Building Rooftop",
"SYS_CMN_T_SEI": "PLC_Main Gate",
"SYS_CMN_T_GRO": "PLC_Sports Field",
"SYS_CMN_T_YAO": "PLC_Grocery Store",
"SYS_CMN_T_POO": "PLC_Swimming Pool",
"SYS_CMN_T_CVS": "PLC_Convenience Store",
"SYS_CMN_T_AKI": "PLC_Vacant Lot",
"SYS_CMN_T_ROL": "PLC_Library Hallway",
"SYS_CMN_T_TGR": "PLC_School Route",
"SYS_CMN_T_ARC": "PLC_Shopping Street",
"SYS_CMN_T_KH1": "PLC_Outside Kyon\u0027s House",
"AKID0": "MAP_FOREST_DAY",
"AKIN0": "MAP_FOREST_NIGHT",
"BUND0": "MAP_CLUBROOM_DAY",
Expand Down
101 changes: 94 additions & 7 deletions src/SerialLoops.Lib/Items/PlaceItem.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
using HaruhiChokuretsuLib.Archive.Event;
using HaruhiChokuretsuLib.Archive;
using HaruhiChokuretsuLib.Archive;
using HaruhiChokuretsuLib.Archive.Event;
using HaruhiChokuretsuLib.Archive.Graphics;
using HaruhiChokuretsuLib.Util;
using SkiaSharp;
using System.Collections.Generic;
using System.Linq;
using HaruhiChokuretsuLib.Archive.Data;
using HaruhiChokuretsuLib.Util;
using System.Numerics;
using Topten.RichTextKit;

namespace SerialLoops.Lib.Items
{
public class PlaceItem : Item, IPreviewableGraphic
{
public int Index { get; set; }
public GraphicsFile PlaceGraphic { get; set; }
public string PlaceName { get; set; }
public (string ScriptName, ScriptCommandInvocation command)[] ScriptUses { get; set; }

public PlaceItem(int index, GraphicsFile placeGrp, Project project) : base(placeGrp.Name[0..^3], ItemType.Place)
Expand All @@ -27,9 +30,8 @@ public override void Refresh(Project project, ILogger log)
PopulateScriptUses(project.Evt);
}

public SKBitmap GetPreview(Project project)
public static SKBitmap Unscramble(SKBitmap placeGraphic)
{
SKBitmap placeGraphic = PlaceGraphic.GetImage(transparentIndex: 0);
SKBitmap adjustedPlace = new(placeGraphic.Width, placeGraphic.Height);
SKCanvas canvas = new(adjustedPlace);

Expand All @@ -51,16 +53,101 @@ public SKBitmap GetPreview(Project project)
}

canvas.Flush();

return adjustedPlace;
}

public SKBitmap GetPreview(Project project)
{
return Unscramble(PlaceGraphic.GetImage(transparentIndex: 0));
}

public SKBitmap GetNewPlaceGraphic(SKTypeface msGothicHaruhi)
{
string spaceAdjustedText = PlaceName.Replace(" ", " ");
SKBitmap newPlaceBitmap = new(PlaceGraphic.Width, PlaceGraphic.Height);
SKCanvas canvas = new(newPlaceBitmap);
SKColor bgColor = new SKColor(0, 249, 0);
canvas.DrawRegion(new(new SKRectI(0, 0, newPlaceBitmap.Width, newPlaceBitmap.Height)), new SKPaint { Color = bgColor });
TextBlock placeText = new()
{
Alignment = TextAlignment.Left,
FontMapper = new CustomFontMapper(),
MaxWidth = newPlaceBitmap.Width - 2,
MaxHeight = newPlaceBitmap.Height - 12,
};
placeText.AddText(spaceAdjustedText, new Style()
{
TextColor = SKColors.Black,
FontFamily = msGothicHaruhi.FamilyName,
FontSize = 15.0f,
LetterSpacing = -1,
HaloColor = new SKColor(160, 160, 160),
HaloBlur = 0,
HaloWidth = 4,
});
TextBlock placeTextShadow = new()
{
Alignment = TextAlignment.Left,
FontMapper = new CustomFontMapper(),
MaxWidth = newPlaceBitmap.Width - 2,
MaxHeight = newPlaceBitmap.Height - 12,
};
placeTextShadow.AddText(spaceAdjustedText, new Style()
{
TextColor = SKColors.Black,
FontFamily = msGothicHaruhi.FamilyName,
FontSize = 15.0f,
LetterSpacing = -1,
HaloColor = new SKColor(88, 88, 88),
HaloBlur = 0,
HaloWidth = 4,
});
placeTextShadow.Paint(canvas, new SKPoint(2, 7), new() { Edging = SKFontEdging.Alias });
placeText.Paint(canvas, new SKPoint(1, 6), new() { Edging = SKFontEdging.SubpixelAntialias });
canvas.Flush();

// Antialiasing creates some semitransparent pixels on top of our green background, which causes them to render as green
// rather than as transparent. To prevent this, we forcibly set them back to the transparent color
for (int y = 0; y < newPlaceBitmap.Height; y++)
{
for (int x = 0; x < newPlaceBitmap.Width; x++)
{
if (Helpers.ColorDistance(newPlaceBitmap.GetPixel(x, y), bgColor) < 350)
{
newPlaceBitmap.SetPixel(x, y, bgColor);
}
}
}

return newPlaceBitmap;
}

public void PopulateScriptUses(ArchiveFile<EventFile> evt)
{
ScriptUses = evt.Files.SelectMany(e =>
e.ScriptSections.SelectMany(sec =>
sec.Objects.Where(c => c.Command.Mnemonic == "SET_PLACE").Select(c => (e.Name[0..^1], c))))
.Where(t => t.c.Parameters[1] == Index).ToArray();
}

public class CustomFontMapper : FontMapper
{
private static Dictionary<string, SKTypeface> _fonts = new();

public static void AddFont(SKTypeface typeface)
{
_fonts.Add(typeface.FamilyName, typeface);
}

public static bool HasFont()
{
return _fonts.Count > 0;
}

public override SKTypeface TypefaceFromStyle(IStyle style, bool ignoreFontVariants)
{
return _fonts[style.FontFamily];
}
}
}
}
2 changes: 1 addition & 1 deletion src/SerialLoops.Lib/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ public LoadProjectResult LoadArchives(ILogger log, IProgressTracker tracker)

for (int i = 0; i < Items.Count; i++)
{
if (Items[i].CanRename)
if (Items[i].CanRename || Items[i].Type == ItemDescription.ItemType.Place) // We don't want to manually rename places, but they do use the display name pattern
{
try
{
Expand Down
5 changes: 4 additions & 1 deletion src/SerialLoops.Lib/SerialLoops.Lib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@

<ItemGroup>
<PackageReference Include="BunLabs.NAudio.Flac" Version="2.0.1" />
<PackageReference Include="HaruhiChokuretsuLib" Version="0.27.2" />
<PackageReference Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.8.2.3" />
<PackageReference Include="HarfBuzzSharp.NativeAssets.macOS" Version="2.8.2.3" />
<PackageReference Include="HaruhiChokuretsuLib" Version="0.27.5" />
<PackageReference Include="NAudio.Vorbis" Version="1.5.0" />
<PackageReference Include="NitroPacker.Core" Version="2.1.0" />
<PackageReference Include="NLayer" Version="1.14.0" />
<PackageReference Include="NLayer.NAudioSupport" Version="1.3.0" />
<PackageReference Include="QuikGraph" Version="2.5.0" />
<PackageReference Include="Topten.RichTextKit" Version="0.4.165" />
<PackageReference Include="VCDiff" Version="4.0.1" />
</ItemGroup>

Expand Down
8 changes: 4 additions & 4 deletions src/SerialLoops/Dialogs/GraphicSelectionDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@ private void InitializeComponent()
_filter.TextChanged += (sender, args) =>
{
_selector.DataStore = new ObservableCollection<IPreviewableGraphic>(_items
.Where(i => ((ItemDescription)i).Name.Contains(_filter.Text, StringComparison.OrdinalIgnoreCase)));
.Where(i => ((ItemDescription)i).DisplayName.Contains(_filter.Text, StringComparison.OrdinalIgnoreCase)));
};

_selector = new ListBox
{
Size = new Size(150, 390),
DataStore = _items,
SelectedIndex = _items.IndexOf(_currentSelection),
ItemTextBinding = Binding.Delegate<IPreviewableGraphic, string>(i => ((ItemDescription)i).Name),
ItemTextBinding = Binding.Delegate<IPreviewableGraphic, string>(i => ((ItemDescription)i).DisplayName),
ItemKeyBinding = Binding.Delegate<IPreviewableGraphic, string>(i => ((ItemDescription)i).Name),
};

Expand Down Expand Up @@ -126,7 +126,7 @@ private StackLayout GeneratePreview()
Label backgroundTypeLabel = new();
if (_selector.SelectedValue is not null)
{
if (((ItemDescription)_selector.SelectedValue).Type == ItemDescription.ItemType.Background && ((ItemDescription)_selector.SelectedValue).Name != "NONE")
if (((ItemDescription)_selector.SelectedValue).Type == ItemDescription.ItemType.Background && ((ItemDescription)_selector.SelectedValue).DisplayName != "NONE")
{
backgroundTypeLabel.Text = ((BackgroundItem)_selector.SelectedValue).BackgroundType.ToString();
}
Expand All @@ -139,7 +139,7 @@ private StackLayout GeneratePreview()
Spacing = 10,
Items =
{
new Label { Text = _selector.SelectedValue == null ? "No preview available" : ((ItemDescription)_selector.SelectedValue).Name },
new Label { Text = _selector.SelectedValue == null ? "No preview available" : ((ItemDescription)_selector.SelectedValue).DisplayName },
new SKGuiImage(_selector.SelectedValue == null ? new SKBitmap(64, 64) :
((IPreviewableGraphic) _selector.SelectedValue).GetPreview(_project, 250, 350)),
backgroundTypeLabel,
Expand Down
19 changes: 0 additions & 19 deletions src/SerialLoops/Editors/CharacterEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,24 +156,5 @@ private void UpdatePreview(StackLayout nameplatePreviewLayout, SKBitmap blankNam
nameplatePreviewLayout.Items.Clear();
nameplatePreviewLayout.Items.Add(new SKGuiImage(_character.GetNewNameplate(blankNameplate, blankNameplateBaseArrow, _project)));
}
private class CustomFontMapper : FontMapper
{
private static readonly Dictionary<string, SKTypeface> _fonts = new();

public static void AddFont(SKTypeface typeface)
{
_fonts.Add(typeface.FamilyName, typeface);
}

public static bool HasFont()
{
return _fonts.Count > 0;
}

public override SKTypeface TypefaceFromStyle(IStyle style, bool ignoreFontVariants)
{
return _fonts[style.FontFamily];
}
}
}
}
40 changes: 39 additions & 1 deletion src/SerialLoops/Editors/PlaceEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
using SerialLoops.Lib;
using SerialLoops.Lib.Items;
using SerialLoops.Utility;
using SkiaSharp;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Topten.RichTextKit;

namespace SerialLoops.Editors
{
Expand All @@ -17,13 +22,46 @@ public PlaceEditor(PlaceItem placeItem, Project project, ILogger log) : base(pla
public override Container GetEditorPanel()
{
_place = (PlaceItem)Description;
if (string.IsNullOrEmpty(_place.PlaceName))
{
_place.PlaceName = _place.DisplayName[4..];
}

TextBox placeTextBox = new() { Text = _place.DisplayName[4..] };

StackLayout previewPanel = new()
{
Items =
{
new SKGuiImage(_place.GetPreview(_project)),
},
};

using Stream typefaceStream = Assembly.GetCallingAssembly().GetManifestResourceStream("SerialLoops.Graphics.MS-Gothic-Haruhi.ttf");
SKTypeface msGothicHaruhi = SKTypeface.FromStream(typefaceStream);
if (!PlaceItem.CustomFontMapper.HasFont())
{
PlaceItem.CustomFontMapper.AddFont(msGothicHaruhi);
}

placeTextBox.TextChanged += (sender, args) =>
{
_place.PlaceName = placeTextBox.Text;

previewPanel.Items.Clear();
previewPanel.Items.Add(new SKGuiImage(_place.GetNewPlaceGraphic(msGothicHaruhi)));

UpdateTabTitle(false);
};

return new StackLayout
{
Orientation = Orientation.Vertical,
Spacing = 5,
Items =
{
new SKGuiImage(_place.GetPreview(_project)),
ControlGenerator.GetControlWithLabel("Place Name", placeTextBox),
previewPanel,
}
};
}
Expand Down
1 change: 1 addition & 0 deletions src/SerialLoops/Editors/ScriptEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1800,6 +1800,7 @@ private void UpdatePreview()
else if (command.Verb == CommandVerb.INVEST_START)
{
sprites.Clear();
previousSprites.Clear();
}
previousCommand = command;
}
Expand Down
Binary file added src/SerialLoops/Graphics/MS-Gothic-Haruhi.ttf
Binary file not shown.
17 changes: 16 additions & 1 deletion src/SerialLoops/MainForm.eto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public partial class MainForm : Form
private SubMenuItem _recentProjectsCommand;

private SKBitmap _blankNameplate, _blankNameplateBaseArrow;
private SKTypeface _msGothicHaruhi;

public string ShutdownUpdateUrl = null;

Expand All @@ -55,6 +56,8 @@ private void OpenProjectView(Project project, IProgressTracker tracker)
_blankNameplate = SKBitmap.Decode(blankNameplateStream);
using Stream blankNameplateBaseArrowStream = Assembly.GetCallingAssembly().GetManifestResourceStream("SerialLoops.Graphics.BlankNameplateBaseArrow.png");
_blankNameplateBaseArrow = SKBitmap.Decode(blankNameplateBaseArrowStream);
using Stream typefaceStream = Assembly.GetCallingAssembly().GetManifestResourceStream("SerialLoops.Graphics.MS-Gothic-Haruhi.ttf");
_msGothicHaruhi = SKTypeface.FromStream(typefaceStream);

EditorTabs = new(project, this, Log);
ItemExplorer = new(project, EditorTabs, Log);
Expand Down Expand Up @@ -415,7 +418,7 @@ private void SaveProject_Executed(object sender, EventArgs e)
break;
case ItemDescription.ItemType.Character:
CharacterItem characterItem = (CharacterItem)item;
if (characterItem.NameplateProperties.Name != item.Name[4..])
if (characterItem.NameplateProperties.Name != item.DisplayName[4..])
{
Shared.RenameItem(OpenProject, ItemExplorer, EditorTabs, Log, $"CHR_{characterItem.NameplateProperties.Name}");
}
Expand All @@ -430,6 +433,18 @@ private void SaveProject_Executed(object sender, EventArgs e)
savedExtra = true;
}
break;
case ItemDescription.ItemType.Place:
PlaceItem placeItem = (PlaceItem)item;
if (placeItem.PlaceName != item.DisplayName[4..])
{
Shared.RenameItem(OpenProject, ItemExplorer, EditorTabs, Log, $"PLC_{placeItem.PlaceName}");
}
MemoryStream placeStream = new();
SKBitmap newPlaceImage = PlaceItem.Unscramble(PlaceItem.Unscramble(placeItem.GetNewPlaceGraphic(_msGothicHaruhi)));
placeItem.PlaceGraphic.SetImage(newPlaceImage);
newPlaceImage.Encode(placeStream, SKEncodedImageFormat.Png, 1);
IO.WriteBinaryFile(Path.Combine("assets", "graphics", $"{placeItem.PlaceGraphic.Index:X3}.png"), placeStream.ToArray(), OpenProject, Log);
break;
case ItemDescription.ItemType.Scenario:
ScenarioStruct scenario = ((ScenarioItem)item).Scenario;
IO.WriteStringFile(Path.Combine("assets", "events", $"{OpenProject.Evt.Files.First(f => f.Name == "SCENARIOS").Index:X3}.s"),
Expand Down
5 changes: 4 additions & 1 deletion src/SerialLoops/SerialLoops.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
</PropertyGroup>

<ItemGroup>
<None Remove="Graphics\MS-Gothic-Haruhi.ttf" />
<None Remove="Graphics\BlankNameplate.png" />
<None Remove="Graphics\BlankNameplateBaseArrow.png" />
<None Remove="Graphics\msgothic-variablewidth.ttf" />
Expand Down Expand Up @@ -68,6 +69,9 @@
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="Graphics\MS-Gothic-Haruhi.ttf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="Graphics\BlankNameplate.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
Expand All @@ -82,7 +86,6 @@
<ItemGroup>
<PackageReference Include="Eto.Forms" Version="2.7.5" />
<PackageReference Include="System.Text.Json" Version="7.0.2" />
<PackageReference Include="Topten.RichTextKit" Version="0.4.165" />
</ItemGroup>

<ItemGroup>
Expand Down

0 comments on commit 13ede7b

Please sign in to comment.