mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-02 17:51:35 -06:00
471 lines
19 KiB
C++
471 lines
19 KiB
C++
#include <modules/streamnodes/rendering/renderabletimevaryingplaneimagelocal.h>
|
|
#include <ghoul/misc/profiling.h>
|
|
#include <modules/base/basemodule.h>
|
|
#include <openspace/documentation/documentation.h>
|
|
#include <openspace/documentation/verifier.h>
|
|
#include <ghoul/filesystem/file.h>
|
|
#include <ghoul/filesystem/filesystem.h>
|
|
#include <ghoul/io/texture/texturereader.h>
|
|
#include <ghoul/logging/logmanager.h>
|
|
#include <ghoul/misc/crc32.h>
|
|
#include <ghoul/opengl/texture.h>
|
|
#include <fstream>
|
|
#include <modules/fieldlinessequence/fieldlinessequencemodule.h>
|
|
#include <modules/fieldlinessequence/util/kameleonfieldlinehelper.h>
|
|
#include <openspace/engine/globals.h>
|
|
#include <openspace/engine/windowdelegate.h>
|
|
#include <openspace/interaction/navigationhandler.h>
|
|
#include <openspace/interaction/orbitalnavigator.h>
|
|
#include <openspace/rendering/renderengine.h>
|
|
#include <openspace/scene/scene.h>
|
|
#include <openspace/util/timemanager.h>
|
|
#include <openspace/util/updatestructures.h>
|
|
#include <ghoul/filesystem/filesystem.h>
|
|
#include <ghoul/logging/logmanager.h>
|
|
|
|
// Test debugging tools more then logmanager
|
|
#include <ghoul/logging/consolelog.h>
|
|
#include <ghoul/logging/visualstudiooutputlog.h>
|
|
#include <ghoul/filesystem/cachemanager.h>
|
|
|
|
#include <ghoul/opengl/programobject.h>
|
|
#include <ghoul/opengl/textureunit.h>
|
|
#include <fstream>
|
|
#include <thread>
|
|
#include <openspace/json.h>
|
|
#include <openspace/query/query.h>
|
|
|
|
namespace {
|
|
constexpr const char* KeyLazyLoading = "LazyLoading";
|
|
constexpr const char* _loggerCat = "RenderableTimeVaryingPlaneImageLocal";
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo TextureInfo = {
|
|
"Texture",
|
|
"Texture",
|
|
"This value specifies an image that is loaded from disk and is used as a texture "
|
|
"that is applied to this plane. This image has to be square."
|
|
};
|
|
|
|
constexpr openspace::properties::Property::PropertyInfo RenderableTypeInfo = {
|
|
"RenderableType",
|
|
"RenderableType",
|
|
"This value specifies if the plane should be rendered in the Background,"
|
|
"Opaque, Transparent, or Overlay rendering step."
|
|
};
|
|
|
|
} // namespace
|
|
|
|
namespace openspace {
|
|
|
|
documentation::Documentation RenderableTimeVaryingPlaneImageLocal::Documentation() {
|
|
using namespace documentation;
|
|
return {
|
|
"Renderable Plane Image Local",
|
|
"base_renderable_plane_image_local",
|
|
{
|
|
{
|
|
TextureInfo.identifier,
|
|
new StringVerifier,
|
|
Optional::No,
|
|
TextureInfo.description
|
|
},
|
|
{
|
|
RenderableTypeInfo.identifier,
|
|
new StringVerifier,
|
|
Optional::Yes,
|
|
RenderableTypeInfo.description
|
|
},
|
|
{
|
|
KeyLazyLoading,
|
|
new BoolVerifier,
|
|
Optional::Yes,
|
|
"If this value is set to 'true', the image for this plane will not be "
|
|
"loaded at startup but rather when image is shown for the first time. "
|
|
"Additionally, if the plane is hidden, the image will automatically be "
|
|
"unloaded"
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
RenderableTimeVaryingPlaneImageLocal::RenderableTimeVaryingPlaneImageLocal(const ghoul::Dictionary& dictionary)
|
|
: RenderablePlane(dictionary)
|
|
, _texturePath(TextureInfo)
|
|
{
|
|
documentation::testSpecificationAndThrow(
|
|
Documentation(),
|
|
dictionary,
|
|
"RenderableTimeVaryingPlaneImageLocal"
|
|
);
|
|
|
|
addProperty(_blendMode);
|
|
|
|
_texturePath = absPath(dictionary.value<std::string>(TextureInfo.identifier));
|
|
_textureFile = std::make_unique<ghoul::filesystem::File>(_texturePath);
|
|
|
|
addProperty(_texturePath);
|
|
_texturePath.onChange([this]() {loadTexture(); });
|
|
_textureFile->setCallback(
|
|
[this](const ghoul::filesystem::File&) { _textureIsDirty = true; }
|
|
);
|
|
|
|
if (dictionary.hasKey(RenderableTypeInfo.identifier)) {
|
|
std::string renderType = dictionary.value<std::string>(
|
|
RenderableTypeInfo.identifier
|
|
);
|
|
if (renderType == "Background") {
|
|
setRenderBin(Renderable::RenderBin::Background);
|
|
}
|
|
else if (renderType == "Opaque") {
|
|
setRenderBin(Renderable::RenderBin::Opaque);
|
|
}
|
|
else if (renderType == "PreDeferredTransparent") {
|
|
setRenderBin(Renderable::RenderBin::PreDeferredTransparent);
|
|
}
|
|
else if (renderType == "PostDeferredTransparent") {
|
|
setRenderBin(Renderable::RenderBin::PostDeferredTransparent);
|
|
}
|
|
else if (renderType == "Overlay") {
|
|
setRenderBin(Renderable::RenderBin::Overlay);
|
|
}
|
|
}
|
|
else {
|
|
setRenderBin(Renderable::RenderBin::Opaque);
|
|
}
|
|
|
|
if (dictionary.hasKey(KeyLazyLoading)) {
|
|
_isLoadingLazily = dictionary.value<bool>(KeyLazyLoading);
|
|
|
|
if (_isLoadingLazily) {
|
|
_enabled.onChange([this]() {
|
|
if (!_enabled) {
|
|
BaseModule::TextureManager.release(_texture);
|
|
_texture = nullptr;
|
|
}
|
|
if (_enabled) {
|
|
_textureIsDirty = true;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
bool RenderableTimeVaryingPlaneImageLocal::isReady() const {
|
|
return RenderablePlane::isReady();
|
|
}
|
|
|
|
#pragma optimize ("", off)
|
|
|
|
void RenderableTimeVaryingPlaneImageLocal::initializeGL() {
|
|
RenderablePlane::initializeGL();
|
|
|
|
LDEBUG("sourcefiles size:" + std::to_string(_sourceFiles.size()));
|
|
|
|
if (!extractMandatoryInfoFromDictionary()) {
|
|
return;
|
|
}
|
|
extractTriggerTimesFromFileNames();
|
|
computeSequenceEndTime();
|
|
|
|
_textureFiles.resize(_sourceFiles.size());
|
|
for(int i = 0; i < _sourceFiles.size(); ++i){
|
|
|
|
//unsigned int hash = ghoul::hashCRC32File(_sourceFiles[i]);
|
|
|
|
/*
|
|
_texture = BaseModule::TextureManager.request(
|
|
std::to_string(hash),
|
|
[path = _sourceFiles[_activeTriggerTimeIndex]]() -> std::unique_ptr<ghoul::opengl::Texture> {
|
|
|
|
ghoul::io::TextureReader::ref().loadTexture(absPath(path));
|
|
|
|
_texture = _textureFiles[_activeTriggerTimeIndex];
|
|
// LDEBUGC(
|
|
// "RenderableTimeVaryingPlaneImageLocal",
|
|
// fmt::format("Loaded texture from '{}'", absPath(path))
|
|
//);
|
|
|
|
|
|
texture->uploadTexture();
|
|
texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
|
texture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge);
|
|
//texture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge);
|
|
|
|
|
|
// return texture;
|
|
|
|
// );
|
|
|
|
*/
|
|
|
|
// std::unique_ptr<ghoul::opengl::Texture> texture =
|
|
_textureFiles[i] = ghoul::io::TextureReader::ref().loadTexture(absPath(_sourceFiles[i]));
|
|
//temp* = förra texturen;
|
|
//texture=
|
|
/* _textureFiles[i] = BaseModule::TextureManager.request(
|
|
std::to_string(hash),
|
|
[path = _sourceFiles[i]]()->std::unique_ptr<ghoul::opengl::Texture> {
|
|
|
|
|
|
//std::unique_ptr<ghoul::opengl::Texture> texture = ghoul::io::TextureReader::ref().loadTexture(absPath(path));
|
|
//texture->uploadTexture();
|
|
//texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
|
//
|
|
//texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
|
//texture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge);
|
|
|
|
texture->purgeFromRAM();
|
|
|
|
|
|
return texture;
|
|
});
|
|
*/
|
|
_textureFiles[i]->setInternalFormat(GL_COMPRESSED_RGBA);
|
|
_textureFiles[i]->uploadTexture();
|
|
_textureFiles[i]->setFilter(ghoul::opengl::Texture::FilterMode::Linear);
|
|
//_textureFiles[i]->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
|
_textureFiles[i]->purgeFromRAM();
|
|
//BaseModule::TextureManager.release(_textureFiles[i]);
|
|
|
|
|
|
// _textureFiles[i] = ghoul::io::TextureReader::ref().loadTexture(absPath(_sourceFiles[i]));
|
|
//_textureFiles[i]->uploadTexture();
|
|
//_textureFiles[i]->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
|
//_textureFiles[i]->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge);
|
|
//_textureFiles[i]->purgeFromRAM();
|
|
|
|
|
|
//_textureFiles[i] = std::move(_texture);
|
|
//BaseModule::TextureManager.release(_texture);
|
|
/*
|
|
unsigned int hash = ghoul::hashCRC32File(_sourceFiles[i]);
|
|
|
|
_texture = BaseModule::TextureManager.request(
|
|
std::to_string(hash),
|
|
[path = _sourceFiles[i]]()->std::unique_ptr<ghoul::opengl::Texture> {
|
|
std::unique_ptr<ghoul::opengl::Texture> texture = ghoul::io::TextureReader::ref().loadTexture(absPath(path));
|
|
};
|
|
*/
|
|
//_textureFiles[i] = texture;
|
|
//_textureFiles[i] = _texture;
|
|
// BaseModule::TextureManager.release(_textureFiles[i]);
|
|
}
|
|
|
|
if (!_isLoadingLazily) {
|
|
loadTexture();
|
|
}
|
|
}
|
|
|
|
bool RenderableTimeVaryingPlaneImageLocal::extractMandatoryInfoFromDictionary()
|
|
{
|
|
// Ensure that the source folder exists and then extract
|
|
// the files with the same extension as <inputFileTypeString>
|
|
ghoul::filesystem::Directory sourceFolder(_texturePath);
|
|
if (FileSys.directoryExists(sourceFolder)) {
|
|
// Extract all file paths from the provided folder
|
|
_sourceFiles = sourceFolder.readFiles(
|
|
ghoul::filesystem::Directory::Recursive::No,
|
|
ghoul::filesystem::Directory::Sort::Yes
|
|
);
|
|
// Ensure that there are available and valid source files left
|
|
if (_sourceFiles.empty()) {
|
|
LERROR(fmt::format(
|
|
"{}: {} contains no {} files",
|
|
_identifier, _texturePath, "extension"
|
|
));
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
LERROR(fmt::format(
|
|
"{}: FieldlinesSequence {} is not a valid directory",
|
|
_identifier,
|
|
_texturePath
|
|
));
|
|
return false;
|
|
}
|
|
_nStates = _sourceFiles.size();
|
|
LDEBUG("returning true");
|
|
return true;
|
|
}
|
|
void RenderableTimeVaryingPlaneImageLocal::deinitializeGL() {
|
|
_textureFile = nullptr;
|
|
|
|
|
|
BaseModule::TextureManager.release(_texture);
|
|
// for (int i = 0; i < _textureFiles.size(); ++i) {
|
|
// BaseModule::TextureManager.release(_textureFiles[i]);
|
|
// }
|
|
_textureFiles.clear();
|
|
RenderablePlane::deinitializeGL();
|
|
}
|
|
|
|
void RenderableTimeVaryingPlaneImageLocal::bindTexture() {
|
|
_texture->bind();
|
|
// _textureFiles[_activeTriggerTimeIndex]->bind();
|
|
}
|
|
|
|
void RenderableTimeVaryingPlaneImageLocal::update(const UpdateData& data) {
|
|
ZoneScoped
|
|
RenderablePlane::update(data);
|
|
|
|
if (!this->_enabled) {
|
|
return;
|
|
}
|
|
|
|
|
|
const double currentTime = data.time.j2000Seconds();
|
|
const bool isInInterval = (currentTime >= _startTimes[0]) &&
|
|
(currentTime < _sequenceEndTime);
|
|
//const bool isInInterval = true;
|
|
if (isInInterval) {
|
|
ZoneScopedN("isInInterval")
|
|
const size_t nextIdx = _activeTriggerTimeIndex + 1;
|
|
if (
|
|
// true => Previous frame was not within the sequence interval
|
|
//_activeTriggerTimeIndex < 0 ||
|
|
// true => We stepped back to a time represented by another state
|
|
currentTime < _startTimes[_activeTriggerTimeIndex] ||
|
|
// true => We stepped forward to a time represented by another state
|
|
(nextIdx < _nStates && currentTime >= _startTimes[nextIdx]))
|
|
{
|
|
updateActiveTriggerTimeIndex(currentTime);
|
|
//LDEBUG("Vi borde uppdatera1");
|
|
|
|
// _mustLoadNewStateFromDisk = true;
|
|
//LDEBUG("vi borde uppdatera");
|
|
_needsUpdate = true;
|
|
|
|
} // else {we're still in same state as previous frame (no changes needed)}
|
|
}
|
|
else {
|
|
ZoneScopedN("else")
|
|
//not in interval => set everything to false
|
|
//LDEBUG("not in interval");
|
|
_activeTriggerTimeIndex = 0;
|
|
_needsUpdate = false;
|
|
}
|
|
|
|
if ((_needsUpdate || _textureIsDirty) && !_isLoadingTexture) {
|
|
ZoneScopedN("needsupdate")
|
|
_isLoadingTexture = true;
|
|
loadTexture();
|
|
_textureIsDirty = false;
|
|
}
|
|
}
|
|
// Extract J2000 time from file names
|
|
// Requires files to be named as such: 'YYYY-MM-DDTHH-MM-SS-XXX.json'
|
|
void RenderableTimeVaryingPlaneImageLocal::extractTriggerTimesFromFileNames() {
|
|
// number of characters in filename (excluding '.json')
|
|
constexpr const int FilenameSize = 23;
|
|
// size(".json")
|
|
constexpr const int ExtSize = 4;
|
|
|
|
for (const std::string& filePath : _sourceFiles) {
|
|
LDEBUG("filepath " + filePath);
|
|
const size_t strLength = filePath.size();
|
|
// Extract the filename from the path (without extension)
|
|
std::string timeString = filePath.substr(
|
|
strLength - FilenameSize - ExtSize,
|
|
FilenameSize - 1
|
|
);
|
|
// Ensure the separators are correct
|
|
timeString.replace(4, 1, "-");
|
|
timeString.replace(7, 1, "-");
|
|
timeString.replace(13, 1, ":");
|
|
timeString.replace(16, 1, ":");
|
|
timeString.replace(19, 1, ".");
|
|
const double triggerTime = Time::convertTime(timeString);
|
|
LDEBUG("timestring " + timeString);
|
|
_startTimes.push_back(triggerTime);
|
|
}
|
|
}
|
|
void RenderableTimeVaryingPlaneImageLocal::updateActiveTriggerTimeIndex(double currentTime) {
|
|
auto iter = std::upper_bound(_startTimes.begin(), _startTimes.end(), currentTime);
|
|
if (iter != _startTimes.end()) {
|
|
if (iter != _startTimes.begin()) {
|
|
_activeTriggerTimeIndex = static_cast<int>(
|
|
std::distance(_startTimes.begin(), iter)
|
|
) - 1;
|
|
}
|
|
else {
|
|
_activeTriggerTimeIndex = 0;
|
|
}
|
|
}
|
|
else {
|
|
_activeTriggerTimeIndex = static_cast<int>(_nStates) - 1;
|
|
}
|
|
}
|
|
void RenderableTimeVaryingPlaneImageLocal::computeSequenceEndTime() {
|
|
if (_nStates > 1) {
|
|
const double lastTriggerTime = _startTimes[_nStates - 1];
|
|
const double sequenceDuration = lastTriggerTime - _startTimes[0];
|
|
const double averageStateDuration = sequenceDuration /
|
|
(static_cast<double>(_nStates) - 1.0);
|
|
_sequenceEndTime = lastTriggerTime + averageStateDuration;
|
|
}
|
|
else {
|
|
// If there's just one state it should never disappear!
|
|
_sequenceEndTime = DBL_MAX;
|
|
}
|
|
}
|
|
void RenderableTimeVaryingPlaneImageLocal::loadTexture() {
|
|
if (_activeTriggerTimeIndex != -1) {
|
|
// ghoul::opengl::Texture* t = _texture;
|
|
//std::unique_ptr<ghoul::opengl::Texture> t = _texture;
|
|
|
|
_texture = _textureFiles[_activeTriggerTimeIndex].get();
|
|
//_texture->uploadTexture();
|
|
//unsigned int hash = ghoul::hashCRC32File(_sourceFiles[_activeTriggerTimeIndex]);
|
|
|
|
//_texture = _textureFiles[_activeTriggerTimeIndex];
|
|
//_texture->uploadTexture();
|
|
//_texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
|
//_texture->purgeFromRAM();
|
|
// _textureFiles[_activeTriggerTimeIndex]->uploadTexture();
|
|
// _textureFiles[_activeTriggerTimeIndex]->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
|
//_texture->uploadTexture();
|
|
//_texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
|
//_texture->purgeFromRAM();
|
|
//_textureFiles[_activeTriggerTimeIndex]->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge);
|
|
// _textureFiles[_activeTriggerTimeIndex]->purgeFromRAM();
|
|
//_texture = _textureFiles[_activeTriggerTimeIndex];
|
|
|
|
//ghoul::io::TextureReader::ref().loadTexture(absPath(path));
|
|
|
|
// _texture = _textureFiles[_activeTriggerTimeIndex];
|
|
// LDEBUGC(
|
|
// "RenderableTimeVaryingPlaneImageLocal",
|
|
// fmt::format("Loaded texture from '{}'", absPath(path))
|
|
//);
|
|
//_texture _textureFiles[_activeTriggerTimeIndex];
|
|
|
|
// texture->uploadTexture();
|
|
// texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
|
// texture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge);
|
|
//texture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge);
|
|
|
|
|
|
// return texture;
|
|
|
|
// );
|
|
|
|
//_textureFiles[_activeTriggerTimeIndex]->uploadTexture();
|
|
//_textureFiles[_activeTriggerTimeIndex]->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
|
|
//_textureFiles[_activeTriggerTimeIndex]->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge);
|
|
//_textureFiles[_activeTriggerTimeIndex]->purgeFromRAM();
|
|
|
|
//BaseModule::TextureManager.release(t);
|
|
/*
|
|
_textureFile = std::make_unique<ghoul::filesystem::File>(_sourceFiles[_activeTriggerTimeIndex]);
|
|
_textureFile->setCallback(
|
|
[&](const ghoul::filesystem::File&) { _textureIsDirty = true; }
|
|
);
|
|
*/
|
|
_isLoadingTexture = false;
|
|
//glTexParameterf(_texture, GL_TEXTURE_MIN_FILTER, 0);
|
|
}
|
|
}
|
|
|
|
} // namespace openspace
|