mirror of https://github.com/CGAL/cgal
1980 lines
59 KiB
C++
1980 lines
59 KiB
C++
#include "config.h"
|
|
#include "Scene.h"
|
|
|
|
#include <CGAL/Three/Scene_item.h>
|
|
#include <CGAL/Three/Scene_print_item_interface.h>
|
|
#include <CGAL/Three/Scene_transparent_interface.h>
|
|
#include <CGAL/Three/Scene_zoomable_item_interface.h>
|
|
#include <CGAL/Three/Three.h>
|
|
|
|
#include <CGAL/Three/Scene_item.h>
|
|
#include <CGAL/Three/Scene_print_item_interface.h>
|
|
#include <CGAL/Three/Viewer_interface.h>
|
|
|
|
|
|
#include <QObject>
|
|
#include <QMetaObject>
|
|
#include <QString>
|
|
#include <QGLWidget>
|
|
#include <QEvent>
|
|
#include <QMouseEvent>
|
|
#include <QPainter>
|
|
#include <QColorDialog>
|
|
#include <QApplication>
|
|
#include <QPointer>
|
|
#include <QList>
|
|
#include <QAbstractProxyModel>
|
|
#include <QMimeData>
|
|
#include <QOpenGLFramebufferObject>
|
|
|
|
|
|
Scene::Scene(QObject* parent)
|
|
: QStandardItemModel(parent),
|
|
selected_item(-1),
|
|
item_A(-1),
|
|
item_B(-1)
|
|
{
|
|
|
|
connect(this, SIGNAL(selectionRay(double, double, double,
|
|
double, double, double)),
|
|
this, SLOT(setSelectionRay(double, double, double,
|
|
double, double, double)));
|
|
connect(this, SIGNAL(indexErased(Scene_interface::Item_id)),
|
|
this, SLOT(adjustIds(Scene_interface::Item_id)));
|
|
picked = false;
|
|
gl_init = false;
|
|
dont_emit_changes = false;
|
|
|
|
}
|
|
Scene::Item_id
|
|
Scene::addItem(CGAL::Three::Scene_item* item)
|
|
{
|
|
Bbox bbox_before = bbox();
|
|
m_entries.push_back(item);
|
|
Item_id id = m_entries.size() - 1;
|
|
connect(item, SIGNAL(itemChanged()),
|
|
this, SLOT(itemChanged()));
|
|
connect(item, SIGNAL(itemVisibilityChanged()),
|
|
this, SLOT(itemVisibilityChanged()));
|
|
connect(item, SIGNAL(redraw()),
|
|
this, SLOT(callDraw()));
|
|
if(item->isFinite()
|
|
&& !item->isEmpty()
|
|
&& bbox_before + item->bbox() != bbox_before
|
|
)
|
|
{
|
|
Q_EMIT updated_bbox(true);
|
|
}
|
|
QList<QStandardItem*> list;
|
|
for(int i=0; i<5; i++)
|
|
{
|
|
list<<new QStandardItem();
|
|
list.at(i)->setEditable(false);
|
|
}
|
|
invisibleRootItem()->appendRow(list);
|
|
for(int i=0; i<5; i++){
|
|
index_map[list.at(i)->index()] = m_entries.size() -1;
|
|
}
|
|
Q_EMIT updated();
|
|
children.push_back(id);
|
|
Q_EMIT newItem(id);
|
|
CGAL::Three::Scene_group_item* group =
|
|
qobject_cast<CGAL::Three::Scene_group_item*>(item);
|
|
if(group)
|
|
addGroup(group);
|
|
//init the item for the mainViewer to avoid using unexisting
|
|
//VAOs if the mainViewer is not the first to be drawn.
|
|
QOpenGLFramebufferObject* fbo = CGAL::Three::Three::mainViewer()->depthPeelingFbo();
|
|
CGAL::Three::Three::mainViewer()->setDepthPeelingFbo(nullptr);//to prevent crashing as the fbo is not initialized in this call.
|
|
item->draw(CGAL::Three::Three::mainViewer());
|
|
item->drawEdges(CGAL::Three::Three::mainViewer());
|
|
item->drawPoints(CGAL::Three::Three::mainViewer());
|
|
CGAL::Three::Three::mainViewer()->setDepthPeelingFbo(fbo);
|
|
if(group)
|
|
m_groups.append(id);
|
|
return id;
|
|
}
|
|
|
|
CGAL::Three::Scene_item*
|
|
Scene::replaceItem(Scene::Item_id index, CGAL::Three::Scene_item* item, bool emit_item_about_to_be_destroyed)
|
|
{
|
|
if(index < 0 || index >= m_entries.size())
|
|
return nullptr;
|
|
|
|
connect(item, SIGNAL(itemChanged()),
|
|
this, SLOT(itemChanged()));
|
|
connect(item, SIGNAL(itemVisibilityChanged()),
|
|
this, SLOT(itemVisibilityChanged()));
|
|
connect(item, SIGNAL(redraw()),
|
|
this, SLOT(callDraw()));
|
|
CGAL::Three::Scene_group_item* group =
|
|
qobject_cast<CGAL::Three::Scene_group_item*>(m_entries[index]);
|
|
QList<Scene_item*> group_children;
|
|
if(group)
|
|
{
|
|
m_groups.removeAll(index);
|
|
Q_FOREACH(Item_id id, group->getChildren())
|
|
{
|
|
CGAL::Three::Scene_item* child = group->getChild(id);
|
|
group->unlockChild(child);
|
|
group_children << child;
|
|
}
|
|
}
|
|
CGAL::Three::Scene_group_item* parent = m_entries[index]->parentGroup();
|
|
bool is_locked = false;
|
|
if(parent)
|
|
{
|
|
is_locked = parent->isChildLocked(m_entries[index]);
|
|
parent->unlockChild(m_entries[index]);
|
|
parent->removeChild(m_entries[index]);
|
|
}
|
|
std::swap(m_entries[index], item);
|
|
if(parent)
|
|
{
|
|
changeGroup(m_entries[index], parent);
|
|
if(is_locked)
|
|
parent->lockChild(m_entries[index]);
|
|
}
|
|
|
|
Q_EMIT newItem(index);
|
|
if ( item->isFinite() && !item->isEmpty() &&
|
|
m_entries[index]->isFinite() && !m_entries[index]->isEmpty() &&
|
|
item->bbox()!=m_entries[index]->bbox() )
|
|
{
|
|
Q_EMIT updated_bbox(true);
|
|
}
|
|
|
|
if(emit_item_about_to_be_destroyed) {
|
|
Q_EMIT itemAboutToBeDestroyed(item);
|
|
item->aboutToBeDestroyed();
|
|
}
|
|
|
|
Q_EMIT updated();
|
|
group =
|
|
qobject_cast<CGAL::Three::Scene_group_item*>(m_entries[index]);
|
|
if(group)
|
|
{
|
|
addGroup(group);
|
|
m_groups.append(index);
|
|
}
|
|
itemChanged(index);
|
|
Q_EMIT restoreCollapsedState();
|
|
redraw_model();
|
|
Q_EMIT selectionChanged(index);
|
|
Q_FOREACH(Scene_item* child, group_children)
|
|
{
|
|
erase(item_id(child));
|
|
}
|
|
return item;
|
|
}
|
|
|
|
Scene::Item_id
|
|
Scene::erase(Scene::Item_id index)
|
|
{
|
|
if(index <0 || index >= numberOfEntries())
|
|
return -1;
|
|
|
|
CGAL::Three::Scene_item* item = m_entries[index];
|
|
if(qobject_cast<Scene_group_item*>(item))
|
|
{
|
|
setSelectedItemsList(QList<Scene_interface::Item_id>()<<item_id(item));
|
|
return erase(selectionIndices());
|
|
}
|
|
m_groups.removeAll(index);
|
|
if(item->parentGroup()
|
|
&& item->parentGroup()->isChildLocked(item))
|
|
return -1;
|
|
//clears the Scene_view
|
|
clear();
|
|
index_map.clear();
|
|
if(item->parentGroup())
|
|
item->parentGroup()->removeChild(item);
|
|
|
|
//removes the item from all groups that contain it
|
|
Item_id removed_item = item_id(item);
|
|
children.removeAll(removed_item);
|
|
indexErased(removed_item);
|
|
m_entries.removeAll(item);
|
|
Q_EMIT itemAboutToBeDestroyed(item);
|
|
item->aboutToBeDestroyed();
|
|
item->deleteLater();
|
|
selected_item = -1;
|
|
//re-creates the Scene_view
|
|
Q_FOREACH(Item_id id, children)
|
|
{
|
|
organize_items(this->item(id), invisibleRootItem(), 0);
|
|
}
|
|
QStandardItemModel::beginResetModel();
|
|
Q_EMIT updated();
|
|
QStandardItemModel::endResetModel();
|
|
Q_EMIT restoreCollapsedState();
|
|
if(--index >= 0)
|
|
return index;
|
|
if(!m_entries.isEmpty())
|
|
return 0;
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
Scene::erase(QList<int> indices)
|
|
{
|
|
if(indices.empty())
|
|
return -1;
|
|
QList<CGAL::Three::Scene_item*> to_be_removed;
|
|
int max_index = -1;
|
|
Q_FOREACH(int index, indices) {
|
|
if(index < 0 || index >= m_entries.size())
|
|
continue;
|
|
|
|
max_index = (std::max)(max_index, index);
|
|
CGAL::Three::Scene_item* item = m_entries[index];
|
|
if(item->parentGroup()
|
|
&& item->parentGroup()->isChildLocked(item))
|
|
if(!indices.contains(item_id(item->parentGroup())))
|
|
continue;
|
|
Scene_group_item* group = qobject_cast<Scene_group_item*>(item);
|
|
if(group)
|
|
{
|
|
Q_FOREACH(Item_id id, group->getChildren())
|
|
{
|
|
CGAL::Three::Scene_item* child = group->getChild(id);
|
|
if(!to_be_removed.contains(child))
|
|
to_be_removed.push_back(child);
|
|
}
|
|
}
|
|
if(!to_be_removed.contains(item))
|
|
to_be_removed.push_back(item);
|
|
}
|
|
|
|
Q_FOREACH(Scene_item* item, to_be_removed) {
|
|
Item_id removed_item = item_id(item);
|
|
if(removed_item == -1) //case of the selection_item, for example.
|
|
continue;
|
|
if(item->parentGroup())
|
|
item->parentGroup()->removeChild(item);
|
|
children.removeAll(removed_item);
|
|
indexErased(removed_item);
|
|
m_groups.removeAll(removed_item);
|
|
m_entries.removeAll(item);
|
|
|
|
Q_EMIT itemAboutToBeDestroyed(item);
|
|
item->aboutToBeDestroyed();
|
|
item->deleteLater();
|
|
}
|
|
clear();
|
|
index_map.clear();
|
|
selected_item = -1;
|
|
Q_FOREACH(Item_id id, children)
|
|
{
|
|
organize_items(item(id), invisibleRootItem(), 0);
|
|
}
|
|
QStandardItemModel::beginResetModel();
|
|
Q_EMIT updated();
|
|
QStandardItemModel::endResetModel();
|
|
Q_EMIT restoreCollapsedState();
|
|
|
|
int index = max_index + 1 - indices.size();
|
|
if(index >= m_entries.size()) {
|
|
index = m_entries.size() - 1;
|
|
}
|
|
if(index >= 0)
|
|
return index;
|
|
if(!m_entries.isEmpty())
|
|
return 0;
|
|
return -1;
|
|
|
|
}
|
|
|
|
void Scene::remove_item_from_groups(Scene_item* item)
|
|
{
|
|
CGAL::Three::Scene_group_item* group = item->parentGroup();
|
|
if(group)
|
|
{
|
|
group->removeChild(item);
|
|
children.push_back(item_id(item));
|
|
}
|
|
}
|
|
Scene::~Scene()
|
|
{
|
|
Q_FOREACH(CGAL::QGLViewer* viewer, CGAL::QGLViewer::QGLViewerPool())
|
|
{
|
|
removeViewer(static_cast<CGAL::Three::Viewer_interface*>(viewer));
|
|
viewer->setProperty("is_destroyed", true);
|
|
}
|
|
Q_FOREACH(QOpenGLVertexArrayObject* vao, vaos.values())
|
|
{
|
|
vao->destroy();
|
|
delete vao;
|
|
}
|
|
Q_FOREACH(CGAL::Three::Scene_item* item_ptr, m_entries)
|
|
{
|
|
item_ptr->deleteLater();
|
|
}
|
|
m_entries.clear();
|
|
}
|
|
|
|
CGAL::Three::Scene_item*
|
|
Scene::item(Item_id index) const
|
|
{
|
|
return m_entries.value(index); // QList::value checks bounds
|
|
}
|
|
|
|
Scene::Item_id
|
|
Scene::item_id(CGAL::Three::Scene_item* scene_item) const
|
|
{
|
|
return m_entries.indexOf(scene_item);
|
|
}
|
|
|
|
int
|
|
Scene::numberOfEntries() const
|
|
{
|
|
return m_entries.size();
|
|
}
|
|
|
|
// Duplicate a scene item.
|
|
// Return the ID of the new item (-1 on error).
|
|
Scene::Item_id
|
|
Scene::duplicate(Item_id index)
|
|
{
|
|
if(index < 0 || index >= m_entries.size())
|
|
return -1;
|
|
|
|
const CGAL::Three::Scene_item* item = m_entries[index];
|
|
CGAL::Three::Scene_item* new_item = item->clone();
|
|
if(new_item) {
|
|
new_item->setName(tr("%1 (copy)").arg(item->name()));
|
|
new_item->setColor(item->color());
|
|
new_item->setVisible(item->visible());
|
|
addItem(new_item);
|
|
return m_entries.size() - 1;
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
void Scene::initializeGL(CGAL::Three::Viewer_interface* viewer)
|
|
{
|
|
|
|
//Vertex source code
|
|
const char vertex_source[] =
|
|
{
|
|
"#version 150 \n"
|
|
"in vec4 vertex; \n"
|
|
"in vec2 v_texCoord; \n"
|
|
"uniform mat4 projection_matrix; \n"
|
|
"out vec2 f_texCoord; \n"
|
|
"void main(void) \n"
|
|
"{ \n"
|
|
" f_texCoord = v_texCoord; \n"
|
|
" gl_Position = projection_matrix * vertex; \n"
|
|
"} \n"
|
|
|
|
};
|
|
|
|
const char vertex_source_comp[] =
|
|
{
|
|
"attribute highp vec4 vertex; \n"
|
|
"attribute highp vec2 v_texCoord; \n"
|
|
"uniform highp mat4 projection_matrix; \n"
|
|
"varying highp vec2 f_texCoord; \n"
|
|
"void main(void) \n"
|
|
"{ \n"
|
|
" f_texCoord = v_texCoord; \n"
|
|
" gl_Position = projection_matrix * vertex; \n"
|
|
"} \n"
|
|
|
|
};
|
|
//Fragment source code
|
|
const char fragment_source[] =
|
|
{
|
|
"#version 150 \n"
|
|
"in vec2 f_texCoord; \n"
|
|
"out vec4 out_color ; \n"
|
|
"uniform sampler2D s_texture; \n"
|
|
"void main(void) \n"
|
|
"{ \n"
|
|
" out_color = texture(s_texture, f_texCoord); \n"
|
|
"} \n"
|
|
};
|
|
const char fragment_source_comp[] =
|
|
{
|
|
"varying highp vec2 f_texCoord; \n"
|
|
"uniform sampler2D texture; \n"
|
|
"void main(void) \n"
|
|
"{ \n"
|
|
" gl_FragColor = texture2D(texture, f_texCoord); \n"
|
|
"} \n"
|
|
};
|
|
|
|
|
|
QOpenGLShader vertex_shader(QOpenGLShader::Vertex);
|
|
QOpenGLShader fragment_shader(QOpenGLShader::Fragment);
|
|
if(viewer->isOpenGL_4_3())
|
|
{
|
|
if(!vertex_shader.compileSourceCode(vertex_source))
|
|
{
|
|
std::cerr<<"Compiling vertex source FAILED"<<std::endl;
|
|
}
|
|
|
|
if(!fragment_shader.compileSourceCode(fragment_source))
|
|
{
|
|
std::cerr<<"Compiling fragmentsource FAILED"<<std::endl;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(!vertex_shader.compileSourceCode(vertex_source_comp))
|
|
{
|
|
std::cerr<<"Compiling vertex source FAILED"<<std::endl;
|
|
}
|
|
|
|
if(!fragment_shader.compileSourceCode(fragment_source_comp))
|
|
{
|
|
std::cerr<<"Compiling fragmentsource FAILED"<<std::endl;
|
|
}
|
|
}
|
|
|
|
if(!program.addShader(&vertex_shader))
|
|
{
|
|
std::cerr<<"adding vertex shader FAILED"<<std::endl;
|
|
}
|
|
if(!program.addShader(&fragment_shader))
|
|
{
|
|
std::cerr<<"adding fragment shader FAILED"<<std::endl;
|
|
}
|
|
if(!program.link())
|
|
{
|
|
//std::cerr<<"linking Program FAILED"<<std::endl;
|
|
qDebug() << program.log();
|
|
}
|
|
points[0] = -1.0f; points[1] = -1.0f; points[2] = 0.0f;
|
|
points[3] = 1.0f; points[4] = 1.0f; points[5] = 0.0f;
|
|
points[6] = 1.0f; points[7] = -1.0f; points[8] = 0.0f;
|
|
points[9] = -1.0f; points[10] = -1.0f; points[11] = 0.0f;
|
|
points[12] = -1.0f; points[13] = 1.0f; points[14] = 0.0f;
|
|
points[15] = 1.0f; points[16] = 1.0f; points[17] = 0.0f;
|
|
|
|
uvs[0] = 0.0f; uvs[1] = 0.0f;
|
|
uvs[2] = 1.0f; uvs[3] = 1.0f;
|
|
uvs[4] = 1.0f; uvs[5] = 0.0f;
|
|
uvs[6] = 0.0f; uvs[7] = 0.0f;
|
|
uvs[8] = 0.0f; uvs[9] = 1.0f;
|
|
uvs[10] = 1.0f; uvs[11] = 1.0f;
|
|
|
|
vbo[0].create();
|
|
vbo[1].create();
|
|
|
|
viewer->makeCurrent();
|
|
vaos[viewer] = new QOpenGLVertexArrayObject();
|
|
vaos[viewer]->create();
|
|
program.bind();
|
|
vaos[viewer]->bind();
|
|
vbo[0].bind();
|
|
vbo[0].allocate(points, 18 * sizeof(float));
|
|
program.enableAttributeArray("vertex");
|
|
program.setAttributeArray("vertex", GL_FLOAT, nullptr, 3);
|
|
vbo[0].release();
|
|
|
|
vbo[1].bind();
|
|
vbo[1].allocate(uvs, 12 * sizeof(float));
|
|
program.enableAttributeArray("v_texCoord");
|
|
program.setAttributeArray("v_texCoord", GL_FLOAT, nullptr, 2);
|
|
vbo[1].release();
|
|
vaos[viewer]->release();
|
|
program.release();
|
|
gl_init = true;
|
|
}
|
|
|
|
void Scene::s_itemAboutToBeDestroyed(CGAL::Three::Scene_item *rmv_itm)
|
|
{
|
|
Q_FOREACH(CGAL::Three::Scene_item* item, m_entries)
|
|
{
|
|
if(item == rmv_itm)
|
|
item->itemAboutToBeDestroyed(item);
|
|
}
|
|
}
|
|
bool
|
|
Scene::keyPressEvent(QKeyEvent* e){
|
|
bool res=false;
|
|
for (QList<int>::iterator it=selected_items_list.begin(),endit=selected_items_list.end();
|
|
it!=endit;++it)
|
|
{
|
|
CGAL::Three::Scene_item* item=m_entries[*it];
|
|
res |= item->keyPressEvent(e);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
void
|
|
Scene::draw(CGAL::Three::Viewer_interface* viewer)
|
|
{
|
|
draw_aux(false, viewer);
|
|
}
|
|
void
|
|
Scene::drawWithNames(CGAL::Three::Viewer_interface* viewer)
|
|
{
|
|
draw_aux(true, viewer);
|
|
}
|
|
|
|
bool item_should_be_skipped_in_draw(Scene_item* item) {
|
|
if(!item->visible()) return true;
|
|
if(item->has_group == 0) return false;
|
|
Scene_group_item* group = item->parentGroup();
|
|
while(group != nullptr) {
|
|
if(!group->visible()) return false;
|
|
group = group->parentGroup();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void Scene::renderScene(const QList<Scene_interface::Item_id> &items,
|
|
Viewer_interface *viewer,
|
|
QMap<float, int>& picked_item_IDs,
|
|
bool with_names,
|
|
int pass,
|
|
bool writing_depth,
|
|
QOpenGLFramebufferObject *fbo)
|
|
{
|
|
viewer->setCurrentPass(pass);
|
|
viewer->setDepthWriting(writing_depth);
|
|
viewer->setDepthPeelingFbo(fbo);
|
|
Q_FOREACH(Scene_interface::Item_id index, items)
|
|
{
|
|
CGAL::Three::Scene_item& item = *m_entries[index];
|
|
CGAL::Three::Scene_group_item* group =
|
|
qobject_cast<CGAL::Three::Scene_group_item*>(&item);
|
|
if(index == selected_item || selected_items_list.contains(index))
|
|
{
|
|
item.selection_changed(true);
|
|
}
|
|
else
|
|
{
|
|
item.selection_changed(false);
|
|
}
|
|
if(group ||item.visible())
|
|
{
|
|
if( group || item.renderingMode() == Flat || item.renderingMode() == FlatPlusEdges || item.renderingMode() == Gouraud || item.renderingMode() == GouraudPlusEdges )
|
|
{
|
|
if(with_names) {
|
|
viewer->glClearDepthf(1.0);
|
|
viewer->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
}
|
|
item.draw(viewer);
|
|
if(with_names) {
|
|
|
|
// read depth buffer at pick location;
|
|
float depth = 1.0;
|
|
viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
|
|
if (depth != 1.0)
|
|
{
|
|
//add object to list of picked objects;
|
|
picked_item_IDs[depth] = index;
|
|
}
|
|
}
|
|
}
|
|
if(group)
|
|
group->renderChildren(viewer, picked_item_IDs, picked_pixel, with_names);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Scene::renderWireScene(const QList<Scene_interface::Item_id> &items,
|
|
Viewer_interface *viewer,
|
|
QMap<float, int>& picked_item_IDs,
|
|
bool with_names)
|
|
{
|
|
Q_FOREACH(Scene_interface::Item_id index, items)
|
|
{
|
|
CGAL::Three::Scene_item& item = *m_entries[index];
|
|
CGAL::Three::Scene_group_item* group =
|
|
qobject_cast<CGAL::Three::Scene_group_item*>(&item);
|
|
if(index == selected_item || selected_items_list.contains(index))
|
|
{
|
|
item.selection_changed(true);
|
|
}
|
|
else
|
|
{
|
|
item.selection_changed(false);
|
|
}
|
|
|
|
if(group ||item.visible())
|
|
{
|
|
if( group || (!with_names && item.renderingMode() == FlatPlusEdges )
|
|
|| item.renderingMode() == Wireframe
|
|
|| item.renderingMode() == PointsPlusNormals
|
|
|| item.renderingMode() == GouraudPlusEdges)
|
|
{
|
|
if(with_names) {
|
|
viewer->glClearDepthf(1.0);
|
|
viewer->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
}
|
|
viewer->setGlPointSize(2.f);
|
|
item.drawEdges(viewer);
|
|
}
|
|
else{
|
|
if( item.renderingMode() == PointsPlusNormals ){
|
|
viewer->setGlPointSize(2.f);
|
|
if(index == selected_item || selected_items_list.contains(index))
|
|
{
|
|
|
|
item.selection_changed(true);
|
|
}
|
|
else
|
|
{
|
|
|
|
item.selection_changed(false);
|
|
}
|
|
item.drawEdges(viewer);
|
|
}
|
|
}
|
|
|
|
if((item.renderingMode() == Wireframe || item.renderingMode() == PointsPlusNormals )
|
|
&& with_names)
|
|
{
|
|
|
|
// read depth buffer at pick location;
|
|
float depth = 1.0;
|
|
viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
|
|
if (depth != 1.0)
|
|
{
|
|
//add object to list of picked objects;
|
|
picked_item_IDs[depth] = index;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Scene::renderPointScene(const QList<Scene_interface::Item_id> &items,
|
|
Viewer_interface *viewer,
|
|
QMap<float, int>& picked_item_IDs,
|
|
bool with_names)
|
|
{
|
|
Q_FOREACH(Scene_interface::Item_id index, items)
|
|
{
|
|
CGAL::Three::Scene_item& item = *m_entries[index];
|
|
CGAL::Three::Scene_group_item* group =
|
|
qobject_cast<CGAL::Three::Scene_group_item*>(&item);
|
|
if(group ||item.visible())
|
|
{
|
|
if(item.renderingMode() == Points && with_names) {
|
|
viewer->glClearDepthf(1.0);
|
|
viewer->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
}
|
|
|
|
if(group || item.renderingMode() == Points ||
|
|
(item.renderingMode() == PointsPlusNormals) ||
|
|
(item.renderingMode() == ShadedPoints))
|
|
{
|
|
if(with_names) {
|
|
viewer->glClearDepthf(1.0);
|
|
viewer->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
}
|
|
viewer->setGlPointSize(3.0f);
|
|
item.drawPoints(viewer);
|
|
}
|
|
if(item.renderingMode() == Points && with_names) {
|
|
// read depth buffer at pick location;
|
|
float depth = 1.0;
|
|
viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
|
|
if (depth != 1.0)
|
|
{
|
|
//add object to list of picked objects;
|
|
picked_item_IDs[depth] = index;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool Scene::has_alpha()
|
|
{
|
|
Q_FOREACH(Scene_item* item, m_entries)
|
|
if(item->alpha() != 1.0f)
|
|
return true;
|
|
return false;
|
|
}
|
|
void
|
|
Scene::draw_aux(bool with_names, CGAL::Three::Viewer_interface* viewer)
|
|
{
|
|
QMap<float, int> picked_item_IDs;
|
|
if(with_names)
|
|
viewer->glEnable(GL_DEPTH_TEST);
|
|
if(!gl_init)
|
|
initializeGL(viewer);
|
|
//treat opaque items first to ensure that when two items are the same, but only one is opaque,
|
|
//the item stays opaque
|
|
QList<Item_id> opaque_items;
|
|
QList<Item_id> transparent_items;
|
|
Q_FOREACH(Item_id id, children)
|
|
{
|
|
Scene_item* item = m_entries[id];
|
|
Scene_group_item* group = qobject_cast<Scene_group_item*>(item);
|
|
bool is_transparent=false;
|
|
if(item->alpha() != 1.0f)
|
|
is_transparent = true;
|
|
else if(group)
|
|
{
|
|
for(const auto& child : group->getChildren())
|
|
{
|
|
if(group->getChild(child)->alpha() < 1.0f)
|
|
{
|
|
is_transparent = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(!is_transparent)
|
|
opaque_items.push_back(id);
|
|
else
|
|
transparent_items.push_back(id);
|
|
}
|
|
renderScene(children, viewer, picked_item_IDs, with_names, -1, false, nullptr);
|
|
if(with_names)
|
|
{
|
|
//here we get the selected point, before erasing the depth buffer. We store it
|
|
//in a dynamic property as a QList<double>. If there is some alpha, the
|
|
//depth buffer is altered, and the picking will return true even when it is
|
|
// performed in the background, when it should return false. To avoid that,
|
|
// we distinguish the case were there is no alpha, to let the viewer
|
|
//perform it, and the case where the pixel is not found. In the first case,
|
|
//we erase the property, in the latter we return an empty list.
|
|
//According ot that, in the viewer, either we perform the picking, either we do nothing.
|
|
if(has_alpha()) {
|
|
bool found = false;
|
|
CGAL::qglviewer::Vec point = viewer->camera()->pointUnderPixel(picked_pixel, found) - viewer->offset();
|
|
if(found){
|
|
QList<QVariant> picked_point;
|
|
picked_point <<point.x
|
|
<<point.y
|
|
<<point.z;
|
|
viewer->setProperty("picked_point", picked_point);
|
|
}
|
|
else{
|
|
viewer->setProperty("picked_point", QList<QVariant>());
|
|
}
|
|
}
|
|
else {
|
|
viewer->setProperty("picked_point", {});
|
|
}
|
|
}
|
|
if(!with_names && has_alpha())
|
|
{
|
|
std::vector<QOpenGLFramebufferObject*> fbos;
|
|
std::vector<QOpenGLFramebufferObject*> depth_test;
|
|
QColor background = viewer->backgroundColor();
|
|
fbos.resize(static_cast<int>(viewer->total_pass()));
|
|
depth_test.resize(static_cast<int>(viewer->total_pass())-1);
|
|
|
|
//first pass
|
|
fbos[0] = new QOpenGLFramebufferObject(viewer->width(), viewer->height(),QOpenGLFramebufferObject::Depth, GL_TEXTURE_2D, GL_RGBA32F);
|
|
fbos[0]->bind();
|
|
viewer->glDisable(GL_BLEND);
|
|
viewer->glEnable(GL_DEPTH_TEST);
|
|
viewer->glDepthFunc(GL_LESS);
|
|
viewer->glClearColor(0.0f,
|
|
0.0f,
|
|
0.0f,
|
|
0.0f);
|
|
viewer->glClearDepthf(1);
|
|
viewer->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
renderScene(opaque_items, viewer, picked_item_IDs, false, 0,false, nullptr);
|
|
renderScene(transparent_items, viewer, picked_item_IDs, false, 0,false, nullptr);
|
|
fbos[0]->release();
|
|
depth_test[0] = new QOpenGLFramebufferObject(viewer->width(), viewer->height(),QOpenGLFramebufferObject::Depth, GL_TEXTURE_2D, GL_RGBA32F);
|
|
depth_test[0]->bind();
|
|
viewer->glDisable(GL_BLEND);
|
|
viewer->glEnable(GL_DEPTH_TEST);
|
|
viewer->glDepthFunc(GL_LESS);
|
|
viewer->glClearColor(0.0f,
|
|
0.0f,
|
|
0.0f,
|
|
0.0f);
|
|
viewer->glClearDepthf(1);
|
|
viewer->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
renderScene(opaque_items, viewer, picked_item_IDs, false, 0,true, nullptr);
|
|
renderScene(transparent_items, viewer, picked_item_IDs, false, 0,true, nullptr);
|
|
depth_test[0]->release();
|
|
|
|
//other passes
|
|
for(int i=1; i<viewer->total_pass()-1; ++i)
|
|
{
|
|
fbos[i] = new QOpenGLFramebufferObject(viewer->width(), viewer->height(),QOpenGLFramebufferObject::Depth, GL_TEXTURE_2D, GL_RGBA32F);
|
|
fbos[i]->bind();
|
|
viewer->glDisable(GL_BLEND);
|
|
viewer->glEnable(GL_DEPTH_TEST);
|
|
viewer->glDepthFunc(GL_LESS);
|
|
viewer->glClearColor(0.0f,
|
|
0.0f,
|
|
0.0f,
|
|
0.0f);
|
|
viewer->glClearDepthf(1);
|
|
viewer->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
renderWireScene(children, viewer, picked_item_IDs, false);
|
|
renderPointScene(children, viewer, picked_item_IDs, false);
|
|
renderScene(opaque_items , viewer, picked_item_IDs, false, i, false, depth_test[i-1]);
|
|
renderScene(transparent_items, viewer, picked_item_IDs, false, i, false, depth_test[i-1]);
|
|
fbos[i]->release();
|
|
|
|
depth_test[i] = new QOpenGLFramebufferObject(viewer->width(), viewer->height(),QOpenGLFramebufferObject::Depth, GL_TEXTURE_2D, GL_RGBA32F);
|
|
depth_test[i]->bind();
|
|
viewer->glDisable(GL_BLEND);
|
|
viewer->glEnable(GL_DEPTH_TEST);
|
|
viewer->glDepthFunc(GL_LESS);
|
|
viewer->glClearColor(0.0f,
|
|
0.0f,
|
|
0.0f,
|
|
0.0f);
|
|
viewer->glClearDepthf(1);
|
|
viewer->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
renderScene(opaque_items , viewer, picked_item_IDs, false, i, true, depth_test[i-1]);
|
|
renderScene(transparent_items, viewer, picked_item_IDs, false, i, true, depth_test[i-1]);
|
|
depth_test[i]->release();
|
|
}
|
|
|
|
|
|
//last pass
|
|
fbos[static_cast<int>(viewer->total_pass())-1] = new QOpenGLFramebufferObject(viewer->width(), viewer->height(),QOpenGLFramebufferObject::Depth, GL_TEXTURE_2D, GL_RGBA32F);
|
|
fbos[static_cast<int>(viewer->total_pass())-1]->bind();
|
|
viewer->glDisable(GL_BLEND);
|
|
viewer->glEnable(GL_DEPTH_TEST);
|
|
viewer->glDepthFunc(GL_LESS);
|
|
viewer->glClearColor(0.0f,
|
|
0.0f,
|
|
0.0f,
|
|
0.0f);
|
|
viewer->glClearDepthf(1);
|
|
viewer->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
renderScene(opaque_items , viewer, picked_item_IDs, false, static_cast<int>(viewer->total_pass())-1, false, depth_test[static_cast<int>(viewer->total_pass())-2]);
|
|
renderScene(transparent_items, viewer, picked_item_IDs, false, static_cast<int>(viewer->total_pass())-1, false, depth_test[static_cast<int>(viewer->total_pass())-2]);
|
|
fbos[static_cast<int>(viewer->total_pass())-1]->release();
|
|
if(viewer->getStoredFrameBuffer() != nullptr)
|
|
viewer->getStoredFrameBuffer()->bind();
|
|
|
|
//blending
|
|
program.bind();
|
|
vaos[viewer]->bind();
|
|
viewer->glClearColor(static_cast<GLclampf>(background.redF()),
|
|
static_cast<GLclampf>(background.greenF()),
|
|
static_cast<GLclampf>(background.blueF()),
|
|
0.0f);
|
|
viewer->glDisable(GL_DEPTH_TEST);
|
|
viewer->glClear(GL_COLOR_BUFFER_BIT);
|
|
viewer->glEnable(GL_BLEND);
|
|
viewer->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
QMatrix4x4 proj_mat;
|
|
proj_mat.setToIdentity();
|
|
proj_mat.ortho(-1,1,-1,1,0,1);
|
|
program.setUniformValue("projection_matrix", proj_mat);
|
|
for(int i=0; i< static_cast<int>(viewer->total_pass())-1; ++i)
|
|
delete depth_test[i];
|
|
for(int i = static_cast<int>(viewer->total_pass())-1; i>=0; --i)
|
|
{
|
|
viewer->glBindTexture(GL_TEXTURE_2D, fbos[i]->texture());
|
|
viewer->glDrawArrays(GL_TRIANGLES,0,static_cast<GLsizei>(6));
|
|
delete fbos[i];
|
|
}
|
|
viewer->glDisable(GL_BLEND);
|
|
viewer->glEnable(GL_DEPTH_TEST);
|
|
vaos[viewer]->release();
|
|
program.release();
|
|
}
|
|
|
|
viewer->glDepthFunc(GL_LEQUAL);
|
|
// Wireframe OpenGL drawing
|
|
renderWireScene(children, viewer, picked_item_IDs, with_names);
|
|
// Points OpenGL drawing
|
|
renderPointScene(children, viewer, picked_item_IDs, with_names);
|
|
|
|
if(with_names)
|
|
{
|
|
QList<float> depths = picked_item_IDs.keys();
|
|
if(!depths.isEmpty())
|
|
{
|
|
std::sort(depths.begin(), depths.end());
|
|
int id = picked_item_IDs[depths.first()];
|
|
setSelectedItemIndex(id);
|
|
viewer->setSelectedName(id);
|
|
|
|
}
|
|
}
|
|
if(with_names)
|
|
picked = true;
|
|
else
|
|
picked = false;
|
|
//scrolls the sceneView to the selected item's line.
|
|
if(picked)
|
|
{
|
|
Q_EMIT(itemPicked(index_map.key(mainSelectionIndex())));
|
|
}
|
|
Q_EMIT drawFinished();
|
|
}
|
|
|
|
// workaround for Qt-4.2 (see above)
|
|
#undef lighter
|
|
QVariant
|
|
Scene::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!index.isValid())
|
|
{
|
|
return QVariant();
|
|
}
|
|
|
|
int id = index_map[index];
|
|
if(id < 0 || id >= m_entries.size())
|
|
return QVariant();
|
|
if(role == ::Qt::ToolTipRole)
|
|
{
|
|
return m_entries[id]->toolTip();
|
|
}
|
|
switch(index.column())
|
|
{
|
|
case ColorColumn:
|
|
if(role == ::Qt::DecorationRole)
|
|
return m_entries.value(id)->color();
|
|
break;
|
|
case NameColumn:
|
|
if(role == ::Qt::DisplayRole || role == ::Qt::EditRole)
|
|
return m_entries.value(id)->name();
|
|
if(role == ::Qt::FontRole)
|
|
return m_entries.value(id)->font();
|
|
break;
|
|
case RenderingModeColumn:
|
|
if(role == ::Qt::DisplayRole) {
|
|
return m_entries.value(id)->renderingModeName();
|
|
}
|
|
else if(role == ::Qt::EditRole) {
|
|
return static_cast<int>(m_entries.value(id)->renderingMode());
|
|
}
|
|
else if(role == ::Qt::TextAlignmentRole) {
|
|
return ::Qt::AlignCenter;
|
|
}
|
|
break;
|
|
case ABColumn:
|
|
if(role == ::Qt::DisplayRole) {
|
|
if(id == item_A)
|
|
return "A";
|
|
if(id == item_B)
|
|
return "B";
|
|
}
|
|
else if(role == ::Qt::TextAlignmentRole) {
|
|
return ::Qt::AlignLeft;
|
|
}
|
|
break;
|
|
case VisibleColumn:
|
|
if(role == ::Qt::DisplayRole || role == ::Qt::EditRole)
|
|
return m_entries.value(id)->visible();
|
|
break;
|
|
default:
|
|
return QVariant();
|
|
}
|
|
return QVariant();
|
|
}
|
|
|
|
QVariant
|
|
Scene::headerData ( int section, ::Qt::Orientation orientation, int role ) const
|
|
{
|
|
if(orientation == ::Qt::Horizontal) {
|
|
if (role == ::Qt::DisplayRole)
|
|
{
|
|
switch(section)
|
|
{
|
|
case NameColumn:
|
|
return tr("Name");
|
|
break;
|
|
case ColorColumn:
|
|
return tr("#");
|
|
break;
|
|
case RenderingModeColumn:
|
|
return tr("Mode");
|
|
case ABColumn:
|
|
return tr("A/B");
|
|
break;
|
|
case VisibleColumn:
|
|
return tr("View");
|
|
break;
|
|
default:
|
|
return QVariant();
|
|
}
|
|
}
|
|
else if(role == ::Qt::ToolTipRole) {
|
|
if(section == RenderingModeColumn) {
|
|
return tr("Rendering mode (points/wireframe/flat/flat+edges/Gouraud)");
|
|
}
|
|
else if(section == ABColumn) {
|
|
return tr("Selection A/Selection B");
|
|
}
|
|
}
|
|
}
|
|
return QStandardItemModel::headerData(section, orientation, role);
|
|
}
|
|
|
|
Qt::ItemFlags
|
|
Scene::flags ( const QModelIndex & index ) const
|
|
{
|
|
if (index.isValid() && index.column() == NameColumn) {
|
|
return QStandardItemModel::flags(index) | ::Qt::ItemIsEditable;
|
|
}
|
|
else {
|
|
return QStandardItemModel::flags(index);
|
|
}
|
|
}
|
|
|
|
bool
|
|
Scene::setData(const QModelIndex &index,
|
|
const QVariant &value,
|
|
int role)
|
|
{
|
|
|
|
if( role != ::Qt::EditRole || !index.isValid() )
|
|
return false;
|
|
|
|
int id = index_map[index];
|
|
if(id < 0 || id >= m_entries.size()){
|
|
return false;
|
|
}
|
|
|
|
CGAL::Three::Scene_item* item = m_entries[id];
|
|
|
|
if(!item) return false;
|
|
switch(index.column())
|
|
{
|
|
case NameColumn:
|
|
item->setName(value.toString());
|
|
Q_EMIT dataChanged(index, index);
|
|
return true;
|
|
break;
|
|
case ColorColumn:
|
|
if(selectionIndices().contains(item_id(item)))
|
|
Q_FOREACH(Item_id item_index, selectionIndices())
|
|
this->item(item_index)->setColor(value.value<QColor>());
|
|
else
|
|
item->setColor(value.value<QColor>());
|
|
Q_EMIT dataChanged(index, index);
|
|
return true;
|
|
break;
|
|
case RenderingModeColumn:
|
|
{
|
|
RenderingMode rendering_mode = static_cast<RenderingMode>(value.toInt());
|
|
// Find next supported rendering mode
|
|
int counter = 0;
|
|
while ( ! item->supportsRenderingMode(rendering_mode)
|
|
)
|
|
{
|
|
rendering_mode = static_cast<RenderingMode>( (rendering_mode+1) % NumberOfRenderingMode );
|
|
if(counter++ == NumberOfRenderingMode)
|
|
break;
|
|
}
|
|
item->setRenderingMode(rendering_mode);
|
|
QModelIndex nindex = createIndex(m_entries.size()-1,RenderingModeColumn+1);
|
|
Q_EMIT dataChanged(index, nindex);
|
|
return true;
|
|
break;
|
|
}
|
|
case VisibleColumn:
|
|
item->setVisible(value.toBool());
|
|
Q_EMIT dataChanged(index, createIndex(m_entries.size()-1,VisibleColumn+1));
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Scene::dropMimeData(const QMimeData * /*data*/,
|
|
Qt::DropAction /*action*/,
|
|
int /*row*/,
|
|
int /*column*/,
|
|
const QModelIndex &parent)
|
|
{
|
|
//gets the moving items
|
|
QList<Scene_item*> items;
|
|
QList<int> groups_children;
|
|
|
|
//get IDs of all children of selected groups
|
|
Q_FOREACH(int i, selected_items_list)
|
|
{
|
|
CGAL::Three::Scene_group_item* group =
|
|
qobject_cast<CGAL::Three::Scene_group_item*>(item(i));
|
|
if(group)
|
|
{
|
|
Q_FOREACH(Item_id id, group->getChildren())
|
|
{
|
|
CGAL::Three::Scene_item* child = item(id);
|
|
groups_children << item_id(child);
|
|
}
|
|
}
|
|
}
|
|
// Insure that children of selected groups will not be added twice
|
|
Q_FOREACH(int i, selected_items_list)
|
|
{
|
|
if(!groups_children.contains(i))
|
|
{
|
|
items << item(i);
|
|
}
|
|
}
|
|
//Gets the group at the drop position
|
|
CGAL::Three::Scene_group_item* group = nullptr;
|
|
if(parent.isValid())
|
|
group = qobject_cast<CGAL::Three::Scene_group_item*>(this->item(index_map[parent]));
|
|
bool one_contained = false;
|
|
if(group)
|
|
{
|
|
Q_FOREACH(int id, selected_items_list)
|
|
if(group->getChildren().contains(id))
|
|
{
|
|
one_contained = true;
|
|
break;
|
|
|
|
}
|
|
}
|
|
//if the drop item is not a group_item or if it already contains the item, then the drop action must be ignored
|
|
if(!group ||one_contained)
|
|
{
|
|
//unless the drop zone is empty, which means the item should be removed from all groups.
|
|
if(!parent.isValid())
|
|
{
|
|
Q_FOREACH(Scene_item* item, items)
|
|
{
|
|
if(item->parentGroup())
|
|
{
|
|
item->parentGroup()->removeChild(item);
|
|
addChild(item);
|
|
}
|
|
}
|
|
redraw_model();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
Q_FOREACH(Scene_item* item, items)
|
|
changeGroup(item, group);
|
|
redraw_model();
|
|
return true;
|
|
}
|
|
|
|
//todo : if a group is selected, don't treat it's children.
|
|
bool Scene::sort_lists(QVector<QList<int> >&sorted_lists, bool up)
|
|
{
|
|
QVector<int> group_found;
|
|
Q_FOREACH(int i, selectionIndices())
|
|
{
|
|
Scene_item* item = this->item(i);
|
|
if(item->has_group == 0)
|
|
{
|
|
sorted_lists.first().push_back(i);
|
|
}
|
|
else
|
|
{
|
|
int group_id = item_id(item->parentGroup());
|
|
if(group_found.contains(group_id))
|
|
sorted_lists[group_id].push_back(i);
|
|
else
|
|
{
|
|
group_found.push_back(group_id);
|
|
if(sorted_lists.size() < group_id+1)
|
|
sorted_lists.resize(group_id+1);
|
|
sorted_lists[group_id].push_back(i);
|
|
}
|
|
}
|
|
}
|
|
//iterate the first list to find the groups that are selected and remove the corresponding
|
|
//sub lists.
|
|
//todo: do that for each group. (treat subgroups)
|
|
for(int i = 0; i< sorted_lists.first().size(); ++i)
|
|
{
|
|
Scene_group_item* group = qobject_cast<Scene_group_item*>(this->item(sorted_lists.first()[i]));
|
|
if(group && ! group->getChildren().isEmpty() && sorted_lists.first()[i] < sorted_lists.size())
|
|
{
|
|
sorted_lists[sorted_lists.first()[i]].clear();
|
|
}
|
|
}
|
|
std::sort(sorted_lists.first().begin(), sorted_lists.first().end(),
|
|
[this](int a, int b) {
|
|
return children.indexOf(a) < children.indexOf(b);
|
|
});
|
|
if(!sorted_lists.first().isEmpty())
|
|
{
|
|
if(up && children.indexOf(sorted_lists.first().first()) == 0)
|
|
return false;
|
|
else if(!up && children.indexOf(sorted_lists.first().last()) == children.size() -1)
|
|
return false;
|
|
}
|
|
for(int i=1; i<sorted_lists.size(); ++i)
|
|
{
|
|
QList<int>& list = sorted_lists[i];
|
|
if(list.isEmpty())
|
|
continue;
|
|
Scene_group_item* group = qobject_cast<Scene_group_item*>(this->item(i));
|
|
if(!group)
|
|
continue;
|
|
std::sort(list.begin(), list.end(),
|
|
[group](int a, int b) {
|
|
return group->getChildren().indexOf(a) < group->getChildren().indexOf(b);
|
|
});
|
|
if(up && group->getChildren().indexOf(list.first()) == 0)
|
|
return false;
|
|
else if(!up && group->getChildren().indexOf(list.last()) == group->getChildren().size()-1)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
void Scene::moveRowUp()
|
|
{
|
|
if(selectionIndices().isEmpty())
|
|
return;
|
|
QVector<QList<int> >sorted_lists(1);
|
|
QList<int> to_select;
|
|
//sort lists according to the indices of each item in its container (scene or group)
|
|
//if moving one up would put it out of range, then we stop and do nothing.
|
|
if(!sort_lists(sorted_lists, true))
|
|
return;
|
|
|
|
for(int i=0; i<sorted_lists.first().size(); ++i)
|
|
{
|
|
Item_id selected_id = sorted_lists.first()[i];
|
|
Scene_item* selected_item = item(selected_id);
|
|
if(!selected_item)
|
|
return;
|
|
if(index_map.key(selected_id).row() > 0)
|
|
{
|
|
//if not in group
|
|
QModelIndex baseId = index_map.key(selected_id);
|
|
int newId = children.indexOf(
|
|
index_map.value(index(baseId.row()-1, baseId.column(),baseId.parent()))) ;
|
|
children.move(children.indexOf(selected_id), newId);
|
|
redraw_model();
|
|
to_select.append(m_entries.indexOf(selected_item));
|
|
}
|
|
}
|
|
for(int i=1; i<sorted_lists.size(); ++i)
|
|
{
|
|
for(int j = 0; j< sorted_lists[i].size(); ++j)
|
|
{
|
|
Item_id selected_id = sorted_lists[i][j];
|
|
Scene_item* selected_item = item(selected_id);
|
|
if(!selected_item)
|
|
return;
|
|
if(index_map.key(selected_id).row() > 0)
|
|
{
|
|
Scene_group_item* group = selected_item->parentGroup();
|
|
if(group)
|
|
{
|
|
int id = group->getChildren().indexOf(item_id(selected_item));
|
|
group->moveUp(id);
|
|
redraw_model();
|
|
to_select.append(m_entries.indexOf(selected_item));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(!to_select.isEmpty()){
|
|
selectionChanged(to_select);
|
|
}
|
|
}
|
|
void Scene::moveRowDown()
|
|
{
|
|
if(selectionIndices().isEmpty())
|
|
return;
|
|
QVector<QList<int> >sorted_lists(1);
|
|
QList<int> to_select;
|
|
//sort lists according to the indices of each item in its container (scene or group)
|
|
//if moving one up would put it out of range, then we stop and do nothing.
|
|
if(!sort_lists(sorted_lists, false))
|
|
return;
|
|
for(int i=sorted_lists.first().size()-1; i>=0; --i)
|
|
{
|
|
Item_id selected_id = sorted_lists.first()[i];
|
|
Scene_item* selected_item = item(selected_id);
|
|
if(!selected_item)
|
|
return;
|
|
if(index_map.key(selected_id).row() < rowCount(index_map.key(selected_id).parent())-1)
|
|
{
|
|
//if not in group
|
|
QModelIndex baseId = index_map.key(selected_id);
|
|
int newId = children.indexOf(
|
|
index_map.value(index(baseId.row()+1, baseId.column(),baseId.parent()))) ;
|
|
children.move(children.indexOf(selected_id), newId);
|
|
|
|
redraw_model();
|
|
to_select.prepend(m_entries.indexOf(selected_item));
|
|
}
|
|
}
|
|
for(int i=1; i<sorted_lists.size(); ++i){
|
|
if(sorted_lists[i].isEmpty())
|
|
continue;
|
|
for(int j = sorted_lists[i].size()-1; j >=0; --j)
|
|
{
|
|
Item_id selected_id = sorted_lists[i][j];
|
|
Scene_item* selected_item = item(selected_id);
|
|
if(!selected_item)
|
|
return;
|
|
if(index_map.key(selected_id).row() < rowCount(index_map.key(selected_id).parent())-1)
|
|
{
|
|
if(item(selected_id)->has_group >0)
|
|
{
|
|
Scene_group_item* group = selected_item->parentGroup();
|
|
if(group)
|
|
{
|
|
int id = group->getChildren().indexOf(item_id(selected_item));
|
|
group->moveDown(id);
|
|
}
|
|
}
|
|
redraw_model();
|
|
to_select.prepend(m_entries.indexOf(selected_item));
|
|
}
|
|
}
|
|
}
|
|
if(!to_select.isEmpty()){
|
|
selectionChanged(to_select);
|
|
}
|
|
}
|
|
Scene::Item_id Scene::mainSelectionIndex() const {
|
|
return (selectionIndices().size() == 1) ? selected_item : -1;
|
|
}
|
|
|
|
QList<int> Scene::selectionIndices() const {
|
|
return selected_items_list;
|
|
}
|
|
|
|
int Scene::selectionAindex() const {
|
|
return item_A;
|
|
}
|
|
|
|
int Scene::selectionBindex() const {
|
|
return item_B;
|
|
}
|
|
|
|
QItemSelection Scene::createSelection(int i)
|
|
{
|
|
return QItemSelection(index_map.keys(i).at(0),
|
|
index_map.keys(i).at(4));
|
|
}
|
|
|
|
QItemSelection Scene::createSelection(QList<int> is)
|
|
{
|
|
QItemSelection sel;
|
|
Q_FOREACH(int i, is)
|
|
sel.select(index_map.keys(i).at(0),
|
|
index_map.keys(i).at(4));
|
|
return sel;
|
|
}
|
|
|
|
QItemSelection Scene::createSelectionAll()
|
|
{
|
|
//it is not possible to directly create a selection with items that have different parents, so
|
|
//we do it iteratively.
|
|
QItemSelection sel;
|
|
sel.select(this->createIndex(0, 0),
|
|
this->createIndex(m_entries.size(), LastColumn));
|
|
for(const auto& gid : m_groups)
|
|
{
|
|
CGAL::Three::Scene_group_item* group =
|
|
qobject_cast<CGAL::Three::Scene_group_item*>(item(gid));
|
|
sel.select(index_map.keys(group->getChildren().first()).at(0),
|
|
index_map.keys(group->getChildren().last()).at(4));
|
|
}
|
|
return sel;
|
|
}
|
|
|
|
void Scene::itemChanged()
|
|
{
|
|
CGAL::Three::Scene_item* item = qobject_cast<CGAL::Three::Scene_item*>(sender());
|
|
if(item)
|
|
itemChanged(item);
|
|
}
|
|
|
|
void Scene::itemChanged(Item_id i)
|
|
{
|
|
if(dont_emit_changes)
|
|
return;
|
|
if(i < 0 || i >= m_entries.size())
|
|
return;
|
|
|
|
Q_EMIT dataChanged(this->createIndex(i, 0),
|
|
this->createIndex(i, LastColumn));
|
|
}
|
|
|
|
void Scene::itemChanged(CGAL::Three::Scene_item*item )
|
|
{
|
|
if(dont_emit_changes)
|
|
return;
|
|
itemChanged(item_id(item));
|
|
}
|
|
|
|
void Scene::allItemsChanged()
|
|
{
|
|
Q_EMIT dataChanged(this->createIndex(0, 0),
|
|
this->createIndex(m_entries.size() - 1, LastColumn));
|
|
}
|
|
|
|
void Scene::itemVisibilityChanged()
|
|
{
|
|
CGAL::Three::Scene_item* item = qobject_cast<CGAL::Three::Scene_item*>(sender());
|
|
if(item)
|
|
itemVisibilityChanged(item);
|
|
}
|
|
|
|
void Scene::itemVisibilityChanged(CGAL::Three::Scene_item* item)
|
|
{
|
|
if(item->isFinite()
|
|
&& !item->isEmpty())
|
|
{
|
|
//does not recenter
|
|
if(visibility_recentering_enabled){
|
|
Q_EMIT updated_bbox(true);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool SceneDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
|
const QStyleOptionViewItem &option,
|
|
const QModelIndex &index)
|
|
{
|
|
QAbstractProxyModel* proxyModel = dynamic_cast<QAbstractProxyModel*>(model);
|
|
Q_ASSERT(proxyModel);
|
|
Scene *scene = dynamic_cast<Scene*>(proxyModel->sourceModel());
|
|
Q_ASSERT(scene);
|
|
int id = scene->index_map[proxyModel->mapToSource(index)];
|
|
switch(index.column()) {
|
|
case Scene::VisibleColumn:
|
|
if (event->type() == QEvent::MouseButtonPress) {
|
|
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
|
|
if(mouseEvent->button() == ::Qt::LeftButton) {
|
|
int x = mouseEvent->pos().x() - option.rect.x();
|
|
if(x >= (option.rect.width() - size)/2 &&
|
|
x <= (option.rect.width() + size)/2) {
|
|
model->setData(index, !model->data(index).toBool());
|
|
}
|
|
}
|
|
return false; //so that the selection can change
|
|
}
|
|
return true;
|
|
break;
|
|
case Scene::ColorColumn:
|
|
if (event->type() == QEvent::MouseButtonPress) {
|
|
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
|
|
if(mouseEvent->button() == ::Qt::LeftButton) {
|
|
QColor color =
|
|
QColorDialog::getColor(model->data(index).value<QColor>(),
|
|
nullptr/*,
|
|
tr("Select color"),
|
|
QColorDialog::ShowAlphaChannel*/);
|
|
if (color.isValid()) {
|
|
model->setData(index, color );
|
|
}
|
|
}
|
|
}
|
|
else if(event->type() == QEvent::MouseButtonDblClick) {
|
|
return true; // block double-click
|
|
}
|
|
return false;
|
|
break;
|
|
case Scene::RenderingModeColumn:
|
|
if (event->type() == QEvent::MouseButtonPress) {
|
|
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
|
|
if(mouseEvent->button() == ::Qt::LeftButton) {
|
|
// Switch rendering mode
|
|
/*RenderingMode*/int rendering_mode = model->data(index, ::Qt::EditRole).toInt();
|
|
rendering_mode = (rendering_mode+1) % NumberOfRenderingMode;
|
|
model->setData(index, rendering_mode);
|
|
}
|
|
}
|
|
else if(event->type() == QEvent::MouseButtonDblClick) {
|
|
return true; // block double-click
|
|
}
|
|
return false;
|
|
break;
|
|
case Scene::ABColumn:
|
|
if (event->type() == QEvent::MouseButtonPress) {
|
|
if(id == scene->item_B) {
|
|
scene->item_A = id;
|
|
scene->item_B = -1;
|
|
}
|
|
else if(id == scene->item_A) {
|
|
scene->item_B = id;
|
|
scene->item_A = -1;
|
|
}
|
|
else if(scene->item_A == -1) {
|
|
scene->item_A = id;
|
|
}
|
|
else {
|
|
scene->item_B = id;
|
|
}
|
|
scene->dataChanged(scene->createIndex(0, Scene::ABColumn),
|
|
scene->createIndex(scene->rowCount() - 1, Scene::ABColumn));
|
|
}
|
|
return false;
|
|
break;
|
|
default:
|
|
return QItemDelegate::editorEvent(event, model, option, index);
|
|
}
|
|
}
|
|
|
|
void SceneDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
|
const QModelIndex &index) const
|
|
{
|
|
QModelIndex test = proxy->mapToSource(index);
|
|
if (index.column() != Scene::VisibleColumn) {
|
|
QItemDelegate::paint(painter, option, index);
|
|
} else {
|
|
const QAbstractItemModel *model = index.model();
|
|
|
|
QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ?
|
|
(option.state & QStyle::State_Active) ? QPalette::Normal : QPalette::Inactive : QPalette::Disabled;
|
|
|
|
if (option.state & QStyle::State_Selected)
|
|
painter->fillRect(option.rect, option.palette.color(cg, QPalette::Highlight));
|
|
bool checked = model->data(index, ::Qt::DisplayRole).toBool();
|
|
int width = option.rect.width();
|
|
int height = option.rect.height();
|
|
size = (std::min)(width, height);
|
|
int x = option.rect.x() + (option.rect.width() / 2) - (size / 2);;
|
|
int y = option.rect.y() + (option.rect.height() / 2) - (size / 2);
|
|
if(test.row()>=0 && test.row()<scene->m_entries.size()){
|
|
|
|
if(checked) {
|
|
painter->drawPixmap(x, y, checkOnPixmap.scaled(QSize(size, size),
|
|
::Qt::KeepAspectRatio,
|
|
::Qt::SmoothTransformation));
|
|
}
|
|
else {
|
|
painter->drawPixmap(x, y, checkOffPixmap.scaled(QSize(size, size),
|
|
::Qt::KeepAspectRatio,
|
|
::Qt::SmoothTransformation));
|
|
}
|
|
}
|
|
drawFocus(painter, option, option.rect); // since we draw the grid ourselves
|
|
}
|
|
}
|
|
|
|
void Scene::setItemVisible(int index, bool b)
|
|
{
|
|
if( index < 0 || index >= m_entries.size() )
|
|
return;
|
|
m_entries[index]->setVisible(b);
|
|
Q_EMIT dataChanged(this->createIndex(index, VisibleColumn),
|
|
this->createIndex(index, VisibleColumn));
|
|
}
|
|
|
|
void Scene::setSelectionRay(double orig_x,
|
|
double orig_y,
|
|
double orig_z,
|
|
double dir_x,
|
|
double dir_y,
|
|
double dir_z)
|
|
{
|
|
CGAL::Three::Scene_item* item = this->item(selected_item);
|
|
if(item) item->select(orig_x,
|
|
orig_y,
|
|
orig_z,
|
|
dir_x,
|
|
dir_y,
|
|
dir_z);
|
|
}
|
|
|
|
void Scene::setItemA(int i)
|
|
{
|
|
item_A = i;
|
|
if(item_A == item_B)
|
|
{
|
|
item_B = -1;
|
|
}
|
|
Q_EMIT dataChanged(this->createIndex(0, ABColumn),
|
|
this->createIndex(m_entries.size()-1, ABColumn));
|
|
}
|
|
|
|
void Scene::setItemB(int i)
|
|
{
|
|
item_B = i;
|
|
if(item_A == item_B)
|
|
{
|
|
item_A = -1;
|
|
}
|
|
Q_EMIT updated();
|
|
Q_EMIT dataChanged(this->createIndex(0, ABColumn),
|
|
this->createIndex(m_entries.size()-1, ABColumn));
|
|
}
|
|
|
|
Scene::Bbox Scene::bbox() const
|
|
{
|
|
if(m_entries.empty())
|
|
return Bbox(0,0,0,0,0,0);
|
|
|
|
bool bbox_initialized = false;
|
|
Bbox bbox = Bbox(0,0,0,0,0,0);
|
|
Q_FOREACH(CGAL::Three::Scene_item* item, m_entries)
|
|
{
|
|
if(item->isFinite() && !item->isEmpty() && item->visible()) {
|
|
if(bbox_initialized) {
|
|
|
|
bbox = bbox + item->bbox();
|
|
}
|
|
else {
|
|
bbox = item->bbox();
|
|
bbox_initialized = true;
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
return bbox;
|
|
}
|
|
|
|
QList<Scene_item*> Scene::item_entries() const
|
|
{
|
|
return m_entries;
|
|
}
|
|
void Scene::redraw_model()
|
|
{
|
|
//makes the hierarchy in the tree
|
|
//clears the model
|
|
clear();
|
|
index_map.clear();
|
|
//fills the model
|
|
Q_FOREACH(Item_id id, children)
|
|
{
|
|
organize_items(m_entries[id], invisibleRootItem(), 0);
|
|
}
|
|
Q_EMIT restoreCollapsedState();
|
|
}
|
|
void Scene::changeGroup(Scene_item *item, CGAL::Three::Scene_group_item *target_group)
|
|
{
|
|
//remove item from the containing group if any
|
|
if(item->parentGroup())
|
|
{
|
|
if(item->parentGroup()->isChildLocked(item))
|
|
return;
|
|
item->parentGroup()->removeChild(item);
|
|
children.push_back(item_id(item));
|
|
}
|
|
else
|
|
{
|
|
children.removeAll(item_id(item));
|
|
}
|
|
//add the item to the target group
|
|
target_group->addChild(item);
|
|
item->moveToGroup(target_group);
|
|
redraw_model();
|
|
Q_EMIT updated();
|
|
}
|
|
|
|
void Scene::printPrimitiveId(QPoint point, CGAL::Three::Viewer_interface* viewer)
|
|
{
|
|
Scene_item *it = item(mainSelectionIndex());
|
|
if(it)
|
|
{
|
|
//Only call printPrimitiveId if the item is a Scene_print_item_interface
|
|
Scene_print_item_interface* item= qobject_cast<Scene_print_item_interface*>(it);
|
|
if(item)
|
|
item->printPrimitiveId(point, viewer);
|
|
}
|
|
}
|
|
void Scene::printVertexIds()
|
|
{
|
|
Scene_item *it = item(mainSelectionIndex());
|
|
if(it)
|
|
{
|
|
Scene_print_item_interface* item= qobject_cast<Scene_print_item_interface*>(it);
|
|
if(item)
|
|
item->printVertexIds();
|
|
}
|
|
}
|
|
|
|
void Scene::printEdgeIds()
|
|
{
|
|
Scene_item *it = item(mainSelectionIndex());
|
|
if(it)
|
|
{
|
|
//Only call printEdgeIds if the item is a Scene_print_item_interface
|
|
Scene_print_item_interface* item= qobject_cast<Scene_print_item_interface*>(it);
|
|
if(item)
|
|
item->printEdgeIds();
|
|
}
|
|
}
|
|
|
|
void Scene::printFaceIds()
|
|
{
|
|
Scene_item *it = item(mainSelectionIndex());
|
|
if(it)
|
|
{
|
|
//Only call printFaceIds if the item is a Scene_print_item_interface
|
|
Scene_print_item_interface* item= qobject_cast<Scene_print_item_interface*>(it);
|
|
if(item)
|
|
item->printFaceIds();
|
|
}
|
|
}
|
|
|
|
void Scene::printAllIds()
|
|
{
|
|
Scene_item *it = item(mainSelectionIndex());
|
|
if(it)
|
|
{
|
|
//Only call printFaceIds if the item is a Scene_print_item_interface
|
|
Scene_print_item_interface* item= qobject_cast<Scene_print_item_interface*>(it);
|
|
if(item)
|
|
item->printAllIds();
|
|
}
|
|
}
|
|
void Scene::updatePrimitiveIds(CGAL::Three::Scene_item* it)
|
|
{
|
|
if(it)
|
|
{
|
|
Scene_print_item_interface* item= qobject_cast<Scene_print_item_interface*>(it);
|
|
if(item)
|
|
{
|
|
//As this function works as a toggle, the first call hides the ids and the second one shows them again,
|
|
//thereby triggering their re-computation.
|
|
item->printVertexIds();
|
|
item->printVertexIds();
|
|
|
|
item->printEdgeIds();
|
|
item->printEdgeIds();
|
|
|
|
item->printFaceIds();
|
|
item->printFaceIds();
|
|
}
|
|
}
|
|
}
|
|
bool Scene::testDisplayId(double x, double y, double z, CGAL::Three::Viewer_interface* viewer)
|
|
{
|
|
CGAL::Three::Scene_item *i = item(mainSelectionIndex());
|
|
if(!i)
|
|
return false;
|
|
Scene_print_item_interface* spit= qobject_cast<Scene_print_item_interface*>(i);
|
|
if(spit && i->visible())
|
|
{
|
|
bool res = spit->testDisplayId(x,y,z, viewer);
|
|
return res;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
#include "Scene_find_items.h"
|
|
|
|
void Scene::organize_items(Scene_item* item, QStandardItem* root, int loop)
|
|
{
|
|
if(item->has_group <= loop)
|
|
{
|
|
QList<QStandardItem*> list;
|
|
for(int i=0; i<5; i++)
|
|
{
|
|
list<<new QStandardItem();
|
|
list.at(i)->setEditable(false);
|
|
|
|
}
|
|
root->appendRow(list);
|
|
for(int i=0; i<5; i++){
|
|
index_map[list.at(i)->index()] = m_entries.indexOf(item);
|
|
}
|
|
CGAL::Three::Scene_group_item* group =
|
|
qobject_cast<CGAL::Three::Scene_group_item*>(item);
|
|
if(group)
|
|
{
|
|
Q_FOREACH(Item_id id, group->getChildren())
|
|
{
|
|
CGAL::Three::Scene_item* child = group->getChild(id);
|
|
organize_items(child, list.first(), loop+1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Scene::setExpanded(QModelIndex id)
|
|
{
|
|
CGAL::Three::Scene_group_item* group =
|
|
qobject_cast<CGAL::Three::Scene_group_item*>(item(getIdFromModelIndex(id)));
|
|
if(group)
|
|
{
|
|
group->setExpanded(true);
|
|
}
|
|
}
|
|
void Scene::setCollapsed(QModelIndex id)
|
|
{
|
|
CGAL::Three::Scene_group_item* group =
|
|
qobject_cast<CGAL::Three::Scene_group_item*>(item(getIdFromModelIndex(id)));
|
|
if(group)
|
|
{
|
|
group->setExpanded(false);
|
|
}
|
|
}
|
|
|
|
int Scene::getIdFromModelIndex(QModelIndex modelId)const
|
|
{
|
|
return index_map.value(modelId);
|
|
}
|
|
|
|
QList<QModelIndex> Scene::getModelIndexFromId(int id) const
|
|
{
|
|
return index_map.keys(id);
|
|
}
|
|
|
|
void Scene::addGroup(Scene_group_item* group)
|
|
{
|
|
connect(this, SIGNAL(drawFinished()), group, SLOT(resetDraw()));
|
|
connect(this, SIGNAL(indexErased(Scene_interface::Item_id)),
|
|
group, SLOT(adjustIds(Scene_interface::Item_id)));
|
|
}
|
|
|
|
namespace scene { namespace details {
|
|
|
|
Q_DECL_EXPORT
|
|
CGAL::Three::Scene_item*
|
|
findItem(const CGAL::Three::Scene_interface* scene_interface,
|
|
const QMetaObject& metaobj,
|
|
QString name, Scene_item_name_fn_ptr fn) {
|
|
const Scene* scene = dynamic_cast<const Scene*>(scene_interface);
|
|
if(!scene) return nullptr;
|
|
Q_FOREACH(CGAL::Three::Scene_item* item, scene->entries()) {
|
|
CGAL::Three::Scene_item* ptr = qobject_cast<CGAL::Three::Scene_item*>(metaobj.cast(item));
|
|
if(ptr && ((ptr->*fn)() == name)) return ptr;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Q_DECL_EXPORT
|
|
QList<CGAL::Three::Scene_item*>
|
|
findItems(const CGAL::Three::Scene_interface* scene_interface,
|
|
|
|
const QMetaObject&,
|
|
QString name, Scene_item_name_fn_ptr fn)
|
|
{
|
|
const Scene* scene = dynamic_cast<const Scene*>(scene_interface);
|
|
QList<CGAL::Three::Scene_item*> list;
|
|
if(!scene) return list;
|
|
|
|
Q_FOREACH(CGAL::Three::Scene_item* item, scene->entries()) {
|
|
CGAL::Three::Scene_item* ptr = qobject_cast<CGAL::Three::Scene_item*>(item);
|
|
if(ptr && ((ptr->*fn)() == name)) {
|
|
list << ptr;
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
} // end namespace details
|
|
} // end namespace scene
|
|
|
|
void Scene::zoomToPosition(QPoint point, Viewer_interface *viewer)
|
|
{
|
|
for(int i=0; i<numberOfEntries(); ++i)
|
|
{
|
|
if(!item(i)->visible())
|
|
continue;
|
|
Scene_zoomable_item_interface* zoom_item = qobject_cast<Scene_zoomable_item_interface*>(item(i));
|
|
if(zoom_item)
|
|
{
|
|
zoom_item->zoomToPosition(point, viewer);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Scene::adjustIds(Item_id removed_id)
|
|
{
|
|
for(int i = 0; i < children.size(); ++i)
|
|
{
|
|
if(children[i] >= removed_id)
|
|
--children[i];
|
|
}
|
|
for(int i = removed_id; i < numberOfEntries(); ++i)
|
|
{
|
|
m_entries[i]->setId(i-1);//the signal is emitted before m_entries is amputed from the item, so new id is current id -1.
|
|
}
|
|
}
|
|
|
|
void Scene::computeBbox()
|
|
{
|
|
if(m_entries.empty())
|
|
{
|
|
last_bbox = Bbox(0,0,0,0,0,0);
|
|
return;
|
|
}
|
|
|
|
bool bbox_initialized = false;
|
|
Bbox bbox = Bbox(0,0,0,0,0,0);
|
|
Q_FOREACH(CGAL::Three::Scene_item* item, m_entries)
|
|
{
|
|
if(item->isFinite() && !item->isEmpty() ) {
|
|
if(bbox_initialized) {
|
|
|
|
bbox = bbox + item->bbox();
|
|
}
|
|
else {
|
|
bbox = item->bbox();
|
|
bbox_initialized = true;
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
last_bbox = bbox;
|
|
}
|
|
|
|
void Scene::newViewer(Viewer_interface *viewer)
|
|
{
|
|
initGL(viewer);
|
|
Q_FOREACH(Scene_item* item, m_entries)
|
|
{
|
|
item->newViewer(viewer);
|
|
}
|
|
}
|
|
|
|
void Scene::removeViewer(Viewer_interface *viewer)
|
|
{
|
|
//already destroyed;
|
|
if(viewer->property("is_destroyed").toBool())
|
|
return;
|
|
|
|
vaos[viewer]->destroy();
|
|
vaos[viewer]->deleteLater();
|
|
vaos.remove(viewer);
|
|
Q_FOREACH(Scene_item* item, m_entries)
|
|
{
|
|
item->removeViewer(viewer);
|
|
}
|
|
}
|
|
|
|
void Scene::initGL(Viewer_interface *viewer)
|
|
{
|
|
viewer->makeCurrent();
|
|
vaos[viewer] = new QOpenGLVertexArrayObject();
|
|
vaos[viewer]->create();
|
|
program.bind();
|
|
vaos[viewer]->bind();
|
|
vbo[0].bind();
|
|
vbo[0].allocate(points, 18 * sizeof(float));
|
|
program.enableAttributeArray("vertex");
|
|
program.setAttributeArray("vertex", GL_FLOAT, nullptr, 3);
|
|
vbo[0].release();
|
|
|
|
vbo[1].bind();
|
|
vbo[1].allocate(uvs, 12 * sizeof(float));
|
|
program.enableAttributeArray("v_texCoord");
|
|
program.setAttributeArray("v_texCoord", GL_FLOAT, nullptr, 2);
|
|
vbo[1].release();
|
|
vaos[viewer]->release();
|
|
program.release();
|
|
}
|
|
|
|
void Scene::callDraw(){
|
|
Q_FOREACH(CGAL::QGLViewer* v, CGAL::QGLViewer::QGLViewerPool())
|
|
{
|
|
qobject_cast<Viewer_interface*>(v)->update();
|
|
}
|
|
}
|
|
|
|
void Scene::enableVisibilityRecentering(bool b)
|
|
{
|
|
visibility_recentering_enabled = b;
|
|
}
|
|
|
|
void Scene::addChild(Scene_item *item)
|
|
{
|
|
children.push_back(item_id(item));
|
|
}
|