From 4fa3e8f22496624547aa6cf75900fa7380733f75 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Fri, 21 Jan 2022 12:08:16 +0100 Subject: [PATCH 01/30] Is this how we want to put it? This is just about the structure and the interfaces. Do we want to put more restrictions? Or Less? --- .../datatools/io/dataformat/CSVDataFormat.h | 38 ++++++++++++++ .../datatools/io/dataformat/DataFormat.h | 50 +++++++++++++++++++ plugins/datatools/src/datatools.cpp | 4 ++ 3 files changed, 92 insertions(+) create mode 100644 plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h create mode 100644 plugins/datatools/include/datatools/io/dataformat/DataFormat.h diff --git a/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h b/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h new file mode 100644 index 0000000000..1d9c86d835 --- /dev/null +++ b/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h @@ -0,0 +1,38 @@ +#pragma once + +#include "DataFormat.h" + +namespace megamol { +namespace datatools { +namespace io { +namespace dataformat { + +struct CSVColumnInfo { + std::string name; + // TODO +}; + +struct CSVFrame { + using FrameIndexType = uint32_t; + using DataIndexType = uint32_t; + + FrameIndexType FrameIndex; + DataIndexType NumColumns; + DataIndexType NumRows; + std::vector ColumnInfos; + std::vector Values; +}; + +class CSVDataFormat : public AbstractDataFormat { + std::unique_ptr ReadFrame(std::ifstream& io) override { + return std::make_unique(); + } + void WriteFrame(std::ofstream& io, CSVFrame frame) override{} +}; + +using CSVFileCollection = FolderContainer; + +} // namespace dataformat +} // namespace io +} // namespace datatools +} // namespace megamol diff --git a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h new file mode 100644 index 0000000000..7965528b9c --- /dev/null +++ b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h @@ -0,0 +1,50 @@ +#pragma once + +#include + +namespace megamol { +namespace datatools { +namespace io { +namespace dataformat { + +template +class AbstractDataFormat { +public: + virtual ~AbstractDataFormat() = default; + using FrameType = F; + virtual std::unique_ptr ReadFrame(std::ifstream& io) = 0; + virtual void WriteFrame(std::ofstream& io, F frame) = 0; +}; + +template +class AbstractDataContainer { +public: + virtual ~AbstractDataContainer() = default; + using Format = F; + using FrameIndex = typename F::FrameType::FrameIndexType; + + virtual bool Open(std::string location) = 0; // todo mode +}; + +// A directory containing several files, one for each frame +template +class FolderContainer : public AbstractDataContainer { + bool Open(std::string location) override { + return true; + } +}; + +// One big blob of data, each frame sitting at some offset +template +class BlobContainer : public AbstractDataContainer { + bool Open(std::string location) override { + return true; + } +}; + +// some other containers...? + +} // namespace dataformat +} // namespace io +} // namespace datatools +} // namespace megamol diff --git a/plugins/datatools/src/datatools.cpp b/plugins/datatools/src/datatools.cpp index 8cab402b13..888882789c 100644 --- a/plugins/datatools/src/datatools.cpp +++ b/plugins/datatools/src/datatools.cpp @@ -89,6 +89,8 @@ #include "table/TableToParticles.h" #include "table/TableWhere.h" +#include "datatools/io/dataformat/CSVDataFormat.h" + namespace megamol::datatools { class DatatoolsPluginInstance : public megamol::core::utility::plugins::AbstractPluginInstance { REGISTERPLUGIN(DatatoolsPluginInstance) @@ -185,6 +187,8 @@ class DatatoolsPluginInstance : public megamol::core::utility::plugins::Abstract this->call_descriptions.RegisterAutoDescription(); this->call_descriptions.RegisterAutoDescription(); this->call_descriptions.RegisterAutoDescription(); + // TODO this is just for testing, it needs to go away! + io::dataformat::CSVFileCollection coll; } }; } // namespace megamol::datatools From 2134538aadb4034b9f4ef1f8a2eabb5dd27ef1a1 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Fri, 21 Jan 2022 12:39:49 +0100 Subject: [PATCH 02/30] frames should (de)serialize themselves --- .../datatools/io/dataformat/CSVDataFormat.h | 17 ++++++++++++----- .../datatools/io/dataformat/DataFormat.h | 7 ++++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h b/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h index 1d9c86d835..5bf6676da0 100644 --- a/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h @@ -12,19 +12,26 @@ struct CSVColumnInfo { // TODO }; -struct CSVFrame { +struct CSVFrame : AbstractFrame { using FrameIndexType = uint32_t; using DataIndexType = uint32_t; - FrameIndexType FrameIndex; - DataIndexType NumColumns; - DataIndexType NumRows; + FrameIndexType FrameIndex = 0; + DataIndexType NumColumns = 0; + DataIndexType NumRows = 0; std::vector ColumnInfos; std::vector Values; + + bool Read(std::ifstream& io) override { + return true; + } + bool Write(std::ofstream& io) override { + return true; + } }; class CSVDataFormat : public AbstractDataFormat { - std::unique_ptr ReadFrame(std::ifstream& io) override { + std::unique_ptr ReadFrame(std::ifstream& io, CSVFrame::FrameIndexType idx) override { return std::make_unique(); } void WriteFrame(std::ofstream& io, CSVFrame frame) override{} diff --git a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h index 7965528b9c..d33811871a 100644 --- a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h @@ -7,12 +7,17 @@ namespace datatools { namespace io { namespace dataformat { +struct AbstractFrame { + virtual bool Read(std::ifstream& io) = 0; + virtual bool Write(std::ofstream& io) = 0; +}; + template class AbstractDataFormat { public: virtual ~AbstractDataFormat() = default; using FrameType = F; - virtual std::unique_ptr ReadFrame(std::ifstream& io) = 0; + virtual std::unique_ptr ReadFrame(std::ifstream& io, typename F::FrameIndexType idx) = 0; virtual void WriteFrame(std::ofstream& io, F frame) = 0; }; From 6fd75076f86b614ee08cace07498384e2560dbd8 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Mon, 24 Jan 2022 13:15:23 +0100 Subject: [PATCH 03/30] fixes --- .../datatools/include/datatools/io/dataformat/CSVDataFormat.h | 2 +- plugins/datatools/include/datatools/io/dataformat/DataFormat.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h b/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h index 5bf6676da0..c4ab39fe93 100644 --- a/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h @@ -34,7 +34,7 @@ class CSVDataFormat : public AbstractDataFormat { std::unique_ptr ReadFrame(std::ifstream& io, CSVFrame::FrameIndexType idx) override { return std::make_unique(); } - void WriteFrame(std::ofstream& io, CSVFrame frame) override{} + void WriteFrame(std::ofstream& io, CSVFrame const& frame) override {} }; using CSVFileCollection = FolderContainer; diff --git a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h index d33811871a..63764d8990 100644 --- a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h @@ -18,7 +18,7 @@ class AbstractDataFormat { virtual ~AbstractDataFormat() = default; using FrameType = F; virtual std::unique_ptr ReadFrame(std::ifstream& io, typename F::FrameIndexType idx) = 0; - virtual void WriteFrame(std::ofstream& io, F frame) = 0; + virtual void WriteFrame(std::ofstream& io, F const& frame) = 0; }; template From 85529205e842b3d0ce34533cf1ead72b28a56727 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Tue, 25 Jan 2022 10:23:51 +0100 Subject: [PATCH 04/30] more tinkering and open questions --- .../datatools/io/dataformat/DataFormat.h | 63 +++++++++++++++---- .../datatools/io/dataformat/PNGDataFormat.h | 58 +++++++++++++++++ plugins/datatools/src/datatools.cpp | 2 + 3 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h diff --git a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h index 63764d8990..970e67f312 100644 --- a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h @@ -1,6 +1,8 @@ #pragma once +#include #include +#include namespace megamol { namespace datatools { @@ -12,36 +14,71 @@ struct AbstractFrame { virtual bool Write(std::ofstream& io) = 0; }; -template +template class AbstractDataFormat { public: virtual ~AbstractDataFormat() = default; - using FrameType = F; - virtual std::unique_ptr ReadFrame(std::ifstream& io, typename F::FrameIndexType idx) = 0; - virtual void WriteFrame(std::ofstream& io, F const& frame) = 0; + using FrameType = Frame; + using FrameIndexType = typename FrameType::FrameIndexType; + using FileType = std::filesystem::directory_entry; + using FileListType = std::vector; + + virtual std::unique_ptr ReadFrame(std::ifstream& io, FrameIndexType idx) = 0; + virtual void WriteFrame(std::ofstream& io, Frame const& frame) = 0; + + virtual FileListType EnumerateFramesInDirectory(FileType Path, std::string FilePattern) = 0; }; -template +template class AbstractDataContainer { public: virtual ~AbstractDataContainer() = default; - using Format = F; - using FrameIndex = typename F::FrameType::FrameIndexType; + using FormatType = Format; + using FrameType = typename Format::FrameType; + using FrameIndexType = typename FrameType::FrameIndexType; + + std::unique_ptr ReadFrame(FrameIndexType idx) { + // here we should actually grab the frames from some background thread that reads ahead and stuff? + FrameType f; + f.Read(IndexToIStream(idx)); + return std::make_unique(f); + } + + void WriteFrame(FrameIndexType idx, FrameType const& frame) {}; - virtual bool Open(std::string location) = 0; // todo mode + virtual std::ifstream IndexToIStream(FrameIndexType idx) = 0; + virtual std::ofstream IndexToOStream(FrameIndexType idx) = 0; }; // A directory containing several files, one for each frame -template -class FolderContainer : public AbstractDataContainer { - bool Open(std::string location) override { +template +class FolderContainer : public AbstractDataContainer { +public: + using FrameType = typename Format::FrameType; + using FrameIndexType = typename FrameType::FrameIndexType; + + bool Open(std::string location, std::string pattern) { + files = Format::EnumerateFramesInDirectory(location, pattern); return true; } + + std::ifstream IndexToIStream(FrameIndexType idx) override { + return std::ifstream (files[idx].path().string().c_str(), std::ifstream::binary); + } + std::ofstream IndexToOStream(FrameIndexType idx) override { + // TODO some code for making paths when idx > what we already had + // TODO what about sparse stuff, i.e. when the numbers were not consecutive? + auto filename = files[idx].path().string().c_str(); + return std::ofstream(filename, std::ifstream::binary); + } + +private: + typename Format::FileListType files; }; // One big blob of data, each frame sitting at some offset -template -class BlobContainer : public AbstractDataContainer { +template +class BlobContainer : public AbstractDataContainer { bool Open(std::string location) override { return true; } diff --git a/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h b/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h new file mode 100644 index 0000000000..77d81980ec --- /dev/null +++ b/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h @@ -0,0 +1,58 @@ +#pragma once + +#include "DataFormat.h" +#include "mmcore/utility/graphics/ScreenShotComments.h" + +#include +#include + +namespace megamol { +namespace datatools { +namespace io { +namespace dataformat { + +struct PNGFrame : AbstractFrame { + using FrameIndexType = uint32_t; + using SizeType = uint32_t; + + FrameIndexType FrameIndex = 0; + SizeType Width = 0, Height = 0; + megamol::core::utility::graphics::ScreenShotComments::comments_storage_map comments; + + std::vector Values; + + bool Read(std::ifstream& io) override { + return true; + } + bool Write(std::ofstream& io) override { + return true; + } +}; + +class PNGDataFormat : public AbstractDataFormat { + std::unique_ptr ReadFrame(std::ifstream& io, PNGFrame::FrameIndexType idx) override { + return std::make_unique(); + } + + void WriteFrame(std::ofstream& io, PNGFrame const& frame) override {} + + FileListType EnumerateFramesInDirectory(FileType Path, std::string FilePattern) override { + // TODO how to separate name, extension, and frame number? + auto r = std::regex(FilePattern); + FileListType files; + for (const auto& entry : std::filesystem::directory_iterator(Path)) { + if (std::regex_match(entry.path().filename().string(), r)) { + files.push_back(entry); + } + } + std::sort(files.begin(), files.end()); + return files; + } +}; + +using PNGFileCollection = FolderContainer; + +} // namespace dataformat +} // namespace io +} // namespace datatools +} // namespace megamol diff --git a/plugins/datatools/src/datatools.cpp b/plugins/datatools/src/datatools.cpp index 888882789c..8cb9ca826c 100644 --- a/plugins/datatools/src/datatools.cpp +++ b/plugins/datatools/src/datatools.cpp @@ -90,6 +90,7 @@ #include "table/TableWhere.h" #include "datatools/io/dataformat/CSVDataFormat.h" +#include "datatools/io/dataformat/PNGDataFormat.h" namespace megamol::datatools { class DatatoolsPluginInstance : public megamol::core::utility::plugins::AbstractPluginInstance { @@ -189,6 +190,7 @@ class DatatoolsPluginInstance : public megamol::core::utility::plugins::Abstract this->call_descriptions.RegisterAutoDescription(); // TODO this is just for testing, it needs to go away! io::dataformat::CSVFileCollection coll; + io::dataformat::PNGFileCollection coll2; } }; } // namespace megamol::datatools From 7a1f39fe69b8284f08f7f69bfd8fed11ea9e44c8 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Tue, 25 Jan 2022 10:29:45 +0100 Subject: [PATCH 05/30] before I forget --- .../datatools/include/datatools/io/dataformat/DataFormat.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h index 970e67f312..d4955fd067 100644 --- a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h @@ -53,6 +53,7 @@ class AbstractDataContainer { // A directory containing several files, one for each frame template class FolderContainer : public AbstractDataContainer { + // this container supports arbitrary insertion and appending public: using FrameType = typename Format::FrameType; using FrameIndexType = typename FrameType::FrameIndexType; @@ -79,7 +80,8 @@ class FolderContainer : public AbstractDataContainer { // One big blob of data, each frame sitting at some offset template class BlobContainer : public AbstractDataContainer { - bool Open(std::string location) override { + // TODO this container does not support frame insertion. it should support frame appending. + bool Open(std::string location) { return true; } }; From c15b9f9b797c941aae956a9235b0edb4f8505ffc Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Tue, 25 Jan 2022 18:34:26 +0100 Subject: [PATCH 06/30] more plumbing --- .../datatools/io/dataformat/DataFormat.h | 73 +++++++++++++++++-- .../datatools/io/dataformat/PNGDataFormat.h | 22 +++--- plugins/datatools/src/datatools.cpp | 7 +- 3 files changed, 79 insertions(+), 23 deletions(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h index d4955fd067..8552bb0463 100644 --- a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h @@ -2,6 +2,7 @@ #include #include +#include #include namespace megamol { @@ -10,10 +11,44 @@ namespace io { namespace dataformat { struct AbstractFrame { + virtual ~AbstractFrame() = default; virtual bool Read(std::ifstream& io) = 0; virtual bool Write(std::ofstream& io) = 0; }; +struct AbstractNaming { + virtual ~AbstractNaming() = default; + virtual std::regex Pattern() = 0; +}; + +template +struct BaseNumbering { + virtual ~BaseNumbering() = default; + using FrameIndexType = typename Frame::FrameIndexType; + + BaseNumbering(uint8_t digits = 5) : digits(digits) { + reg = std::regex(std::string("(\d{") + std::to_string(digits) + "})"); + } + + virtual FrameIndexType ExtractNumber(std::string filename) { + std::smatch matches; + if (std::regex_match(filename, matches, reg)) { + return std::stoi(matches[0].str()); + } + return static_cast(0); + } + + virtual std::string MakeFileName(std::string prefix, FrameIndexType idx) { + std::stringstream str; + str << std::setfill('0') << std::setw(digits) << idx; + return prefix + str.str(); + } + +private: + std::regex reg; + uint8_t digits; +}; + template class AbstractDataFormat { public: @@ -21,14 +56,13 @@ class AbstractDataFormat { using FrameType = Frame; using FrameIndexType = typename FrameType::FrameIndexType; using FileType = std::filesystem::directory_entry; - using FileListType = std::vector; virtual std::unique_ptr ReadFrame(std::ifstream& io, FrameIndexType idx) = 0; virtual void WriteFrame(std::ofstream& io, Frame const& frame) = 0; - virtual FileListType EnumerateFramesInDirectory(FileType Path, std::string FilePattern) = 0; }; +// TODO read-ahead number template class AbstractDataContainer { public: @@ -36,6 +70,10 @@ class AbstractDataContainer { using FormatType = Format; using FrameType = typename Format::FrameType; using FrameIndexType = typename FrameType::FrameIndexType; + // TODO: Adrian's LRUCache here since we need most of the functionality anyway, so why not. + using FrameCollection = std::unordered_map; + + // TODO generic EnumerateFrames that only files the frame indices with empty frames for now? std::unique_ptr ReadFrame(FrameIndexType idx) { // here we should actually grab the frames from some background thread that reads ahead and stuff? @@ -44,7 +82,7 @@ class AbstractDataContainer { return std::make_unique(f); } - void WriteFrame(FrameIndexType idx, FrameType const& frame) {}; + void WriteFrame(FrameIndexType idx, FrameType const& frame) {} virtual std::ifstream IndexToIStream(FrameIndexType idx) = 0; virtual std::ofstream IndexToOStream(FrameIndexType idx) = 0; @@ -55,12 +93,30 @@ template class FolderContainer : public AbstractDataContainer { // this container supports arbitrary insertion and appending public: + using FileType = typename Format::FileType; + using FileListType = std::vector; using FrameType = typename Format::FrameType; using FrameIndexType = typename FrameType::FrameIndexType; - bool Open(std::string location, std::string pattern) { - files = Format::EnumerateFramesInDirectory(location, pattern); - return true; + FolderContainer( + std::string location, std::unique_ptr naming, BaseNumbering numbering = BaseNumbering()) + : naming(std::move(naming)) + , numbering(numbering) { + files = EnumerateFramesInDirectory(FileType(location)); + } + + // TODO specific EnumerateFrames that uses the dir enumerator below? + + FileListType EnumerateFramesInDirectory(FileType Path) { + auto r = std::regex(naming->Pattern()); + FileListType files; + for (const auto& entry : std::filesystem::directory_iterator(Path)) { + if (std::regex_match(entry.path().filename().string(), r)) { + files.push_back(entry); + } + } + std::sort(files.begin(), files.end()); + return files; } std::ifstream IndexToIStream(FrameIndexType idx) override { @@ -74,13 +130,16 @@ class FolderContainer : public AbstractDataContainer { } private: - typename Format::FileListType files; + FileListType files; + BaseNumbering numbering; + std::unique_ptr naming; }; // One big blob of data, each frame sitting at some offset template class BlobContainer : public AbstractDataContainer { // TODO this container does not support frame insertion. it should support frame appending. + // totally TODO actually bool Open(std::string location) { return true; } diff --git a/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h b/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h index 77d81980ec..64f3d6fc15 100644 --- a/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h @@ -11,6 +11,9 @@ namespace datatools { namespace io { namespace dataformat { +// todo where would we point when we read a mmpld frame? +// todo: end pointer? +// does this map to MMPLD and ADIOS? struct PNGFrame : AbstractFrame { using FrameIndexType = uint32_t; using SizeType = uint32_t; @@ -29,25 +32,18 @@ struct PNGFrame : AbstractFrame { } }; +struct PNGNaming : AbstractNaming { + std::regex Pattern() override { + return std::regex("^.*?\\.png"); + } +}; + class PNGDataFormat : public AbstractDataFormat { std::unique_ptr ReadFrame(std::ifstream& io, PNGFrame::FrameIndexType idx) override { return std::make_unique(); } void WriteFrame(std::ofstream& io, PNGFrame const& frame) override {} - - FileListType EnumerateFramesInDirectory(FileType Path, std::string FilePattern) override { - // TODO how to separate name, extension, and frame number? - auto r = std::regex(FilePattern); - FileListType files; - for (const auto& entry : std::filesystem::directory_iterator(Path)) { - if (std::regex_match(entry.path().filename().string(), r)) { - files.push_back(entry); - } - } - std::sort(files.begin(), files.end()); - return files; - } }; using PNGFileCollection = FolderContainer; diff --git a/plugins/datatools/src/datatools.cpp b/plugins/datatools/src/datatools.cpp index 8cb9ca826c..99ea0ca89e 100644 --- a/plugins/datatools/src/datatools.cpp +++ b/plugins/datatools/src/datatools.cpp @@ -188,9 +188,10 @@ class DatatoolsPluginInstance : public megamol::core::utility::plugins::Abstract this->call_descriptions.RegisterAutoDescription(); this->call_descriptions.RegisterAutoDescription(); this->call_descriptions.RegisterAutoDescription(); - // TODO this is just for testing, it needs to go away! - io::dataformat::CSVFileCollection coll; - io::dataformat::PNGFileCollection coll2; + + // TODO BUG HAZARD this is just for testing, it needs to go away! + //io::dataformat::CSVFileCollection coll("c:/temp"); + io::dataformat::PNGFileCollection coll2("c:\temp", std::make_unique()); } }; } // namespace megamol::datatools From 2dbd4bb87055d3725315591d1264e14c64208692 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Tue, 25 Jan 2022 18:35:55 +0100 Subject: [PATCH 07/30] cleanup --- .../include/datatools/io/dataformat/PNGDataFormat.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h b/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h index 64f3d6fc15..195bb8ac4c 100644 --- a/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h @@ -38,14 +38,7 @@ struct PNGNaming : AbstractNaming { } }; -class PNGDataFormat : public AbstractDataFormat { - std::unique_ptr ReadFrame(std::ifstream& io, PNGFrame::FrameIndexType idx) override { - return std::make_unique(); - } - - void WriteFrame(std::ofstream& io, PNGFrame const& frame) override {} -}; - +using PNGDataFormat = AbstractDataFormat; using PNGFileCollection = FolderContainer; } // namespace dataformat From e6de7d80d6930947cb9b46588bebaf78916a6968 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Tue, 25 Jan 2022 19:20:20 +0100 Subject: [PATCH 08/30] cleanup and bug fix (thx Adrian) --- .../include/datatools/io/dataformat/CSVDataFormat.h | 8 +------- .../include/datatools/io/dataformat/DataFormat.h | 13 ++++++------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h b/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h index c4ab39fe93..8a49fb19d7 100644 --- a/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h @@ -30,13 +30,7 @@ struct CSVFrame : AbstractFrame { } }; -class CSVDataFormat : public AbstractDataFormat { - std::unique_ptr ReadFrame(std::ifstream& io, CSVFrame::FrameIndexType idx) override { - return std::make_unique(); - } - void WriteFrame(std::ofstream& io, CSVFrame const& frame) override {} -}; - +using CSVDataFormat = AbstractDataFormat; using CSVFileCollection = FolderContainer; } // namespace dataformat diff --git a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h index 8552bb0463..246e60e3c4 100644 --- a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h @@ -21,7 +21,7 @@ struct AbstractNaming { virtual std::regex Pattern() = 0; }; -template +template struct BaseNumbering { virtual ~BaseNumbering() = default; using FrameIndexType = typename Frame::FrameIndexType; @@ -59,7 +59,6 @@ class AbstractDataFormat { virtual std::unique_ptr ReadFrame(std::ifstream& io, FrameIndexType idx) = 0; virtual void WriteFrame(std::ofstream& io, Frame const& frame) = 0; - }; // TODO read-ahead number @@ -98,10 +97,10 @@ class FolderContainer : public AbstractDataContainer { using FrameType = typename Format::FrameType; using FrameIndexType = typename FrameType::FrameIndexType; - FolderContainer( - std::string location, std::unique_ptr naming, BaseNumbering numbering = BaseNumbering()) + FolderContainer(std::string location, std::unique_ptr naming, + std::unique_ptr> numbering = std::make_unique >()) : naming(std::move(naming)) - , numbering(numbering) { + , numbering(std::move(numbering)) { files = EnumerateFramesInDirectory(FileType(location)); } @@ -120,7 +119,7 @@ class FolderContainer : public AbstractDataContainer { } std::ifstream IndexToIStream(FrameIndexType idx) override { - return std::ifstream (files[idx].path().string().c_str(), std::ifstream::binary); + return std::ifstream(files[idx].path().string().c_str(), std::ifstream::binary); } std::ofstream IndexToOStream(FrameIndexType idx) override { // TODO some code for making paths when idx > what we already had @@ -131,8 +130,8 @@ class FolderContainer : public AbstractDataContainer { private: FileListType files; - BaseNumbering numbering; std::unique_ptr naming; + std::unique_ptr> numbering; }; // One big blob of data, each frame sitting at some offset From f2e26964bff56bc0be453a6f46c9664715cc3277 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Fri, 28 Jan 2022 09:59:20 +0100 Subject: [PATCH 09/30] tinkering with LRU from Adrian --- .../datatools/io/dataformat/DataFormat.h | 41 ++++-- .../datatools/io/dataformat/LRUCache.h | 126 ++++++++++++++++++ 2 files changed, 153 insertions(+), 14 deletions(-) create mode 100644 plugins/datatools/include/datatools/io/dataformat/LRUCache.h diff --git a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h index 246e60e3c4..54a03f2d5c 100644 --- a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h @@ -5,6 +5,8 @@ #include #include +#include "LRUCache.h" + namespace megamol { namespace datatools { namespace io { @@ -14,6 +16,7 @@ struct AbstractFrame { virtual ~AbstractFrame() = default; virtual bool Read(std::ifstream& io) = 0; virtual bool Write(std::ofstream& io) = 0; + virtual std::size_t GetSize() = 0; }; struct AbstractNaming { @@ -65,26 +68,33 @@ class AbstractDataFormat { template class AbstractDataContainer { public: - virtual ~AbstractDataContainer() = default; using FormatType = Format; using FrameType = typename Format::FrameType; using FrameIndexType = typename FrameType::FrameIndexType; - // TODO: Adrian's LRUCache here since we need most of the functionality anyway, so why not. - using FrameCollection = std::unordered_map; + using FrameCollection = LRUCache; + + AbstractDataContainer(FrameIndexType readAhead = 3) + : readAhead(readAhead) + , frames(LRUCache()) { + } + + virtual ~AbstractDataContainer() = default; // TODO generic EnumerateFrames that only files the frame indices with empty frames for now? + virtual FrameIndexType EnumerateFrames() = 0; - std::unique_ptr ReadFrame(FrameIndexType idx) { + std::shared_ptr ReadFrame(FrameIndexType idx) { // here we should actually grab the frames from some background thread that reads ahead and stuff? - FrameType f; - f.Read(IndexToIStream(idx)); - return std::make_unique(f); + return frames.findOrCreate(idx, *this); } void WriteFrame(FrameIndexType idx, FrameType const& frame) {} virtual std::ifstream IndexToIStream(FrameIndexType idx) = 0; virtual std::ofstream IndexToOStream(FrameIndexType idx) = 0; +protected: + FrameIndexType readAhead; + FrameCollection frames; }; // A directory containing several files, one for each frame @@ -99,23 +109,25 @@ class FolderContainer : public AbstractDataContainer { FolderContainer(std::string location, std::unique_ptr naming, std::unique_ptr> numbering = std::make_unique >()) - : naming(std::move(naming)) + : files(EnumerateFramesInDirectory(FileType(location))) + , naming(std::move(naming)) , numbering(std::move(numbering)) { - files = EnumerateFramesInDirectory(FileType(location)); } - // TODO specific EnumerateFrames that uses the dir enumerator below? + FrameIndexType EnumerateFrames() override { + return static_cast(files.size()); + } FileListType EnumerateFramesInDirectory(FileType Path) { auto r = std::regex(naming->Pattern()); - FileListType files; + FileListType fileList; for (const auto& entry : std::filesystem::directory_iterator(Path)) { if (std::regex_match(entry.path().filename().string(), r)) { - files.push_back(entry); + fileList.push_back(entry); } } - std::sort(files.begin(), files.end()); - return files; + std::sort(fileList.begin(), fileList.end()); + return fileList; } std::ifstream IndexToIStream(FrameIndexType idx) override { @@ -124,6 +136,7 @@ class FolderContainer : public AbstractDataContainer { std::ofstream IndexToOStream(FrameIndexType idx) override { // TODO some code for making paths when idx > what we already had // TODO what about sparse stuff, i.e. when the numbers were not consecutive? + // TODO the clang dangling pointer auto filename = files[idx].path().string().c_str(); return std::ofstream(filename, std::ifstream::binary); } diff --git a/plugins/datatools/include/datatools/io/dataformat/LRUCache.h b/plugins/datatools/include/datatools/io/dataformat/LRUCache.h new file mode 100644 index 0000000000..17016c15db --- /dev/null +++ b/plugins/datatools/include/datatools/io/dataformat/LRUCache.h @@ -0,0 +1,126 @@ +#pragma once + +/** + * MegaMol + * Copyright (c) 2021, MegaMol Dev Team + * All rights reserved. + */ + +#include +#include + +namespace megamol { +namespace datatools { +namespace io { +namespace dataformat { + +template +class LRUCache { +public: + + // TODO thread safety + + using Value = typename Container::FrameType; + using Key = typename Container::FrameType::FrameIndexType; + + LRUCache() = default; + + void clear() { + entries.clear(); + accessCount = 0; + totalByteCount = 0; + } + + std::shared_ptr get(const Key& key) const { + auto result = entries.find(key); + if (result != entries.end()) { + result->second.lastAccess = accessCount++; + return result->second.value; + } else { + return nullptr; + } + } + + std::shared_ptr operator[](const Key& key) const { + return get(key); + } + + std::shared_ptr findOrCreate(const Key& key, Container& container) { + if (maximumSize == 0) { + // I do not keep dibs, I have no space + return std::move(container.ReadFrame(key)); + } + + auto result = entries.find(key); + if (result != entries.end()) { + result->second.lastAccess = accessCount++; + return result->second.value; + } else { + Entry entry; + entry.lastAccess = accessCount++; + entry.value = std::move(container.ReadFrame(key)); + entry.byteCount = entry.value != nullptr ? entry.GetSize() : 0; + + totalByteCount += entry.byteCount; + entries.insert(std::make_pair(key, entry)); + + cleanUp(); + + return entry.value; + } + } + + void setMaximumSize(std::size_t maximumSize) { + if (this->maximumSize != maximumSize) { + this->maximumSize = maximumSize; + cleanUp(); + } + } + + std::size_t getMaximumSize() const { + return maximumSize; + } + +private: + struct Entry { + // I own the data and keep dibs so it does not disappear when unused but we still have space + std::shared_ptr value; + mutable std::size_t lastAccess = 0; + std::size_t byteCount = 0; + }; + + void cleanUp() { + if (maximumSize == 0) { + entries.clear(); + } else if (totalByteCount > maximumSize) { + // Obtain list of entries + std::vector> entryList; + for (auto it = entries.begin(); it != entries.end(); ++it) { + entryList.push_back(*it); + } + + // Sort by last access time (oldest entries last) + std::sort(entryList.begin(), entryList.end(), + [](const auto& a, const auto& b) { return a.lastAccess > b.lastAccess; }); + + // Clean up until total memory usage is below threshold + std::size_t cleanupThreshold = maximumSize * cleanupFactor; + while (totalByteCount > cleanupThreshold && !entryList.empty()) { + totalByteCount -= entryList.back().value.byteCount; + entries.erase(entryList.back().first); + entryList.pop_back(); + } + } + } + + std::unordered_map entries; + mutable std::size_t accessCount = 0; + std::size_t totalByteCount = 0; + std::size_t maximumSize = 0; + float cleanupFactor = 0.9; +}; + +} // namespace dataformat +} // namespace io +} // namespace datatools +} // namespace megamol From f72bd28fb5e3530167fdc87377fa9260ae93e7ae Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Mon, 31 Jan 2022 16:34:27 +0100 Subject: [PATCH 10/30] meanwhile, a small fix for mmpldinfo --- utils/MMPLD/mmpldinfo.py | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/utils/MMPLD/mmpldinfo.py b/utils/MMPLD/mmpldinfo.py index 019d744b0a..9e82717446 100644 --- a/utils/MMPLD/mmpldinfo.py +++ b/utils/MMPLD/mmpldinfo.py @@ -179,6 +179,7 @@ def readParticles(number, vertType, colType, file, listIndex): parser.add_argument('--bboxonly', action='count', help='only print the bbox of head/tail, not the particles)') parser.add_argument('--versiononly', action='count', help='show only file version and exit') parser.add_argument('--dumpxyz', action='store', help='dump/convert mmpld to xyz files _.xyz') +parser.add_argument('--dumpft', action='count', help='dump frame table') parseResult = parser.parse_args() specific_only = parseResult.bboxonly or parseResult.versiononly @@ -239,22 +240,36 @@ def readParticles(number, vertType, colType, file, listIndex): exit(1) frameTable = [] + refFrameOffset = 60 for x in range(frameCount + 1): - frameTable.append(getUInt64(f)) + frameOffset = getUInt64(f) + if frameOffset < refFrameOffset: + print(f"error: frame table entry {x} is invalid: not monotonically increasing or too small first offset: ({frameOffset}) < ({refFrameOffset})") + refFrameOffset = frameOffset + frameTable.append(frameOffset) if (f.tell() != frameTable[0]): - print("warning: dead data trailing header") + print(f"warning: dead data trailing header: position after reading frame table ({f.tell()}) is not the start of the first frame ({frameTable[0]})") + + if os.path.getsize(filename) != frameTable[frameCount]: + print(f"error: file end pointer (frameTable[{frameCount}]) in frame table inconsistent with file size ({os.path.getsize(filename)})! ", end='') + if os.path.getsize(filename) < frameTable[frameCount]: + print("Data truncated.") + if os.path.getsize(filename) > frameTable[frameCount]: + print("Trailing garbage.") + + if parseResult.dumpft: + print("Frame Table:") + print("index offset") + sum = 0 + for i in range(len(frameTable)): + print(f"{i:5}: {frameTable[i]:20}") + if i < frameCount: + sum = sum + frameTable[i+1] - frameTable[i] + # else: + # print(f"ignoring entry {i}, should be the end pointer") + print(f"average frame size: {sum / frameCount}") - f.seek(0, os.SEEK_END) - if (f.tell() < frameTable[frameCount]): - print("warning: file truncated") - if (f.tell() > frameTable[frameCount]): - print("warning: dead data trailing body") - - for x in range(frameCount): - if (frameTable[x + 1] <= frameTable[x]): - print("frame table corrupted at frame " + str(x)) - minNumLists = 0 maxNumLists = 0 minNumParts = 0 From efb74c645584e6a4206bed7a3543477f19a60fcb Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 2 Feb 2022 12:08:28 +0100 Subject: [PATCH 11/30] tinkering... --- .../datatools/io/dataformat/DataFormat.h | 23 +++++++---- .../datatools/io/dataformat/PNGDataFormat.h | 41 ++++++++++++++----- plugins/datatools/src/datatools.cpp | 2 +- 3 files changed, 46 insertions(+), 20 deletions(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h index 54a03f2d5c..8c37d90409 100644 --- a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h @@ -12,6 +12,8 @@ namespace datatools { namespace io { namespace dataformat { +// every call ideally should implement this, as a generic interface for "brain dumps" +// this has *nothing* to do with proper file formats. readers support these to provide data via the said call struct AbstractFrame { virtual ~AbstractFrame() = default; virtual bool Read(std::ifstream& io) = 0; @@ -19,15 +21,18 @@ struct AbstractFrame { virtual std::size_t GetSize() = 0; }; +struct AbstractMetadata { + using FrameIndexType = uint32_t; +}; + struct AbstractNaming { virtual ~AbstractNaming() = default; virtual std::regex Pattern() = 0; }; -template +template struct BaseNumbering { virtual ~BaseNumbering() = default; - using FrameIndexType = typename Frame::FrameIndexType; BaseNumbering(uint8_t digits = 5) : digits(digits) { reg = std::regex(std::string("(\d{") + std::to_string(digits) + "})"); @@ -57,11 +62,10 @@ class AbstractDataFormat { public: virtual ~AbstractDataFormat() = default; using FrameType = Frame; - using FrameIndexType = typename FrameType::FrameIndexType; using FileType = std::filesystem::directory_entry; - virtual std::unique_ptr ReadFrame(std::ifstream& io, FrameIndexType idx) = 0; - virtual void WriteFrame(std::ofstream& io, Frame const& frame) = 0; + //virtual std::unique_ptr ReadFrame(std::ifstream& io, FrameIndexType idx) = 0; + //virtual void WriteFrame(std::ofstream& io, Frame const& frame) = 0; }; // TODO read-ahead number @@ -104,11 +108,12 @@ class FolderContainer : public AbstractDataContainer { public: using FileType = typename Format::FileType; using FileListType = std::vector; - using FrameType = typename Format::FrameType; - using FrameIndexType = typename FrameType::FrameIndexType; + using FrameIndexType = typename Format::FrameIndexType; + + // TODO fix basenumbering FolderContainer(std::string location, std::unique_ptr naming, - std::unique_ptr> numbering = std::make_unique >()) + std::unique_ptr> numbering = std::make_unique>()) : files(EnumerateFramesInDirectory(FileType(location))) , naming(std::move(naming)) , numbering(std::move(numbering)) { @@ -144,7 +149,7 @@ class FolderContainer : public AbstractDataContainer { private: FileListType files; std::unique_ptr naming; - std::unique_ptr> numbering; + std::unique_ptr> numbering; }; // One big blob of data, each frame sitting at some offset diff --git a/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h b/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h index 195bb8ac4c..c1b913077b 100644 --- a/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h @@ -11,18 +11,36 @@ namespace datatools { namespace io { namespace dataformat { -// todo where would we point when we read a mmpld frame? -// todo: end pointer? -// does this map to MMPLD and ADIOS? -struct PNGFrame : AbstractFrame { - using FrameIndexType = uint32_t; +// this this goes into the call. with that exact read/write signature for brain dumps +struct ImageFrame : AbstractFrame { using SizeType = uint32_t; - FrameIndexType FrameIndex = 0; + struct ChannelType { + enum Value : uint8_t {UINT8, FLOAT}; + ChannelType() = default; + constexpr ChannelType(Value v) : val(v) {} + constexpr operator Value() const { + return val; + } + explicit operator bool() = delete; + constexpr uint8_t GetByteSize() const { + switch (val) { + case UINT8: + return sizeof(uint8_t); + case FLOAT: + return sizeof(float); + } + return sizeof(uint8_t); + } + private: + Value val; + }; + + ChannelType Type; + uint8_t NumChannels = 1; SizeType Width = 0, Height = 0; - megamol::core::utility::graphics::ScreenShotComments::comments_storage_map comments; - std::vector Values; + std::vector Values; bool Read(std::ifstream& io) override { return true; @@ -38,8 +56,11 @@ struct PNGNaming : AbstractNaming { } }; -using PNGDataFormat = AbstractDataFormat; -using PNGFileCollection = FolderContainer; +// todo where would we point when we read a mmpld frame? +// todo: end pointer? +// does this map to MMPLD and ADIOS? +//using PNGDataFormat = AbstractDataFormat; +//using PNGFileCollection = FolderContainer; } // namespace dataformat } // namespace io diff --git a/plugins/datatools/src/datatools.cpp b/plugins/datatools/src/datatools.cpp index 99ea0ca89e..bb23541a51 100644 --- a/plugins/datatools/src/datatools.cpp +++ b/plugins/datatools/src/datatools.cpp @@ -191,7 +191,7 @@ class DatatoolsPluginInstance : public megamol::core::utility::plugins::Abstract // TODO BUG HAZARD this is just for testing, it needs to go away! //io::dataformat::CSVFileCollection coll("c:/temp"); - io::dataformat::PNGFileCollection coll2("c:\temp", std::make_unique()); + //io::dataformat::PNGFileCollection coll2("c:\temp", std::make_unique()); } }; } // namespace megamol::datatools From 9ef222d5ff36d325dc9526c704f5dabe84da713c Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 2 Feb 2022 14:22:51 +0100 Subject: [PATCH 12/30] this is no good. --- .../include/datatools/io/dataformat/PNGDataFormat.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h b/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h index c1b913077b..ef0b234667 100644 --- a/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h @@ -12,7 +12,7 @@ namespace io { namespace dataformat { // this this goes into the call. with that exact read/write signature for brain dumps -struct ImageFrame : AbstractFrame { +struct Image2DFrame : AbstractFrame { using SizeType = uint32_t; struct ChannelType { @@ -40,14 +40,19 @@ struct ImageFrame : AbstractFrame { uint8_t NumChannels = 1; SizeType Width = 0, Height = 0; - std::vector Values; - + void SetData() {} bool Read(std::ifstream& io) override { return true; } bool Write(std::ofstream& io) override { return true; } + std::size_t GetSize() override { + + } + +private: + std::vector Values; }; struct PNGNaming : AbstractNaming { From 614345db345e09373f3a9f14ed19d754892dfe56 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 2 Feb 2022 18:47:28 +0100 Subject: [PATCH 13/30] still plot holes --- .../datatools/io/dataformat/DataFormat.h | 6 +- .../datatools/io/dataformat/ImageCalls.h | 107 ++++++++++++++++++ .../datatools/io/dataformat/PNGDataFormat.h | 45 +------- 3 files changed, 111 insertions(+), 47 deletions(-) create mode 100644 plugins/datatools/include/datatools/io/dataformat/ImageCalls.h diff --git a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h index 8c37d90409..9adb406be5 100644 --- a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h @@ -16,9 +16,9 @@ namespace dataformat { // this has *nothing* to do with proper file formats. readers support these to provide data via the said call struct AbstractFrame { virtual ~AbstractFrame() = default; - virtual bool Read(std::ifstream& io) = 0; - virtual bool Write(std::ofstream& io) = 0; - virtual std::size_t GetSize() = 0; + virtual bool Read(std::istream& io) = 0; + virtual bool Write(std::ostream& io) const = 0; + [[nodiscard]] virtual std::size_t ByteSize() const = 0; }; struct AbstractMetadata { diff --git a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h new file mode 100644 index 0000000000..12d04d76cb --- /dev/null +++ b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h @@ -0,0 +1,107 @@ +#pragma once + +#include "DataFormat.h" + +namespace megamol { +namespace datatools { +namespace io { +namespace dataformat { + +// do we want to pull out an interface? what kind of code do we write against this? +// which variants do we want to handle dynamically? different channel types probably. dimensionality is unlikely. +// different numbers of components? +template +struct ImageFrame : AbstractFrame { + static_assert(Dimensions > 0 && Dimensions < 4, "ImageFrame supports 1D, 2D, and 3D Images only"); + + using SizeType = uint32_t; + using ComponentSizeType = uint8_t; + + bool Read(std::istream& io) override { + uint8_t dims; + io.read(reinterpret_cast(&dims), sizeof(uint8_t)); + if (dims != Dimensions) + throw std::invalid_argument("inappropriate number of dimensions in ImageFrame dump!"); + io.read(static_cast(&this->numComponents), sizeof(ComponentSizeType)); + io.read(static_cast(&this->width), sizeof(SizeType)); + io.read(static_cast(&this->height), sizeof(SizeType)); + io.read(static_cast(&this->depth), sizeof(SizeType)); + data.resize(width * height * depth * numComponents); + io.read(this->data.data(), ByteSize()); + return true; + } + + bool Write(std::ostream& io) const override { + uint8_t dims = Dimensions; + io.write(reinterpret_cast(&dims), sizeof(uint8_t)); + io.write(static_cast(&this->numComponents), sizeof(ComponentSizeType)); + io.write(static_cast(&this->width), sizeof(SizeType)); + io.write(static_cast(&this->height), sizeof(SizeType)); + io.write(static_cast(&this->depth), sizeof(SizeType)); + io.write(this->data.data(), ByteSize()); + return true; + } + + void SetData(std::vector&& data, ComponentSizeType numComponents = 1, SizeType width = 1, + SizeType height = 1, SizeType depth = 1) { + ASSERT(width * height * depth * numComponents == data.size()); + // some asserts regarding Dimensions and parameters? or rather not? + this->data = data; + this->numComponents = numComponents; + this->width = width; + this->height = height; + this->depth = depth; + } + + const std::vector GetData() { + return data; + } + + ChannelType GetValue(SizeType index) { + return data[index]; + } + + void SetValue(SizeType index, ChannelType val) { + data[index] = val; + } + + inline SizeType ValueIndex(SizeType x, SizeType y = 0, SizeType z = 0, ComponentSizeType c = 0) { + return ((z * height + y) * width + x) * numComponents + c; + } + + [[nodiscard]] std::size_t ByteSize() const override { + return width * height * depth * numComponents * sizeof(ChannelType); + } + + [[nodiscard]] std::size_t ElementSize() const { + return numComponents * sizeof(ChannelType); + } + + [[nodiscard]] SizeType NumElements() const { + return width * height * depth; + } + + [[nodiscard]] SizeType Width() const { + return width; + } + + [[nodiscard]] SizeType Height() const { + return height; + } + + [[nodiscard]] SizeType Depth() const { + return depth; + } + +private: + std::vector data; + ComponentSizeType numComponents = 1; + SizeType width = 0, height = 0, depth = 0; +}; + +using Uint8Image2DFrame = ImageFrame; + +} // namespace dataformat +} // namespace io +} // namespace datatools +} // namespace megamol diff --git a/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h b/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h index ef0b234667..2183089a78 100644 --- a/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/PNGDataFormat.h @@ -5,56 +5,13 @@ #include #include +#include namespace megamol { namespace datatools { namespace io { namespace dataformat { -// this this goes into the call. with that exact read/write signature for brain dumps -struct Image2DFrame : AbstractFrame { - using SizeType = uint32_t; - - struct ChannelType { - enum Value : uint8_t {UINT8, FLOAT}; - ChannelType() = default; - constexpr ChannelType(Value v) : val(v) {} - constexpr operator Value() const { - return val; - } - explicit operator bool() = delete; - constexpr uint8_t GetByteSize() const { - switch (val) { - case UINT8: - return sizeof(uint8_t); - case FLOAT: - return sizeof(float); - } - return sizeof(uint8_t); - } - private: - Value val; - }; - - ChannelType Type; - uint8_t NumChannels = 1; - SizeType Width = 0, Height = 0; - - void SetData() {} - bool Read(std::ifstream& io) override { - return true; - } - bool Write(std::ofstream& io) override { - return true; - } - std::size_t GetSize() override { - - } - -private: - std::vector Values; -}; - struct PNGNaming : AbstractNaming { std::regex Pattern() override { return std::regex("^.*?\\.png"); From af577cdee941dd0f2db0833edb092cfe14d4f3e7 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 3 Feb 2022 18:49:32 +0100 Subject: [PATCH 14/30] we really have some weird MMPLD files flying around... --- utils/MMPLD/mmpldinfo.py | 49 ++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/utils/MMPLD/mmpldinfo.py b/utils/MMPLD/mmpldinfo.py index 9e82717446..0ddf52583d 100644 --- a/utils/MMPLD/mmpldinfo.py +++ b/utils/MMPLD/mmpldinfo.py @@ -67,14 +67,18 @@ def listFramedata(parseResult, frame): # returns timeStamp, numLists def readFrameHeader(file): + mem = 0 timestamp = 0.0 if (version >= 102): timestamp = getFloat(f) + mem += 4 numLists = getUInt(f) - return timestamp, numLists + mem +=4 + return timestamp, numLists, mem # returns vertType, colType, stride, globalRad, globalCol, intensityRange, listNumParts, listBBox def readListHeader(file): + frameMem = 0 vertType = getByte(f) if (vertType >= len(vertexNames)): vertType = 0 @@ -83,6 +87,7 @@ def readListHeader(file): colType = 0 if (vertType == 0): colType = 0 + frameMem += 2 listFramedata(parseResult, fi) and print(" #%u: %s, %s" % (li, vertexNames[vertType], colorNames[colType])) stride = vertexSizes[vertType] + colorSizes[colType] @@ -94,23 +99,29 @@ def readListHeader(file): listBBox = (0.0, 0.0, 0.0, 0.0, 0.0, 0.0) if (vertType == 1 or vertType == 3 or vertType == 4): globalRad = getFloat(f) + frameMem += 4 listFramedata(parseResult, fi) and print(" global radius: %f" % (globalRad)) if (colType == 0): globalCol = [getByte(f) for x in range(4)] + frameMem += 4 listFramedata(parseResult, fi) and print(" global color: (%u, %u, %u, %u)" % (tuple(globalCol))) elif (colType == 3 or colType == 7): intensityRange = [getFloat(f) for x in range(2)] + frameMem += 8 listFramedata(parseResult, fi) and print(" intensity color range: [%f, %f]" % (tuple(intensityRange))) listNumParts = getUInt64(f) + frameMem += 8 #listFramedata and print(" %Q particle%s" % countPlural(listNumParts)) listFramedata(parseResult, fi) and print(" {0} particle{1}".format(*pluralTuple(listNumParts))) + frameMem += listNumParts * stride if (version >= 103): listBBox = [getFloat(f) for x in range(6)] + frameMem += 6 * 4 listFramedata(parseResult, fi) and print(" list bounding box: (%f, %f, %f) - (%f, %f, %f)" % (tuple(box))) - return vertType, colType, stride, globalRad, globalCol, intensityRange, listNumParts, listBBox + return vertType, colType, stride, globalRad, globalCol, intensityRange, listNumParts, listBBox, frameMem def readParticles(number, vertType, colType, file, listIndex): mins = [sys.float_info.max, sys.float_info.max, sys.float_info.max] @@ -180,10 +191,12 @@ def readParticles(number, vertType, colType, file, listIndex): parser.add_argument('--versiononly', action='count', help='show only file version and exit') parser.add_argument('--dumpxyz', action='store', help='dump/convert mmpld to xyz files _.xyz') parser.add_argument('--dumpft', action='count', help='dump frame table') +parser.add_argument('--try-recovery', action='count', help='try interpreting trailing dead data as a dangling frame') parseResult = parser.parse_args() specific_only = parseResult.bboxonly or parseResult.versiononly hideVersion = parseResult.bboxonly +fakeFrame = False if (not specific_only): print("") @@ -250,16 +263,26 @@ def readParticles(number, vertType, colType, file, listIndex): if (f.tell() != frameTable[0]): print(f"warning: dead data trailing header: position after reading frame table ({f.tell()}) is not the start of the first frame ({frameTable[0]})") + if parseResult.v: + print("dead data:") + for i in range(frameTable[0] - f.tell()): + print(hex(getByte(f)), end=' ') + print() if os.path.getsize(filename) != frameTable[frameCount]: - print(f"error: file end pointer (frameTable[{frameCount}]) in frame table inconsistent with file size ({os.path.getsize(filename)})! ", end='') + print(f"error: file end pointer (frameTable[{frameCount}]) in frame table inconsistent with file size ({os.path.getsize(filename)}): ", end='') if os.path.getsize(filename) < frameTable[frameCount]: print("Data truncated.") if os.path.getsize(filename) > frameTable[frameCount]: print("Trailing garbage.") + if parseResult.try_recovery: + print("--> Appending hypothetical frame until the end of the file <--") + fakeFrame = True + frameCount += 1 + frameTable.append(os.path.getsize(filename)) if parseResult.dumpft: - print("Frame Table:") + print(f"Frame Table{' (recovered)' if fakeFrame else ''}:") print("index offset") sum = 0 for i in range(len(frameTable)): @@ -280,7 +303,10 @@ def readParticles(number, vertType, colType, file, listIndex): for fi in range(frameCount): f.seek(frameTable[fi], os.SEEK_SET) - timeStamp, numLists = readFrameHeader(f) + expectedFrameSize = frameTable[fi+1] - frameTable[fi] + if parseResult.v: + print(f"jumping to frame {fi}, expecting a frame of size {expectedFrameSize}") + timeStamp, numLists, frameTotalMem = readFrameHeader(f) timeStampString = "" if (version >= 102): timeStampString = "(%f)" % timeStamp @@ -294,9 +320,10 @@ def readParticles(number, vertType, colType, file, listIndex): maxNumLists = numLists frameNumParts = 0 for li in range(numLists): - vertType, colType, stride, globalRad, globalCol, intensityRange, listNumParts, listBBox = readListHeader(f) + vertType, colType, stride, globalRad, globalCol, intensityRange, listNumParts, listBBox, frameMem = readListHeader(f) frameNumParts += listNumParts - + frameTotalMem += frameMem + if (not parseResult.dumpxyz): if (listFramedata(parseResult, fi)): if (parseResult.head): @@ -328,8 +355,10 @@ def readParticles(number, vertType, colType, file, listIndex): else: f.seek(listNumParts * stride, os.SEEK_CUR) - if (f.tell() != frameTable[fi + 1]): - print("warning: trailing data after frame %u or frame table corrupted" % (fi)) + if frameTotalMem != expectedFrameSize: + print(f"frame size {frameTotalMem} differs from expected size {expectedFrameSize} (from frameTable)") + # if (f.tell() != frameTable[fi + 1]): + # print("warning: trailing data after frame %u or frame table corrupted" % (fi)) if (fi == 0): minNumParts = maxNumParts = frameNumParts else: @@ -349,7 +378,7 @@ def readParticles(number, vertType, colType, file, listIndex): timeStamp, numLists = readFrameHeader(f) for li in range(numLists): - vertType, colType, stride, globalRad, globalCol, intensityRange, listNumParts, listBBox = readListHeader(f) + vertType, colType, stride, globalRad, globalCol, intensityRange, listNumParts, listBBox, particleMem = readListHeader(f) readParticles(listNumParts, vertType, colType, f, li) accumulatedParts += frameNumParts From 50a3cf3b45197e38064bffe07e2239b05ec02b68 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Fri, 4 Feb 2022 08:33:56 +0100 Subject: [PATCH 15/30] frametable hex to facilitate manual fixing --- utils/MMPLD/mmpldinfo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/MMPLD/mmpldinfo.py b/utils/MMPLD/mmpldinfo.py index 0ddf52583d..c12c3a32d9 100644 --- a/utils/MMPLD/mmpldinfo.py +++ b/utils/MMPLD/mmpldinfo.py @@ -283,10 +283,10 @@ def readParticles(number, vertType, colType, file, listIndex): if parseResult.dumpft: print(f"Frame Table{' (recovered)' if fakeFrame else ''}:") - print("index offset") + print("index offset hex") sum = 0 for i in range(len(frameTable)): - print(f"{i:5}: {frameTable[i]:20}") + print(f"{i:5}: {frameTable[i]:20} {frameTable[i]:#018x}") if i < frameCount: sum = sum + frameTable[i+1] - frameTable[i] # else: From 5a43922dd00cbf0ee5bdc193c2b33dd6576f11a0 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 10 Feb 2022 17:05:38 +0100 Subject: [PATCH 16/30] tiny cosmetic fix in graph errors --- core/src/MegaMolGraph.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/MegaMolGraph.cpp b/core/src/MegaMolGraph.cpp index ffb717bda6..ebea64af0e 100644 --- a/core/src/MegaMolGraph.cpp +++ b/core/src/MegaMolGraph.cpp @@ -600,7 +600,7 @@ bool megamol::core::MegaMolGraph::add_call(CallInstantiationRequest_t const& req if (!slots.empty()) { slot_names = ""; for (auto x = 0; x < slots.size() - 1; ++x) { - slot_names += slots[x]->Name(); + slot_names += slots[x]->Name() + ", "; } slot_names += slots[slots.size() - 1]->Name(); } @@ -620,7 +620,7 @@ bool megamol::core::MegaMolGraph::add_call(CallInstantiationRequest_t const& req if (!slots.empty()) { slot_names = ""; for (auto x = 0; x < slots.size() - 1; ++x) { - slot_names += slots[x]->Name(); + slot_names += slots[x]->Name() + ", "; } slot_names += slots[slots.size() - 1]->Name(); } From a21d2961835c962b3a6dac48e2cccbb6cbef8869 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 10 Feb 2022 18:08:24 +0100 Subject: [PATCH 17/30] another error output fix --- core/src/CoreInstance.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/CoreInstance.cpp b/core/src/CoreInstance.cpp index a8a840d977..c43882dd9f 100644 --- a/core/src/CoreInstance.cpp +++ b/core/src/CoreInstance.cpp @@ -3236,6 +3236,9 @@ void megamol::core::CoreInstance::loadPlugin( } catch (const vislib::Exception& vex) { megamol::core::utility::log::Log::DefaultLog.WriteMsg( loadFailedLevel, "Unable to load Plugin: %s (%s, &d)", vex.GetMsgA(), vex.GetFile(), vex.GetLine()); + } catch (const std::exception& ex) { + megamol::core::utility::log::Log::DefaultLog.WriteMsg( + loadFailedLevel, "Unable to load Plugin: %s", ex.what()); } catch (...) { megamol::core::utility::log::Log::DefaultLog.WriteMsg( loadFailedLevel, "Unable to load Plugin: unknown exception"); From d9de52305cdff775c76ef4296beddde41b2c194c Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 10 Feb 2022 18:08:53 +0100 Subject: [PATCH 18/30] more tinkering --- .../datatools/io/dataformat/CSVDataFormat.h | 12 +- .../datatools/io/dataformat/ImageCalls.h | 238 +++++++++++++++--- .../io/dataformat/ImageElementType.h | 56 +++++ 3 files changed, 265 insertions(+), 41 deletions(-) create mode 100644 plugins/datatools/include/datatools/io/dataformat/ImageElementType.h diff --git a/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h b/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h index 8a49fb19d7..b6a628de0d 100644 --- a/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/CSVDataFormat.h @@ -22,12 +22,12 @@ struct CSVFrame : AbstractFrame { std::vector ColumnInfos; std::vector Values; - bool Read(std::ifstream& io) override { - return true; - } - bool Write(std::ofstream& io) override { - return true; - } + //bool Read(std::ifstream& io) override { + // return true; + //} + //bool Write(std::ofstream& io) override { + // return true; + //} }; using CSVDataFormat = AbstractDataFormat; diff --git a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h index 12d04d76cb..439a06e1cc 100644 --- a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h +++ b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h @@ -1,6 +1,7 @@ #pragma once #include "DataFormat.h" +#include "ImageElementType.h" namespace megamol { namespace datatools { @@ -10,71 +11,210 @@ namespace dataformat { // do we want to pull out an interface? what kind of code do we write against this? // which variants do we want to handle dynamically? different channel types probably. dimensionality is unlikely. // different numbers of components? -template + +// TODO: get rid of NumComponents. There is only one, keep multiple images if you want more channels. +// exception: RGBA8 as UINT32 ? Does it matter? + +// typename ChannelType does not work, that is not a static decision. +// For some data sources you only know after actually opening the file what's in it. +// TODO: volume ist ein byte-vektor und wir benutzen span. fertig. +template struct ImageFrame : AbstractFrame { static_assert(Dimensions > 0 && Dimensions < 4, "ImageFrame supports 1D, 2D, and 3D Images only"); using SizeType = uint32_t; - using ComponentSizeType = uint8_t; bool Read(std::istream& io) override { - uint8_t dims; + uint8_t dims, chanTypes; io.read(reinterpret_cast(&dims), sizeof(uint8_t)); if (dims != Dimensions) - throw std::invalid_argument("inappropriate number of dimensions in ImageFrame dump!"); - io.read(static_cast(&this->numComponents), sizeof(ComponentSizeType)); - io.read(static_cast(&this->width), sizeof(SizeType)); - io.read(static_cast(&this->height), sizeof(SizeType)); - io.read(static_cast(&this->depth), sizeof(SizeType)); - data.resize(width * height * depth * numComponents); - io.read(this->data.data(), ByteSize()); + throw std::invalid_argument("ImageFrame::Read: inappropriate number of dimensions in ImageFrame dump!"); + io.read(reinterpret_cast(&chanTypes), sizeof(uint8_t)); + elementType.Set(chanTypes); + io.read(reinterpret_cast(&this->width), sizeof(SizeType)); + io.read(reinterpret_cast(&this->height), sizeof(SizeType)); + io.read(reinterpret_cast(&this->depth), sizeof(SizeType)); + data.resize(static_cast(width) * height * depth); + io.read(reinterpret_cast(this->data.data()), ByteSize()); return true; } bool Write(std::ostream& io) const override { - uint8_t dims = Dimensions; - io.write(reinterpret_cast(&dims), sizeof(uint8_t)); - io.write(static_cast(&this->numComponents), sizeof(ComponentSizeType)); - io.write(static_cast(&this->width), sizeof(SizeType)); - io.write(static_cast(&this->height), sizeof(SizeType)); - io.write(static_cast(&this->depth), sizeof(SizeType)); - io.write(this->data.data(), ByteSize()); + uint8_t const dims = Dimensions; + io.write(reinterpret_cast(&dims), sizeof(uint8_t)); + io.write(reinterpret_cast(&elementType), sizeof(uint8_t)); + io.write(reinterpret_cast(&this->width), sizeof(SizeType)); + io.write(reinterpret_cast(&this->height), sizeof(SizeType)); + io.write(reinterpret_cast(&this->depth), sizeof(SizeType)); + io.write(reinterpret_cast(this->data.data()), ByteSize()); return true; } - void SetData(std::vector&& data, ComponentSizeType numComponents = 1, SizeType width = 1, - SizeType height = 1, SizeType depth = 1) { - ASSERT(width * height * depth * numComponents == data.size()); - // some asserts regarding Dimensions and parameters? or rather not? + void SetData(std::vector&& data, ImageElementType channelType, SizeType width = 1, SizeType height = 1, + SizeType depth = 1) { + ASSERT(width * height * depth * channelType.ByteSize() == data.size()); this->data = data; - this->numComponents = numComponents; this->width = width; this->height = height; this->depth = depth; + this->elementType = channelType; + } + + // data will be controlled by this instance, caller loses access! + void SetData(uint8_t* data, std::size_t count, ImageElementType channelType, SizeType width = 1, SizeType height = 1, SizeType depth = 1) { + auto vec = std::vector(data, data + count); + delete[] data; + SetData(vec, channelType, width, height, depth); + } + + template + constexpr T* ViewAs() const { + return static_cast(data.data()); + } + + template + std::vector GetCopy() { + std::vector out; + out.reserve(NumElements()); + switch (elementType) { + case ImageElementType::UINT8: + CopyInto(out); + break; + case ImageElementType::UINT16: + CopyInto(out); + break; + case ImageElementType::UINT32: + // AKA case ChannelType::RGBA8: + CopyInto(out); + break; + case ImageElementType::FLOAT: + CopyInto(out); + break; + case ImageElementType::DOUBLE: + CopyInto(out); + break; + default: + throw std::logic_error("ImageFrame::GetCopy: invalid elementType"); + } + return std::move(out); + } + + template + std::vector GetCopyNormalized() { + std::vector out; + out.reserve(NumElements()); + switch (elementType) { + case ImageElementType::UINT8: + CopyIntoNormalized(out); + break; + case ImageElementType::UINT16: + CopyIntoNormalized(out); + break; + case ImageElementType::UINT32: + // AKA case ChannelType::RGBA8: + CopyIntoNormalized(out); + break; + case ImageElementType::FLOAT: + CopyIntoNormalized(out); + break; + case ImageElementType::DOUBLE: + CopyIntoNormalized(out); + break; + default: + throw std::logic_error("ImageFrame::GetCopyNormalized: invalid elementType"); + } + return std::move(out); } - const std::vector GetData() { - return data; + template + T GetValue(SizeType index) const { + if (index >= NumElements()) + throw std::invalid_argument("ImageFrame::GetValue: index out of bounds"); + switch (elementType) { + case ImageElementType::UINT8: + return static_cast(ViewAs()[index]); + break; + case ImageElementType::UINT16: + return static_cast(ViewAs()[index]); + break; + case ImageElementType::UINT32: + // AKA case ChannelType::RGBA8: + return static_cast(ViewAs()[index]); + break; + case ImageElementType::FLOAT: + return static_cast(ViewAs()[index]); + break; + case ImageElementType::DOUBLE: + return static_cast(ViewAs()[index]); + break; + default: + throw std::logic_error("ImageFrame::GetValue: invalid elementType"); + } } - ChannelType GetValue(SizeType index) { - return data[index]; + template + void SetValue(SizeType index, T val) { + if (index >= NumElements()) + throw std::invalid_argument("ImageFrame::SetValue: index out of bounds"); + switch (elementType) { + case ImageElementType::UINT8: + SetAbsolute(index, val); + break; + case ImageElementType::UINT16: + SetAbsolute(index, val); + break; + case ImageElementType::UINT32: + // AKA case ChannelType::RGBA8: + SetAbsolute(index, val); + break; + case ImageElementType::FLOAT: + SetAbsolute(index, val); + break; + case ImageElementType::DOUBLE: + SetAbsolute(index, val); + break; + default: + throw std::logic_error("ImageFrame::SetValue: invalid elementType"); + } } - void SetValue(SizeType index, ChannelType val) { - data[index] = val; + template + void SetValueNormalized(SizeType index, T val, T maximum = std::numeric_limits::max()) { + if (index >= NumElements()) + throw std::invalid_argument("ImageFrame::SetValueNormalized: index out of bounds"); + const double relative = static_cast(val) / maximum; + switch (elementType) { + case ImageElementType::UINT8: + SetRelative(index, relative); + break; + case ImageElementType::UINT16: + SetRelative(index, relative); + break; + case ImageElementType::UINT32: + // AKA case ChannelType::RGBA8: + SetRelative(index, relative); + break; + case ImageElementType::FLOAT: + SetRelative(index, relative); + break; + case ImageElementType::DOUBLE: + SetRelative(index, relative); + break; + default: + throw std::logic_error("ImageFrame::SetValueNormalized: invalid elementType"); + } } - inline SizeType ValueIndex(SizeType x, SizeType y = 0, SizeType z = 0, ComponentSizeType c = 0) { - return ((z * height + y) * width + x) * numComponents + c; + [[nodiscard]] SizeType ValueIndex(SizeType x, SizeType y = 0, SizeType z = 0) const { + return (z * height + y) * width + x; } [[nodiscard]] std::size_t ByteSize() const override { - return width * height * depth * numComponents * sizeof(ChannelType); + return width * height * depth * elementType.ByteSize(); } [[nodiscard]] std::size_t ElementSize() const { - return numComponents * sizeof(ChannelType); + return elementType.ByteSize(); } [[nodiscard]] SizeType NumElements() const { @@ -94,12 +234,40 @@ struct ImageFrame : AbstractFrame { } private: - std::vector data; - ComponentSizeType numComponents = 1; + template + T* AccessAs() { + return reinterpret_cast(data.data()); + } + + template + void SetRelative(SizeType index, double relative) { + AccessAs()[index] = static_cast(relative * std::numeric_limits::max()); + } + + template + void SetAbsolute(SizeType index, Source val) { + AccessAs()[index] = static_cast(val); + } + + template + void CopyInto(std::vector& out) { + std::transform(ViewAs(), ViewAs() + NumElements(), std::back_inserter(out), + [](const auto& val) { return static_cast(val); }); + } + + template + void CopyIntoNormalized(std::vector& out) { + std::transform(ViewAs(), ViewAs() + NumElements(), std::back_inserter(out), [](const auto& val) { + return static_cast((val / std::numeric_limits::max()) * std::numeric_limits::max()); + }); + } + + std::vector data; SizeType width = 0, height = 0, depth = 0; + ImageElementType elementType = ImageElementType::UINT8; }; -using Uint8Image2DFrame = ImageFrame; +//using Uint8Image2DFrame = ImageFrame; } // namespace dataformat } // namespace io diff --git a/plugins/datatools/include/datatools/io/dataformat/ImageElementType.h b/plugins/datatools/include/datatools/io/dataformat/ImageElementType.h new file mode 100644 index 0000000000..84011aabb6 --- /dev/null +++ b/plugins/datatools/include/datatools/io/dataformat/ImageElementType.h @@ -0,0 +1,56 @@ +namespace megamol { +namespace datatools { +namespace io { +namespace dataformat { + +class ImageElementType { +public: + enum Value : uint8_t { + UINT8 = 1, + UINT16 = 2, + UINT32 = 3, // This is a semantic alias! OK? + RGBA8 = 3, // This is a semantic alias! OK? + FLOAT = 4, + DOUBLE = 5 + }; + ImageElementType() = default; + constexpr ImageElementType(Value ct) : value(ct) {} + constexpr operator Value() const { + return value; + } + explicit operator bool() = delete; + void Set(uint8_t other) { + if (other < 1 || other > 5) + throw std::invalid_argument("value not supported"); + value = static_cast(other); + } + //constexpr operator uint8_t() const { + // return static_cast(value); + //} + + [[nodiscard]] constexpr std::size_t ByteSize() const { + switch (value) { + case UINT8: + return sizeof(uint8_t); + case UINT16: + return sizeof(uint16_t); + case UINT32: + // AKA case RGBA8: + return sizeof(uint32_t); + case FLOAT: + return sizeof(float); + case DOUBLE: + return sizeof(double); + } + return 0; + } + +private: + Value value = UINT8; +}; + + +} // namespace dataformat +} // namespace io +} // namespace datatools +} // namespace megamol From ef1c94a531986545597b8b183c63e1fbd1e1b6bc Mon Sep 17 00:00:00 2001 From: gralkapk Date: Mon, 14 Feb 2022 11:43:53 +0100 Subject: [PATCH 19/30] dispatch example --- .../datatools/io/dataformat/ImageCalls.h | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h index 439a06e1cc..12c83f8c1e 100644 --- a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h +++ b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h @@ -205,6 +205,41 @@ struct ImageFrame : AbstractFrame { } } + template + void SetValueNormalized2(SizeType index, T val, T maximum = std::numeric_limits::max()) { + if (index >= NumElements()) + throw std::invalid_argument("ImageFrame::SetValueNormalized: index out of bounds"); + const double relative = static_cast(val) / maximum; + Dispatcher::dispatch(elementType)(this, index, relative); + } + + // https://stackoverflow.com/questions/16552166/c-function-dispatch-with-template-parameters + template + struct Dispatcher { + static typename FunctionWrapper::Function* dispatch(ImageElementType::Value it) { + switch (it) { + case ImageElementType::UINT8: + return &FunctionWrapper::template run; + break; + case ImageElementType::UINT16: + return &FunctionWrapper::template run; + break; + case ImageElementType::UINT32: + // AKA case ChannelType::RGBA8: + return &FunctionWrapper::template run; + break; + case ImageElementType::FLOAT: + return &FunctionWrapper::template run; + break; + case ImageElementType::DOUBLE: + return &FunctionWrapper::template run; + break; + default: + throw std::logic_error("ImageFrame::Dispatcher: invalid elementType"); + } + } + }; + [[nodiscard]] SizeType ValueIndex(SizeType x, SizeType y = 0, SizeType z = 0) const { return (z * height + y) * width + x; } @@ -244,6 +279,15 @@ struct ImageFrame : AbstractFrame { AccessAs()[index] = static_cast(relative * std::numeric_limits::max()); } + struct SetRelative_FW { + using Function = void(ImageFrame*, SizeType, double); + + template + static void run(ImageFrame* that, SizeType index, double relative) { + that->SetRelative(index, relative); + }; + }; + template void SetAbsolute(SizeType index, Source val) { AccessAs()[index] = static_cast(val); @@ -267,7 +311,7 @@ struct ImageFrame : AbstractFrame { ImageElementType elementType = ImageElementType::UINT8; }; -//using Uint8Image2DFrame = ImageFrame; +//using Uint8Image2DFrame = ImageFrame<2>; } // namespace dataformat } // namespace io From 6fa917e46db6148d023db60286c90158f5e9fb8a Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Mon, 14 Feb 2022 18:09:31 +0100 Subject: [PATCH 20/30] Apply the hammer of Gralka! --- .../datatools/io/dataformat/ImageCalls.h | 187 ++++++------------ 1 file changed, 63 insertions(+), 124 deletions(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h index 12c83f8c1e..b42db19884 100644 --- a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h +++ b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h @@ -61,152 +61,50 @@ struct ImageFrame : AbstractFrame { } // data will be controlled by this instance, caller loses access! - void SetData(uint8_t* data, std::size_t count, ImageElementType channelType, SizeType width = 1, SizeType height = 1, SizeType depth = 1) { + void SetData(uint8_t* data, std::size_t count, ImageElementType channelType, SizeType width = 1, + SizeType height = 1, SizeType depth = 1) { auto vec = std::vector(data, data + count); delete[] data; SetData(vec, channelType, width, height, depth); } - template - constexpr T* ViewAs() const { - return static_cast(data.data()); + template + constexpr const T* ViewAs() const { + return reinterpret_cast(data.data()); } - template + template std::vector GetCopy() { std::vector out; out.reserve(NumElements()); - switch (elementType) { - case ImageElementType::UINT8: - CopyInto(out); - break; - case ImageElementType::UINT16: - CopyInto(out); - break; - case ImageElementType::UINT32: - // AKA case ChannelType::RGBA8: - CopyInto(out); - break; - case ImageElementType::FLOAT: - CopyInto(out); - break; - case ImageElementType::DOUBLE: - CopyInto(out); - break; - default: - throw std::logic_error("ImageFrame::GetCopy: invalid elementType"); - } - return std::move(out); + Dispatcher>::dispatch(elementType)(this, out); + return out; } template - std::vector GetCopyNormalized() { + std::vector GetCopyNormalized(ResultType maximum = std::numeric_limits::max()) { std::vector out; out.reserve(NumElements()); - switch (elementType) { - case ImageElementType::UINT8: - CopyIntoNormalized(out); - break; - case ImageElementType::UINT16: - CopyIntoNormalized(out); - break; - case ImageElementType::UINT32: - // AKA case ChannelType::RGBA8: - CopyIntoNormalized(out); - break; - case ImageElementType::FLOAT: - CopyIntoNormalized(out); - break; - case ImageElementType::DOUBLE: - CopyIntoNormalized(out); - break; - default: - throw std::logic_error("ImageFrame::GetCopyNormalized: invalid elementType"); - } - return std::move(out); + Dispatcher>::dispatch(elementType)(this, out, maximum); + return out; } - template - T GetValue(SizeType index) const { + template + ReturnType GetValue(SizeType index) { if (index >= NumElements()) throw std::invalid_argument("ImageFrame::GetValue: index out of bounds"); - switch (elementType) { - case ImageElementType::UINT8: - return static_cast(ViewAs()[index]); - break; - case ImageElementType::UINT16: - return static_cast(ViewAs()[index]); - break; - case ImageElementType::UINT32: - // AKA case ChannelType::RGBA8: - return static_cast(ViewAs()[index]); - break; - case ImageElementType::FLOAT: - return static_cast(ViewAs()[index]); - break; - case ImageElementType::DOUBLE: - return static_cast(ViewAs()[index]); - break; - default: - throw std::logic_error("ImageFrame::GetValue: invalid elementType"); - } + return Dispatcher>::dispatch(elementType)(this, index); } - template - void SetValue(SizeType index, T val) { - if (index >= NumElements()) - throw std::invalid_argument("ImageFrame::SetValue: index out of bounds"); - switch (elementType) { - case ImageElementType::UINT8: - SetAbsolute(index, val); - break; - case ImageElementType::UINT16: - SetAbsolute(index, val); - break; - case ImageElementType::UINT32: - // AKA case ChannelType::RGBA8: - SetAbsolute(index, val); - break; - case ImageElementType::FLOAT: - SetAbsolute(index, val); - break; - case ImageElementType::DOUBLE: - SetAbsolute(index, val); - break; - default: - throw std::logic_error("ImageFrame::SetValue: invalid elementType"); - } - } - - template - void SetValueNormalized(SizeType index, T val, T maximum = std::numeric_limits::max()) { + template + void SetValue(SizeType index, InputType val) { if (index >= NumElements()) throw std::invalid_argument("ImageFrame::SetValueNormalized: index out of bounds"); - const double relative = static_cast(val) / maximum; - switch (elementType) { - case ImageElementType::UINT8: - SetRelative(index, relative); - break; - case ImageElementType::UINT16: - SetRelative(index, relative); - break; - case ImageElementType::UINT32: - // AKA case ChannelType::RGBA8: - SetRelative(index, relative); - break; - case ImageElementType::FLOAT: - SetRelative(index, relative); - break; - case ImageElementType::DOUBLE: - SetRelative(index, relative); - break; - default: - throw std::logic_error("ImageFrame::SetValueNormalized: invalid elementType"); - } + Dispatcher>::dispatch(elementType)(this, index, val); } template - void SetValueNormalized2(SizeType index, T val, T maximum = std::numeric_limits::max()) { + void SetValueNormalized(SizeType index, T val, T maximum = std::numeric_limits::max()) { if (index >= NumElements()) throw std::invalid_argument("ImageFrame::SetValueNormalized: index out of bounds"); const double relative = static_cast(val) / maximum; @@ -279,13 +177,53 @@ struct ImageFrame : AbstractFrame { AccessAs()[index] = static_cast(relative * std::numeric_limits::max()); } + template + struct GetAbsolute_FW { + using Function = ReturnType(ImageFrame*, SizeType); + + template + static ReturnType run(ImageFrame* that, SizeType index) { + return static_cast(that->ViewAs()[index]); + } + }; + + template + struct SetAbsolute_FW { + using Function = void(ImageFrame*, SizeType, InputType); + + template + static void run(ImageFrame* that, SizeType index, InputType val) { + that->SetAbsolute(index, val); + } + }; + struct SetRelative_FW { using Function = void(ImageFrame*, SizeType, double); template static void run(ImageFrame* that, SizeType index, double relative) { that->SetRelative(index, relative); - }; + } + }; + + template + struct GetCopy_FW { + using Function = void(ImageFrame*, std::vector&); + + template + static void run(ImageFrame* that, std::vector& out) { + that->CopyInto(out); + } + }; + + template + struct GetCopyNormalized_FW { + using Function = void(ImageFrame*, std::vector&, ResultType); + + template + static void run(ImageFrame* that, std::vector& out, ResultType maximum) { + that->CopyIntoNormalized(out, maximum); + } }; template @@ -300,9 +238,10 @@ struct ImageFrame : AbstractFrame { } template - void CopyIntoNormalized(std::vector& out) { - std::transform(ViewAs(), ViewAs() + NumElements(), std::back_inserter(out), [](const auto& val) { - return static_cast((val / std::numeric_limits::max()) * std::numeric_limits::max()); + void CopyIntoNormalized(std::vector& out, Dest maximum) { + std::transform( + ViewAs(), ViewAs() + NumElements(), std::back_inserter(out), [maximum](const auto& val) { + return static_cast((val / static_cast(std::numeric_limits::max())) * maximum); }); } From c79044bf762c7e90a130d264327d43a9cde4ea9e Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Mon, 14 Feb 2022 18:19:14 +0100 Subject: [PATCH 21/30] even more fun --- .../datatools/io/dataformat/ImageCalls.h | 88 +++++++++++-------- 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h index b42db19884..329f4d7b10 100644 --- a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h +++ b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h @@ -73,19 +73,19 @@ struct ImageFrame : AbstractFrame { return reinterpret_cast(data.data()); } - template - std::vector GetCopy() { - std::vector out; + template + std::vector GetCopy() { + std::vector out; out.reserve(NumElements()); - Dispatcher>::dispatch(elementType)(this, out); + Dispatcher>::dispatch(elementType)(this, out); return out; } - template - std::vector GetCopyNormalized(ResultType maximum = std::numeric_limits::max()) { - std::vector out; + template + std::vector GetCopyNormalized(ReturnType maximum = std::numeric_limits::max()) { + std::vector out; out.reserve(NumElements()); - Dispatcher>::dispatch(elementType)(this, out, maximum); + Dispatcher>::dispatch(elementType)(this, out, maximum); return out; } @@ -96,6 +96,13 @@ struct ImageFrame : AbstractFrame { return Dispatcher>::dispatch(elementType)(this, index); } + template + ReturnType GetValueNormalized(SizeType index, ReturnType maximum = std::numeric_limits::max()) { + if (index >= NumElements()) + throw std::invalid_argument("ImageFrame::GetValueNormalized: index out of bounds"); + return Dispatcher>::dispatch(elementType)(this, index, maximum); + } + template void SetValue(SizeType index, InputType val) { if (index >= NumElements()) @@ -111,33 +118,6 @@ struct ImageFrame : AbstractFrame { Dispatcher::dispatch(elementType)(this, index, relative); } - // https://stackoverflow.com/questions/16552166/c-function-dispatch-with-template-parameters - template - struct Dispatcher { - static typename FunctionWrapper::Function* dispatch(ImageElementType::Value it) { - switch (it) { - case ImageElementType::UINT8: - return &FunctionWrapper::template run; - break; - case ImageElementType::UINT16: - return &FunctionWrapper::template run; - break; - case ImageElementType::UINT32: - // AKA case ChannelType::RGBA8: - return &FunctionWrapper::template run; - break; - case ImageElementType::FLOAT: - return &FunctionWrapper::template run; - break; - case ImageElementType::DOUBLE: - return &FunctionWrapper::template run; - break; - default: - throw std::logic_error("ImageFrame::Dispatcher: invalid elementType"); - } - } - }; - [[nodiscard]] SizeType ValueIndex(SizeType x, SizeType y = 0, SizeType z = 0) const { return (z * height + y) * width + x; } @@ -167,6 +147,33 @@ struct ImageFrame : AbstractFrame { } private: + // https://stackoverflow.com/questions/16552166/c-function-dispatch-with-template-parameters + template + struct Dispatcher { + static typename FunctionWrapper::Function* dispatch(ImageElementType::Value it) { + switch (it) { + case ImageElementType::UINT8: + return &FunctionWrapper::template run; + break; + case ImageElementType::UINT16: + return &FunctionWrapper::template run; + break; + case ImageElementType::UINT32: + // AKA case ChannelType::RGBA8: + return &FunctionWrapper::template run; + break; + case ImageElementType::FLOAT: + return &FunctionWrapper::template run; + break; + case ImageElementType::DOUBLE: + return &FunctionWrapper::template run; + break; + default: + throw std::logic_error("ImageFrame::Dispatcher: invalid elementType"); + } + } + }; + template T* AccessAs() { return reinterpret_cast(data.data()); @@ -187,6 +194,17 @@ struct ImageFrame : AbstractFrame { } }; + template + struct GetRelative_FW { + using Function = ReturnType(ImageFrame*, SizeType, ReturnType); + + template + static ReturnType run(ImageFrame* that, SizeType index, ReturnType maximum) { + return static_cast( + (that->ViewAs()[index] / static_cast(std::numeric_limits::max())) * maximum); + } + }; + template struct SetAbsolute_FW { using Function = void(ImageFrame*, SizeType, InputType); From e6d6fa1555c3c69f5164fa4496f9e7ecb6e2b26d Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Tue, 15 Feb 2022 18:06:04 +0100 Subject: [PATCH 22/30] const for thoroughness --- .../datatools/io/dataformat/ImageCalls.h | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h index 329f4d7b10..74c627b06a 100644 --- a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h +++ b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h @@ -74,7 +74,7 @@ struct ImageFrame : AbstractFrame { } template - std::vector GetCopy() { + std::vector GetCopy() const { std::vector out; out.reserve(NumElements()); Dispatcher>::dispatch(elementType)(this, out); @@ -82,7 +82,7 @@ struct ImageFrame : AbstractFrame { } template - std::vector GetCopyNormalized(ReturnType maximum = std::numeric_limits::max()) { + std::vector GetCopyNormalized(ReturnType maximum = std::numeric_limits::max()) const { std::vector out; out.reserve(NumElements()); Dispatcher>::dispatch(elementType)(this, out, maximum); @@ -90,14 +90,14 @@ struct ImageFrame : AbstractFrame { } template - ReturnType GetValue(SizeType index) { + ReturnType GetValue(SizeType index) const { if (index >= NumElements()) throw std::invalid_argument("ImageFrame::GetValue: index out of bounds"); return Dispatcher>::dispatch(elementType)(this, index); } template - ReturnType GetValueNormalized(SizeType index, ReturnType maximum = std::numeric_limits::max()) { + ReturnType GetValueNormalized(SizeType index, ReturnType maximum = std::numeric_limits::max()) const { if (index >= NumElements()) throw std::invalid_argument("ImageFrame::GetValueNormalized: index out of bounds"); return Dispatcher>::dispatch(elementType)(this, index, maximum); @@ -186,20 +186,20 @@ struct ImageFrame : AbstractFrame { template struct GetAbsolute_FW { - using Function = ReturnType(ImageFrame*, SizeType); + using Function = ReturnType(ImageFrame const*, SizeType); template - static ReturnType run(ImageFrame* that, SizeType index) { + static ReturnType run(ImageFrame const* that, SizeType index) { return static_cast(that->ViewAs()[index]); } }; template struct GetRelative_FW { - using Function = ReturnType(ImageFrame*, SizeType, ReturnType); + using Function = ReturnType(ImageFrame const*, SizeType, ReturnType); template - static ReturnType run(ImageFrame* that, SizeType index, ReturnType maximum) { + static ReturnType run(ImageFrame const* that, SizeType index, ReturnType maximum) { return static_cast( (that->ViewAs()[index] / static_cast(std::numeric_limits::max())) * maximum); } @@ -226,20 +226,20 @@ struct ImageFrame : AbstractFrame { template struct GetCopy_FW { - using Function = void(ImageFrame*, std::vector&); + using Function = void(ImageFrame const*, std::vector&); template - static void run(ImageFrame* that, std::vector& out) { + static void run(ImageFrame const* that, std::vector& out) { that->CopyInto(out); } }; template struct GetCopyNormalized_FW { - using Function = void(ImageFrame*, std::vector&, ResultType); + using Function = void(ImageFrame const*, std::vector&, ResultType); template - static void run(ImageFrame* that, std::vector& out, ResultType maximum) { + static void run(ImageFrame const* that, std::vector& out, ResultType maximum) { that->CopyIntoNormalized(out, maximum); } }; @@ -250,13 +250,13 @@ struct ImageFrame : AbstractFrame { } template - void CopyInto(std::vector& out) { + void CopyInto(std::vector& out) const { std::transform(ViewAs(), ViewAs() + NumElements(), std::back_inserter(out), [](const auto& val) { return static_cast(val); }); } template - void CopyIntoNormalized(std::vector& out, Dest maximum) { + void CopyIntoNormalized(std::vector& out, Dest maximum) const { std::transform( ViewAs(), ViewAs() + NumElements(), std::back_inserter(out), [maximum](const auto& val) { return static_cast((val / static_cast(std::numeric_limits::max())) * maximum); From 851db606274f570dc3dbff34cad668de21ba48b3 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 16 Feb 2022 16:29:02 +0100 Subject: [PATCH 23/30] still not happy --- .../datatools/io/dataformat/ImageCalls.h | 74 +++++++++++++++++++ .../io/dataformat/ImageElementType.h | 21 ++++++ 2 files changed, 95 insertions(+) diff --git a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h index 74c627b06a..19fde3e7b4 100644 --- a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h +++ b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h @@ -96,6 +96,66 @@ struct ImageFrame : AbstractFrame { return Dispatcher>::dispatch(elementType)(this, index); } + //template + //struct Iterator { + // using iterator_category = std::forward_iterator_tag; + // using difference_type = SizeType; // huh. + // using value_type = ReturnType; + // using pointer = value_type*; + // using reference = value_type&; + + // Iterator(ImageFrame* img, SizeType idx) : img(img), idx(idx) {} + + // reference operator*() const { + // temp_storage = img->GetValue(idx); + // return temp_storage; + // } + // pointer operator->() { + // temp_storage = img->GetValue(idx); + // return &temp_storage; + // } + + // Iterator& operator++() { + // ++idx; + // return *this; + // } + + // Iterator operator++(int) { + // Iterator tmp = *this; + // ++(*this); + // return tmp; + // } + + // friend bool operator==(const Iterator& a, const Iterator& b) { + // return a.idx == b.idx; + // } + // friend bool operator!=(const Iterator& a, const Iterator& b) { + // return a.idx != b.idx; + // } + + //private: + // ReturnType temp_storage = static_cast(0); + // ImageFrame* img; + // SizeType idx; + //}; + + // this still feels wonky + template + T* begin() { + if(typeid(T) != elementType.TypeId()) { + throw std::invalid_argument("cannot generate iterator for a type different from the contents"); + } + return &AccessAs()[0]; + } + + template + T* end() { + if (typeid(T) != elementType.TypeId()) { + throw std::invalid_argument("cannot generate iterator for a type different from the contents"); + } + return &AccessAs()[data.size()]; + } + template ReturnType GetValueNormalized(SizeType index, ReturnType maximum = std::numeric_limits::max()) const { if (index >= NumElements()) @@ -194,6 +254,20 @@ struct ImageFrame : AbstractFrame { } }; + //template + //struct GetIterator_FW { + // using Function = Iterator(ImageFrame*, SizeType); + + // template + // static Iterator run(ImageFrame* that, T* ptr) { + // return GetIterator(ptr); + // } + //}; + //template + //Iterator GetIterator(InternalType *ptr) const { + // return Iterator(ptr); + //} + template struct GetRelative_FW { using Function = ReturnType(ImageFrame const*, SizeType, ReturnType); diff --git a/plugins/datatools/include/datatools/io/dataformat/ImageElementType.h b/plugins/datatools/include/datatools/io/dataformat/ImageElementType.h index 84011aabb6..85ac53844f 100644 --- a/plugins/datatools/include/datatools/io/dataformat/ImageElementType.h +++ b/plugins/datatools/include/datatools/io/dataformat/ImageElementType.h @@ -1,3 +1,7 @@ +#pragma once + +#include + namespace megamol { namespace datatools { namespace io { @@ -45,6 +49,23 @@ class ImageElementType { return 0; } + [[nodiscard]] const type_info& TypeId() const { + switch (value) { + case UINT8: + return typeid(uint8_t); + case UINT16: + return typeid(uint16_t); + case UINT32: + // AKA case RGBA8: + return typeid(uint32_t); + case FLOAT: + return typeid(float); + case DOUBLE: + return typeid(double); + } + return typeid(void); + } + private: Value value = UINT8; }; From 58b410ace667a50770a974c55ab462dc95f01f56 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Wed, 16 Feb 2022 17:12:37 +0100 Subject: [PATCH 24/30] cleanup --- .../datatools/io/dataformat/ImageCalls.h | 61 +------------------ .../io/dataformat/ImageElementType.h | 10 +-- 2 files changed, 7 insertions(+), 64 deletions(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h index 19fde3e7b4..241c1e88c8 100644 --- a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h +++ b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h @@ -96,53 +96,10 @@ struct ImageFrame : AbstractFrame { return Dispatcher>::dispatch(elementType)(this, index); } - //template - //struct Iterator { - // using iterator_category = std::forward_iterator_tag; - // using difference_type = SizeType; // huh. - // using value_type = ReturnType; - // using pointer = value_type*; - // using reference = value_type&; - - // Iterator(ImageFrame* img, SizeType idx) : img(img), idx(idx) {} - - // reference operator*() const { - // temp_storage = img->GetValue(idx); - // return temp_storage; - // } - // pointer operator->() { - // temp_storage = img->GetValue(idx); - // return &temp_storage; - // } - - // Iterator& operator++() { - // ++idx; - // return *this; - // } - - // Iterator operator++(int) { - // Iterator tmp = *this; - // ++(*this); - // return tmp; - // } - - // friend bool operator==(const Iterator& a, const Iterator& b) { - // return a.idx == b.idx; - // } - // friend bool operator!=(const Iterator& a, const Iterator& b) { - // return a.idx != b.idx; - // } - - //private: - // ReturnType temp_storage = static_cast(0); - // ImageFrame* img; - // SizeType idx; - //}; - // this still feels wonky template T* begin() { - if(typeid(T) != elementType.TypeId()) { + if (typeid(T) != elementType.TypeId()) { throw std::invalid_argument("cannot generate iterator for a type different from the contents"); } return &AccessAs()[0]; @@ -219,7 +176,7 @@ struct ImageFrame : AbstractFrame { return &FunctionWrapper::template run; break; case ImageElementType::UINT32: - // AKA case ChannelType::RGBA8: + case ImageElementType::RGBA8: return &FunctionWrapper::template run; break; case ImageElementType::FLOAT: @@ -254,20 +211,6 @@ struct ImageFrame : AbstractFrame { } }; - //template - //struct GetIterator_FW { - // using Function = Iterator(ImageFrame*, SizeType); - - // template - // static Iterator run(ImageFrame* that, T* ptr) { - // return GetIterator(ptr); - // } - //}; - //template - //Iterator GetIterator(InternalType *ptr) const { - // return Iterator(ptr); - //} - template struct GetRelative_FW { using Function = ReturnType(ImageFrame const*, SizeType, ReturnType); diff --git a/plugins/datatools/include/datatools/io/dataformat/ImageElementType.h b/plugins/datatools/include/datatools/io/dataformat/ImageElementType.h index 85ac53844f..cb5f385464 100644 --- a/plugins/datatools/include/datatools/io/dataformat/ImageElementType.h +++ b/plugins/datatools/include/datatools/io/dataformat/ImageElementType.h @@ -13,9 +13,9 @@ class ImageElementType { UINT8 = 1, UINT16 = 2, UINT32 = 3, // This is a semantic alias! OK? - RGBA8 = 3, // This is a semantic alias! OK? - FLOAT = 4, - DOUBLE = 5 + RGBA8 = 4, // This is a semantic alias! OK? + FLOAT = 5, + DOUBLE = 6 }; ImageElementType() = default; constexpr ImageElementType(Value ct) : value(ct) {} @@ -39,7 +39,7 @@ class ImageElementType { case UINT16: return sizeof(uint16_t); case UINT32: - // AKA case RGBA8: + case RGBA8: return sizeof(uint32_t); case FLOAT: return sizeof(float); @@ -56,7 +56,7 @@ class ImageElementType { case UINT16: return typeid(uint16_t); case UINT32: - // AKA case RGBA8: + case RGBA8: return typeid(uint32_t); case FLOAT: return typeid(float); From 6c68385349d55f8e992e27c4a2e9450abe0791dd Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 17 Feb 2022 10:26:17 +0100 Subject: [PATCH 25/30] we accidentally designed a channel, not a frame --- .../datatools/io/dataformat/DataFormat.h | 4 +- .../datatools/io/dataformat/ImageCalls.h | 76 +++++++++++++------ 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h index 9adb406be5..38ad6f8dd1 100644 --- a/plugins/datatools/include/datatools/io/dataformat/DataFormat.h +++ b/plugins/datatools/include/datatools/io/dataformat/DataFormat.h @@ -16,8 +16,8 @@ namespace dataformat { // this has *nothing* to do with proper file formats. readers support these to provide data via the said call struct AbstractFrame { virtual ~AbstractFrame() = default; - virtual bool Read(std::istream& io) = 0; - virtual bool Write(std::ostream& io) const = 0; + virtual void Read(std::istream& io) = 0; + virtual void Write(std::ostream& io) const = 0; [[nodiscard]] virtual std::size_t ByteSize() const = 0; }; diff --git a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h index 241c1e88c8..fe21e9325a 100644 --- a/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h +++ b/plugins/datatools/include/datatools/io/dataformat/ImageCalls.h @@ -19,16 +19,16 @@ namespace dataformat { // For some data sources you only know after actually opening the file what's in it. // TODO: volume ist ein byte-vektor und wir benutzen span. fertig. template -struct ImageFrame : AbstractFrame { - static_assert(Dimensions > 0 && Dimensions < 4, "ImageFrame supports 1D, 2D, and 3D Images only"); +struct ImageChannel { + static_assert(Dimensions > 0 && Dimensions < 4, "ImageChannel supports 1D, 2D, and 3D Images only"); using SizeType = uint32_t; - bool Read(std::istream& io) override { + void Read(std::istream& io) { uint8_t dims, chanTypes; io.read(reinterpret_cast(&dims), sizeof(uint8_t)); if (dims != Dimensions) - throw std::invalid_argument("ImageFrame::Read: inappropriate number of dimensions in ImageFrame dump!"); + throw std::invalid_argument("ImageChannel::Read: inappropriate number of dimensions in ImageChannel dump!"); io.read(reinterpret_cast(&chanTypes), sizeof(uint8_t)); elementType.Set(chanTypes); io.read(reinterpret_cast(&this->width), sizeof(SizeType)); @@ -36,10 +36,9 @@ struct ImageFrame : AbstractFrame { io.read(reinterpret_cast(&this->depth), sizeof(SizeType)); data.resize(static_cast(width) * height * depth); io.read(reinterpret_cast(this->data.data()), ByteSize()); - return true; } - bool Write(std::ostream& io) const override { + void Write(std::ostream& io) const { uint8_t const dims = Dimensions; io.write(reinterpret_cast(&dims), sizeof(uint8_t)); io.write(reinterpret_cast(&elementType), sizeof(uint8_t)); @@ -47,7 +46,6 @@ struct ImageFrame : AbstractFrame { io.write(reinterpret_cast(&this->height), sizeof(SizeType)); io.write(reinterpret_cast(&this->depth), sizeof(SizeType)); io.write(reinterpret_cast(this->data.data()), ByteSize()); - return true; } void SetData(std::vector&& data, ImageElementType channelType, SizeType width = 1, SizeType height = 1, @@ -92,7 +90,7 @@ struct ImageFrame : AbstractFrame { template ReturnType GetValue(SizeType index) const { if (index >= NumElements()) - throw std::invalid_argument("ImageFrame::GetValue: index out of bounds"); + throw std::invalid_argument("ImageChannel::GetValue: index out of bounds"); return Dispatcher>::dispatch(elementType)(this, index); } @@ -116,21 +114,21 @@ struct ImageFrame : AbstractFrame { template ReturnType GetValueNormalized(SizeType index, ReturnType maximum = std::numeric_limits::max()) const { if (index >= NumElements()) - throw std::invalid_argument("ImageFrame::GetValueNormalized: index out of bounds"); + throw std::invalid_argument("ImageChannel::GetValueNormalized: index out of bounds"); return Dispatcher>::dispatch(elementType)(this, index, maximum); } template void SetValue(SizeType index, InputType val) { if (index >= NumElements()) - throw std::invalid_argument("ImageFrame::SetValueNormalized: index out of bounds"); + throw std::invalid_argument("ImageChannel::SetValue: index out of bounds"); Dispatcher>::dispatch(elementType)(this, index, val); } template void SetValueNormalized(SizeType index, T val, T maximum = std::numeric_limits::max()) { if (index >= NumElements()) - throw std::invalid_argument("ImageFrame::SetValueNormalized: index out of bounds"); + throw std::invalid_argument("ImageChannel::SetValueNormalized: index out of bounds"); const double relative = static_cast(val) / maximum; Dispatcher::dispatch(elementType)(this, index, relative); } @@ -139,7 +137,7 @@ struct ImageFrame : AbstractFrame { return (z * height + y) * width + x; } - [[nodiscard]] std::size_t ByteSize() const override { + [[nodiscard]] std::size_t ByteSize() const { return width * height * depth * elementType.ByteSize(); } @@ -186,7 +184,7 @@ struct ImageFrame : AbstractFrame { return &FunctionWrapper::template run; break; default: - throw std::logic_error("ImageFrame::Dispatcher: invalid elementType"); + throw std::logic_error("ImageChannel::Dispatcher: invalid elementType"); } } }; @@ -203,20 +201,20 @@ struct ImageFrame : AbstractFrame { template struct GetAbsolute_FW { - using Function = ReturnType(ImageFrame const*, SizeType); + using Function = ReturnType(ImageChannel const*, SizeType); template - static ReturnType run(ImageFrame const* that, SizeType index) { + static ReturnType run(ImageChannel const* that, SizeType index) { return static_cast(that->ViewAs()[index]); } }; template struct GetRelative_FW { - using Function = ReturnType(ImageFrame const*, SizeType, ReturnType); + using Function = ReturnType(ImageChannel const*, SizeType, ReturnType); template - static ReturnType run(ImageFrame const* that, SizeType index, ReturnType maximum) { + static ReturnType run(ImageChannel const* that, SizeType index, ReturnType maximum) { return static_cast( (that->ViewAs()[index] / static_cast(std::numeric_limits::max())) * maximum); } @@ -224,39 +222,39 @@ struct ImageFrame : AbstractFrame { template struct SetAbsolute_FW { - using Function = void(ImageFrame*, SizeType, InputType); + using Function = void(ImageChannel*, SizeType, InputType); template - static void run(ImageFrame* that, SizeType index, InputType val) { + static void run(ImageChannel* that, SizeType index, InputType val) { that->SetAbsolute(index, val); } }; struct SetRelative_FW { - using Function = void(ImageFrame*, SizeType, double); + using Function = void(ImageChannel*, SizeType, double); template - static void run(ImageFrame* that, SizeType index, double relative) { + static void run(ImageChannel* that, SizeType index, double relative) { that->SetRelative(index, relative); } }; template struct GetCopy_FW { - using Function = void(ImageFrame const*, std::vector&); + using Function = void(ImageChannel const*, std::vector&); template - static void run(ImageFrame const* that, std::vector& out) { + static void run(ImageChannel const* that, std::vector& out) { that->CopyInto(out); } }; template struct GetCopyNormalized_FW { - using Function = void(ImageFrame const*, std::vector&, ResultType); + using Function = void(ImageChannel const*, std::vector&, ResultType); template - static void run(ImageFrame const* that, std::vector& out, ResultType maximum) { + static void run(ImageChannel const* that, std::vector& out, ResultType maximum) { that->CopyIntoNormalized(out, maximum); } }; @@ -285,6 +283,34 @@ struct ImageFrame : AbstractFrame { ImageElementType elementType = ImageElementType::UINT8; }; +template +struct ImageFrame: AbstractFrame { + std::vector > channels; + + void Read(std::istream& io) override { + uint8_t numChannels; + io.read(reinterpret_cast(&numChannels), sizeof(uint8_t)); + channels.resize(numChannels); + for (auto c = 0; c < numChannels; ++c) { + channels[c].Read(io); + } + } + + void Write(std::ostream& io) const override { + const uint8_t numChannels = static_cast(channels.size()); + io.write(reinterpret_cast(&numChannels), sizeof(uint8_t)); + for (auto c = 0; c < numChannels; ++c) { + channels[c].Write(io); + } + } + + [[nodiscard]] std::size_t ByteSize() const override { + return std::accumulate(channels.begin(), channels.end(), 0, + [](ImageChannel& i) -> std::size_t { return i.ByteSize(); }); + } + +}; + //using Uint8Image2DFrame = ImageFrame<2>; } // namespace dataformat From 4fe2345e311743dd57bc6ffbcd6ca7bdfe471bdc Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 17 Feb 2022 19:23:39 +0100 Subject: [PATCH 26/30] surface lic does something, but might be broken --- .../shaders/RaycastVolumeRenderer-Fragment.glsl | 16 ++++++++++++++++ .../shaders/RaycastVolumeRenderer-Vertex.glsl | 17 +++++++++++++++++ plugins/astro_gl/shaders/SurfaceLICRenderer.btf | 10 ++++++++++ plugins/astro_gl/src/SurfaceLICRenderer.cpp | 4 ++-- 4 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 plugins/astro_gl/shaders/RaycastVolumeRenderer-Fragment.glsl create mode 100644 plugins/astro_gl/shaders/RaycastVolumeRenderer-Vertex.glsl diff --git a/plugins/astro_gl/shaders/RaycastVolumeRenderer-Fragment.glsl b/plugins/astro_gl/shaders/RaycastVolumeRenderer-Fragment.glsl new file mode 100644 index 0000000000..13d5f6f058 --- /dev/null +++ b/plugins/astro_gl/shaders/RaycastVolumeRenderer-Fragment.glsl @@ -0,0 +1,16 @@ +uniform sampler2D src_tx2D; +uniform sampler2D normal_tx2D; +uniform sampler2D depth_tx2D; + +in vec2 uv_coord; + +layout (location = 0) out vec4 frag_out; +layout (location = 1) out vec4 normal_out; + +void main() +{ + frag_out = texture(src_tx2D, uv_coord); + normal_out = texture(normal_tx2D, uv_coord); + + gl_FragDepth = texture(depth_tx2D, uv_coord).x; +} diff --git a/plugins/astro_gl/shaders/RaycastVolumeRenderer-Vertex.glsl b/plugins/astro_gl/shaders/RaycastVolumeRenderer-Vertex.glsl new file mode 100644 index 0000000000..44e07c7d4c --- /dev/null +++ b/plugins/astro_gl/shaders/RaycastVolumeRenderer-Vertex.glsl @@ -0,0 +1,17 @@ +out vec2 uv_coord; + +void main() +{ + const vec4 vertices[6] = vec4[6]( + vec4(-1.0, -1.0, 0.0, 0.0), + vec4( 1.0, 1.0, 1.0, 1.0), + vec4(-1.0, 1.0, 0.0, 1.0), + vec4( 1.0, 1.0, 1.0, 1.0), + vec4(-1.0, -1.0, 0.0, 0.0), + vec4( 1.0, -1.0, 1.0, 0.0)); + + const vec4 vertex = vertices[gl_VertexID]; + + uv_coord = vertex.zw; + gl_Position = vec4(vertex.xy, -1.0, 1.0); +} diff --git a/plugins/astro_gl/shaders/SurfaceLICRenderer.btf b/plugins/astro_gl/shaders/SurfaceLICRenderer.btf index 810ce9c5a0..48c1e2e9a8 100644 --- a/plugins/astro_gl/shaders/SurfaceLICRenderer.btf +++ b/plugins/astro_gl/shaders/SurfaceLICRenderer.btf @@ -12,4 +12,14 @@ SurfaceLIC-Functions.glsl SurfaceLIC-Compute.glsl + + + 430 + RaycastVolumeRenderer-Vertex.glsl + + + + 430 + RaycastVolumeRenderer-Fragment.glsl + diff --git a/plugins/astro_gl/src/SurfaceLICRenderer.cpp b/plugins/astro_gl/src/SurfaceLICRenderer.cpp index a49b8eb84a..26daae05a2 100644 --- a/plugins/astro_gl/src/SurfaceLICRenderer.cpp +++ b/plugins/astro_gl/src/SurfaceLICRenderer.cpp @@ -131,9 +131,9 @@ bool SurfaceLICRenderer::create() { if (!this->lic_compute_shdr.Link()) return false; - if (!ssf->MakeShaderSource("RaycastVolumeRenderer::vert", vertex_shader_src)) + if (!ssf->MakeShaderSource("SurfaceLICRenderer::vert", vertex_shader_src)) return false; - if (!ssf->MakeShaderSource("RaycastVolumeRenderer::frag", fragment_shader_src)) + if (!ssf->MakeShaderSource("SurfaceLICRenderer::frag", fragment_shader_src)) return false; if (!this->render_to_framebuffer_shdr.Compile(vertex_shader_src.Code(), vertex_shader_src.Count(), fragment_shader_src.Code(), fragment_shader_src.Count())) From f5aa7f62fee6c0667eec25d42bdb155a767df6d7 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 17 Feb 2022 19:23:51 +0100 Subject: [PATCH 27/30] fixed bug in tablecolumnfilter --- plugins/datatools/src/table/TableColumnFilter.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/datatools/src/table/TableColumnFilter.cpp b/plugins/datatools/src/table/TableColumnFilter.cpp index 9de0424b0a..09cbb47c6a 100644 --- a/plugins/datatools/src/table/TableColumnFilter.cpp +++ b/plugins/datatools/src/table/TableColumnFilter.cpp @@ -65,8 +65,10 @@ bool TableColumnFilter::processData(core::Call& c) { if (!(*inCall)()) return false; - if (this->datahash != inCall->DataHash() || this->frameID != inCall->GetFrameID()) { - this->datahash = inCall->DataHash(); + if (this->datahash != inCall->DataHash() || this->frameID != inCall->GetFrameID() || + this->selectionStringSlot.IsDirty()) { + this->datahash++; + this->selectionStringSlot.ResetDirty(); this->frameID = inCall->GetFrameID(); auto column_count = inCall->GetColumnsCount(); From 7f0e9687eb462aa2c36180ea3f45249e6ef259d3 Mon Sep 17 00:00:00 2001 From: Guido Reina Date: Thu, 3 Mar 2022 19:11:59 +0100 Subject: [PATCH 28/30] typo --- plugins/volume_gl/src/RaycastVolumeRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/volume_gl/src/RaycastVolumeRenderer.cpp b/plugins/volume_gl/src/RaycastVolumeRenderer.cpp index 220aebd548..fcf6e21cce 100644 --- a/plugins/volume_gl/src/RaycastVolumeRenderer.cpp +++ b/plugins/volume_gl/src/RaycastVolumeRenderer.cpp @@ -55,7 +55,7 @@ RaycastVolumeRenderer::RaycastVolumeRenderer() , m_volumetricData_callerSlot("getData", "Connects the volume renderer with a voluemtric data source") , m_lights_callerSlot("lights", "Lights are retrieved over this slot.") , m_transferFunction_callerSlot( - "getTranfserFunction", "Connects the volume renderer with a transfer function") { + "getTransferFunction", "Connects the volume renderer with a transfer function") { this->m_renderer_callerSlot.SetCompatibleCall(); this->MakeSlotAvailable(&this->m_renderer_callerSlot); From 7a0a4cac4e60eb4affe939eac8ce5ad933bad8d1 Mon Sep 17 00:00:00 2001 From: Alexander Straub Date: Fri, 4 Mar 2022 17:35:16 +0100 Subject: [PATCH 29/30] Clear before rendering, as FBO is reused and may not be empty --- plugins/volume_gl/src/RaycastVolumeRenderer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/volume_gl/src/RaycastVolumeRenderer.cpp b/plugins/volume_gl/src/RaycastVolumeRenderer.cpp index fcf6e21cce..68028276a7 100644 --- a/plugins/volume_gl/src/RaycastVolumeRenderer.cpp +++ b/plugins/volume_gl/src/RaycastVolumeRenderer.cpp @@ -495,6 +495,8 @@ bool RaycastVolumeRenderer::Render(megamol::core_gl::view::CallRender3DGL& cr) { } // copy image to framebuffer + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + bool state_depth_test = glIsEnabled(GL_DEPTH_TEST); bool state_blend = glIsEnabled(GL_BLEND); From 5a4b860f71d6ed79c383542f18e3c7981428de16 Mon Sep 17 00:00:00 2001 From: Alexander Straub Date: Fri, 4 Mar 2022 17:37:00 +0100 Subject: [PATCH 30/30] Use glowl Framebuffer and correct chaining mechanism, both for calling a separate input renderer, and to render into the provided framebuffer --- plugins/astro_gl/src/SurfaceLICRenderer.cpp | 46 +++++++-------------- plugins/astro_gl/src/SurfaceLICRenderer.h | 4 +- 2 files changed, 18 insertions(+), 32 deletions(-) diff --git a/plugins/astro_gl/src/SurfaceLICRenderer.cpp b/plugins/astro_gl/src/SurfaceLICRenderer.cpp index 26daae05a2..1ce2388b3a 100644 --- a/plugins/astro_gl/src/SurfaceLICRenderer.cpp +++ b/plugins/astro_gl/src/SurfaceLICRenderer.cpp @@ -18,6 +18,7 @@ #include "vislib_gl/graphics/gl/GLSLShader.h" #include "vislib_gl/graphics/gl/ShaderSource.h" +#include "glowl/FramebufferObject.hpp" #include "glowl/Texture.hpp" #include "glowl/Texture2D.hpp" #include "glowl/Texture3D.hpp" @@ -49,6 +50,7 @@ SurfaceLICRenderer::SurfaceLICRenderer() , ambient_color("lighting::ambient color", "Ambient color") , specular_color("lighting::specular color", "Specular color") , light_color("lighting::light color", "Light color") + , fbo(nullptr) , hash(-1) { this->input_renderer.SetCompatibleCall(); @@ -202,39 +204,21 @@ bool SurfaceLICRenderer::Render(core_gl::view::CallRender3DGL& call) { ci->SetCamera(cam); auto viewport = call.GetViewResolution(); - if (this->fbo.GetWidth() != viewport.x || this->fbo.GetHeight() != viewport.y) { - if (this->fbo.IsValid()) - this->fbo.Release(); - - std::array cap; - cap[0].internalFormat = GL_RGBA8; - cap[0].format = GL_RGBA; - cap[0].type = GL_UNSIGNED_BYTE; - cap[1].internalFormat = GL_RGBA32F; - cap[1].format = GL_RGBA; - cap[1].type = GL_FLOAT; - - vislib_gl::graphics::gl::FramebufferObject::DepthAttachParams dap; - dap.format = GL_DEPTH_COMPONENT24; - dap.state = vislib_gl::graphics::gl::FramebufferObject::ATTACHMENT_TEXTURE; - - vislib_gl::graphics::gl::FramebufferObject::StencilAttachParams sap; - sap.format = GL_STENCIL_INDEX; - sap.state = vislib_gl::graphics::gl::FramebufferObject::ATTACHMENT_DISABLED; - - this->fbo.Create(viewport.x, viewport.y, cap.size(), cap.data(), dap, sap); - } + if (this->fbo == nullptr || this->fbo->getWidth() != viewport.x || this->fbo->getHeight() != viewport.y) { + this->fbo = std::make_shared(viewport.x, viewport.y, glowl::FramebufferObject::DEPTH24); - this->fbo.Enable(); + this->fbo->createColorAttachment(GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); + this->fbo->createColorAttachment(GL_RGBA32F, GL_RGBA, GL_FLOAT); + } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + ci->SetFramebuffer(this->fbo); + if (!(*ci)(core_gl::view::CallRender3DGL::FnRender)) return false; call.SetTimeFramesCount(ci->TimeFramesCount()); - this->fbo.Disable(); - // Get input velocities auto cd = this->input_velocities.CallAs(); if (cd == nullptr) @@ -358,11 +342,11 @@ bool SurfaceLICRenderer::Render(core_gl::view::CallRender3DGL& call) { glUniform3fv(this->pre_compute_shdr.ParameterLocation("resolution"), 1, resolution.data()); glActiveTexture(GL_TEXTURE0); - this->fbo.BindDepthTexture(); + this->fbo->bindDepthbuffer(); glUniform1i(this->pre_compute_shdr.ParameterLocation("depth_tx2D"), 0); glActiveTexture(GL_TEXTURE1); - this->fbo.BindColourTexture(1); + this->fbo->bindColorbuffer(1); glUniform1i(this->pre_compute_shdr.ParameterLocation("normal_tx2D"), 1); glActiveTexture(GL_TEXTURE2); @@ -434,7 +418,7 @@ bool SurfaceLICRenderer::Render(core_gl::view::CallRender3DGL& call) { this->light_color.Param()->Value().data()); glActiveTexture(GL_TEXTURE0); - this->fbo.BindDepthTexture(); + this->fbo->bindDepthbuffer(); glUniform1i(this->lic_compute_shdr.ParameterLocation("depth_tx2D"), 0); glActiveTexture(GL_TEXTURE1); @@ -442,7 +426,7 @@ bool SurfaceLICRenderer::Render(core_gl::view::CallRender3DGL& call) { glUniform1i(this->lic_compute_shdr.ParameterLocation("velocity_tx2D"), 1); glActiveTexture(GL_TEXTURE2); - this->fbo.BindColourTexture(1); + this->fbo->bindColorbuffer(1); glUniform1i(this->lic_compute_shdr.ParameterLocation("normal_tx2D"), 2); glActiveTexture(GL_TEXTURE3); @@ -480,6 +464,8 @@ bool SurfaceLICRenderer::Render(core_gl::view::CallRender3DGL& call) { glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT); // Render to framebuffer + call.GetFramebuffer()->bind(); + bool state_depth_test = glIsEnabled(GL_DEPTH_TEST); bool state_blend = glIsEnabled(GL_BLEND); @@ -495,7 +481,7 @@ bool SurfaceLICRenderer::Render(core_gl::view::CallRender3DGL& call) { glUniform1i(this->render_to_framebuffer_shdr.ParameterLocation("src_tx2D"), 0); glActiveTexture(GL_TEXTURE1); - this->fbo.BindDepthTexture(); + this->fbo->bindDepthbuffer(); glUniform1i(this->render_to_framebuffer_shdr.ParameterLocation("depth_tx2D"), 1); glDrawArrays(GL_TRIANGLES, 0, 6); diff --git a/plugins/astro_gl/src/SurfaceLICRenderer.h b/plugins/astro_gl/src/SurfaceLICRenderer.h index 45f45a1dd6..b0aef93c7d 100644 --- a/plugins/astro_gl/src/SurfaceLICRenderer.h +++ b/plugins/astro_gl/src/SurfaceLICRenderer.h @@ -14,10 +14,10 @@ #include "mmcore/param/ParamSlot.h" #include "mmcore_gl/view/Renderer3DModuleGL.h" -#include "vislib_gl/graphics/gl/FramebufferObject.h" #include "vislib_gl/graphics/gl/GLSLComputeShader.h" #include "vislib_gl/graphics/gl/GLSLShader.h" +#include "glowl/FramebufferObject.hpp" #include "glowl/Texture2D.hpp" #include "glowl/Texture3D.hpp" @@ -132,7 +132,7 @@ class SurfaceLICRenderer : public megamol::core_gl::view::Renderer3DModuleGL { std::unique_ptr noise_texture; /** FBO for input */ - vislib_gl::graphics::gl::FramebufferObject fbo; + std::shared_ptr fbo; /** Noise texture data */ std::vector noise;