#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Test debugging tools more then logmanager #include #include #include #include #include #include #include #include #include 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(TextureInfo.identifier)); _textureFile = std::make_unique(_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( 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(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::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 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 { //std::unique_ptr 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 { std::unique_ptr 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 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( std::distance(_startTimes.begin(), iter) ) - 1; } else { _activeTriggerTimeIndex = 0; } } else { _activeTriggerTimeIndex = static_cast(_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(_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 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(_sourceFiles[_activeTriggerTimeIndex]); _textureFile->setCallback( [&](const ghoul::filesystem::File&) { _textureIsDirty = true; } ); */ _isLoadingTexture = false; //glTexParameterf(_texture, GL_TEXTURE_MIN_FILTER, 0); } } } // namespace openspace