Commit 046c3ab1 authored by Pierre Kraemer's avatar Pierre Kraemer

update surface selection plugin

parent 573668ba
...@@ -36,7 +36,41 @@ ...@@ -36,7 +36,41 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="1" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Method :</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="combo_selectionMethod">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>SingleCell</string>
</property>
</item>
<item>
<property name="text">
<string>WithinSphere</string>
</property>
</item>
</widget>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
......
...@@ -13,12 +13,20 @@ namespace CGoGN ...@@ -13,12 +13,20 @@ namespace CGoGN
namespace SCHNApps namespace SCHNApps
{ {
enum SelectionMethod
{
SingleCell = 0,
WithinSphere = 1
};
struct MapParameters struct MapParameters
{ {
MapParameters() MapParameters() :
selectionMethod(SingleCell)
{} {}
VertexAttribute<PFP2::VEC3> positionAttribute; VertexAttribute<PFP2::VEC3> positionAttribute;
SelectionMethod selectionMethod;
}; };
class Surface_Selection_Plugin : public PluginInteraction class Surface_Selection_Plugin : public PluginInteraction
...@@ -52,7 +60,6 @@ public: ...@@ -52,7 +60,6 @@ public:
private slots: private slots:
// slots called from SCHNApps signals // slots called from SCHNApps signals
void selectedViewChanged(View* prev, View* cur);
void selectedMapChanged(MapHandlerGen* prev, MapHandlerGen* cur); void selectedMapChanged(MapHandlerGen* prev, MapHandlerGen* cur);
void mapAdded(MapHandlerGen* map); void mapAdded(MapHandlerGen* map);
void mapRemoved(MapHandlerGen* map); void mapRemoved(MapHandlerGen* map);
...@@ -63,18 +70,22 @@ private slots: ...@@ -63,18 +70,22 @@ private slots:
public slots: public slots:
// slots for Python calls // slots for Python calls
void changePositionAttribute(const QString& view, const QString& map, const QString& name); void changePositionAttribute(const QString& view, const QString& map, const QString& name);
void changeSelectionMethod(const QString& view, const QString& map, unsigned int method);
protected: protected:
Surface_Selection_DockTab* m_dockTab; Surface_Selection_DockTab* m_dockTab;
QHash<View*, QHash<MapHandlerGen*, MapParameters> > h_viewParameterSet; QHash<MapHandlerGen*, MapParameters> h_parameterSet;
Utils::Drawer* m_drawer; bool m_selecting;
Utils::VBO* m_selectionSphereVBO;
Utils::PointSprite* m_pointSprite; Utils::PointSprite* m_pointSprite;
Utils::Drawer* m_drawer;
bool m_selecting; // selected cells drawing
Utils::VBO* m_selectedVerticesVBO;
// WithinSphere parameters
Utils::VBO* m_selectionSphereVBO;
PFP2::VEC3 m_selectionCenter; PFP2::VEC3 m_selectionCenter;
PFP2::REAL m_selectionRadius; PFP2::REAL m_selectionRadius;
}; };
......
...@@ -29,6 +29,7 @@ private: ...@@ -29,6 +29,7 @@ private:
private slots: private slots:
void positionAttributeChanged(int index); void positionAttributeChanged(int index);
void selectionMethodChanged(int index);
private: private:
void addVertexAttribute(const QString& name); void addVertexAttribute(const QString& name);
......
...@@ -25,14 +25,16 @@ bool Surface_Selection_Plugin::enable() ...@@ -25,14 +25,16 @@ bool Surface_Selection_Plugin::enable()
m_dockTab = new Surface_Selection_DockTab(m_schnapps, this); m_dockTab = new Surface_Selection_DockTab(m_schnapps, this);
m_schnapps->addPluginDockTab(this, m_dockTab, "Surface_Selection"); m_schnapps->addPluginDockTab(this, m_dockTab, "Surface_Selection");
m_pointSprite = new CGoGN::Utils::PointSprite();
m_drawer = new Utils::Drawer(); m_drawer = new Utils::Drawer();
m_selectedVerticesVBO = new Utils::VBO();
m_selectionSphereVBO = new Utils::VBO(); m_selectionSphereVBO = new Utils::VBO();
m_pointSprite = new CGoGN::Utils::PointSprite();
registerShader(m_drawer->getShader()); registerShader(m_drawer->getShader());
registerShader(m_pointSprite); registerShader(m_pointSprite);
connect(m_schnapps, SIGNAL(selectedViewChanged(View*, View*)), this, SLOT(selectedViewChanged(View*, View*)));
connect(m_schnapps, SIGNAL(selectedMapChanged(MapHandlerGen*, MapHandlerGen*)), this, SLOT(selectedMapChanged(MapHandlerGen*, MapHandlerGen*))); connect(m_schnapps, SIGNAL(selectedMapChanged(MapHandlerGen*, MapHandlerGen*)), this, SLOT(selectedMapChanged(MapHandlerGen*, MapHandlerGen*)));
connect(m_schnapps, SIGNAL(mapAdded(MapHandlerGen*)), this, SLOT(mapAdded(MapHandlerGen*))); connect(m_schnapps, SIGNAL(mapAdded(MapHandlerGen*)), this, SLOT(mapAdded(MapHandlerGen*)));
connect(m_schnapps, SIGNAL(mapRemoved(MapHandlerGen*)), this, SLOT(mapRemoved(MapHandlerGen*))); connect(m_schnapps, SIGNAL(mapRemoved(MapHandlerGen*)), this, SLOT(mapRemoved(MapHandlerGen*)));
...@@ -47,8 +49,9 @@ bool Surface_Selection_Plugin::enable() ...@@ -47,8 +49,9 @@ bool Surface_Selection_Plugin::enable()
void Surface_Selection_Plugin::disable() void Surface_Selection_Plugin::disable()
{ {
delete m_selectionSphereVBO;
delete m_pointSprite; delete m_pointSprite;
delete m_selectedVerticesVBO;
delete m_selectionSphereVBO;
disconnect(m_schnapps, SIGNAL(selectedViewChanged(View*, View*)), this, SLOT(selectedViewChanged(View*, View*))); disconnect(m_schnapps, SIGNAL(selectedViewChanged(View*, View*)), this, SLOT(selectedViewChanged(View*, View*)));
disconnect(m_schnapps, SIGNAL(selectedMapChanged(MapHandlerGen*, MapHandlerGen*)), this, SLOT(selectedMapChanged(MapHandlerGen*, MapHandlerGen*))); disconnect(m_schnapps, SIGNAL(selectedMapChanged(MapHandlerGen*, MapHandlerGen*)), this, SLOT(selectedMapChanged(MapHandlerGen*, MapHandlerGen*)));
...@@ -64,7 +67,7 @@ void Surface_Selection_Plugin::drawMap(View* view, MapHandlerGen* map) ...@@ -64,7 +67,7 @@ void Surface_Selection_Plugin::drawMap(View* view, MapHandlerGen* map)
{ {
if(map->isSelectedMap()) if(map->isSelectedMap())
{ {
const MapParameters& p = h_viewParameterSet[view][map]; const MapParameters& p = h_parameterSet[map];
if(p.positionAttribute.isValid()) if(p.positionAttribute.isValid())
{ {
unsigned int orbit = m_schnapps->getCurrentOrbit(); unsigned int orbit = m_schnapps->getCurrentOrbit();
...@@ -72,15 +75,20 @@ void Surface_Selection_Plugin::drawMap(View* view, MapHandlerGen* map) ...@@ -72,15 +75,20 @@ void Surface_Selection_Plugin::drawMap(View* view, MapHandlerGen* map)
if(selector) if(selector)
{ {
const std::vector<Dart>& selectedCells = selector->getSelectedCells(); const std::vector<Dart>& selectedCells = selector->getSelectedCells();
switch(orbit)
{
case VERTEX : {
m_pointSprite->setAttributePosition(m_selectedVerticesVBO);
m_pointSprite->setSize(map->getBBdiagSize() / 500.0f);
m_pointSprite->setColor(CGoGN::Geom::Vec4f(1.0f, 0.0f, 0.0f, 1.0f));
m_pointSprite->setLightPosition(CGoGN::Geom::Vec3f(0.0f, 0.0f, 1.0f));
m_drawer->newList(GL_COMPILE_AND_EXECUTE); m_pointSprite->enableVertexAttribs();
m_drawer->pointSize(3.0f); glEnable(GL_BLEND);
m_drawer->color3f(0.0f, 0.0f, 1.0f); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
m_drawer->begin(GL_POINTS); glDrawArrays(GL_POINTS, 0, selectedCells.size());
for(std::vector<Dart>::const_iterator it = selectedCells.begin(); it != selectedCells.end(); ++it) glDisable(GL_BLEND);
m_drawer->vertex(p.positionAttribute[*it]); m_pointSprite->disableVertexAttribs();
m_drawer->end();
m_drawer->endList();
if(m_selecting) if(m_selecting)
{ {
...@@ -89,10 +97,21 @@ void Surface_Selection_Plugin::drawMap(View* view, MapHandlerGen* map) ...@@ -89,10 +97,21 @@ void Surface_Selection_Plugin::drawMap(View* view, MapHandlerGen* map)
m_selectionSphereVBO->updateData(selectionPoint); m_selectionSphereVBO->updateData(selectionPoint);
m_pointSprite->setAttributePosition(m_selectionSphereVBO); m_pointSprite->setAttributePosition(m_selectionSphereVBO);
m_pointSprite->setSize(m_selectionRadius);
m_pointSprite->setColor(CGoGN::Geom::Vec4f(0.0f, 0.0f, 1.0f, 0.5f)); m_pointSprite->setColor(CGoGN::Geom::Vec4f(0.0f, 0.0f, 1.0f, 0.5f));
m_pointSprite->setLightPosition(CGoGN::Geom::Vec3f(0.0f, 0.0f, 1.0f)); m_pointSprite->setLightPosition(CGoGN::Geom::Vec3f(0.0f, 0.0f, 1.0f));
switch(p.selectionMethod)
{
case SingleCell : {
m_pointSprite->setSize(map->getBBdiagSize() / 250.0f);
break;
}
case WithinSphere : {
m_pointSprite->setSize(m_selectionRadius);
break;
}
}
m_pointSprite->enableVertexAttribs(); m_pointSprite->enableVertexAttribs();
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
...@@ -100,6 +119,15 @@ void Surface_Selection_Plugin::drawMap(View* view, MapHandlerGen* map) ...@@ -100,6 +119,15 @@ void Surface_Selection_Plugin::drawMap(View* view, MapHandlerGen* map)
glDisable(GL_BLEND); glDisable(GL_BLEND);
m_pointSprite->disableVertexAttribs(); m_pointSprite->disableVertexAttribs();
} }
break;
}
case EDGE : {
break;
}
case FACE : {
break;
}
}
} }
} }
} }
...@@ -130,8 +158,13 @@ void Surface_Selection_Plugin::mousePress(View* view, QMouseEvent* event) ...@@ -130,8 +158,13 @@ void Surface_Selection_Plugin::mousePress(View* view, QMouseEvent* event)
if(m_selecting && (event->button() == Qt::LeftButton || event->button() == Qt::RightButton)) if(m_selecting && (event->button() == Qt::LeftButton || event->button() == Qt::RightButton))
{ {
MapHandlerGen* mh = m_schnapps->getSelectedMap(); MapHandlerGen* mh = m_schnapps->getSelectedMap();
const MapParameters& p = h_viewParameterSet[view][mh]; const MapParameters& p = h_parameterSet[mh];
if(p.positionAttribute.isValid()) if(p.positionAttribute.isValid())
{
unsigned int orbit = m_schnapps->getCurrentOrbit();
CellSelectorGen* selector = m_schnapps->getSelectedSelector(orbit);
if(selector)
{ {
QPoint pixel(event->x(), event->y()); QPoint pixel(event->x(), event->y());
qglviewer::Vec orig; qglviewer::Vec orig;
...@@ -146,37 +179,46 @@ void Surface_Selection_Plugin::mousePress(View* view, QMouseEvent* event) ...@@ -146,37 +179,46 @@ void Surface_Selection_Plugin::mousePress(View* view, QMouseEvent* event)
Dart d; Dart d;
PFP2::MAP* map = static_cast<MapHandler<PFP2>*>(mh)->getMap(); PFP2::MAP* map = static_cast<MapHandler<PFP2>*>(mh)->getMap();
Algo::Selection::vertexRaySelection<PFP2>(*map, p.positionAttribute, rayA, AB, d);
switch(orbit)
{
case VERTEX : {
Algo::Selection::vertexRaySelection<PFP2>(*map, p.positionAttribute, rayA, AB, d);
if(d != NIL) if(d != NIL)
{ {
switch(p.selectionMethod)
{
case SingleCell : {
if(event->button() == Qt::LeftButton)
selector->select(d);
else if(event->button() == Qt::RightButton)
selector->unselect(d);
break;
}
case WithinSphere : {
Algo::Surface::Selection::Collector_WithinSphere<PFP2> neigh(*map, p.positionAttribute, m_selectionRadius); Algo::Surface::Selection::Collector_WithinSphere<PFP2> neigh(*map, p.positionAttribute, m_selectionRadius);
neigh.collectAll(d); neigh.collectAll(d);
unsigned int orbit = m_schnapps->getCurrentOrbit();
CellSelectorGen* selector = m_schnapps->getSelectedSelector(orbit);
if(selector)
{
if(event->button() == Qt::LeftButton) if(event->button() == Qt::LeftButton)
{ selector->select(neigh.getInsideVertices());
switch(orbit) else if(event->button() == Qt::RightButton)
{ selector->unselect(neigh.getInsideVertices());
case DART: break; break;
case VERTEX: selector->select(neigh.getInsideVertices()); break;
case EDGE: selector->select(neigh.getInsideEdges()); break;
case FACE: selector->select(neigh.getInsideFaces()); break;
} }
} }
else if(event->button() == Qt::RightButton)
{ const std::vector<Dart>& selectedCells = selector->getSelectedCells();
switch(orbit) std::vector<PFP2::VEC3> selectedPoints;
{ for(std::vector<Dart>::const_iterator it = selectedCells.begin(); it != selectedCells.end(); ++it)
case DART: break; selectedPoints.push_back(p.positionAttribute[*it]);
case VERTEX: selector->unselect(neigh.getInsideVertices()); break; m_selectedVerticesVBO->updateData(selectedPoints);
case EDGE: selector->unselect(neigh.getInsideEdges()); break; }
case FACE: selector->unselect(neigh.getInsideFaces()); break; break;
} }
case EDGE : {
break;
}
case FACE : {
break;
} }
} }
} }
...@@ -194,7 +236,7 @@ void Surface_Selection_Plugin::mouseMove(View* view, QMouseEvent* event) ...@@ -194,7 +236,7 @@ void Surface_Selection_Plugin::mouseMove(View* view, QMouseEvent* event)
if(m_selecting) if(m_selecting)
{ {
MapHandlerGen* mh = m_schnapps->getSelectedMap(); MapHandlerGen* mh = m_schnapps->getSelectedMap();
const MapParameters& p = h_viewParameterSet[view][mh]; const MapParameters& p = h_parameterSet[mh];
if(p.positionAttribute.isValid()) if(p.positionAttribute.isValid())
{ {
QPoint pixel(event->x(), event->y()); QPoint pixel(event->x(), event->y());
...@@ -223,6 +265,11 @@ void Surface_Selection_Plugin::mouseMove(View* view, QMouseEvent* event) ...@@ -223,6 +265,11 @@ void Surface_Selection_Plugin::mouseMove(View* view, QMouseEvent* event)
void Surface_Selection_Plugin::wheelEvent(View* view, QWheelEvent* event) void Surface_Selection_Plugin::wheelEvent(View* view, QWheelEvent* event)
{ {
if(m_selecting) if(m_selecting)
{
MapHandlerGen* mh = m_schnapps->getSelectedMap();
const MapParameters& p = h_parameterSet[mh];
if(p.selectionMethod == WithinSphere)
{ {
if(event->delta() > 0) if(event->delta() > 0)
m_selectionRadius *= 0.9f; m_selectionRadius *= 0.9f;
...@@ -230,6 +277,7 @@ void Surface_Selection_Plugin::wheelEvent(View* view, QWheelEvent* event) ...@@ -230,6 +277,7 @@ void Surface_Selection_Plugin::wheelEvent(View* view, QWheelEvent* event)
m_selectionRadius *= 1.1f; m_selectionRadius *= 1.1f;
view->updateGL(); view->updateGL();
} }
}
} }
void Surface_Selection_Plugin::viewLinked(View *view) void Surface_Selection_Plugin::viewLinked(View *view)
...@@ -243,11 +291,6 @@ void Surface_Selection_Plugin::viewLinked(View *view) ...@@ -243,11 +291,6 @@ void Surface_Selection_Plugin::viewLinked(View *view)
void Surface_Selection_Plugin::selectedViewChanged(View *prev, View *cur)
{
m_dockTab->updateMapParameters();
}
void Surface_Selection_Plugin::selectedMapChanged(MapHandlerGen *prev, MapHandlerGen *cur) void Surface_Selection_Plugin::selectedMapChanged(MapHandlerGen *prev, MapHandlerGen *cur)
{ {
m_dockTab->updateMapParameters(); m_dockTab->updateMapParameters();
...@@ -286,8 +329,20 @@ void Surface_Selection_Plugin::changePositionAttribute(const QString& view, cons ...@@ -286,8 +329,20 @@ void Surface_Selection_Plugin::changePositionAttribute(const QString& view, cons
MapHandlerGen* m = m_schnapps->getMap(map); MapHandlerGen* m = m_schnapps->getMap(map);
if(v && m) if(v && m)
{ {
h_viewParameterSet[v][m].positionAttribute = m->getAttribute<PFP2::VEC3, VERTEX>(name); h_parameterSet[m].positionAttribute = m->getAttribute<PFP2::VEC3, VERTEX>(name);
if(v->isSelectedView() && m->isSelectedMap()) if(m->isSelectedMap())
m_dockTab->updateMapParameters();
}
}
void Surface_Selection_Plugin::changeSelectionMethod(const QString& view, const QString& map, unsigned int method)
{
View* v = m_schnapps->getView(view);
MapHandlerGen* m = m_schnapps->getMap(map);
if(v && m)
{
h_parameterSet[m].selectionMethod = SelectionMethod(method);
if(m->isSelectedMap())
m_dockTab->updateMapParameters(); m_dockTab->updateMapParameters();
} }
} }
......
...@@ -17,6 +17,7 @@ Surface_Selection_DockTab::Surface_Selection_DockTab(SCHNApps* s, Surface_Select ...@@ -17,6 +17,7 @@ Surface_Selection_DockTab::Surface_Selection_DockTab(SCHNApps* s, Surface_Select
setupUi(this); setupUi(this);
connect(combo_positionAttribute, SIGNAL(currentIndexChanged(int)), this, SLOT(positionAttributeChanged(int))); connect(combo_positionAttribute, SIGNAL(currentIndexChanged(int)), this, SLOT(positionAttributeChanged(int)));
connect(combo_selectionMethod, SIGNAL(currentIndexChanged(int)), this, SLOT(selectionMethodChanged(int)));
} }
...@@ -27,13 +28,19 @@ void Surface_Selection_DockTab::positionAttributeChanged(int index) ...@@ -27,13 +28,19 @@ void Surface_Selection_DockTab::positionAttributeChanged(int index)
{ {
if(!b_updatingUI) if(!b_updatingUI)
{ {
View* view = m_schnapps->getSelectedView();
MapHandlerGen* map = m_schnapps->getSelectedMap(); MapHandlerGen* map = m_schnapps->getSelectedMap();
if(view && map) if(map)
{ m_plugin->h_parameterSet[map].positionAttribute = map->getAttribute<PFP2::VEC3, VERTEX>(combo_positionAttribute->currentText());
m_plugin->h_viewParameterSet[view][map].positionAttribute = map->getAttribute<PFP2::VEC3, VERTEX>(combo_positionAttribute->currentText());
view->updateGL();
} }
}
void Surface_Selection_DockTab::selectionMethodChanged(int index)
{
if(!b_updatingUI)
{
MapHandlerGen* map = m_schnapps->getSelectedMap();
if(map)
m_plugin->h_parameterSet[map].selectionMethod = SelectionMethod(index);
} }
} }
...@@ -58,12 +65,11 @@ void Surface_Selection_DockTab::updateMapParameters() ...@@ -58,12 +65,11 @@ void Surface_Selection_DockTab::updateMapParameters()
combo_positionAttribute->clear(); combo_positionAttribute->clear();
combo_positionAttribute->addItem("- select attribute -"); combo_positionAttribute->addItem("- select attribute -");
View* view = m_schnapps->getSelectedView();
MapHandlerGen* map = m_schnapps->getSelectedMap(); MapHandlerGen* map = m_schnapps->getSelectedMap();
if(view && map) if(map)
{ {
const MapParameters& p = m_plugin->h_viewParameterSet[view][map]; const MapParameters& p = m_plugin->h_parameterSet[map];
QString vec3TypeName = QString::fromStdString(nameOfType(PFP2::VEC3())); QString vec3TypeName = QString::fromStdString(nameOfType(PFP2::VEC3()));
...@@ -80,6 +86,8 @@ void Surface_Selection_DockTab::updateMapParameters() ...@@ -80,6 +86,8 @@ void Surface_Selection_DockTab::updateMapParameters()
++i; ++i;
} }
} }
combo_selectionMethod->setCurrentIndex(p.selectionMethod);
} }
b_updatingUI = false; b_updatingUI = false;
......
...@@ -32,8 +32,8 @@ public: ...@@ -32,8 +32,8 @@ public:
virtual unsigned int getOrbit() = 0; virtual unsigned int getOrbit() = 0;
virtual void select(Dart d, bool emitSignal) = 0; virtual void select(Dart d, bool emitSignal = true) = 0;
virtual void unselect(Dart d, bool emitSignal) = 0; virtual void unselect(Dart d, bool emitSignal = true) = 0;
inline void select(const std::vector<Dart>& d) inline void select(const std::vector<Dart>& d)
{ {
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include "Topology/generic/functor.h" #include "Topology/generic/functor.h"
#include "Topology/generic/attributeHandler.h" #include "Topology/generic/attributeHandler.h"
//#include "Utils/drawer.h" #include "Utils/drawer.h"
#include "Algo/Render/GL2/mapRender.h" #include "Algo/Render/GL2/mapRender.h"
#include "Algo/Geometry/boundingbox.h" #include "Algo/Geometry/boundingbox.h"
...@@ -55,9 +55,9 @@ public slots: ...@@ -55,9 +55,9 @@ public slots:
Utils::GLSLShader* getBBDrawerShader() const Utils::GLSLShader* getBBDrawerShader() const
{ {
// if(m_bbDrawer) if(m_bbDrawer)
// return m_bbDrawer->getShader(); return m_bbDrawer->getShader();
// else else
return NULL; return NULL;
} }
...@@ -197,7 +197,7 @@ protected: ...@@ -197,7 +197,7 @@ protected:
qglviewer::Vec m_bbMin; qglviewer::Vec m_bbMin;
qglviewer::Vec m_bbMax; qglviewer::Vec m_bbMax;
float m_bbDiagSize; float m_bbDiagSize;
// Utils::Drawer* m_bbDrawer; Utils::Drawer* m_bbDrawer;
Algo::Render::GL2::MapRender* m_render; Algo::Render::GL2::MapRender* m_render;
......
...@@ -75,17 +75,17 @@ void MapHandler<PFP>::draw(Utils::GLSLShader* shader, int primitive) ...@@ -75,17 +75,17 @@ void MapHandler<PFP>::draw(Utils::GLSLShader* shader, int primitive)
template <typename PFP>