Files
test/source/blender/freestyle/intern/winged_edge/WXEdge.cpp
Campbell Barton e955c94ed3 License Headers: Set copyright to "Blender Authors", add AUTHORS
Listing the "Blender Foundation" as copyright holder implied the Blender
Foundation holds copyright to files which may include work from many
developers.

While keeping copyright on headers makes sense for isolated libraries,
Blender's own code may be refactored or moved between files in a way
that makes the per file copyright holders less meaningful.

Copyright references to the "Blender Foundation" have been replaced with
"Blender Authors", with the exception of `./extern/` since these this
contains libraries which are more isolated, any changed to license
headers there can be handled on a case-by-case basis.

Some directories in `./intern/` have also been excluded:

- `./intern/cycles/` it's own `AUTHORS` file is planned.
- `./intern/opensubdiv/`.

An "AUTHORS" file has been added, using the chromium projects authors
file as a template.

Design task: #110784

Ref !110783.
2023-08-16 00:20:26 +10:00

311 lines
9.1 KiB
C++

/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup freestyle
* \brief Classes to define an Extended Winged Edge data structure.
*/
#include "WXEdge.h"
#include "BLI_sys_types.h"
#include "BKE_global.h"
namespace Freestyle {
/**********************************
* *
* *
* WXFace *
* *
* *
**********************************/
uint WXFaceLayer::Get0VertexIndex() const
{
int i = 0;
int nEdges = _pWXFace->numberOfEdges();
for (i = 0; i < nEdges; ++i) {
if (_DotP[i] == 0.0f) { /* TODO: this comparison is weak, check if it actually works */
return i;
}
}
return -1;
}
uint WXFaceLayer::GetSmoothEdgeIndex() const
{
int i = 0;
int nEdges = _pWXFace->numberOfEdges();
for (i = 0; i < nEdges; ++i) {
if ((_DotP[i] == 0.0f) && (_DotP[(i + 1) % nEdges] == 0.0f)) { /* TODO: ditto */
return i;
}
}
return -1;
}
void WXFaceLayer::RetrieveCuspEdgesIndices(vector<int> &oCuspEdges)
{
int i = 0;
int nEdges = _pWXFace->numberOfEdges();
for (i = 0; i < nEdges; ++i) {
if (_DotP[i] * _DotP[(i + 1) % nEdges] < 0.0f) {
// we got one
oCuspEdges.push_back(i);
}
}
}
WXSmoothEdge *WXFaceLayer::BuildSmoothEdge()
{
// if the smooth edge has already been built: exit
if (_pSmoothEdge) {
return _pSmoothEdge;
}
float ta, tb;
WOEdge *woea(nullptr), *woeb(nullptr);
bool ok = false;
vector<int> cuspEdgesIndices;
int indexStart, indexEnd;
uint nedges = _pWXFace->numberOfEdges();
if (_nNullDotP == nedges) {
_pSmoothEdge = nullptr;
return _pSmoothEdge;
}
if ((_nPosDotP != 0) && (_nPosDotP != _DotP.size()) && (_nNullDotP == 0)) {
// that means that we have a smooth edge that starts from an edge and ends at an edge
//-----------------------------
// We retrieve the 2 edges for which we have opposite signs for each extremity
RetrieveCuspEdgesIndices(cuspEdgesIndices);
if (cuspEdgesIndices.size() != 2) { // we necessarily have 2 cusp edges
return nullptr;
}
// let us determine which cusp edge corresponds to the starting:
// We can do that because we defined that a silhouette edge had the back facing part on its
// right. So if the WOEdge woea is such that woea[0].dotp > 0 and woea[1].dotp < 0, it is the
// starting edge.
//-------------------------------------------
if (_DotP[cuspEdgesIndices[0]] > 0.0f) {
woea = _pWXFace->GetOEdge(cuspEdgesIndices[0]);
woeb = _pWXFace->GetOEdge(cuspEdgesIndices[1]);
indexStart = cuspEdgesIndices[0];
indexEnd = cuspEdgesIndices[1];
}
else {
woea = _pWXFace->GetOEdge(cuspEdgesIndices[1]);
woeb = _pWXFace->GetOEdge(cuspEdgesIndices[0]);
indexStart = cuspEdgesIndices[1];
indexEnd = cuspEdgesIndices[0];
}
// Compute the interpolation:
ta = _DotP[indexStart] / (_DotP[indexStart] - _DotP[(indexStart + 1) % nedges]);
tb = _DotP[indexEnd] / (_DotP[indexEnd] - _DotP[(indexEnd + 1) % nedges]);
ok = true;
}
else if (_nNullDotP == 1) {
// that means that we have exactly one of the 2 extremities of our silhouette edge is a vertex
// of the mesh
if (ELEM(_nPosDotP, 2, 0)) {
_pSmoothEdge = nullptr;
return _pSmoothEdge;
}
RetrieveCuspEdgesIndices(cuspEdgesIndices);
// We should have only one EdgeCusp:
if (cuspEdgesIndices.size() != 1) {
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "Warning in BuildSmoothEdge: weird WXFace configuration" << endl;
}
_pSmoothEdge = nullptr;
return nullptr;
}
uint index0 = Get0VertexIndex(); // retrieve the 0 vertex index
uint nedges = _pWXFace->numberOfEdges();
if (_DotP[cuspEdgesIndices[0]] > 0.0f) {
woea = _pWXFace->GetOEdge(cuspEdgesIndices[0]);
woeb = _pWXFace->GetOEdge(index0);
indexStart = cuspEdgesIndices[0];
ta = _DotP[indexStart] / (_DotP[indexStart] - _DotP[(indexStart + 1) % nedges]);
tb = 0.0f;
}
else {
woea = _pWXFace->GetOEdge(index0);
woeb = _pWXFace->GetOEdge(cuspEdgesIndices[0]);
indexEnd = cuspEdgesIndices[0];
ta = 0.0f;
tb = _DotP[indexEnd] / (_DotP[indexEnd] - _DotP[(indexEnd + 1) % nedges]);
}
ok = true;
}
else if (_nNullDotP == 2) {
// that means that the silhouette edge is an edge of the mesh
int index = GetSmoothEdgeIndex();
if (!_pWXFace->front()) { // is it in the right order ?
// the order of the WOEdge index is wrong
woea = _pWXFace->GetOEdge((index + 1) % nedges);
woeb = _pWXFace->GetOEdge((index - 1) % nedges);
ta = 0.0f;
tb = 1.0f;
ok = true;
}
else {
// here it's not good, our edge is a single point -> skip that face
ok = false;
#if 0
// the order of the WOEdge index is good
woea = _pWXFace->GetOEdge((index - 1) % nedges);
woeb = _pWXFace->GetOEdge((index + 1) % nedges);
ta = 1.0f;
tb = 0.0f;
#endif
}
}
if (ok) {
_pSmoothEdge = new WXSmoothEdge;
_pSmoothEdge->setWOeA(woea);
_pSmoothEdge->setWOeB(woeb);
_pSmoothEdge->setTa(ta);
_pSmoothEdge->setTb(tb);
if (_Nature & Nature::SILHOUETTE) {
if (_nNullDotP != 2) {
if (_DotP[_ClosestPointIndex] + 0.01f > 0.0f) {
_pSmoothEdge->setFront(true);
}
else {
_pSmoothEdge->setFront(false);
}
}
}
}
#if 0
// check bording edges to see if they have different dotp values in bording faces.
for (int i = 0; i < numberOfEdges(); i++) {
WSFace *bface = (WSFace *)GetBordingFace(i);
if (bface) {
if ((front()) ^ (bface->front()))
{ // fA->front XOR fB->front (true if one is 0 and the other is 1)
// that means that the edge i of the face is a silhouette edge
// CHECK FIRST WHETHER THE EXACTSILHOUETTEEDGE HAS
// NOT YET BEEN BUILT ON THE OTHER FACE (1 is enough).
if (((WSExactFace *)bface)->exactSilhouetteEdge()) {
// that means that this silhouette edge has already been built
return ((WSExactFace *)bface)->exactSilhouetteEdge();
}
// Else we must build it
WOEdge *woea, *woeb;
float ta, tb;
if (!front()) { // is it in the right order ?
// the order of the WOEdge index is wrong
woea = _OEdgeList[(i + 1) % numberOfEdges()];
if (0 == i) {
woeb = _OEdgeList[numberOfEdges() - 1];
}
else {
woeb = _OEdgeList[(i - 1)];
}
ta = 0.0f;
tb = 1.0f;
}
else {
// the order of the WOEdge index is good
if (0 == i) {
woea = _OEdgeList[numberOfEdges() - 1];
}
else {
woea = _OEdgeList[(i - 1)];
}
woeb = _OEdgeList[(i + 1) % numberOfEdges()];
ta = 1.0f;
tb = 0.0f;
}
_pSmoothEdge = new ExactSilhouetteEdge(ExactSilhouetteEdge::VERTEX_VERTEX);
_pSmoothEdge->setWOeA(woea);
_pSmoothEdge->setWOeA(woeb);
_pSmoothEdge->setTa(ta);
_pSmoothEdge->setTb(tb);
return _pSmoothEdge;
}
}
}
#endif
return _pSmoothEdge;
}
void WXFace::ComputeCenter()
{
vector<WVertex *> iVertexList;
RetrieveVertexList(iVertexList);
Vec3f center;
for (vector<WVertex *>::iterator wv = iVertexList.begin(), wvend = iVertexList.end();
wv != wvend;
++wv)
{
center += (*wv)->GetVertex();
}
center /= float(iVertexList.size());
setCenter(center);
}
/**********************************
* *
* *
* WXShape *
* *
* *
**********************************/
WFace *WXShape::MakeFace(vector<WVertex *> &iVertexList,
vector<bool> &iFaceEdgeMarksList,
uint iMaterialIndex)
{
WFace *face = WShape::MakeFace(iVertexList, iFaceEdgeMarksList, iMaterialIndex);
if (!face) {
return nullptr;
}
Vec3f center;
for (vector<WVertex *>::iterator wv = iVertexList.begin(), wvend = iVertexList.end();
wv != wvend;
++wv)
{
center += (*wv)->GetVertex();
}
center /= float(iVertexList.size());
((WXFace *)face)->setCenter(center);
return face;
}
WFace *WXShape::MakeFace(vector<WVertex *> &iVertexList,
vector<Vec3f> &iNormalsList,
vector<Vec2f> &iTexCoordsList,
vector<bool> &iFaceEdgeMarksList,
uint iMaterialIndex)
{
WFace *face = WShape::MakeFace(
iVertexList, iNormalsList, iTexCoordsList, iFaceEdgeMarksList, iMaterialIndex);
#if 0
Vec3f center;
for (vector<WVertex *>::iterator wv = iVertexList.begin(), wvend = iVertexList.end();
wv != wvend;
++wv)
{
center += (*wv)->GetVertex();
}
center /= float(iVertexList.size());
((WXFace *)face)->setCenter(center);
#endif
return face;
}
} /* namespace Freestyle */