Creation and deletion of sources, loading and new session. Cleanup code

and prevent crash on delete.
This commit is contained in:
brunoherbelin
2020-05-09 00:56:37 +02:00
parent 451c793cdd
commit c1b76de6e0
16 changed files with 408 additions and 100 deletions

View File

@@ -210,6 +210,7 @@ set(VMIX_SRCS
Source.cpp
Session.cpp
SessionVisitor.cpp
GarbageVisitor.cpp
SessionCreator.cpp
Mixer.cpp
Settings.cpp

164
GarbageVisitor.cpp Normal file
View File

@@ -0,0 +1,164 @@
#include <algorithm>
#include "Log.h"
#include "Scene.h"
#include "GarbageVisitor.h"
GarbageVisitor::GarbageVisitor(Node *nodetocollect) : Visitor()
{
targets_.push_front(nodetocollect);
current_ = nullptr;
found_ == false;
}
GarbageVisitor::GarbageVisitor(Source *sourcetocollect) : Visitor()
{
targets_.push_front(sourcetocollect->group(View::MIXING));
targets_.push_front(sourcetocollect->group(View::GEOMETRY));
targets_.push_front(sourcetocollect->group(View::RENDERING));
current_ = nullptr;
found_ == false;
}
void GarbageVisitor::visit(Node &n)
{
// found the target
// if (n.id() == target_->id())
// if ( &n == target_ )
if ( std::count(targets_.begin(), targets_.end(), &n) )
{
// end recursive
found_ = true;
// take the node out of the Tree
if (current_)
current_->detatchChild(&n);
}
}
GarbageVisitor::~GarbageVisitor()
{
// actually delete the Node
}
void GarbageVisitor::visit(Group &n)
{
// no need to go further if the node was found (or is this group)
if (found_)
return;
// current group
current_ = &n;
// loop over members of a group
// and stop when found
for (NodeSet::iterator node = n.begin(); !found_ && node != n.end(); node++) {
// visit the child node
(*node)->accept(*this);
// un-stack recursive browsing
current_ = &n;
}
}
void GarbageVisitor::visit(Scene &n)
{
n.root()->accept(*this);
}
void GarbageVisitor::visit(Switch &n)
{
}
void GarbageVisitor::visit(Animation &n)
{
}
void GarbageVisitor::visit(Primitive &n)
{
}
void GarbageVisitor::visit(Surface &n)
{
}
void GarbageVisitor::visit(ImageSurface &n)
{
}
void GarbageVisitor::visit(FrameBufferSurface &n)
{
}
void GarbageVisitor::visit(MediaSurface &n)
{
}
void GarbageVisitor::visit(MediaPlayer &n)
{
}
void GarbageVisitor::visit(Shader &n)
{
}
void GarbageVisitor::visit(ImageShader &n)
{
}
void GarbageVisitor::visit(ImageProcessingShader &n)
{
}
void GarbageVisitor::visit(LineStrip &n)
{
}
void GarbageVisitor::visit(LineSquare &)
{
}
void GarbageVisitor::visit(LineCircle &n)
{
}
void GarbageVisitor::visit(Mesh &n)
{
}
void GarbageVisitor::visit(Frame &n)
{
}
void GarbageVisitor::visit (Source& s)
{
}
void GarbageVisitor::visit (MediaSource& s)
{
}

47
GarbageVisitor.h Normal file
View File

@@ -0,0 +1,47 @@
#ifndef GARBAGEVISITOR_H
#define GARBAGEVISITOR_H
#include <list>
#include "Source.h"
#include "Visitor.h"
class GarbageVisitor : public Visitor {
Group *current_;
std::list<Node *> targets_;
bool found_;
public:
GarbageVisitor(Source *sourcetocollect);
GarbageVisitor(Node *nodetocollect);
~GarbageVisitor();
void visit(Scene& n) override;
void visit(Node& n) override;
void visit(Group& n) override;
void visit(Switch& n) override;
void visit(Animation& n) override;
void visit(Primitive& n) override;
void visit(Surface& n) override;
void visit(ImageSurface& n) override;
void visit(MediaSurface& n) override;
void visit(FrameBufferSurface& n) override;
void visit(LineStrip& n) override;
void visit(LineSquare&) override;
void visit(LineCircle& n) override;
void visit(Mesh& n) override;
void visit(Frame& n) override;
void visit(MediaPlayer& n) override;
void visit(Shader& n) override;
void visit(ImageShader& n) override;
void visit(ImageProcessingShader& n) override;
void visit (Source& s) override;
void visit (MediaSource& s) override;
};
#endif // GARBAGEVISITOR_H

View File

@@ -11,7 +11,7 @@ class ImageProcessingShader : public Shader
public:
ImageProcessingShader();
virtual ~ImageProcessingShader() {}
// virtual ~ImageProcessingShader() {}
void use() override;
void reset() override;

View File

@@ -5,7 +5,7 @@
#include "ImageShader.h"
#include "Resource.h"
ShadingProgram imageShadingProgram("shaders/image.vs", "shaders/image.fs");
static ShadingProgram imageShadingProgram("shaders/image.vs", "shaders/image.fs");
const char* ImageShader::mask_names[10] = { "None", "Vignette", "Halo", "Circle", "Round", "Top", "Botton", "Left", "Right", "Custom" };
std::vector< uint > ImageShader::mask_presets;
@@ -50,7 +50,7 @@ void ImageShader::reset()
{
Shader::reset();
// setup double texturing
// setup double texturing (TODO : do it only once)
program_->use();
program_->setUniform("iChannel0", 0);
program_->setUniform("iChannel1", 1);

View File

@@ -16,7 +16,7 @@ class ImageShader : public Shader
public:
ImageShader();
virtual ~ImageShader() {}
// virtual ~ImageShader() {}
void use() override;
void reset() override;

View File

@@ -333,22 +333,18 @@ Mesh::Mesh(const std::string& ply_path, const std::string& tex_path) : Primitive
}
// default non texture shader (deleted in Primitive)
shader_ = new Shader;
shader_ = new Shader();
}
void Mesh::setTexture(uint textureindex)
{
if (textureindex) {
// replace previous shader with a new Image Shader
if (shader_)
delete shader_;
shader_ = new ImageShader;
replaceShader( new ImageShader() );
// set texture
textureindex_ = textureindex;
}
}
void Mesh::init()

