/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2016 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #include #include #include #include #include namespace { const std::string _loggerCat = "ModelGeometry"; const std::string keyGeomModelFile = "GeometryFile"; const int8_t CurrentCacheVersion = 3; const std::string keyType = "Type"; const std::string keyName = "Name"; const std::string keySize = "Magnification"; } namespace openspace { namespace modelgeometry { ModelGeometry* ModelGeometry::createFromDictionary(const ghoul::Dictionary& dictionary) { std::string geometryType; const bool success = dictionary.getValue( keyType, geometryType); if (!success) { LERROR("ModelGeometry did not contain a correct value of the key '" << keyType << "'"); return nullptr; } ghoul::TemplateFactory* factory = FactoryManager::ref().factory(); ModelGeometry* result = factory->create(geometryType, dictionary); if (result == nullptr) { LERROR("Failed to create a ModelGeometry object of type '" << geometryType << "'"); return nullptr; } return result; } ModelGeometry::ModelGeometry(const ghoul::Dictionary& dictionary) : _parent(nullptr) , _magnification("magnification", "Magnification", 0.f, 0.f, 10.f) , _mode(GL_TRIANGLES) { setName("ModelGeometry"); std::string name; bool success = dictionary.getValue(keyName, name); ghoul_assert(success, "Name tag was not present"); if (dictionary.hasKeyAndValue(keySize)) _magnification = static_cast(dictionary.value(keySize)); success = dictionary.getValue(keyGeomModelFile, _file); if (!success) { LERROR("Geometric Model file of '" << name << "' did not provide a key '" << keyGeomModelFile << "'"); } _file = FileSys.absolutePath(_file); if (!FileSys.fileExists(_file, ghoul::filesystem::FileSystem::RawPath::Yes)) LERROR("Could not load the geometric model file '" << _file << "': File not found"); addProperty(_magnification); } ModelGeometry::~ModelGeometry() { } void ModelGeometry::render() { glBindVertexArray(_vaoID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo); glDrawElements(_mode, static_cast(_indices.size()), GL_UNSIGNED_INT, 0); glBindVertexArray(0); } void ModelGeometry::changeRenderMode(const GLenum mode) { _mode = mode; } bool ModelGeometry::initialize(Renderable* parent) { _parent = parent; PowerScaledScalar ps = PowerScaledScalar(1.0, 0.0); // will set proper bounding soon. _parent->setBoundingSphere(ps); if (_vertices.empty()) return false; glGenVertexArrays(1, &_vaoID); glGenBuffers(1, &_vbo); glGenBuffers(1, &_ibo); glBindVertexArray(_vaoID); glBindBuffer(GL_ARRAY_BUFFER, _vbo); glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(Vertex), _vertices.data(), GL_STATIC_DRAW); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast(offsetof(Vertex, location))); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast(offsetof(Vertex, tex))); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast(offsetof(Vertex, normal))); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices.size() * sizeof(int), _indices.data(), GL_STATIC_DRAW); glBindVertexArray(0); return true; } void ModelGeometry::deinitialize() { glDeleteBuffers(1, &_vbo); glDeleteVertexArrays(1, &_vaoID); glDeleteBuffers(1, &_ibo); } bool ModelGeometry::loadObj(const std::string& filename) { std::string cachedFile = FileSys.cacheManager()->cachedFilename( filename, ghoul::filesystem::CacheManager::Persistent::Yes ); bool hasCachedFile = FileSys.fileExists(cachedFile); if (hasCachedFile) { LINFO("Cached file '" << cachedFile << "' used for Model file '" << filename << "'"); bool success = loadCachedFile(cachedFile); if (success) return true; else FileSys.cacheManager()->removeCacheFile(filename); // Intentional fall-through to the 'else' computation to generate the cache // file for the next run } else { LINFO("Cached file '" << cachedFile << "' used for Model file '" << filename << "' not found"); } LINFO("Loading Model file '" << filename << "'"); bool success = loadModel(filename); if (!success) return false; LINFO("Saving cache"); success = saveCachedFile(cachedFile); return success; } bool ModelGeometry::saveCachedFile(const std::string& filename) { std::ofstream fileStream(filename, std::ofstream::binary); if (fileStream.good()) { fileStream.write(reinterpret_cast(&CurrentCacheVersion), sizeof(int8_t)); int64_t vSize = _vertices.size(); fileStream.write(reinterpret_cast(&vSize), sizeof(int64_t)); int64_t iSize = _indices.size(); fileStream.write(reinterpret_cast(&iSize), sizeof(int64_t)); fileStream.write(reinterpret_cast(_vertices.data()), sizeof(Vertex) * vSize); fileStream.write(reinterpret_cast(_indices.data()), sizeof(int) * iSize); return fileStream.good(); } else { LERROR("Error opening file '" << filename << "' for save cache file"); return false; } } bool ModelGeometry::loadCachedFile(const std::string& filename) { std::ifstream fileStream(filename, std::ifstream::binary); if (fileStream.good()) { int8_t version = 0; fileStream.read(reinterpret_cast(&version), sizeof(int8_t)); if (version != CurrentCacheVersion) { LINFO("The format of the cached file has changed, deleting old cache"); fileStream.close(); FileSys.deleteFile(filename); return false; } int64_t vSize, iSize; fileStream.read(reinterpret_cast(&vSize), sizeof(int64_t)); fileStream.read(reinterpret_cast(&iSize), sizeof(int64_t)); if (vSize == 0 || iSize == 0) { LERROR("Error opening file '" << filename << "' for loading cache file"); return false; } _vertices.resize(vSize); _indices.resize(iSize); fileStream.read(reinterpret_cast(_vertices.data()), sizeof(Vertex) * vSize); fileStream.read(reinterpret_cast(_indices.data()), sizeof(int) * iSize); return fileStream.good(); } else { LERROR("Error opening file '" << filename << "' for loading cache file"); return false; } } bool ModelGeometry::getVertices(std::vector* vertexList) { vertexList->clear(); for (auto v : _vertices) vertexList->push_back(v); return !(vertexList->empty()); } bool ModelGeometry::getIndices(std::vector* indexList) { indexList->clear(); for (auto i : _indices) indexList->push_back(i); return !(indexList->empty()); } void ModelGeometry::setUniforms(ghoul::opengl::ProgramObject& program) { program.setUniform("_magnification", _magnification); } } // namespace modelgeometry } // namespace openspace