/* +------------------------------------------------------+ ____/ \____ /| - Open source game framework licensed to freely use, | \ / / | copy, modify and sell without restriction | +--\ ^__^ /--+ | | | ~/ \~ | | - created for | | ~~~~~~~~~~~~ | +------------------------------------------------------+ | SPACE ~~~~~ | / | ~~~~~~~ BOX |/ +-------------*/ #include "Model.hpp" sb::Model::Model(const std::map>& attributes_pack) { for (auto attributes : attributes_pack) { this->attributes(attributes.second, attributes.first); } } sb::Model::Model(const std::map& attributes_pack) { for (auto attributes : attributes_pack) { this->attributes(attributes.second, attributes.first); } } sb::Model::Model(const std::initializer_list& names) { for (const std::string& name : names) { this->attributes(sb::Attributes(), name); } } std::map>& sb::Model::attributes() { return _attributes; } const std::map>& sb::Model::attributes() const { return _attributes; } std::shared_ptr& sb::Model::attributes(const std::string& name) { return attributes().at(name); } const std::shared_ptr& 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(attributes), name); } void sb::Model::attributes(const std::shared_ptr& attributes, const std::string& name) { this->attributes()[name] = attributes; } std::shared_ptr& 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::Model::textures() const { return _textures; } std::vector& 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(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(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 << " 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; }