View File

@@ -13,6 +13,7 @@ using namespace tinyxml2;
#include "Settings.h"
#include "SystemToolkit.h"
#include "ImageProcessingShader.h"
#include "GarbageVisitor.h"
#include "SessionVisitor.h"
#include "SessionCreator.h"
@@ -84,8 +85,35 @@ void Mixer::insertSource(Source *s)
}
void Mixer::deleteSource(Source *s)
{
// SessionVisitor visit;
// geometry_.scene.accept(visit);
// visit.doc()->SaveFile("./geombefore.xml");
// SessionVisitor visitm;
// mixing_.scene.accept(visitm);
// visitm.doc()->SaveFile("./mixbefore.xml");
unsetCurrentSource();
// remove source Nodes from views
// GarbageVisitor mixingremover(s->group(View::MIXING));
// mixingremover.visit(mixing_.scene);
// GarbageVisitor geomremover(s->group(View::GEOMETRY));
// geomremover.visit(geometry_.scene);
Log::Info("MIXING");
mixing_.scene.root()->detatchChild( s->group(View::MIXING) );
Log::Info("GEOMETRY");
geometry_.scene.root()->detatchChild( s->group(View::GEOMETRY) );
// delete source
session_->deleteSource(s);
// SessionVisitor visit2;
// geometry_.scene.accept(visit2);
// visit2.doc()->SaveFile("./geomafter.xml");
// SessionVisitor visit2m;
// mixing_.scene.accept(visit2m);
// visit2m.doc()->SaveFile("./mixmafter.xml");
}
void Mixer::renameSource(Source *s, const std::string &newname)
@@ -114,12 +142,19 @@ void Mixer::renameSource(Source *s, const std::string &newname)
void Mixer::setCurrentSource(SourceList::iterator it)
{
unsetCurrentSource();
// nothing to do if already current
if ( current_source_ == it )
return;
// change current
if ( it != session_->end() ) {
current_source_ = it;
current_source_index_ = session_->index(it);
(*current_source_)->setOverlayVisible(true);
}
// default
else
unsetCurrentSource();
}
void Mixer::setCurrentSource(Node *node)
@@ -217,6 +252,7 @@ void Mixer::save(const std::string& filename)
for (iter = session_->begin(); iter != session_->end(); iter++)
{
SessionVisitor sv(&xmlDoc, session);
// source visitor
(*iter)->accept(sv);
}
@@ -267,11 +303,11 @@ bool Mixer::open(const std::string& filename)
newSession( new_session );
// insert nodes of sources into views
SourceList::iterator iter;
for (iter = new_session->begin(); iter != new_session->end(); iter++)
SourceList::iterator source_iter;
for (source_iter = new_session->begin(); source_iter != new_session->end(); source_iter++)
{
mixing_.scene.root()->addChild( (*iter)->group(View::MIXING) );
geometry_.scene.root()->addChild( (*iter)->group(View::GEOMETRY) );
mixing_.scene.root()->addChild( (*source_iter)->group(View::MIXING) );
geometry_.scene.root()->addChild( (*source_iter)->group(View::GEOMETRY) );
}
}
@@ -295,13 +331,25 @@ bool Mixer::open(const std::string& filename)
void Mixer::newSession(Session *newsession)
{
// TODO : remove roots of scenes for views?
// mixing_.scene.clear();
// geometry_.scene.clear();
// delete session : delete all sources
if (session_)
if (session_) {
// remove nodes from views
for (auto source_iter = session_->begin(); source_iter != session_->end(); source_iter++)
{
// GarbageVisitor mixingremover( (*source_iter)->group(View::MIXING) );
// mixingremover.visit(mixing_.scene);
// GarbageVisitor geomremover( (*source_iter)->group(View::GEOMETRY) );
// geomremover.visit(geometry_.scene);
Log::Info("MIXING");
mixing_.scene.root()->detatchChild( (*source_iter)->group(View::MIXING) );
Log::Info("GEOMETRY");
geometry_.scene.root()->detatchChild( (*source_iter)->group(View::GEOMETRY) );
}
// clear session
delete session_;
}
// validate new session
if (newsession)

View File

@@ -40,6 +40,11 @@ Surface::Surface(Shader *s) : Primitive(s), textureindex_(0)
}
Surface::~Surface()
{
}
void Surface::init()
{
// use static unique vertex array object
@@ -58,7 +63,7 @@ void Surface::init()
// 2. remember global vertex array object
unique_vao_ = vao_;
unique_drawCount = drawCount_;
// 3. unique_vao_ will NOT be deleted because ImageSurface::deleteGLBuffers_() is empty
// 3. unique_vao_ will NOT be deleted
}
}
@@ -283,6 +288,12 @@ void LineSquare::accept(Visitor& v)
v.visit(*this);
}
LineSquare::~LineSquare()
{
if (shader_)
delete shader_;
}
LineCircle::LineCircle(glm::vec4 color, uint linewidth) : LineStrip(std::vector<glm::vec3>(), color, linewidth)
{
@@ -330,3 +341,9 @@ void LineCircle::accept(Visitor& v)
v.visit(*this);
}
LineCircle::~LineCircle()
{
if (shader_)
delete shader_;
}

