diff --git a/qglengine/globject.cpp b/qglengine/globject.cpp index 1e4f192..44d5ce4 100644 --- a/qglengine/globject.cpp +++ b/qglengine/globject.cpp @@ -51,6 +51,7 @@ ObjectBase::~ObjectBase() { if (scene_) { scene_->__objectDeleted(this); scene_->setTreeChanged(); + scene_->setTreeStructChanged(); } foreach (ObjectBase * c, children_) { c->parent_ = nullptr; @@ -364,6 +365,8 @@ void ObjectBase::setColor(QColor c, bool with_children) { void ObjectBase::setMesh(Mesh * v) { + if (scene_) + v = scene_->attachMesh(v); mesh_ = v; setSceneTreeChanged(); setObjectsChanged(); diff --git a/qglengine/glscene.cpp b/qglengine/glscene.cpp index 0759a42..2674b26 100644 --- a/qglengine/glscene.cpp +++ b/qglengine/glscene.cpp @@ -171,6 +171,7 @@ void Scene::removeObject(ObjectBase & o, bool inChildren) { void Scene::clearObjects(bool deleteAll) { root_->clearChildren(deleteAll); + cleanUnused(); setTreeStructChanged(); emitSelectionChanged(); } @@ -253,6 +254,20 @@ ObjectBase * Scene::selectedObject() const { } +void Scene::cleanUnused() { + QSet ums; + QMapIterator> it(geometries_used); + while (it.hasNext()) + ums |= it.next().value().keys().toSet(); + for (int i = 0; i < geometries.size(); ++i) { + if (ums.contains(geometries[i])) continue; + td_geometries << geometries[i]; + geometries.removeAt(i); + --i; + } +} + + const Box3D & Scene::boundingBox() const { root_->calculateBoundingBox(); return root_->boundingBox(); @@ -319,25 +334,8 @@ void Scene::attachObject(ObjectBase * o) { if (!o) return; o->setScene(this); if (o->mesh()) { // search suitable mesh in this scene - uint ohash = o->mesh()->hash(); - bool need_new = true; - foreach (Mesh * m, geometries) { - if (m == o->mesh()) { // already exists by ptr - need_new = false; - setObjectMeshChanged(o); - break; - } - if (m->hash() == ohash) { // already exists by hash - need_new = false; - o->setMesh(m); - break; - } - } - if (need_new) { // need to clone mesh and add to scene - Mesh * nmesh = o->mesh()->clone(); - o->setMesh(nmesh); - geometries << nmesh; - } + o->mesh_ = attachMesh(o->mesh()); + setObjectMeshChanged(o); } if (o->material()) { // search suitable material in this scene uint ohash = o->material()->hash(); @@ -361,6 +359,25 @@ void Scene::attachObject(ObjectBase * o) { materials << nmat; } } + setTreeStructChanged(); +} + + +Mesh * Scene::attachMesh(Mesh * mesh) { + if (!mesh) return 0; + uint mhash = mesh->hash(); + foreach (Mesh * m, geometries) { + if (m == mesh) { // already exists by ptr + return m; + } + if (m->hash() == mhash) { // already exists by hash + return m; + } + } + // need to clone mesh and add to scene + Mesh * nmesh = mesh->clone(); + geometries << nmesh; + return nmesh; } @@ -421,14 +438,15 @@ bool Scene::prepare() { if (tree_changed) { tree_changed = false; lights_changed = true; - if (tree_struct_changed) { - tree_struct_changed = false; - QMetaObject::invokeMethod(this, "treeChanged", Qt::QueuedConnection); - } geometries_used[rpSolid ].clear(); geometries_used[rpTransparent].clear(); lights_used.clear(); prepareTree(root_); + if (tree_struct_changed) { + tree_struct_changed = false; + cleanUnused(); + QMetaObject::invokeMethod(this, "treeChanged", Qt::QueuedConnection); + } } mat_changed = false; return true; @@ -440,7 +458,7 @@ void Scene::destroy() { selected_top.clear(); emitSelectionChanged(); root_->clearChildren(true); - qDeleteAll(geometries); + td_geometries << geometries; qDeleteAll(materials); geometries.clear(); materials.clear(); @@ -449,6 +467,15 @@ void Scene::destroy() { } +void Scene::destroyUnused(QOpenGLExtraFunctions * f) { + if (!td_geometries.isEmpty()) qDebug() << "destroyUnused" << td_geometries.size(); + foreach (Mesh * i, td_geometries) + i->destroy(f); + qDeleteAll(td_geometries); + td_geometries.clear(); +} + + QDataStream & operator <<(QDataStream & s, const Scene * p) { ChunkStream cs; //qDebug() << "place" << p->name() << "..."; diff --git a/qglengine/glscene.h b/qglengine/glscene.h index 3df3520..212660b 100644 --- a/qglengine/glscene.h +++ b/qglengine/glscene.h @@ -77,6 +77,7 @@ public: void clearSelection(); ObjectBaseList selectedObjects(bool top_only = false) const; ObjectBase * selectedObject() const; + void cleanUnused(); const Box3D & boundingBox() const; @@ -89,6 +90,7 @@ public: void dump(); void destroy(); + void destroyUnused(QOpenGLExtraFunctions * f); protected: void prepareTree(ObjectBase * o); @@ -99,6 +101,7 @@ protected: QString uniqueName(QString n, const QSet & names); void attachObject(ObjectBase * o); + Mesh * attachMesh(Mesh * mesh); void setTreeChanged(); void setTreeStructChanged(); void setMaterialsChanged() {mat_changed = true;} @@ -112,7 +115,7 @@ protected: bool need_reload_materials, tree_struct_changed; QVector mat_map_changed; - QVector geometries; + QVector geometries, td_geometries; QVector materials; QMap> geometries_used; // [pass][mesh] = ObjectBaseList diff --git a/qglengine/renderer.cpp b/qglengine/renderer.cpp index 89ebad8..759cc63 100644 --- a/qglengine/renderer.cpp +++ b/qglengine/renderer.cpp @@ -255,6 +255,7 @@ void Renderer::renderScene() { Camera * cam = view->camera(); QOpenGLShaderProgram * prog = 0; bool scene_changed = scene.prepare(); + scene.destroyUnused(f); /// reload materials on change if (scene_changed || scene.need_reload_materials) { @@ -332,7 +333,6 @@ void Renderer::renderScene() { if (bindShader(srTonemapPass, &prog)) { prog->setUniformValue("gamma", gamma_); prog->setUniformValue("frame_max", tone_proc.frameMax()); - //fbo_1x1.bindColorTexture(0, 1); fbo_out.bindColorTexture(obrSum, 0); fbo_out.setWriteBuffer(obrTonemap); renderQuad(prog, quad);