Freestyle: Fix for destructive view map modifications during chaining operations.
authorTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>
Thu, 2 Oct 2014 06:26:53 +0000 (15:26 +0900)
committerTamito Kajiyama <rd6t-kjym@asahi-net.or.jp>
Thu, 2 Oct 2014 08:52:16 +0000 (17:52 +0900)
The view map is mostly treated as a read-only data structure by line stylization
operations (i.e., selection, chaining, splitting, sorting and stroke creation).  The
only exception is the chaining operation in some cases where insertion of extra
FEdge objects is necessary to ensure the continuity of underlying FEdges from
which a chain is constructed.

The present revision addresses the removal of extra FEdges so to keep the view
map clean and suitable for reuse in subsequent render frames.

source/blender/freestyle/intern/application/Controller.cpp
source/blender/freestyle/intern/stroke/Chain.cpp
source/blender/freestyle/intern/view_map/Silhouette.h
source/blender/freestyle/intern/view_map/ViewMap.cpp
source/blender/freestyle/intern/view_map/ViewMap.h

index a7f936ff1713afec1511a1dfa298814fa13fbc30..29fed062cdf5b84cd12f28eae92660ac8067f996 100644 (file)
@@ -423,10 +423,15 @@ void Controller::DeleteViewMap(bool freeCache)
                        _DebugNode->addRef();
        }
 
-       if ((freeCache || !_EnableViewMapCache) && NULL != _ViewMap) {
-               delete _ViewMap;
-               _ViewMap = NULL;
-               prevSceneHash = -1.0;
+       if (NULL != _ViewMap) {
+               if (freeCache || !_EnableViewMapCache) {
+                       delete _ViewMap;
+                       _ViewMap = NULL;
+                       prevSceneHash = -1.0;
+               }
+               else {
+                       _ViewMap->Clean();
+               }
        }
 }
 
index 7fd756472b075418bd16ec0641c010d4da34de3b..0e8c2c9ae6fcf96ecdbe514bf014dda863086d53 100644 (file)
@@ -59,6 +59,7 @@ void Chain::push_viewedge_back(ViewEdge *iViewEdge, bool orientation)
                CurvePoint *cp = _Vertices.back(); // assumed to be instantiated as new CurvePoint(iSVertex, 0, 0.f);
                SVertex *sv_first = (*vfirst);
                FEdge *fe = _fedgeB->duplicate();
+               fe->setTemporary(true);
                fe->setVertexB(sv_first);
                fe->vertexA()->shape()->AddEdge(fe);
                fe->vertexA()->AddFEdge(fe);
@@ -119,6 +120,7 @@ void Chain::push_viewedge_front(ViewEdge *iViewEdge, bool orientation)
                SVertex *sv_curr = (*v);
                FEdge *fe = (orientation) ? iViewEdge->fedgeA() : iViewEdge->fedgeB();
                FEdge *fe2 = fe->duplicate();
+               fe2->setTemporary(true);
                fe2->setVertexA(sv_curr);
                fe2->setVertexB(sv_last);
                sv_last->AddFEdge(fe2);
index d838b98c1a8b59b5b0f5d06651c3c0697eb27093..94b00157ccd4b00831b31e4e9dfc77e84fd0d06f 100644 (file)
@@ -378,6 +378,17 @@ public:
                _FEdges.push_back(iFEdge);
        }
 
+       /*! Remove an FEdge from the list of edges emanating from this SVertex. */
+       inline void RemoveFEdge(FEdge *iFEdge)
+       {
+               for (vector<FEdge *>::iterator fe = _FEdges.begin(), fend = _FEdges.end(); fe != fend; fe++) {
+                       if (iFEdge == (*fe)) {
+                               _FEdges.erase(fe);
+                               break;
+                       }
+               }
+       }
+
        /* replaces edge 1 by edge 2 in the list of edges */
        inline void Replace(FEdge *e1, FEdge *e2)
        {
@@ -441,6 +452,10 @@ public:
        /*! angle in radians */
        inline real curvature2d_as_angle() const;
 #endif
+
+#ifdef WITH_CXX_GUARDEDALLOC
+       MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:SVertex")
+#endif
 };
 
 /**********************************/
@@ -518,6 +533,8 @@ protected:
 
        bool _isInImage;
 