View File

@@ -19,8 +19,6 @@ class FrameBuffer;
*/
class Surface : public Primitive {
void deleteGLBuffers_() override {}
public:
Surface(Shader *s = new ImageShader);
@@ -33,6 +31,7 @@ public:
protected:
uint textureindex_;
virtual ~Surface();
};
@@ -152,13 +151,13 @@ public:
*/
class LineSquare : public LineStrip {
void deleteGLBuffers_() override {}
public:
LineSquare(glm::vec4 color, uint linewidth = 1);
void init() override;
void accept(Visitor& v) override;
virtual ~LineSquare();
};
@@ -167,13 +166,13 @@ public:
*/
class LineCircle : public LineStrip {
void deleteGLBuffers_() override {}
public:
LineCircle(glm::vec4 color, uint linewidth = 1);
void init() override;
void accept(Visitor& v) override;
virtual ~LineCircle();
};

View File

@@ -3,8 +3,11 @@
#include "Shader.h"
#include "Primitives.h"
#include "Visitor.h"
#include "GarbageVisitor.h"
#include "Log.h"
#include "SessionVisitor.h"
#include <glad/glad.h>
#include <glm/gtc/type_ptr.hpp>
@@ -17,7 +20,7 @@
#include <algorithm>
Group *Scene::limbo = new Group;
//Group *Scene::limbo = new Group;
glm::mat4 transform(glm::vec3 translation, glm::vec3 rotation, glm::vec3 scale)
{
@@ -30,7 +33,7 @@ glm::mat4 transform(glm::vec3 translation, glm::vec3 rotation, glm::vec3 scale)
}
// Node
Node::Node() : initialized_(false), visible_(true)
Node::Node() : initialized_(false), visible_(true), refcount_(0)
{
// create unique id
auto duration = std::chrono::system_clock::now().time_since_epoch();
@@ -61,16 +64,19 @@ void Node::accept(Visitor& v)
// Primitive
Primitive::~Primitive()
{
deleteGLBuffers_();
if ( vao_ )
glDeleteVertexArrays ( 1, &vao_);
if (shader_)
delete shader_;
}
void Primitive::init()
{
deleteGLBuffers_();
if ( vao_ )
glDeleteVertexArrays ( 1, &vao_);
// Vertex Array
glGenVertexArrays( 1, &vao_ );
@@ -171,23 +177,21 @@ void Primitive::replaceShader( Shader *newshader )
}
}
void Primitive::deleteGLBuffers_()
{
if ( vao_ )
glDeleteVertexArrays ( 1, &vao_);
}
// Group
Group::~Group()
{
Log::Info("Delete Group %d ", id());
for(NodeSet::iterator it = children_.begin(); it != children_.end(); ) {
// this group is not parent of that node anymore
(*it)->parents_.remove(this);
Log::Info(" Child %d (%d)", (*it)->id(), (*it)->refcount_);
(*it)->refcount_--;
// if this group was the only remaining parent
if ( (*it)->parents_.size() < 1 )
// put the child in limbo
Scene::limbo->addChild( *it );
if ( (*it)->refcount_ < 1 ) {
Log::Info(" Deleting %d (%d)", (*it)->id(), (*it)->refcount_);
// delete
delete (*it);
}
// erase this iterator from the list
it = children_.erase(it);
}
@@ -196,19 +200,33 @@ Group::~Group()
void Group::addChild(Node *child)
{
children_.insert(child);
child->parents_.push_back(this);
child->refcount_++;
// children_.push_back(child); // list test
// child->parents_.push_back(this);
}
void Group::detatchChild(Node *child)
{
NodeSet::iterator it = std::find_if(children_.begin(), children_.end(), hasId(child->id()));
if ( it != children_.end())
{
child->parents_.remove(this);
Log::Info("Group %d (N=%d) detaching %d", id(), numChildren(), child->id());
// find the node with this id, and erase it out of the list of children
// NB: do NOT delete with remove : this takes all nodes with same depth (i.e. equal depth in set)
NodeSet::iterator it = std::find_if(children_.begin(), children_.end(), hasId(child->id()));
if ( it != children_.end()) {
// detatch child from group parent
children_.erase(it);
child->refcount_--;
// // detatch parent from child
// (*it)->parents_.remove(this);
}
// children_.remove(child);
Log::Info("Group %d (N=%d)", id(), numChildren());
}
void Group::update( float dt )
@@ -294,11 +312,11 @@ void Switch::addChild(Node *child)
setActiveChild(child);
}
void Switch::detatchChild(Node *child)
{
Group::detatchChild(child);
active_ = children_.begin();
}
//void Switch::detatchChild(Node *child)
//{
// Group::detatchChild(child);
// active_ = children_.begin();
//}
void Switch::unsetActiveChild ()
@@ -385,24 +403,30 @@ Scene::Scene(): root_(nullptr)
Scene::~Scene()
{
deleteNode(root_);
// deleteNode(root_);
}
void Scene::deleteNode(Node *node)
{
for(auto it = node->parents_.begin(); it != node->parents_.end();){
(*it)->detatchChild(node);
}
limbo->addChild(node);
GarbageVisitor remover(node);
remover.visit(*this);
// // remove this node to the list of chidren of all its parents
// for(auto parent = node->parents_.begin(); parent != node->parents_.end(); parent++){
// (*parent)->children_.erase(node);
// }
// node->parents_.clear();
// limbo->addChild(node);
}
void Scene::update(float dt)
{
root_->update( dt );
// remove nodes from limbo
}
void Scene::accept(Visitor& v)

26
Scene.h
View File

@@ -45,13 +45,11 @@ class Node {
int id_;
bool initialized_;
public:
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; }
@@ -67,14 +65,14 @@ public:
virtual void accept (Visitor& v);
// public members, to manipulate with care
std::list<Group*> parents_;
bool visible_;
uint refcount_;
glm::mat4 transform_;
glm::vec3 scale_, rotation_, translation_;
protected:
virtual ~Node ();
};
@@ -107,6 +105,7 @@ public:
inline Shader *shader () const { return shader_; }
void replaceShader (Shader* newshader);
virtual ~Primitive();
protected:
Shader* shader_;
uint vao_, drawMode_, drawCount_;
@@ -114,8 +113,7 @@ protected:
std::vector<glm::vec4> colors_;
std::vector<glm::vec2> texCoords_;
std::vector<uint> indices_;
virtual void deleteGLBuffers_();
virtual ~Primitive();
};
//
@@ -131,6 +129,8 @@ struct z_comparator
};
typedef std::multiset<Node*, z_comparator> NodeSet;
//typedef std::list<Node*> NodeSet;
struct hasId: public std::unary_function<Node*, bool>
{
inline bool operator()(const Node* e) const
@@ -142,6 +142,7 @@ private:
int _id;
};
/**
* @brief The Group class contains a list of pointers to Nodes.
*
@@ -157,9 +158,11 @@ private:
*/
class Group : public Node {
friend class Scene;
public:
Group() : Node() {}
virtual ~Group();
virtual void update (float dt) override;
virtual void accept (Visitor& v) override;
@@ -172,10 +175,10 @@ public:
NodeSet::iterator end();
uint numChildren() const;
protected:
NodeSet children_;
// destructor
virtual ~Group();
};
/**
@@ -195,7 +198,7 @@ public:
virtual void draw (glm::mat4 modelview, glm::mat4 projection) override;
void addChild (Node *child) override;
void detatchChild (Node *child) override;
// void detatchChild (Node *child) override;
void unsetActiveChild ();
void setActiveChild (Node *child);
@@ -257,8 +260,9 @@ public:
// Node *find(int id);
// void remove(Node *n);
//
static void deleteNode(Node *node);
static Group *limbo;
void deleteNode(Node *node);
// static Group *limbo;
};

View File

@@ -1,7 +1,9 @@
#include <algorithm>
#include "defines.h"
#include "FrameBuffer.h"
#include "Session.h"
#include "GarbageVisitor.h"
Session::Session()
{
@@ -11,10 +13,8 @@ Session::~Session()
{
// 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);
// erase this source from the list
it = deleteSource(*it);
}
}
@@ -22,14 +22,15 @@ Session::~Session()
// update all sources
void Session::update(float dt)
{
// render of all sources
// pre-render of all sources
for( SourceList::iterator it = sources_.begin(); it != sources_.end(); it++){
(*it)->render( );
}
// update the scene tree
render_.update(dt);
// always draw render view
// draw render view in Frame Buffer
render_.draw();
}
@@ -50,19 +51,24 @@ SourceList::iterator Session::deleteSource(Source *s)
SourceList::iterator its = find(s);
// ok, its in the list !
if (its != sources_.end()) {
// iterate backward to previous element in the list (hopefully exist)
its--;
// remove the source and delete it
sources_.remove(s);
// remove Node from the rendering scene
// GarbageVisitor remover(s->group(View::RENDERING));
// remover.visit(render_.scene);
render_.scene.root()->detatchChild( s->group(View::RENDERING) );
// erase the source from the update list & get next element
its = sources_.erase(its);
// delete the source : safe now
delete s;
// return
return its;
// NB: GarbageVisitor ends here, and deletes the Group RENDERING
}
return sources_.end();
// return end of next element
return its;
}

View File

@@ -41,7 +41,7 @@ class Shader
public:
Shader();
virtual ~Shader() {}
// virtual ~Shader() {}
// unique identifyer generated at instanciation
inline int id () const { return id_; }

View File

@@ -50,12 +50,10 @@ Source::~Source()
// 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]);
delete groups_[View::RENDERING];
delete groups_[View::MIXING];
delete groups_[View::GEOMETRY];
groups_.clear();
}
@@ -120,7 +118,9 @@ MediaSource::MediaSource(const std::string &name) : Source(name), uri_("")
MediaSource::~MediaSource()
{
delete mediasurface_;
// TODO delete media surface with visitor
//delete mediasurface_;
delete mediaplayer_;
// TODO verify that all surfaces and node is deleted in Source destructor
}
@@ -162,7 +162,7 @@ void MediaSource::init()
// rendershader_->iChannelResolution[0] = glm::vec3(mediaplayer()->width(), mediaplayer()->height(), 0.f);
// create the surfaces to draw the frame buffer in the views
// TODO Provide the source specific effect shader
// TODO Provide the source custom effect shader
rendersurface_ = new FrameBufferSurface(renderbuffer_, blendingshader_);
groups_[View::RENDERING]->addChild(rendersurface_);
groups_[View::GEOMETRY]->addChild(rendersurface_);

View File

@@ -50,7 +50,8 @@
static TextEditor editor;
static std::thread FileDialogThread_;
//static std::thread *FileDialogThread_;
static bool FileDialogPending_ = false;
static bool FileDialogFinished_ = false;
static std::string FileDialogFilename_ = "";
@@ -60,7 +61,9 @@ void ShowAboutOpengl(bool* p_open);
void ShowAbout(bool* p_open);
static void FileDialogOpen(std::string path)
{
{
FileDialogPending_ = true;
char const * lTheOpenFileName;
char const * lFilterPatterns[2] = { "*.vmx" };
@@ -313,6 +316,7 @@ void UserInterface::NewFrame()
// handle FileDialog
if (FileDialogFinished_) {
FileDialogFinished_ = false;
FileDialogPending_ = false;
Mixer::manager().open(FileDialogFilename_);
}
}
@@ -320,7 +324,6 @@ void UserInterface::NewFrame()
void UserInterface::Render()
{
// ImVec2 geometry(static_cast<float>(Rendering::manager().Width()), static_cast<float>(Rendering::manager().Height()));
// // file modal dialog
// geometry.x *= 0.4f;
// geometry.y *= 0.4f;
@@ -332,8 +335,7 @@ void UserInterface::Render()
// }
// FileDialog::Instance()->CloseDialog(currentFileDialog.c_str());
// }
FileDialog::RenderCurrent();
// FileDialog::RenderCurrent();
// warning modal dialog
Log::Render();
@@ -378,16 +380,16 @@ void UserInterface::Terminate()
void UserInterface::showMenuFile()
{
// TODO : New
if (ImGui::MenuItem( ICON_FA_FILE " New", "Ctrl+W")) {
if (ImGui::MenuItem( ICON_FA_FILE " New", "Ctrl+W", false, !FileDialogPending_)) {
Mixer::manager().newSession();
navigator.hidePannel();
}
if (ImGui::MenuItem( ICON_FA_FILE_UPLOAD " Open", "Ctrl+O")) {
if (ImGui::MenuItem( ICON_FA_FILE_UPLOAD " Open", "Ctrl+O", false, !FileDialogPending_)) {
// launch file dialog to open a session file
FileDialogThread_ = std::thread(FileDialogOpen, "./");
std::thread (FileDialogOpen, "./").detach();
navigator.hidePannel();
}
if (ImGui::MenuItem( ICON_FA_FILE_DOWNLOAD " Save", "Ctrl+S")) {
if (ImGui::MenuItem( ICON_FA_FILE_DOWNLOAD " Save", "Ctrl+S", false, !FileDialogPending_)) {
// UserInterface::manager().OpenFileMedia();
}
// TODO : Save As...