diff --git a/CloneSource.cpp b/CloneSource.cpp index eae8d2a..12c9786 100644 --- a/CloneSource.cpp +++ b/CloneSource.cpp @@ -30,10 +30,11 @@ #include "CloneSource.h" +const char* CloneSource::cloning_provenance_label[2] = { "Original texture", "Post-processed image" }; CloneSource::CloneSource(Source *origin, uint64_t id) : Source(id), origin_(origin), cloningsurface_(nullptr), - read_index_(0), write_index_(0), delay_(0.0), paused_(false), image_mode_(CLONE_TEXTURE) + read_index_(0), write_index_(0), delay_(0.0), paused_(false), provenance_(CLONE_TEXTURE) { // initial name copies the origin name: diplucates are namanged in session name_ = origin->name(); @@ -44,7 +45,8 @@ CloneSource::CloneSource(Source *origin, uint64_t id) : Source(id), origin_(orig // init array stack_.fill(nullptr); - timestamp_.fill(0.0); + elapsed_stack_.fill(0.0); + timestamps_.fill(0); timer_ = g_timer_new (); } @@ -79,21 +81,23 @@ void CloneSource::init() { if (origin_ && origin_->mode_ > Source::UNINITIALIZED) { - // create frame buffers where to copy frames of the origin source + // internal surface to draw the original texture + cloningsurface_ = new Surface; + cloningsurface_->setTextureIndex( origin()->texture() ); + + // frame buffers where to draw frames from the origin source glm::vec3 res = origin_->frame()->resolution(); for (size_t i = 0; i < stack_.size(); ++i){ stack_[i] = new FrameBuffer( res, origin_->frame()->use_alpha() ); } - g_timer_start(timer_); - - cloningsurface_ = new Surface; - cloningsurface_->setTextureIndex( origin()->texture() ); - // set initial texture surface texturesurface_->setTextureIndex( stack_[read_index_]->texture() ); - // create Frame buffer matching size of images + // activate elapsed-timer + g_timer_start(timer_); + + // create render Frame buffer matching size of images FrameBuffer *renderbuffer = new FrameBuffer( res, true); // set the renderbuffer of the source and attach rendering nodes @@ -135,23 +139,19 @@ void CloneSource::setActive (bool on) } } -void CloneSource::replay() -{ - read_index_ = (write_index_ + 1 )%(stack_.size()); -} - void CloneSource::update(float dt) { - if (active_ && !paused_ && cloningsurface_ != nullptr) { + if (active_ && !paused_ && origin_ && cloningsurface_ != nullptr) { double now = g_timer_elapsed (timer_, NULL) ; // increment enplacement of write index write_index_ = (write_index_+1)%(stack_.size()); - timestamp_[write_index_] = now; + elapsed_stack_[write_index_] = now; + timestamps_[write_index_] = origin_->playtime(); // CLONE_RENDER : blit rendered framebuffer in the stack - if (image_mode_ == CLONE_RENDER) + if (provenance_ == CLONE_RENDER) origin_->frame()->blit(stack_[write_index_]); // CLONE_TEXTURE : render origin texture in the stack else { @@ -168,7 +168,7 @@ void CloneSource::update(float dt) { // starting where we are at, get the next index that satisfies the delay size_t previous_index = read_index_; - while ( now - timestamp_[read_index_] > delay_) { + while ( now - elapsed_stack_[read_index_] > delay_) { // usually, one frame increment suffice read_index_ = (read_index_ + 1 )%(stack_.size()); // break the loop if running infinite (never happens) @@ -197,17 +197,27 @@ void CloneSource::play (bool on) if (paused_ == on) { // restart clean if was paused - if (paused_) { - g_timer_reset(timer_); - timestamp_.fill(0.0); - write_index_ = 0; - read_index_ = 1; - } + if (paused_) + replay(); // toggle state paused_ = !on; } } +void CloneSource::replay() +{ + g_timer_reset(timer_); + elapsed_stack_.fill(0.0); + write_index_ = 0; + read_index_ = 1; +} + +guint64 CloneSource::playtime () const +{ + return timestamps_[read_index_]; +} + + uint CloneSource::texture() const { if (cloningsurface_ != nullptr) diff --git a/CloneSource.h b/CloneSource.h index 0e6e7a2..238279d 100644 --- a/CloneSource.h +++ b/CloneSource.h @@ -21,21 +21,25 @@ public: void play (bool on) override; bool playable () const override { return true; } void replay () override; + guint64 playtime () const override; uint texture() const override; bool failed() const override { return origin_ == nullptr; } void accept (Visitor& v) override; + // implementation of cloning mechanism CloneSource *clone(uint64_t id = 0) override; inline void detach() { origin_ = nullptr; } inline Source *origin() const { return origin_; } + // Clone properties typedef enum { CLONE_TEXTURE = 0, CLONE_RENDER - } CloneImageMode; + } CloneSourceProvenance; + static const char* cloning_provenance_label[2]; - void setImageMode(CloneImageMode m) { image_mode_ = m; } - CloneImageMode imageMode() const { return image_mode_; } + void setCloningProvenance(CloneSourceProvenance m) { provenance_ = m; } + CloneSourceProvenance cloningProvenance() const { return provenance_; } void setDelay(double second); double delay() const { return delay_; } @@ -50,18 +54,20 @@ protected: void init() override; Source *origin_; - // cloning + // cloning & stack of past frames std::array stack_; Surface *cloningsurface_; size_t read_index_, write_index_; + // time management GTimer *timer_; - std::array timestamp_; + std::array elapsed_stack_; + std::array timestamps_; double delay_; // control bool paused_; - CloneImageMode image_mode_; + CloneSourceProvenance provenance_; }; diff --git a/ImGuiVisitor.cpp b/ImGuiVisitor.cpp index 6f395b9..9c76b52 100644 --- a/ImGuiVisitor.cpp +++ b/ImGuiVisitor.cpp @@ -702,13 +702,15 @@ void ImGuiVisitor::visit (RenderSource& s) ImGuiToolkit::Icon(s.icon().x, s.icon().y); ImGui::SameLine(0, IMGUI_SAME_LINE); ImGui::Text("Rendering Output"); - if ( ImGui::Button(IMGUI_TITLE_PREVIEW, ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) + if ( ImGui::Button(ICON_FA_DESKTOP " Show window", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) Settings::application.widget.preview = true; + ImGui::SameLine(0, IMGUI_SAME_LINE); + ImGui::Text("Output"); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); - int m = (int) s.renderMode(); - if (ImGui::Combo("Rendering", &m, RenderSource::render_mode_label, IM_ARRAYSIZE(RenderSource::render_mode_label)) ) - s.setRenderMode((RenderSource::RenderSourceMode)m); + int m = (int) s.renderingProvenance(); + if (ImGui::Combo("Render", &m, RenderSource::rendering_provenance_label, IM_ARRAYSIZE(RenderSource::rendering_provenance_label)) ) + s.setRenderingProvenance((RenderSource::RenderSourceProvenance)m); } @@ -719,13 +721,13 @@ void ImGuiVisitor::visit (CloneSource& s) ImGui::Text("Clone"); if ( ImGui::Button(s.origin()->name().c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) Mixer::manager().setCurrentSource(s.origin()); - ImGui::SameLine(); + ImGui::SameLine(0, IMGUI_SAME_LINE); ImGui::Text("Source"); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); - int m = (int) s.imageMode(); - if (ImGui::Combo("Image", &m, "Original\0Post-processed\0") ) - s.setImageMode((CloneSource::CloneImageMode)m); + int m = (int) s.cloningProvenance(); + if (ImGui::Combo("Render", &m, CloneSource::cloning_provenance_label, IM_ARRAYSIZE(CloneSource::cloning_provenance_label)) ) + s.setCloningProvenance((CloneSource::CloneSourceProvenance)m); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); float d = s.delay(); diff --git a/InfoVisitor.cpp b/InfoVisitor.cpp index 83addc4..eb28e7e 100644 --- a/InfoVisitor.cpp +++ b/InfoVisitor.cpp @@ -174,7 +174,8 @@ void InfoVisitor::visit (RenderSource& s) return; std::ostringstream oss; - oss << "Rendering Output (" << RenderSource::render_mode_label[s.renderMode()]; + oss << "Rendering Output ("; + oss << RenderSource::rendering_provenance_label[s.renderingProvenance()]; oss << ") " << std::endl; if (s.frame()){ @@ -195,7 +196,9 @@ void InfoVisitor::visit (CloneSource& s) return; std::ostringstream oss; - oss << "Clone of '" << s.origin()->name() << "' " << std::endl; + oss << "Clone of '" << s.origin()->name() << "' ("; + oss << CloneSource::cloning_provenance_label[s.cloningProvenance()]; + oss << ") " << std::endl; if (s.frame()){ oss << s.frame()->width() << " x " << s.frame()->height() << ", "; diff --git a/RenderSource.cpp b/RenderSource.cpp index da9591d..e806336 100644 --- a/RenderSource.cpp +++ b/RenderSource.cpp @@ -29,10 +29,10 @@ #include "RenderSource.h" -const char* RenderSource::render_mode_label[2] = { "Loopback", "Non recursive" }; +const char* RenderSource::rendering_provenance_label[2] = { "Loopback", "Non-recursive" }; -RenderSource::RenderSource(uint64_t id) : Source(id), session_(nullptr), rendered_output_(nullptr), rendered_surface_(nullptr), - paused_(false), render_mode_(RENDER_TEXTURE) +RenderSource::RenderSource(uint64_t id) : Source(id), session_(nullptr), runtime_(0), rendered_output_(nullptr), rendered_surface_(nullptr), + paused_(false), provenance_(RENDER_TEXTURE) { // set symbol symbol_ = new Symbol(Symbol::RENDER, glm::vec3(0.75f, 0.75f, 0.01f)); @@ -106,7 +106,7 @@ void RenderSource::update(float dt) if (active_ && !paused_ && session_ && rendered_output_) { - if (render_mode_ == RENDER_EXCLUSIVE) { + if (provenance_ == RENDER_EXCLUSIVE) { // temporarily exclude this RenderSource from the rendering groups_[View::RENDERING]->visible_ = false; // simulate a rendering of the session in a framebuffer @@ -121,6 +121,7 @@ void RenderSource::update(float dt) else session_->frame()->blit(rendered_output_); + runtime_ = session_->runtime(); // rendered_output_->begin(true); // if not blit // rendered_surface_->draw(glm::identity(), rendered_output_->projection()); @@ -136,12 +137,6 @@ void RenderSource::play (bool on) paused_ = !on; } -void RenderSource::replay() -{ - -} - - glm::vec3 RenderSource::resolution() const { if (rendered_output_ != nullptr) @@ -155,7 +150,7 @@ glm::vec3 RenderSource::resolution() const void RenderSource::accept(Visitor& v) { Source::accept(v); -// if (!failed()) + if (!failed()) v.visit(*this); } diff --git a/RenderSource.h b/RenderSource.h index 72759db..5317cdb 100644 --- a/RenderSource.h +++ b/RenderSource.h @@ -13,11 +13,11 @@ public: // implementation of source API void update (float dt) override; -// void setActive (bool on) override; bool playing () const override { return !paused_; } void play (bool) override; - void replay () override; + void replay () override {} bool playable () const override { return true; } + guint64 playtime () const override { return runtime_; } bool failed () const override; uint texture() const override; void accept (Visitor& v) override; @@ -27,29 +27,30 @@ public: glm::vec3 resolution() const; - glm::ivec2 icon() const override; - std::string info() const override; - typedef enum { RENDER_TEXTURE = 0, RENDER_EXCLUSIVE - } RenderSourceMode; - static const char* render_mode_label[2]; + } RenderSourceProvenance; + static const char* rendering_provenance_label[2]; - void setRenderMode(RenderSourceMode m) { render_mode_ = m; } - RenderSourceMode renderMode() const { return render_mode_; } + void setRenderingProvenance(RenderSourceProvenance m) { provenance_ = m; } + RenderSourceProvenance renderingProvenance() const { return provenance_; } + + glm::ivec2 icon() const override; + std::string info() const override; protected: void init() override; Session *session_; + uint64_t runtime_; FrameBuffer *rendered_output_; Surface *rendered_surface_; // control bool paused_; - RenderSourceMode render_mode_; + RenderSourceProvenance provenance_; }; diff --git a/SessionCreator.cpp b/SessionCreator.cpp index d9e8df0..ac56e9d 100644 --- a/SessionCreator.cpp +++ b/SessionCreator.cpp @@ -975,9 +975,9 @@ void SessionLoader::visit (SessionGroupSource& s) void SessionLoader::visit (RenderSource& s) { // set attributes - int mode = 0; - xmlCurrent_->QueryIntAttribute("renderMode", &mode); - s.setRenderMode((RenderSource::RenderSourceMode)mode); + int p = 0; + xmlCurrent_->QueryIntAttribute("provenance", &p); + s.setRenderingProvenance((RenderSource::RenderSourceProvenance)p); // set session s.setSession( session_ ); @@ -1093,12 +1093,12 @@ void SessionLoader::visit (GenericStreamSource& s) void SessionLoader::visit (CloneSource& s) { // set attributes - int imagemode = 0; - xmlCurrent_->QueryIntAttribute("imageMode", &imagemode); - s.setImageMode((CloneSource::CloneImageMode)imagemode); + int p = 0; + xmlCurrent_->QueryIntAttribute("provenance", &p); + s.setCloningProvenance((CloneSource::CloneSourceProvenance)p); - double delay = 0.0; - xmlCurrent_->QueryDoubleAttribute("delay", &delay); - s.setDelay(delay); + double d = 0.0; + xmlCurrent_->QueryDoubleAttribute("delay", &d); + s.setDelay(d); } diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp index 9a75e9f..e7a2a3c 100644 --- a/SessionVisitor.cpp +++ b/SessionVisitor.cpp @@ -630,13 +630,13 @@ void SessionVisitor::visit (SessionGroupSource& s) void SessionVisitor::visit (RenderSource& s) { xmlCurrent_->SetAttribute("type", "RenderSource"); - xmlCurrent_->SetAttribute("renderMode", (int) s.renderMode()); + xmlCurrent_->SetAttribute("provenance", (int) s.renderingProvenance()); } void SessionVisitor::visit (CloneSource& s) { xmlCurrent_->SetAttribute("type", "CloneSource"); - xmlCurrent_->SetAttribute("imageMode", (int) s.imageMode()); + xmlCurrent_->SetAttribute("provenance", (int) s.cloningProvenance()); xmlCurrent_->SetAttribute("delay", (double) s.delay()); XMLElement *origin = xmlDoc_->NewElement("origin"); diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index 8c777d3..c252969 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -3007,20 +3007,26 @@ void SourceController::RenderSingleSource(Source *s) if (ImGui::IsItemHovered()){ // fill info string s->accept(info_); - + // draw overlay frame and text float tooltip_height = 3.f * ImGui::GetTextLineHeightWithSpacing(); ImDrawList* draw_list = ImGui::GetWindowDrawList(); draw_list->AddRectFilled(top, top + ImVec2(framesize.x, tooltip_height), IMGUI_COLOR_OVERLAY); ImGui::SetCursorScreenPos(top + ImVec2(h_space_, v_space_)); ImGui::Text("%s", info_.str().c_str()); - + // special case Streams: print framerate StreamSource *sts = dynamic_cast(s); if (sts && s->playing()) { ImGui::SetCursorScreenPos(top + ImVec2( framesize.x - 1.5f * buttons_height_, 0.5f * tooltip_height)); ImGui::Text("%.1f Hz", sts->stream()->updateFrameRate()); } } - // Play icon lower left corner + else + // make sure next ItemHovered refreshes the info_ + info_.reset(); + + /// + /// Play icon lower left corner + /// ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE); ImGui::SetCursorScreenPos(bottom + ImVec2(h_space_, -ImGui::GetTextLineHeightWithSpacing())); ImGui::Text("%s %s", SourcePlayIcon(s), GstToolkit::time_to_string(s->playtime()).c_str() );