From b4f6070642a04081ee3c8d72cb8280d10da1c80d Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 25 Nov 2014 19:15:59 +0100 Subject: [PATCH] Started cleanup of RenderableStars class --- ext/ghoul | 2 +- .../rendering/stars/renderablestars.h | 37 +- include/openspace/util/constants.h | 9 +- openspace-data | 2 +- src/rendering/stars/renderablestars.cpp | 445 ++++++++++-------- 5 files changed, 288 insertions(+), 207 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index d06a196c28..1a05da7f5c 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit d06a196c2895ab8f548c3e520690eb921f3437d4 +Subproject commit 1a05da7f5c345bf69894bacadf1783df9b081be8 diff --git a/include/openspace/rendering/stars/renderablestars.h b/include/openspace/rendering/stars/renderablestars.h index fa52926f29..445b9b219c 100644 --- a/include/openspace/rendering/stars/renderablestars.h +++ b/include/openspace/rendering/stars/renderablestars.h @@ -33,10 +33,9 @@ #include #include +namespace openspace { -namespace openspace{ - -class RenderableStars : public Renderable{ +class RenderableStars : public Renderable { public: RenderableStars(const ghoul::Dictionary& dictionary); ~RenderableStars(); @@ -47,12 +46,34 @@ public: void render(const RenderData& data) override; void update(const UpdateData& data) override; -protected: +private: + class DataSource { + public: + const std::vector& data() const; + + virtual bool loadData() = 0; + + protected: + std::vector _data; + }; + + class SpeckDataSource : public DataSource { + public: + SpeckDataSource(const ghoul::Dictionary& dictionary); + + bool loadData() override; + + private: + bool readSpeckFile(); + bool loadCachedFile(const std::string& file); + bool saveCachedFile(const std::string& file) const; + + std::string _file; + }; + + void loadTexture(); -private: - std::ifstream& skipToLine(std::ifstream& file, unsigned int num); - bool readSpeckFile(const std::string& path); void generateBufferObjects(const void* data); properties::StringProperty _colorTexturePath; @@ -64,6 +85,8 @@ private: std::string _speckPath; + DataSource* _source; + //GLint vertsToDraw; GLuint _vboID; diff --git a/include/openspace/util/constants.h b/include/openspace/util/constants.h index 18bcb36255..57d0a55d9d 100644 --- a/include/openspace/util/constants.h +++ b/include/openspace/util/constants.h @@ -88,8 +88,13 @@ namespace modelgeometry { } // namespace modelgeometry namespace renderablestars { - const std::string keySpeckFile = "SpeckFile"; - const std::string keyPathModule = "ModulePath"; + const std::string keyDataSource = "DataSource"; + const std::string keyTexture = "Texture"; + + namespace datasource { + const std::string keyType = "Type"; + const std::string keyFile = "File"; + } // namespace datasource } // namespace renderablestars namespace renderablevolumegl { diff --git a/openspace-data b/openspace-data index bdf9fefa78..3dc211027b 160000 --- a/openspace-data +++ b/openspace-data @@ -1 +1 @@ -Subproject commit bdf9fefa784d3c764c1e217dd438a400f51a72f3 +Subproject commit 3dc211027b3668e0cfd37bf1f6c7c0dec09a62e8 diff --git a/src/rendering/stars/renderablestars.cpp b/src/rendering/stars/renderablestars.cpp index 8ad791b18e..8473a40117 100644 --- a/src/rendering/stars/renderablestars.cpp +++ b/src/rendering/stars/renderablestars.cpp @@ -22,66 +22,66 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -//standard includes -#include -#include -#include -#include -#include -#include - -// openspace includes #include -#include -#include +#include +#include + +#include +#include #include #include -#include -#include -#include -#define _USE_MATH_DEFINES -#include - -#define GLSPRITES -//#define GLPOINTS +#include namespace { const std::string _loggerCat = "RenderableStars"; } namespace openspace { + RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _colorTexturePath("colorTexture", "Color Texture") , _haloProgram(nullptr) , _pointProgram(nullptr) , _texture(nullptr) + , _source(nullptr) { - std::string path; - dictionary.getValue(constants::renderablestars::keyPathModule, path); - std::string texturePath = ""; - if (dictionary.hasKey("Textures.Color")) { - dictionary.getValue("Textures.Color", texturePath); - _colorTexturePath = path + "/" + texturePath; + if (dictionary.hasKey(constants::renderablestars::keyTexture)) { + dictionary.getValue(constants::renderablestars::keyTexture, texturePath); + _colorTexturePath = absPath(texturePath); } - dictionary.getValue(constants::renderablestars::keySpeckFile, path); - _speckPath = FileSys.absolutePath(path); + ghoul::TemplateFactory sourceFactory; + sourceFactory.registerClass("Speck"); + + ghoul::Dictionary sourceDictionary; + bool success = dictionary.getValue(constants::renderablestars::keyDataSource, + sourceDictionary); + if (!success) { + LERROR("RenderableStars did not have key '" << + constants::renderablestars::keyDataSource << "'"); + return; + } + std::string type = ""; + success = sourceDictionary.getValue(constants::renderablestars::datasource::keyType, type); + if (!success) { + LERROR("DataSource did not have key '" << constants::renderablestars::datasource::keyType << "'"); + return; + } + + _source = sourceFactory.create(type, sourceDictionary); addProperty(_colorTexturePath); _colorTexturePath.onChange(std::bind(&RenderableStars::loadTexture, this)); } -RenderableStars::~RenderableStars(){ - glDeleteBuffers(1, &_vboID); - glDeleteVertexArrays(1, &_vaoID); - deinitialize(); +RenderableStars::~RenderableStars() { } -std::ifstream& RenderableStars::skipToLine(std::ifstream& file, unsigned int num){ +std::ifstream& skipToLine(std::ifstream& file, unsigned int num){ file.seekg(std::ios::beg); for (size_t i = 0; i < num - 1; ++i){ file.ignore(std::numeric_limits::max(), '\n'); @@ -89,139 +89,6 @@ std::ifstream& RenderableStars::skipToLine(std::ifstream& file, unsigned int num return file; } - -//#define ROTATESTARS - -bool RenderableStars::readSpeckFile(const std::string& path){ - - bool readCache = false; - - std::ifstream file; - std::string str, starDescription, datastr; - std::vector strvec; - std::vector starcluster; - std::vector floatingPointData; - - int count = 0; - const std::string absPath = FileSys.absolutePath(path); - std::string::size_type last - = absPath.find_last_of(ghoul::filesystem::FileSystem::PathSeparator); - if (last == std::string::npos) return false; - std::string cacheName = absPath.substr(last + 1, absPath.size() - absPath.rfind('.') - 1); - std::string basePath = absPath.substr(0, last); - cacheName = basePath + "\\" + cacheName + ".bin"; - - //if (!FileSys.fileExists(cacheName)){ - if (!readCache){ // dumb boolean for now. - std::ofstream cache; - cache.open(cacheName, std::ios::binary); - - file.open(absPath); - if (!file.is_open()){ - LERROR("Failed to open spec file for : '" << path << "'"); - return false; - } - // count metadata lines to skip. - do{ - getline(file, str); - count++; - } while (str[0] != ' '); - // set seek pointer to first line with actual data - skipToLine(file, count); - count = 0; - - do{ - getline(file, str); - if (file.eof()) break; - // split the line on pound symbol. we only want data. - std::size_t mid = str.find('#'); - if (mid != std::string::npos){ - datastr = str.substr(0, mid); - std::size_t end = str.find('\n'); - if (end == std::string::npos) - starDescription = str.substr(mid, end); - } - // split data string on whitespace -> push to to vector - std::istringstream ss(datastr); - std::copy(std::istream_iterator(ss), - std::istream_iterator(), - std::back_inserter >(strvec)); - ss.clear(); - // conv. string vector to doubles - floatingPointData.reserve(strvec.size()); - transform(strvec.begin(), strvec.end(), back_inserter(floatingPointData), - [](std::string const& val) {return std::stod(val); }); - // store data concerning apparent luminocity, brigthness etc. - // convert to powerscaled coordinate - psc powerscaled = PowerScaledCoordinate::CreatePowerScaledCoordinate(floatingPointData[0], - floatingPointData[1], - floatingPointData[2]); - // Convert parsecs -> meter - // Could convert floatingPointData instead ?? - // (possible as 3.4 × 10^38 is max rep nr of float) - PowerScaledScalar parsecsToMetersFactor = glm::vec2(0.308567758, 17); - powerscaled[0] *= parsecsToMetersFactor[0]; - powerscaled[1] *= parsecsToMetersFactor[0]; - powerscaled[2] *= parsecsToMetersFactor[0]; - powerscaled[3] += parsecsToMetersFactor[1]; - -#ifdef ROTATESTARS - glm::mat4 transform = glm::mat4(1); - - glm::dmat3 stateMatrix; - double initTime = 0; - openspace::SpiceManager::ref().getPositionTransformMatrixGLM("GALACTIC", "IAU_EARTH", 0, stateMatrix); - - for (int i = 0; i < 3; i++){ - for (int j = 0; j < 3; j++){ - transform[i][j] = stateMatrix[i][j]; - } - } - - glm::vec4 tmp(powerscaled[0], powerscaled[1], powerscaled[2], powerscaled[3] ); - tmp = transform*tmp; - - powerscaled[0] = tmp[0]; - powerscaled[1] = tmp[1]; - powerscaled[2] = tmp[2]; - powerscaled[3] = tmp[3]; -#endif - // We use std::vector to store data - // needs no preallocation and has tightly packed arr. - for (int i = 0; i < 4; i++){ - starcluster.push_back(powerscaled[i]); - cache << ' ' << powerscaled[i]; - } - // will need more elegant solution here. - starcluster.push_back(floatingPointData[3]); - starcluster.push_back(floatingPointData[4]); - starcluster.push_back(floatingPointData[5]); - - strvec.clear(); - floatingPointData.clear(); - count++; - } while (file.good()); - }else{ - LINFO("Found cached data, loading"); - file.open(cacheName, std::ios::binary); - while (file.good()){ - if (file.eof()) break; - count++; - float cachedValue; - file >> cachedValue; - starcluster.push_back(cachedValue); - } - } - v_stride = 7; // stride in VBO, set manually for now. - v_size = static_cast(starcluster.size()); // size of VBO - v_total = v_size / v_stride; // total number of vertecies - - // create vao and interleaved vbo from vectors internal array - generateBufferObjects(&starcluster[0]); - - return true; -} - void RenderableStars::generateBufferObjects(const void* data){ // generate and buffer data glGenVertexArrays(1, &_vaoID); @@ -262,9 +129,21 @@ bool RenderableStars::initialize(){ if (_pointProgram == nullptr) completeSuccess &= OsEng.ref().configurationManager().getValue("PointProgram", _pointProgram); - // Run read star-datafile routine. - if (!readSpeckFile(_speckPath)) - LERROR("Failed to read speck file for path : '" << _speckPath << "'"); + completeSuccess &= _source->loadData(); + + const std::vector& data = _source->data(); + + v_stride = 7; // stride in VBO, set manually for now. + v_size = static_cast(data.size()); // size of VBO + v_total = v_size / v_stride; // total number of vertecies + + // create vao and interleaved vbo from vectors internal array + generateBufferObjects(&data[0]); + + + //// Run read star-datafile routine. + //if (!readSpeckFile(_speckPath)) + // LERROR("Failed to read speck file for path : '" << _speckPath << "'"); loadTexture(); completeSuccess &= (_texture != nullptr); @@ -273,6 +152,9 @@ bool RenderableStars::initialize(){ } bool RenderableStars::deinitialize(){ + glDeleteBuffers(1, &_vboID); + glDeleteVertexArrays(1, &_vaoID); + delete _texture; _texture = nullptr; return true; @@ -303,7 +185,6 @@ void RenderableStars::render(const RenderData& data){ glEnable(GL_BLEND); glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE); -#ifdef GLSPRITES glm::mat4 modelMatrix = data.camera.modelMatrix(); glm::mat4 viewMatrix = data.camera.viewMatrix(); glm::mat4 projectionMatrix = data.camera.projectionMatrix(); @@ -328,34 +209,33 @@ void RenderableStars::render(const RenderData& data){ glBindVertexArray(_vaoID); glDrawArrays(GL_POINTS, 0, v_total); glBindVertexArray(0); -#endif _haloProgram->deactivate(); -#ifdef GLPOINTS - -// ---------------------- RENDER POINTS ----------------------------- - _pointProgram->activate(); - - _pointProgram->setUniform("ViewProjection", data.camera.viewProjectionMatrix); - _pointProgram->setUniform("ModelTransform", transform); - _pointProgram->setUniform("campos", campos.vec4()); - _pointProgram->setUniform("objpos", currentPosition.vec4()); - _pointProgram->setUniform("camrot", camrot); - //_pointProgram->setUniform("scaling", scaling.vec2()); - - glEnable(GL_PROGRAM_POINT_SIZE_EXT); // Allows shader to determine pointsize. - - //glEnable(GL_POINT_SMOOTH); // decrepated in core profile, workaround in frag. - glBindVertexArray(_vaoID); - glDrawArrays(GL_POINTS, 0, v_total*7); - glBindVertexArray(0); - - glDisable(GL_BLEND); - - _pointProgram->deactivate(); - glEnable(GL_DEPTH_TEST); - -#endif +//#ifdef GLPOINTS +// +//// ---------------------- RENDER POINTS ----------------------------- +// _pointProgram->activate(); +// +// _pointProgram->setUniform("ViewProjection", data.camera.viewProjectionMatrix); +// _pointProgram->setUniform("ModelTransform", transform); +// _pointProgram->setUniform("campos", campos.vec4()); +// _pointProgram->setUniform("objpos", currentPosition.vec4()); +// _pointProgram->setUniform("camrot", camrot); +// //_pointProgram->setUniform("scaling", scaling.vec2()); +// +// glEnable(GL_PROGRAM_POINT_SIZE_EXT); // Allows shader to determine pointsize. +// +// //glEnable(GL_POINT_SMOOTH); // decrepated in core profile, workaround in frag. +// glBindVertexArray(_vaoID); +// glDrawArrays(GL_POINTS, 0, v_total*7); +// glBindVertexArray(0); +// +// glDisable(GL_BLEND); +// +// _pointProgram->deactivate(); +// glEnable(GL_DEPTH_TEST); +// +//#endif glDisable(GL_BLEND); } @@ -376,5 +256,178 @@ void RenderableStars::update(const UpdateData& data) } - + +const std::vector& RenderableStars::DataSource::data() const { + return _data; +} + +RenderableStars::SpeckDataSource::SpeckDataSource(const ghoul::Dictionary& dictionary) + : DataSource() + , _file("") +{ + bool success = dictionary.getValue(constants::renderablestars::datasource::keyFile, _file); + if (!success) { + LERROR("SpeckDataSource did not contain key '" << + constants::renderablestars::datasource::keyFile << "'"); + return; + } + _file = absPath(_file); +} + +bool RenderableStars::SpeckDataSource::loadData() { + std::string cachedFile = ""; + FileSys.cacheManager()->getCachedFile(_file, cachedFile, true); + + bool hasCachedFile = FileSys.fileExists(cachedFile); + if (hasCachedFile) { + LINFO("Cached file '" << cachedFile << "' used for Speck file '" << _file << "'"); + + bool success = loadCachedFile(cachedFile); + if (success) + return true; + else + FileSys.cacheManager()->removeCacheFile(_file); + // Intentional fall-through to the 'else' computation to generate the cache + // file for the next run + } + else { + LINFO("Cache for Speck file '" << _file << "' not found"); + } + LINFO("Loading Speck file '" << _file << "'"); + + bool success = readSpeckFile(); + if (!success) + return false; + + LINFO("Saving cache"); + success = saveCachedFile(cachedFile); + + return success; +} + +bool RenderableStars::SpeckDataSource::readSpeckFile() { + std::ifstream file(_file); + if (!file.good()) { + LERROR("Failed to open Speck file '" << _file << "'"); + return false; + } + + int nValues = 0; + + // The beginning of the speck file has a header that either contains comments + // (signaled by a preceding '#') or information about the structure of the file + // (signaled by the keywords 'datavar', 'texturevar', and 'texture') + std::string line = ""; + while (true) { + std::ifstream::streampos position = file.tellg(); + std::getline(file, line); + + if (line[0] == '#') + continue; + + if (line.substr(0, 7) != "datavar" && + line.substr(0, 10) != "texturevar" && + line.substr(0, 7) != "texture") + { + // we read a line that doesn't belong to the header, so we have to jump back + // before the beginning of the current line + file.seekg(position); + break; + } + + if (line.substr(0, 7) == "datavar") { + // datavar lines are structured as follows: + // datavar # description + // where # is the index of the data variable; so if we repeatedly overwrite + // the 'nValues' variable with the latest index, we will end up with the total + // number of values (+3 since X Y Z are not counted in the Speck file index) + std::stringstream str(line); + + std::string dummy; + str >> dummy; + str >> nValues; + nValues += 1; // We want the number, but the index is 0 based + } + } + + nValues += 3; // X Y Z are not counted in the Speck file indices + + do { + std::vector values(nValues); + + std::getline(file, line); + std::stringstream str(line); + + for (int i = 0; i < nValues; ++i) + str >> values[i]; + + // Extract the position (in parsecs) + psc position = PowerScaledCoordinate::CreatePowerScaledCoordinate( + values[0], + values[1], + values[2] + ); + + // Convert parsecs -> meter + PowerScaledScalar parsecsToMetersFactor = PowerScaledScalar(0.308567758f, 17.f); + position[0] *= parsecsToMetersFactor[0]; + position[1] *= parsecsToMetersFactor[0]; + position[2] *= parsecsToMetersFactor[0]; + position[3] += parsecsToMetersFactor[1]; + + // Push the position into the data array + _data.push_back(position[0]); + _data.push_back(position[1]); + _data.push_back(position[2]); + _data.push_back(position[3]); + + // Push the other values into the array + _data.push_back(values[3]); // colorb_v + _data.push_back(values[4]); // luminance + _data.push_back(values[5]); // absolute magnitude + } while (!file.eof()); + + return true; +} + +bool RenderableStars::SpeckDataSource::loadCachedFile(const std::string& file) { + std::ifstream fileStream(file, std::ifstream::binary); + if (fileStream.good()) { + int32_t nValues = 0; + fileStream.read(reinterpret_cast(&nValues), sizeof(int32_t)); + + _data.resize(nValues); + fileStream.read(reinterpret_cast(&_data[0]), nValues * sizeof(_data[0])); + + bool success = fileStream.good(); + return success; + } + else { + LERROR("Error opening file '" << file << "' for loading cache file"); + return false; + } +} + +bool RenderableStars::SpeckDataSource::saveCachedFile(const std::string& file) const { + std::ofstream fileStream(file, std::ofstream::binary); + if (fileStream.good()) { + int32_t nValues = static_cast(_data.size()); + if (nValues == 0) { + LERROR("Error writing cache: No values were loaded"); + return false; + } + fileStream.write(reinterpret_cast(&nValues), sizeof(int32_t)); + + size_t nBytes = nValues * sizeof(_data[0]); + fileStream.write(reinterpret_cast(&_data[0]), nBytes); + + bool success = fileStream.good(); + return success; + } + else { + LERROR("Error opening file '" << file << "' for save cache file"); + return false; + } +} + } \ No newline at end of file