Index: ps/trunk/source/graphics/TerrainTextureEntry.cpp =================================================================== --- ps/trunk/source/graphics/TerrainTextureEntry.cpp (revision 26117) +++ ps/trunk/source/graphics/TerrainTextureEntry.cpp (revision 26118) @@ -1,366 +1,365 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "TerrainTextureEntry.h" -#include "lib/utf8.h" -#include "lib/ogl.h" +#include "graphics/MaterialManager.h" +#include "graphics/Terrain.h" +#include "graphics/TerrainProperties.h" +#include "graphics/TerrainTextureManager.h" +#include "graphics/Texture.h" #include "lib/allocators/shared_ptr.h" #include "lib/file/io/io.h" +#include "lib/ogl.h" #include "lib/res/graphics/ogl_tex.h" - +#include "lib/utf8.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" #include "ps/XML/Xeromyces.h" - -#include "graphics/MaterialManager.h" -#include "graphics/Terrain.h" -#include "graphics/TerrainTextureManager.h" -#include "graphics/TerrainProperties.h" -#include "graphics/Texture.h" #include "renderer/Renderer.h" #include CTerrainTextureEntry::CTerrainTextureEntry(CTerrainPropertiesPtr properties, const VfsPath& path): m_pProperties(properties), m_BaseColor(0), m_BaseColorValid(false) { ENSURE(properties); CXeromyces XeroFile; if (XeroFile.Load(g_VFS, path, "terrain_texture") != PSRETURN_OK) { LOGERROR("Terrain xml not found (%s)", path.string8()); return; } #define EL(x) int el_##x = XeroFile.GetElementID(#x) #define AT(x) int at_##x = XeroFile.GetAttributeID(#x) EL(tag); EL(terrain); EL(texture); EL(textures); EL(material); EL(props); EL(alphamap); AT(file); AT(name); #undef AT #undef EL XMBElement root = XeroFile.GetRoot(); if (root.GetNodeName() != el_terrain) { LOGERROR("Invalid terrain format (unrecognised root element '%s')", XeroFile.GetElementString(root.GetNodeName())); return; } std::vector > samplers; VfsPath alphamap("standard"); m_Tag = utf8_from_wstring(path.Basename().string()); XERO_ITER_EL(root, child) { int child_name = child.GetNodeName(); if (child_name == el_textures) { XERO_ITER_EL(child, textures_element) { ENSURE(textures_element.GetNodeName() == el_texture); CStr name; VfsPath terrainTexturePath; XERO_ITER_ATTR(textures_element, relativePath) { if (relativePath.Name == at_file) terrainTexturePath = VfsPath("art/textures/terrain") / relativePath.Value.FromUTF8(); else if (relativePath.Name == at_name) name = relativePath.Value; } samplers.emplace_back(name, terrainTexturePath); } } else if (child_name == el_material) { VfsPath mat = VfsPath("art/materials") / child.GetText().FromUTF8(); if (CRenderer::IsInitialised()) m_Material = g_Renderer.GetMaterialManager().LoadMaterial(mat); } else if (child_name == el_alphamap) { alphamap = child.GetText().FromUTF8(); } else if (child_name == el_props) { CTerrainPropertiesPtr ret (new CTerrainProperties(properties)); ret->LoadXml(child, &XeroFile, path); if (ret) m_pProperties = ret; } else if (child_name == el_tag) { m_Tag = child.GetText(); } } for (size_t i = 0; i < samplers.size(); ++i) { CTextureProperties texture(samplers[i].second); texture.SetWrap(GL_REPEAT); // TODO: anisotropy should probably be user-configurable, but we want it to be // at least 2 for terrain else the ground looks very blurry when you tilt the // camera upwards texture.SetMaxAnisotropy(2.0f); if (CRenderer::IsInitialised()) { CTexturePtr texptr = g_Renderer.GetTextureManager().CreateTexture(texture); m_Material.AddSampler(CMaterial::TextureSampler(samplers[i].first, texptr)); } } if (CRenderer::IsInitialised()) LoadAlphaMaps(alphamap); float texAngle = 0.f; float texSize = 1.f; if (m_pProperties) { m_Groups = m_pProperties->GetGroups(); 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; GroupVector::iterator it=m_Groups.begin(); for (;it!=m_Groups.end();++it) (*it)->AddTerrain(this); } CTerrainTextureEntry::~CTerrainTextureEntry() { for (GroupVector::iterator it=m_Groups.begin();it!=m_Groups.end();++it) (*it)->RemoveTerrain(this); } // BuildBaseColor: calculate the root color of the texture, used for coloring minimap, and store // in m_BaseColor member void CTerrainTextureEntry::BuildBaseColor() { // Use the explicit properties value if possible if (m_pProperties && m_pProperties->HasBaseColor()) { m_BaseColor=m_pProperties->GetBaseColor(); m_BaseColorValid = true; return; } // Use the texture color if available if (GetTexture()->TryLoad()) { m_BaseColor = GetTexture()->GetBaseColor(); m_BaseColorValid = true; } } const float* CTerrainTextureEntry::GetTextureMatrix() const { return &m_TextureMatrix._11; } // LoadAlphaMaps: load the 14 default alpha maps, pack them into one composite texture and // calculate the coordinate of each alphamap within this packed texture -void CTerrainTextureEntry::LoadAlphaMaps(VfsPath &amtype) +void CTerrainTextureEntry::LoadAlphaMaps(const VfsPath& alphaMapType) { - std::wstring key = L"(alpha map composite" + amtype.string() + L")"; + const std::wstring key = L"(alpha map composite" + alphaMapType.string() + L")"; - CTerrainTextureManager::TerrainAlphaMap::iterator it = g_TexMan.m_TerrainAlphas.find(amtype); + CTerrainTextureManager::TerrainAlphaMap::iterator it = g_TexMan.m_TerrainAlphas.find(alphaMapType); if (it != g_TexMan.m_TerrainAlphas.end()) { m_TerrainAlpha = it; return; } - g_TexMan.m_TerrainAlphas[amtype] = TerrainAlpha(); - it = g_TexMan.m_TerrainAlphas.find(amtype); + g_TexMan.m_TerrainAlphas[alphaMapType] = TerrainAlpha(); + it = g_TexMan.m_TerrainAlphas.find(alphaMapType); TerrainAlpha &result = it->second; // // load all textures and store Handle in array // Handle textures[NUM_ALPHA_MAPS] = {0}; VfsPath path(L"art/textures/terrain/alphamaps"); - path = path / amtype; + path = path / alphaMapType; - const wchar_t* fnames[NUM_ALPHA_MAPS] = { + const wchar_t* fnames[NUM_ALPHA_MAPS] = + { L"blendcircle.png", L"blendlshape.png", L"blendedge.png", L"blendedgecorner.png", L"blendedgetwocorners.png", L"blendfourcorners.png", L"blendtwooppositecorners.png", L"blendlshapecorner.png", L"blendtwocorners.png", L"blendcorner.png", L"blendtwoedges.png", L"blendthreecorners.png", L"blendushape.png", L"blendbad.png" }; size_t base = 0; // texture width/height (see below) // for convenience, we require all alpha maps to be of the same BPP // (avoids another ogl_tex_get_size call, and doesn't hurt) size_t bpp = 0; - for(size_t i=0;i data; - AllocateAligned(data, total_w*total_h, maxSectorSize); + AllocateAligned(data, totalWidth * totalHeight, maxSectorSize); // for each tile on row - for (size_t i = 0; i < NUM_ALPHA_MAPS; i++) + for (size_t i = 0; i < NUM_ALPHA_MAPS; ++i) { // get src of copy u8* src = 0; ignore_result(ogl_tex_get_data(textures[i], &src)); - size_t srcstep = bpp/8; + const size_t srcStep = bpp / 8; // get destination of copy - u8* dst = data.get() + (i*tile_w); + u8* dst = data.get() + (i * tileWidth); // for each row of image - for (size_t j = 0; j < base; j++) + for (size_t j = 0; j < base; ++j) { // duplicate first pixel *dst++ = *src; *dst++ = *src; // copy a row - for (size_t k = 0; k < base; k++) + for (size_t k = 0; k < base; ++k) { *dst++ = *src; - src += srcstep; + src += srcStep; } // duplicate last pixel - *dst++ = *(src-srcstep); - *dst++ = *(src-srcstep); + *dst++ = *(src - srcStep); + *dst++ = *(src - srcStep); // advance write pointer for next row - dst += total_w-tile_w; + dst += totalWidth - tileWidth; } - result.m_AlphaMapCoords[i].u0 = float(i*tile_w+2) / float(total_w); - result.m_AlphaMapCoords[i].u1 = float((i+1)*tile_w-2) / float(total_w); + result.m_AlphaMapCoords[i].u0 = static_cast(i * tileWidth + 2) / totalWidth; + result.m_AlphaMapCoords[i].u1 = static_cast((i + 1) * tileWidth - 2) / totalWidth; result.m_AlphaMapCoords[i].v0 = 0.0f; result.m_AlphaMapCoords[i].v1 = 1.0f; } for (size_t i = 0; i < NUM_ALPHA_MAPS; i++) ignore_result(ogl_tex_free(textures[i])); // upload the composite texture Tex t; - ignore_result(t.wrap(total_w, total_h, 8, TEX_GREY, data, 0)); + ignore_result(t.wrap(totalWidth, totalHeight, 8, TEX_GREY, data, 0)); // uncomment the following to save a png of the generated texture // in the public/ directory, for debugging /*VfsPath filename("blendtex.png"); DynArray da; RETURN_STATUS_IF_ERR(tex_encode(&t, filename.Extension(), &da)); // write to disk //Status ret = INFO::OK; { std::shared_ptr file = DummySharedPtr(da.base); const ssize_t bytes_written = g_VFS->CreateFile(filename, file, da.pos); if(bytes_written > 0) ENSURE(bytes_written == (ssize_t)da.pos); //else // ret = (Status)bytes_written; } ignore_result(da_free(&da));*/ Handle hCompositeAlphaMap = ogl_tex_wrap(&t, g_VFS, key); ignore_result(ogl_tex_set_filter(hCompositeAlphaMap, GL_LINEAR)); ignore_result(ogl_tex_set_wrap (hCompositeAlphaMap, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE)); ogl_tex_upload(hCompositeAlphaMap, GL_ALPHA, 0, 0); result.m_hCompositeAlphaMap = hCompositeAlphaMap; m_TerrainAlpha = it; } Index: ps/trunk/source/graphics/TerrainTextureEntry.h =================================================================== --- ps/trunk/source/graphics/TerrainTextureEntry.h (revision 26117) +++ ps/trunk/source/graphics/TerrainTextureEntry.h (revision 26118) @@ -1,95 +1,91 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #ifndef INCLUDED_TERRAINTEXTUREENTRY #define INCLUDED_TERRAINTEXTUREENTRY -#include "TerrainTextureManager.h" -#include "TextureManager.h" -#include "Material.h" - -#include "lib/res/handle.h" +#include "graphics/Material.h" +#include "graphics/TerrainTextureManager.h" +#include "graphics/TextureManager.h" #include "lib/file/vfs/vfs_path.h" +#include "lib/res/handle.h" #include "maths/Matrix3D.h" #include "ps/CStr.h" #include -////////////////////////////////////////////////////////////////////////////////////////////////////////// // CTerrainTextureEntry: class wrapping a terrain texture object; contains various other required // elements - color of minimap, terrain "group" it belongs to, etc class CTerrainTextureEntry { public: - typedef std::vector GroupVector; - -private: - // Tag = file name stripped of path and extension (grass_dark_1) - CStr m_Tag; - - // The property sheet used by this texture - CTerrainPropertiesPtr m_pProperties; - - CMaterial m_Material; - - CMatrix3D m_TextureMatrix; - - // BGRA color of topmost mipmap level, for coloring minimap, or a color - // specified by the terrain properties - u32 m_BaseColor; - // ..Valid is true if the base color has been cached - bool m_BaseColorValid; - - // All terrain type groups we're a member of - GroupVector m_Groups; - - // calculate the root color of the texture, used for coloring minimap - void BuildBaseColor(); + using GroupVector = std::vector; - void LoadAlphaMaps(VfsPath &amtype); - -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); ~CTerrainTextureEntry(); const CStr& GetTag() const { return m_Tag; } const CTerrainProperties& GetProperties() const { return *m_pProperties; } // Get texture handle, load texture if not loaded. const CTexturePtr& GetTexture() const { return m_Material.GetDiffuseTexture(); } const CMaterial& GetMaterial() const { return m_Material; } // Returns a matrix of the form [c 0 -s 0; -s 0 -c 0; 0 0 0 0; 0 0 0 1] // mapping world-space (x,y,z,1) coordinates onto (u,v,0,1) texcoords const float* GetTextureMatrix() const; // Get mipmap color in BGRA format u32 GetBaseColor() { if (!m_BaseColorValid) BuildBaseColor(); return m_BaseColor; } - //TerrainAlpha *m_TerrainAlpha; CTerrainTextureManager::TerrainAlphaMap::iterator m_TerrainAlpha; + +private: + // Tag = file name stripped of path and extension (grass_dark_1) + CStr m_Tag; + + // The property sheet used by this texture + CTerrainPropertiesPtr m_pProperties; + + CMaterial m_Material; + + CMatrix3D m_TextureMatrix; + + // BGRA color of topmost mipmap level, for coloring minimap, or a color + // specified by the terrain properties + u32 m_BaseColor; + // ..Valid is true if the base color has been cached + bool m_BaseColorValid; + + // All terrain type groups we're a member of + GroupVector m_Groups; + + // calculate the root color of the texture, used for coloring minimap + void BuildBaseColor(); + + void LoadAlphaMaps(const VfsPath& alphaMapType); }; #endif