Skip to content
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
4 changes: 2 additions & 2 deletions Yafc.Model/Data/DataClasses.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public abstract class FactorioObject : IFactorioObjectWrapper, IComparable<Facto
public string typeDotName => type + '.' + name;
public string locName { get; internal set; } = null!; // null-forgiving: Copied from name if still null at the end of CalculateMaps
public string? locDescr { get; internal set; }
public FactorioIconPart[]? iconSpec { get; internal set; }
internal FactorioIconPart[]? iconSpec { get; set; }
public Icon icon { get; internal set; }
public FactorioId id { get; internal set; }
internal abstract FactorioObjectSortOrder sortingOrder { get; }
Expand Down Expand Up @@ -76,7 +76,7 @@ public void FallbackLocalization(FactorioObject? other, LocalizableString1 descr

public class FactorioIconPart(string path) {
public string path = path;
public float size = 32;
public int size = 32;
public float x, y, r = 1, g = 1, b = 1, a = 1;
public float scale = 1;

Expand Down
38 changes: 22 additions & 16 deletions Yafc.Parser/Data/FactorioDataDeserializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ private static void AddTemperatureToFluidIcon(Fluid fluid) {
fluid.iconSpec =
[
.. fluid.iconSpec ?? [],
.. iconStr.Take(4).Select((x, n) => new FactorioIconPart("__.__/" + x) { y = -16, x = (n * 7) - 12, scale = 0.28f }),
.. iconStr.Take(4).Select((x, n) => new FactorioIconPart("__.__/" + x) { size = 64, y = -32, x = (n * 14) - 24, scale = 0.28f }),
];
}

Expand Down Expand Up @@ -244,8 +244,9 @@ private void RenderIcons() {
}

private unsafe Icon CreateIconFromSpec(Dictionary<(string mod, string path), IntPtr> cache, params FactorioIconPart[] spec) {
const int iconSize = IconCollection.IconSize;
nint targetSurface = SDL.SDL_CreateRGBSurfaceWithFormat(0, iconSize, iconSize, 0, SDL.SDL_PIXELFORMAT_RGBA8888);
const int cachedIconSize = IconCollection.IconSize;
int renderSize = MathUtils.Round(spec[0].size * spec[0].scale);
nint targetSurface = SDL.SDL_CreateRGBSurfaceWithFormat(0, renderSize, renderSize, 0, SDL.SDL_PIXELFORMAT_RGBA8888);
_ = SDL.SDL_SetSurfaceBlendMode(targetSurface, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);

foreach (var icon in spec) {
Expand All @@ -272,10 +273,6 @@ private unsafe Icon CreateIconFromSpec(Dictionary<(string mod, string path), Int
image = SDL.SDL_ConvertSurfaceFormat(old, SDL.SDL_PIXELFORMAT_RGBA8888, 0);
SDL.SDL_FreeSurface(old);
}

if (surface.h > iconSize * 2) {
image = SoftwareScaler.DownscaleIcon(image, iconSize);
}
}
cache[modPath] = image;
}
Expand All @@ -287,10 +284,10 @@ private unsafe Icon CreateIconFromSpec(Dictionary<(string mod, string path), Int
}

ref var sdlSurface = ref RenderingUtils.AsSdlSurface(image);
int targetSize = icon.scale == 1f ? iconSize : MathUtils.Ceil(icon.size * icon.scale) * (iconSize / 32); // TODO research formula
int targetSize = MathUtils.Round(icon.size * icon.scale);
_ = SDL.SDL_SetSurfaceColorMod(image, MathUtils.FloatToByte(icon.r), MathUtils.FloatToByte(icon.g), MathUtils.FloatToByte(icon.b));
//SDL.SDL_SetSurfaceAlphaMod(image, MathUtils.FloatToByte(icon.a));
int basePosition = (iconSize - targetSize) / 2;
int basePosition = (renderSize - targetSize) / 2;
SDL.SDL_Rect targetRect = new SDL.SDL_Rect {
x = basePosition,
y = basePosition,
Expand All @@ -300,14 +297,14 @@ private unsafe Icon CreateIconFromSpec(Dictionary<(string mod, string path), Int

if (icon.x != 0) {
// These two formulas have variously multiplied icon.x (or icon.y) by a scaling factor of iconSize / icon.size,
// iconSize * icon.scale, or iconSize. (const int iconSize = 32)
// iconSize * icon.scale, or iconSize (iconSize is now const int cachedIconSize = 32).
// Presumably the scaling factor had a purpose, but I can't find it. Py and Vanilla objects (e.g. Recipe.Moss-1 and
// Entity.lane-splitter) draw correctly after removing the scaling factor.
targetRect.x = MathUtils.Clamp(targetRect.x + MathUtils.Round(icon.x), 0, iconSize - targetRect.w);
targetRect.x = MathUtils.Clamp(targetRect.x + MathUtils.Round(icon.x), 0, renderSize - targetRect.w);
}

if (icon.y != 0) {
targetRect.y = MathUtils.Clamp(targetRect.y + MathUtils.Round(icon.y), 0, iconSize - targetRect.h);
targetRect.y = MathUtils.Clamp(targetRect.y + MathUtils.Round(icon.y), 0, renderSize - targetRect.h);
}

SDL.SDL_Rect srcRect = new SDL.SDL_Rect {
Expand All @@ -317,6 +314,9 @@ private unsafe Icon CreateIconFromSpec(Dictionary<(string mod, string path), Int
_ = SDL.SDL_BlitScaled(image, ref srcRect, targetSurface, ref targetRect);
}

if (RenderingUtils.AsSdlSurface(targetSurface).h > cachedIconSize * 2) {
targetSurface = SoftwareScaler.DownscaleIcon(targetSurface, cachedIconSize);
}
return IconCollection.AddIcon(targetSurface);
}

Expand Down Expand Up @@ -742,19 +742,25 @@ private void DeserializeLocation(LuaTable table, ErrorCollector collector) {
}

if (table.Get("icon", out string? s)) {
target.iconSpec = [new FactorioIconPart(s) { size = table.Get("icon_size", 64f) }];
target.iconSpec = [new FactorioIconPart(s) { size = table.Get("icon_size", 64) }];
}
else if (table.Get("icons", out LuaTable? iconList)) {
target.iconSpec = [.. iconList.ArrayElements<LuaTable>().Select(x => {
if (!x.Get("icon", out string? path)) {
throw new NotSupportedException($"One of the icon layers for {name} does not have a path.");
}

FactorioIconPart part = new(path) {
size = x.Get("icon_size", 64f),
scale = x.Get("scale", 1f)
int expectedSize = target switch {
// These are the only expected sizes for icons we render.
// New classes of icons (e.g. achievements) will need new cases to make IconParts with default scale render correctly.
// https://lua-api.factorio.com/latest/types/IconData.html
Technology => 256,
_ => 64
};

FactorioIconPart part = new(path) { size = x.Get("icon_size", 64) };
part.scale = x.Get("scale", expectedSize / 2f / part.size);

if (x.Get("shift", out LuaTable? shift)) {
part.x = shift.Get<float>(1);
part.y = shift.Get<float>(2);
Expand Down
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
Version:
Date:
Fixes:
- Fix rendering of multi-icon technologies (e.g. shooting speed techs)
- Add simplified support for debug.getinfo(), only returns short_src. Fixes #455, #504.
----------------------------------------------------------------------------------------------------------------------
Version: 2.15.0
Expand Down
Loading