spacebox/src/Model.cpp

296 lines
6.7 KiB
C++

/* +------------------------------------------------------+
____/ \____ /| - Open source game framework licensed to freely use, |
\ / / | copy, modify and sell without restriction |
+--\ ^__^ /--+ | |
| ~/ \~ | | - created for <https://foam.shampoo.ooo> |
| ~~~~~~~~~~~~ | +------------------------------------------------------+
| SPACE ~~~~~ | /
| ~~~~~~~ BOX |/
+-------------*/
#include "Model.hpp"
sb::Model::Model(const std::map<std::string, std::shared_ptr<sb::Attributes>>& attributes_pack)
{
for (auto attributes : attributes_pack)
{
this->attributes(attributes.second, attributes.first);
}
}
sb::Model::Model(const std::map<std::string, sb::Attributes>& attributes_pack)
{
for (auto attributes : attributes_pack)
{
this->attributes(attributes.second, attributes.first);
}
}
sb::Model::Model(const std::initializer_list<std::string>& names)
{
for (const std::string& name : names)
{
this->attributes(sb::Attributes(), name);
}
}
std::map<std::string, std::shared_ptr<sb::Attributes>>& sb::Model::attributes()
{
return _attributes;
}
const std::map<std::string, std::shared_ptr<sb::Attributes>>& sb::Model::attributes() const
{
return _attributes;
}
std::shared_ptr<sb::Attributes>& sb::Model::attributes(const std::string& name)
{
return attributes().at(name);
}
const std::shared_ptr<sb::Attributes>& sb::Model::attributes(const std::string& name) const
{
return attributes().at(name);
}
void sb::Model::attributes(const sb::Attributes& attributes, const std::string& name)
{
this->attributes(std::make_shared<sb::Attributes>(attributes), name);
}
void sb::Model::attributes(const std::shared_ptr<sb::Attributes>& attributes, const std::string& name)
{
this->attributes()[name] = attributes;
}
std::shared_ptr<sb::Attributes>& sb::Model::operator[](const std::string& name)
{
auto element = attributes().find(name);
/* add an empty Attributes at name if it doesn't exist yet */
if (element == attributes().end())
{
attributes(sb::Attributes{}, name);
}
return attributes()[name];
}
void sb::Model::enable() const
{
for (const auto& attributes : this->attributes())
{
try
{
attributes.second->enable();
}
catch (const std::runtime_error& error)
{
std::ostringstream message;
message << "Error enabling " << attributes.first << " attributes on model: " << error.what();
throw std::runtime_error(message.str());
}
}
}
void sb::Model::disable() const
{
for (const auto& attributes : this->attributes())
{
attributes.second->disable();
}
}
const std::vector<sb::Texture>& sb::Model::textures() const
{
return _textures;
}
std::vector<sb::Texture>& sb::Model::textures()
{
return _textures;
}
const sb::Texture& sb::Model::texture(int index) const
{
if (textures().empty())
{
throw std::out_of_range("There are no textures attached to this model.");
}
else
{
return textures()[glm::mod(index, static_cast<int>(textures().size()))];
}
}
sb::Texture& sb::Model::texture(int index)
{
if (textures().empty())
{
throw std::out_of_range("There are no textures attached to this model.");
}
else
{
return textures()[glm::mod(index, static_cast<int>(textures().size()))];
}
}
void sb::Model::texture(const sb::Texture& texture)
{
textures().push_back(texture);
}
void sb::Model::load()
{
for (sb::Texture& texture : textures())
{
texture.load();
}
}
void sb::Model::add(sb::VBO& vbo)
{
for (auto& [name, attributes] : attributes())
{
vbo.add(*attributes);
}
}
void sb::Model::bind_textures() const
{
for (const sb::Texture& texture : textures())
{
try
{
texture.bind();
}
catch (const std::runtime_error& error)
{
std::ostringstream message;
message << "Error binding " << *this << ": " << error.what();
throw std::runtime_error(message.str());
}
}
}
void sb::Model::bind_attributes() const
{
for (auto& [name, attributes] : attributes())
{
try
{
attributes->bind();
}
catch (const std::runtime_error& error)
{
std::ostringstream message;
message << "Error binding " << *this << ": " << error.what();
throw std::runtime_error(message.str());
}
}
}
void sb::Model::bind() const
{
bind_textures();
bind_attributes();
}
const glm::mat4& sb::Model::transformation() const
{
return _transformation;
}
const glm::mat4& sb::Model::transform(const glm::mat4& transformation)
{
_transformation *= transformation;
return this->transformation();
}
const glm::mat4& sb::Model::untransform()
{
_transformation = glm::mat4(1.0f);
return transformation();
}
const glm::mat4& sb::Model::scale(const glm::vec3& scale)
{
return transform(glm::scale(scale));
}
const glm::mat4& sb::Model::rotate(float angle, glm::vec3 axis)
{
return transform(glm::rotate(angle, axis));
}
const glm::mat4& sb::Model::translate(glm::vec3 translation)
{
return transform(glm::translate(translation));
}
std::size_t sb::Model::size() const
{
std::size_t sum = 0;
for (const auto& attributes : this->attributes())
{
sum += attributes.second->size();
}
return sum;
}
sb::Model::operator glm::mat4() const
{
return _transformation;
}
sb::Model::operator std::string() const
{
std::ostringstream message;
message << "<sb::Model with " << _textures.size() << " textures";
if (_attributes.size() > 0)
{
message << " and " << _attributes.size() << " attributes ( ";
for (const auto& [name, attributes] : _attributes)
{
message << name << " ";
}
message << ")";
}
message << ">";
return message.str();
}
std::ostream& sb::operator<<(std::ostream& out, const sb::Model& model)
{
out << std::string(model);
return out;
}
sb::PlaneDoubleBuffer::PlaneDoubleBuffer() : Plane()
{
texture(sb::Texture());
texture(sb::Texture());
}
void sb::PlaneDoubleBuffer::generate(const glm::vec2& size)
{
for (sb::Texture* buffer : {&texture(FRONT), &texture(BACK)})
{
buffer->generate(size);
}
}
sb::Texture& sb::PlaneDoubleBuffer::active()
{
return swapped ? texture(BACK) : texture(FRONT);
}
sb::Texture& sb::PlaneDoubleBuffer::inactive()
{
return swapped ? texture(FRONT) : texture(BACK);
}
void sb::PlaneDoubleBuffer::swap()
{
swapped = !swapped;
}