Skip to content

Commit 73df2cf

Browse files
committed
fix: Fix multi-layer icon rendering again, this time for techs.
1 parent 688db7d commit 73df2cf

File tree

3 files changed

+26
-18
lines changed

3 files changed

+26
-18
lines changed

Yafc.Model/Data/DataClasses.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public abstract class FactorioObject : IFactorioObjectWrapper, IComparable<Facto
3737
public string typeDotName => type + '.' + name;
3838
public string locName { get; internal set; } = null!; // null-forgiving: Copied from name if still null at the end of CalculateMaps
3939
public string? locDescr { get; internal set; }
40-
public FactorioIconPart[]? iconSpec { get; internal set; }
40+
internal FactorioIconPart[]? iconSpec { get; set; }
4141
public Icon icon { get; internal set; }
4242
public FactorioId id { get; internal set; }
4343
internal abstract FactorioObjectSortOrder sortingOrder { get; }
@@ -76,7 +76,7 @@ public void FallbackLocalization(FactorioObject? other, LocalizableString1 descr
7676

7777
public class FactorioIconPart(string path) {
7878
public string path = path;
79-
public float size = 32;
79+
public int size = 32;
8080
public float x, y, r = 1, g = 1, b = 1, a = 1;
8181
public float scale = 1;
8282

Yafc.Parser/Data/FactorioDataDeserializer.cs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ private static void AddTemperatureToFluidIcon(Fluid fluid) {
9090
fluid.iconSpec =
9191
[
9292
.. fluid.iconSpec ?? [],
93-
.. iconStr.Take(4).Select((x, n) => new FactorioIconPart("__.__/" + x) { y = -16, x = (n * 7) - 12, scale = 0.28f }),
93+
.. iconStr.Take(4).Select((x, n) => new FactorioIconPart("__.__/" + x) { size = 64, y = -32, x = (n * 14) - 24, scale = 0.28f }),
9494
];
9595
}
9696

@@ -244,8 +244,9 @@ private void RenderIcons() {
244244
}
245245

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

251252
foreach (var icon in spec) {
@@ -272,10 +273,6 @@ private unsafe Icon CreateIconFromSpec(Dictionary<(string mod, string path), Int
272273
image = SDL.SDL_ConvertSurfaceFormat(old, SDL.SDL_PIXELFORMAT_RGBA8888, 0);
273274
SDL.SDL_FreeSurface(old);
274275
}
275-
276-
if (surface.h > iconSize * 2) {
277-
image = SoftwareScaler.DownscaleIcon(image, iconSize);
278-
}
279276
}
280277
cache[modPath] = image;
281278
}
@@ -287,10 +284,10 @@ private unsafe Icon CreateIconFromSpec(Dictionary<(string mod, string path), Int
287284
}
288285

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

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

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

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

317+
if (RenderingUtils.AsSdlSurface(targetSurface).h > cachedIconSize * 2) {
318+
targetSurface = SoftwareScaler.DownscaleIcon(targetSurface, cachedIconSize);
319+
}
320320
return IconCollection.AddIcon(targetSurface);
321321
}
322322

@@ -742,19 +742,25 @@ private void DeserializeLocation(LuaTable table, ErrorCollector collector) {
742742
}
743743

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

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

761+
FactorioIconPart part = new(path) { size = x.Get("icon_size", 64) };
762+
part.scale = x.Get("scale", expectedSize / 2f / part.size);
763+
758764
if (x.Get("shift", out LuaTable? shift)) {
759765
part.x = shift.Get<float>(1);
760766
part.y = shift.Get<float>(2);

changelog.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ Version:
2323
Date:
2424
Fixes:
2525
- Add simplified support for debug.getinfo(), only returns short_src. Fixes #455, #504.
26+
Fixes:
27+
- Fix rendering of multi-icon technologies (e.g. shooting speed techs)
2628
----------------------------------------------------------------------------------------------------------------------
2729
Version: 2.15.0
2830
Date: September 1st 2025

0 commit comments

Comments
 (0)