Commit c32aa9d5 authored by Pierre Kraemer's avatar Pierre Kraemer

SCHNApps: new surface_radiance plugin

+ add shader RadiancePerVertex in CGoGN
+ add spherical harmonics in CGoGN
parent 562b8f4d
......@@ -31,6 +31,8 @@ find_package(SuiteSparse REQUIRED)
#find_package(SuperLU REQUIRED)
add_definitions(-DWITH_QT)
SET( QT_USE_QTOPENGL TRUE )
SET( QT_USE_QTXML TRUE )
SET( QT_USE_QTDESIGNER TRUE )
......
......@@ -12,6 +12,7 @@ ADD_SUBDIRECTORY(surface_deformation)
ADD_SUBDIRECTORY(surface_modelisation)
#ADD_SUBDIRECTORY(surface_tilings)
ADD_SUBDIRECTORY(surface_distance)
ADD_SUBDIRECTORY(surface_radiance)
ADD_SUBDIRECTORY(volume_import)
#ADD_SUBDIRECTORY(volume_render)
cmake_minimum_required(VERSION 2.8)
SET( PLUGIN_NAME Surface_Radiance )
SET( PLUGIN_ROOT_DIR ${SCHNApps_ROOT_DIR}/Plugins/surface_radiance )
INCLUDE_DIRECTORIES(
${PLUGIN_ROOT_DIR}/include
${CMAKE_CURRENT_BINARY_DIR}
)
file(
GLOB_RECURSE
PLUGIN_FILES
${PLUGIN_ROOT_DIR}/src/*.cpp
${PLUGIN_ROOT_DIR}/include/*.h
${PLUGIN_ROOT_DIR}/include/*.hpp
)
file(
GLOB_RECURSE
PLUGIN_UI_FILES
${PLUGIN_ROOT_DIR}/forms/*.ui
)
SET(
PLUGIN_QOBJECT_FILES
${PLUGIN_ROOT_DIR}/include/surface_radiance.h
${PLUGIN_ROOT_DIR}/include/surface_radiance_dockTab.h
)
include( ${SCHNApps_ROOT_DIR}/Plugins/plugins_cmake.txt )
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Surface_Radiance_TabWidget</class>
<widget class="QWidget" name="Surface_Radiance_TabWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>225</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Position :</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="combo_positionVBO">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>- select VBO -</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Normal :</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="combo_normalVBO">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>- select VBO -</string>
</property>
</item>
</widget>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
#ifndef _SURFACE_RADIANCE_PLUGIN_H_
#define _SURFACE_RADIANCE_PLUGIN_H_
#include "plugin_interaction.h"
#include "surface_radiance_dockTab.h"
#include "Utils/sphericalHarmonics.h"
#include "Utils/Shaders/shaderRadiancePerVertex.h"
#include "Algo/Import/import.h"
#include "Algo/Import/import2tables.h"
namespace CGoGN
{
namespace SCHNApps
{
typedef SphericalHarmonics<PFP2::REAL, PFP2::VEC3> SH_TYPE;
struct MapParameters
{
MapParameters() :
positionVBO(NULL),
normalVBO(NULL),
radianceTexture(NULL),
paramVBO(NULL)
{}
Utils::VBO* positionVBO;
Utils::VBO* normalVBO;
CGoGN::Utils::ShaderRadiancePerVertex* radiancePerVertexShader;
VertexAttribute<SH_TYPE, PFP2::MAP> radiance;
Utils::Texture<2, Geom::Vec3f>* radianceTexture;
VertexAttribute<Geom::Vec2i, PFP2::MAP> param;
Utils::VBO* paramVBO;
};
class Surface_Radiance_Plugin : public PluginInteraction
{
Q_OBJECT
Q_INTERFACES(CGoGN::SCHNApps::Plugin)
friend class Surface_Radiance_DockTab;
public:
Surface_Radiance_Plugin()
{}
~Surface_Radiance_Plugin()
{}
virtual bool enable();
virtual void disable();
virtual void draw(View *view) {}
virtual void drawMap(View* view, MapHandlerGen* map);
virtual void keyPress(View* view, QKeyEvent* event) {}
virtual void keyRelease(View* view, QKeyEvent* event) {}
virtual void mousePress(View* view, QMouseEvent* event) {}
virtual void mouseRelease(View* view, QMouseEvent* event) {}
virtual void mouseMove(View* view, QMouseEvent* event) {}
virtual void wheelEvent(View* view, QWheelEvent* event) {}
virtual void viewLinked(View *view) {}
virtual void viewUnlinked(View *view) {}
private slots:
// slots called from SCHNApps signals
void selectedViewChanged(View* prev, View* cur);
void selectedMapChanged(MapHandlerGen* prev, MapHandlerGen* cur);
void mapAdded(MapHandlerGen* map);
void mapRemoved(MapHandlerGen* map);
// slots called from MapHandler signals
void vboAdded(Utils::VBO* vbo);
void vboRemoved(Utils::VBO* vbo);
void attributeModified(unsigned int orbit, QString nameAttr);
void importFromFileDialog();
public slots:
// slots for Python calls
void changePositionVBO(const QString& map, const QString& vbo);
void changeNormalVBO(const QString& map, const QString& vbo);
MapHandlerGen* importFromFile(const QString& fileName);
protected:
Surface_Radiance_DockTab* m_dockTab;
QHash<MapHandlerGen*, MapParameters> h_mapParameterSet;
QAction* m_importAction;
};
class MeshTablesSurface_Radiance : public CGoGN::Algo::Surface::Import::MeshTablesSurface<PFP2>
{
public:
MeshTablesSurface_Radiance(MAP& m) : MeshTablesSurface<PFP2>(m)
{}
/**
* @brief importPLY
* @param filename: the ply file to be imported. This file is supposed to have a three position, three normal and at least three radiance scalars per vertex.
* @return succeeded
*/
template <typename SH_TYPE>
bool importPLY(const std::string& filename)
{
// Open file
std::ifstream fp(filename, std::ios::in | std::ios::binary) ;
if (!fp.good())
{
CGoGNerr << "Unable to open file " << filename << CGoGNendl ;
return false ;
}
// Read quantities : #vertices, #faces, #properties, degree of polynomials
std::string tag ;
fp >> tag;
if (tag != std::string("ply")) // verify file type
{
CGoGNerr << filename << " is not a ply file !" << CGoGNout ;
return false ;
}
do // go to "format"
{
fp >> tag ;
} while (tag != std::string("format")) ;
fp >> tag ;
bool binary = (tag != "ascii") ;
do // go to #vertices
{
fp >> tag ;
} while (tag != std::string("vertex")) ;
unsigned int nbVertices ;
fp >> nbVertices ; // Read #vertices
bool position = false ;
bool normal = false ;
bool radiance = false ;
unsigned int propSize = 0 ; // for binary read
unsigned int nbProps = 0 ; // # properties
unsigned int nbCoefs = 0 ; // # coefficients
do // go to #faces and count #properties
{
fp >> tag ;
if (tag == std::string("property"))
{
++nbProps ;
}
else if (tag == std::string("int8") || tag == std::string("uint8"))
{
if (propSize < 2)
{
propSize = 1 ;
std::cerr << "only float32 of float64 is yet handled" << std::endl ;
assert(!"only float32 or float64 is yet handled") ;
}
else
{
std::cerr << "only float32 of float64 is yet handled" << std::endl ;
assert(!"only float32 or float64 is yet handled") ;
}
}
else if (tag == std::string("int16") || tag == std::string("uint16"))
{
if (propSize == 0 || propSize == 2)
{
propSize = 2 ;
std::cerr << "only float32 of float64 is yet handled" << std::endl ;
assert(!"only float32 or float64 is yet handled") ;
}
else
{
std::cerr << "only float32 of float64 is yet handled" << std::endl ;
assert(!"only float32 or float64 is yet handled") ;
}
}
else if (tag == std::string("int32") || tag == std::string("float32") || tag == std::string("uint32"))
{
if (propSize == 0 || propSize == 4)
{
propSize = 4 ;
}
else
{
std::cerr << "only float32 of float64 is yet handled" << std::endl ;
assert(!"only float32 or float64 is yet handled") ;
}
}
else if (tag == std::string("int64") || tag == std::string("float64"))
{
if (propSize == 0 || propSize == 8)
{
propSize = 8 ;
}
else
{
std::cerr << "only float32 of float64 is yet handled" << std::endl ;
assert(!"only float32 or float64 is yet handled") ;
}
}
else if (tag == std::string("x") || tag == std::string("y") || tag == std::string("z"))
position = true ;
else if (tag == std::string("nx") || tag == std::string("ny") || tag == std::string("nz"))
normal = true ;
else if (tag.substr(0,6) == std::string("SHcoef"))
{
radiance = true ;
++nbCoefs ;
}
} while (tag != std::string("face")) ;
assert((nbCoefs % 3) == 0 || !"Import only supports RGB SphericalHarmonics (i.e. Tcoef==VEC3)") ;
nbCoefs /= 3 ;
SH_TYPE::set_nb_coefs(nbCoefs) ;
fp >> this->m_nbFaces ; // Read #vertices
do // go to end of header
{
fp >> tag ;
} while (tag != std::string("end_header")) ;
if (binary)
{
char* endline = new char[1] ;
fp.read(endline, sizeof(char)) ;
if (*endline == '\r') // for windows
fp.read(endline, sizeof(char)) ;
assert(*endline == '\n') ;
delete[] endline ;
}
// Define containers
assert((position && normal && radiance) || !"Import: position, normal and radiance attributs should be provided") ;
if (!(position && normal && radiance))
return false ;
VertexAttribute<VEC3, MAP> positions = this->m_map.template checkAttribute<VEC3, VERTEX, MAP>("position") ;
VertexAttribute<VEC3, MAP> normals = this->m_map.template checkAttribute<VEC3, VERTEX, MAP>("normal") ;
VertexAttribute<SH_TYPE, MAP> radiances = this->m_map.template checkAttribute<SH_TYPE, VERTEX, MAP>("radiance") ;
// Read vertices
std::vector<unsigned int> verticesID ;
if (propSize == 4)
{
this->m_nbVertices = readVerticesPLY<float, SH_TYPE>(fp, binary, nbVertices, nbProps, propSize, positions, normals, radiances, verticesID) ;
}
else if (propSize == 8)
{
this->m_nbVertices = readVerticesPLY<double, SH_TYPE>(fp, binary, nbVertices, nbProps, propSize, positions, normals, radiances, verticesID) ;
}
// Read faces index
this->m_nbEdges.reserve(this->m_nbFaces) ;
this->m_emb.reserve(3 * this->m_nbFaces) ;
for (unsigned int i = 0 ; i < this->m_nbFaces ; ++i)
{
// read the indices of vertices for current face
unsigned int nbEdgesForFace ;
if (binary)
{
unsigned char tmp ;
fp.read((char*)&(tmp), sizeof(unsigned char)) ;
nbEdgesForFace = tmp ;
}
else
fp >> nbEdgesForFace ;
this->m_nbEdges.push_back(nbEdgesForFace);
unsigned int vertexID ;
if (binary)
{
for (unsigned int j=0 ; j < nbEdgesForFace ; ++j)
{
fp.read((char*)&vertexID, sizeof(unsigned int)) ;
this->m_emb.push_back(verticesID[vertexID]);
}
}
else
{
for (unsigned int j=0 ; j < nbEdgesForFace ; ++j)
{
fp >> vertexID ;
this->m_emb.push_back(verticesID[vertexID]);
}
}
}
// Close file
fp.close() ;
return true ;
}
private:
/**
* \brief reads the list of vertices in a radiance PLY file. The function is template of the type of arithmetic (float, double) used in the file to be read
* \param fp IN: the file pointer descriptor
* \param binary IN: binary mode for reading fp
* \param nbVertices IN: the number of vertices to read
* \param nbProps IN: the number of properties according to the header
* \param positions IN/OUT: the positions container
* \param normals IN/OUT: the normals container
* \param radiances IN/OUT: the radiances container
* \param verticesID IN/OUT: the vector of vertex IDs
* \return number of vertices readVerticesPLY
*/
template <typename REAL, typename SH_TYPE>
unsigned int readVerticesPLY(
std::ifstream& fp, bool binary,
const unsigned int& nbVertices, const unsigned int& nbProps, const unsigned int& propSize,
VertexAttribute<PFP2::VEC3, PFP2::MAP>& positions,
VertexAttribute<PFP2::VEC3, PFP2::MAP>& normals,
VertexAttribute<SH_TYPE, PFP2::MAP>& radiances,
std::vector<unsigned int>& verticesID
)
{
verticesID.reserve(nbVertices) ;
REAL* properties = new REAL[nbProps] ;
AttributeContainer& container = this->m_map.template getAttributeContainer<VERTEX>() ;
for (unsigned int i = 0 ; i < nbVertices ; ++i) // Read and store properties for current vertex
{
unsigned int id = container.insertLine() ;
verticesID.push_back(id) ;
if (binary)
{
fp.read((char*)properties,nbProps * propSize) ;
}
else
{
for (unsigned int j = 0 ; j < nbProps ; ++j) // get all properties
fp >> properties[j] ;
}
positions[id] = VEC3(properties[0],properties[1],properties[2]) ; // position
normals[id] = VEC3(properties[3],properties[4],properties[5]) ; // normal
int coefno = 6 ;
for (int l = 0 ; l <= SH_TYPE::get_resolution() ; ++l) // radiance
for (int m = -l ; m <= l ; ++m)
{
radiances[id].get_coef(l,m) = VEC3(properties[coefno],properties[coefno+1],properties[coefno+2]) ;
coefno += 3 ;
}
}
this->m_nbVertices = verticesID.size() ;
delete[] properties ;
return verticesID.size() ;
}
};
} // namespace SCHNApps
} // namespace CGoGN
#endif
#ifndef _SURFACE_RADIANCE_DOCK_TAB_H_
#define _SURFACE_RADIANCE_DOCK_TAB_H_
#include "ui_surface_radiance.h"
#include "Utils/vbo.h"
namespace CGoGN
{
namespace SCHNApps
{
class SCHNApps;
class Surface_Radiance_Plugin;
struct MapParameters;
class Surface_Radiance_DockTab : public QWidget, public Ui::Surface_Radiance_TabWidget
{
Q_OBJECT
friend class Surface_Radiance_Plugin;
public:
Surface_Radiance_DockTab(SCHNApps* s, Surface_Radiance_Plugin* p);
private:
SCHNApps* m_schnapps;
Surface_Radiance_Plugin* m_plugin;
MapParameters* m_currentParams;
bool b_updatingUI;
private slots:
void positionVBOChanged(int index);
void normalVBOChanged(int index);
private:
void addPositionVBO(QString name);
void removePositionVBO(QString name);
void addNormalVBO(QString name);
void removeNormalVBO(QString name);
void updateMapParameters();
};
} // namespace SCHNApps
} // namespace CGoGN
#endif
#include "surface_radiance.h"
#include "mapHandler.h"
#include "camera.h"
#include <QFileDialog>
#include <QFileInfo>
namespace CGoGN
{
namespace SCHNApps
{
bool Surface_Radiance_Plugin::enable()
{
// magic line that init static variables of GenericMap in the plugins
GenericMap::copyAllStatics(m_schnapps->getStaticPointers());
m_dockTab = new Surface_Radiance_DockTab(m_schnapps, this);
m_schnapps->addPluginDockTab(this, m_dockTab, "Surface_Radiance");
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(mapAdded(MapHandlerGen*)), this, SLOT(mapAdded(MapHandlerGen*)));
connect(m_schnapps, SIGNAL(mapRemoved(MapHandlerGen*)), this, SLOT(mapRemoved(MapHandlerGen*)));
foreach(MapHandlerGen* map, m_schnapps->getMapSet().values())
mapAdded(map);
m_dockTab->updateMapParameters();
m_importAction = new QAction("import", this);
m_schnapps->addMenuAction(this, "Radiance;Import", m_importAction);
connect(m_importAction, SIGNAL(triggered()), this, SLOT(importFromFileDialog()));
return true;
}
void Surface_Radiance_Plugin::disable()
{
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(mapAdded(MapHandlerGen*)), this, SLOT(mapAdded(MapHandlerGen*)));
disconnect(m_schnapps, SIGNAL(mapRemoved(MapHandlerGen*)), this, SLOT(mapRemoved(MapHandlerGen*)));
foreach(MapHandlerGen* map, m_schnapps->getMapSet().values())
mapRemoved(map);
}
void Surface_Radiance_Plugin::drawMap(View* view, MapHandlerGen* map)
{
const MapParameters& p = h_mapParameterSet[map];
if(p.positionVBO && p.normalVBO)
{
p.radiancePerVertexShader->setAttributePosition(p.positionVBO);
p.radiancePerVertexShader->setAttributeNormal(p.normalVBO);
qglviewer::Vec c = view->getCurrentCamera()->position();
PFP2::VEC3 camera(c.x, c.y, c.z);
p.radiancePerVertexShader->setCamera(camera);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0f, 1.0f);
map->draw(p.radiancePerVertexShader, Algo::Render::GL2::TRIANGLES);
glDisable(GL_POLYGON_OFFSET_FILL);
}
}
void Surface_Radiance_Plugin::selectedViewChanged(View *prev, View *cur)
{
m_dockTab->updateMapParameters();
}
void Surface_Radiance_Plugin::selectedMapChanged(MapHandlerGen *prev, MapHandlerGen *cur)
{
m_dockTab->updateMapParameters();
if (cur == NULL)
m_dockTab->setDisabled(true);
else
m_dockTab->setDisabled(false);
}
void Surface_Radiance_Plugin::mapAdded(MapHandlerGen* map)
{
connect(map, SIGNAL(vboAdded(Utils::VBO*)), this, SLOT(vboAdded(Utils::VBO*)));
connect(map, SIGNAL(vboRemoved(Utils::VBO*)), this, SLOT(vboRemoved(Utils::VBO*)));
connect(map, SIGNAL(attributeModified(unsigned int, QString)), this, SLOT(attributeModified(unsigned int, QString)));
}
void Surface_Radiance_Plugin::mapRemoved(MapHandlerGen* map)
{
disconnect(map, SIGNAL(vboAdded(Utils::VBO*)), this, SLOT(vboAdded(U