- Author
- Laurent Rineau, Sebastien Loriot, Andreas Fabri, Maxime Gimeno
This package regroups the files making the API for creating and adding a new plugin to the Polyhedron_demo.
Understanding the Polyhedron Demo
There are several levels in this demo.
- The
MainWindow
, which contains the UI elements.
- Among these elements is the
Viewer
, which is the drawable surface that handles all the drawing and all the keyboard and mouse events.
- The
Viewer
has a reference to a CGAL::Three::Scene_interface
, which contains a list of all the items (the drawn elements).
A plugin usually make use of objects that inherit from CGAL::Three::Scene_item
or uses some of them to demonstrate a CGAL feature, so it might have to deal with the above elements.
Creating a Simple Plugin
The Plugin Itself
A basic plugin will inherit from CGAL::Three::Polyhedron_demo_plugin_interface
. It must be created in the corresponding folder named after its package, and containing all the files created for the plugin, and a CMakeLists.txt file. Its name must be of the form Xxxx_yyyy_plugin.
The class must contain the following lines :
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
Your plugin must override the three pure virtual functions inherited from Polyhedron_demo_plugin_interface :
- actions() that will hold the actions of the plugin
- applicable() that will decide if the plugin can be used with the current selection of items
- init() that will declare and link the actions of the plugin
The function init() is used just like a constructor. This is where you will connect all the actions, signals and slots of your plugin.
This is also where you will declare the submenu of Operations in which your actions will be displayed.
As a plugin is a QObject, it uses automoc and therefore must contain the line:
#include "Xxxx_yyyy_plugin.moc"
Example :
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
#include <QApplication>
#include <QObject>
#include <QAction>
#include <QMainWindow>
#include <QInputDialog>
#include <QMessageBox>
#include "Messages_interface.h"
class BasicPlugin :
public QObject,
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
public:
bool applicable(QAction*) const Q_DECL_OVERRIDE
{
return true;
}
QList<QAction*> actions() const Q_DECL_OVERRIDE
{
return _actions;
}
{
this->messageInterface = mi;
this->scene = sc;
this->mw = mainWindow;
QAction *actionHelloWorld= new QAction(QString("Hello World"), mw);
actionHelloWorld->setProperty("submenuName", "Basic");
if(actionHelloWorld) {
connect(actionHelloWorld, SIGNAL(triggered()),
this, SLOT(helloWorld()));
_actions << actionHelloWorld;
}
}
private Q_SLOTS:
void helloWorld()
{
messageInterface->information(QString("Hello World!"));
}
private:
QList<QAction*> _actions;
Messages_interface* messageInterface;
QMainWindow* mw;
};
#include "Basic_plugin.moc"
Once you have written your plugin, you must add it to the project using the CMakeLists.txt file.
If you created your plugin in an existing directory, the CMakeLists.txt file already exists. If you created a new directory, you must create it.
The CMakeLists.txt file :
include( polyhedron_demo_macros )
polyhedron_demo_plugin(basic_plugin Basic_plugin)
Adding a Dialog to Your Plugin
This section describes how to add a dialog when an action is triggered.
For a minimalist dialog intended, for instance, to get a single parameter, you can create a QInputDialog
:
void helloWorld()
{
bool ok = false;
const unsigned int parameter =
QInputDialog::getInt((QWidget*)mw,
tr("Hello World"),
tr("Hello dear user! What integer would you want me to display for you ? "),
10,
0,
100,
1,
&ok);
if(!ok) return;
messageInterface->information(QString("You asked me to display %1, so here it is : %1").arg(parameter));
}
For a more elaborate interface, you will have to use the designer tool of QtCreator. Create a new Qt Designer form (file->New file or Project->Qt->).
Then select among the template/form choices.
Name it Xxxx_yyyy_dialog.ui (you may have to rename it once it is created as QtCreator tends to forget the capital letters), and add it to the project in the CMakeLists :
qt5_wrap_ui( basicUI_FILES Basic_dialog.ui )
polyhedron_demo_plugin(basic_plugin Basic_plugin ${basicUI_FILES})
Add a layout to the dialog with a drag and drop and lay it out.
Edit the ui file with the editor.
then add the following line to your plugin file:
#include "ui_Xxxx_yyyy_plugin.h"
You can then add a new class to your cpp file, inheriting from QDialog
and your own dialog, accessible with "Ui::".
Add the macro Q_OBJECT
and the line setupUi(this)
in your constructor.
class ComplexDialog :
public QDialog,
public Ui::BasicDialog
{
Q_OBJECT
public:
ComplexDialog(QWidget* =0)
{
setupUi(this);
}
};
You can populate the dialog in the action, using dialog.show()
or dialog.exec()
.
void helloWorld()
{
ComplexDialog *dialog = new ComplexDialog();
if(!dialog->exec())
return;
QString result = dialog->lineEdit->text();
bool ok = false;
int int_res = result.toInt(&ok);
if(!ok)
{
QMessageBox::warning(mw,
"ERROR",
tr("This is not an integer !")
);
return;
}
messageInterface->information(QString("You asked me to display %1, so here it is : %1").arg(int_res));
}
Adding a Warning/Error Box to Your Plugin
It is really simple to add a pop-up box with Qt. Use a QMessageBox and give it some arguments :
QString result = dialog->lineEdit->text();
bool ok = false;
int int_res = result.toInt(&ok);
if(!ok)
{
QMessageBox::warning(mw,
"ERROR",
tr("This is not an integer !")
);
return;
}
Adding a Dock Widget
This section describes how to add a dock widget to the application.
You can make your plugin inherit from CGAL::Three::Polyhedron_demo_plugin_helper, which gives acces to the function CGAL::Three::Polyhedron_demo_plugin_helper::addDockWidget. This will manage automatically the position and tabification of a dock widget.
Just like with the Dialog, create a new Qt Designer form (file->New file or Project->Qt->Qt Designer Form), choose `QDockWidget in Widgets
Add it to the project in the CMakeLists.txt :
qt5_wrap_ui( dockUI_FILES Basic_dock_widget.ui )
polyhedron_demo_plugin(dock_widget_plugin Dock_widget_plugin ${dockUI_FILES})
Edit the ui file with the editor, then add the following line to your plugin file:
#include "ui_Basic_dock_widget.h"
As for the Dialog, create a new class for your widget
class DockWidget :
public QDockWidget,
public Ui::BasicDockWidget
{
public:
DockWidget(QString name, QWidget *parent)
:QDockWidget(name,parent)
{
setupUi(this);
}
};
and add a reference to an object of this type as private members of your plugin:
private:
DockWidget* dock_widget;
and initialize it in the init function, where you will also use signal/slots to connect it to the plugin:
{
this->messageInterface = mi;
this->scene = sc;
this->mw = mw;
QAction *actionHelloWorld= new QAction(QString("Open Dock Widget"), mw);
actionHelloWorld->setProperty("submenuName", "Basic");
if(actionHelloWorld) {
connect(actionHelloWorld, SIGNAL(triggered()),
this, SLOT(helloWorld()));
_actions << actionHelloWorld;
}
dock_widget = new DockWidget("Print a number", mw);
dock_widget->setVisible(false);
addDockWidget(dock_widget);
connect(dock_widget->pushButton, SIGNAL(clicked(bool)),
this, SLOT(on_dock_button_clicked()));
}
You can use the functions show()
/hide()
to make your dock widget visible or not.
void helloWorld()
{
if(dock_widget->isVisible()) { dock_widget->hide(); }
else { dock_widget->show(); }
}
void on_dock_button_clicked()
{
messageInterface->information(QString("Here is your number :%1").arg(dock_widget->spinBox->value()));
}
By default, a dock widget will remain visible next time the demo is launched if it has not been closed. If you want to avoid that behavior, override the function closure()
in you plugin, and simply call hide()
on your dock widget in it.
void closure()Q_DECL_OVERRIDE
{
dock_widget->hide();
}
Using a Scene_item
Using an existing item
You can get a reference to the items present in the scene in your plugin. To do so, you will need to use the reference to the scene that you can get in the init() function :
This Scene_interface will give you access to the following functions :
that give you access to any item in the scene.
Example of use :
messageInterface->information(QString("The selected item's name is : %1").arg(item->name()));
Don't forget to adapt your applicable() function :
bool applicable(QAction*) const Q_DECL_OVERRIDE
{
return scene->selectionIndices().size() ==1;
}
Creating an item of an existing type
You might want your plugin to create a new item. This is possible thanks to the scene.
Simply create a new instance of the item you want and call the function CGAL::Three::Scene_interface::addItem :
Scene_plane_item *new_item = new Scene_plane_item(scene);
new_item->setName("Trivial Plane");
new_item->setColor(Qt::blue);
new_item->setNormal(0.0,0.0,1.0);
scene->addItem(new_item);
Once your code is written, you will need to link the item's library to your plugin thanks to the CMakeLists, using the command target_link_library :
polyhedron_demo_plugin(basic_item_plugin Basic_item_plugin)
# links the library containing the scene_plane_item with the plugin
target_link_libraries(basic_item_plugin PUBLIC scene_basic_objects)
Creating a new type of item
If you cannot use an existing type of item, like the Scene_polyhedron_item or the Scene_c3t3_item for your plugin, you will have to create one, by deriving CGAL::Three::Scene_item.
An item is simply a graphic representation of a geometric data set. You need to compute this data, and to display it in CGAL::Three::Scene_item::draw.
#ifdef scene_triangle_item_EXPORTS
# define SCENE_TRIANGLE_ITEM_EXPORT Q_DECL_EXPORT
#else
# define SCENE_TRIANGLE_ITEM_EXPORT Q_DECL_IMPORT
#endif
{
Q_OBJECT
public :
Scene_triangle_item(double ax,double ay, double az,
double bx,double by, double bz,
double cx,double cy, double cz);
bool supportsRenderingMode(
RenderingMode m)
const Q_DECL_OVERRIDE {
}
void invalidateOpenGLBuffers() Q_DECL_OVERRIDE;
void computeElements(double ax,double ay, double az,
double bx,double by, double bz,
double cx,double cy, double cz) const Q_DECL_OVERRIDE;
Scene_item* clone() const Q_DECL_OVERRIDE {return 0;}
QString toolTip() const Q_DECL_OVERRIDE {return QString();}
private:
mutable std::vector<float> vertices;
mutable int nb_pos;
mutable QOpenGLShaderProgram *program;
};
The minimalist item above is designed to draw a simple triangle. There are several steps that need to be followed when creating an item :
- Computing the data
One way to store the data you computed is to use member std::vector. It must be done every time a change occurs in the item's geometry (usually done in a function called invalidateOpenGLBuffers).
void Scene_triangle_item::computeElements(double ax, double ay, double az,
double bx, double by, double bz,
double cx, double cy, double cz)const
{
vertices.resize(9);
vertices[0] = ax; vertices[1] = ay; vertices[2] = az;
vertices[3] = bx; vertices[4] = by; vertices[5] = bz;
vertices[6] = cx; vertices[7] = cy; vertices[8] = cz;
}
- Filling the OpenGL buffers
The application uses OpenGL VBOs to display the geometry. Those are buffers that will stream their data to the GPU. This step consists to put the data stored in the std::vector in those buffers. In this exemple, we only need one VBO and one VAO, as we are only storing one kind of data. But if we wanted to store normals and colors, for instance, we would need as much VBOs, and if there were several types of display, let's say multiple RenderingMode, we would need as much VAOs. (See OpenGL doc about VBOs/VAOs for more details).
{
{
program = getShaderProgram(PROGRAM_WITH_LIGHT, viewer);
program->bind();
vaos[0]->bind();
buffers[0].bind();
buffers[0].allocate(vertices.data(),
static_cast<GLsizei>(vertices.size()*sizeof(float)));
program->enableAttributeArray("vertex");
program->setAttributeBuffer("vertex",GL_FLOAT,0,3);
buffers[0].release();
vaos[0]->release();
program->release();
}
nb_pos = vertices.size();
vertices.resize(0);
std::vector<float>(vertices).swap(vertices);
are_buffers_filled = true;
}
The code above gets a ShaderProgram, that holds the characteristics of the display (here a basic lighting), binds its VAO and VBO and gives it the data.
- Displaying the data
Originally, it's the viewer that requires displaying. It calls the scene, that calls each visible item's draw(),drawEdges() and drawPoints() functions individually. Therefore, this is in those functions that the display of the data must be handled :
{
if(!are_buffers_filled)
{
computeElements(0, 0, 0,
1, 0, 0,
0.5, 0.5, 0);
initializeBuffers(viewer);
}
vaos[0]->bind();
program = getShaderProgram(PROGRAM_WITH_LIGHT);
attribBuffers(viewer, PROGRAM_WITH_LIGHT);
program->bind();
program->setAttributeValue("colors", this->color());
viewer->glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(nb_pos/3));
vaos[0]->release();
program->release();
}
To display, you need to call the same program that got configured previously, and to bind it before you call the OpenGL drawing function.
If you created your item in a specific file and you need to use it outside your plugin (like in another plugin), it is recommended to put it in the demo's root directory, and you will have to define your item in the general Polyhedron_demo's CMakeLists.txt by using the macro add_item :
add_item(scene_trivial_item Scene_trivial_item.cpp)
target_link_libraries(scene_trivial_item PUBLIC scene_dependances_item)
Using a Scene_group_item
This section will explain how to use a group item in a plugin.
A group item is a virtual item that is not seen in the viewer, nor drawn, but acts as a parent for a list of actual items. Its main goal lies within the interaction with the SceneView
(which is the list of items on the left of the viewer). With group items, this view becomes hierarchic, which allows to interact with several objects at the same time, and organize this view.
To use a group item in your plugin, you will need a CGAL::Three::Scene_group_item
, of course, and a CGAL::Three::Scene_interface
.
Create a new Scene_group_item
, add it to the scene with CGAL::Three::Scene_interface::addItem()
and give it the items you want to regroup with CGAL::Three::Scene_interface::changeGroup()
.
Keep in mind that you must pass items to a group only if those items are already in the scene.
You also have the possibility to "lock" a child of a group with CGAL::Three::Scene_group_item::lockChild()
to prevent it from being moved or erased.
Scene_group_item *group = new Scene_group_item("New group");
scene->addItem(group);
scene->changeGroup(item, group);
scene->changeGroup(new_item,group);
Creating an IO Plugin
An IO plugin is a plugin desined to load from and save to a certain type of file. Its name is generally of the form Xxxx_yyyy_io_plugin
It inherits from the CGAL::Three::Polyhedron_demo_io_plugin_interface. It must implement the following functions :
Creating an External Plugin
An external plugin is a plugin that is written in any directory but the official Plugin directory, and which will not be automatically loaded along with the others. To create an external plugin, you must make a new Cmake project.
project( Example_plugin )
Configure CMake as you desire and fetch the right Qt5 packages :
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)
cmake_minimum_required(VERSION 3.1)
#Find CGAL
find_package(CGAL COMPONENTS Qt5)
include( ${CGAL_USE_FILE} )
# Find Qt5 itself
find_package(Qt5
QUIET
COMPONENTS OpenGL Script Svg Xml
OPTIONAL_COMPONENTS ScriptTools)
You will probably have to fetch the libraries exported by the Polyhedron_demo, like the Scene_items.
find_package(CGAL_polyhedron_demo
HINTS "${CGAL_DIR}" "${CGAL_DIR}/Polyhedron/demo/Polyhedron-build"
)
include( ${CGAL_POLYHEDRON_DEMO_USE_FILE} )
Be careful, the polyhedron_demo build directory must contain a build of the demo that comes from the same CGAL version than the one of your CGAL_DIR. Finally, you can declare your plugin
polyhedron_demo_plugin(example_plugin Example_plugin)
If you need targets from the Polyhedron_demo, you will have to add the prefix 'Polyhedron_' to the target's name, as the exported targets belong to the namespace Polyhedron_
polyhedron_demo_plugin(basic_item_plugin Basic_item_plugin)
target_link_libraries(basic_item_plugin PUBLIC Polyhedron_scene_basic_objects)
Notice that an external plugin will not be automatically loaded in the Polyhedron demo. It must be built in its own project.
Complete CMakeLists :
project( Example_plugin )
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)
cmake_minimum_required(VERSION 3.1)
#Find CGAL
find_package(CGAL COMPONENTS Qt5)
include( ${CGAL_USE_FILE} )
# Find Qt5 itself
find_package(Qt5
QUIET
COMPONENTS OpenGL Script Svg Xml
OPTIONAL_COMPONENTS ScriptTools)
if(Qt5_FOUND AND CGAL_FOUND)
find_package(CGAL_polyhedron_demo)
include( ${CGAL_POLYHEDRON_DEMO_USE_FILE} )
# Let plugins be compiled in the same directory as the executable.
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
polyhedron_demo_plugin(example_plugin Example_plugin)
endif()
Examples
All the examples have been constructed as external plugins in CGAL/Three/demo/Three/Example_plugin. You will have to use "Load plugin" in the File menu or set the environment variable POLYHEDRON_DEMO_PLUGINS_PATH if you want to test it.
Creating a Basic Plugin
File Three/Example_plugin/Basic_plugin.cpp
#define EXAMPLE_COMPLEXITY 0
#include "ui_Basic_dialog.h"
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
#include <QApplication>
#include <QObject>
#include <QAction>
#include <QMainWindow>
#include <QInputDialog>
#include <QMessageBox>
#include "Messages_interface.h"
class ComplexDialog :
public QDialog,
public Ui::BasicDialog
{
Q_OBJECT
public:
ComplexDialog(QWidget* =0)
{
setupUi(this);
}
};
class BasicPlugin :
public QObject,
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
public:
bool applicable(QAction*) const Q_DECL_OVERRIDE
{
return true;
}
QList<QAction*> actions() const Q_DECL_OVERRIDE
{
return _actions;
}
{
this->messageInterface = mi;
this->scene = sc;
this->mw = mainWindow;
QAction *actionHelloWorld= new QAction(QString("Hello World"), mw);
actionHelloWorld->setProperty("submenuName", "Basic");
if(actionHelloWorld) {
connect(actionHelloWorld, SIGNAL(triggered()),
this, SLOT(helloWorld()));
_actions << actionHelloWorld;
}
}
private Q_SLOTS:
#if EXAMPLE_COMPLEXITY == 0
void helloWorld()
{
messageInterface->information(QString("Hello World!"));
}
#elif EXAMPLE_COMPLEXITY == 1
void helloWorld()
{
bool ok = false;
const unsigned int parameter =
QInputDialog::getInt((QWidget*)mw,
tr("Hello World"),
tr("Hello dear user! What integer would you want me to display for you ? "),
10,
0,
100,
1,
&ok);
if(!ok) return;
messageInterface->information(QString("You asked me to display %1, so here it is : %1").arg(parameter));
}
#elif EXAMPLE_COMPLEXITY == 2
void helloWorld()
{
ComplexDialog *dialog = new ComplexDialog();
if(!dialog->exec())
return;
QString result = dialog->lineEdit->text();
bool ok = false;
int int_res = result.toInt(&ok);
if(!ok)
{
QMessageBox::warning(mw,
"ERROR",
tr("This is not an integer !")
);
return;
}
messageInterface->information(QString("You asked me to display %1, so here it is : %1").arg(int_res));
}
#endif
private:
QList<QAction*> _actions;
Messages_interface* messageInterface;
QMainWindow* mw;
};
#include "Basic_plugin.moc"
Creating a DockWidget
File Three/Example_plugin/Dock_widget_plugin.cpp
#include "ui_Basic_dock_widget.h"
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
#include <QApplication>
#include <QObject>
#include <QAction>
#include <QMainWindow>
#include "Messages_interface.h"
class DockWidget :
public QDockWidget,
public Ui::BasicDockWidget
{
public:
DockWidget(QString name, QWidget *parent)
:QDockWidget(name,parent)
{
setupUi(this);
}
};
class BasicPlugin :
public QObject,
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
public:
bool applicable(QAction*) const Q_DECL_OVERRIDE
{
return true;
}
QList<QAction*> actions() const Q_DECL_OVERRIDE
{
return _actions;
}
{
this->messageInterface = mi;
this->scene = sc;
this->mw = mw;
QAction *actionHelloWorld= new QAction(QString("Open Dock Widget"), mw);
actionHelloWorld->setProperty("submenuName", "Basic");
if(actionHelloWorld) {
connect(actionHelloWorld, SIGNAL(triggered()),
this, SLOT(helloWorld()));
_actions << actionHelloWorld;
}
dock_widget = new DockWidget("Print a number", mw);
dock_widget->setVisible(false);
addDockWidget(dock_widget);
connect(dock_widget->pushButton, SIGNAL(clicked(bool)),
this, SLOT(on_dock_button_clicked()));
}
private Q_SLOTS:
void helloWorld()
{
if(dock_widget->isVisible()) { dock_widget->hide(); }
else { dock_widget->show(); }
}
void on_dock_button_clicked()
{
messageInterface->information(QString("Here is your number :%1").arg(dock_widget->spinBox->value()));
}
void closure()Q_DECL_OVERRIDE
{
dock_widget->hide();
}
private:
QList<QAction*> _actions;
Messages_interface* messageInterface;
DockWidget* dock_widget;
};
#include "Dock_widget_plugin.moc"
Using an Existing Item and Create a New Item of an Existing Type
File Three/Example_plugin/Basic_item_plugin.cpp
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
#include <QApplication>
#include <QObject>
#include <QAction>
#include <QMainWindow>
#include <QInputDialog>
#include "Messages_interface.h"
#include "CGAL/Three/Scene_group_item.h"
#include "Scene_plane_item.h"
class BasicItemPlugin :
public QObject,
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
public:
bool applicable(QAction*) const Q_DECL_OVERRIDE
{
return scene->selectionIndices().size() ==1;
}
QList<QAction*> actions() const Q_DECL_OVERRIDE
{
return _actions;
}
{
this->messageInterface = mi;
this->scene = sc;
this->mw = mw;
QAction *actionHelloWorld= new QAction(QString("Create a group"), mw);
actionHelloWorld->setProperty("submenuName", "Basic");
if(actionHelloWorld) {
connect(actionHelloWorld, SIGNAL(triggered()),
this, SLOT(helloWorld()));
_actions << actionHelloWorld;
}
}
private Q_SLOTS:
void helloWorld()
{
messageInterface->information(QString("The selected item's name is : %1").arg(item->name()));
Scene_plane_item *new_item = new Scene_plane_item(scene);
new_item->setName("Trivial Plane");
new_item->setColor(Qt::blue);
new_item->setNormal(0.0,0.0,1.0);
scene->addItem(new_item);
Scene_group_item *group = new Scene_group_item("New group");
scene->addItem(group);
scene->changeGroup(item, group);
scene->changeGroup(new_item,group);
}
private:
QList<QAction*> _actions;
Messages_interface* messageInterface;
QMainWindow* mw;
};
#include "Basic_item_plugin.moc"
Creating a new Type of Item
File Three/Example_plugin/Example_plugin.cpp
#include <QApplication>
#include <QMainWindow>
#include <QAction>
#include <QVector>
#include <CGAL/Three/Scene_item.h>
#include <CGAL/Three/Viewer_interface.h>
#include <CGAL/Three/Scene_group_item.h>
#ifdef scene_triangle_item_EXPORTS
# define SCENE_TRIANGLE_ITEM_EXPORT Q_DECL_EXPORT
#else
# define SCENE_TRIANGLE_ITEM_EXPORT Q_DECL_IMPORT
#endif
{
Q_OBJECT
public :
Scene_triangle_item(double ax,double ay, double az,
double bx,double by, double bz,
double cx,double cy, double cz);
bool supportsRenderingMode(
RenderingMode m)
const Q_DECL_OVERRIDE {
}
void invalidateOpenGLBuffers() Q_DECL_OVERRIDE;
void computeElements(double ax,double ay, double az,
double bx,double by, double bz,
double cx,double cy, double cz) const Q_DECL_OVERRIDE;
Scene_item* clone() const Q_DECL_OVERRIDE {return 0;}
QString toolTip() const Q_DECL_OVERRIDE {return QString();}
private:
mutable std::vector<float> vertices;
mutable int nb_pos;
mutable QOpenGLShaderProgram *program;
};
Scene_triangle_item::Scene_triangle_item(double ax,double ay, double az,
double bx,double by, double bz,
double cx,double cy, double cz)
:
CGAL::Three::Scene_item(1,1)
{
nb_pos = 0;
are_buffers_filled = false;
computeElements(ax, ay, az,
bx, by, bz,
cx, cy, cz);
invalidateOpenGLBuffers();
}
void Scene_triangle_item::computeElements(double ax, double ay, double az,
double bx, double by, double bz,
double cx, double cy, double cz)const
{
vertices.resize(9);
vertices[0] = ax; vertices[1] = ay; vertices[2] = az;
vertices[3] = bx; vertices[4] = by; vertices[5] = bz;
vertices[6] = cx; vertices[7] = cy; vertices[8] = cz;
}
{
if(!are_buffers_filled)
{
computeElements(0, 0, 0,
1, 0, 0,
0.5, 0.5, 0);
initializeBuffers(viewer);
}
vaos[0]->bind();
program = getShaderProgram(PROGRAM_WITH_LIGHT);
attribBuffers(viewer, PROGRAM_WITH_LIGHT);
program->bind();
program->setAttributeValue("colors", this->color());
viewer->glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(nb_pos/3));
vaos[0]->release();
program->release();
}
void Scene_triangle_item::invalidateOpenGLBuffers()
{
are_buffers_filled = false;
}
{
{
program = getShaderProgram(PROGRAM_WITH_LIGHT, viewer);
program->bind();
vaos[0]->bind();
buffers[0].bind();
buffers[0].allocate(vertices.data(),
static_cast<GLsizei>(vertices.size()*sizeof(float)));
program->enableAttributeArray("vertex");
program->setAttributeBuffer("vertex",GL_FLOAT,0,3);
buffers[0].release();
vaos[0]->release();
program->release();
}
nb_pos = vertices.size();
vertices.resize(0);
std::vector<float>(vertices).swap(vertices);
are_buffers_filled = true;
}
#include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
class Q_DECL_EXPORT Polyhedron_demo_example_plugin :
public QObject,
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
public :
this->scene = scene_interface;
this->mw = mainWindow;
QAction* actionDrawTriangle= new QAction("Draw Triangle", mw);
if(actionDrawTriangle) {
connect(actionDrawTriangle, SIGNAL(triggered()),
this, SLOT(draw_triangle()));
_actions << actionDrawTriangle;
}
}
bool applicable(QAction*) const Q_DECL_OVERRIDE
{
return true;
}
QList<QAction*> actions() const Q_DECL_OVERRIDE{
return _actions;
}
public Q_SLOTS:
void draw_triangle() {
triangle = new Scene_triangle_item(0, 0, 0,
1, 0, 0,
0.5, 0.5, 0);
triangle->setName(QString("Basic triangle"));
scene->addItem(triangle);
}
private:
QList<QAction*> _actions;
};
#include "Example_plugin.moc"