Properties pannel of Session

Also added custom thumbnail of session.
This commit is contained in:
Bruno
2021-08-01 00:29:44 +02:00
parent c5f0be2b32
commit d1e833e0a1
7 changed files with 222 additions and 43 deletions

View File

@@ -38,11 +38,13 @@ void captureMixerSession(tinyxml2::XMLDocument *doc, std::string node, std::stri
Session *se = Mixer::manager().session();
// get the thumbnail (requires one opengl update to render)
FrameBufferImage *thumbnail = se->thumbnail();
XMLElement *imageelement = SessionVisitor::ImageToXML(thumbnail, doc);
if (imageelement)
sessionNode->InsertEndChild(imageelement);
delete thumbnail;
FrameBufferImage *thumbnail = se->renderThumbnail();
if (thumbnail) {
XMLElement *imageelement = SessionVisitor::ImageToXML(thumbnail, doc);
if (imageelement)
sessionNode->InsertEndChild(imageelement);
delete thumbnail;
}
// save all sources using source visitor
SessionVisitor sv(doc, sessionNode);

View File

@@ -18,7 +18,7 @@ SessionNote::SessionNote(const std::string &t, bool l, int s): label(std::to_str
{
}
Session::Session() : active_(true), filename_(""), failedSource_(nullptr), fading_target_(0.f)
Session::Session() : active_(true), filename_(""), failedSource_(nullptr), fading_target_(0.f), thumbnail_(nullptr)
{
config_[View::RENDERING] = new Group;
config_[View::RENDERING]->scale_ = glm::vec3(0.f);
@@ -228,6 +228,33 @@ Source *Session::popSource()
return s;
}
static void replaceThumbnail(Session *s)
{
if (s != nullptr) {
FrameBufferImage *t = s->renderThumbnail();
if (t != nullptr) // avoid recursive infinite loop
s->setThumbnail(t);
}
}
void Session::setThumbnail(FrameBufferImage *t)
{
resetThumbnail();
// replace with given image
if (t != nullptr)
thumbnail_ = t;
// no thumbnail image given: capture from rendering in a parallel thread
else
std::thread( replaceThumbnail, this ).detach();
}
void Session::resetThumbnail()
{
if (thumbnail_ != nullptr)
delete thumbnail_;
thumbnail_ = nullptr;
}
void Session::setResolution(glm::vec3 resolution, bool useAlpha)
{
// setup the render view: if not specified the default config resulution will be used

View File

@@ -85,8 +85,13 @@ public:
// get frame result of render
inline FrameBuffer *frame () const { return render_.frame(); }
// get thumbnail image
inline FrameBufferImage *thumbnail () { return render_.thumbnail(); }
// get an newly rendered thumbnail
inline FrameBufferImage *renderThumbnail () { return render_.thumbnail(); }
// get / set thumbnail image
inline FrameBufferImage *thumbnail () const { return thumbnail_; }
void setThumbnail(FrameBufferImage *t = nullptr);
void resetThumbnail();
// configure rendering resolution
void setResolution (glm::vec3 resolution, bool useAlpha = false);
@@ -153,7 +158,7 @@ protected:
std::vector<SourceIdList> play_groups_;
float fading_target_;
std::mutex access_;
FrameBufferImage *thumbnail_;
};

View File

@@ -54,7 +54,13 @@ SessionInformation SessionCreator::info(const std::string& filename)
}
const XMLElement *session = doc.FirstChildElement("Session");
if (session != nullptr ) {
ret.thumbnail = XMLToImage(session);
const XMLElement *thumbnailelement = session->FirstChildElement("Thumbnail");
// if there is a user defined thumbnail, get it
if (thumbnailelement)
ret.thumbnail = XMLToImage(thumbnailelement);
// otherwise get the default saved thumbnail in session
else
ret.thumbnail = XMLToImage(session);
}
}
}
@@ -100,7 +106,8 @@ void SessionCreator::load(const std::string& filename)
// ready to read sources
sessionFilePath_ = SystemToolkit::path_filename(filename);
SessionLoader::load( xmlDoc_.FirstChildElement("Session") );
XMLElement *sessionNode = xmlDoc_.FirstChildElement("Session");
SessionLoader::load( sessionNode );
// create groups
std::list< SourceList > groups = getMixingGroups();
@@ -116,6 +123,15 @@ void SessionCreator::load(const std::string& filename)
// load playlists
loadPlayGroups( xmlDoc_.FirstChildElement("PlayGroups") );
// thumbnail
const XMLElement *thumbnailelement = sessionNode->FirstChildElement("Thumbnail");
// if there is a user-defined thumbnail, get it
if (thumbnailelement) {
FrameBufferImage *thumbnail = XMLToImage(thumbnailelement);
if (thumbnail != nullptr)
session_->setThumbnail( thumbnail );
}
// all good
session_->setFilename(filename);
}

