460 lines
17 KiB
C++
460 lines
17 KiB
C++
/*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
/** \file
|
|
* \ingroup freestyle
|
|
* \brief Class to render a WingedEdge data structure from a polyhedral data structure organized in
|
|
* nodes of a scene graph
|
|
*/
|
|
|
|
#include <set>
|
|
|
|
#include "WingedEdgeBuilder.h"
|
|
|
|
#include "../geometry/GeomUtils.h"
|
|
|
|
#include "../scene_graph/NodeShape.h"
|
|
|
|
using namespace std;
|
|
|
|
namespace Freestyle {
|
|
|
|
void WingedEdgeBuilder::visitIndexedFaceSet(IndexedFaceSet &ifs)
|
|
{
|
|
if (_pRenderMonitor && _pRenderMonitor->testBreak()) {
|
|
return;
|
|
}
|
|
WShape *shape = new WShape;
|
|
if (!buildWShape(*shape, ifs)) {
|
|
delete shape;
|
|
return;
|
|
}
|
|
shape->setId(ifs.getId().getFirst());
|
|
// ifs.setId(shape->GetId());
|
|
}
|
|
|
|
void WingedEdgeBuilder::visitNodeShape(NodeShape &ns)
|
|
{
|
|
// Sets the current material to iShapeode->material:
|
|
_current_frs_material = &(ns.frs_material());
|
|
}
|
|
|
|
void WingedEdgeBuilder::visitNodeTransform(NodeTransform &tn)
|
|
{
|
|
if (!_current_matrix) {
|
|
_current_matrix = new Matrix44r(tn.matrix());
|
|
return;
|
|
}
|
|
|
|
_matrices_stack.push_back(_current_matrix);
|
|
Matrix44r *new_matrix = new Matrix44r(*_current_matrix * tn.matrix());
|
|
_current_matrix = new_matrix;
|
|
}
|
|
|
|
void WingedEdgeBuilder::visitNodeTransformAfter(NodeTransform &UNUSED(transform))
|
|
{
|
|
delete _current_matrix;
|
|
|
|
if (_matrices_stack.empty()) {
|
|
_current_matrix = nullptr;
|
|
return;
|
|
}
|
|
|
|
_current_matrix = _matrices_stack.back();
|
|
_matrices_stack.pop_back();
|
|
}
|
|
|
|
bool WingedEdgeBuilder::buildWShape(WShape &shape, IndexedFaceSet &ifs)
|
|
{
|
|
unsigned int vsize = ifs.vsize();
|
|
unsigned int nsize = ifs.nsize();
|
|
// soc unused - unsigned tsize = ifs.tsize();
|
|
|
|
const float *vertices = ifs.vertices();
|
|
const float *normals = ifs.normals();
|
|
const float *texCoords = ifs.texCoords();
|
|
|
|
float *new_vertices;
|
|
float *new_normals;
|
|
|
|
new_vertices = new float[vsize];
|
|
new_normals = new float[nsize];
|
|
|
|
// transform coordinates from local to world system
|
|
if (_current_matrix) {
|
|
transformVertices(vertices, vsize, *_current_matrix, new_vertices);
|
|
transformNormals(normals, nsize, *_current_matrix, new_normals);
|
|
}
|
|
else {
|
|
memcpy(new_vertices, vertices, vsize * sizeof(*new_vertices));
|
|
memcpy(new_normals, normals, nsize * sizeof(*new_normals));
|
|
}
|
|
|
|
const IndexedFaceSet::TRIANGLES_STYLE *faceStyle = ifs.trianglesStyle();
|
|
|
|
vector<FrsMaterial> frs_materials;
|
|
if (ifs.msize()) {
|
|
const FrsMaterial *const *mats = ifs.frs_materials();
|
|
for (unsigned i = 0; i < ifs.msize(); ++i) {
|
|
frs_materials.push_back(*(mats[i]));
|
|
}
|
|
shape.setFrsMaterials(frs_materials);
|
|
}
|
|
|
|
#if 0
|
|
const FrsMaterial *mat = (ifs.frs_material());
|
|
if (mat) {
|
|
shape.setFrsMaterial(*mat);
|
|
}
|
|
else if (_current_frs_material) {
|
|
shape.setFrsMaterial(*_current_frs_material);
|
|
}
|
|
#endif
|
|
const IndexedFaceSet::FaceEdgeMark *faceEdgeMarks = ifs.faceEdgeMarks();
|
|
|
|
// sets the current WShape to shape
|
|
_current_wshape = &shape;
|
|
|
|
// create a WVertex for each vertex
|
|
buildWVertices(shape, new_vertices, vsize);
|
|
|
|
const unsigned int *vindices = ifs.vindices();
|
|
const unsigned int *nindices = ifs.nindices();
|
|
const unsigned int *tindices = nullptr;
|
|
if (ifs.tsize()) {
|
|
tindices = ifs.tindices();
|
|
}
|
|
|
|
const unsigned int *mindices = nullptr;
|
|
if (ifs.msize()) {
|
|
mindices = ifs.mindices();
|
|
}
|
|
const unsigned int *numVertexPerFace = ifs.numVertexPerFaces();
|
|
const unsigned int numfaces = ifs.numFaces();
|
|
|
|
for (unsigned int index = 0; index < numfaces; index++) {
|
|
switch (faceStyle[index]) {
|
|
case IndexedFaceSet::TRIANGLE_STRIP:
|
|
buildTriangleStrip(new_vertices,
|
|
new_normals,
|
|
frs_materials,
|
|
texCoords,
|
|
faceEdgeMarks,
|
|
vindices,
|
|
nindices,
|
|
mindices,
|
|
tindices,
|
|
numVertexPerFace[index]);
|
|
break;
|
|
case IndexedFaceSet::TRIANGLE_FAN:
|
|
buildTriangleFan(new_vertices,
|
|
new_normals,
|
|
frs_materials,
|
|
texCoords,
|
|
faceEdgeMarks,
|
|
vindices,
|
|
nindices,
|
|
mindices,
|
|
tindices,
|
|
numVertexPerFace[index]);
|
|
break;
|
|
case IndexedFaceSet::TRIANGLES:
|
|
buildTriangles(new_vertices,
|
|
new_normals,
|
|
frs_materials,
|
|
texCoords,
|
|
faceEdgeMarks,
|
|
vindices,
|
|
nindices,
|
|
mindices,
|
|
tindices,
|
|
numVertexPerFace[index]);
|
|
break;
|
|
}
|
|
vindices += numVertexPerFace[index];
|
|
nindices += numVertexPerFace[index];
|
|
if (mindices) {
|
|
mindices += numVertexPerFace[index];
|
|
}
|
|
if (tindices) {
|
|
tindices += numVertexPerFace[index];
|
|
}
|
|
faceEdgeMarks++;
|
|
}
|
|
|
|
delete[] new_vertices;
|
|
delete[] new_normals;
|
|
|
|
if (shape.GetFaceList().empty()) { // this may happen due to degenerate triangles
|
|
return false;
|
|
}
|
|
|
|
#if 0
|
|
// compute bbox
|
|
shape.ComputeBBox();
|
|
// compute mean edge size:
|
|
shape.ComputeMeanEdgeSize();
|
|
#endif
|
|
|
|
// Parse the built winged-edge shape to update post-flags
|
|
set<Vec3f> normalsSet;
|
|
vector<WVertex *> &wvertices = shape.getVertexList();
|
|
for (vector<WVertex *>::iterator wv = wvertices.begin(), wvend = wvertices.end(); wv != wvend;
|
|
++wv) {
|
|
if ((*wv)->isBoundary()) {
|
|
continue;
|
|
}
|
|
if ((*wv)->GetEdges().empty()) {
|
|
// This means that the WVertex has no incoming edges... (12-Sep-2011 T.K.)
|
|
continue;
|
|
}
|
|
normalsSet.clear();
|
|
WVertex::face_iterator fit = (*wv)->faces_begin();
|
|
WVertex::face_iterator fitend = (*wv)->faces_end();
|
|
for (; fit != fitend; ++fit) {
|
|
WFace *face = *fit;
|
|
normalsSet.insert(face->GetVertexNormal(*wv));
|
|
if (normalsSet.size() != 1) {
|
|
break;
|
|
}
|
|
}
|
|
if (normalsSet.size() != 1) {
|
|
(*wv)->setSmooth(false);
|
|
}
|
|
}
|
|
|
|
// Adds the new WShape to the WingedEdge structure
|
|
_winged_edge->addWShape(&shape);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WingedEdgeBuilder::buildWVertices(WShape &shape, const float *vertices, unsigned vsize)
|
|
{
|
|
WVertex *vertex;
|
|
for (unsigned int i = 0; i < vsize; i += 3) {
|
|
vertex = new WVertex(Vec3f(vertices[i], vertices[i + 1], vertices[i + 2]));
|
|
vertex->setId(i / 3);
|
|
shape.AddVertex(vertex);
|
|
}
|
|
}
|
|
|
|
void WingedEdgeBuilder::buildTriangleStrip(const float * /*vertices*/,
|
|
const float *normals,
|
|
vector<FrsMaterial> & /*iMaterials*/,
|
|
const float *texCoords,
|
|
const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
|
|
const unsigned *vindices,
|
|
const unsigned *nindices,
|
|
const unsigned *mindices,
|
|
const unsigned *tindices,
|
|
const unsigned nvertices)
|
|
{
|
|
unsigned nDoneVertices = 2; // number of vertices already treated
|
|
unsigned nTriangle = 0; // number of the triangle currently being treated
|
|
// int nVertex = 0; // vertex number
|
|
|
|
WShape *currentShape = _current_wshape; // the current shape being built
|
|
vector<WVertex *> triangleVertices;
|
|
vector<Vec3f> triangleNormals;
|
|
vector<Vec2f> triangleTexCoords;
|
|
vector<bool> triangleFaceEdgeMarks;
|
|
|
|
while (nDoneVertices < nvertices) {
|
|
// clear the vertices list:
|
|
triangleVertices.clear();
|
|
// Then rebuild it:
|
|
if (0 == nTriangle % 2) { // if nTriangle is even
|
|
triangleVertices.push_back(currentShape->getVertexList()[vindices[nTriangle] / 3]);
|
|
triangleVertices.push_back(currentShape->getVertexList()[vindices[nTriangle + 1] / 3]);
|
|
triangleVertices.push_back(currentShape->getVertexList()[vindices[nTriangle + 2] / 3]);
|
|
|
|
triangleNormals.emplace_back(normals[nindices[nTriangle]],
|
|
normals[nindices[nTriangle] + 1],
|
|
normals[nindices[nTriangle] + 2]);
|
|
triangleNormals.emplace_back(normals[nindices[nTriangle + 1]],
|
|
normals[nindices[nTriangle + 1] + 1],
|
|
normals[nindices[nTriangle + 1] + 2]);
|
|
triangleNormals.emplace_back(normals[nindices[nTriangle + 2]],
|
|
normals[nindices[nTriangle + 2] + 1],
|
|
normals[nindices[nTriangle + 2] + 2]);
|
|
|
|
if (texCoords) {
|
|
triangleTexCoords.emplace_back(texCoords[tindices[nTriangle]],
|
|
texCoords[tindices[nTriangle] + 1]);
|
|
triangleTexCoords.emplace_back(texCoords[tindices[nTriangle + 1]],
|
|
texCoords[tindices[nTriangle + 1] + 1]);
|
|
triangleTexCoords.emplace_back(texCoords[tindices[nTriangle + 2]],
|
|
texCoords[tindices[nTriangle + 2] + 1]);
|
|
}
|
|
}
|
|
else { // if nTriangle is odd
|
|
triangleVertices.push_back(currentShape->getVertexList()[vindices[nTriangle] / 3]);
|
|
triangleVertices.push_back(currentShape->getVertexList()[vindices[nTriangle + 2] / 3]);
|
|
triangleVertices.push_back(currentShape->getVertexList()[vindices[nTriangle + 1] / 3]);
|
|
|
|
triangleNormals.emplace_back(normals[nindices[nTriangle]],
|
|
normals[nindices[nTriangle] + 1],
|
|
normals[nindices[nTriangle] + 2]);
|
|
triangleNormals.emplace_back(normals[nindices[nTriangle + 2]],
|
|
normals[nindices[nTriangle + 2] + 1],
|
|
normals[nindices[nTriangle + 2] + 2]);
|
|
triangleNormals.emplace_back(normals[nindices[nTriangle + 1]],
|
|
normals[nindices[nTriangle + 1] + 1],
|
|
normals[nindices[nTriangle + 1] + 2]);
|
|
|
|
if (texCoords) {
|
|
triangleTexCoords.emplace_back(texCoords[tindices[nTriangle]],
|
|
texCoords[tindices[nTriangle] + 1]);
|
|
triangleTexCoords.emplace_back(texCoords[tindices[nTriangle + 2]],
|
|
texCoords[tindices[nTriangle + 2] + 1]);
|
|
triangleTexCoords.emplace_back(texCoords[tindices[nTriangle + 1]],
|
|
texCoords[tindices[nTriangle + 1] + 1]);
|
|
}
|
|
}
|
|
triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[nTriangle / 3] & IndexedFaceSet::FACE_MARK) !=
|
|
0);
|
|
triangleFaceEdgeMarks.push_back(
|
|
(iFaceEdgeMarks[nTriangle / 3] & IndexedFaceSet::EDGE_MARK_V1V2) != 0);
|
|
triangleFaceEdgeMarks.push_back(
|
|
(iFaceEdgeMarks[nTriangle / 3] & IndexedFaceSet::EDGE_MARK_V2V3) != 0);
|
|
triangleFaceEdgeMarks.push_back(
|
|
(iFaceEdgeMarks[nTriangle / 3] & IndexedFaceSet::EDGE_MARK_V3V1) != 0);
|
|
if (mindices) {
|
|
currentShape->MakeFace(triangleVertices,
|
|
triangleNormals,
|
|
triangleTexCoords,
|
|
triangleFaceEdgeMarks,
|
|
mindices[nTriangle / 3]);
|
|
}
|
|
else {
|
|
currentShape->MakeFace(
|
|
triangleVertices, triangleNormals, triangleTexCoords, triangleFaceEdgeMarks, 0);
|
|
}
|
|
nDoneVertices++; // with a strip, each triangle is one vertex more
|
|
nTriangle++;
|
|
}
|
|
}
|
|
|
|
void WingedEdgeBuilder::buildTriangleFan(const float * /*vertices*/,
|
|
const float * /*normals*/,
|
|
vector<FrsMaterial> & /*iMaterials*/,
|
|
const float * /*texCoords*/,
|
|
const IndexedFaceSet::FaceEdgeMark * /*iFaceEdgeMarks*/,
|
|
const unsigned * /*vindices*/,
|
|
const unsigned * /*nindices*/,
|
|
const unsigned * /*mindices*/,
|
|
const unsigned * /*tindices*/,
|
|
const unsigned /*nvertices*/)
|
|
{
|
|
// Nothing to be done
|
|
}
|
|
|
|
void WingedEdgeBuilder::buildTriangles(const float * /*vertices*/,
|
|
const float *normals,
|
|
vector<FrsMaterial> & /*iMaterials*/,
|
|
const float *texCoords,
|
|
const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
|
|
const unsigned *vindices,
|
|
const unsigned *nindices,
|
|
const unsigned *mindices,
|
|
const unsigned *tindices,
|
|
const unsigned nvertices)
|
|
{
|
|
WShape *currentShape = _current_wshape; // the current shape begin built
|
|
vector<WVertex *> triangleVertices;
|
|
vector<Vec3f> triangleNormals;
|
|
vector<Vec2f> triangleTexCoords;
|
|
vector<bool> triangleFaceEdgeMarks;
|
|
|
|
// Each triplet of vertices is considered as an independent triangle
|
|
for (unsigned int i = 0; i < nvertices / 3; i++) {
|
|
triangleVertices.push_back(currentShape->getVertexList()[vindices[3 * i] / 3]);
|
|
triangleVertices.push_back(currentShape->getVertexList()[vindices[3 * i + 1] / 3]);
|
|
triangleVertices.push_back(currentShape->getVertexList()[vindices[3 * i + 2] / 3]);
|
|
|
|
triangleNormals.emplace_back(
|
|
normals[nindices[3 * i]], normals[nindices[3 * i] + 1], normals[nindices[3 * i] + 2]);
|
|
triangleNormals.emplace_back(normals[nindices[3 * i + 1]],
|
|
normals[nindices[3 * i + 1] + 1],
|
|
normals[nindices[3 * i + 1] + 2]);
|
|
triangleNormals.emplace_back(normals[nindices[3 * i + 2]],
|
|
normals[nindices[3 * i + 2] + 1],
|
|
normals[nindices[3 * i + 2] + 2]);
|
|
|
|
if (texCoords) {
|
|
triangleTexCoords.emplace_back(texCoords[tindices[3 * i]], texCoords[tindices[3 * i] + 1]);
|
|
triangleTexCoords.emplace_back(texCoords[tindices[3 * i + 1]],
|
|
texCoords[tindices[3 * i + 1] + 1]);
|
|
triangleTexCoords.emplace_back(texCoords[tindices[3 * i + 2]],
|
|
texCoords[tindices[3 * i + 2] + 1]);
|
|
}
|
|
|
|
triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[i] & IndexedFaceSet::FACE_MARK) != 0);
|
|
triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[i] & IndexedFaceSet::EDGE_MARK_V1V2) != 0);
|
|
triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[i] & IndexedFaceSet::EDGE_MARK_V2V3) != 0);
|
|
triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[i] & IndexedFaceSet::EDGE_MARK_V3V1) != 0);
|
|
}
|
|
if (mindices) {
|
|
currentShape->MakeFace(
|
|
triangleVertices, triangleNormals, triangleTexCoords, triangleFaceEdgeMarks, mindices[0]);
|
|
}
|
|
else {
|
|
currentShape->MakeFace(
|
|
triangleVertices, triangleNormals, triangleTexCoords, triangleFaceEdgeMarks, 0);
|
|
}
|
|
}
|
|
|
|
void WingedEdgeBuilder::transformVertices(const float *vertices,
|
|
unsigned vsize,
|
|
const Matrix44r &transform,
|
|
float *res)
|
|
{
|
|
const float *v = vertices;
|
|
float *pv = res;
|
|
|
|
for (unsigned int i = 0; i < vsize / 3; i++) {
|
|
HVec3r hv_tmp(v[0], v[1], v[2]);
|
|
HVec3r hv(transform * hv_tmp);
|
|
for (unsigned int j = 0; j < 3; j++) {
|
|
pv[j] = hv[j] / hv[3];
|
|
}
|
|
v += 3;
|
|
pv += 3;
|
|
}
|
|
}
|
|
|
|
void WingedEdgeBuilder::transformNormals(const float *normals,
|
|
unsigned nsize,
|
|
const Matrix44r &transform,
|
|
float *res)
|
|
{
|
|
const float *n = normals;
|
|
float *pn = res;
|
|
|
|
for (unsigned int i = 0; i < nsize / 3; i++) {
|
|
Vec3r hn(n[0], n[1], n[2]);
|
|
hn = GeomUtils::rotateVector(transform, hn);
|
|
for (unsigned int j = 0; j < 3; j++) {
|
|
pn[j] = hn[j];
|
|
}
|
|
n += 3;
|
|
pn += 3;
|
|
}
|
|
}
|
|
|
|
} /* namespace Freestyle */
|