1 /* Copyright (C) 2022 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
18 #include "precompiled.h"
20 #include "TerrainTextureEntry.h"
22 #include "graphics/MaterialManager.h"
23 #include "graphics/Terrain.h"
24 #include "graphics/TerrainProperties.h"
25 #include "graphics/TerrainTextureManager.h"
26 #include "graphics/TextureManager.h"
28 #include "ps/CLogger.h"
29 #include "ps/CStrInternStatic.h"
30 #include "ps/Filesystem.h"
31 #include "ps/XML/Xeromyces.h"
32 #include "renderer/Renderer.h"
33 #include "renderer/SceneRenderer.h"
37 CTerrainTextureEntry::CTerrainTextureEntry(CTerrainPropertiesPtr properties
, const VfsPath
& path
):
38 m_pProperties(properties
),
40 m_BaseColorValid(false)
45 if (XeroFile
.Load(g_VFS
, path
, "terrain_texture") != PSRETURN_OK
)
47 LOGERROR("Terrain xml not found (%s)", path
.string8());
51 #define EL(x) int el_##x = XeroFile.GetElementID(#x)
52 #define AT(x) int at_##x = XeroFile.GetAttributeID(#x)
65 XMBElement root
= XeroFile
.GetRoot();
67 if (root
.GetNodeName() != el_terrain
)
69 LOGERROR("Invalid terrain format (unrecognised root element '%s')", XeroFile
.GetElementString(root
.GetNodeName()));
73 std::vector
<std::pair
<CStr
, VfsPath
> > samplers
;
74 VfsPath
alphamap("standard");
75 m_Tag
= utf8_from_wstring(path
.Basename().string());
77 XERO_ITER_EL(root
, child
)
79 int child_name
= child
.GetNodeName();
81 if (child_name
== el_textures
)
83 XERO_ITER_EL(child
, textures_element
)
85 ENSURE(textures_element
.GetNodeName() == el_texture
);
88 VfsPath terrainTexturePath
;
89 XERO_ITER_ATTR(textures_element
, relativePath
)
91 if (relativePath
.Name
== at_file
)
92 terrainTexturePath
= VfsPath("art/textures/terrain") / relativePath
.Value
.FromUTF8();
93 else if (relativePath
.Name
== at_name
)
94 name
= relativePath
.Value
;
96 samplers
.emplace_back(name
, terrainTexturePath
);
97 if (name
== str_baseTex
.string())
98 m_DiffuseTexturePath
= terrainTexturePath
;
102 else if (child_name
== el_material
)
104 VfsPath mat
= VfsPath("art/materials") / child
.GetText().FromUTF8();
105 if (CRenderer::IsInitialised())
106 m_Material
= g_Renderer
.GetSceneRenderer().GetMaterialManager().LoadMaterial(mat
);
108 else if (child_name
== el_alphamap
)
110 alphamap
= child
.GetText().FromUTF8();
112 else if (child_name
== el_props
)
114 CTerrainPropertiesPtr
ret (new CTerrainProperties(properties
));
115 ret
->LoadXml(child
, &XeroFile
, path
);
116 if (ret
) m_pProperties
= ret
;
118 else if (child_name
== el_tag
)
120 m_Tag
= child
.GetText();
124 for (size_t i
= 0; i
< samplers
.size(); ++i
)
126 CTextureProperties
texture(samplers
[i
].second
);
127 texture
.SetAddressMode(Renderer::Backend::Sampler::AddressMode::REPEAT
);
128 texture
.SetAnisotropicFilter(true);
130 if (CRenderer::IsInitialised())
132 CTexturePtr texptr
= g_Renderer
.GetTextureManager().CreateTexture(texture
);
133 m_Material
.AddSampler(CMaterial::TextureSampler(samplers
[i
].first
, texptr
));
137 if (CRenderer::IsInitialised())
138 m_TerrainAlpha
= g_TexMan
.LoadAlphaMap(alphamap
);
140 float texAngle
= 0.f
;
145 m_Groups
= m_pProperties
->GetGroups();
146 texAngle
= m_pProperties
->GetTextureAngle();
147 texSize
= m_pProperties
->GetTextureSize();
150 m_TextureMatrix
.SetZero();
151 m_TextureMatrix
._11
= cosf(texAngle
) / texSize
;
152 m_TextureMatrix
._13
= -sinf(texAngle
) / texSize
;
153 m_TextureMatrix
._21
= -sinf(texAngle
) / texSize
;
154 m_TextureMatrix
._23
= -cosf(texAngle
) / texSize
;
155 m_TextureMatrix
._44
= 1.f
;
157 GroupVector::iterator it
=m_Groups
.begin();
158 for (;it
!=m_Groups
.end();++it
)
159 (*it
)->AddTerrain(this);
162 CTerrainTextureEntry::~CTerrainTextureEntry()
164 for (GroupVector::iterator it
=m_Groups
.begin();it
!=m_Groups
.end();++it
)
165 (*it
)->RemoveTerrain(this);
168 // BuildBaseColor: calculate the root color of the texture, used for coloring minimap, and store
169 // in m_BaseColor member
170 void CTerrainTextureEntry::BuildBaseColor()
172 // Use the explicit properties value if possible
173 if (m_pProperties
&& m_pProperties
->HasBaseColor())
175 m_BaseColor
=m_pProperties
->GetBaseColor();
176 m_BaseColorValid
= true;
180 // Use the texture color if available
181 if (GetTexture()->TryLoad())
183 m_BaseColor
= GetTexture()->GetBaseColor();
184 m_BaseColorValid
= true;