View File

@@ -51,12 +51,26 @@ bool SessionVisitor::saveSession(const std::string& filename, Session *session)
// source visitor
(*iter)->accept(sv);
// get the thumbnail
// save the thumbnail
FrameBufferImage *thumbnail = session->thumbnail();
XMLElement *imageelement = SessionVisitor::ImageToXML(thumbnail, &xmlDoc);
if (imageelement)
sessionNode->InsertEndChild(imageelement);
delete thumbnail;
if (thumbnail != nullptr && thumbnail->width > 0 && thumbnail->height > 0) {
XMLElement *thumbnailelement = xmlDoc.NewElement("Thumbnail");
XMLElement *imageelement = SessionVisitor::ImageToXML(thumbnail, &xmlDoc);
if (imageelement) {
sessionNode->InsertEndChild(thumbnailelement);
thumbnailelement->InsertEndChild(imageelement);
}
}
// if no thumbnail is set by user, capture thumbnail now
else {
thumbnail = session->renderThumbnail();
if (thumbnail) {
XMLElement *imageelement = SessionVisitor::ImageToXML(thumbnail, &xmlDoc);
if (imageelement)
sessionNode->InsertEndChild(imageelement);
delete thumbnail;
}
}
// 2. config of views
saveConfig( &xmlDoc, session );

View File

