Files
maszyna/betterRenderer/renderer/source/materialparser.cpp
2026-03-14 20:51:11 +01:00

367 lines
12 KiB
C++

#include "materialparser.h"
#include "nvrenderer/nvrenderer.h"
#include <utilities/Globals.h>
#include <utilities/Logs.h>
#include <fmt/format.h>
#include <model/material.h>
#include <parser.h>
#include <utilities/utilities.h>
#include <yaml-cpp/yaml.h>
#include <string>
std::string_view MaterialAdapter::GetTexturePathForEntry(
std::string_view key) const {
if (m_material_internal) {
return m_material_internal->GetTexturePathForEntry(key);
}
return std::string_view();
}
int MaterialAdapter::GetTextureSizeBiasForEntry(std::string_view key) const {
if (m_material_internal) {
return m_material_internal->GetTextureSizeBiasForEntry(key);
}
return 0;
}
std::string_view MaterialAdapter::GetShader() const {
if (m_material_internal) {
return m_material_internal->GetShader();
}
return std::string_view();
}
int MaterialAdapter::GetShadowRank() const {
if (m_material_internal) {
return m_material_internal->GetShadowRank();
}
return 0;
}
glm::dvec2 MaterialAdapter::GetSize() const {
if (m_material_internal) {
return m_material_internal->GetSize();
}
return {-1., -1.};
}
std::optional<float> MaterialAdapter::GetOpacity() const {
if (m_material_internal) {
return m_material_internal->GetOpacity();
}
return std::nullopt;
}
bool MaterialAdapter::Parse(std::string_view filepath) {
if (m_material_internal = MaterialAdapterManul::Parse(filepath);
m_material_internal) {
return true;
}
if (m_material_internal = MaterialAdapterLegacyMatFile::Parse(filepath);
m_material_internal) {
return true;
}
if (m_material_internal = MaterialAdapterSingleTexture::Parse(filepath);
m_material_internal) {
return true;
}
return false;
}
std::optional<bool> MaterialAdapter::GetMaskedShadowOverride() const {
if (m_material_internal) {
return m_material_internal->GetMaskedShadowOverride();
}
return std::nullopt;
}
std::shared_ptr<MaterialAdapterInternal> MaterialAdapterLegacyMatFile::Parse(
std::string_view path) {
auto const locator{material_manager::find_on_disk(std::string(path))};
if (locator.first.size()) {
// try to parse located file resource
cParser materialparser(locator.first + locator.second,
cParser::buffer_FILE);
auto material = std::make_shared<MaterialAdapterLegacyMatFile>();
while (material->ParseLevel(materialparser, 0)) {
}
return material;
} else {
return nullptr;
}
}
std::string_view MaterialAdapterLegacyMatFile::GetTexturePathForEntry(
std::string_view key) const {
if (key == "diffuse") {
if (auto it = m_texture_mapping.find("_diffuse:");
it != m_texture_mapping.end()) {
return it->second.m_path;
}
if (auto it = m_texture_mapping.find("1:"); it != m_texture_mapping.end()) {
return it->second.m_path;
}
} else if (key == "normal") {
if (auto it = m_texture_mapping.find("_normals:");
it != m_texture_mapping.end()) {
return it->second.m_path;
}
if (auto it = m_texture_mapping.find("_normalmap:");
it != m_texture_mapping.end()) {
return it->second.m_path;
}
if (auto it = m_texture_mapping.find("_reflmap:");
it != m_texture_mapping.end()) {
return it->second.m_path;
}
if (auto it = m_texture_mapping.find("2:"); it != m_texture_mapping.end()) {
return it->second.m_path;
}
} else {
if (auto it = m_texture_mapping.find(fmt::format("_{}:", key));
it != m_texture_mapping.end()) {
return it->second.m_path;
}
}
return std::string_view();
}
std::string_view MaterialAdapterLegacyMatFile::GetShader() const {
if (m_shader == "water") {
return "legacy_water";
}
if (m_shader == "rain_windscreen") {
return "windshield_rain";
}
if (IsSpecGlossShader() && HasSpecGlossMap()) {
if (IsNormalMapShader() && HasNormalMap()) {
return "legacy_normalmap_specgloss";
}
return "legacy_specgloss";
}
if (IsNormalMapShader() && HasNormalMap()) {
return "legacy_normalmap";
}
if (HasNormalMap()) {
return "legacy_reflection";
}
return "legacy";
}
bool MaterialAdapterLegacyMatFile::ParseLevel(cParser& parser, int priority) {
// NOTE: comma can be part of legacy file names, so we don't treat it as a
// separator here
auto key{parser.getToken<std::string>(true, "\n\r\t ;[]")};
// key can be an actual key or block end
if ((true == key.empty()) || (key == "}")) {
return false;
}
if (priority != -1) {
// regular attribute processing mode
// mark potential material change
// update_on_weather_change |= is_weather(key);
// update_on_season_change |= is_season(key);
if (key == Global.Weather) {
// weather textures override generic (pri 0) and seasonal (pri 1) textures
// seasonal weather textures (pri 1+2=3) override generic weather (pri 2)
// textures skip the opening bracket
auto const value{parser.getToken<std::string>(true, "\n\r\t ;")};
while (ParseLevel(parser, priority + 2)) {
; // all work is done in the header
}
} else if (key == Global.Season) {
// seasonal textures override generic textures
// skip the opening bracket
auto const value{parser.getToken<std::string>(true, "\n\r\t ;")};
while (ParseLevel(parser, priority + 1)) {
; // all work is done in the header
}
}
else if (key.compare(0, 7, "texture") == 0) {
key.erase(0, 7);
auto value{deserialize_random_set(parser)};
replace_slashes(value);
auto& [tex_priority, texture] = m_texture_mapping[key];
if (tex_priority < priority) {
texture = value;
tex_priority = priority;
}
} else if (key.compare(0, 5, "param") == 0) {
// key.erase(0, 5);
//
parser.getToken<std::string>(true, "\n\r\t;");
// std::istringstream stream(value);
// glm::vec4 data;
// stream >> data.r;
// stream >> data.g;
// stream >> data.b;
// stream >> data.a;
//
// auto it = parse_info->param_mapping.find(key);
// if (it == parse_info->param_mapping.end())
// parse_info->param_mapping.emplace(
// std::make_pair(key, parse_info_s::param_def({data, Priority})));
// else if (Priority > it->second.priority) {
// parse_info->param_mapping.erase(it);
// parse_info->param_mapping.emplace(
// std::make_pair(key, parse_info_s::param_def({data, Priority})));
// }
} else if (key == "shader:" &&
(m_shader.empty() || priority > m_shader_priority)) {
m_shader = deserialize_random_set(parser);
m_shader_priority = priority;
} else if (key == "opacity:" && priority > m_opacity_priority) {
std::string value = deserialize_random_set(parser);
m_opacity = std::stof(value); // m7t: handle exception
m_opacity_priority = priority;
} else if (key == "selfillum:" && priority > m_selfillum_priority) {
std::string value = deserialize_random_set(parser);
m_selfillum = std::stof(value); // m7t: handle exception
m_selfillum_priority = priority;
} else if (key == "glossiness:" /* && Priority > m_glossiness_priority*/) {
deserialize_random_set(parser);
// glossiness = std::stof(value); // m7t: handle exception
// m_glossiness_priority = Priority;
} else if (key == "shadow_rank:") {
std::string value = deserialize_random_set(parser);
m_shadow_rank = std::stoi(value); // m7t: handle exception
} else if (key == "size:") {
parser.getTokens(2);
parser >> m_size.x >> m_size.y;
} else {
auto const value = parser.getToken<std::string>(true, "\n\r\t ;");
if (value == "{") {
// unrecognized or ignored token, but comes with attribute block and
// potential further nesting go through it and discard the content
while (ParseLevel(parser, -1)) {
; // all work is done in the header
}
}
}
} else {
// discard mode; ignores all retrieved tokens
auto const value{parser.getToken<std::string>(true, "\n\r\t ;")};
if (value == "{") {
// ignored tokens can come with their own blocks, ignore these recursively
// go through it and discard the content
while (true == ParseLevel(parser, -1)) {
; // all work is done in the header
}
}
}
return true; // return value marks a key: value pair was extracted, nothing
// about whether it's recognized
}
bool MaterialAdapterLegacyMatFile::HasNormalMap() const {
return m_texture_mapping.find("_normals:") != m_texture_mapping.end() ||
m_texture_mapping.find("_normalmap:") != m_texture_mapping.end() ||
m_texture_mapping.find("_reflmap:") != m_texture_mapping.end() ||
m_texture_mapping.find("2:") != m_texture_mapping.end();
}
bool MaterialAdapterLegacyMatFile::HasSpecGlossMap() const {
return m_texture_mapping.find("_specgloss:") != m_texture_mapping.end();
}
bool MaterialAdapterLegacyMatFile::IsNormalMapShader() const {
return m_shader.find("normalmap") != std::string::npos ||
m_shader.find("parallax") != std::string::npos;
}
bool MaterialAdapterLegacyMatFile::IsReflectionShader() const {
return m_shader.find("reflmap") != std::string::npos;
}
bool MaterialAdapterLegacyMatFile::IsSpecGlossShader() const {
return m_shader.find("specgloss") != std::string::npos;
}
std::optional<float> MaterialAdapterLegacyMatFile::GetOpacity() const {
return m_opacity;
}
std::shared_ptr<MaterialAdapterInternal> MaterialAdapterSingleTexture::Parse(
std::string_view path) {
return std::make_shared<MaterialAdapterSingleTexture>(path);
}
std::string_view MaterialAdapterSingleTexture::GetTexturePathForEntry(
std::string_view key) const {
if (key == "diffuse") {
return m_tex_diffuse;
}
return std::string_view();
}
std::string_view MaterialAdapterSingleTexture::GetShader() const {
return "legacy";
}
std::optional<float> MaterialAdapterSingleTexture::GetOpacity() const {
return std::nullopt;
}
std::shared_ptr<MaterialAdapterInternal> MaterialAdapterManul::Parse(
std::string_view path) {
std::string entries[]{
Global.asCurrentTexturePath + std::string(path) + ".manul",
std::string(path) + ".manul"};
for (auto it = std::begin(entries); it != std::end(entries); ++it) {
if (!std::filesystem::exists(*it)) {
continue;
}
auto root = YAML::LoadFile(*it);
auto material = std::make_shared<MaterialAdapterManul>();
material->m_shader = root["shader"].as<std::string>();
for (const auto it : root["textures"]) {
material->m_textures[it.first.as<std::string>()] =
it.second.as<std::string>();
}
if (auto alpha_threshold = root["alpha_threshold"];
alpha_threshold.IsScalar()) {
material->m_alpha_threshold = alpha_threshold.as<float>();
}
if (auto size_bias = root["max_resolution_bias"]; size_bias.IsScalar())
material->m_size_bias = size_bias.as<int>();
return material;
}
return nullptr;
}
std::string_view MaterialAdapterManul::GetTexturePathForEntry(
std::string_view key) const {
if (auto it = m_textures.find(std::string(key)); it != m_textures.end()) {
return it->second;
}
return std::string_view();
}
int MaterialAdapterManul::GetTextureSizeBiasForEntry(
std::string_view key) const {
return m_size_bias;
}
std::string_view MaterialAdapterManul::GetShader() const { return m_shader; }
std::optional<float> MaterialAdapterManul::GetOpacity() const {
return m_alpha_threshold;
}
std::optional<bool> MaterialAdapterInternal::GetMaskedShadowOverride() const {
auto threshold = GetOpacity();
if (threshold.has_value()) {
return !!*threshold;
}
return std::nullopt;
}