#include "UI/NeuIcons.h" namespace Neu { FLinearColor OreColor(FName OreId) { if (OreId == TEXT("cobalt")) { return Hex(0x3fe6ff); } if (OreId == TEXT("pearl")) { return Hex(0xff5ad8); } return Hex(0xff9a3c); // ferrite, and anything unknown } FString OreSymbol(FName OreId) { if (OreId == TEXT("cobalt")) { return TEXT("Co"); } if (OreId == TEXT("pearl")) { return TEXT("Pe"); } return TEXT("Fe"); } FNeuIconStyle IconStyleFor(FName ItemId) { struct FRow { const TCHAR* Id; ENeuIconShape Shape; uint32 Rgb; const TCHAR* Glyph; }; static const FRow Rows[] = { { TEXT("ferrite"), ENeuIconShape::Ore, 0xff9a3c, TEXT("Fe") }, { TEXT("cobalt"), ENeuIconShape::Ore, 0x3fe6ff, TEXT("Co") }, { TEXT("pearl"), ENeuIconShape::Ore, 0xff5ad8, TEXT("Pe") }, { TEXT("ingot"), ENeuIconShape::Refined, 0xff9a3c, TEXT("Ig") }, { TEXT("wafer"), ENeuIconShape::Refined, 0x3fe6ff, TEXT("Wf") }, { TEXT("lattice"), ENeuIconShape::Refined, 0xff5ad8, TEXT("Lt") }, { TEXT("flashlight"), ENeuIconShape::Tool, 0xf5e6a8, TEXT("FL") }, { TEXT("scanner"), ENeuIconShape::Tool, 0x62d9e6, TEXT("SC") }, { TEXT("propulsor"), ENeuIconShape::Tool, 0xa58cff, TEXT("PR") }, { TEXT("flare"), ENeuIconShape::Use, 0xff6b57, TEXT("FR") }, { TEXT("beacon"), ENeuIconShape::Use, 0xf5b95a, TEXT("BC") }, { TEXT("tank1"), ENeuIconShape::Tank, 0x62d9e6, TEXT("O2") }, { TEXT("tank2"), ENeuIconShape::Tank, 0x72e3a5, TEXT("O2") }, { TEXT("silverfin"), ENeuIconShape::Bio, 0xbfd7e0, TEXT("Sf") }, { TEXT("lanternfish"), ENeuIconShape::Bio, 0x72e3a5, TEXT("Lf") }, { TEXT("jelly"), ENeuIconShape::Bio, 0xa58cff, TEXT("Jl") }, { TEXT("polyp"), ENeuIconShape::Bio, 0xf5b95a, TEXT("Pl") }, { TEXT("weapon"), ENeuIconShape::Weapon, 0x7f95a3, TEXT("WP") }, { TEXT("orebox"), ENeuIconShape::Box, 0xff9a3c, TEXT("OB") }, }; const FString Id = ItemId.ToString(); for (const FRow& Row : Rows) { if (Id == Row.Id) { return { Row.Shape, Hex(Row.Rgb), Row.Glyph }; } } if (Id.StartsWith(TEXT("kit_"))) { const FString Rest = Id.RightChop(4); FString Glyph = Rest.Left(2); if (Glyph.Len() > 0) { Glyph = Glyph.Left(1).ToUpper() + Glyph.RightChop(1).ToLower(); } return { ENeuIconShape::Kit, Hex(0x72e3a5), Glyph }; } FString Glyph = Id.Left(2); if (Glyph.Len() > 0) { Glyph = Glyph.Left(1).ToUpper() + Glyph.RightChop(1).ToLower(); } return { ENeuIconShape::Generic, Hex(0x7f95a3), Glyph }; } namespace { FLinearColor Shade(const FLinearColor& C, float F) { return FLinearColor(FMath::Clamp(C.R * F, 0.f, 1.f), FMath::Clamp(C.G * F, 0.f, 1.f), FMath::Clamp(C.B * F, 0.f, 1.f), C.A); } } void DrawItemIcon(FNeuPainter& P, FVector2f C, float Size, FName ItemId, bool bDim) { const FNeuIconStyle St = IconStyleFor(ItemId); const float OldAlpha = P.Alpha; if (bDim) { P.Alpha *= 0.4f; } const float S = Size; const float H = S * 0.5f; const FLinearColor Ink = Neu::Bg(); const float GlyphPx = FMath::Max(9.f, S * 0.30f); auto Glyph = [&](FVector2f At, float Px, const FLinearColor& Color) { P.TextBox(St.Glyph, At - FVector2f(S, Px * 0.7f), FVector2f(2.f * S, Px * 1.4f), ENeuFont::Bold, Px, Color, ENeuAlign::Center, ENeuVAlign::Center); }; switch (St.Shape) { case ENeuIconShape::Ore: { // Faceted pentagon, point up: a light top facet, mid left and dark right facets. TArray Pent; for (int32 I = 0; I < 5; ++I) { const float A = FMath::DegreesToRadians(-90.f + 72.f * I); Pent.Add(C + FVector2f(FMath::Cos(A), FMath::Sin(A)) * (H * 0.92f)); } P.Polygon(Pent, St.Color); TArray Top = { Pent[0], Pent[1], C }; TArray Left = { Pent[3], Pent[4], C }; TArray Right = { Pent[1], Pent[2], C }; P.Polygon(Top, Shade(St.Color, 1.18f)); P.Polygon(Left, Shade(St.Color, 0.86f)); P.Polygon(Right, Shade(St.Color, 0.72f)); Glyph(C + FVector2f(0.f, H * 0.14f), GlyphPx, Ink); break; } case ENeuIconShape::Refined: { // Three bars stacked like a pile of ingots. const float BW = S * 0.74f; const float BH = S * 0.22f; for (int32 I = 0; I < 3; ++I) { const FVector2f Pos = C + FVector2f(-BW * 0.5f + (I == 1 ? S * 0.05f : 0.f), -S * 0.36f + I * (BH + S * 0.045f)); P.RoundRect(Pos, FVector2f(BW, BH), 3.f, Shade(St.Color, 1.0f - 0.14f * I)); P.RoundRect(Pos, FVector2f(BW, BH * 0.35f), 3.f, Neu::WithAlpha(FLinearColor::White, 0.18f)); } Glyph(C + FVector2f(0.f, S * 0.285f), FMath::Max(7.f, S * 0.2f), Ink); break; } case ENeuIconShape::Tank: { const float TW = S * 0.42f; const float TH = S * 0.84f; P.RoundRect(C + FVector2f(-TW * 0.5f, -TH * 0.5f + S * 0.05f), FVector2f(TW, TH), TW * 0.5f, St.Color); P.RoundRect(C + FVector2f(-TW * 0.5f, -TH * 0.5f + S * 0.05f), FVector2f(TW * 0.4f, TH), TW * 0.2f, Neu::WithAlpha(FLinearColor::White, 0.2f)); P.RoundRect(C + FVector2f(-S * 0.09f, -TH * 0.5f - S * 0.05f), FVector2f(S * 0.18f, S * 0.12f), 2.f, Neu::Dim()); Glyph(C + FVector2f(0.f, S * 0.10f), GlyphPx * 0.9f, Ink); break; } case ENeuIconShape::Tool: { P.Disc(C, H * 0.88f, Shade(St.Color, 0.55f)); P.Disc(C, H * 0.72f, St.Color); P.Disc(C, H * 0.50f, Shade(St.Color, 0.75f)); Glyph(C, GlyphPx, Ink); break; } case ENeuIconShape::Kit: { // Isometric box: top rhombus, left and right faces. const float W = H * 0.86f; const float D = H * 0.5f; const FVector2f Top = C + FVector2f(0.f, -H * 0.82f); const FVector2f UL = C + FVector2f(-W, -H * 0.82f + D); const FVector2f UR = C + FVector2f(W, -H * 0.82f + D); const FVector2f Mid = C + FVector2f(0.f, -H * 0.82f + 2.f * D); const FVector2f BL = UL + FVector2f(0.f, H * 0.95f); const FVector2f BR = UR + FVector2f(0.f, H * 0.95f); const FVector2f BM = Mid + FVector2f(0.f, H * 0.95f); P.Polygon({ Top, UR, Mid, UL }, Shade(St.Color, 1.12f)); P.Polygon({ UL, Mid, BM, BL }, Shade(St.Color, 0.82f)); P.Polygon({ Mid, UR, BR, BM }, Shade(St.Color, 0.62f)); Glyph(C + FVector2f(0.f, H * 0.34f), GlyphPx * 0.85f, Ink); break; } case ENeuIconShape::Bio: { // A fat droplet with a small tail: reads as a creature without drawing a fish per species. P.Disc(C + FVector2f(-S * 0.05f, 0.f), H * 0.62f, St.Color); P.Polygon({ C + FVector2f(H * 0.35f, 0.f), C + FVector2f(H * 0.92f, -H * 0.42f), C + FVector2f(H * 0.92f, H * 0.42f) }, Shade(St.Color, 0.8f)); P.Disc(C + FVector2f(-S * 0.27f, -S * 0.10f), S * 0.04f, Ink); Glyph(C + FVector2f(S * 0.02f, S * 0.05f), GlyphPx * 0.8f, Ink); break; } case ENeuIconShape::Weapon: { P.RoundRect(C + FVector2f(-S * 0.40f, -S * 0.16f), FVector2f(S * 0.80f, S * 0.22f), 4.f, St.Color); P.RoundRect(C + FVector2f(-S * 0.16f, -S * 0.02f), FVector2f(S * 0.20f, S * 0.40f), 4.f, Shade(St.Color, 0.8f)); break; } case ENeuIconShape::Box: { P.RoundRect(C + FVector2f(-S * 0.42f, -S * 0.32f), FVector2f(S * 0.84f, S * 0.64f), 4.f, Shade(St.Color, 0.9f)); P.RoundRect(C + FVector2f(-S * 0.42f, -S * 0.10f), FVector2f(S * 0.84f, S * 0.18f), 0.f, Neu::WithAlpha(Ink, 0.55f)); Glyph(C + FVector2f(0.f, -S * 0.21f), GlyphPx * 0.8f, Ink); break; } case ENeuIconShape::Use: { // A stick with a bright head (flares and beacons). P.RoundRect(C + FVector2f(-S * 0.08f, -S * 0.10f), FVector2f(S * 0.16f, S * 0.52f), 3.f, Shade(St.Color, 0.7f)); P.Disc(C + FVector2f(0.f, -S * 0.22f), S * 0.17f, St.Color); P.Disc(C + FVector2f(0.f, -S * 0.22f), S * 0.30f, Neu::WithAlpha(St.Color, 0.18f)); Glyph(C + FVector2f(0.f, S * 0.34f), GlyphPx * 0.75f, St.Color); break; } case ENeuIconShape::Generic: default: { P.RoundRect(C - FVector2f(H * 0.7f, H * 0.7f), FVector2f(H * 1.4f, H * 1.4f), 6.f, Shade(St.Color, 0.6f)); Glyph(C, GlyphPx, Neu::Txt()); break; } } P.Alpha = OldAlpha; } }