Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add editing for place names #184

Merged
merged 3 commits into from
May 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be nice to add a bool ("preview") flag to this method -- if set, instead of painting the BG green it'll just be transparent. That way, this can be passed to render a preview without the green BG, while the method can be passed without the preview bool to get the real image.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kind of disagree here tbh, bc GetNewPlaceGraphic shouldn't be used for previews, imo. There's a separate GetPreview method that does that; GetNewPlaceGraphic should only be used for replacing the place graphic.

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..] };
jonko0493 marked this conversation as resolved.
Show resolved Hide resolved

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