diff --git a/Mixer.cpp b/Mixer.cpp index 2d54df1..252b825 100644 --- a/Mixer.cpp +++ b/Mixer.cpp @@ -82,6 +82,11 @@ void Mixer::insertSource(Source *s) geometry_.scene.root()->addChild(s->group(View::GEOMETRY)); } +void Mixer::deleteSource(Source *s) +{ + unsetCurrentSource(); + session_->deleteSource(s); +} void Mixer::renameSource(Source *s, const std::string &newname) { @@ -290,7 +295,10 @@ bool Mixer::open(const std::string& filename) void Mixer::newSession(Session *newsession) { - // TODO : remove roots of scenes for views? done in session + // TODO : remove roots of scenes for views? +// mixing_.scene.clear(); +// geometry_.scene.clear(); + // delete session : delete all sources if (session_) delete session_; diff --git a/Mixer.h b/Mixer.h index 6fd4d81..40312fd 100644 --- a/Mixer.h +++ b/Mixer.h @@ -36,6 +36,9 @@ public: // manangement of sources void createSourceMedia(std::string uri); + // TODO: deleteSource(); + void deleteSource(Source *s); + // operations on sources void renameSource(Source *s, const std::string &newname); diff --git a/RenderingManager.cpp b/RenderingManager.cpp index 72abc82..35b3a86 100644 --- a/RenderingManager.cpp +++ b/RenderingManager.cpp @@ -348,7 +348,7 @@ glm::vec3 Rendering::unProject(glm::vec2 screen_coordinate, glm::mat4 modelview) glm::vec3 coordinates = glm::vec3( screen_coordinate.x, main_window_attributes_.viewport.y - screen_coordinate.y, 0.f); glm::vec4 viewport = glm::vec4( 0.f, 0.f, main_window_attributes_.viewport.x, main_window_attributes_.viewport.y); - Log::Info("unproject %d x %d", main_window_attributes_.viewport.x, main_window_attributes_.viewport.y); +// Log::Info("unproject %d x %d", main_window_attributes_.viewport.x, main_window_attributes_.viewport.y); glm::vec3 point = glm::unProject(coordinates, modelview, Projection(), viewport); diff --git a/Scene.cpp b/Scene.cpp index a17b17c..1ba6b7d 100644 --- a/Scene.cpp +++ b/Scene.cpp @@ -17,6 +17,8 @@ #include +Group *Scene::limbo = new Group; + glm::mat4 transform(glm::vec3 translation, glm::vec3 rotation, glm::vec3 scale) { glm::mat4 View = glm::translate(glm::identity(), translation); @@ -179,13 +181,13 @@ void Primitive::deleteGLBuffers_() // Group Group::~Group() { - for(auto it = children_.begin(); it != children_.end(); ) { + for(NodeSet::iterator it = children_.begin(); it != children_.end(); ) { // this group is not parent of that node anymore (*it)->parents_.remove(this); // if this group was the only remaining parent if ( (*it)->parents_.size() < 1 ) - // delete the child - delete (*it); + // put the child in limbo + Scene::limbo->addChild( *it ); // erase this iterator from the list it = children_.erase(it); } @@ -197,6 +199,7 @@ void Group::addChild(Node *child) child->parents_.push_back(this); } + void Group::detatchChild(Node *child) { NodeSet::iterator it = std::find_if(children_.begin(), children_.end(), hasId(child->id())); @@ -375,14 +378,31 @@ void Animation::accept(Visitor& v) v.visit(*this); } -Scene::Scene() +Scene::Scene(): root_(nullptr) { root_ = new Group; } Scene::~Scene() { - delete root_; + deleteNode(root_); +} + + +void Scene::deleteNode(Node *node) +{ + for(auto it = node->parents_.begin(); it != node->parents_.end();){ + (*it)->detatchChild(node); + } + + limbo->addChild(node); +} + +void Scene::update(float dt) +{ + root_->update( dt ); + + // remove nodes from limbo } void Scene::accept(Visitor& v) diff --git a/Scene.h b/Scene.h index 0bcfb9a..2d402ac 100644 --- a/Scene.h +++ b/Scene.h @@ -45,12 +45,13 @@ class Node { int id_; bool initialized_; + public: Node (); - virtual ~Node (); // unique identifyer generated at instanciation inline int id () const { return id_; } +// void detatch(); // must initialize the node before draw virtual void init() { initialized_ = true; } @@ -71,6 +72,9 @@ public: glm::mat4 transform_; glm::vec3 scale_, rotation_, translation_; + +protected: + virtual ~Node (); }; @@ -91,9 +95,10 @@ public: */ class Primitive : public Node { + public: Primitive(Shader *s = nullptr) : Node(), shader_(s), vao_(0), drawMode_(0), drawCount_(0) {} - virtual ~Primitive(); + virtual void init () override; virtual void accept (Visitor& v) override; @@ -110,6 +115,7 @@ protected: std::vector texCoords_; std::vector indices_; virtual void deleteGLBuffers_(); + virtual ~Primitive(); }; // @@ -151,9 +157,9 @@ private: */ class Group : public Node { + public: Group() : Node() {} - virtual ~Group(); virtual void update (float dt) override; virtual void accept (Visitor& v) override; @@ -168,6 +174,8 @@ public: protected: NodeSet children_; + // destructor + virtual ~Group(); }; /** @@ -239,12 +247,18 @@ public: void accept (Visitor& v); + void update(float dt); + +// void addNode(Node *); + + Group *root() { return root_; } // Node *find(int id); // void remove(Node *n); // - + static void deleteNode(Node *node); + static Group *limbo; }; diff --git a/Session.cpp b/Session.cpp index b652f01..78a5cb8 100644 --- a/Session.cpp +++ b/Session.cpp @@ -9,13 +9,14 @@ Session::Session() } Session::~Session() { - // TODO delete all sources + // delete all sources for(auto it = sources_.begin(); it != sources_.end(); ) { // delete source delete (*it); // erase this iterator from the list it = sources_.erase(it); } + } // update all sources @@ -54,6 +55,7 @@ SourceList::iterator Session::deleteSource(Source *s) // remove the source and delete it sources_.remove(s); + delete s; // return diff --git a/Source.cpp b/Source.cpp index a8aec3e..b8bd1fb 100644 --- a/Source.cpp +++ b/Source.cpp @@ -45,14 +45,17 @@ Source::Source(const std::string &name) : name_(name), initialized_(false) Source::~Source() { // delete render objects - delete rendershader_; if (renderbuffer_) delete renderbuffer_; - // delete groups and their children - delete groups_[View::RENDERING]; - delete groups_[View::MIXING]; - delete groups_[View::GEOMETRY]; + // all groups and their children are deleted in the scene + // this includes rendersurface_ , overlay_, blendingshader_ and rendershader_ +// delete groups_[View::RENDERING]; +// delete groups_[View::MIXING]; +// delete groups_[View::GEOMETRY]; + Scene::deleteNode(groups_[View::RENDERING]); + Scene::deleteNode(groups_[View::MIXING]); + Scene::deleteNode(groups_[View::GEOMETRY]); groups_.clear(); } diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index 0e8b298..37e3236 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -1,7 +1,6 @@ #include #include #include -#include // ImGui #include "imgui.h" @@ -32,7 +31,6 @@ #include "defines.h" #include "Log.h" #include "SystemToolkit.h" -#include "TextEditor.h" #include "UserInterfaceManager.h" #include "RenderingManager.h" #include "Resource.h" @@ -48,34 +46,36 @@ #include "ImageShader.h" #include "ImageProcessingShader.h" -static std::thread loadThread; -static bool loadThreadDone = false; +#include "TextEditor.h" static TextEditor editor; + +static std::thread FileDialogThread_; +static bool FileDialogFinished_ = false; +static std::string FileDialogFilename_ = ""; + + void ShowAboutGStreamer(bool* p_open); void ShowAboutOpengl(bool* p_open); void ShowAbout(bool* p_open); -static void NativeOpenFile(std::string ext) +static void FileDialogOpen(std::string path) { - char const * lTheOpenFileName; - char const * lFilterPatterns[2] = { "*.txt", "*.text" }; + char const * lFilterPatterns[2] = { "*.vmx" }; - lTheOpenFileName = tinyfd_openFileDialog( "Open a text file", "", 2, lFilterPatterns, nullptr, 0); + lTheOpenFileName = tinyfd_openFileDialog( "Open a session file", path.c_str(), 1, lFilterPatterns, nullptr, 0); if (!lTheOpenFileName) { - tinyfd_messageBox(APP_TITLE, "Open file name is NULL. ", "ok", "warning", 1); + FileDialogFilename_ = ""; } else { - char buf[1024]; - sprintf( buf, "he selected file is :\n %s", lTheOpenFileName ); - tinyfd_messageBox(APP_TITLE, buf, "ok", "info", 1); + FileDialogFilename_ = std::string( lTheOpenFileName ); } - loadThreadDone = true; + FileDialogFinished_ = true; } @@ -286,12 +286,16 @@ void UserInterface::handleMouse() } - - + if ( ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) ) + { + // display the info on source in left pannel + navigator.showPannelSource( Mixer::manager().indexCurrentSource() ); + } } } + void UserInterface::NewFrame() { // Start the Dear ImGui frame @@ -306,6 +310,11 @@ void UserInterface::NewFrame() // navigator bar first navigator.Render(); + // handle FileDialog + if (FileDialogFinished_) { + FileDialogFinished_ = false; + Mixer::manager().open(FileDialogFilename_); + } } void UserInterface::Render() @@ -370,10 +379,13 @@ void UserInterface::showMenuFile() { // TODO : New if (ImGui::MenuItem( ICON_FA_FILE " New", "Ctrl+W")) { - + Mixer::manager().newSession(); + navigator.hidePannel(); } if (ImGui::MenuItem( ICON_FA_FILE_UPLOAD " Open", "Ctrl+O")) { -// UserInterface::manager().OpenFileMedia(); + // launch file dialog to open a session file + FileDialogThread_ = std::thread(FileDialogOpen, "./"); + navigator.hidePannel(); } if (ImGui::MenuItem( ICON_FA_FILE_DOWNLOAD " Save", "Ctrl+S")) { // UserInterface::manager().OpenFileMedia(); @@ -406,6 +418,7 @@ void ToolBox::Render() // first run ImGui::SetNextWindowPos(ImVec2(40, 40), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(400, 300), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSizeConstraints(ImVec2(350, 300), ImVec2(FLT_MAX, FLT_MAX)); if ( !ImGui::Begin(IMGUI_TITLE_TOOLBOX, &Settings::application.toolbox, ImGuiWindowFlags_MenuBar) ) { ImGui::End(); @@ -429,18 +442,6 @@ void ToolBox::Render() ImGui::EndMenuBar(); } - // TEMPLATE CODE FOR FILE BROWSER -// if( ImGui::Button( ICON_FA_FOLDER_OPEN " Open File" ) && !loadThread.joinable()) -// { -// loadThreadDone = false; -// loadThread = std::thread(NativeOpenFile, "hello"); -// } - -// if( loadThreadDone && loadThread.joinable() ) { -// loadThread.join(); -// // TODO : deal with filename -// } - ImGui::End(); // "v-mix" @@ -484,17 +485,26 @@ void ToolBox::Render() } } + void UserInterface::RenderPreview() { + struct CustomConstraints // Helper functions for aspect-ratio constraints + { + static void AspectRatio(ImGuiSizeCallbackData* data) { float *ar = (float*) data->UserData; data->DesiredSize.x = (*ar * data->CurrentSize.y) - 70.f; } + + }; + FrameBuffer *output = Mixer::manager().session()->frame(); if (output) { + float ar = output->aspectRatio(); ImGui::SetNextWindowPos(ImVec2(850, 450), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(380, 260), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSizeConstraints(ImVec2(300, 200), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::AspectRatio, &ar); ImGui::Begin(ICON_FA_LAPTOP " Preview", &Settings::application.preview, ImGuiWindowFlags_NoScrollbar); float width = ImGui::GetContentRegionAvail().x; - ImVec2 imagesize ( width, width / output->aspectRatio()); + ImVec2 imagesize ( width, width / ar); ImGui::Image((void*)(intptr_t)output->texture(), imagesize, ImVec2(0.f, 0.f), ImVec2(1.f, -1.f)); ImGui::End(); @@ -517,6 +527,7 @@ void UserInterface::RenderMediaPlayer() ImGui::SetNextWindowPos(ImVec2(200, 200), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSizeConstraints(ImVec2(350, 300), ImVec2(FLT_MAX, FLT_MAX)); if ( !ImGui::Begin(IMGUI_TITLE_MEDIAPLAYER, &Settings::application.media_player, ImGuiWindowFlags_NoScrollbar) || !show) { ImGui::End(); @@ -748,6 +759,17 @@ void Navigator::clearSelection() selected_button[i] = false; } +void Navigator::showPannelSource(int index) +{ + selected_source_index = index; +} + +void Navigator::hidePannel() +{ + clearSelection(); + selected_source_index = -1; +} + void Navigator::Render() { ImGuiIO& io = ImGui::GetIO(); @@ -845,7 +867,12 @@ void Navigator::Render() // window to create a source else if (selected_button[NAV_NEW]) { - RenderNewPannel(); + // if a source is selected in the meantime, revert to selected source pannel + if (Mixer::manager().indexCurrentSource() > -1 ) + selected_button[NAV_NEW] = false; + else + // show new source pannel + RenderNewPannel(); } // window to configure a selected source else if (selected_source_index > -1) @@ -853,7 +880,11 @@ void Navigator::Render() // manipulate current source, and activate corresponding button clearSelection(); selected_button[Mixer::manager().indexCurrentSource()] = true; - RenderSourcePannel(Mixer::manager().currentSource()); + Source *s = Mixer::manager().currentSource(); + if (s) + RenderSourcePannel(s); + else + selected_source_index = -1; } ImGui::PopStyleColor(2); @@ -861,41 +892,43 @@ void Navigator::Render() } - +// Source pannel : *s was checked before void Navigator::RenderSourcePannel(Source *s) { - if (s) + // Next window is a side pannel + ImGui::SetNextWindowPos( ImVec2(width, 0), ImGuiCond_Always ); + ImGui::SetNextWindowSize( ImVec2( 5.f * width, height), ImGuiCond_Always ); + ImGui::SetNextWindowBgAlpha(0.85f); // Transparent background + if (ImGui::Begin("##navigatorSource", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) { - // Next window is a side pannel - ImGui::SetNextWindowPos( ImVec2(width, 0), ImGuiCond_Always ); - ImGui::SetNextWindowSize( ImVec2( 5.f * width, height), ImGuiCond_Always ); - ImGui::SetNextWindowBgAlpha(0.85f); // Transparent background - if (ImGui::Begin("##navigatorNewSource", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) - { - // TITLE - ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE); - ImGui::Text("Source"); - ImGui::PopFont(); - - static char buf5[128]; - sprintf ( buf5, "%s", s->name().c_str() ); - ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); - if (ImGui::InputText("Name", buf5, 64, ImGuiInputTextFlags_CharsNoBlank)){ - Mixer::manager().renameSource(s, buf5); - } - // blending pannel - static ImGuiVisitor v; - s->blendingShader()->accept(v); - // preview - float width = ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN; - ImVec2 imagesize ( width, width / s->frame()->aspectRatio()); - ImGui::Image((void*)(uintptr_t) s->frame()->texture(), imagesize); - // image processing pannel - s->processingShader()->accept(v); + // TITLE + ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE); + ImGui::Text("Source"); + ImGui::PopFont(); + static char buf5[128]; + sprintf ( buf5, "%s", s->name().c_str() ); + ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); + if (ImGui::InputText("Name", buf5, 64, ImGuiInputTextFlags_CharsNoBlank)){ + Mixer::manager().renameSource(s, buf5); + } + // blending pannel + static ImGuiVisitor v; + s->blendingShader()->accept(v); + // preview + float preview_width = ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN; + ImVec2 imagesize ( preview_width, preview_width / s->frame()->aspectRatio()); + ImGui::Image((void*)(uintptr_t) s->frame()->texture(), imagesize); + // image processing pannel + s->processingShader()->accept(v); + // delete button + ImGui::Text(" "); + if ( ImGui::Button("Delete", ImVec2(ImGui::GetContentRegionAvail().x, 0)) ) { + + Mixer::manager().deleteSource(s); } - ImGui::End(); } + ImGui::End(); } void Navigator::RenderNewPannel() @@ -916,9 +949,9 @@ void Navigator::RenderNewPannel() ImGui::Combo("Type", &new_source_type, "Media\0Render\0Clone\0"); if (new_source_type == 0) { - static char filename[128]; + static char filename[128] = "file:///home/bhbn/Videos/iss.mov"; if (ImGuiToolkit::ButtonIcon(2, 5)) { - + // browse file } ImGui::SameLine(0, 10); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); @@ -927,6 +960,11 @@ void Navigator::RenderNewPannel() // Description ImGuiToolkit::HelpMarker("A Media source displays an image or a video file."); + ImGui::Text(" "); + if ( ImGui::Button("Create !", ImVec2(5.f * width - padding_width, 0)) ) { + Mixer::manager().createSourceMedia(filename); + selected_button[NAV_NEW] = false; + } } else if (new_source_type == 1){ @@ -937,11 +975,6 @@ void Navigator::RenderNewPannel() ImGuiToolkit::HelpMarker("A Clone source duplicates the content of another source."); } - if ( ImGui::Button("Create !", ImVec2(5.f * width - padding_width, 0)) ) { - - selected_button[NAV_NEW] = false; - } - } ImGui::End(); } @@ -952,14 +985,17 @@ void Navigator::RenderMainPannel() ImGui::SetNextWindowPos( ImVec2(width, 0), ImGuiCond_Always ); ImGui::SetNextWindowSize( ImVec2( 5.f * width, height), ImGuiCond_Always ); ImGui::SetNextWindowBgAlpha(0.85f); // Transparent background - if (ImGui::Begin("##navigatorNewSource", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) + if (ImGui::Begin("##navigatorMain", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)) { // TITLE ImGuiToolkit::PushFont(ImGuiToolkit::FONT_LARGE); ImGui::Text(APP_NAME); ImGui::PopFont(); - if (ImGui::BeginMenu("Session")) + ImGui::Text("Session"); + ImGui::SameLine(); + ImGui::SetCursorPosX( 5.f * width IMGUI_RIGHT_ALIGN); + if (ImGui::BeginMenu("File")) { UserInterface::manager().showMenuFile(); ImGui::EndMenu(); diff --git a/UserInterfaceManager.h b/UserInterfaceManager.h index 3ae82aa..f64fd17 100644 --- a/UserInterfaceManager.h +++ b/UserInterfaceManager.h @@ -1,6 +1,7 @@ #ifndef __UI_MANAGER_H_ #define __UI_MANAGER_H_ +#include #include #include using namespace std; @@ -15,19 +16,19 @@ class Source; class Navigator { + // geometry left bar + float width; + float height; + float sourcelist_height; + float padding_width; + // top items : group of buttons openning a pannel int selected_source_index; bool selected_button[NAV_COUNT]; void clearSelection(); void toggle(int index); - // bottom items : individual buttons - - float width; - float height; - float sourcelist_height; - float padding_width; - + // side pannels void RenderSourcePannel(Source *s); void RenderNewPannel(); void RenderMainPannel(); @@ -35,6 +36,8 @@ class Navigator public: Navigator(); + void hidePannel(); + void showPannelSource(int index); void Render(); }; @@ -51,6 +54,8 @@ public: void Render(); }; +// TODO: class ShaderEditor + class UserInterface { friend class Navigator; @@ -68,6 +73,16 @@ class UserInterface void handleMouse(); void showMenuFile(); +// typedef enum { +// FILE_DIALOG_INACTIVE = 0, +// FILE_DIALOG_ACTIVE, +// FILE_DIALOG_FINISHED +// } FileDialogStatus; +// FileDialogStatus filestatus_; +// std::string filename_; +// std::thread filethread_; +// void startOpenFileDialog(); + // Private Constructor UserInterface(); UserInterface(UserInterface const& copy); // Not Implemented diff --git a/View.cpp b/View.cpp index 8c4d6c1..75fb97e 100644 --- a/View.cpp +++ b/View.cpp @@ -39,7 +39,7 @@ void View::saveSettings() void View::update(float dt) { // recursive update from root of scene - scene.root()->update( dt ); + scene.update( dt ); } MixingView::MixingView() : View(MIXING) diff --git a/main.cpp b/main.cpp index 60231d8..042df03 100644 --- a/main.cpp +++ b/main.cpp @@ -106,11 +106,11 @@ int main(int, char**) Rendering::manager().PushFrontDrawCallback(drawScene); // init elements to the scene - if ( !Mixer::manager().open("./testsession.vmx") ) - { - Mixer::manager().createSourceMedia("file:///home/bhbn/Videos/iss.mov"); - Mixer::manager().createSourceMedia("file:///home/bhbn/Videos/fish.mp4"); - } +// if ( !Mixer::manager().open("./testsession.vmx") ) +// { +// Mixer::manager().createSourceMedia("file:///home/bhbn/Videos/iss.mov"); +// Mixer::manager().createSourceMedia("file:///home/bhbn/Videos/fish.mp4"); +// } // Animation A; // A.translation_ = glm::vec3(0.f, 0.f, 3.f); @@ -135,7 +135,7 @@ int main(int, char**) Rendering::manager().Draw(); } - Mixer::manager().save("./testsession.vmx"); +// Mixer::manager().save("./testsession.vmx"); UserInterface::manager().Terminate(); Rendering::manager().Terminate();