@@ -767,7 +767,10 @@ void UserInterface::Render()
}
// verify the video recorder is valid
FrameGrabbing::manager().verify(&video_recorder_);
if (video_recorder_ && video_recorder_->duration() > Settings::application.record.timeout ){
if (video_recorder_ // if there is an ongoing recorder
&& Settings::application.record.timeout < RECORD_MAX_TIMEOUT // and if the timeout is valid
&& video_recorder_->duration() > Settings::application.record.timeout ) // and the timeout is reached
{
video_recorder_->stop();
video_recorder_ = nullptr;
}
@@ -1078,27 +1081,33 @@ void UserInterface::RenderPreview()
Settings::application.widget.preview = false;
if (ImGui::BeginMenu(IMGUI_TITLE_PREVIEW))
{
glm::ivec2 p = FrameBuffer::getParametersFromResolution(output->resolution());
std::ostringstream info;
info << "Resolution " << output->width() << "x" << output->height();
if (p.x > -1)
info << " " << FrameBuffer::aspect_ratio_name[p.x] ;
ImGui::MenuItem(info.str().c_str(), nullptr, false, false);
// cannot change resolution when recording
if (video_recorder_ == nullptr && p.y > -1) {
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::Combo("Height", &p.y, FrameBuffer::resolution_name, IM_ARRAYSIZE(FrameBuffer::resolution_name) ) )
{
glm::vec3 res = FrameBuffer::getResolutionFromParameters(p.x, p.y);
Mixer::manager().session()->setResolution(res);
}
}
// glm::ivec2 p = FrameBuffer::getParametersFromResolution(output->resolution());
// std::ostringstream info;
// info << "Resolution " << output->width() << "x" << output->height();
// if (p.x > -1)
// info << " " << FrameBuffer::aspect_ratio_name[p.x] ;
// ImGui::MenuItem(info.str().c_str(), nullptr, false, false);
// // cannot change resolution when recording
// if (video_recorder_ == nullptr && p.y > -1) {
// ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
// if (ImGui::Combo("Height", &p.y, FrameBuffer::resolution_name, IM_ARRAYSIZE(FrameBuffer::resolution_name) ) )
// {
// glm::vec3 res = FrameBuffer::getResolutionFromParameters(p.x, p.y);
// Mixer::manager().session()->setResolution(res);
// }
// }
if ( ImGui::MenuItem( ICON_FA_PLUS " Insert Rendering Source") )
Mixer::manager().addSource( Mixer::manager().createSourceRender() );
if ( ImGui::MenuItem( ICON_FA_WINDOW_RESTORE " Show output window") )
Rendering::manager().outputWindow().show();
bool isfullscreen = Rendering::manager().outputWindow().isFullscreen();
if ( ImGui::MenuItem( ICON_FA_EXPAND_ALT " Fullscreen output window", nullptr, &isfullscreen) ) {
Rendering::manager().outputWindow().show();
Rendering::manager().outputWindow().toggleFullscreen();
}
ImGui::Separator();
bool pinned = Settings::application.widget.preview_view == Settings::application.current_view;
@@ -4105,7 +4114,7 @@ void Navigator::RenderMainPannelVimix()
_file_info = info.description;
if (info.thumbnail) {
// set image content to thumbnail display
_file_thumbnail.set( info.thumbnail );
_file_thumbnail.fill( info.thumbnail );
delete info.thumbnail;
} else
_file_thumbnail.reset();
@@ -4148,7 +4157,7 @@ void Navigator::RenderMainPannelVimix()
// Right side of the list: helper and options
ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_top.y));
if ( ImGuiToolkit::IconButton( ICON_FA_FILE )) {
if ( ImGuiToolkit::IconButton( ICON_FA_FILE " +" )) {
Mixer::manager().close(Settings::application.smooth_transition );
hidePannel();
}
@@ -4174,13 +4183,112 @@ void Navigator::RenderMainPannelVimix()
// Status
//
ImGui::Spacing();
ImGui::Text("Status");
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::Combo("##SelectHistory", &Settings::application.pannel_history_mode, ICON_FA_STAR " Snapshots\0" ICON_FA_HISTORY " Undo history\0");
ImGui::Text("Current");
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::Combo("##SelectHistory", &Settings::application.pannel_history_mode,
ICON_FA_STAR " Snapshots\0" ICON_FA_HISTORY " Undo history\0" ICON_FA_FILE_ALT " Properties\0");
if (Settings::application.pannel_history_mode > 1) {
std::string sessionfilename = Mixer::manager().session()->filename();
// Information and resolution
FrameBuffer *output = Mixer::manager().session()->frame();
if (output)
{
// fill information buffer
ImGuiTextBuffer info;
if (!sessionfilename.empty())
info.appendf("%s\n", SystemToolkit::filename(sessionfilename).c_str());
else
info.append("<unsaved>\n");
info.appendf("Sources: %d\n", Mixer::manager().session()->numSource());
glm::ivec2 p = FrameBuffer::getParametersFromResolution(output->resolution());
if (p.x > -1)
info.appendf("Ratio: %s\n", FrameBuffer::aspect_ratio_name[p.x]);
info.appendf("Resolution: %dx%d", output->width(), output->height());
// Show info text bloc (multi line, dark background)
ImGuiToolkit::PushFont( ImGuiToolkit::FONT_MONO );
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.14f, 0.14f, 0.14f, 0.9f));
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
ImGui::InputTextMultiline("##Info", (char *)info.c_str(), info.size(), ImVec2(IMGUI_RIGHT_ALIGN, 4*ImGui::GetTextLineHeightWithSpacing()), ImGuiInputTextFlags_ReadOnly);
ImGui::PopStyleColor(1);
ImGui::PopFont();
// change resolution (height only)
if (p.y > -1) {
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
// cannot change resolution when recording
if ( UserInterface::manager().isRecording() ) {
// show static info (same size than combo)
static char dummy_str[512];
sprintf(dummy_str, "%s", FrameBuffer::resolution_name[p.y]);
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.14f, 0.14f, 0.14f, 0.9f));
ImGui::InputText("Height", dummy_str, IM_ARRAYSIZE(dummy_str), ImGuiInputTextFlags_ReadOnly);
ImGui::PopStyleColor(1);
}
else {
// combo box to select height
if (ImGui::Combo("Height", &p.y, FrameBuffer::resolution_name, IM_ARRAYSIZE(FrameBuffer::resolution_name) ) )
{
glm::vec3 res = FrameBuffer::getResolutionFromParameters(p.x, p.y);
Mixer::manager().session()->setResolution(res);
}
}
}
}
// the session file exists
if (!sessionfilename.empty())
{
// Thumbnail
static Thumbnail _file_thumbnail;
static FrameBufferImage *thumbnail = nullptr;
if ( ImGui::Button( ICON_FA_TAGS " Capture thumbnail", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) {
Mixer::manager().session()->setThumbnail();
thumbnail = nullptr;
}
pos_bot = ImGui::GetCursorPos();
if (ImGui::IsItemHovered()){
// thumbnail changed
if (thumbnail != Mixer::manager().session()->thumbnail()) {
_file_thumbnail.reset();
thumbnail = Mixer::manager().session()->thumbnail();
if (thumbnail != nullptr)
_file_thumbnail.fill( thumbnail );
}
if (_file_thumbnail.filled()) {
ImGui::BeginTooltip();
_file_thumbnail.Render(230);
ImGui::EndTooltip();
}
}
if (Mixer::manager().session()->thumbnail()) {
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.7);
ImGui::SameLine();
if (ImGuiToolkit::IconButton(ICON_FA_BACKSPACE, "Remove captured thumbnail")) {
Mixer::manager().session()->resetThumbnail();
_file_thumbnail.reset();
thumbnail = nullptr;
}
ImGui::PopStyleVar();
}
ImGui::SetCursorPos( pos_bot );
// Folder
std::string path = SystemToolkit::path_filename(sessionfilename);
std::string label = BaseToolkit::trunc_string(path, 23);
label = BaseToolkit::transliterate(label);
ImGuiToolkit::ButtonOpenUrl( label.c_str(), path.c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0) );
}
}
//
// UNDO History
if (Settings::application.pannel_history_mode > 0) {
else if (Settings::application.pannel_history_mode > 0) {
static uint _over = 0;
static uint64_t _displayed_over = 0;
@@ -4220,7 +4328,7 @@ void Navigator::RenderMainPannelVimix()
FrameBufferImage *im = Action::manager().thumbnail(_over);
if (im) {
// set image content to thumbnail display
_undo_thumbnail.set( im );
_undo_thumbnail.fill( im );
delete im;
}
else
@@ -4329,7 +4437,7 @@ void Navigator::RenderMainPannelVimix()
FrameBufferImage *im = Action::manager().thumbnail(_over);
if (im) {
// set image content to thumbnail display
_snap_thumbnail.set( im );
_snap_thumbnail.fill( im );
delete im;
}
else
@@ -4742,12 +4850,17 @@ Thumbnail::~Thumbnail()
glDeleteTextures(1, &texture_);
}
bool Thumbnail::filled()
{
return aspect_ratio_ > 0.f;
}
void Thumbnail::reset()
{
aspect_ratio_ = -1.f;
}
void Thumbnail::set(const FrameBufferImage *image)
void Thumbnail::fill(const FrameBufferImage *image)
{
if (!texture_) {
glGenTextures(1, &texture_);
@@ -4764,7 +4877,7 @@ void Thumbnail::set(const FrameBufferImage *image)
void Thumbnail::Render(float width)
{
if (aspect_ratio_>0.f)
if (filled())
ImGui::Image((void*)(intptr_t)texture_, ImVec2(width, width/aspect_ratio_), ImVec2(0,0), ImVec2(0.5f*aspect_ratio_, 1.f));
}

View File

@@ -45,7 +45,8 @@ public:
~Thumbnail();
void reset();
void set (const FrameBufferImage *image);
void fill (const FrameBufferImage *image);
bool filled();
void Render(float width);
};
@@ -218,6 +219,7 @@ public:
void fillShaderEditor(const std::string &text);
void StartScreenshot();
inline bool isRecording() const { return video_recorder_ != nullptr; }
protected: