Alpha 27 | Art| Fix: "Garrisoned" prop point for Athenian "Parthenon" Wonder model
[0ad.git] / source / graphics / ShaderDefines.cpp
blob064cde5be380405b9749bef2b0e5edffb21470f9
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 "ShaderDefines.h"
22 #include "graphics/ShaderProgram.h"
23 #include "lib/hash.h"
24 #include "maths/Vector4D.h"
25 #include "ps/ThreadUtil.h"
27 #include <algorithm>
28 #include <sstream>
30 namespace std
32 template<>
33 struct hash<CVector4D>
35 std::size_t operator()(const CVector4D& v) const
37 size_t hash = 0;
38 hash_combine(hash, v.X);
39 hash_combine(hash, v.Y);
40 hash_combine(hash, v.Z);
41 hash_combine(hash, v.W);
42 return hash;
47 bool operator==(const CShaderParams<CStrIntern>::SItems& a, const CShaderParams<CStrIntern>::SItems& b)
49 return a.items == b.items;
52 bool operator==(const CShaderParams<CVector4D>::SItems& a, const CShaderParams<CVector4D>::SItems& b)
54 return a.items == b.items;
57 template<typename value_t>
58 bool CShaderParams<value_t>::SItems::NameLess(const Item& a, const Item& b)
60 return a.first < b.first;
63 template<typename value_t>
64 typename CShaderParams<value_t>::SItems* CShaderParams<value_t>::GetInterned(const SItems& items)
66 ENSURE(Threading::IsMainThread()); // s_InternedItems is not thread-safe
68 typename InternedItems_t::iterator it = s_InternedItems.find(items);
69 if (it != s_InternedItems.end())
70 return it->second.get();
72 // Sanity test: the items list is meant to be sorted by name.
73 // This is a reasonable place to verify that, since this will be called once per distinct SItems.
74 ENSURE(std::is_sorted(items.items.begin(), items.items.end(), SItems::NameLess));
76 std::shared_ptr<SItems> ptr = std::make_shared<SItems>(items);
77 s_InternedItems.insert(std::make_pair(items, ptr));
78 return ptr.get();
81 template<typename value_t>
82 CShaderParams<value_t>::CShaderParams()
84 *this = s_Empty;
87 template<typename value_t>
88 CShaderParams<value_t>::CShaderParams(SItems* items) : m_Items(items)
92 template<typename value_t>
93 CShaderParams<value_t> CShaderParams<value_t>::CreateEmpty()
95 SItems items;
96 items.RecalcHash();
97 return CShaderParams(GetInterned(items));
100 template<typename value_t>
101 void CShaderParams<value_t>::Set(CStrIntern name, const value_t& value)
103 SItems items = *m_Items;
105 typename SItems::Item addedItem = std::make_pair(name, value);
107 // Add the new item in a way that preserves the sortedness and uniqueness of item names
108 for (typename std::vector<typename SItems::Item>::iterator it = items.items.begin(); ; ++it)
110 if (it == items.items.end() || addedItem.first < it->first)
112 items.items.insert(it, addedItem);
113 break;
115 else if (addedItem.first == it->first)
117 it->second = addedItem.second;
118 break;
122 items.RecalcHash();
123 m_Items = GetInterned(items);
126 template<typename value_t>
127 void CShaderParams<value_t>::SetMany(const CShaderParams& params)
129 SItems items;
130 // set_union merges the two sorted lists into a new sorted list;
131 // if two items are equivalent (i.e. equal names, possibly different values)
132 // then the one from the first list is kept
133 std::set_union(
134 params.m_Items->items.begin(), params.m_Items->items.end(),
135 m_Items->items.begin(), m_Items->items.end(),
136 std::inserter(items.items, items.items.begin()),
137 SItems::NameLess);
138 items.RecalcHash();
139 m_Items = GetInterned(items);
142 template<typename value_t>
143 std::map<CStrIntern, value_t> CShaderParams<value_t>::GetMap() const
145 std::map<CStrIntern, value_t> ret;
146 for (size_t i = 0; i < m_Items->items.size(); ++i)
147 ret[m_Items->items[i].first] = m_Items->items[i].second;
148 return ret;
151 template<typename value_t>
152 size_t CShaderParams<value_t>::GetHash() const
154 return m_Items->hash;
157 template<typename value_t>
158 void CShaderParams<value_t>::SItems::RecalcHash()
160 size_t h = 0;
161 for (size_t i = 0; i < items.size(); ++i)
163 hash_combine(h, items[i].first);
164 hash_combine(h, items[i].second);
166 hash = h;
170 void CShaderDefines::Add(CStrIntern name, CStrIntern value)
172 Set(name, value);
175 int CShaderDefines::GetInt(const char* name) const
177 CStrIntern nameIntern(name);
178 for (size_t i = 0; i < m_Items->items.size(); ++i)
180 if (m_Items->items[i].first == nameIntern)
182 int ret;
183 std::stringstream str(m_Items->items[i].second.c_str());
184 str >> ret;
185 return ret;
188 return 0;
192 void CShaderUniforms::Add(const char* name, const CVector4D& value)
194 Set(CStrIntern(name), value);
197 CVector4D CShaderUniforms::GetVector(const char* name) const
199 CStrIntern nameIntern(name);
200 for (size_t i = 0; i < m_Items->items.size(); ++i)
202 if (m_Items->items[i].first == nameIntern)
204 return m_Items->items[i].second;
207 return CVector4D();
210 void CShaderUniforms::BindUniforms(
211 Renderer::Backend::IDeviceCommandContext* deviceCommandContext,
212 Renderer::Backend::IShaderProgram* shader) const
214 for (const SItems::Item& item : m_Items->items)
216 const CVector4D& v = item.second;
217 deviceCommandContext->SetUniform(
218 shader->GetBindingSlot(item.first), v.AsFloatArray());
222 void CShaderRenderQueries::Add(const char* name)
224 if (name == CStr("sim_time"))
226 m_Items.emplace_back(RQUERY_TIME, CStrIntern(name));
228 else if (name == CStr("water_tex"))
230 m_Items.emplace_back(RQUERY_WATER_TEX, CStrIntern(name));
232 else if (name == CStr("sky_cube"))
234 m_Items.emplace_back(RQUERY_SKY_CUBE, CStrIntern(name));
238 // Explicit instantiations:
240 template<> CShaderParams<CStrIntern>::InternedItems_t CShaderParams<CStrIntern>::s_InternedItems = CShaderParams<CStrIntern>::InternedItems_t();
241 template<> CShaderParams<CVector4D>::InternedItems_t CShaderParams<CVector4D>::s_InternedItems = CShaderParams<CVector4D>::InternedItems_t();
243 template<> CShaderParams<CStrIntern> CShaderParams<CStrIntern>::s_Empty = CShaderParams<CStrIntern>::CreateEmpty();
244 template<> CShaderParams<CVector4D> CShaderParams<CVector4D>::s_Empty = CShaderParams<CVector4D>::CreateEmpty();
246 template class CShaderParams<CStrIntern>;
247 template class CShaderParams<CVector4D>;