2012-04-03 20:44:46 +02:00
|
|
|
/* Copyright (C) 2012 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "precompiled.h"
|
|
|
|
|
|
|
|
#include "ShaderDefines.h"
|
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
#include "maths/Vector4D.h"
|
2012-04-03 20:44:46 +02:00
|
|
|
#include "ps/ThreadUtil.h"
|
|
|
|
|
2012-04-13 17:01:51 +02:00
|
|
|
#include <sstream>
|
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
size_t hash_value(const CStrIntern& v)
|
|
|
|
{
|
|
|
|
return v.GetHash();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t hash_value(const CVector4D& v)
|
|
|
|
{
|
|
|
|
size_t hash = 0;
|
|
|
|
boost::hash_combine(hash, v.X);
|
|
|
|
boost::hash_combine(hash, v.Y);
|
|
|
|
boost::hash_combine(hash, v.Z);
|
|
|
|
boost::hash_combine(hash, v.W);
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t hash_value(const CShaderParams<CStrIntern>::SItems& items)
|
|
|
|
{
|
|
|
|
return items.hash;
|
|
|
|
}
|
2012-04-03 20:44:46 +02:00
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
size_t hash_value(const CShaderParams<CVector4D>::SItems& items)
|
2012-04-03 20:44:46 +02:00
|
|
|
{
|
|
|
|
return items.hash;
|
|
|
|
}
|
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
bool operator==(const CShaderParams<CStrIntern>::SItems& a, const CShaderParams<CStrIntern>::SItems& b)
|
2012-04-03 20:44:46 +02:00
|
|
|
{
|
|
|
|
return a.items == b.items;
|
|
|
|
}
|
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
bool operator==(const CShaderParams<CVector4D>::SItems& a, const CShaderParams<CVector4D>::SItems& b)
|
|
|
|
{
|
|
|
|
return a.items == b.items;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename value_t>
|
2012-04-03 20:44:46 +02:00
|
|
|
struct ItemNameCmp
|
|
|
|
{
|
2012-04-08 17:55:06 +02:00
|
|
|
typedef typename CShaderParams<value_t>::SItems::Item Item;
|
|
|
|
|
|
|
|
typedef Item first_argument_type;
|
|
|
|
typedef Item second_argument_type;
|
|
|
|
bool operator()(const Item& a, const Item& b) const
|
2012-04-03 20:44:46 +02:00
|
|
|
{
|
|
|
|
return a.first < b.first;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
template<typename value_t>
|
2012-04-03 20:44:46 +02:00
|
|
|
struct ItemNameGeq
|
|
|
|
{
|
2012-04-08 17:55:06 +02:00
|
|
|
typedef typename CShaderParams<value_t>::SItems::Item Item;
|
|
|
|
|
|
|
|
bool operator()(const Item& a, const Item& b) const
|
2012-04-03 20:44:46 +02:00
|
|
|
{
|
|
|
|
return !(b.first < a.first);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
template<typename value_t>
|
|
|
|
typename CShaderParams<value_t>::SItems* CShaderParams<value_t>::GetInterned(const SItems& items)
|
2012-04-03 20:44:46 +02:00
|
|
|
{
|
2012-04-08 17:55:06 +02:00
|
|
|
ENSURE(ThreadUtil::IsMainThread()); // s_InternedItems is not thread-safe
|
2012-04-03 20:44:46 +02:00
|
|
|
|
2012-04-08 19:44:29 +02:00
|
|
|
typename InternedItems_t::iterator it = s_InternedItems.find(items);
|
2012-04-08 17:55:06 +02:00
|
|
|
if (it != s_InternedItems.end())
|
2012-04-03 20:44:46 +02:00
|
|
|
return it->second.get();
|
|
|
|
|
|
|
|
// Sanity test: the items list is meant to be sorted by name.
|
|
|
|
// This is a reasonable place to verify that, since this will be called once per distinct SItems.
|
2012-04-08 17:55:06 +02:00
|
|
|
typedef ItemNameCmp<value_t> Cmp;
|
|
|
|
ENSURE(std::adjacent_find(items.items.begin(), items.items.end(), std::binary_negate<Cmp>(Cmp())) == items.items.end());
|
2012-04-03 20:44:46 +02:00
|
|
|
|
|
|
|
shared_ptr<SItems> ptr(new SItems(items));
|
2012-04-08 17:55:06 +02:00
|
|
|
s_InternedItems.insert(std::make_pair(items, ptr));
|
2012-04-03 20:44:46 +02:00
|
|
|
return ptr.get();
|
|
|
|
}
|
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
template<typename value_t>
|
|
|
|
CShaderParams<value_t>::CShaderParams()
|
2012-04-03 20:44:46 +02:00
|
|
|
{
|
|
|
|
SItems items;
|
|
|
|
items.RecalcHash();
|
|
|
|
m_Items = GetInterned(items);
|
|
|
|
}
|
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
template<typename value_t>
|
|
|
|
void CShaderParams<value_t>::Set(CStrIntern name, const value_t& value)
|
2012-04-03 20:44:46 +02:00
|
|
|
{
|
|
|
|
SItems items = *m_Items;
|
|
|
|
|
2012-04-08 19:44:29 +02:00
|
|
|
typename SItems::Item addedItem = std::make_pair(name, value);
|
2012-04-03 20:44:46 +02:00
|
|
|
|
|
|
|
// Add the new item in a way that preserves the sortedness and uniqueness of item names
|
2012-04-08 19:44:29 +02:00
|
|
|
for (typename std::vector<typename SItems::Item>::iterator it = items.items.begin(); ; ++it)
|
2012-04-03 20:44:46 +02:00
|
|
|
{
|
|
|
|
if (it == items.items.end() || addedItem.first < it->first)
|
|
|
|
{
|
|
|
|
items.items.insert(it, addedItem);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (addedItem.first == it->first)
|
|
|
|
{
|
|
|
|
it->second = addedItem.second;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
items.RecalcHash();
|
|
|
|
m_Items = GetInterned(items);
|
|
|
|
}
|
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
template<typename value_t>
|
|
|
|
void CShaderParams<value_t>::SetMany(const CShaderParams& params)
|
2012-04-03 20:44:46 +02:00
|
|
|
{
|
|
|
|
SItems items;
|
|
|
|
// set_union merges the two sorted lists into a new sorted list;
|
|
|
|
// if two items are equivalent (i.e. equal names, possibly different values)
|
|
|
|
// then the one from the first list is kept
|
|
|
|
std::set_union(
|
2012-04-08 17:55:06 +02:00
|
|
|
params.m_Items->items.begin(), params.m_Items->items.end(),
|
2012-04-03 20:44:46 +02:00
|
|
|
m_Items->items.begin(), m_Items->items.end(),
|
|
|
|
std::inserter(items.items, items.items.begin()),
|
2012-04-08 17:55:06 +02:00
|
|
|
ItemNameCmp<value_t>());
|
2012-04-03 20:44:46 +02:00
|
|
|
items.RecalcHash();
|
|
|
|
m_Items = GetInterned(items);
|
|
|
|
}
|
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
template<typename value_t>
|
|
|
|
std::map<CStrIntern, value_t> CShaderParams<value_t>::GetMap() const
|
2012-04-03 20:44:46 +02:00
|
|
|
{
|
2012-04-08 17:55:06 +02:00
|
|
|
std::map<CStrIntern, value_t> ret;
|
2012-04-03 20:44:46 +02:00
|
|
|
for (size_t i = 0; i < m_Items->items.size(); ++i)
|
2012-04-08 17:55:06 +02:00
|
|
|
ret[m_Items->items[i].first] = m_Items->items[i].second;
|
2012-04-03 20:44:46 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
template<typename value_t>
|
|
|
|
size_t CShaderParams<value_t>::GetHash() const
|
|
|
|
{
|
|
|
|
return m_Items->hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename value_t>
|
|
|
|
void CShaderParams<value_t>::SItems::RecalcHash()
|
|
|
|
{
|
|
|
|
size_t h = 0;
|
|
|
|
for (size_t i = 0; i < items.size(); ++i)
|
|
|
|
{
|
|
|
|
boost::hash_combine(h, items[i].first);
|
|
|
|
boost::hash_combine(h, items[i].second);
|
|
|
|
}
|
|
|
|
hash = h;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CShaderDefines::Add(const char* name, const char* value)
|
|
|
|
{
|
|
|
|
Set(CStrIntern(name), CStrIntern(value));
|
|
|
|
}
|
|
|
|
|
2012-04-03 20:44:46 +02:00
|
|
|
int CShaderDefines::GetInt(const char* name) const
|
|
|
|
{
|
|
|
|
CStrIntern nameIntern(name);
|
|
|
|
for (size_t i = 0; i < m_Items->items.size(); ++i)
|
|
|
|
{
|
|
|
|
if (m_Items->items[i].first == nameIntern)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
std::stringstream str(m_Items->items[i].second.c_str());
|
|
|
|
str >> ret;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
|
|
|
|
void CShaderUniforms::Add(const char* name, const CVector4D& value)
|
2012-04-03 20:44:46 +02:00
|
|
|
{
|
2012-04-08 17:55:06 +02:00
|
|
|
Set(CStrIntern(name), value);
|
2012-04-03 20:44:46 +02:00
|
|
|
}
|
|
|
|
|
2012-04-08 17:55:06 +02:00
|
|
|
CVector4D CShaderUniforms::GetVector(const char* name) const
|
2012-04-03 20:44:46 +02:00
|
|
|
{
|
2012-04-08 17:55:06 +02:00
|
|
|
CStrIntern nameIntern(name);
|
|
|
|
for (size_t i = 0; i < m_Items->items.size(); ++i)
|
|
|
|
{
|
|
|
|
if (m_Items->items[i].first == nameIntern)
|
|
|
|
{
|
|
|
|
return m_Items->items[i].second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return CVector4D();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CShaderUniforms::BindUniforms(const CShaderProgramPtr& shader) const
|
|
|
|
{
|
|
|
|
const std::vector<SItems::Item>& items = m_Items->items;
|
2012-04-03 20:44:46 +02:00
|
|
|
for (size_t i = 0; i < items.size(); ++i)
|
|
|
|
{
|
2012-04-08 17:55:06 +02:00
|
|
|
CShaderProgram::Binding binding = shader->GetUniformBinding(items[i].first);
|
|
|
|
if (binding.Active())
|
|
|
|
{
|
|
|
|
CVector4D v = items[i].second;
|
|
|
|
shader->Uniform(binding, v.X, v.Y, v.Z, v.W);
|
|
|
|
}
|
2012-04-03 20:44:46 +02:00
|
|
|
}
|
|
|
|
}
|
2012-04-08 17:55:06 +02:00
|
|
|
|
|
|
|
// Explicit instantiations:
|
|
|
|
|
2012-04-08 19:44:29 +02:00
|
|
|
template<> CShaderParams<CStrIntern>::InternedItems_t CShaderParams<CStrIntern>::s_InternedItems = CShaderParams<CStrIntern>::InternedItems_t();
|
|
|
|
template<> CShaderParams<CVector4D>::InternedItems_t CShaderParams<CVector4D>::s_InternedItems = CShaderParams<CVector4D>::InternedItems_t();
|
2012-04-08 17:55:06 +02:00
|
|
|
|
|
|
|
template class CShaderParams<CStrIntern>;
|
|
|
|
template class CShaderParams<CVector4D>;
|