Commit b122ba2e authored by Simon Boyé's avatar Simon Boyé

Vitelotte: Started refactoring (QMesh, QMeshRenderer) + gl_viewer example.

parent 4ab5c275
......@@ -126,7 +126,7 @@ void FemSolver::initMatrices()
// 'Magic' initialization of base matrices for quadratic elements.
// See Paul Tsipouras, Compact representation of triangular finite
// elements for Poisson's equation, International Journal for
// Numerical Methods in Engineering, Volume 11, Issue 3, pages 419430,
// Numerical Methods in Engineering, Volume 11, Issue 3, pages 419-430,
// 1977
const FemScalar _1_6 = 1. / 6.;
......
This diff is collapsed.
inline unsigned QMesh::parseIndicesList(const std::string& _list, unsigned* _indices, unsigned _maxSize)
{
unsigned nbIndices = 1;
std::string split(_list);
for(std::string::iterator c = split.begin(); c != split.end(); ++c)
{
if(*c == '/')
{
*c = ' ';
++nbIndices;
}
}
assert(nbIndices <= _maxSize);
std::istringstream in(split);
for(unsigned i = 0; i < nbIndices; ++i)
{
if(in.eof() || in.fail())
{
return 0;
}
in >> _indices[i];
}
if(!in.eof() || in.fail())
{
return 0;
}
return nbIndices;
}
#define QVG_CHECK_PARSE_ERROR() \
do\
{\
in >> std::ws;\
if(in.fail() || in.bad() || in.eof())\
{\
if(in.eof())\
throw QvgParseError("Unexpected end of file.");\
else\
throw QvgParseError("Error while parsing. File probably malformed.");\
}\
} while(false)
inline void QMesh::loadQvgFromFile(const std::string& _filename)
{
getValid() = false;
std::ifstream in(_filename.c_str());
if(!in.good())
{
throw QvgParseError("Unable to read file.");
}
// Check header validity
std::string tmpStr;
in >> tmpStr;
if(in.fail() && tmpStr != "qvg")
{
throw QvgParseError("Not a QVG file.");
}
QVG_CHECK_PARSE_ERROR();
in >> tmpStr;
if(!in.fail() && tmpStr != "1.0")
{
throw QvgParseError("Unsupported version "+tmpStr+".");
}
QVG_CHECK_PARSE_ERROR();
//Check sizes
unsigned nbVertices;
unsigned nbNodes;
unsigned nbCurves;
unsigned nbTriangles;
in >> nbVertices >> nbNodes >> nbCurves >> nbTriangles;
QVG_CHECK_PARSE_ERROR();
getVertices().resize(nbVertices);
getNodes().resize(nbNodes);
getCurves().resize(nbCurves);
getTriangles().resize(nbTriangles);
getSingularTriangles().resize(nbTriangles);
//Read body
// Vertices
for(unsigned i = 0; i < nbVertices; ++i)
{
in >> tmpStr;
if(!in.fail() && tmpStr != "v")
{
throw QvgParseError("Expected a vertex, got \""+tmpStr+"\".");
}
QMesh::VertexList& vertices = getVertices();
in >> vertices[i](0) >> vertices[i](1);
getBoundingBox().extend(vertices[i]);
QVG_CHECK_PARSE_ERROR();
}
//Nodes
for(unsigned i = 0; i < nbNodes; ++i)
{
in >> tmpStr;
if(!in.fail() && tmpStr != "n")
{
throw QvgParseError("Expected a node, got \""+tmpStr+"\".");
}
QMesh::NodeList& nodes = getNodes();
in >> nodes[i][0] >> nodes[i][1] >> nodes[i][2] >> nodes[i][3];
QVG_CHECK_PARSE_ERROR();
}
// Curves
for(unsigned i = 0; i < nbCurves; ++i)
{
in >> tmpStr;
if(!in.fail() && tmpStr != "cc" && tmpStr != "cq")
{
throw QvgParseError("Expected a curve, got \""+tmpStr+"\".");
}
QMesh::CurveList& curves = getCurves();
if(tmpStr == "cc")
{
in >> curves[i].first[0] >> curves[i].first[1] >> curves[i].second[0] >> curves[i].second[1];
}
else
{
in >> curves[i].first[0] >> curves[i].first[1];
curves[i].second = curves[i].first;
}
QVG_CHECK_PARSE_ERROR();
}
// Faces
unsigned tmpIndices[3];
unsigned triangleIndex = 0;
unsigned singularIndex = 0;
QMesh::TriangleList& triangles = getTriangles();
QMesh::SingularTriangleList& singularTriangles = getSingularTriangles();
for(unsigned fi = 0; fi < nbTriangles; ++fi)
{
in >> tmpStr;
if(!in.fail() && tmpStr != "f" && tmpStr != "fs")
{
throw QvgParseError("Expected a face, got \""+tmpStr+"\".");
}
QVG_CHECK_PARSE_ERROR();
bool singular = (tmpStr == "fs");
// read vertex and vertex nodes
int singularVx = -1;
for(unsigned vi = 0; vi < 3; ++vi)
{
in >> tmpStr;
QVG_CHECK_PARSE_ERROR();
unsigned read = parseIndicesList(tmpStr, tmpIndices, 3);
if(!singular)
{
if(read != 2)
{
throw QvgParseError("Unexpected number of vertex index.");
}
triangles[triangleIndex].vertex(vi) = tmpIndices[0];
triangles[triangleIndex].vxNode(vi) = tmpIndices[1];
}
else
{
if(read != 2 && read != 3)
{
throw QvgParseError("Unexpected number of vertex indices.");
}
singularTriangles[singularIndex].vertex(vi) = tmpIndices[0];
singularTriangles[singularIndex].vxNode(vi) = tmpIndices[1];
if(read == 3)
{
if(singularVx != -1)
{
throw QvgParseError("Error: face with several singular vertices.");
}
singularTriangles[singularIndex].vxNode(3) = tmpIndices[2];
singularVx = vi;
}
}
}
if(singular && singularVx == -1)
{
throw QvgParseError("Error: singular triangle without singular node.");
}
// Read egde nodes
for(unsigned ei = 0; ei < 3; ++ei)
{
in >> tmpStr;
if(fi != nbTriangles - 1 || ei != 2)
{
QVG_CHECK_PARSE_ERROR();
}
else if(in.fail() || in.bad())
{
throw QvgParseError("Error while parsing. File probably malformed.");
}
unsigned read = parseIndicesList(tmpStr, tmpIndices, 3);
if(read != 1 && read != 2)
{
throw QvgParseError("Unexpected number of edge indices.");
}
if(!singular)
{
triangles[triangleIndex].edgeNode(ei) = tmpIndices[0];
}
else
{
singularTriangles[singularIndex].edgeNode(ei) = tmpIndices[0];
}
}
// Cyclic permutation so singular vertex is 0
if(singularVx != -1)
{
std::rotate(singularTriangles[singularIndex].m_vertices, singularTriangles[singularIndex].m_vertices + singularVx, singularTriangles[singularIndex].m_vertices + 3);
std::rotate(singularTriangles[singularIndex].m_nodes, singularTriangles[singularIndex].m_nodes + singularVx, singularTriangles[singularIndex].m_nodes + 3);
std::rotate(singularTriangles[singularIndex].m_nodes + 4, singularTriangles[singularIndex].m_nodes + 4 + singularVx, singularTriangles[singularIndex].m_nodes + 7);
}
if(!singular)
{
++triangleIndex;
}
else
{
++singularIndex;
}
}
triangles.resize(triangleIndex);
singularTriangles.resize(singularIndex);
getValid() = true;
in >> std::ws;
if(!in.eof())
{
throw QvgParseError("Error: expected end of file.");
}
}
inline void QMesh::dumpQvg(std::ostream& _out)
{
//assert(isValid());
_out << "Vertices : " << nbVertices() << "\n";
for(unsigned i = 0; i < nbVertices(); ++i)
{
_out << " " << getVertices()[i].transpose() << "\n";
}
_out << "Nodes : " << nbNodes() << "\n";
for(unsigned i = 0; i < nbNodes(); ++i)
{
_out << " " << getNodes()[i].transpose() << "\n";
}
_out << "Edges : " << nbCurves() << "\n";
for(unsigned i = 0; i < nbCurves(); ++i)
{
_out << " " << getCurves()[i].first.transpose() << " / " << getCurves()[i].second.transpose() << "\n";
}
_out << "Triangles : " << nbTriangles() << "\n";
for(unsigned i = 0; i < nbTriangles(); ++i)
{
_out << " "
<< getTriangles()[i].vertex(0) << " "
<< getTriangles()[i].vertex(1) << " "
<< getTriangles()[i].vertex(2) << " / "
<< getTriangles()[i].vxNode(0) << " "
<< getTriangles()[i].vxNode(1) << " "
<< getTriangles()[i].vxNode(2) << " / "
<< getTriangles()[i].edgeNode(0) << " "
<< getTriangles()[i].edgeNode(1) << " "
<< getTriangles()[i].edgeNode(2) << "\n";
}
_out << "Singular triangles: " << nbSingularTriangles() << "\n";
for(unsigned i = 0; i < nbSingularTriangles(); ++i)
{
_out << " "
<< getSingularTriangles()[i].vertex(0) << " "
<< getSingularTriangles()[i].vertex(1) << " "
<< getSingularTriangles()[i].vertex(2) << " / "
<< getSingularTriangles()[i].vxNode(0) << " "
<< getSingularTriangles()[i].vxNode(1) << " "
<< getSingularTriangles()[i].vxNode(2) << " "
<< getSingularTriangles()[i].vxNode(3) << " / "
<< getSingularTriangles()[i].edgeNode(0) << " "
<< getSingularTriangles()[i].edgeNode(1) << " "
<< getSingularTriangles()[i].edgeNode(2) << "\n";
}
}
......@@ -3,10 +3,12 @@
#include <GL/glew.h>
#include "qMesh.h"
#include "../../common/GLUtils/technique.h"
#include "../Core/qMesh.h"
#include "../../common/gl_utils/shader.h"
namespace Vitelotte {
static const char* vert_common = " \n\
#version 410 core \n\
\n\
......@@ -243,8 +245,8 @@ public:
~QMeshRenderer()
{
SAFE_DELETE(m_pSingularProgram);
SAFE_DELETE(m_pTriangleProgram);
PATATE_SAFE_DELETE(m_pSingularProgram);
PATATE_SAFE_DELETE(m_pTriangleProgram);
};
void render(Eigen::Matrix4f& _viewMatrix, float _zoom = 1.f, float _pointRadius = 2.f, float _lineWidth = 1.f, bool _showShaderWireframe = false);
......@@ -273,249 +275,13 @@ private:
QMesh* m_pQMesh;
Technique* m_pTriangleProgram;
Technique* m_pSingularProgram;
Shader* m_pTriangleProgram;
Shader* m_pSingularProgram;
};
inline bool QMeshRenderer::init(QMesh* _qMesh)
{
setQMesh(_qMesh);
if(m_pQMesh && m_pQMesh->isValid())
{
if(loadShaders())
{
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
return initGl();
}
}
return false;
}
inline bool QMeshRenderer::loadShaders()
{
GLCheckError();
m_pTriangleProgram = new Technique();
if(!m_pTriangleProgram->Init())
{
return false;
}
bool bRes = true;
bRes &= m_pTriangleProgram->AddShader(GL_VERTEX_SHADER, vert_common);
bRes &= m_pTriangleProgram->AddShader(GL_GEOMETRY_SHADER, geom_common);
bRes &= m_pTriangleProgram->AddShader(GL_FRAGMENT_SHADER, frag_common);
bRes &= m_pTriangleProgram->AddShader(GL_FRAGMENT_SHADER, frag_triangle);
assert(bRes);
bRes &= m_pTriangleProgram->Finalize();
assert(bRes);
m_pSingularProgram = new Technique();
if(!m_pSingularProgram->Init())
{
return false;
}
bRes &= m_pSingularProgram->AddShader(GL_VERTEX_SHADER, vert_common);
bRes &= m_pSingularProgram->AddShader(GL_GEOMETRY_SHADER, geom_common);
bRes &= m_pSingularProgram->AddShader(GL_FRAGMENT_SHADER, frag_common);
bRes &= m_pSingularProgram->AddShader(GL_FRAGMENT_SHADER, frag_singular);
assert(bRes);
bRes &= m_pSingularProgram->Finalize();
assert(bRes);
return GLCheckError();;
}
inline bool QMeshRenderer::initGl()
{
std::vector<unsigned> triangleIndices;
std::vector<unsigned> singularIndices;
QMesh::NodeList triangleNodes;
QMesh::NodeList singularNodes;
triangleIndices.reserve(m_pQMesh->nbTriangles() * 3);
singularIndices.reserve(m_pQMesh->nbSingularTriangles() * 3);
triangleNodes.reserve(m_pQMesh->nbTriangles() * 6);
singularNodes.reserve(m_pQMesh->nbSingularTriangles() * 7);
for(unsigned i = 0; i < m_pQMesh->nbTriangles(); ++i)
{
for(int j = 0; j < 3; ++j)
{
triangleIndices.push_back(m_pQMesh->getTriangles()[i].m_vertices[j]);
}
for(int j = 0; j < 6; ++j)
{
triangleNodes.push_back(m_pQMesh->getNodes()[m_pQMesh->getTriangles()[i].m_nodes[j]]);
}
}
for(unsigned i = 0; i < m_pQMesh->nbSingularTriangles(); ++i)
{
for(int j = 0; j < 3; ++j)
{
singularIndices.push_back(m_pQMesh->getSingularTriangles()[i].m_vertices[j]);
}
for(int j = 0; j < 7; ++j)
{
singularNodes.push_back(m_pQMesh->getNodes()[m_pQMesh->getSingularTriangles()[i].m_nodes[j]]);
}
}
if(!m_verticesBuffer)
{
glGenBuffers(1, &m_verticesBuffer);
}
glBindBuffer(GL_ARRAY_BUFFER, m_verticesBuffer);
glBufferData(GL_ARRAY_BUFFER, m_pQMesh->nbVertices() * sizeof(Eigen::Vector2f), &(m_pQMesh->getVertices()[0]), GL_STATIC_DRAW);
if(!m_triangleIndicesBuffer)
{
glGenBuffers(1, &m_triangleIndicesBuffer);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_triangleIndicesBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_pQMesh->nbTriangles() * 3 * sizeof(unsigned), &triangleIndices[0], GL_STATIC_DRAW);
if(m_pQMesh->nbSingularTriangles() > 0)
{
if(!m_singularIndicesBuffer)
{
glGenBuffers(1, &m_singularIndicesBuffer);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_singularIndicesBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_pQMesh->nbSingularTriangles() * 3 * sizeof(unsigned), &singularIndices[0], GL_STATIC_DRAW);
}
if(!m_triangleNodesBuffer)
{
glGenBuffers(1, &m_triangleNodesBuffer);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_triangleNodesBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangleNodes.size() * sizeof(Eigen::Vector4f), &triangleNodes[0], GL_STATIC_DRAW);
if(singularNodes.size() > 0)
{
if(!m_singularNodesBuffer)
{
glGenBuffers(1, &m_singularNodesBuffer);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_singularNodesBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, singularNodes.size() * sizeof(Eigen::Vector4f), &singularNodes[0], GL_STATIC_DRAW);
}
if(!m_triangleNodesTexture)
{
glGenTextures(1, &m_triangleNodesTexture);
}
glBindTexture(GL_TEXTURE_BUFFER, m_triangleNodesTexture);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_triangleNodesBuffer);
if(m_singularNodesBuffer)
{
if(!m_singularNodesTexture)
{
glGenTextures(1, &m_singularNodesTexture);
}
glBindTexture(GL_TEXTURE_BUFFER, m_singularNodesTexture);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, m_singularNodesBuffer);
}
return (glGetError() == GL_NO_ERROR);
}
inline void QMeshRenderer::renderTriangles(GLuint _shader, bool _singular)
{
if(m_pQMesh && m_pQMesh->isValid())
{
if(_singular && !(m_pQMesh->nbSingularTriangles() > 0))
{
return;
}
glUseProgram(_shader);
GLint verticesLoc = glGetAttribLocation(_shader, "vx_position");
if(verticesLoc >= 0)
{
glEnableVertexAttribArray(verticesLoc);
glBindBuffer(GL_ARRAY_BUFFER, m_verticesBuffer);
glVertexAttribPointer(verticesLoc, 2, GL_FLOAT, false, sizeof(Eigen::Vector2f), 0);
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_BUFFER, _singular ? m_singularNodesTexture : m_triangleNodesTexture);
glUniform1i(glGetUniformLocation(_shader, "nodes"), 0);
#include "qMeshRenderer.hpp"
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _singular ? m_singularIndicesBuffer : m_triangleIndicesBuffer);
glDrawElements(GL_TRIANGLES, m_pQMesh->nbTriangles() * 3, GL_UNSIGNED_INT, 0);
if(verticesLoc >= 0)
{
glDisableVertexAttribArray(verticesLoc);
}
}
}
inline void QMeshRenderer::render(Eigen::Matrix4f& _viewMatrix, float _zoom, float _pointRadius, float _lineWidth, bool _showShaderWireframe)
{
for(int pass = 0; pass < 2; ++pass)
{
Technique* program = (pass == 0) ? m_pTriangleProgram : m_pSingularProgram;
if(program)
{
program->Enable();
GLuint viewMatrixLoc = program->GetUniformLocation("viewMatrix");
if(viewMatrixLoc >= 0)
{
glUniformMatrix4fv(viewMatrixLoc, 1, false, _viewMatrix.data());
}
GLint wireLoc = program->GetUniformLocation("showWireframe");
if(wireLoc >=0 )
{
glUniform1i(wireLoc, _showShaderWireframe);
}
GLuint zoomLoc = program->GetUniformLocation("zoom");
if(zoomLoc >= 0)
{
glUniform1f(zoomLoc, _zoom);
}
GLuint pointRadiutLoc = program->GetUniformLocation("pointRadius");
if(pointRadiutLoc >= 0)
{
glUniform1f(pointRadiutLoc, _pointRadius);
}
GLuint halfLineWidthLoc = program->GetUniformLocation("halfLineWidth");
if(halfLineWidthLoc >= 0)
{
glUniform1f(halfLineWidthLoc, _lineWidth / 2.f);
}
if(pass == 0)
{
renderTriangles(program->GetShaderId());
}
else
{
renderTriangles(program->GetShaderId(), true);
}
}
}
}
#endif
\ No newline at end of file
#endif
inline bool QMeshRenderer::init(QMesh* _qMesh)
{
setQMesh(_qMesh);
if(m_pQMesh && m_pQMesh->isValid())
{
if(loadShaders())
{
glGenVertexArrays(1, &m_vao);
glBindVertexArray(m_vao);
return initGl();
}
}
return false;
}
inline bool QMeshRenderer::loadShaders()
{
PATATE_GLCheckError();
m_pTriangleProgram = new Shader();
if(!m_pTriangleProgram->Init())
{
return false;
}
bool bRes = true;
bRes &= m_pTriangleProgram->AddShader(GL_VERTEX_SHADER, vert_common);
bRes &= m_pTriangleProgram->AddShader(GL_GEOMETRY_SHADER, geom_common);
bRes &= m_pTriangleProgram->AddShader(GL_FRAGMENT_SHADER, frag_common);
bRes &= m_pTriangleProgram->AddShader(GL_FRAGMENT_SHADER, frag_triangle);
assert(bRes);
bRes &= m_pTriangleProgram->Finalize();
assert(bRes);
m_pSingularProgram = new Shader();
if(!m_pSingularProgram->Init())
{
return false;
}
bRes &= m_pSingularProgram->AddShader(GL_VERTEX_SHADER, vert_common);
bRes &= m_pSingularProgram->AddShader(GL_GEOMETRY_SHADER, geom_common);
bRes &= m_pSingularProgram->AddShader(GL_FRAGMENT_SHADER, frag_common);
bRes &= m_pSingularProgram->AddShader(GL_FRAGMENT_SHADER, frag_singular);
assert(bRes);
bRes &= m_pSingularProgram->Finalize();
assert(bRes);
return PATATE_GLCheckError();;
}
inline bool QMeshRenderer::initGl()
{
std::vector<unsigned> triangleIndices;
std::vector<unsigned> singularIndices;
QMesh::NodeList triangleNodes;
QMesh::NodeList singularNodes;
triangleIndices.reserve(m_pQMesh->nbTriangles() * 3);
singularIndices.reserve(m_pQMesh->nbSingularTriangles() * 3);
triangleNodes.reserve(m_pQMesh->nbTriangles() * 6);
singularNodes.reserve(m_pQMesh->nbSingularTriangles() * 7);
for(unsigned i = 0; i < m_pQMesh->nbTriangles(); ++i)
{
for(int j = 0; j < 3; ++j)
{
triangleIndices.push_back(m_pQMesh->getTriangles()[i].m_vertices[j]);
}
for(int j = 0; j < 6; ++j)
{
triangleNodes.push_back(m_pQMesh->getNodes()[m_pQMesh->getTriangles()[i].m_nodes[j]]);
}
}
for(unsigned i = 0; i < m_pQMesh->nbSingularTriangles(); ++i)
{
for(int j = 0; j < 3; ++j)
{
singularIndices.push_back(m_pQMesh->getSingularTriangles()[i].m_vertices[j]);
}
for(int j = 0; j < 7; ++j)
{
singularNodes.push_back(m_pQMesh->getNodes()[m_pQMesh->getSingularTriangles()[i].m_nodes[j]]);
}
}
if(!m_verticesBuffer)
{
glGenBuffers(1, &m_verticesBuffer);