diff --git a/source/graphics/TerrainTextureEntry.cpp b/source/graphics/TerrainTextureEntry.cpp index a5859ac158..d87889863b 100644 --- a/source/graphics/TerrainTextureEntry.cpp +++ b/source/graphics/TerrainTextureEntry.cpp @@ -137,8 +137,8 @@ CTerrainTextureEntry::CTerrainTextureEntry(CTerrainPropertiesPtr properties, con if (CRenderer::IsInitialised()) m_TerrainAlpha = g_TexMan.LoadAlphaMap(alphamap); - float texAngle = 0.f; - float texSize = 1.f; + float texAngle{0.f}; + float texSize{1.f}; if (m_pProperties) { @@ -146,19 +146,33 @@ CTerrainTextureEntry::CTerrainTextureEntry(CTerrainPropertiesPtr properties, con texAngle = m_pProperties->GetTextureAngle(); texSize = m_pProperties->GetTextureSize(); } - - m_TextureMatrix.SetZero(); - m_TextureMatrix._11 = cosf(texAngle) / texSize; - m_TextureMatrix._13 = -sinf(texAngle) / texSize; - m_TextureMatrix._21 = -sinf(texAngle) / texSize; - m_TextureMatrix._23 = -cosf(texAngle) / texSize; - m_TextureMatrix._44 = 1.f; + GenerateTextureMatrix(texAngle, texSize); GroupVector::iterator it=m_Groups.begin(); for (;it!=m_Groups.end();++it) (*it)->AddTerrain(this); } +CTerrainTextureEntry::CTerrainTextureEntry(const CStr tag): + m_pProperties(nullptr), + m_BaseColor(0), + m_BaseColorValid(false), + m_DiffuseTexturePath(""), + m_Tag(tag) +{ + if (!CRenderer::IsInitialised()) + return; + + const VfsPath alphamap{"standard"}; + const VfsPath mat{VfsPath{"art/materials"} / "terrain_norm_spec.xml"}; + m_Material = g_Renderer.GetSceneRenderer().GetMaterialManager().LoadMaterial(mat); + const CTexturePtr texptr{g_Renderer.GetTextureManager().GetErrorTexture()}; + m_Material.AddSampler(CMaterial::TextureSampler{str_baseTex, texptr}); + m_TerrainAlpha = g_TexMan.LoadAlphaMap(alphamap); + + GenerateTextureMatrix(0.0f, 1.f); +} + CTerrainTextureEntry::~CTerrainTextureEntry() { for (GroupVector::iterator it=m_Groups.begin();it!=m_Groups.end();++it) @@ -184,3 +198,13 @@ void CTerrainTextureEntry::BuildBaseColor() m_BaseColorValid = true; } } + +void CTerrainTextureEntry::GenerateTextureMatrix(const float texAngle, const float texSize) +{ + m_TextureMatrix.SetZero(); + m_TextureMatrix._11 = cosf(texAngle) / texSize; + m_TextureMatrix._13 = -sinf(texAngle) / texSize; + m_TextureMatrix._21 = -sinf(texAngle) / texSize; + m_TextureMatrix._23 = -cosf(texAngle) / texSize; + m_TextureMatrix._44 = 1.f; +} diff --git a/source/graphics/TerrainTextureEntry.h b/source/graphics/TerrainTextureEntry.h index 4ae1647b76..08fcfc0da3 100644 --- a/source/graphics/TerrainTextureEntry.h +++ b/source/graphics/TerrainTextureEntry.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -37,6 +37,19 @@ public: // Most of the texture's data is delay-loaded, so after the constructor has // been called, the texture entry is ready to be used. CTerrainTextureEntry(CTerrainPropertiesPtr props, const VfsPath& path); + + /** + * @brief Constructs a terrain texture entry with the given tag. + * + * This constructor creates a placeholder (dummy) texture entry, + * allowing the system to handle missing terrain textures gracefully. + * It ensures stability by avoiding crashes when a texture file is + * not found. + * + * @param tag The identifier for the terrain texture entry. + */ + CTerrainTextureEntry(const CStr tag); + ~CTerrainTextureEntry(); const CStr& GetTag() const { return m_Tag; } @@ -67,6 +80,7 @@ public: CTerrainTextureManager::TerrainAlphaMap::iterator m_TerrainAlpha; private: + void GenerateTextureMatrix(const float texAngle, const float texSize); // Tag = file name stripped of path and extension (grass_dark_1) CStr m_Tag; diff --git a/source/graphics/TerrainTextureManager.cpp b/source/graphics/TerrainTextureManager.cpp index b7b1e46dbf..77a61cc035 100644 --- a/source/graphics/TerrainTextureManager.cpp +++ b/source/graphics/TerrainTextureManager.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2024 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -67,7 +67,7 @@ void CTerrainTextureManager::UnloadTerrainTextures() m_LastGroupIndex = 0; } -CTerrainTextureEntry* CTerrainTextureManager::FindTexture(const CStr& tag_) const +CTerrainTextureEntry* CTerrainTextureManager::FindTexture(const CStr& tag_) { CStr tag = tag_.BeforeLast("."); // Strip extension @@ -75,8 +75,13 @@ CTerrainTextureEntry* CTerrainTextureManager::FindTexture(const CStr& tag_) cons if (te->GetTag() == tag) return te; - LOGWARNING("CTerrainTextureManager: Couldn't find terrain %s", tag.c_str()); - return 0; + LOGWARNING("CTerrainTextureManager: Couldn't find terrain %s using fallback texture", tag.c_str()); + + // If the texture is not found, return a default texture. + // This is a fallback texture, so it should not be used in the editor. + CTerrainTextureEntry* fallback{new CTerrainTextureEntry{tag}}; + m_TextureEntries.push_back(fallback); + return fallback; } CTerrainTextureEntry* CTerrainTextureManager::AddTexture(const CTerrainPropertiesPtr& props, const VfsPath& path) diff --git a/source/graphics/TerrainTextureManager.h b/source/graphics/TerrainTextureManager.h index 9ba32c5f58..7ed6e3bf6f 100644 --- a/source/graphics/TerrainTextureManager.h +++ b/source/graphics/TerrainTextureManager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2023 Wildfire Games. +/* Copyright (C) 2025 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -103,7 +103,7 @@ public: void UnloadTerrainTextures(); - CTerrainTextureEntry* FindTexture(const CStr& tag) const; + CTerrainTextureEntry* FindTexture(const CStr& tag); // Create a texture object for a new terrain texture at path, using the // property sheet props.