diff --git a/CMakeLists.txt b/CMakeLists.txt index 0563969..8d47c21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -293,6 +293,7 @@ set(VMIX_SRCS TransitionView.cpp Source.cpp CloneSource.cpp + RenderSource.cpp SourceCallback.cpp SourceList.cpp Session.cpp diff --git a/ImGuiVisitor.cpp b/ImGuiVisitor.cpp index df87fc6..6f395b9 100644 --- a/ImGuiVisitor.cpp +++ b/ImGuiVisitor.cpp @@ -43,6 +43,7 @@ #include "MediaPlayer.h" #include "MediaSource.h" #include "CloneSource.h" +#include "RenderSource.h" #include "SessionSource.h" #include "PatternSource.h" #include "DeviceSource.h" @@ -703,6 +704,12 @@ void ImGuiVisitor::visit (RenderSource& s) ImGui::Text("Rendering Output"); if ( ImGui::Button(IMGUI_TITLE_PREVIEW, ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) Settings::application.widget.preview = true; + + 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); + } void ImGuiVisitor::visit (CloneSource& s) @@ -720,13 +727,10 @@ void ImGuiVisitor::visit (CloneSource& s) if (ImGui::Combo("Image", &m, "Original\0Post-processed\0") ) s.setImageMode((CloneSource::CloneImageMode)m); - ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); float d = s.delay(); -// if (ImGui::SliderFloat("Delay", &d, 0.f, 1.f, "%.2f s")){ - if (ImGui::SliderFloat("Delay", &d, 0.f, 1.f, d < 0.01f ? "None" : "%.2f s")){ + if (ImGui::SliderFloat("Delay", &d, 0.f, 1.f, d < 0.01f ? "None" : "%.2f s")) s.setDelay(d); - } } diff --git a/InfoVisitor.cpp b/InfoVisitor.cpp index 6b030b0..83addc4 100644 --- a/InfoVisitor.cpp +++ b/InfoVisitor.cpp @@ -39,6 +39,7 @@ #include "MediaPlayer.h" #include "MediaSource.h" #include "CloneSource.h" +#include "RenderSource.h" #include "SessionSource.h" #include "PatternSource.h" #include "DeviceSource.h" @@ -172,7 +173,19 @@ void InfoVisitor::visit (RenderSource& s) if (current_id_ == s.id()) return; - information_ = "Rendering Output"; + std::ostringstream oss; + oss << "Rendering Output (" << RenderSource::render_mode_label[s.renderMode()]; + oss << ") " << std::endl; + + if (s.frame()){ + oss << s.frame()->width() << " x " << s.frame()->height() << ", "; + if (s.frame()->use_alpha()) + oss << "RGBA"; + else + oss << "RGB"; + } + + information_ = oss.str(); current_id_ = s.id(); } @@ -186,7 +199,10 @@ void InfoVisitor::visit (CloneSource& s) if (s.frame()){ oss << s.frame()->width() << " x " << s.frame()->height() << ", "; - oss << "RGBA"; + if (s.frame()->use_alpha()) + oss << "RGBA"; + else + oss << "RGB"; } information_ = oss.str(); diff --git a/Mixer.cpp b/Mixer.cpp index 7c034cb..03962a7 100644 --- a/Mixer.cpp +++ b/Mixer.cpp @@ -43,6 +43,7 @@ #include "SessionVisitor.h" #include "SessionSource.h" #include "CloneSource.h" +#include "RenderSource.h" #include "MediaSource.h" #include "PatternSource.h" #include "DeviceSource.h" diff --git a/RenderSource.cpp b/RenderSource.cpp new file mode 100644 index 0000000..da9591d --- /dev/null +++ b/RenderSource.cpp @@ -0,0 +1,170 @@ +/* + * This file is part of vimix - video live mixer + * + * **Copyright** (C) 2019-2022 Bruno Herbelin + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +**/ + +#include + +#include "defines.h" +#include "Log.h" +#include "FrameBuffer.h" +#include "Decorations.h" +#include "Resource.h" +#include "Visitor.h" +#include "Session.h" + +#include "RenderSource.h" + +const char* RenderSource::render_mode_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) +{ + // set symbol + symbol_ = new Symbol(Symbol::RENDER, glm::vec3(0.75f, 0.75f, 0.01f)); + symbol_->scale_.y = 1.5f; +} + +RenderSource::~RenderSource() +{ + if (rendered_output_ != nullptr) + delete rendered_output_; +} + +bool RenderSource::failed() const +{ + if ( rendered_output_ != nullptr && session_ != nullptr ) + return rendered_output_->resolution() != session_->frame()->resolution(); + + return false; +} + +uint RenderSource::texture() const +{ + if (rendered_output_ != nullptr) + return rendered_output_->texture(); + else if (session_ && session_->frame()) + return session_->frame()->texture(); + else + return Resource::getTextureBlack(); // getTextureTransparent ? +} + +//void RenderSource::setActive (bool on) +//{ + +//} + +void RenderSource::init() +{ + if (session_ && session_->frame() && session_->frame()->texture() != Resource::getTextureBlack()) { + + FrameBuffer *fb = session_->frame(); + + // get the texture index from framebuffer of view for RENDER_TEXTURE mode +// rendered_surface_ = new Surface; +// rendered_surface_->setTextureIndex( fb->texture() ); + + // create the frame buffer displayed by the source (all modes) + rendered_output_ = new FrameBuffer( fb->resolution(), fb->use_alpha() ); + // needs a first initialization + fb->blit(rendered_output_); + + // set the texture index from internal framebuffer, apply it to the source texture surface + texturesurface_->setTextureIndex( rendered_output_->texture() ); + + // create Frame buffer matching size of output session + FrameBuffer *renderbuffer = new FrameBuffer( fb->resolution() ); + + // set the renderbuffer of the source and attach rendering nodes + attach(renderbuffer); + + // deep update to reorder + ++View::need_deep_update_; + + // done init + Log::Info("Source Render linked to session (%d x %d).", int(fb->resolution().x), int(fb->resolution().y) ); + } +} + +void RenderSource::update(float dt) +{ + static glm::mat4 projection = glm::ortho(-1.f, 1.f, 1.f, -1.f, -SCENE_DEPTH, 1.f); + + if (active_ && !paused_ && session_ && rendered_output_) { + + if (render_mode_ == RENDER_EXCLUSIVE) { + // temporarily exclude this RenderSource from the rendering + groups_[View::RENDERING]->visible_ = false; + // simulate a rendering of the session in a framebuffer + glm::mat4 P = glm::scale( projection, glm::vec3(1.f / rendered_output_->aspectRatio(), 1.f, 1.f)); + rendered_output_->begin(); + // access to private RenderView in the session to call draw on the root of the scene + session_->render_.scene.root()->draw(glm::identity(), P); + rendered_output_->end(); + // restore this RenderSource visibility + groups_[View::RENDERING]->visible_ = true; + } + else + session_->frame()->blit(rendered_output_); + + + // rendered_output_->begin(true); // if not blit + // rendered_surface_->draw(glm::identity(), rendered_output_->projection()); + // rendered_output_->end(); + } + + Source::update(dt); +} + +void RenderSource::play (bool on) +{ + // toggle state + paused_ = !on; +} + +void RenderSource::replay() +{ + +} + + +glm::vec3 RenderSource::resolution() const +{ + if (rendered_output_ != nullptr) + return rendered_output_->resolution(); + else if (session_ && session_->frame()) + return session_->frame()->resolution(); + else + return glm::vec3(0.f); +} + +void RenderSource::accept(Visitor& v) +{ + Source::accept(v); +// if (!failed()) + v.visit(*this); +} + +glm::ivec2 RenderSource::icon() const +{ + return glm::ivec2(ICON_SOURCE_RENDER); +} + +std::string RenderSource::info() const +{ + return std::string("Render loopback"); +} diff --git a/RenderSource.h b/RenderSource.h new file mode 100644 index 0000000..72759db --- /dev/null +++ b/RenderSource.h @@ -0,0 +1,56 @@ +#ifndef RENDERSOURCE_H +#define RENDERSOURCE_H + +#include "Source.h" + + + +class RenderSource : public Source +{ +public: + RenderSource(uint64_t id = 0); + ~RenderSource(); + + // 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; + bool playable () const override { return true; } + bool failed () const override; + uint texture() const override; + void accept (Visitor& v) override; + + inline Session *session () const { return session_; } + inline void setSession (Session *se) { session_ = se; } + + 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]; + + void setRenderMode(RenderSourceMode m) { render_mode_ = m; } + RenderSourceMode renderMode() const { return render_mode_; } + +protected: + + void init() override; + Session *session_; + + FrameBuffer *rendered_output_; + Surface *rendered_surface_; + + // control + bool paused_; + RenderSourceMode render_mode_; +}; + + +#endif // RENDERSOURCE_H diff --git a/Session.cpp b/Session.cpp index 4a8c661..411e4b9 100644 --- a/Session.cpp +++ b/Session.cpp @@ -27,6 +27,7 @@ #include "FrameGrabber.h" #include "SessionCreator.h" #include "SessionSource.h" +#include "RenderSource.h" #include "MixingGroup.h" #include "Log.h" @@ -129,11 +130,11 @@ void Session::update(float dt) else { if ( !(*it)->ready() ) ready = false; - // render the source - (*it)->render(); // update the source (*it)->setActive(activation_threshold_); (*it)->update(dt); + // render the source // TODO: verify ok to render after update + (*it)->render(); } } diff --git a/Session.h b/Session.h index 91dd49a..2b55018 100644 --- a/Session.h +++ b/Session.h @@ -32,6 +32,8 @@ struct SessionSnapshots { class Session { + friend class RenderSource; + public: Session(); ~Session(); diff --git a/SessionCreator.cpp b/SessionCreator.cpp index 87ec47a..d9e8df0 100644 --- a/SessionCreator.cpp +++ b/SessionCreator.cpp @@ -34,6 +34,7 @@ #include "NetworkSource.h" #include "MultiFileSource.h" #include "StreamSource.h" +#include "RenderSource.h" #include "Session.h" #include "ImageShader.h" #include "ImageProcessingShader.h" @@ -973,6 +974,12 @@ void SessionLoader::visit (SessionGroupSource& s) void SessionLoader::visit (RenderSource& s) { + // set attributes + int mode = 0; + xmlCurrent_->QueryIntAttribute("renderMode", &mode); + s.setRenderMode((RenderSource::RenderSourceMode)mode); + + // set session s.setSession( session_ ); } diff --git a/SessionSource.cpp b/SessionSource.cpp index 7e034e4..5ec30cf 100644 --- a/SessionSource.cpp +++ b/SessionSource.cpp @@ -382,77 +382,3 @@ std::string SessionGroupSource::info() const else return std::string("undefined group."); } - -RenderSource::RenderSource(uint64_t id) : Source(id), session_(nullptr) -{ - // set symbol - symbol_ = new Symbol(Symbol::RENDER, glm::vec3(0.75f, 0.75f, 0.01f)); - symbol_->scale_.y = 1.5f; -} - -bool RenderSource::failed() const -{ - if ( renderbuffer_ != nullptr && session_ != nullptr ) - return renderbuffer_->resolution() != session_->frame()->resolution(); - - return false; -} - -uint RenderSource::texture() const -{ - if (session_ && session_->frame()) - return session_->frame()->texture(); - else - return Resource::getTextureBlack(); // getTextureTransparent ? -} - -void RenderSource::init() -{ - if (session_ && session_->frame() && session_->frame()->texture() != Resource::getTextureBlack()) { - - FrameBuffer *fb = session_->frame(); - - // get the texture index from framebuffer of view, apply it to the surface - texturesurface_->setTextureIndex( fb->texture() ); - - // create Frame buffer matching size of output session - FrameBuffer *renderbuffer = new FrameBuffer( fb->resolution() ); - - // set the renderbuffer of the source and attach rendering nodes - attach(renderbuffer); - - // deep update to reorder - ++View::need_deep_update_; - - // done init - Log::Info("Source Render linked to session (%d x %d).", int(fb->resolution().x), int(fb->resolution().y) ); - } -} - - -glm::vec3 RenderSource::resolution() const -{ - if (renderbuffer_ != nullptr) - return renderbuffer_->resolution(); - else if (session_ && session_->frame()) - return session_->frame()->resolution(); - else - return glm::vec3(0.f); -} - -void RenderSource::accept(Visitor& v) -{ - Source::accept(v); -// if (!failed()) - v.visit(*this); -} - -glm::ivec2 RenderSource::icon() const -{ - return glm::ivec2(ICON_SOURCE_RENDER); -} - -std::string RenderSource::info() const -{ - return std::string("Render loopback"); -} diff --git a/SessionSource.h b/SessionSource.h index f6dd63f..c74d8a8 100644 --- a/SessionSource.h +++ b/SessionSource.h @@ -83,33 +83,4 @@ protected: glm::vec3 resolution_; }; - -class RenderSource : public Source -{ -public: - RenderSource(uint64_t id = 0); - - // implementation of source API - bool playing () const override { return true; } - void play (bool) override {} - bool playable () const override { return false; } - bool failed () const override; - uint texture() const override; - void accept (Visitor& v) override; - - inline Session *session () const { return session_; } - inline void setSession (Session *se) { session_ = se; } - - glm::vec3 resolution() const; - - glm::ivec2 icon() const override; - std::string info() const override; - -protected: - - void init() override; - Session *session_; -}; - - #endif // SESSIONSOURCE_H diff --git a/SessionVisitor.cpp b/SessionVisitor.cpp index 10a309c..9a75e9f 100644 --- a/SessionVisitor.cpp +++ b/SessionVisitor.cpp @@ -29,6 +29,7 @@ using namespace tinyxml2; #include "Decorations.h" #include "Source.h" #include "CloneSource.h" +#include "RenderSource.h" #include "MediaSource.h" #include "Session.h" #include "SessionSource.h" @@ -626,9 +627,10 @@ void SessionVisitor::visit (SessionGroupSource& s) } -void SessionVisitor::visit (RenderSource&) +void SessionVisitor::visit (RenderSource& s) { xmlCurrent_->SetAttribute("type", "RenderSource"); + xmlCurrent_->SetAttribute("renderMode", (int) s.renderMode()); } void SessionVisitor::visit (CloneSource& s) diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index f22eb45..8c777d3 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -77,6 +77,7 @@ using namespace std; #include "FrameBuffer.h" #include "MediaPlayer.h" #include "CloneSource.h" +#include "RenderSource.h" #include "MediaSource.h" #include "SessionSource.h" #include "PatternSource.h"