diff --git a/dDashboardServer/routes/SettingsCatalog.cpp b/dDashboardServer/routes/SettingsCatalog.cpp index 3c1e42ae0..4dc91ace6 100644 --- a/dDashboardServer/routes/SettingsCatalog.cpp +++ b/dDashboardServer/routes/SettingsCatalog.cpp @@ -458,6 +458,7 @@ namespace { c.Add(Float(UGC, "glow_emissive", "Glow emissive strength", "With the glow shader on: the glow shapes' material emissive, how far the emissive shader goes from lit to the plain color (1: fully).", "1", 0, 10)); c.Add(Text(UGC, "metal_material_types", "Metal material types", "Materials.xml MaterialTypes drawn as metal, comma separated (none: only LU Toolbox's metallic colors).", "shinySteel")); c.Add(Text(UGC, "brushed_material_types", "Brushed steel material types", "Materials.xml MaterialTypes drawn as brushed steel, comma separated (none: no such colors).", "brushedSteel,matteSteel")); + c.Add(Text(UGC, "brushed_colors", "Brushed steel colors", "LEGO color ids drawn as brushed steel whatever their Materials.xml type, comma separated (e.g. the drum lacquered 298,300,1002,1004). Empty: none.", "")); c.Add(Bool(UGC, "remove_hidden_faces", "Remove faces nobody can see", "", true)); c.Add(Bool(UGC, "hsr_ground_plane", "Nothing seen from below", "Also removes what can only be seen from under the model.", false)); c.Add(Unit(Int(UGC, "optimize_resolution", "Detail of the visibility renders", "", "1024", 64, 4096), "pixels")); diff --git a/dUgcServer/UgcModel.cpp b/dUgcServer/UgcModel.cpp index 21b05c9c0..3f2e22b8c 100644 --- a/dUgcServer/UgcModel.cpp +++ b/dUgcServer/UgcModel.cpp @@ -191,6 +191,7 @@ namespace UgcModel { } eLook LookOf(uint32_t id, const UgcBricks::Material& material, const LookRules& rules) { + if (const auto color = rules.colors.find(id); color != rules.colors.end()) return color->second; if (rules.paletteGlow && UgcPalette::Glow(id)) return eLook::GLOW; if (rules.paletteMetallic && UgcPalette::IsMetallic(id)) return eLook::METAL; const auto type = rules.materialTypes.find(material.type); diff --git a/dUgcServer/UgcModel.h b/dUgcServer/UgcModel.h index 990f2f84a..301d16100 100644 --- a/dUgcServer/UgcModel.h +++ b/dUgcServer/UgcModel.h @@ -75,9 +75,11 @@ namespace UgcModel { /** * Which colors have which look, from the client's data: a Materials.xml MaterialType (brickdb.zip) and LU Toolbox's - * metallic and glow colors (UgcPalette). Glow wins over metal; transparent bricks are always plastic. + * metallic and glow colors (UgcPalette), and colors named in the settings. A named color wins, then glow over metal; + * transparent bricks are always plastic. */ struct LookRules { + std::map colors; // LEGO color ids given a look by the settings (brushed_colors) std::map materialTypes{ { "shinySteel", eLook::METAL }, { "brushedSteel", eLook::BRUSHED }, { "matteSteel", eLook::BRUSHED } }; bool paletteMetallic{ true }; // LU Toolbox's Metallic colors (UgcPalette::IsMetallic) are METAL bool paletteGlow{ true }; // its glow colors (UgcPalette::Glow) are GLOW diff --git a/dUgcServer/UgcServer.cpp b/dUgcServer/UgcServer.cpp index a2f9c54d4..c87a5ce03 100644 --- a/dUgcServer/UgcServer.cpp +++ b/dUgcServer/UgcServer.cpp @@ -106,6 +106,15 @@ namespace { if (!type.empty() && type != "none") settings.build.looks.materialTypes[type] = look; } } + // LEGO color ids drawn as brushed steel whatever their Materials.xml type + { + std::stringstream stream(Game::config->GetValue("brushed_colors")); + std::string id; + while (std::getline(stream, id, ',')) { + std::erase_if(id, [](unsigned char c) { return std::isspace(c); }); + if (const auto color = GeneralUtils::TryParse(id)) settings.build.looks.colors[*color] = UgcModel::eLook::BRUSHED; + } + } settings.optimize.removeHidden = Setting("remove_hidden_faces", 1) != 0; settings.optimize.groundPlane = Setting("hsr_ground_plane", 0) != 0; settings.optimize.resolution = Setting("optimize_resolution", 1024); diff --git a/docs/UgcServer.md b/docs/UgcServer.md index b59c1c0e5..09e821b9c 100644 --- a/docs/UgcServer.md +++ b/docs/UgcServer.md @@ -221,11 +221,12 @@ all of its levels, so each look needs a group of its own. | Setting (`ugcconfig.ini`, dashboard: UGC models) | Default | What it writes | | --- | --- | --- | | `shader_metal` | 0 (off) | `S_Metal_Model` for metal colors: 88 is Polished Metal (gameValue 98). The client loads `textures/metal/metal_reflection_polished.dds` itself and tints it by the vertex color (`Metallic.fx`, `Technique_Lighting_PolishedMetal_VertColor`). | -| `shader_brushed` | 0 (off) | `S_Brushed_Model` for brushed steel colors: 89 is Brushed Steel (gameValue 99; it loads `metal_reflection_brushed.dds` and `_noise.dds`, the noise in object space). The client's Materials.xml has no such colors, so this only does something with a Materials.xml that names them. | +| `shader_brushed` | 0 (off) | `S_Brushed_Model` for brushed steel colors: 89 is Brushed Steel (gameValue 99; it loads `metal_reflection_brushed.dds` and `_noise.dds`, the noise in object space). The textures are registered by the client (0x00453730) as global shader textures 6 and 7, so the .nif needs none. The client's Materials.xml has no brushed types, so this needs `brushed_colors` or a Materials.xml that names them. | | `shader_glow` | 0 (off) | `S_Glow_Model` for opaque glowing colors: 46 is LEGO-Emissive (gameValue 53), which draws `lerp(lit, vertex color, vertex alpha * material emissive red)`, opaque. | | `glow_emissive` | 1 | The glow shapes' `NiMaterialProperty` emissive (grey): how far the shader goes from lit to the plain color. | | `metal_material_types` | `shinySteel` | Materials.xml `MaterialType`s that are metal (empty: the default; `none`: none). | | `brushed_material_types` | `brushedSteel,matteSteel` | Materials.xml `MaterialType`s that are brushed steel. | +| `brushed_colors` | empty | LEGO color ids that are brushed steel whatever their type (e.g. the drum lacquered 298, 300, 1002, 1004); they win over the metal and glow colors. | Which color has which look is data, not a list in the code (`UgcModel::LookOf`): glow is LU Toolbox's glow table (`UgcPalette::Glow`: 50, 294, 329, 9000-9027), metal is LU Toolbox's metallic table (`UgcPalette::IsMetallic`) plus diff --git a/resources/ugcconfig.ini b/resources/ugcconfig.ini index 3ea60c6d2..ebcf86489 100644 --- a/resources/ugcconfig.ini +++ b/resources/ugcconfig.ini @@ -81,6 +81,8 @@ shader_glow=0 glow_emissive=1 metal_material_types=shinySteel brushed_material_types=brushedSteel,matteSteel +# brushed_colors: LEGO color ids drawn as brushed steel whatever their type (e.g. the drum lacquered 298,300,1002,1004) +brushed_colors= # Remove faces that can't be seen from anywhere (optimize_resolution: detail of the renders that decide it; # hsr_ground_plane: 1 also removes what can only be seen from below the model) diff --git a/tests/dUgcTests/UgcTests.cpp b/tests/dUgcTests/UgcTests.cpp index 6de99012f..104c0626b 100644 --- a/tests/dUgcTests/UgcTests.cpp +++ b/tests/dUgcTests/UgcTests.cpp @@ -1148,6 +1148,12 @@ TEST(UgcShaders, LooksComeFromTheColorData) { EXPECT_EQ(UgcModel::LookOf(329, plastic, rules), UgcModel::eLook::GLOW); // LU Toolbox's glow colors EXPECT_EQ(UgcModel::LookOf(50, plastic, rules), UgcModel::eLook::GLOW); EXPECT_EQ(UgcModel::LookOf(9016, plastic, rules), UgcModel::eLook::GLOW); + UgcModel::LookRules named; + named.colors[298] = UgcModel::eLook::BRUSHED; + named.colors[329] = UgcModel::eLook::BRUSHED; + EXPECT_EQ(UgcModel::LookOf(298, steel, named), UgcModel::eLook::BRUSHED); // a named color wins over its type + EXPECT_EQ(UgcModel::LookOf(329, plastic, named), UgcModel::eLook::BRUSHED); // and over the glow colors + EXPECT_EQ(UgcModel::LookOf(150, steel, named), UgcModel::eLook::METAL); UgcModel::LookRules none; none.materialTypes.clear(); none.paletteMetallic = false;