1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 /** \file
18  * \ingroup freestyle
19  * \brief Classes to define an Extended Winged Edge data structure.
20  */
21 
22 #include "WXEdge.h"
23 #include "BKE_global.h"
24 
25 namespace Freestyle {
26 
27 /**********************************
28  *                                *
29  *                                *
30  *             WXFace             *
31  *                                *
32  *                                *
33  **********************************/
34 
Get0VertexIndex() const35 unsigned int WXFaceLayer::Get0VertexIndex() const
36 {
37   int i = 0;
38   int nEdges = _pWXFace->numberOfEdges();
39   for (i = 0; i < nEdges; ++i) {
40     if (_DotP[i] == 0.0f) {  // TODO this comparison is weak, check if it actually works
41       return i;
42     }
43   }
44   return -1;
45 }
GetSmoothEdgeIndex() const46 unsigned int WXFaceLayer::GetSmoothEdgeIndex() const
47 {
48   int i = 0;
49   int nEdges = _pWXFace->numberOfEdges();
50   for (i = 0; i < nEdges; ++i) {
51     if ((_DotP[i] == 0.0f) && (_DotP[(i + 1) % nEdges] == 0.0f)) {  // TODO ditto
52       return i;
53     }
54   }
55   return -1;
56 }
57 
RetrieveCuspEdgesIndices(vector<int> & oCuspEdges)58 void WXFaceLayer::RetrieveCuspEdgesIndices(vector<int> &oCuspEdges)
59 {
60   int i = 0;
61   int nEdges = _pWXFace->numberOfEdges();
62   for (i = 0; i < nEdges; ++i) {
63     if (_DotP[i] * _DotP[(i + 1) % nEdges] < 0.0f) {
64       // we got one
65       oCuspEdges.push_back(i);
66     }
67   }
68 }
69 
BuildSmoothEdge()70 WXSmoothEdge *WXFaceLayer::BuildSmoothEdge()
71 {
72   // if the smooth edge has already been built: exit
73   if (_pSmoothEdge) {
74     return _pSmoothEdge;
75   }
76   float ta, tb;
77   WOEdge *woea(0), *woeb(0);
78   bool ok = false;
79   vector<int> cuspEdgesIndices;
80   int indexStart, indexEnd;
81   unsigned nedges = _pWXFace->numberOfEdges();
82   if (_nNullDotP == nedges) {
83     _pSmoothEdge = NULL;
84     return _pSmoothEdge;
85   }
86   if ((_nPosDotP != 0) && (_nPosDotP != _DotP.size()) && (_nNullDotP == 0)) {
87     // that means that we have a smooth edge that starts from an edge and ends at an edge
88     //-----------------------------
89     // We retrieve the 2 edges for which we have opposite signs for each extremity
90     RetrieveCuspEdgesIndices(cuspEdgesIndices);
91     if (cuspEdgesIndices.size() != 2) {  // we necessarly have 2 cusp edges
92       return 0;
93     }
94 
95     // let us determine which cusp edge corresponds to the starting:
96     // We can do that because we defined that a silhouette edge had the back facing part on its
97     // right. So if the WOEdge woea is such that woea[0].dotp > 0 and woea[1].dotp < 0, it is the
98     // starting edge.
99     //-------------------------------------------
100 
101     if (_DotP[cuspEdgesIndices[0]] > 0.0f) {
102       woea = _pWXFace->GetOEdge(cuspEdgesIndices[0]);
103       woeb = _pWXFace->GetOEdge(cuspEdgesIndices[1]);
104       indexStart = cuspEdgesIndices[0];
105       indexEnd = cuspEdgesIndices[1];
106     }
107     else {
108       woea = _pWXFace->GetOEdge(cuspEdgesIndices[1]);
109       woeb = _pWXFace->GetOEdge(cuspEdgesIndices[0]);
110       indexStart = cuspEdgesIndices[1];
111       indexEnd = cuspEdgesIndices[0];
112     }
113 
114     // Compute the interpolation:
115     ta = _DotP[indexStart] / (_DotP[indexStart] - _DotP[(indexStart + 1) % nedges]);
116     tb = _DotP[indexEnd] / (_DotP[indexEnd] - _DotP[(indexEnd + 1) % nedges]);
117     ok = true;
118   }
119   else if (_nNullDotP == 1) {
120     // that means that we have exactly one of the 2 extremities of our silhouette edge is a vertex
121     // of the mesh
122     if ((_nPosDotP == 2) || (_nPosDotP == 0)) {
123       _pSmoothEdge = NULL;
124       return _pSmoothEdge;
125     }
126     RetrieveCuspEdgesIndices(cuspEdgesIndices);
127     // We should have only one EdgeCusp:
128     if (cuspEdgesIndices.size() != 1) {
129       if (G.debug & G_DEBUG_FREESTYLE) {
130         cout << "Warning in BuildSmoothEdge: weird WXFace configuration" << endl;
131       }
132       _pSmoothEdge = NULL;
133       return NULL;
134     }
135     unsigned index0 = Get0VertexIndex();  // retrieve the 0 vertex index
136     unsigned nedges = _pWXFace->numberOfEdges();
137     if (_DotP[cuspEdgesIndices[0]] > 0.0f) {
138       woea = _pWXFace->GetOEdge(cuspEdgesIndices[0]);
139       woeb = _pWXFace->GetOEdge(index0);
140       indexStart = cuspEdgesIndices[0];
141       ta = _DotP[indexStart] / (_DotP[indexStart] - _DotP[(indexStart + 1) % nedges]);
142       tb = 0.0f;
143     }
144     else {
145       woea = _pWXFace->GetOEdge(index0);
146       woeb = _pWXFace->GetOEdge(cuspEdgesIndices[0]);
147       indexEnd = cuspEdgesIndices[0];
148       ta = 0.0f;
149       tb = _DotP[indexEnd] / (_DotP[indexEnd] - _DotP[(indexEnd + 1) % nedges]);
150     }
151     ok = true;
152   }
153   else if (_nNullDotP == 2) {
154     // that means that the silhouette edge is an edge of the mesh
155     int index = GetSmoothEdgeIndex();
156     if (!_pWXFace->front()) {  // is it in the right order ?
157       // the order of the WOEdge index is wrong
158       woea = _pWXFace->GetOEdge((index + 1) % nedges);
159       woeb = _pWXFace->GetOEdge((index - 1) % nedges);
160       ta = 0.0f;
161       tb = 1.0f;
162       ok = true;
163     }
164     else {
165       // here it's not good, our edge is a single point -> skip that face
166       ok = false;
167 #if 0
168       // the order of the WOEdge index is good
169       woea = _pWXFace->GetOEdge((index - 1) % nedges);
170       woeb = _pWXFace->GetOEdge((index + 1) % nedges);
171       ta = 1.0f;
172       tb = 0.0f;
173 #endif
174     }
175   }
176   if (ok) {
177     _pSmoothEdge = new WXSmoothEdge;
178     _pSmoothEdge->setWOeA(woea);
179     _pSmoothEdge->setWOeB(woeb);
180     _pSmoothEdge->setTa(ta);
181     _pSmoothEdge->setTb(tb);
182     if (_Nature & Nature::SILHOUETTE) {
183       if (_nNullDotP != 2) {
184         if (_DotP[_ClosestPointIndex] + 0.01f > 0.0f) {
185           _pSmoothEdge->setFront(true);
186         }
187         else {
188           _pSmoothEdge->setFront(false);
189         }
190       }
191     }
192   }
193 
194 #if 0
195   // check bording edges to see if they have different dotp values in bording faces.
196   for (int i = 0; i < numberOfEdges(); i++) {
197     WSFace *bface = (WSFace *)GetBordingFace(i);
198     if (bface) {
199       if ((front()) ^
200           (bface->front())) {  // fA->front XOR fB->front (true if one is 0 and the other is 1)
201         // that means that the edge i of the face is a silhouette edge
202         // CHECK FIRST WHETHER THE EXACTSILHOUETTEEDGE HAS
203         // NOT YET BEEN BUILT ON THE OTHER FACE (1 is enough).
204         if (((WSExactFace *)bface)->exactSilhouetteEdge()) {
205           // that means that this silhouette edge has already been built
206           return ((WSExactFace *)bface)->exactSilhouetteEdge();
207         }
208         // Else we must build it
209         WOEdge *woea, *woeb;
210         float ta, tb;
211         if (!front()) {  // is it in the right order ?
212           // the order of the WOEdge index is wrong
213           woea = _OEdgeList[(i + 1) % numberOfEdges()];
214           if (0 == i) {
215             woeb = _OEdgeList[numberOfEdges() - 1];
216           }
217           else {
218             woeb = _OEdgeList[(i - 1)];
219           }
220           ta = 0.0f;
221           tb = 1.0f;
222         }
223         else {
224           // the order of the WOEdge index is good
225           if (0 == i) {
226             woea = _OEdgeList[numberOfEdges() - 1];
227           }
228           else {
229             woea = _OEdgeList[(i - 1)];
230           }
231           woeb = _OEdgeList[(i + 1) % numberOfEdges()];
232           ta = 1.0f;
233           tb = 0.0f;
234         }
235 
236         _pSmoothEdge = new ExactSilhouetteEdge(ExactSilhouetteEdge::VERTEX_VERTEX);
237         _pSmoothEdge->setWOeA(woea);
238         _pSmoothEdge->setWOeA(woeb);
239         _pSmoothEdge->setTa(ta);
240         _pSmoothEdge->setTb(tb);
241 
242         return _pSmoothEdge;
243       }
244     }
245   }
246 #endif
247   return _pSmoothEdge;
248 }
249 
ComputeCenter()250 void WXFace::ComputeCenter()
251 {
252   vector<WVertex *> iVertexList;
253   RetrieveVertexList(iVertexList);
254   Vec3f center;
255   for (vector<WVertex *>::iterator wv = iVertexList.begin(), wvend = iVertexList.end();
256        wv != wvend;
257        ++wv) {
258     center += (*wv)->GetVertex();
259   }
260   center /= (float)iVertexList.size();
261   setCenter(center);
262 }
263 
264 /**********************************
265  *                                *
266  *                                *
267  *             WXShape            *
268  *                                *
269  *                                *
270  **********************************/
271 
MakeFace(vector<WVertex * > & iVertexList,vector<bool> & iFaceEdgeMarksList,unsigned iMaterialIndex)272 WFace *WXShape::MakeFace(vector<WVertex *> &iVertexList,
273                          vector<bool> &iFaceEdgeMarksList,
274                          unsigned iMaterialIndex)
275 {
276   WFace *face = WShape::MakeFace(iVertexList, iFaceEdgeMarksList, iMaterialIndex);
277   if (!face) {
278     return NULL;
279   }
280 
281   Vec3f center;
282   for (vector<WVertex *>::iterator wv = iVertexList.begin(), wvend = iVertexList.end();
283        wv != wvend;
284        ++wv) {
285     center += (*wv)->GetVertex();
286   }
287   center /= (float)iVertexList.size();
288   ((WXFace *)face)->setCenter(center);
289 
290   return face;
291 }
292 
MakeFace(vector<WVertex * > & iVertexList,vector<Vec3f> & iNormalsList,vector<Vec2f> & iTexCoordsList,vector<bool> & iFaceEdgeMarksList,unsigned iMaterialIndex)293 WFace *WXShape::MakeFace(vector<WVertex *> &iVertexList,
294                          vector<Vec3f> &iNormalsList,
295                          vector<Vec2f> &iTexCoordsList,
296                          vector<bool> &iFaceEdgeMarksList,
297                          unsigned iMaterialIndex)
298 {
299   WFace *face = WShape::MakeFace(
300       iVertexList, iNormalsList, iTexCoordsList, iFaceEdgeMarksList, iMaterialIndex);
301 
302 #if 0
303   Vec3f center;
304   for (vector<WVertex *>::iterator wv = iVertexList.begin(), wvend = iVertexList.end();
305        wv != wvend;
306        ++wv) {
307     center += (*wv)->GetVertex();
308   }
309   center /= (float)iVertexList.size();
310   ((WXFace *)face)->setCenter(center);
311 #endif
312 
313   return face;
314 }
315 
316 } /* namespace Freestyle */
317