/
ShaderLibrary.cpp
189 lines (148 loc) · 5.94 KB
/
ShaderLibrary.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#include "ShaderLibrary.h"
#include <utility>
#include "iimage.h"
#include "itextstream.h"
#include "ShaderTemplate.h"
namespace shaders
{
// Insert into the definitions map, if not already present
bool ShaderLibrary::addDefinition(const std::string& name,
const ShaderDefinition& def)
{
std::pair<ShaderDefinitionMap::iterator, bool> result = _definitions.insert(
ShaderDefinitionMap::value_type(name, def)
);
return result.second;
}
std::shared_ptr<ShaderTemplate> ShaderLibrary::getTemplate(const std::string& name)
{
auto decl = std::static_pointer_cast<ShaderTemplate>(
GlobalDeclarationManager().findDeclaration(decl::Type::Material, name));
if (decl)
{
return decl;
}
// The shader definition hasn't been found, let's check if the name
// refers to a file in the VFS
if (auto img = GlobalImageLoader().imageFromVFS(name); img)
{
// Insert a new declaration, creating a diffusemap with that image
decl = std::static_pointer_cast<ShaderTemplate>(
GlobalDeclarationManager().findOrCreateDeclaration(decl::Type::Material, name));
auto imgExpr = std::make_shared<ImageExpression>(name);
decl->addLayer(IShaderLayer::DIFFUSE, imgExpr);
decl->setFileInfo(vfs::FileInfo("materials/", "_autogenerated_by_darkradiant_.mtr", vfs::Visibility::HIDDEN));
return decl;
}
rWarning() << "ShaderLibrary: definition not found: " << name << std::endl;
// Insert a new declaration, creating a diffusemap with that image
decl = std::static_pointer_cast<ShaderTemplate>(
GlobalDeclarationManager().findOrCreateDeclaration(decl::Type::Material, name));
decl->setDescription("This material is missing and has been auto-generated by DarkRadiant");
// Make the definition VFS-visible to let them show in MediaBrowser (#5475)
decl->setFileInfo(vfs::FileInfo("materials/", "_autogenerated_by_darkradiant_.mtr", vfs::Visibility::NORMAL));
return decl;
}
bool ShaderLibrary::definitionExists(const std::string& name) const
{
return GlobalDeclarationManager().findDeclaration(decl::Type::Material, name) != nullptr;
}
void ShaderLibrary::copyDefinition(const std::string& nameOfOriginal, const std::string& nameOfCopy)
{
// These need to be checked by the caller
assert(definitionExists(nameOfOriginal));
assert(!definitionExists(nameOfCopy));
auto originalDecl = GlobalDeclarationManager().findDeclaration(decl::Type::Material, nameOfOriginal);
auto decl = GlobalDeclarationManager().findOrCreateDeclaration(decl::Type::Material, nameOfCopy);
// Replace the syntax block of the target with the one of the original
auto syntax = originalDecl->getBlockSyntax();
syntax.fileInfo = vfs::FileInfo{ "", "", vfs::Visibility::HIDDEN };
decl->setBlockSyntax(syntax);
}
bool ShaderLibrary::renameDefinition(const std::string& oldName, const std::string& newName)
{
auto result = GlobalDeclarationManager().renameDeclaration(decl::Type::Material, oldName, newName);
#if 0
// These need to be checked by the caller
assert(definitionExists(oldName));
assert(!definitionExists(newName));
// Rename in definition table
auto extracted = _definitions.extract(oldName);
extracted.key() = newName;
_definitions.insert(std::move(extracted));
#endif
// Rename in shaders table (if existing)
if (result && _shaders.count(oldName) > 0)
{
auto extractedShader = _shaders.extract(oldName);
extractedShader.key() = newName;
// Insert it under the new name before setting the CShader instance's name
// the observing OpenGLShader instance will request the material to reconstruct itself
// If the new name is not present at that point, the library will create a default material.
auto insertedShader = _shaders.insert(std::move(extractedShader));
// Rename the CShader instance
insertedShader.position->second->setName(newName);
}
return result;
}
void ShaderLibrary::removeDefinition(const std::string& name)
{
assert(definitionExists(name));
GlobalDeclarationManager().removeDeclaration(decl::Type::Material, name);
#if 0
_definitions.erase(name);
#endif
_shaders.erase(name);
}
ShaderDefinition& ShaderLibrary::getEmptyDefinition()
{
if (!_emptyDefinition)
{
auto shaderTemplate = std::make_shared<ShaderTemplate>("_emptyTemplate", "\n"
"\"description\"\t\"This material is internal and has no corresponding declaration\"");
_emptyDefinition = std::make_unique<ShaderDefinition>(shaderTemplate,
vfs::FileInfo("materials/", "_autogenerated_by_darkradiant_.mtr", vfs::Visibility::HIDDEN));
}
return *_emptyDefinition;
}
CShaderPtr ShaderLibrary::findShader(const std::string& name)
{
// Try to lookup the shader in the active shaders list
auto existing = _shaders.find(name);
if (existing != _shaders.end())
{
// A shader has been found, return its pointer
return existing->second;
}
// No shader has been found, retrieve its declaration (may also be a dummy one)
auto decl = getTemplate(name);
// Construct a new shader object with this def and insert it into the map
return _shaders.emplace(name, std::make_shared<CShader>(name, decl)).first->second;
}
void ShaderLibrary::clear()
{
_shaders.clear();
_definitions.clear();
}
std::size_t ShaderLibrary::getNumDefinitions()
{
return _definitions.size();
}
void ShaderLibrary::foreachShaderName(const ShaderNameCallback& callback)
{
GlobalDeclarationManager().foreachDeclaration(decl::Type::Material, [&](const decl::IDeclaration::Ptr& decl)
{
if (decl->getBlockSyntax().fileInfo.visibility == vfs::Visibility::NORMAL)
{
callback(decl->getDeclName());
}
});
}
void ShaderLibrary::foreachShader(const std::function<void(const CShaderPtr&)>& func)
{
for (const ShaderMap::value_type& pair : _shaders)
{
func(pair.second);
}
}
} // namespace shaders