+       bool _isTemporary;
+
 public:
        /*! A field that can be used by the user to store any data.
         *  This field must be reseted afterwards using ResetUserData().
@@ -538,6 +555,7 @@ public:
                _occludeeEmpty = true;
                _isSmooth = false;
                _isInImage = true;
+               _isTemporary = false;
        }
 
        /*! Builds an FEdge going from vA to vB. */
@@ -554,6 +572,7 @@ public:
                _occludeeEmpty = true;
                _isSmooth = false;
                _isInImage = true;
+               _isTemporary = false;
        }
 
        /*! Copy constructor */
@@ -573,6 +592,7 @@ public:
                _occludeeEmpty = iBrother._occludeeEmpty;
                _isSmooth = iBrother._isSmooth;
                _isInImage = iBrother._isInImage;
+               _isTemporary = iBrother._isTemporary;
                iBrother.userdata = this;
                userdata = 0;
        }
@@ -708,6 +728,11 @@ public:
                return _isInImage;
        }
 
+       inline bool isTemporary() const
+       {
+               return _isTemporary;
+       }
+
        /* modifiers */
        /*! Sets the first SVertex. */
        inline void setVertexA(SVertex *vA)
@@ -803,6 +828,11 @@ public:
                _isInImage = iFlag;
        }
 
+       inline void setTemporary(bool iFlag)
+       {
+               _isTemporary = iFlag;
+       }
+
        /* checks whether two FEdge have a common vertex.
         *  Returns a pointer on the common vertex if it exists, NULL otherwise.
         */
@@ -931,6 +961,10 @@ public:
         *    The sampling with which we want to iterate over points of this FEdge.
         */
        virtual inline Interface0DIterator pointsEnd(float t = 0.0f);
+
+#ifdef WITH_CXX_GUARDEDALLOC
+       MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:FEdge")
+#endif
 };
 
 //
@@ -1241,6 +1275,10 @@ public:
        {
                _bFaceMark = iFaceMark;
        }
+
+#ifdef WITH_CXX_GUARDEDALLOC
+       MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:FEdgeSharp")
+#endif
 };
 
 /*! Class defining a smooth edge. This kind of edge typically runs across a face of the input mesh. It can be
@@ -1353,6 +1391,10 @@ public:
        {
                _FrsMaterialIndex = i;
        }
+
+#ifdef WITH_CXX_GUARDEDALLOC
+       MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:FEdgeSmooth")
+#endif
 };
 
 
index fd5ebb99f729d0cc9d5e08747646fe8ff5712236..6bb0082e379a50bee4e55459a10e585ec7b1d078 100644 (file)
@@ -63,6 +63,30 @@ ViewMap::~ViewMap()
        _VEdges.clear();
 }
 
+void ViewMap::Clean()
+{
+       vector<FEdge*> tmpEdges;
+
+       for (vector<ViewShape*>::iterator vs = _VShapes.begin(), vsend = _VShapes.end(); vs != vsend; vs++) {
+               vector<FEdge*>& edges = (*vs)->sshape()->getEdgeList();
+               for (vector<FEdge*>::iterator it = edges.begin(), itend = edges.end(); it != itend; it++) {
+                       if ((*it)->isTemporary()) {
+                               (*it)->setTemporary(false); // avoid being counted multiple times
+                               tmpEdges.push_back(*it);
+                       }
+               }
+       }
+
+       for (vector<FEdge*>::iterator it = tmpEdges.begin(), itend = tmpEdges.end(); it != itend; it++) {
+               for (vector<ViewShape*>::iterator vs = _VShapes.begin(), vsend = _VShapes.end(); vs != vsend; vs++) {
+                       (*vs)->sshape()->RemoveEdge(*it);
+               }
+               (*it)->vertexA()->RemoveFEdge(*it);
+               (*it)->vertexB()->RemoveFEdge(*it);
+               delete (*it);
+       }
+}
+
 ViewShape *ViewMap::viewShape(unsigned id)
 {
        int index = _shapeIdToIndex[id];
index a3c3bfbacff7b72e49c569cf4af982c4e1a8ff0d..0ee1864e0867f474485803d192cde0558a0a327c 100644 (file)
@@ -236,6 +236,9 @@ public:
        /* connects a FEdge to the graph trough a SVertex */
        //FEdge *Connect(FEdge *ioEdge, SVertex *ioVertex);
 
+       /* Clean temporary FEdges created by chaining */
+       virtual void Clean();
+
 #ifdef WITH_CXX_GUARDEDALLOC
        MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:ViewMap")
 #endif