-
Notifications
You must be signed in to change notification settings - Fork 47
/
ShaderLibrary.cpp
145 lines (112 loc) · 4.74 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
#include "ShaderLibrary.h"
#include <utility>
#include "iimage.h"
#include "itextstream.h"
#include "ShaderTemplate.h"
namespace shaders
{
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.name = nameOfCopy;
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);
// 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);
_shaders.erase(name);
}
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();
}
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