mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-05-08 04:20:14 -05:00
Feature/speck loader (#1585)
* Implement a shared speckfile loader * Apply new speck loader to RenderableBillboardsCloud, RenderablePlanesCloud, RenderablePoints
This commit is contained in:
@@ -55,7 +55,6 @@ namespace {
|
||||
"spriteTexture", "hasColorMap"
|
||||
};
|
||||
|
||||
constexpr int8_t CurrentCacheVersion = 1;
|
||||
constexpr double PARSEC = 0.308567756E17;
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo SpriteTextureInfo = {
|
||||
@@ -197,26 +196,22 @@ RenderablePoints::RenderablePoints(const ghoul::Dictionary& dictionary)
|
||||
}
|
||||
|
||||
bool RenderablePoints::isReady() const {
|
||||
return (_program != nullptr) && (!_fullData.empty());
|
||||
return _program && (!_dataset.entries.empty());
|
||||
}
|
||||
|
||||
void RenderablePoints::initialize() {
|
||||
ZoneScoped
|
||||
|
||||
bool success = loadData();
|
||||
if (!success) {
|
||||
throw ghoul::RuntimeError("Error loading data");
|
||||
_dataset = speck::data::loadFileWithCache(_speckFile);
|
||||
|
||||
if (_hasColorMapFile) {
|
||||
readColorMapFile();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePoints::initializeGL() {
|
||||
ZoneScoped
|
||||
|
||||
// OBS: The ProgramObject name is later used to release the program as well, so the
|
||||
// name parameter to requestProgramObject and the first parameter to
|
||||
// buildRenderProgram has to be the same or an assertion will be thrown at the
|
||||
// end of the program.
|
||||
|
||||
if (_hasSpriteTexture) {
|
||||
_program = DigitalUniverseModule::ProgramObjectManager.request(
|
||||
"RenderablePoints Sprite",
|
||||
@@ -288,10 +283,7 @@ void RenderablePoints::render(const RenderData& data, RendererTasks&) {
|
||||
|
||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||
glBindVertexArray(_vao);
|
||||
const GLsizei nAstronomicalObjects = static_cast<GLsizei>(
|
||||
_fullData.size() / _nValuesPerAstronomicalObject
|
||||
);
|
||||
glDrawArrays(GL_POINTS, 0, nAstronomicalObjects);
|
||||
glDrawArrays(GL_POINTS, 0, static_cast<GLsizei>(_dataset.entries.size()));
|
||||
|
||||
glDisable(GL_PROGRAM_POINT_SIZE);
|
||||
glBindVertexArray(0);
|
||||
@@ -304,7 +296,7 @@ void RenderablePoints::update(const UpdateData&) {
|
||||
if (_dataIsDirty) {
|
||||
LDEBUG("Regenerating data");
|
||||
|
||||
createDataSlice();
|
||||
std::vector<double> slice = createDataSlice();
|
||||
|
||||
if (_vao == 0) {
|
||||
glGenVertexArrays(1, &_vao);
|
||||
@@ -317,19 +309,13 @@ void RenderablePoints::update(const UpdateData&) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
|
||||
glBufferData(
|
||||
GL_ARRAY_BUFFER,
|
||||
_slicedData.size() * sizeof(double),
|
||||
&_slicedData[0],
|
||||
slice.size() * sizeof(double),
|
||||
slice.data(),
|
||||
GL_STATIC_DRAW
|
||||
);
|
||||
GLint positionAttrib = _program->attributeLocation("in_position");
|
||||
|
||||
if (_hasColorMapFile) {
|
||||
|
||||
// const size_t nAstronomicalObjects = _fullData.size() /
|
||||
// _nValuesPerAstronomicalObject;
|
||||
// const size_t nValues = _slicedData.size() / nAstronomicalObjects;
|
||||
// GLsizei stride = static_cast<GLsizei>(sizeof(double) * nValues);
|
||||
|
||||
glEnableVertexAttribArray(positionAttrib);
|
||||
glVertexAttribLPointer(
|
||||
positionAttrib, 4, GL_DOUBLE, sizeof(double) * 8, nullptr
|
||||
@@ -341,8 +327,8 @@ void RenderablePoints::update(const UpdateData&) {
|
||||
colorMapAttrib,
|
||||
4,
|
||||
GL_DOUBLE,
|
||||
sizeof(double) * 8,
|
||||
reinterpret_cast<void*>(sizeof(double) * 4)
|
||||
8 * sizeof(double),
|
||||
reinterpret_cast<void*>(4 * sizeof(double))
|
||||
);
|
||||
}
|
||||
else {
|
||||
@@ -381,120 +367,12 @@ void RenderablePoints::update(const UpdateData&) {
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderablePoints::loadData() {
|
||||
std::string cachedFile = FileSys.cacheManager()->cachedFilename(_speckFile);
|
||||
bool hasCachedFile = std::filesystem::is_regular_file(cachedFile);
|
||||
if (hasCachedFile) {
|
||||
LINFO(fmt::format(
|
||||
"Cached file '{}' used for Speck file '{}'",
|
||||
cachedFile, _speckFile
|
||||
));
|
||||
|
||||
bool success = loadCachedFile(cachedFile);
|
||||
if (success) {
|
||||
if (_hasColorMapFile) {
|
||||
success &= readColorMapFile();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
else {
|
||||
FileSys.cacheManager()->removeCacheFile(_speckFile);
|
||||
// Intentional fall-through to the 'else' to generate the cache file for
|
||||
// the next run
|
||||
}
|
||||
}
|
||||
else {
|
||||
LINFO(fmt::format("Cache for Speck file '{}' not found", _speckFile));
|
||||
}
|
||||
LINFO(fmt::format("Loading Speck file '{}'", _speckFile));
|
||||
|
||||
bool success = readSpeckFile();
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LINFO("Saving cache");
|
||||
success = saveCachedFile(cachedFile);
|
||||
|
||||
if (_hasColorMapFile) {
|
||||
success &= readColorMapFile();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool RenderablePoints::readSpeckFile() {
|
||||
std::ifstream file(_speckFile);
|
||||
if (!file.good()) {
|
||||
LERROR(fmt::format("Failed to open Speck file '{}'", _speckFile));
|
||||
return false;
|
||||
}
|
||||
|
||||
_nValuesPerAstronomicalObject = 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::streampos position = file.tellg();
|
||||
std::getline(file, line);
|
||||
|
||||
if (line[0] == '#' || line.empty()) {
|
||||
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 >> _nValuesPerAstronomicalObject;
|
||||
// We want the number, but the index is 0 based
|
||||
_nValuesPerAstronomicalObject += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// X Y Z are not counted in the Speck file indices
|
||||
_nValuesPerAstronomicalObject += 3;
|
||||
|
||||
do {
|
||||
std::vector<float> values(_nValuesPerAstronomicalObject);
|
||||
|
||||
std::getline(file, line);
|
||||
std::stringstream str(line);
|
||||
|
||||
for (int i = 0; i < _nValuesPerAstronomicalObject; ++i) {
|
||||
str >> values[i];
|
||||
}
|
||||
|
||||
_fullData.insert(_fullData.end(), values.begin(), values.end());
|
||||
} while (!file.eof());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderablePoints::readColorMapFile() {
|
||||
void RenderablePoints::readColorMapFile() {
|
||||
std::ifstream file(_colorMapFile);
|
||||
if (!file.good()) {
|
||||
LERROR(fmt::format("Failed to open Color Map file '{}'", _colorMapFile));
|
||||
return false;
|
||||
throw ghoul::RuntimeError(fmt::format(
|
||||
"Failed to open Color Map file '{}'", _colorMapFile
|
||||
));
|
||||
}
|
||||
|
||||
std::size_t numberOfColors = 0;
|
||||
@@ -519,7 +397,9 @@ bool RenderablePoints::readColorMapFile() {
|
||||
break;
|
||||
}
|
||||
else if (file.eof()) {
|
||||
return false;
|
||||
throw ghoul::RuntimeError(fmt::format(
|
||||
"Failed to load colors from Color Map file '{}'", _colorMapFile
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,108 +408,26 @@ bool RenderablePoints::readColorMapFile() {
|
||||
std::stringstream str(line);
|
||||
|
||||
glm::vec4 color;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
str >> color[j];
|
||||
}
|
||||
str >> color.r >> color.g >> color.b >> color.a;
|
||||
|
||||
_colorMapData.push_back(color);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderablePoints::loadCachedFile(const std::string& file) {
|
||||
std::ifstream fileStream(file, std::ifstream::binary);
|
||||
if (fileStream.good()) {
|
||||
int8_t version = 0;
|
||||
fileStream.read(reinterpret_cast<char*>(&version), sizeof(int8_t));
|
||||
if (version != CurrentCacheVersion) {
|
||||
LINFO("The format of the cached file has changed: deleting old cache");
|
||||
fileStream.close();
|
||||
if (std::filesystem::is_regular_file(file)) {
|
||||
std::filesystem::remove(file);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t nValues = 0;
|
||||
fileStream.read(reinterpret_cast<char*>(&nValues), sizeof(int32_t));
|
||||
fileStream.read(
|
||||
reinterpret_cast<char*>(&_nValuesPerAstronomicalObject),
|
||||
sizeof(int32_t)
|
||||
);
|
||||
|
||||
_fullData.resize(nValues);
|
||||
fileStream.read(reinterpret_cast<char*>(
|
||||
&_fullData[0]),
|
||||
nValues * sizeof(_fullData[0])
|
||||
);
|
||||
|
||||
const bool success = fileStream.good();
|
||||
return success;
|
||||
}
|
||||
else {
|
||||
LERROR(fmt::format(
|
||||
"Error opening file '{}' for loading cache file",
|
||||
file
|
||||
));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderablePoints::saveCachedFile(const std::string& file) const {
|
||||
std::ofstream fileStream(file, std::ofstream::binary);
|
||||
if (fileStream.good()) {
|
||||
fileStream.write(
|
||||
reinterpret_cast<const char*>(&CurrentCacheVersion),
|
||||
sizeof(int8_t)
|
||||
);
|
||||
|
||||
const int32_t nValues = static_cast<int32_t>(_fullData.size());
|
||||
if (nValues == 0) {
|
||||
LERROR("Error writing cache: No values were loaded");
|
||||
return false;
|
||||
}
|
||||
fileStream.write(reinterpret_cast<const char*>(&nValues), sizeof(int32_t));
|
||||
|
||||
const int32_t nValuesPerAstronomicalObject = static_cast<int32_t>(
|
||||
_nValuesPerAstronomicalObject
|
||||
);
|
||||
fileStream.write(
|
||||
reinterpret_cast<const char*>(&nValuesPerAstronomicalObject),
|
||||
sizeof(int32_t)
|
||||
);
|
||||
|
||||
const size_t nBytes = nValues * sizeof(_fullData[0]);
|
||||
fileStream.write(reinterpret_cast<const char*>(&_fullData[0]), nBytes);
|
||||
|
||||
const bool success = fileStream.good();
|
||||
return success;
|
||||
}
|
||||
else {
|
||||
LERROR(fmt::format("Error opening file '{}' for save cache file", file));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePoints::createDataSlice() {
|
||||
_slicedData.clear();
|
||||
std::vector<double> RenderablePoints::createDataSlice() {
|
||||
std::vector<double> slice;
|
||||
if (_hasColorMapFile) {
|
||||
_slicedData.reserve(8 * (_fullData.size() / _nValuesPerAstronomicalObject));
|
||||
slice.reserve(8 * _dataset.entries.size());
|
||||
}
|
||||
else {
|
||||
_slicedData.reserve(4 * (_fullData.size()/_nValuesPerAstronomicalObject));
|
||||
slice.reserve(4 * _dataset.entries.size());
|
||||
}
|
||||
|
||||
int colorIndex = 0;
|
||||
for (size_t i = 0; i < _fullData.size(); i += _nValuesPerAstronomicalObject) {
|
||||
glm::dvec3 p = glm::dvec3(
|
||||
_fullData[i + 0],
|
||||
_fullData[i + 1],
|
||||
_fullData[i + 2]
|
||||
);
|
||||
for (const speck::Dataset::Entry& e : _dataset.entries) {
|
||||
glm::dvec3 p = e.position;
|
||||
|
||||
// Converting untis
|
||||
// Converting units
|
||||
if (_unit == Kilometer) {
|
||||
p *= 1E3;
|
||||
}
|
||||
@@ -653,15 +451,15 @@ void RenderablePoints::createDataSlice() {
|
||||
|
||||
if (_hasColorMapFile) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
_slicedData.push_back(position[j]);
|
||||
slice.push_back(position[j]);
|
||||
}
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
_slicedData.push_back(_colorMapData[colorIndex][j]);
|
||||
slice.push_back(_colorMapData[colorIndex][j]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
_slicedData.push_back(position[j]);
|
||||
slice.push_back(position[j]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,6 +467,8 @@ void RenderablePoints::createDataSlice() {
|
||||
0 :
|
||||
colorIndex + 1;
|
||||
}
|
||||
|
||||
return slice;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
Reference in New Issue
Block a user