Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'release/scripts')
-rwxr-xr-xrelease/scripts/freestyle/data/env_map/brown00.pngbin0 -> 22195 bytes
-rwxr-xr-xrelease/scripts/freestyle/data/env_map/gray00.pngbin0 -> 18513 bytes
-rwxr-xr-xrelease/scripts/freestyle/data/env_map/gray01.pngbin0 -> 9915 bytes
-rwxr-xr-xrelease/scripts/freestyle/data/env_map/gray02.pngbin0 -> 7197 bytes
-rwxr-xr-xrelease/scripts/freestyle/data/env_map/gray03.pngbin0 -> 16109 bytes
-rwxr-xr-xrelease/scripts/freestyle/style_modules/ChainingIterators.py731
-rwxr-xr-xrelease/scripts/freestyle/style_modules/Functions0D.py81
-rwxr-xr-xrelease/scripts/freestyle/style_modules/Functions1D.py45
-rwxr-xr-xrelease/scripts/freestyle/style_modules/PredicatesB1D.py70
-rwxr-xr-xrelease/scripts/freestyle/style_modules/PredicatesU0D.py103
-rwxr-xr-xrelease/scripts/freestyle/style_modules/PredicatesU1D.py381
-rwxr-xr-xrelease/scripts/freestyle/style_modules/anisotropic_diffusion.py74
-rwxr-xr-xrelease/scripts/freestyle/style_modules/apriori_and_causal_density.py45
-rwxr-xr-xrelease/scripts/freestyle/style_modules/apriori_density.py43
-rwxr-xr-xrelease/scripts/freestyle/style_modules/backbone_stretcher.py36
-rwxr-xr-xrelease/scripts/freestyle/style_modules/blueprint_circles.py46
-rwxr-xr-xrelease/scripts/freestyle/style_modules/blueprint_ellipses.py46
-rwxr-xr-xrelease/scripts/freestyle/style_modules/blueprint_squares.py45
-rwxr-xr-xrelease/scripts/freestyle/style_modules/cartoon.py42
-rwxr-xr-xrelease/scripts/freestyle/style_modules/contour.py42
-rwxr-xr-xrelease/scripts/freestyle/style_modules/curvature2d.py60
-rwxr-xr-xrelease/scripts/freestyle/style_modules/external_contour.py43
-rwxr-xr-xrelease/scripts/freestyle/style_modules/external_contour_sketchy.py48
-rwxr-xr-xrelease/scripts/freestyle/style_modules/external_contour_smooth.py44
-rwxr-xr-xrelease/scripts/freestyle/style_modules/extra-lines.sml3
-rw-r--r--release/scripts/freestyle/style_modules/freestyle_init.py2
-rwxr-xr-xrelease/scripts/freestyle/style_modules/haloing.py50
-rwxr-xr-xrelease/scripts/freestyle/style_modules/ignore_small_occlusions.py41
-rwxr-xr-xrelease/scripts/freestyle/style_modules/invisible_lines.py42
-rwxr-xr-xrelease/scripts/freestyle/style_modules/japanese_bigbrush.py60
-rwxr-xr-xrelease/scripts/freestyle/style_modules/logical_operators.py36
-rwxr-xr-xrelease/scripts/freestyle/style_modules/long_anisotropically_dense.py81
-rwxr-xr-xrelease/scripts/freestyle/style_modules/multiple_parameterization.py51
-rwxr-xr-xrelease/scripts/freestyle/style_modules/nature.py43
-rwxr-xr-xrelease/scripts/freestyle/style_modules/near_lines.py44
-rwxr-xr-xrelease/scripts/freestyle/style_modules/occluded_by_specific_object.py45
-rw-r--r--release/scripts/freestyle/style_modules/parameter_editor.py953
-rwxr-xr-xrelease/scripts/freestyle/style_modules/polygonalize.py40
-rwxr-xr-xrelease/scripts/freestyle/style_modules/qi0.py41
-rwxr-xr-xrelease/scripts/freestyle/style_modules/qi0_not_external_contour.py43
-rwxr-xr-xrelease/scripts/freestyle/style_modules/qi1.py42
-rwxr-xr-xrelease/scripts/freestyle/style_modules/qi2.py42
-rwxr-xr-xrelease/scripts/freestyle/style_modules/sequentialsplit_sketchy.py68
-rwxr-xr-xrelease/scripts/freestyle/style_modules/shaders.py1290
-rwxr-xr-xrelease/scripts/freestyle/style_modules/sketchy_multiple_parameterization.py48
-rwxr-xr-xrelease/scripts/freestyle/style_modules/sketchy_topology_broken.py89
-rwxr-xr-xrelease/scripts/freestyle/style_modules/sketchy_topology_preserved.py49
-rwxr-xr-xrelease/scripts/freestyle/style_modules/split_at_highest_2d_curvatures.py41
-rwxr-xr-xrelease/scripts/freestyle/style_modules/split_at_tvertices.py42
-rwxr-xr-xrelease/scripts/freestyle/style_modules/stroke_texture.py43
-rwxr-xr-xrelease/scripts/freestyle/style_modules/suggestive.py43
-rwxr-xr-xrelease/scripts/freestyle/style_modules/thickness_fof_depth_discontinuity.py62
-rwxr-xr-xrelease/scripts/freestyle/style_modules/tipremover.py42
-rwxr-xr-xrelease/scripts/freestyle/style_modules/tvertex_remover.py42
-rwxr-xr-xrelease/scripts/freestyle/style_modules/uniformpruning_zsort.py40
-rw-r--r--release/scripts/startup/bl_operators/__init__.py1
-rw-r--r--release/scripts/startup/bl_operators/freestyle.py71
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py408
58 files changed, 6062 insertions, 1 deletions
diff --git a/release/scripts/freestyle/data/env_map/brown00.png b/release/scripts/freestyle/data/env_map/brown00.png
new file mode 100755
index 00000000000..855f06f4fb9
--- /dev/null
+++ b/release/scripts/freestyle/data/env_map/brown00.png
Binary files differ
diff --git a/release/scripts/freestyle/data/env_map/gray00.png b/release/scripts/freestyle/data/env_map/gray00.png
new file mode 100755
index 00000000000..7c9b1a8149e
--- /dev/null
+++ b/release/scripts/freestyle/data/env_map/gray00.png
Binary files differ
diff --git a/release/scripts/freestyle/data/env_map/gray01.png b/release/scripts/freestyle/data/env_map/gray01.png
new file mode 100755
index 00000000000..06542908e6b
--- /dev/null
+++ b/release/scripts/freestyle/data/env_map/gray01.png
Binary files differ
diff --git a/release/scripts/freestyle/data/env_map/gray02.png b/release/scripts/freestyle/data/env_map/gray02.png
new file mode 100755
index 00000000000..0208f4920d9
--- /dev/null
+++ b/release/scripts/freestyle/data/env_map/gray02.png
Binary files differ
diff --git a/release/scripts/freestyle/data/env_map/gray03.png b/release/scripts/freestyle/data/env_map/gray03.png
new file mode 100755
index 00000000000..aab9b957c21
--- /dev/null
+++ b/release/scripts/freestyle/data/env_map/gray03.png
Binary files differ
diff --git a/release/scripts/freestyle/style_modules/ChainingIterators.py b/release/scripts/freestyle/style_modules/ChainingIterators.py
new file mode 100755
index 00000000000..f2d953ddc14
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/ChainingIterators.py
@@ -0,0 +1,731 @@
+#
+# Filename : ChainingIterators.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Chaining Iterators to be used with chaining operators
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+
+## the natural chaining iterator
+## It follows the edges of same nature following the topology of
+## objects with preseance on silhouettes, then borders,
+## then suggestive contours, then everything else. It doesn't chain the same ViewEdge twice
+## You can specify whether to stay in the selection or not.
+class pyChainSilhouetteIterator(ChainingIterator):
+ def __init__(self, stayInSelection=1):
+ ChainingIterator.__init__(self, stayInSelection, 1,None,1)
+ def getExactTypeName(self):
+ return "pyChainSilhouetteIterator"
+ def init(self):
+ pass
+ def traverse(self, iter):
+ winner = None
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for i in range(len(natures)):
+ currentNature = self.getCurrentEdge().getNature()
+ if(natures[i] & currentNature):
+ count=0
+ while(it.isEnd() == 0):
+ visitNext = 0
+ oNature = it.getObject().getNature()
+ if(oNature & natures[i] != 0):
+ if(natures[i] != oNature):
+ for j in range(i):
+ if(natures[j] & oNature != 0):
+ visitNext = 1
+ break
+ if(visitNext != 0):
+ break
+ count = count+1
+ winner = it.getObject()
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ return winner
+
+## the natural chaining iterator
+## It follows the edges of same nature on the same
+## objects with preseance on silhouettes, then borders,
+## then suggestive contours, then everything else. It doesn't chain the same ViewEdge twice
+## You can specify whether to stay in the selection or not.
+## You can specify whether to chain iterate over edges that were
+## already visited or not.
+class pyChainSilhouetteGenericIterator(ChainingIterator):
+ def __init__(self, stayInSelection=1, stayInUnvisited=1):
+ ChainingIterator.__init__(self, stayInSelection, stayInUnvisited,None,1)
+ def getExactTypeName(self):
+ return "pyChainSilhouetteGenericIterator"
+ def init(self):
+ pass
+ def traverse(self, iter):
+ winner = None
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for i in range(len(natures)):
+ currentNature = self.getCurrentEdge().getNature()
+ if(natures[i] & currentNature):
+ count=0
+ while(it.isEnd() == 0):
+ visitNext = 0
+ oNature = it.getObject().getNature()
+ ve = it.getObject()
+ if(ve.getId() == self.getCurrentEdge().getId()):
+ it.increment()
+ continue
+ if(oNature & natures[i] != 0):
+ if(natures[i] != oNature):
+ for j in range(i):
+ if(natures[j] & oNature != 0):
+ visitNext = 1
+ break
+ if(visitNext != 0):
+ break
+ count = count+1
+ winner = ve
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ return winner
+
+class pyExternalContourChainingIterator(ChainingIterator):
+ def __init__(self):
+ ChainingIterator.__init__(self, 0, 1,None,1)
+ self._isExternalContour = ExternalContourUP1D()
+
+ def getExactTypeName(self):
+ return "pyExternalContourIterator"
+
+ def init(self):
+ self._nEdges = 0
+ self._isInSelection = 1
+
+ def checkViewEdge(self, ve, orientation):
+ if(orientation != 0):
+ vertex = ve.B()
+ else:
+ vertex = ve.A()
+ it = AdjacencyIterator(vertex,1,1)
+ while(it.isEnd() == 0):
+ ave = it.getObject()
+ if(self._isExternalContour(ave)):
+ return 1
+ it.increment()
+ print("pyExternlContourChainingIterator : didn't find next edge")
+ return 0
+ def traverse(self, iter):
+ winner = None
+ it = AdjacencyIterator(iter)
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(self._isExternalContour(ve)):
+ if (ve.getTimeStamp() == GetTimeStampCF()):
+ winner = ve
+ it.increment()
+
+ self._nEdges = self._nEdges+1
+ if(winner == None):
+ orient = 1
+ it = AdjacencyIterator(iter)
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(it.isIncoming() != 0):
+ orient = 0
+ good = self.checkViewEdge(ve,orient)
+ if(good != 0):
+ winner = ve
+ it.increment()
+ return winner
+
+## the natural chaining iterator
+## with a sketchy multiple touch
+class pySketchyChainSilhouetteIterator(ChainingIterator):
+ def __init__(self, nRounds=3,stayInSelection=1):
+ ChainingIterator.__init__(self, stayInSelection, 0,None,1)
+ self._timeStamp = GetTimeStampCF()+nRounds
+ self._nRounds = nRounds
+ def getExactTypeName(self):
+ return "pySketchyChainSilhouetteIterator"
+ def init(self):
+ self._timeStamp = GetTimeStampCF()+self._nRounds
+ def traverse(self, iter):
+ winner = None
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for i in range(len(natures)):
+ currentNature = self.getCurrentEdge().getNature()
+ if(natures[i] & currentNature):
+ count=0
+ while(it.isEnd() == 0):
+ visitNext = 0
+ oNature = it.getObject().getNature()
+ ve = it.getObject()
+ if(ve.getId() == self.getCurrentEdge().getId()):
+ it.increment()
+ continue
+ if(oNature & natures[i] != 0):
+ if(natures[i] != oNature):
+ for j in range(i):
+ if(natures[j] & oNature != 0):
+ visitNext = 1
+ break
+ if(visitNext != 0):
+ break
+ count = count+1
+ winner = ve
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ if(winner == None):
+ winner = self.getCurrentEdge()
+ if(winner.getChainingTimeStamp() == self._timeStamp):
+ winner = None
+ return winner
+
+
+# Chaining iterator designed for sketchy style.
+# can chain several times the same ViewEdge
+# in order to produce multiple strokes per ViewEdge.
+class pySketchyChainingIterator(ChainingIterator):
+ def __init__(self, nRounds=3, stayInSelection=1):
+ ChainingIterator.__init__(self, stayInSelection, 0,None,1)
+ self._timeStamp = GetTimeStampCF()+nRounds
+ self._nRounds = nRounds
+ def getExactTypeName(self):
+ return "pySketchyChainingIterator"
+
+ def init(self):
+ self._timeStamp = GetTimeStampCF()+self._nRounds
+
+ def traverse(self, iter):
+ winner = None
+ it = AdjacencyIterator(iter)
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == self.getCurrentEdge().getId()):
+ it.increment()
+ continue
+ winner = ve
+ it.increment()
+ if(winner == None):
+ winner = self.getCurrentEdge()
+ if(winner.getChainingTimeStamp() == self._timeStamp):
+ return None
+ return winner
+
+
+## Chaining iterator that fills small occlusions
+## percent
+## The max length of the occluded part
+## expressed in % of the total chain length
+class pyFillOcclusionsRelativeChainingIterator(ChainingIterator):
+ def __init__(self, percent):
+ ChainingIterator.__init__(self, 0, 1,None,1)
+ self._length = 0
+ self._percent = float(percent)
+ def getExactTypeName(self):
+ return "pyFillOcclusionsChainingIterator"
+ def init(self):
+ # each time we're evaluating a chain length
+ # we try to do it once. Thus we reinit
+ # the chain length here:
+ self._length = 0
+ def traverse(self, iter):
+ winner = None
+ winnerOrientation = 0
+ print(self.getCurrentEdge().getId().getFirst(), self.getCurrentEdge().getId().getSecond())
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for nat in natures:
+ if(self.getCurrentEdge().getNature() & nat != 0):
+ count=0
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getNature() & nat != 0):
+ count = count+1
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ if(winner != None):
+ # check whether this edge was part of the selection
+ if(winner.getTimeStamp() != GetTimeStampCF()):
+ #print("---", winner.getId().getFirst(), winner.getId().getSecond())
+ # if not, let's check whether it's short enough with
+ # respect to the chain made without staying in the selection
+ #------------------------------------------------------------
+ # Did we compute the prospective chain length already ?
+ if(self._length == 0):
+ #if not, let's do it
+ _it = pyChainSilhouetteGenericIterator(0,0)
+ _it.setBegin(winner)
+ _it.setCurrentEdge(winner)
+ _it.setOrientation(winnerOrientation)
+ _it.init()
+ while(_it.isEnd() == 0):
+ ve = _it.getObject()
+ #print("--------", ve.getId().getFirst(), ve.getId().getSecond())
+ self._length = self._length + ve.getLength2D()
+ _it.increment()
+ if(_it.isBegin() != 0):
+ break;
+ _it.setBegin(winner)
+ _it.setCurrentEdge(winner)
+ _it.setOrientation(winnerOrientation)
+ if(_it.isBegin() == 0):
+ _it.decrement()
+ while ((_it.isEnd() == 0) and (_it.isBegin() == 0)):
+ ve = _it.getObject()
+ #print("--------", ve.getId().getFirst(), ve.getId().getSecond())
+ self._length = self._length + ve.getLength2D()
+ _it.decrement()
+
+ # let's do the comparison:
+ # nw let's compute the length of this connex non selected part:
+ connexl = 0
+ _cit = pyChainSilhouetteGenericIterator(0,0)
+ _cit.setBegin(winner)
+ _cit.setCurrentEdge(winner)
+ _cit.setOrientation(winnerOrientation)
+ _cit.init()
+ while((_cit.isEnd() == 0) and (_cit.getObject().getTimeStamp() != GetTimeStampCF())):
+ ve = _cit.getObject()
+ #print("-------- --------", ve.getId().getFirst(), ve.getId().getSecond())
+ connexl = connexl + ve.getLength2D()
+ _cit.increment()
+ if(connexl > self._percent * self._length):
+ winner = None
+ return winner
+
+## Chaining iterator that fills small occlusions
+## size
+## The max length of the occluded part
+## expressed in pixels
+class pyFillOcclusionsAbsoluteChainingIterator(ChainingIterator):
+ def __init__(self, length):
+ ChainingIterator.__init__(self, 0, 1,None,1)
+ self._length = float(length)
+ def getExactTypeName(self):
+ return "pySmallFillOcclusionsChainingIterator"
+ def init(self):
+ pass
+ def traverse(self, iter):
+ winner = None
+ winnerOrientation = 0
+ #print(self.getCurrentEdge().getId().getFirst(), self.getCurrentEdge().getId().getSecond())
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for nat in natures:
+ if(self.getCurrentEdge().getNature() & nat != 0):
+ count=0
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getNature() & nat != 0):
+ count = count+1
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ if(winner != None):
+ # check whether this edge was part of the selection
+ if(winner.getTimeStamp() != GetTimeStampCF()):
+ #print("---", winner.getId().getFirst(), winner.getId().getSecond())
+ # nw let's compute the length of this connex non selected part:
+ connexl = 0
+ _cit = pyChainSilhouetteGenericIterator(0,0)
+ _cit.setBegin(winner)
+ _cit.setCurrentEdge(winner)
+ _cit.setOrientation(winnerOrientation)
+ _cit.init()
+ while((_cit.isEnd() == 0) and (_cit.getObject().getTimeStamp() != GetTimeStampCF())):
+ ve = _cit.getObject()
+ #print("-------- --------", ve.getId().getFirst(), ve.getId().getSecond())
+ connexl = connexl + ve.getLength2D()
+ _cit.increment()
+ if(connexl > self._length):
+ winner = None
+ return winner
+
+
+## Chaining iterator that fills small occlusions
+## percent
+## The max length of the occluded part
+## expressed in % of the total chain length
+class pyFillOcclusionsAbsoluteAndRelativeChainingIterator(ChainingIterator):
+ def __init__(self, percent, l):
+ ChainingIterator.__init__(self, 0, 1,None,1)
+ self._length = 0
+ self._absLength = l
+ self._percent = float(percent)
+ def getExactTypeName(self):
+ return "pyFillOcclusionsChainingIterator"
+ def init(self):
+ # each time we're evaluating a chain length
+ # we try to do it once. Thus we reinit
+ # the chain length here:
+ self._length = 0
+ def traverse(self, iter):
+ winner = None
+ winnerOrientation = 0
+ print(self.getCurrentEdge().getId().getFirst(), self.getCurrentEdge().getId().getSecond())
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for nat in natures:
+ if(self.getCurrentEdge().getNature() & nat != 0):
+ count=0
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getNature() & nat != 0):
+ count = count+1
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ if(winner != None):
+ # check whether this edge was part of the selection
+ if(winner.getTimeStamp() != GetTimeStampCF()):
+ #print("---", winner.getId().getFirst(), winner.getId().getSecond())
+ # if not, let's check whether it's short enough with
+ # respect to the chain made without staying in the selection
+ #------------------------------------------------------------
+ # Did we compute the prospective chain length already ?
+ if(self._length == 0):
+ #if not, let's do it
+ _it = pyChainSilhouetteGenericIterator(0,0)
+ _it.setBegin(winner)
+ _it.setCurrentEdge(winner)
+ _it.setOrientation(winnerOrientation)
+ _it.init()
+ while(_it.isEnd() == 0):
+ ve = _it.getObject()
+ #print("--------", ve.getId().getFirst(), ve.getId().getSecond())
+ self._length = self._length + ve.getLength2D()
+ _it.increment()
+ if(_it.isBegin() != 0):
+ break;
+ _it.setBegin(winner)
+ _it.setCurrentEdge(winner)
+ _it.setOrientation(winnerOrientation)
+ if(_it.isBegin() == 0):
+ _it.decrement()
+ while ((_it.isEnd() == 0) and (_it.isBegin() == 0)):
+ ve = _it.getObject()
+ #print("--------", ve.getId().getFirst(), ve.getId().getSecond())
+ self._length = self._length + ve.getLength2D()
+ _it.decrement()
+
+ # let's do the comparison:
+ # nw let's compute the length of this connex non selected part:
+ connexl = 0
+ _cit = pyChainSilhouetteGenericIterator(0,0)
+ _cit.setBegin(winner)
+ _cit.setCurrentEdge(winner)
+ _cit.setOrientation(winnerOrientation)
+ _cit.init()
+ while((_cit.isEnd() == 0) and (_cit.getObject().getTimeStamp() != GetTimeStampCF())):
+ ve = _cit.getObject()
+ #print("-------- --------", ve.getId().getFirst(), ve.getId().getSecond())
+ connexl = connexl + ve.getLength2D()
+ _cit.increment()
+ if((connexl > self._percent * self._length) or (connexl > self._absLength)):
+ winner = None
+ return winner
+
+## Chaining iterator that fills small occlusions without caring about the
+## actual selection
+## percent
+## The max length of the occluded part
+## expressed in % of the total chain length
+class pyFillQi0AbsoluteAndRelativeChainingIterator(ChainingIterator):
+ def __init__(self, percent, l):
+ ChainingIterator.__init__(self, 0, 1,None,1)
+ self._length = 0
+ self._absLength = l
+ self._percent = float(percent)
+ def getExactTypeName(self):
+ return "pyFillOcclusionsChainingIterator"
+ def init(self):
+ # each time we're evaluating a chain length
+ # we try to do it once. Thus we reinit
+ # the chain length here:
+ self._length = 0
+ def traverse(self, iter):
+ winner = None
+ winnerOrientation = 0
+ print(self.getCurrentEdge().getId().getFirst(), self.getCurrentEdge().getId().getSecond())
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for nat in natures:
+ if(self.getCurrentEdge().getNature() & nat != 0):
+ count=0
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getNature() & nat != 0):
+ count = count+1
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ if(winner != None):
+ # check whether this edge was part of the selection
+ if(winner.qi() != 0):
+ #print("---", winner.getId().getFirst(), winner.getId().getSecond())
+ # if not, let's check whether it's short enough with
+ # respect to the chain made without staying in the selection
+ #------------------------------------------------------------
+ # Did we compute the prospective chain length already ?
+ if(self._length == 0):
+ #if not, let's do it
+ _it = pyChainSilhouetteGenericIterator(0,0)
+ _it.setBegin(winner)
+ _it.setCurrentEdge(winner)
+ _it.setOrientation(winnerOrientation)
+ _it.init()
+ while(_it.isEnd() == 0):
+ ve = _it.getObject()
+ #print("--------", ve.getId().getFirst(), ve.getId().getSecond())
+ self._length = self._length + ve.getLength2D()
+ _it.increment()
+ if(_it.isBegin() != 0):
+ break;
+ _it.setBegin(winner)
+ _it.setCurrentEdge(winner)
+ _it.setOrientation(winnerOrientation)
+ if(_it.isBegin() == 0):
+ _it.decrement()
+ while ((_it.isEnd() == 0) and (_it.isBegin() == 0)):
+ ve = _it.getObject()
+ #print("--------", ve.getId().getFirst(), ve.getId().getSecond())
+ self._length = self._length + ve.getLength2D()
+ _it.decrement()
+
+ # let's do the comparison:
+ # nw let's compute the length of this connex non selected part:
+ connexl = 0
+ _cit = pyChainSilhouetteGenericIterator(0,0)
+ _cit.setBegin(winner)
+ _cit.setCurrentEdge(winner)
+ _cit.setOrientation(winnerOrientation)
+ _cit.init()
+ while((_cit.isEnd() == 0) and (_cit.getObject().qi() != 0)):
+ ve = _cit.getObject()
+ #print("-------- --------", ve.getId().getFirst(), ve.getId().getSecond())
+ connexl = connexl + ve.getLength2D()
+ _cit.increment()
+ if((connexl > self._percent * self._length) or (connexl > self._absLength)):
+ winner = None
+ return winner
+
+
+## the natural chaining iterator
+## It follows the edges of same nature on the same
+## objects with preseance on silhouettes, then borders,
+## then suggestive contours, then everything else. It doesn't chain the same ViewEdge twice
+## You can specify whether to stay in the selection or not.
+class pyNoIdChainSilhouetteIterator(ChainingIterator):
+ def __init__(self, stayInSelection=1):
+ ChainingIterator.__init__(self, stayInSelection, 1,None,1)
+ def getExactTypeName(self):
+ return "pyChainSilhouetteIterator"
+ def init(self):
+ pass
+ def traverse(self, iter):
+ winner = None
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ feB = self.getCurrentEdge().fedgeB()
+ feA = ve.fedgeA()
+ vB = feB.vertexB()
+ vA = feA.vertexA()
+ if vA.getId().getFirst() == vB.getId().getFirst():
+ winner = ve
+ break
+ feA = self.getCurrentEdge().fedgeA()
+ feB = ve.fedgeB()
+ vB = feB.vertexB()
+ vA = feA.vertexA()
+ if vA.getId().getFirst() == vB.getId().getFirst():
+ winner = ve
+ break
+ feA = self.getCurrentEdge().fedgeB()
+ feB = ve.fedgeB()
+ vB = feB.vertexB()
+ vA = feA.vertexB()
+ if vA.getId().getFirst() == vB.getId().getFirst():
+ winner = ve
+ break
+ feA = self.getCurrentEdge().fedgeA()
+ feB = ve.fedgeA()
+ vB = feB.vertexA()
+ vA = feA.vertexA()
+ if vA.getId().getFirst() == vB.getId().getFirst():
+ winner = ve
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for i in range(len(natures)):
+ currentNature = self.getCurrentEdge().getNature()
+ if(natures[i] & currentNature):
+ count=0
+ while(it.isEnd() == 0):
+ visitNext = 0
+ oNature = it.getObject().getNature()
+ if(oNature & natures[i] != 0):
+ if(natures[i] != oNature):
+ for j in range(i):
+ if(natures[j] & oNature != 0):
+ visitNext = 1
+ break
+ if(visitNext != 0):
+ break
+ count = count+1
+ winner = it.getObject()
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ return winner
+
diff --git a/release/scripts/freestyle/style_modules/Functions0D.py b/release/scripts/freestyle/style_modules/Functions0D.py
new file mode 100755
index 00000000000..2881a80c386
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/Functions0D.py
@@ -0,0 +1,81 @@
+from freestyle_init import *
+
+
+class pyInverseCurvature2DAngleF0D(UnaryFunction0DDouble):
+ def getName(self):
+ return "InverseCurvature2DAngleF0D"
+
+ def __call__(self, inter):
+ func = Curvature2DAngleF0D()
+ c = func(inter)
+ return (3.1415 - c)
+
+class pyCurvilinearLengthF0D(UnaryFunction0DDouble):
+ def getName(self):
+ return "CurvilinearLengthF0D"
+
+ def __call__(self, inter):
+ i0d = inter.getObject()
+ s = i0d.getExactTypeName()
+ if (string.find(s, "CurvePoint") == -1):
+ print("CurvilinearLengthF0D: not implemented yet for", s)
+ return -1
+ cp = castToCurvePoint(i0d)
+ return cp.t2d()
+
+## estimate anisotropy of density
+class pyDensityAnisotropyF0D(UnaryFunction0DDouble):
+ def __init__(self,level):
+ UnaryFunction0DDouble.__init__(self)
+ self.IsoDensity = ReadCompleteViewMapPixelF0D(level)
+ self.d0Density = ReadSteerableViewMapPixelF0D(0, level)
+ self.d1Density = ReadSteerableViewMapPixelF0D(1, level)
+ self.d2Density = ReadSteerableViewMapPixelF0D(2, level)
+ self.d3Density = ReadSteerableViewMapPixelF0D(3, level)
+ def getName(self):
+ return "pyDensityAnisotropyF0D"
+ def __call__(self, inter):
+ c_iso = self.IsoDensity(inter)
+ c_0 = self.d0Density(inter)
+ c_1 = self.d1Density(inter)
+ c_2 = self.d2Density(inter)
+ c_3 = self.d3Density(inter)
+ cMax = max( max(c_0,c_1), max(c_2,c_3))
+ cMin = min( min(c_0,c_1), min(c_2,c_3))
+ if ( c_iso == 0 ):
+ v = 0
+ else:
+ v = (cMax-cMin)/c_iso
+ return (v)
+
+## Returns the gradient vector for a pixel
+## l
+## the level at which one wants to compute the gradient
+class pyViewMapGradientVectorF0D(UnaryFunction0DVec2f):
+ def __init__(self, l):
+ UnaryFunction0DVec2f.__init__(self)
+ self._l = l
+ self._step = pow(2,self._l)
+ def getName(self):
+ return "pyViewMapGradientVectorF0D"
+ def __call__(self, iter):
+ p = iter.getObject().getPoint2D()
+ gx = ReadCompleteViewMapPixelCF(self._l, int(p.x()+self._step), int(p.y()))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()))
+ gy = ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()+self._step))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()))
+ return Vector([gx, gy])
+
+class pyViewMapGradientNormF0D(UnaryFunction0DDouble):
+ def __init__(self, l):
+ UnaryFunction0DDouble.__init__(self)
+ self._l = l
+ self._step = pow(2,self._l)
+ def getName(self):
+ return "pyViewMapGradientNormF0D"
+ def __call__(self, iter):
+ p = iter.getObject().getPoint2D()
+ gx = ReadCompleteViewMapPixelCF(self._l, int(p.x()+self._step), int(p.y()))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()))
+ gy = ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()+self._step))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()))
+ grad = Vector([gx, gy])
+ return grad.length
+
+
diff --git a/release/scripts/freestyle/style_modules/Functions1D.py b/release/scripts/freestyle/style_modules/Functions1D.py
new file mode 100755
index 00000000000..aaf115356cb
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/Functions1D.py
@@ -0,0 +1,45 @@
+from freestyle_init import *
+from Functions0D import *
+import string
+
+class pyGetInverseProjectedZF1D(UnaryFunction1DDouble):
+ def getName(self):
+ return "pyGetInverseProjectedZF1D"
+
+ def __call__(self, inter):
+ func = GetProjectedZF1D()
+ z = func(inter)
+ return (1.0 - z)
+
+class pyGetSquareInverseProjectedZF1D(UnaryFunction1DDouble):
+ def getName(self):
+ return "pyGetInverseProjectedZF1D"
+
+ def __call__(self, inter):
+ func = GetProjectedZF1D()
+ z = func(inter)
+ return (1.0 - z*z)
+
+class pyDensityAnisotropyF1D(UnaryFunction1DDouble):
+ def __init__(self,level, integrationType=IntegrationType.MEAN, sampling=2.0):
+ UnaryFunction1DDouble.__init__(self, integrationType)
+ self._func = pyDensityAnisotropyF0D(level)
+ self._integration = integrationType
+ self._sampling = sampling
+ def getName(self):
+ return "pyDensityAnisotropyF1D"
+ def __call__(self, inter):
+ v = integrate(self._func, inter.pointsBegin(self._sampling), inter.pointsEnd(self._sampling), self._integration)
+ return v
+
+class pyViewMapGradientNormF1D(UnaryFunction1DDouble):
+ def __init__(self,l, integrationType, sampling=2.0):
+ UnaryFunction1DDouble.__init__(self, integrationType)
+ self._func = pyViewMapGradientNormF0D(l)
+ self._integration = integrationType
+ self._sampling = sampling
+ def getName(self):
+ return "pyViewMapGradientNormF1D"
+ def __call__(self, inter):
+ v = integrate(self._func, inter.pointsBegin(self._sampling), inter.pointsEnd(self._sampling), self._integration)
+ return v
diff --git a/release/scripts/freestyle/style_modules/PredicatesB1D.py b/release/scripts/freestyle/style_modules/PredicatesB1D.py
new file mode 100755
index 00000000000..3b7d21039df
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/PredicatesB1D.py
@@ -0,0 +1,70 @@
+from freestyle_init import *
+from Functions1D import *
+from random import *
+
+class pyZBP1D(BinaryPredicate1D):
+ def getName(self):
+ return "pyZBP1D"
+
+ def __call__(self, i1, i2):
+ func = GetZF1D()
+ return (func(i1) > func(i2))
+
+class pyZDiscontinuityBP1D(BinaryPredicate1D):
+ def __init__(self, iType = IntegrationType.MEAN):
+ BinaryPredicate1D.__init__(self)
+ self._GetZDiscontinuity = ZDiscontinuityF1D(iType)
+
+ def getName(self):
+ return "pyZDiscontinuityBP1D"
+
+ def __call__(self, i1, i2):
+ return (self._GetZDiscontinuity(i1) > self._GetZDiscontinuity(i2))
+
+class pyLengthBP1D(BinaryPredicate1D):
+ def getName(self):
+ return "LengthBP1D"
+
+ def __call__(self, i1, i2):
+ return (i1.getLength2D() > i2.getLength2D())
+
+class pySilhouetteFirstBP1D(BinaryPredicate1D):
+ def getName(self):
+ return "SilhouetteFirstBP1D"
+
+ def __call__(self, inter1, inter2):
+ bpred = SameShapeIdBP1D()
+ if (bpred(inter1, inter2) != 1):
+ return 0
+ if (inter1.getNature() & Nature.SILHOUETTE):
+ return (inter2.getNature() & Nature.SILHOUETTE)
+ return (inter1.getNature() == inter2.getNature())
+
+class pyNatureBP1D(BinaryPredicate1D):
+ def getName(self):
+ return "NatureBP1D"
+
+ def __call__(self, inter1, inter2):
+ return (inter1.getNature() & inter2.getNature())
+
+class pyViewMapGradientNormBP1D(BinaryPredicate1D):
+ def __init__(self,l, sampling=2.0):
+ BinaryPredicate1D.__init__(self)
+ self._GetGradient = pyViewMapGradientNormF1D(l, IntegrationType.MEAN)
+ def getName(self):
+ return "pyViewMapGradientNormBP1D"
+ def __call__(self, i1,i2):
+ print("compare gradient")
+ return (self._GetGradient(i1) > self._GetGradient(i2))
+
+class pyShuffleBP1D(BinaryPredicate1D):
+ def __init__(self):
+ BinaryPredicate1D.__init__(self)
+ seed(1)
+ def getName(self):
+ return "pyNearAndContourFirstBP1D"
+
+ def __call__(self, inter1, inter2):
+ r1 = uniform(0,1)
+ r2 = uniform(0,1)
+ return (r1<r2)
diff --git a/release/scripts/freestyle/style_modules/PredicatesU0D.py b/release/scripts/freestyle/style_modules/PredicatesU0D.py
new file mode 100755
index 00000000000..162254f17ed
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/PredicatesU0D.py
@@ -0,0 +1,103 @@
+from freestyle_init import *
+from Functions0D import *
+
+class pyHigherCurvature2DAngleUP0D(UnaryPredicate0D):
+ def __init__(self,a):
+ UnaryPredicate0D.__init__(self)
+ self._a = a
+
+ def getName(self):
+ return "HigherCurvature2DAngleUP0D"
+
+ def __call__(self, inter):
+ func = Curvature2DAngleF0D()
+ a = func(inter)
+ return ( a > self._a)
+
+class pyUEqualsUP0D(UnaryPredicate0D):
+ def __init__(self,u, w):
+ UnaryPredicate0D.__init__(self)
+ self._u = u
+ self._w = w
+
+ def getName(self):
+ return "UEqualsUP0D"
+
+ def __call__(self, inter):
+ func = pyCurvilinearLengthF0D()
+ u = func(inter)
+ return ( ( u > (self._u-self._w) ) and ( u < (self._u+self._w) ) )
+
+class pyVertexNatureUP0D(UnaryPredicate0D):
+ def __init__(self,nature):
+ UnaryPredicate0D.__init__(self)
+ self._nature = nature
+
+ def getName(self):
+ return "pyVertexNatureUP0D"
+
+ def __call__(self, inter):
+ v = inter.getObject()
+ nat = v.getNature()
+ if(nat & self._nature):
+ return 1;
+ return 0
+
+## check whether an Interface0DIterator
+## is a TVertex and is the one that is
+## hidden (inferred from the context)
+class pyBackTVertexUP0D(UnaryPredicate0D):
+ def __init__(self):
+ UnaryPredicate0D.__init__(self)
+ self._getQI = QuantitativeInvisibilityF0D()
+ def getName(self):
+ return "pyBackTVertexUP0D"
+ def __call__(self, iter):
+ v = iter.getObject()
+ nat = v.getNature()
+ if(nat & Nature.T_VERTEX == 0):
+ return 0
+ next = iter
+ if(next.isEnd()):
+ return 0
+ if(self._getQI(next) != 0):
+ return 1
+ return 0
+
+class pyParameterUP0DGoodOne(UnaryPredicate0D):
+ def __init__(self,pmin,pmax):
+ UnaryPredicate0D.__init__(self)
+ self._m = pmin
+ self._M = pmax
+ #self.getCurvilinearAbscissa = GetCurvilinearAbscissaF0D()
+
+ def getName(self):
+ return "pyCurvilinearAbscissaHigherThanUP0D"
+
+ def __call__(self, inter):
+ #s = self.getCurvilinearAbscissa(inter)
+ u = inter.u()
+ #print(u)
+ return ((u>=self._m) and (u<=self._M))
+
+class pyParameterUP0D(UnaryPredicate0D):
+ def __init__(self,pmin,pmax):
+ UnaryPredicate0D.__init__(self)
+ self._m = pmin
+ self._M = pmax
+ #self.getCurvilinearAbscissa = GetCurvilinearAbscissaF0D()
+
+ def getName(self):
+ return "pyCurvilinearAbscissaHigherThanUP0D"
+
+ def __call__(self, inter):
+ func = Curvature2DAngleF0D()
+ c = func(inter)
+ b1 = (c>0.1)
+ #s = self.getCurvilinearAbscissa(inter)
+ u = inter.u()
+ #print(u)
+ b = ((u>=self._m) and (u<=self._M))
+ return b and b1
+
+
diff --git a/release/scripts/freestyle/style_modules/PredicatesU1D.py b/release/scripts/freestyle/style_modules/PredicatesU1D.py
new file mode 100755
index 00000000000..3529ca8b4e3
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/PredicatesU1D.py
@@ -0,0 +1,381 @@
+from freestyle_init import *
+from Functions1D import *
+
+count = 0
+class pyNFirstUP1D(UnaryPredicate1D):
+ def __init__(self, n):
+ UnaryPredicate1D.__init__(self)
+ self.__n = n
+ def __call__(self, inter):
+ global count
+ count = count + 1
+ if count <= self.__n:
+ return 1
+ return 0
+
+class pyHigherLengthUP1D(UnaryPredicate1D):
+ def __init__(self,l):
+ UnaryPredicate1D.__init__(self)
+ self._l = l
+
+ def getName(self):
+ return "HigherLengthUP1D"
+
+ def __call__(self, inter):
+ return (inter.getLength2D() > self._l)
+
+class pyNatureUP1D(UnaryPredicate1D):
+ def __init__(self,nature):
+ UnaryPredicate1D.__init__(self)
+ self._nature = nature
+ self._getNature = CurveNatureF1D()
+
+ def getName(self):
+ return "pyNatureUP1D"
+
+ def __call__(self, inter):
+ if(self._getNature(inter) & self._nature):
+ return 1
+ return 0
+
+class pyHigherNumberOfTurnsUP1D(UnaryPredicate1D):
+ def __init__(self,n,a):
+ UnaryPredicate1D.__init__(self)
+ self._n = n
+ self._a = a
+
+ def getName(self):
+ return "HigherNumberOfTurnsUP1D"
+
+ def __call__(self, inter):
+ count = 0
+ func = Curvature2DAngleF0D()
+ it = inter.verticesBegin()
+ while(it.isEnd() == 0):
+ if(func(it) > self._a):
+ count = count+1
+ if(count > self._n):
+ return 1
+ it.increment()
+ return 0
+
+class pyDensityUP1D(UnaryPredicate1D):
+ def __init__(self,wsize,threshold, integration = IntegrationType.MEAN, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._wsize = wsize
+ self._threshold = threshold
+ self._integration = integration
+ self._func = DensityF1D(self._wsize, self._integration, sampling)
+
+ def getName(self):
+ return "pyDensityUP1D"
+
+ def __call__(self, inter):
+ if(self._func(inter) < self._threshold):
+ return 1
+ return 0
+
+class pyLowSteerableViewMapDensityUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, level,integration = IntegrationType.MEAN):
+ UnaryPredicate1D.__init__(self)
+ self._threshold = threshold
+ self._level = level
+ self._integration = integration
+
+ def getName(self):
+ return "pyLowSteerableViewMapDensityUP1D"
+
+ def __call__(self, inter):
+ func = GetSteerableViewMapDensityF1D(self._level, self._integration)
+ v = func(inter)
+ print(v)
+ if(v < self._threshold):
+ return 1
+ return 0
+
+class pyLowDirectionalViewMapDensityUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, orientation, level,integration = IntegrationType.MEAN):
+ UnaryPredicate1D.__init__(self)
+ self._threshold = threshold
+ self._orientation = orientation
+ self._level = level
+ self._integration = integration
+
+ def getName(self):
+ return "pyLowDirectionalViewMapDensityUP1D"
+
+ def __call__(self, inter):
+ func = GetDirectionalViewMapDensityF1D(self._orientation, self._level, self._integration)
+ v = func(inter)
+ #print(v)
+ if(v < self._threshold):
+ return 1
+ return 0
+
+class pyHighSteerableViewMapDensityUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, level,integration = IntegrationType.MEAN):
+ UnaryPredicate1D.__init__(self)
+ self._threshold = threshold
+ self._level = level
+ self._integration = integration
+ self._func = GetSteerableViewMapDensityF1D(self._level, self._integration)
+ def getName(self):
+ return "pyHighSteerableViewMapDensityUP1D"
+
+ def __call__(self, inter):
+
+ v = self._func(inter)
+ if(v > self._threshold):
+ return 1
+ return 0
+
+class pyHighDirectionalViewMapDensityUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, orientation, level,integration = IntegrationType.MEAN, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._threshold = threshold
+ self._orientation = orientation
+ self._level = level
+ self._integration = integration
+ self._sampling = sampling
+ def getName(self):
+ return "pyLowDirectionalViewMapDensityUP1D"
+
+ def __call__(self, inter):
+ func = GetDirectionalViewMapDensityF1D(self._orientation, self._level, self._integration, self._sampling)
+ v = func(inter)
+ if(v > self._threshold):
+ return 1
+ return 0
+
+class pyHighViewMapDensityUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, level,integration = IntegrationType.MEAN, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._threshold = threshold
+ self._level = level
+ self._integration = integration
+ self._sampling = sampling
+ self._func = GetCompleteViewMapDensityF1D(self._level, self._integration, self._sampling) # 2.0 is the smpling
+
+ def getName(self):
+ return "pyHighViewMapDensityUP1D"
+
+ def __call__(self, inter):
+ #print("toto")
+ #print(func.getName())
+ #print(inter.getExactTypeName())
+ v= self._func(inter)
+ if(v > self._threshold):
+ return 1
+ return 0
+
+class pyDensityFunctorUP1D(UnaryPredicate1D):
+ def __init__(self,wsize,threshold, functor, funcmin=0.0, funcmax=1.0, integration = IntegrationType.MEAN):
+ UnaryPredicate1D.__init__(self)
+ self._wsize = wsize
+ self._threshold = float(threshold)
+ self._functor = functor
+ self._funcmin = float(funcmin)
+ self._funcmax = float(funcmax)
+ self._integration = integration
+
+ def getName(self):
+ return "pyDensityFunctorUP1D"
+
+ def __call__(self, inter):
+ func = DensityF1D(self._wsize, self._integration)
+ res = self._functor(inter)
+ k = (res-self._funcmin)/(self._funcmax-self._funcmin)
+ if(func(inter) < self._threshold*k):
+ return 1
+ return 0
+
+class pyZSmallerUP1D(UnaryPredicate1D):
+ def __init__(self,z, integration=IntegrationType.MEAN):
+ UnaryPredicate1D.__init__(self)
+ self._z = z
+ self._integration = integration
+ def getName(self):
+ return "pyZSmallerUP1D"
+
+ def __call__(self, inter):
+ func = GetProjectedZF1D(self._integration)
+ if(func(inter) < self._z):
+ return 1
+ return 0
+
+class pyIsOccludedByUP1D(UnaryPredicate1D):
+ def __init__(self,id):
+ UnaryPredicate1D.__init__(self)
+ self._id = id
+ def getName(self):
+ return "pyIsOccludedByUP1D"
+ def __call__(self, inter):
+ func = GetShapeF1D()
+ shapes = func(inter)
+ for s in shapes:
+ if(s.getId() == self._id):
+ return 0
+ it = inter.verticesBegin()
+ itlast = inter.verticesEnd()
+ itlast.decrement()
+ v = it.getObject()
+ vlast = itlast.getObject()
+ tvertex = v.viewvertex()
+ if type(tvertex) is TVertex:
+ print("TVertex: [ ", tvertex.getId().getFirst(), ",", tvertex.getId().getSecond()," ]")
+ eit = tvertex.edgesBegin()
+ while(eit.isEnd() == 0):
+ ve, incoming = eit.getObject()
+ if(ve.getId() == self._id):
+ return 1
+ print("-------", ve.getId().getFirst(), "-", ve.getId().getSecond())
+ eit.increment()
+ tvertex = vlast.viewvertex()
+ if type(tvertex) is TVertex:
+ print("TVertex: [ ", tvertex.getId().getFirst(), ",", tvertex.getId().getSecond()," ]")
+ eit = tvertex.edgesBegin()
+ while(eit.isEnd() == 0):
+ ve, incoming = eit.getObject()
+ if(ve.getId() == self._id):
+ return 1
+ print("-------", ve.getId().getFirst(), "-", ve.getId().getSecond())
+ eit.increment()
+ return 0
+
+class pyIsInOccludersListUP1D(UnaryPredicate1D):
+ def __init__(self,id):
+ UnaryPredicate1D.__init__(self)
+ self._id = id
+ def getName(self):
+ return "pyIsInOccludersListUP1D"
+ def __call__(self, inter):
+ func = GetOccludersF1D()
+ occluders = func(inter)
+ for a in occluders:
+ if(a.getId() == self._id):
+ return 1
+ return 0
+
+class pyIsOccludedByItselfUP1D(UnaryPredicate1D):
+ def __init__(self):
+ UnaryPredicate1D.__init__(self)
+ self.__func1 = GetOccludersF1D()
+ self.__func2 = GetShapeF1D()
+ def getName(self):
+ return "pyIsOccludedByItselfUP1D"
+ def __call__(self, inter):
+ lst1 = self.__func1(inter)
+ lst2 = self.__func2(inter)
+ for vs1 in lst1:
+ for vs2 in lst2:
+ if vs1.getId() == vs2.getId():
+ return 1
+ return 0
+
+class pyIsOccludedByIdListUP1D(UnaryPredicate1D):
+ def __init__(self, idlist):
+ UnaryPredicate1D.__init__(self)
+ self._idlist = idlist
+ self.__func1 = GetOccludersF1D()
+ def getName(self):
+ return "pyIsOccludedByIdListUP1D"
+ def __call__(self, inter):
+ lst1 = self.__func1(inter)
+ for vs1 in lst1:
+ for id in self._idlist:
+ if vs1.getId() == id:
+ return 1
+ return 0
+
+class pyShapeIdListUP1D(UnaryPredicate1D):
+ def __init__(self,idlist):
+ UnaryPredicate1D.__init__(self)
+ self._idlist = idlist
+ self._funcs = []
+ for id in idlist :
+ self._funcs.append(ShapeUP1D(id.getFirst(), id.getSecond()))
+
+ def getName(self):
+ return "pyShapeIdUP1D"
+ def __call__(self, inter):
+ for func in self._funcs :
+ if(func(inter) == 1) :
+ return 1
+ return 0
+
+## deprecated
+class pyShapeIdUP1D(UnaryPredicate1D):
+ def __init__(self,id):
+ UnaryPredicate1D.__init__(self)
+ self._id = id
+ def getName(self):
+ return "pyShapeIdUP1D"
+ def __call__(self, inter):
+ func = GetShapeF1D()
+ shapes = func(inter)
+ for a in shapes:
+ if(a.getId() == self._id):
+ return 1
+ return 0
+
+class pyHighDensityAnisotropyUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, level, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._l = threshold
+ self.func = pyDensityAnisotropyF1D(level, IntegrationType.MEAN, sampling)
+ def getName(self):
+ return "pyHighDensityAnisotropyUP1D"
+ def __call__(self, inter):
+ return (self.func(inter) > self._l)
+
+class pyHighViewMapGradientNormUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, l, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._threshold = threshold
+ self._GetGradient = pyViewMapGradientNormF1D(l, IntegrationType.MEAN)
+ def getName(self):
+ return "pyHighViewMapGradientNormUP1D"
+ def __call__(self, inter):
+ gn = self._GetGradient(inter)
+ #print(gn)
+ return (gn > self._threshold)
+
+class pyDensityVariableSigmaUP1D(UnaryPredicate1D):
+ def __init__(self,functor, sigmaMin,sigmaMax, lmin, lmax, tmin, tmax, integration = IntegrationType.MEAN, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._functor = functor
+ self._sigmaMin = float(sigmaMin)
+ self._sigmaMax = float(sigmaMax)
+ self._lmin = float(lmin)
+ self._lmax = float(lmax)
+ self._tmin = tmin
+ self._tmax = tmax
+ self._integration = integration
+ self._sampling = sampling
+
+ def getName(self):
+ return "pyDensityUP1D"
+
+ def __call__(self, inter):
+ sigma = (self._sigmaMax-self._sigmaMin)/(self._lmax-self._lmin)*(self._functor(inter)-self._lmin) + self._sigmaMin
+ t = (self._tmax-self._tmin)/(self._lmax-self._lmin)*(self._functor(inter)-self._lmin) + self._tmin
+ if(sigma<self._sigmaMin):
+ sigma = self._sigmaMin
+ self._func = DensityF1D(sigma, self._integration, self._sampling)
+ d = self._func(inter)
+ if(d<t):
+ return 1
+ return 0
+
+class pyClosedCurveUP1D(UnaryPredicate1D):
+ def __call__(self, inter):
+ it = inter.verticesBegin()
+ itlast = inter.verticesEnd()
+ itlast.decrement()
+ vlast = itlast.getObject()
+ v = it.getObject()
+ print(v.getId().getFirst(), v.getId().getSecond())
+ print(vlast.getId().getFirst(), vlast.getId().getSecond())
+ if(v.getId() == vlast.getId()):
+ return 1
+ return 0
diff --git a/release/scripts/freestyle/style_modules/anisotropic_diffusion.py b/release/scripts/freestyle/style_modules/anisotropic_diffusion.py
new file mode 100755
index 00000000000..7e7ebf647bd
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/anisotropic_diffusion.py
@@ -0,0 +1,74 @@
+#
+# Filename : anisotropic_diffusion.py
+# Author : Fredo Durand
+# Date : 12/08/2004
+# Purpose : Smoothes lines using an anisotropic diffusion scheme
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+from PredicatesU0D import *
+from math import *
+
+## thickness modifiers
+
+normalInfo=Normal2DF0D()
+curvatureInfo=Curvature2DAngleF0D()
+
+def edgestopping(x, sigma):
+ return exp(- x*x/(2*sigma*sigma))
+
+class pyDiffusion2Shader(StrokeShader):
+ def __init__(self, lambda1, nbIter):
+ StrokeShader.__init__(self)
+ self._lambda = lambda1
+ self._nbIter = nbIter
+ def getName(self):
+ return "pyDiffusionShader"
+ def shade(self, stroke):
+ for i in range (1, self._nbIter):
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v=it.getObject()
+ p1 = v.getPoint()
+ p2 = normalInfo(it.castToInterface0DIterator())*self._lambda*curvatureInfo(it.castToInterface0DIterator())
+ v.setPoint(p1+p2)
+ it.increment()
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D())
+Operators.select( upred )
+bpred = TrueBP1D();
+Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(upred) )
+shaders_list = [
+ ConstantThicknessShader(4),
+ StrokeTextureShader("smoothAlpha.bmp", Stroke.OPAQUE_MEDIUM, 0),
+ SamplingShader(2),
+ pyDiffusion2Shader(-0.03, 30),
+ IncreasingColorShader(1.0,0.0,0.0,1, 0, 1, 0, 1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
+
+
+
diff --git a/release/scripts/freestyle/style_modules/apriori_and_causal_density.py b/release/scripts/freestyle/style_modules/apriori_and_causal_density.py
new file mode 100755
index 00000000000..7cdd4b2fd66
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/apriori_and_causal_density.py
@@ -0,0 +1,45 @@
+#
+# Filename : apriori_and_causal_density.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Selects the lines with high a priori density and
+# subjects them to the causal density so as to avoid
+# cluttering
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), pyHighViewMapDensityUP1D(0.3, IntegrationType.LAST))
+Operators.select(upred)
+bpred = TrueBP1D()
+Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ ConstantThicknessShader(2),
+ ConstantColorShader(0.0, 0.0, 0.0,1)
+ ]
+Operators.create(pyDensityUP1D(1,0.1, IntegrationType.MEAN), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/apriori_density.py b/release/scripts/freestyle/style_modules/apriori_density.py
new file mode 100755
index 00000000000..5ff6c58e77f
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/apriori_density.py
@@ -0,0 +1,43 @@
+#
+# Filename : apriori_density.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws lines having a high a priori density
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+Operators.select(AndUP1D(QuantitativeInvisibilityUP1D(0), pyHighViewMapDensityUP1D(0.1,5)))
+bpred = TrueBP1D()
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), pyHighViewMapDensityUP1D(0.0007,5))
+Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ ConstantThicknessShader(2),
+ ConstantColorShader(0.0, 0.0, 0.0,1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/backbone_stretcher.py b/release/scripts/freestyle/style_modules/backbone_stretcher.py
new file mode 100755
index 00000000000..8a6b9d71a66
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/backbone_stretcher.py
@@ -0,0 +1,36 @@
+#
+# Filename : backbone_stretcher.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Stretches the geometry of visible lines
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [TextureAssignerShader(4), ConstantColorShader(0.5, 0.5, 0.5), BackboneStretcherShader(20)]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/blueprint_circles.py b/release/scripts/freestyle/style_modules/blueprint_circles.py
new file mode 100755
index 00000000000..7f3a7564cfe
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/blueprint_circles.py
@@ -0,0 +1,46 @@
+#
+# Filename : blueprint_circles.py
+# Author : Emmanuel Turquin
+# Date : 04/08/2005
+# Purpose : Produces a blueprint using circular contour strokes
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D())
+bpred = SameShapeIdBP1D()
+Operators.select(upred)
+Operators.bidirectionalChain(ChainPredicateIterator(upred,bpred), NotUP1D(upred))
+Operators.select(pyHigherLengthUP1D(200))
+shaders_list = [
+ ConstantThicknessShader(5),
+ pyBluePrintCirclesShader(3),
+ pyPerlinNoise1DShader(0.1, 15, 8),
+ TextureAssignerShader(4),
+ IncreasingColorShader(0.8, 0.8, 0.3, 0.4, 0.3, 0.3, 0.3, 0.1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/blueprint_ellipses.py b/release/scripts/freestyle/style_modules/blueprint_ellipses.py
new file mode 100755
index 00000000000..a5cfe4ec30b
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/blueprint_ellipses.py
@@ -0,0 +1,46 @@
+#
+# Filename : blueprint_ellipses.py
+# Author : Emmanuel Turquin
+# Date : 04/08/2005
+# Purpose : Produces a blueprint using elliptic contour strokes
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D())
+bpred = SameShapeIdBP1D()
+Operators.select(upred)
+Operators.bidirectionalChain(ChainPredicateIterator(upred,bpred), NotUP1D(upred))
+Operators.select(pyHigherLengthUP1D(200))
+shaders_list = [
+ ConstantThicknessShader(5),
+ pyBluePrintEllipsesShader(3),
+ pyPerlinNoise1DShader(0.1, 10, 8),
+ TextureAssignerShader(4),
+ IncreasingColorShader(0.6, 0.3, 0.3, 0.7, 0.3, 0.3, 0.3, 0.1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/blueprint_squares.py b/release/scripts/freestyle/style_modules/blueprint_squares.py
new file mode 100755
index 00000000000..7798acc7d47
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/blueprint_squares.py
@@ -0,0 +1,45 @@
+# Filename : blueprint_squares.py
+# Author : Emmanuel Turquin
+# Date : 04/08/2005
+# Purpose : Produces a blueprint using square contour strokes
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D())
+bpred = SameShapeIdBP1D()
+Operators.select(upred)
+Operators.bidirectionalChain(ChainPredicateIterator(upred,bpred), NotUP1D(upred))
+Operators.select(pyHigherLengthUP1D(200))
+shaders_list = [
+ ConstantThicknessShader(8),
+ pyBluePrintSquaresShader(2, 20),
+ pyPerlinNoise1DShader(0.07, 10, 8),
+ TextureAssignerShader(4),
+ IncreasingColorShader(0.6, 0.3, 0.3, 0.7, 0.6, 0.3, 0.3, 0.3),
+ ConstantThicknessShader(4)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/cartoon.py b/release/scripts/freestyle/style_modules/cartoon.py
new file mode 100755
index 00000000000..6ace7e0585a
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/cartoon.py
@@ -0,0 +1,42 @@
+#
+# Filename : cartoon.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws colored lines. The color is automatically
+# infered from each object's material in a cartoon-like
+# fashion.
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ BezierCurveShader(3),
+ ConstantThicknessShader(4),
+ pyMaterialColorShader(0.8)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/contour.py b/release/scripts/freestyle/style_modules/contour.py
new file mode 100755
index 00000000000..c4b3a0f0827
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/contour.py
@@ -0,0 +1,42 @@
+#
+# Filename : contour.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws each object's visible contour
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+Operators.select(AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D() ) )
+bpred = SameShapeIdBP1D();
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D())
+Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ ConstantThicknessShader(5.0),
+ IncreasingColorShader(0.8,0,0,1,0.1,0,0,1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/curvature2d.py b/release/scripts/freestyle/style_modules/curvature2d.py
new file mode 100755
index 00000000000..fc2bcab4946
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/curvature2d.py
@@ -0,0 +1,60 @@
+#
+# Filename : curvature2d.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : The stroke points are colored in gray levels and depending
+# on the 2d curvature value
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+class py2DCurvatureColorShader(StrokeShader):
+ def getName(self):
+ return "py2DCurvatureColorShader"
+
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ func = Curvature2DAngleF0D()
+ while it.isEnd() == 0:
+ it0D = it.castToInterface0DIterator()
+ sv = it.getObject()
+ att = sv.attribute()
+ c = func(it0D)
+ if (c<0):
+ print("negative 2D curvature")
+ color = 10.0 * c/3.1415
+ att.setColor(color,color,color);
+ it.increment()
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ StrokeTextureShader("smoothAlpha.bmp", Stroke.OPAQUE_MEDIUM, 0),
+ ConstantThicknessShader(5),
+ py2DCurvatureColorShader()
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/external_contour.py b/release/scripts/freestyle/style_modules/external_contour.py
new file mode 100755
index 00000000000..2a39b79a410
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/external_contour.py
@@ -0,0 +1,43 @@
+#
+# Filename : external_contour.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the external contour of the scene
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from ChainingIterators import *
+from shaders import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D())
+Operators.select(upred )
+bpred = TrueBP1D();
+Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(upred))
+shaders_list = [
+ ConstantThicknessShader(3),
+ ConstantColorShader(0.0, 0.0, 0.0,1)
+ ]
+Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file
diff --git a/release/scripts/freestyle/style_modules/external_contour_sketchy.py b/release/scripts/freestyle/style_modules/external_contour_sketchy.py
new file mode 100755
index 00000000000..8a4c570b279
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/external_contour_sketchy.py
@@ -0,0 +1,48 @@
+#
+# Filename : external_contour_sketchy.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the external contour of the scene using a sketchy
+# chaining iterator (in particular each ViewEdge can be drawn
+# several times
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D())
+Operators.select(upred)
+Operators.bidirectionalChain(pySketchyChainingIterator(), NotUP1D(upred))
+shaders_list = [
+ SamplingShader(4),
+ SpatialNoiseShader(10, 150, 2, 1, 1),
+ IncreasingThicknessShader(4, 10),
+ SmoothingShader(400, 0.1, 0, 0.2, 0, 0, 0, 1),
+ IncreasingColorShader(1,0,0,1,0,1,0,1),
+ TextureAssignerShader(4)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/external_contour_smooth.py b/release/scripts/freestyle/style_modules/external_contour_smooth.py
new file mode 100755
index 00000000000..201dc271388
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/external_contour_smooth.py
@@ -0,0 +1,44 @@
+#
+# Filename : external_contour_smooth.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws a smooth external contour
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+from ChainingIterators import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D())
+Operators.select(upred)
+bpred = TrueBP1D();
+Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(upred))
+shaders_list = [
+ SamplingShader(2),
+ IncreasingThicknessShader(4,20),
+ IncreasingColorShader(1.0, 0.0, 0.5,1, 0.5,1, 0.3, 1),
+ SmoothingShader(100, 0.05, 0, 0.2, 0, 0, 0, 1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/extra-lines.sml b/release/scripts/freestyle/style_modules/extra-lines.sml
new file mode 100755
index 00000000000..c63cd40945d
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/extra-lines.sml
@@ -0,0 +1,3 @@
+1suggestive.py
+1ridges.py
+1nor_suggestive_or_ridges.py
diff --git a/release/scripts/freestyle/style_modules/freestyle_init.py b/release/scripts/freestyle/style_modules/freestyle_init.py
new file mode 100644
index 00000000000..9eb8b2d6340
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/freestyle_init.py
@@ -0,0 +1,2 @@
+from Freestyle import *
+from mathutils import Vector
diff --git a/release/scripts/freestyle/style_modules/haloing.py b/release/scripts/freestyle/style_modules/haloing.py
new file mode 100755
index 00000000000..afa46173d54
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/haloing.py
@@ -0,0 +1,50 @@
+#
+# Filename : haloing.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : This style module selects the lines that
+# are connected (in the image) to a specific
+# object and trims them in order to produce
+# a haloing effect around the target shape
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from PredicatesB1D import *
+from shaders import *
+
+# id corresponds to the id of the target object
+# (accessed by SHIFT+click)
+id = Id(3,0)
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0) , pyIsOccludedByUP1D(id))
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+shaders_list = [
+ IncreasingThicknessShader(3, 5),
+ IncreasingColorShader(1,0,0, 1,0,1,0,1),
+ SamplingShader(1.0),
+ pyTVertexRemoverShader(),
+ TipRemoverShader(3.0)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/ignore_small_occlusions.py b/release/scripts/freestyle/style_modules/ignore_small_occlusions.py
new file mode 100755
index 00000000000..ff6efa89ade
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/ignore_small_occlusions.py
@@ -0,0 +1,41 @@
+#
+# Filename : ignore_small_oclusions.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : The strokes are drawn through small occlusions
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+#Operators.bidirectionalChain(pyFillOcclusionsChainingIterator(0.1))
+Operators.bidirectionalChain(pyFillOcclusionsAbsoluteChainingIterator(12))
+shaders_list = [
+ SamplingShader(5.0),
+ ConstantThicknessShader(3),
+ ConstantColorShader(0.0,0.0,0.0),
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/invisible_lines.py b/release/scripts/freestyle/style_modules/invisible_lines.py
new file mode 100755
index 00000000000..ea509463bfd
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/invisible_lines.py
@@ -0,0 +1,42 @@
+#
+# Filename : invisible_lines.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws all lines whose Quantitative Invisibility
+# is different from 0
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+upred = NotUP1D(QuantitativeInvisibilityUP1D(0))
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+shaders_list = [
+ SamplingShader(5.0),
+ ConstantThicknessShader(3.0),
+ ConstantColorShader(0.7,0.7,0.7)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/japanese_bigbrush.py b/release/scripts/freestyle/style_modules/japanese_bigbrush.py
new file mode 100755
index 00000000000..7f109598aaa
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/japanese_bigbrush.py
@@ -0,0 +1,60 @@
+#
+# Filename : japanese_bigbrush.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Simulates a big brush fr oriental painting
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from PredicatesB1D import *
+from Functions0D import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0)))
+## Splits strokes at points of highest 2D curavture
+## when there are too many abrupt turns in it
+func = pyInverseCurvature2DAngleF0D()
+Operators.recursiveSplit(func, pyParameterUP0D(0.2,0.8), NotUP1D(pyHigherNumberOfTurnsUP1D(3, 0.5)), 2)
+## Keeps only long enough strokes
+Operators.select(pyHigherLengthUP1D(100))
+## Sorts so as to draw the longest strokes first
+## (this will be done using the causal density)
+Operators.sort(pyLengthBP1D())
+shaders_list = [
+ pySamplingShader(10),
+ BezierCurveShader(30),
+ SamplingShader(50),
+ ConstantThicknessShader(10),
+ pyNonLinearVaryingThicknessShader(4,25, 0.6),
+ TextureAssignerShader(6),
+ ConstantColorShader(0.2, 0.2, 0.2,1.0),
+ TipRemoverShader(10)
+ ]
+
+## Use the causal density to avoid cluttering
+Operators.create(pyDensityUP1D(8,0.4, IntegrationType.MEAN), shaders_list)
+
+
diff --git a/release/scripts/freestyle/style_modules/logical_operators.py b/release/scripts/freestyle/style_modules/logical_operators.py
new file mode 100755
index 00000000000..0ecf6623697
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/logical_operators.py
@@ -0,0 +1,36 @@
+from freestyle_init import *
+
+class AndUP1D(UnaryPredicate1D):
+ def __init__(self, pred1, pred2):
+ UnaryPredicate1D.__init__(self)
+ self.__pred1 = pred1
+ self.__pred2 = pred2
+
+ def getName(self):
+ return "AndUP1D"
+
+ def __call__(self, inter):
+ return self.__pred1(inter) and self.__pred2(inter)
+
+class OrUP1D(UnaryPredicate1D):
+ def __init__(self, pred1, pred2):
+ UnaryPredicate1D.__init__(self)
+ self.__pred1 = pred1
+ self.__pred2 = pred2
+
+ def getName(self):
+ return "OrUP1D"
+
+ def __call__(self, inter):
+ return self.__pred1(inter) or self.__pred2(inter)
+
+class NotUP1D(UnaryPredicate1D):
+ def __init__(self, pred):
+ UnaryPredicate1D.__init__(self)
+ self.__pred = pred
+
+ def getName(self):
+ return "NotUP1D"
+
+ def __call__(self, inter):
+ return self.__pred(inter) == 0
diff --git a/release/scripts/freestyle/style_modules/long_anisotropically_dense.py b/release/scripts/freestyle/style_modules/long_anisotropically_dense.py
new file mode 100755
index 00000000000..155ee489680
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/long_anisotropically_dense.py
@@ -0,0 +1,81 @@
+#
+# Filename : long_anisotropically_dense.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Selects the lines that are long and have a high anisotropic
+# a priori density and uses causal density
+# to draw without cluttering. Ideally, half of the
+# selected lines are culled using the causal density.
+#
+# ********************* WARNING *************************************
+# ******** The Directional a priori density maps must ******
+# ******** have been computed prior to using this style module ******
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from PredicatesU0D import *
+from PredicatesB1D import *
+from Functions0D import *
+from Functions1D import *
+from shaders import *
+
+## custom density predicate
+class pyDensityUP1D(UnaryPredicate1D):
+ def __init__(self,wsize,threshold, integration = IntegrationType.MEAN, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._wsize = wsize
+ self._threshold = threshold
+ self._integration = integration
+ self._func = DensityF1D(self._wsize, self._integration, sampling)
+ self._func2 = DensityF1D(self._wsize, IntegrationType.MAX, sampling)
+
+ def getName(self):
+ return "pyDensityUP1D"
+
+ def __call__(self, inter):
+ c = self._func(inter)
+ m = self._func2(inter)
+ if(c < self._threshold):
+ return 1
+ if( m > 4* c ):
+ if ( c < 1.5*self._threshold ):
+ return 1
+ return 0
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0)))
+Operators.select(pyHigherLengthUP1D(40))
+## selects lines having a high anisotropic a priori density
+Operators.select(pyHighDensityAnisotropyUP1D(0.3,4))
+Operators.sort(pyLengthBP1D())
+shaders_list = [
+ SamplingShader(2.0),
+ ConstantThicknessShader(2),
+ ConstantColorShader(0.2,0.2,0.25,1),
+ ]
+## uniform culling
+Operators.create(pyDensityUP1D(3.0,2.0e-2, IntegrationType.MEAN, 0.1), shaders_list)
+
+
diff --git a/release/scripts/freestyle/style_modules/multiple_parameterization.py b/release/scripts/freestyle/style_modules/multiple_parameterization.py
new file mode 100755
index 00000000000..3f0409db5fa
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/multiple_parameterization.py
@@ -0,0 +1,51 @@
+#
+# Filename : multiple_parameterization.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : The thickness and the color of the strokes vary continuously
+# independently from occlusions although only
+# visible lines are actually drawn. This is equivalent
+# to assigning the thickness using a parameterization covering
+# the complete silhouette (visible+invisible) and drawing
+# the strokes using a second parameterization that only
+# covers the visible portions.
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+## Chain following the same nature, but without the restriction
+## of staying inside the selection (0).
+Operators.bidirectionalChain(ChainSilhouetteIterator(0))
+shaders_list = [
+ SamplingShader(20),
+ IncreasingThicknessShader(1.5, 30),
+ ConstantColorShader(0.0,0.0,0.0),
+ IncreasingColorShader(1,0,0,1,0,1,0,1),
+ TextureAssignerShader(-1),
+ pyHLRShader() ## this shader draws only visible portions
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/nature.py b/release/scripts/freestyle/style_modules/nature.py
new file mode 100755
index 00000000000..b5481a8e519
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/nature.py
@@ -0,0 +1,43 @@
+#
+# Filename : nature.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Uses the NatureUP1D predicate to select the lines
+# of a given type (among Nature.SILHOUETTE, Nature.CREASE, Nature.SUGGESTIVE_CONTOURS,
+# Nature.BORDERS).
+# The suggestive contours must have been enabled in the
+# options dialog to appear in the View Map.
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+Operators.select(pyNatureUP1D(Nature.SILHOUETTE))
+Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D( pyNatureUP1D( Nature.SILHOUETTE) ) )
+shaders_list = [
+ IncreasingThicknessShader(3, 10),
+ IncreasingColorShader(0.0,0.0,0.0, 1, 0.8,0,0,1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/near_lines.py b/release/scripts/freestyle/style_modules/near_lines.py
new file mode 100755
index 00000000000..565bca1fe1f
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/near_lines.py
@@ -0,0 +1,44 @@
+#
+# Filename : near_lines.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the lines that are "closer" than a threshold
+# (between 0 and 1)
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), pyZSmallerUP1D(0.5, IntegrationType.MEAN))
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+shaders_list = [
+ TextureAssignerShader(-1),
+ ConstantThicknessShader(5),
+ ConstantColorShader(0.0, 0.0, 0.0)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/occluded_by_specific_object.py b/release/scripts/freestyle/style_modules/occluded_by_specific_object.py
new file mode 100755
index 00000000000..09ce39d5dd6
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/occluded_by_specific_object.py
@@ -0,0 +1,45 @@
+#
+# Filename : occluded_by_specific_object.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws only the lines that are occluded by a given object
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from shaders import *
+
+## the id of the occluder (use SHIFT+click on the ViewMap to
+## retrieve ids)
+id = Id(3,0)
+upred = AndUP1D(NotUP1D(QuantitativeInvisibilityUP1D(0)),
+pyIsInOccludersListUP1D(id))
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+shaders_list = [
+ SamplingShader(5),
+ ConstantThicknessShader(3),
+ ConstantColorShader(0.3,0.3,0.3,1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/parameter_editor.py b/release/scripts/freestyle/style_modules/parameter_editor.py
new file mode 100644
index 00000000000..7d602d4e79e
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/parameter_editor.py
@@ -0,0 +1,953 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# 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.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import Freestyle
+import math
+import time
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+class ColorRampModifier(StrokeShader):
+ def __init__(self, blend, influence, ramp):
+ StrokeShader.__init__(self)
+ self.__blend = blend
+ self.__influence = influence
+ self.__ramp = ramp
+ def evaluate(self, t):
+ col = Freestyle.evaluateColorRamp(self.__ramp, t)
+ col = col.xyz # omit alpha
+ return col
+ def blend_ramp(self, a, b):
+ return Freestyle.blendRamp(self.__blend, a, self.__influence, b)
+
+class CurveMappingModifier(StrokeShader):
+ def __init__(self, blend, influence, mapping, invert, curve):
+ StrokeShader.__init__(self)
+ self.__blend = blend
+ self.__influence = influence
+ assert mapping in ("LINEAR", "CURVE")
+ self.__mapping = getattr(self, mapping)
+ self.__invert = invert
+ self.__curve = curve
+ def LINEAR(self, t):
+ if self.__invert:
+ return 1.0 - t
+ return t
+ def CURVE(self, t):
+ return Freestyle.evaluateCurveMappingF(self.__curve, 0, t)
+ def evaluate(self, t):
+ return self.__mapping(t)
+ def blend_curve(self, v1, v2):
+ fac = self.__influence
+ facm = 1.0 - fac
+ if self.__blend == "MIX":
+ v1 = facm * v1 + fac * v2
+ elif self.__blend == "ADD":
+ v1 += fac * v2
+ elif self.__blend == "MULTIPLY":
+ v1 *= facm + fac * v2;
+ elif self.__blend == "SUBTRACT":
+ v1 -= fac * v2
+ elif self.__blend == "DIVIDE":
+ if v2 != 0.0:
+ v1 = facm * v1 + fac * v1 / v2
+ elif self.__blend == "DIFFERENCE":
+ v1 = facm * v1 + fac * abs(v1 - v2)
+ elif self.__blend == "MININUM":
+ tmp = fac * v1
+ if v1 > tmp:
+ v1 = tmp
+ elif self.__blend == "MAXIMUM":
+ tmp = fac * v1
+ if v1 < tmp:
+ v1 = tmp
+ else:
+ raise ValueError("unknown curve blend type: " + self.__blend)
+ return v1
+
+# Along Stroke modifiers
+
+def iter_t2d_along_stroke(stroke):
+ total = stroke.getLength2D()
+ distance = 0.0
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ p = it.getObject().getPoint()
+ if not it.isBegin():
+ distance += (prev - p).length
+ prev = p
+ t = min(distance / total, 1.0)
+ yield it, t
+ it.increment()
+
+class ColorAlongStrokeShader(ColorRampModifier):
+ def getName(self):
+ return "ColorAlongStrokeShader"
+ def shade(self, stroke):
+ for it, t in iter_t2d_along_stroke(stroke):
+ attr = it.getObject().attribute()
+ a = attr.getColorRGB()
+ b = self.evaluate(t)
+ c = self.blend_ramp(a, b)
+ attr.setColor(c)
+
+class AlphaAlongStrokeShader(CurveMappingModifier):
+ def getName(self):
+ return "AlphaAlongStrokeShader"
+ def shade(self, stroke):
+ for it, t in iter_t2d_along_stroke(stroke):
+ attr = it.getObject().attribute()
+ a = attr.getAlpha()
+ b = self.evaluate(t)
+ c = self.blend_curve(a, b)
+ attr.setAlpha(c)
+
+class ThicknessAlongStrokeShader(CurveMappingModifier):
+ def __init__(self, blend, influence, mapping, invert, curve, value_min, value_max):
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__value_min = value_min
+ self.__value_max = value_max
+ def getName(self):
+ return "ThicknessAlongStrokeShader"
+ def shade(self, stroke):
+ for it, t in iter_t2d_along_stroke(stroke):
+ attr = it.getObject().attribute()
+ a = attr.getThicknessRL()
+ a = a[0] + a[1]
+ b = self.__value_min + self.evaluate(t) * (self.__value_max - self.__value_min)
+ c = self.blend_curve(a, b)
+ attr.setThickness(c/2, c/2)
+
+# Distance from Camera modifiers
+
+def iter_distance_from_camera(stroke, range_min, range_max):
+ normfac = range_max - range_min # normalization factor
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ p = it.getObject().getPoint3D() # in the camera coordinate
+ distance = p.length
+ if distance < range_min:
+ t = 0.0
+ elif distance > range_max:
+ t = 1.0
+ else:
+ t = (distance - range_min) / normfac
+ yield it, t
+ it.increment()
+
+class ColorDistanceFromCameraShader(ColorRampModifier):
+ def __init__(self, blend, influence, ramp, range_min, range_max):
+ ColorRampModifier.__init__(self, blend, influence, ramp)
+ self.__range_min = range_min
+ self.__range_max = range_max
+ def getName(self):
+ return "ColorDistanceFromCameraShader"
+ def shade(self, stroke):
+ for it, t in iter_distance_from_camera(stroke, self.__range_min, self.__range_max):
+ attr = it.getObject().attribute()
+ a = attr.getColorRGB()
+ b = self.evaluate(t)
+ c = self.blend_ramp(a, b)
+ attr.setColor(c)
+
+class AlphaDistanceFromCameraShader(CurveMappingModifier):
+ def __init__(self, blend, influence, mapping, invert, curve, range_min, range_max):
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__range_min = range_min
+ self.__range_max = range_max
+ def getName(self):
+ return "AlphaDistanceFromCameraShader"
+ def shade(self, stroke):
+ for it, t in iter_distance_from_camera(stroke, self.__range_min, self.__range_max):
+ attr = it.getObject().attribute()
+ a = attr.getAlpha()
+ b = self.evaluate(t)
+ c = self.blend_curve(a, b)
+ attr.setAlpha(c)
+
+class ThicknessDistanceFromCameraShader(CurveMappingModifier):
+ def __init__(self, blend, influence, mapping, invert, curve, range_min, range_max, value_min, value_max):
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__range_min = range_min
+ self.__range_max = range_max
+ self.__value_min = value_min
+ self.__value_max = value_max
+ def getName(self):
+ return "ThicknessDistanceFromCameraShader"
+ def shade(self, stroke):
+ for it, t in iter_distance_from_camera(stroke, self.__range_min, self.__range_max):
+ attr = it.getObject().attribute()
+ a = attr.getThicknessRL()
+ a = a[0] + a[1]
+ b = self.__value_min + self.evaluate(t) * (self.__value_max - self.__value_min)
+ c = self.blend_curve(a, b)
+ attr.setThickness(c/2, c/2)
+
+# Distance from Object modifiers
+
+def iter_distance_from_object(stroke, object, range_min, range_max):
+ scene = Freestyle.getCurrentScene()
+ mv = scene.camera.matrix_world.copy() # model-view matrix
+ mv.invert()
+ loc = mv * object.location # loc in the camera coordinate
+ normfac = range_max - range_min # normalization factor
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ p = it.getObject().getPoint3D() # in the camera coordinate
+ distance = (p - loc).length
+ if distance < range_min:
+ t = 0.0
+ elif distance > range_max:
+ t = 1.0
+ else:
+ t = (distance - range_min) / normfac
+ yield it, t
+ it.increment()
+
+class ColorDistanceFromObjectShader(ColorRampModifier):
+ def __init__(self, blend, influence, ramp, target, range_min, range_max):
+ ColorRampModifier.__init__(self, blend, influence, ramp)
+ self.__target = target
+ self.__range_min = range_min
+ self.__range_max = range_max
+ def getName(self):
+ return "ColorDistanceFromObjectShader"
+ def shade(self, stroke):
+ if self.__target is None:
+ return
+ for it, t in iter_distance_from_object(stroke, self.__target, self.__range_min, self.__range_max):
+ attr = it.getObject().attribute()
+ a = attr.getColorRGB()
+ b = self.evaluate(t)
+ c = self.blend_ramp(a, b)
+ attr.setColor(c)
+
+class AlphaDistanceFromObjectShader(CurveMappingModifier):
+ def __init__(self, blend, influence, mapping, invert, curve, target, range_min, range_max):
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__target = target
+ self.__range_min = range_min
+ self.__range_max = range_max
+ def getName(self):
+ return "AlphaDistanceFromObjectShader"
+ def shade(self, stroke):
+ if self.__target is None:
+ return
+ for it, t in iter_distance_from_object(stroke, self.__target, self.__range_min, self.__range_max):
+ attr = it.getObject().attribute()
+ a = attr.getAlpha()
+ b = self.evaluate(t)
+ c = self.blend_curve(a, b)
+ attr.setAlpha(c)
+
+class ThicknessDistanceFromObjectShader(CurveMappingModifier):
+ def __init__(self, blend, influence, mapping, invert, curve, target, range_min, range_max, value_min, value_max):
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__target = target
+ self.__range_min = range_min
+ self.__range_max = range_max
+ self.__value_min = value_min
+ self.__value_max = value_max
+ def getName(self):
+ return "ThicknessDistanceFromObjectShader"
+ def shade(self, stroke):
+ if self.__target is None:
+ return
+ for it, t in iter_distance_from_object(stroke, self.__target, self.__range_min, self.__range_max):
+ attr = it.getObject().attribute()
+ a = attr.getThicknessRL()
+ a = a[0] + a[1]
+ b = self.__value_min + self.evaluate(t) * (self.__value_max - self.__value_min)
+ c = self.blend_curve(a, b)
+ attr.setThickness(c/2, c/2)
+
+# Material modifiers
+
+def iter_material_color(stroke, material_attr):
+ func = MaterialF0D()
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ material = func(it.castToInterface0DIterator())
+ if material_attr == "DIFF":
+ color = (material.diffuseR(),
+ material.diffuseG(),
+ material.diffuseB())
+ elif material_attr == "SPEC":
+ color = (material.specularR(),
+ material.specularG(),
+ material.specularB())
+ else:
+ raise ValueError("unexpected material attribute: " + material_attr)
+ yield it, color
+ it.increment()
+
+def iter_material_value(stroke, material_attr):
+ func = MaterialF0D()
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ material = func(it.castToInterface0DIterator())
+ if material_attr == "DIFF":
+ r = material.diffuseR()
+ g = material.diffuseG()
+ b = material.diffuseB()
+ t = 0.35 * r + 0.45 * r + 0.2 * b
+ elif material_attr == "DIFF_R":
+ t = material.diffuseR()
+ elif material_attr == "DIFF_G":
+ t = material.diffuseG()
+ elif material_attr == "DIFF_B":
+ t = material.diffuseB()
+ elif material_attr == "SPEC":
+ r = material.specularR()
+ g = material.specularG()
+ b = material.specularB()
+ t = 0.35 * r + 0.45 * r + 0.2 * b
+ elif material_attr == "SPEC_R":
+ t = material.specularR()
+ elif material_attr == "SPEC_G":
+ t = material.specularG()
+ elif material_attr == "SPEC_B":
+ t = material.specularB()
+ elif material_attr == "SPEC_HARDNESS":
+ t = material.shininess()
+ elif material_attr == "ALPHA":
+ t = material.diffuseA()
+ else:
+ raise ValueError("unexpected material attribute: " + material_attr)
+ yield it, t
+ it.increment()
+
+class ColorMaterialShader(ColorRampModifier):
+ def __init__(self, blend, influence, ramp, material_attr, use_ramp):
+ ColorRampModifier.__init__(self, blend, influence, ramp)
+ self.__material_attr = material_attr
+ self.__use_ramp = use_ramp
+ def getName(self):
+ return "ColorMaterialShader"
+ def shade(self, stroke):
+ if self.__material_attr in ["DIFF", "SPEC"] and not self.__use_ramp:
+ for it, b in iter_material_color(stroke, self.__material_attr):
+ attr = it.getObject().attribute()
+ a = attr.getColorRGB()
+ c = self.blend_ramp(a, b)
+ attr.setColor(c)
+ else:
+ for it, t in iter_material_value(stroke, self.__material_attr):
+ attr = it.getObject().attribute()
+ a = attr.getColorRGB()
+ b = self.evaluate(t)
+ c = self.blend_ramp(a, b)
+ attr.setColor(c)
+
+class AlphaMaterialShader(CurveMappingModifier):
+ def __init__(self, blend, influence, mapping, invert, curve, material_attr):
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__material_attr = material_attr
+ def getName(self):
+ return "AlphaMaterialShader"
+ def shade(self, stroke):
+ for it, t in iter_material_value(stroke, self.__material_attr):
+ attr = it.getObject().attribute()
+ a = attr.getAlpha()
+ b = self.evaluate(t)
+ c = self.blend_curve(a, b)
+ attr.setAlpha(c)
+
+class ThicknessMaterialShader(CurveMappingModifier):
+ def __init__(self, blend, influence, mapping, invert, curve, material_attr, value_min, value_max):
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__material_attr = material_attr
+ self.__value_min = value_min
+ self.__value_max = value_max
+ def getName(self):
+ return "ThicknessMaterialShader"
+ def shade(self, stroke):
+ for it, t in iter_material_value(stroke, self.__material_attr):
+ attr = it.getObject().attribute()
+ a = attr.getThicknessRL()
+ a = a[0] + a[1]
+ b = self.__value_min + self.evaluate(t) * (self.__value_max - self.__value_min)
+ c = self.blend_curve(a, b)
+ attr.setThickness(c/2, c/2)
+
+# Geometry modifiers
+
+def iter_distance_along_stroke(stroke):
+ distance = 0.0
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ p = it.getObject().getPoint()
+ if not it.isBegin():
+ distance += (prev - p).length
+ prev = p
+ yield it, distance
+ it.increment()
+
+class SinusDisplacementShader(StrokeShader):
+ def __init__(self, wavelength, amplitude, phase):
+ StrokeShader.__init__(self)
+ self._wavelength = wavelength
+ self._amplitude = amplitude
+ self._phase = phase / wavelength * 2 * math.pi
+ self._getNormal = Normal2DF0D()
+ def getName(self):
+ return "SinusDisplacementShader"
+ def shade(self, stroke):
+ for it, distance in iter_distance_along_stroke(stroke):
+ v = it.getObject()
+ n = self._getNormal(it.castToInterface0DIterator())
+ p = v.getPoint()
+ u = v.u()
+ n = n * self._amplitude * math.cos(distance / self._wavelength * 2 * math.pi + self._phase)
+ v.setPoint(p + n)
+
+class PerlinNoise1DShader(StrokeShader):
+ def __init__(self, freq = 10, amp = 10, oct = 4, angle = 45, seed = -1):
+ StrokeShader.__init__(self)
+ self.__noise = Noise(seed)
+ self.__freq = freq
+ self.__amp = amp
+ self.__oct = oct
+ theta = pi * angle / 180.0
+ self.__dir = Vector([cos(theta), sin(theta)])
+ def getName(self):
+ return "PerlinNoise1DShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ v = it.getObject()
+ i = v.getProjectedX() + v.getProjectedY()
+ nres = self.__noise.turbulence1(i, self.__freq, self.__amp, self.__oct)
+ v.setPoint(v.getPoint() + nres * self.__dir)
+ it.increment()
+
+class PerlinNoise2DShader(StrokeShader):
+ def __init__(self, freq = 10, amp = 10, oct = 4, angle = 45, seed = -1):
+ StrokeShader.__init__(self)
+ self.__noise = Noise(seed)
+ self.__freq = freq
+ self.__amp = amp
+ self.__oct = oct
+ theta = pi * angle / 180.0
+ self.__dir = Vector([cos(theta), sin(theta)])
+ def getName(self):
+ return "PerlinNoise2DShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ v = it.getObject()
+ vec = Vector([v.getProjectedX(), v.getProjectedY()])
+ nres = self.__noise.turbulence2(vec, self.__freq, self.__amp, self.__oct)
+ v.setPoint(v.getPoint() + nres * self.__dir)
+ it.increment()
+
+# Predicates and helper functions
+
+class QuantitativeInvisibilityRangeUP1D(UnaryPredicate1D):
+ def __init__(self, qi_start, qi_end):
+ UnaryPredicate1D.__init__(self)
+ self.__getQI = QuantitativeInvisibilityF1D()
+ self.__qi_start = qi_start
+ self.__qi_end = qi_end
+ def getName(self):
+ return "QuantitativeInvisibilityRangeUP1D"
+ def __call__(self, inter):
+ qi = self.__getQI(inter)
+ return self.__qi_start <= qi <= self.__qi_end
+
+def join_unary_predicates(upred_list, bpred):
+ if not upred_list:
+ return TrueUP1D()
+ upred = upred_list[0]
+ for p in upred_list[1:]:
+ upred = bpred(upred, p)
+ return upred
+
+class ObjectNamesUP1D(UnaryPredicate1D):
+ def __init__(self, names, negative):
+ UnaryPredicate1D.__init__(self)
+ self._names = names
+ self._negative = negative
+ def getName(self):
+ return "ObjectNamesUP1D"
+ def __call__(self, viewEdge):
+ found = viewEdge.viewShape().getName() in self._names
+ if self._negative:
+ return not found
+ return found
+
+class WithinImageBorderUP1D(UnaryPredicate1D):
+ def __init__(self, xmin, xmax, ymin, ymax):
+ UnaryPredicate1D.__init__(self)
+ self._xmin = xmin
+ self._xmax = xmax
+ self._ymin = ymin
+ self._ymax = ymax
+ def getName(self):
+ return "WithinImageBorderUP1D"
+ def __call__(self, inter):
+ return self.withinBorder(inter.A()) or self.withinBorder(inter.B())
+ def withinBorder(self, vert):
+ x = vert.getProjectedX()
+ y = vert.getProjectedY()
+ return self._xmin <= x <= self._xmax and self._ymin <= y <= self._ymax
+
+# Stroke caps
+
+def iter_stroke_vertices(stroke):
+ it = stroke.strokeVerticesBegin()
+ prev_p = None
+ while not it.isEnd():
+ sv = it.getObject()
+ p = sv.getPoint()
+ if prev_p is None or (prev_p - p).length > 1e-6:
+ yield sv
+ prev_p = p
+ it.increment()
+
+class RoundCapShader(StrokeShader):
+ def round_cap_thickness(self, x):
+ x = max(0.0, min(x, 1.0))
+ return math.sqrt(1.0 - (x ** 2))
+ def shade(self, stroke):
+ # save the location and attribute of stroke vertices
+ buffer = []
+ for sv in iter_stroke_vertices(stroke):
+ buffer.append((sv.getPoint(), sv.attribute()))
+ nverts = len(buffer)
+ if nverts < 2:
+ return
+ # calculate the number of additional vertices to form caps
+ R, L = stroke[0].attribute().getThicknessRL()
+ caplen_beg = (R + L) / 2.0
+ nverts_beg = max(5, int(R + L))
+ R, L = stroke[-1].attribute().getThicknessRL()
+ caplen_end = (R + L) / 2.0
+ nverts_end = max(5, int(R + L))
+ # adjust the total number of stroke vertices
+ stroke.Resample(nverts + nverts_beg + nverts_end)
+ # restore the location and attribute of the original vertices
+ for i in range(nverts):
+ p, attr = buffer[i]
+ stroke[nverts_beg + i].setPoint(p)
+ stroke[nverts_beg + i].setAttribute(attr)
+ # reshape the cap at the beginning of the stroke
+ q, attr = buffer[1]
+ p, attr = buffer[0]
+ d = p - q
+ d = d / d.length * caplen_beg
+ n = 1.0 / nverts_beg
+ R, L = attr.getThicknessRL()
+ for i in range(nverts_beg):
+ t = (nverts_beg - i) * n
+ stroke[i].setPoint(p + d * t)
+ r = self.round_cap_thickness((nverts_beg - i + 1) * n)
+ stroke[i].setAttribute(attr)
+ stroke[i].attribute().setThickness(R * r, L * r)
+ # reshape the cap at the end of the stroke
+ q, attr = buffer[-2]
+ p, attr = buffer[-1]
+ d = p - q
+ d = d / d.length * caplen_end
+ n = 1.0 / nverts_end
+ R, L = attr.getThicknessRL()
+ for i in range(nverts_end):
+ t = (nverts_end - i) * n
+ stroke[-i-1].setPoint(p + d * t)
+ r = self.round_cap_thickness((nverts_end - i + 1) * n)
+ stroke[-i-1].setAttribute(attr)
+ stroke[-i-1].attribute().setThickness(R * r, L * r)
+
+class SquareCapShader(StrokeShader):
+ def shade(self, stroke):
+ # save the location and attribute of stroke vertices
+ buffer = []
+ for sv in iter_stroke_vertices(stroke):
+ buffer.append((sv.getPoint(), sv.attribute()))
+ nverts = len(buffer)
+ if nverts < 2:
+ return
+ # calculate the number of additional vertices to form caps
+ R, L = stroke[0].attribute().getThicknessRL()
+ caplen_beg = (R + L) / 2.0
+ nverts_beg = 1
+ R, L = stroke[-1].attribute().getThicknessRL()
+ caplen_end = (R + L) / 2.0
+ nverts_end = 1
+ # adjust the total number of stroke vertices
+ stroke.Resample(nverts + nverts_beg + nverts_end)
+ # restore the location and attribute of the original vertices
+ for i in range(nverts):
+ p, attr = buffer[i]
+ stroke[nverts_beg + i].setPoint(p)
+ stroke[nverts_beg + i].setAttribute(attr)
+ # reshape the cap at the beginning of the stroke
+ q, attr = buffer[1]
+ p, attr = buffer[0]
+ d = p - q
+ stroke[0].setPoint(p + d / d.length * caplen_beg)
+ stroke[0].setAttribute(attr)
+ # reshape the cap at the end of the stroke
+ q, attr = buffer[-2]
+ p, attr = buffer[-1]
+ d = p - q
+ stroke[-1].setPoint(p + d / d.length * caplen_beg)
+ stroke[-1].setAttribute(attr)
+
+# dashed line
+
+class DashedLineStartingUP0D(UnaryPredicate0D):
+ def __init__(self, controller):
+ UnaryPredicate0D.__init__(self)
+ self._controller = controller
+ def __call__(self, inter):
+ return self._controller.start()
+
+class DashedLineStoppingUP0D(UnaryPredicate0D):
+ def __init__(self, controller):
+ UnaryPredicate0D.__init__(self)
+ self._controller = controller
+ def __call__(self, inter):
+ return self._controller.stop()
+
+class DashedLineController:
+ def __init__(self, pattern, sampling):
+ self.sampling = float(sampling)
+ k = len(pattern) // 2
+ n = k * 2
+ self.start_pos = [pattern[i] + pattern[i+1] for i in range(0, n, 2)]
+ self.stop_pos = [pattern[i] for i in range(0, n, 2)]
+ self.init()
+ def init(self):
+ self.start_len = 0.0
+ self.start_idx = 0
+ self.stop_len = self.sampling
+ self.stop_idx = 0
+ def start(self):
+ self.start_len += self.sampling
+ if abs(self.start_len - self.start_pos[self.start_idx]) < self.sampling / 2.0:
+ self.start_len = 0.0
+ self.start_idx = (self.start_idx + 1) % len(self.start_pos)
+ return True
+ return False
+ def stop(self):
+ if self.start_len > 0.0:
+ self.init()
+ self.stop_len += self.sampling
+ if abs(self.stop_len - self.stop_pos[self.stop_idx]) < self.sampling / 2.0:
+ self.stop_len = self.sampling
+ self.stop_idx = (self.stop_idx + 1) % len(self.stop_pos)
+ return True
+ return False
+
+# predicates for chaining
+
+class AngleLargerThanBP1D(BinaryPredicate1D):
+ def __init__(self, angle):
+ BinaryPredicate1D.__init__(self)
+ self._angle = math.pi * angle / 180.0
+ def getName(self):
+ return "AngleLargerThanBP1D"
+ def __call__(self, i1, i2):
+ fe1a = i1.fedgeA()
+ fe1b = i1.fedgeB()
+ fe2a = i2.fedgeA()
+ fe2b = i2.fedgeB()
+ sv1a = fe1a.vertexA().getPoint2D()
+ sv1b = fe1b.vertexB().getPoint2D()
+ sv2a = fe2a.vertexA().getPoint2D()
+ sv2b = fe2b.vertexB().getPoint2D()
+ if (sv1a - sv2a).length < 1e-6:
+ dir1 = sv1a - sv1b
+ dir2 = sv2b - sv2a
+ elif (sv1b - sv2b).length < 1e-6:
+ dir1 = sv1b - sv1a
+ dir2 = sv2a - sv2b
+ elif (sv1a - sv2b).length < 1e-6:
+ dir1 = sv1a - sv1b
+ dir2 = sv2a - sv2b
+ elif (sv1b - sv2a).length < 1e-6:
+ dir1 = sv1b - sv1a
+ dir2 = sv2b - sv2a
+ else:
+ return False
+ denom = dir1.length * dir2.length
+ if denom < 1e-6:
+ return False
+ x = (dir1 * dir2) / denom
+ return math.acos(min(max(x, -1.0), 1.0)) > self._angle
+
+class AndBP1D(BinaryPredicate1D):
+ def __init__(self, pred1, pred2):
+ BinaryPredicate1D.__init__(self)
+ self.__pred1 = pred1
+ self.__pred2 = pred2
+ def getName(self):
+ return "AndBP1D"
+ def __call__(self, i1, i2):
+ return self.__pred1(i1, i2) and self.__pred2(i1, i2)
+
+# predicates for splitting
+
+class MaterialBoundaryUP0D(UnaryPredicate0D):
+ def getName(self):
+ return "MaterialBoundaryUP0D"
+ def __call__(self, it):
+ if it.isBegin():
+ return False
+ it_prev = Interface0DIterator(it)
+ it_prev.decrement()
+ v = it.getObject()
+ it.increment()
+ if it.isEnd():
+ return False
+ fe = v.getFEdge(it_prev.getObject())
+ idx1 = fe.materialIndex() if fe.isSmooth() else fe.bMaterialIndex()
+ fe = v.getFEdge(it.getObject())
+ idx2 = fe.materialIndex() if fe.isSmooth() else fe.bMaterialIndex()
+ return idx1 != idx2
+
+# Seed for random number generation
+
+class Seed:
+ def __init__(self):
+ self.t_max = 2 ** 15
+ self.t = int(time.time()) % self.t_max
+ def get(self, seed):
+ if seed < 0:
+ self.t = (self.t + 1) % self.t_max
+ return self.t
+ return seed
+
+_seed = Seed()
+
+# main function for parameter processing
+
+def process(layer_name, lineset_name):
+ scene = Freestyle.getCurrentScene()
+ layer = scene.render.layers[layer_name]
+ lineset = layer.freestyle_settings.linesets[lineset_name]
+ linestyle = lineset.linestyle
+
+ selection_criteria = []
+ # prepare selection criteria by visibility
+ if lineset.select_by_visibility:
+ if lineset.visibility == "VISIBLE":
+ selection_criteria.append(
+ QuantitativeInvisibilityUP1D(0))
+ elif lineset.visibility == "HIDDEN":
+ selection_criteria.append(
+ NotUP1D(QuantitativeInvisibilityUP1D(0)))
+ elif lineset.visibility == "RANGE":
+ selection_criteria.append(
+ QuantitativeInvisibilityRangeUP1D(lineset.qi_start, lineset.qi_end))
+ # prepare selection criteria by edge types
+ if lineset.select_by_edge_types:
+ edge_type_criteria = []
+ if lineset.edge_type_combination == "OR":
+ flags = Nature.NO_FEATURE
+ if lineset.select_silhouette:
+ flags |= Nature.SILHOUETTE
+ if lineset.select_border:
+ flags |= Nature.BORDER
+ if lineset.select_crease:
+ flags |= Nature.CREASE
+ if lineset.select_ridge:
+ flags |= Nature.RIDGE
+ if lineset.select_valley:
+ flags |= Nature.VALLEY
+ if lineset.select_suggestive_contour:
+ flags |= Nature.SUGGESTIVE_CONTOUR
+ if lineset.select_material_boundary:
+ flags |= Nature.MATERIAL_BOUNDARY
+ if flags != Nature.NO_FEATURE:
+ edge_type_criteria.append(pyNatureUP1D(flags))
+ else:
+ if lineset.select_silhouette:
+ edge_type_criteria.append(pyNatureUP1D(Nature.SILHOUETTE))
+ if lineset.select_border:
+ edge_type_criteria.append(pyNatureUP1D(Nature.BORDER))
+ if lineset.select_crease:
+ edge_type_criteria.append(pyNatureUP1D(Nature.CREASE))
+ if lineset.select_ridge:
+ edge_type_criteria.append(pyNatureUP1D(Nature.RIDGE))
+ if lineset.select_valley:
+ edge_type_criteria.append(pyNatureUP1D(Nature.VALLEY))
+ if lineset.select_suggestive_contour:
+ edge_type_criteria.append(pyNatureUP1D(Nature.SUGGESTIVE_CONTOUR))
+ if lineset.select_material_boundary:
+ edge_type_criteria.append(pyNatureUP1D(Nature.MATERIAL_BOUNDARY))
+ if lineset.select_contour:
+ edge_type_criteria.append(ContourUP1D())
+ if lineset.select_external_contour:
+ edge_type_criteria.append(ExternalContourUP1D())
+ if lineset.edge_type_combination == "OR":
+ upred = join_unary_predicates(edge_type_criteria, OrUP1D)
+ else:
+ upred = join_unary_predicates(edge_type_criteria, AndUP1D)
+ if upred is not None:
+ if lineset.edge_type_negation == "EXCLUSIVE":
+ upred = NotUP1D(upred)
+ selection_criteria.append(upred)
+ # prepare selection criteria by group of objects
+ if lineset.select_by_group:
+ if lineset.group is not None and len(lineset.group.objects) > 0:
+ names = dict((ob.name, True) for ob in lineset.group.objects)
+ upred = ObjectNamesUP1D(names, lineset.group_negation == 'EXCLUSIVE')
+ selection_criteria.append(upred)
+ # prepare selection criteria by image border
+ if lineset.select_by_image_border:
+ w = scene.render.resolution_x
+ h = scene.render.resolution_y
+ if scene.render.use_border:
+ xmin = scene.render.border_min_x * w
+ xmax = scene.render.border_max_x * w
+ ymin = scene.render.border_min_y * h
+ ymax = scene.render.border_max_y * h
+ else:
+ xmin, xmax = 0.0, float(w)
+ ymin, ymax = 0.0, float(h)
+ upred = WithinImageBorderUP1D(xmin, xmax, ymin, ymax)
+ selection_criteria.append(upred)
+ # do feature edge selection
+ upred = join_unary_predicates(selection_criteria, AndUP1D)
+ if upred is None:
+ upred = TrueUP1D()
+ Operators.select(upred)
+ # join feature edges
+ bpred = AngleLargerThanBP1D(1.0) # XXX temporary fix for occasional unexpected long lines
+ if linestyle.same_object:
+ bpred = AndBP1D(bpred, SameShapeIdBP1D())
+ Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(upred))
+ # dashed line
+ if linestyle.use_dashed_line:
+ pattern = []
+ if linestyle.dash1 > 0 and linestyle.gap1 > 0:
+ pattern.append(linestyle.dash1)
+ pattern.append(linestyle.gap1)
+ if linestyle.dash2 > 0 and linestyle.gap2 > 0:
+ pattern.append(linestyle.dash2)
+ pattern.append(linestyle.gap2)
+ if linestyle.dash3 > 0 and linestyle.gap3 > 0:
+ pattern.append(linestyle.dash3)
+ pattern.append(linestyle.gap3)
+ if len(pattern) > 0:
+ sampling = 1.0
+ controller = DashedLineController(pattern, sampling)
+ Operators.sequentialSplit(DashedLineStartingUP0D(controller),
+ DashedLineStoppingUP0D(controller),
+ sampling)
+ # split chains of feature edges
+ if linestyle.material_boundary:
+ Operators.sequentialSplit(MaterialBoundaryUP0D())
+ # prepare a list of stroke shaders
+ shaders_list = []
+ for m in linestyle.geometry_modifiers:
+ if not m.use:
+ continue
+ if m.type == "SAMPLING":
+ shaders_list.append(SamplingShader(
+ m.sampling))
+ elif m.type == "BEZIER_CURVE":
+ shaders_list.append(BezierCurveShader(
+ m.error))
+ elif m.type == "SINUS_DISPLACEMENT":
+ shaders_list.append(SinusDisplacementShader(
+ m.wavelength, m.amplitude, m.phase))
+ elif m.type == "SPATIAL_NOISE":
+ shaders_list.append(SpatialNoiseShader(
+ m.amplitude, m.scale, m.octaves, m.smooth, m.pure_random))
+ elif m.type == "PERLIN_NOISE_1D":
+ shaders_list.append(PerlinNoise1DShader(
+ m.frequency, m.amplitude, m.octaves, m.angle, _seed.get(m.seed)))
+ elif m.type == "PERLIN_NOISE_2D":
+ shaders_list.append(PerlinNoise2DShader(
+ m.frequency, m.amplitude, m.octaves, m.angle, _seed.get(m.seed)))
+ elif m.type == "BACKBONE_STRETCHER":
+ shaders_list.append(BackboneStretcherShader(
+ m.amount))
+ elif m.type == "TIP_REMOVER":
+ shaders_list.append(TipRemoverShader(
+ m.tip_length))
+ color = linestyle.color
+ shaders_list.append(ConstantColorShader(color.r, color.g, color.b, linestyle.alpha))
+ shaders_list.append(ConstantThicknessShader(linestyle.thickness))
+ for m in linestyle.color_modifiers:
+ if not m.use:
+ continue
+ if m.type == "ALONG_STROKE":
+ shaders_list.append(ColorAlongStrokeShader(
+ m.blend, m.influence, m.color_ramp))
+ elif m.type == "DISTANCE_FROM_CAMERA":
+ shaders_list.append(ColorDistanceFromCameraShader(
+ m.blend, m.influence, m.color_ramp,
+ m.range_min, m.range_max))
+ elif m.type == "DISTANCE_FROM_OBJECT":
+ shaders_list.append(ColorDistanceFromObjectShader(
+ m.blend, m.influence, m.color_ramp, m.target,
+ m.range_min, m.range_max))
+ elif m.type == "MATERIAL":
+ shaders_list.append(ColorMaterialShader(
+ m.blend, m.influence, m.color_ramp, m.material_attr,
+ m.use_ramp))
+ for m in linestyle.alpha_modifiers:
+ if not m.use:
+ continue
+ if m.type == "ALONG_STROKE":
+ shaders_list.append(AlphaAlongStrokeShader(
+ m.blend, m.influence, m.mapping, m.invert, m.curve))
+ elif m.type == "DISTANCE_FROM_CAMERA":
+ shaders_list.append(AlphaDistanceFromCameraShader(
+ m.blend, m.influence, m.mapping, m.invert, m.curve,
+ m.range_min, m.range_max))
+ elif m.type == "DISTANCE_FROM_OBJECT":
+ shaders_list.append(AlphaDistanceFromObjectShader(
+ m.blend, m.influence, m.mapping, m.invert, m.curve, m.target,
+ m.range_min, m.range_max))
+ elif m.type == "MATERIAL":
+ shaders_list.append(AlphaMaterialShader(
+ m.blend, m.influence, m.mapping, m.invert, m.curve,
+ m.material_attr))
+ for m in linestyle.thickness_modifiers:
+ if not m.use:
+ continue
+ if m.type == "ALONG_STROKE":
+ shaders_list.append(ThicknessAlongStrokeShader(
+ m.blend, m.influence, m.mapping, m.invert, m.curve,
+ m.value_min, m.value_max))
+ elif m.type == "DISTANCE_FROM_CAMERA":
+ shaders_list.append(ThicknessDistanceFromCameraShader(
+ m.blend, m.influence, m.mapping, m.invert, m.curve,
+ m.range_min, m.range_max, m.value_min, m.value_max))
+ elif m.type == "DISTANCE_FROM_OBJECT":
+ shaders_list.append(ThicknessDistanceFromObjectShader(
+ m.blend, m.influence, m.mapping, m.invert, m.curve, m.target,
+ m.range_min, m.range_max, m.value_min, m.value_max))
+ elif m.type == "MATERIAL":
+ shaders_list.append(ThicknessMaterialShader(
+ m.blend, m.influence, m.mapping, m.invert, m.curve,
+ m.material_attr, m.value_min, m.value_max))
+ if linestyle.caps == "ROUND":
+ shaders_list.append(RoundCapShader())
+ elif linestyle.caps == "SQUARE":
+ shaders_list.append(SquareCapShader())
+ # create strokes using the shaders list
+ Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/polygonalize.py b/release/scripts/freestyle/style_modules/polygonalize.py
new file mode 100755
index 00000000000..4446c4c1dcc
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/polygonalize.py
@@ -0,0 +1,40 @@
+#
+# Filename : polygonalize.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Make the strokes more "polygonal"
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ SamplingShader(2.0),
+ ConstantThicknessShader(3),
+ ConstantColorShader(0.0,0.0,0.0),
+ PolygonalizationShader(8)
+ ]
+Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file
diff --git a/release/scripts/freestyle/style_modules/qi0.py b/release/scripts/freestyle/style_modules/qi0.py
new file mode 100755
index 00000000000..d35d23cb7c3
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/qi0.py
@@ -0,0 +1,41 @@
+#
+# Filename : qi0.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the visible lines (chaining follows same nature lines)
+# (most basic style module)
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ SamplingShader(5.0),
+ ConstantThicknessShader(4.0),
+ ConstantColorShader(0.0,0.0,0.0)
+ ]
+Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file
diff --git a/release/scripts/freestyle/style_modules/qi0_not_external_contour.py b/release/scripts/freestyle/style_modules/qi0_not_external_contour.py
new file mode 100755
index 00000000000..eed41af32b4
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/qi0_not_external_contour.py
@@ -0,0 +1,43 @@
+#
+# Filename : qi0_not_external_contour.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the visible lines (chaining follows same nature lines)
+# that do not belong to the external contour of the scene
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D())
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+shaders_list = [
+ SamplingShader(4),
+ SpatialNoiseShader(4, 150, 2, True, True),
+ IncreasingThicknessShader(2, 5),
+ BackboneStretcherShader(20),
+ IncreasingColorShader(1,0,0,1,0,1,0,1),
+ TextureAssignerShader(4)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/qi1.py b/release/scripts/freestyle/style_modules/qi1.py
new file mode 100755
index 00000000000..8d248376138
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/qi1.py
@@ -0,0 +1,42 @@
+#
+# Filename : qi1.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws lines hidden by one surface.
+# *** Quantitative Invisibility must have been
+# enabled in the options dialog to use this style module ****
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(1))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(1)))
+shaders_list = [
+ SamplingShader(5.0),
+ ConstantThicknessShader(3),
+ ConstantColorShader(0.5,0.5,0.5, 1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/qi2.py b/release/scripts/freestyle/style_modules/qi2.py
new file mode 100755
index 00000000000..ba5e97b6982
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/qi2.py
@@ -0,0 +1,42 @@
+#
+# Filename : qi2.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws lines hidden by two surfaces.
+# *** Quantitative Invisibility must have been
+# enabled in the options dialog to use this style module ****
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(2))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(2)))
+shaders_list = [
+ SamplingShader(10),
+ ConstantThicknessShader(1.5),
+ ConstantColorShader(0.7,0.7,0.7, 1)
+ ]
+Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file
diff --git a/release/scripts/freestyle/style_modules/sequentialsplit_sketchy.py b/release/scripts/freestyle/style_modules/sequentialsplit_sketchy.py
new file mode 100755
index 00000000000..53fa03103aa
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/sequentialsplit_sketchy.py
@@ -0,0 +1,68 @@
+#
+# Filename : sequentialsplit_sketchy.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Use the sequential split with two different
+# predicates to specify respectively the starting and
+# the stopping extremities for strokes
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from PredicatesU0D import *
+from Functions0D import *
+
+## Predicate to tell whether a TVertex
+## corresponds to a change from 0 to 1 or not.
+class pyBackTVertexUP0D(UnaryPredicate0D):
+ def __init__(self):
+ UnaryPredicate0D.__init__(self)
+ self._getQI = QuantitativeInvisibilityF0D()
+ def getName(self):
+ return "pyBackTVertexUP0D"
+ def __call__(self, iter):
+ v = iter.getObject()
+ nat = v.getNature()
+ if(nat & Nature.T_VERTEX == 0):
+ return 0
+ if(self._getQI(iter) != 0):
+ return 1
+ return 0
+
+
+upred = QuantitativeInvisibilityUP1D(0)
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+## starting and stopping predicates:
+start = pyVertexNatureUP0D(Nature.NON_T_VERTEX)
+stop = pyBackTVertexUP0D()
+Operators.sequentialSplit(start, stop, 10)
+shaders_list = [
+ SpatialNoiseShader(7, 120, 2, True, True),
+ IncreasingThicknessShader(5, 8),
+ ConstantColorShader(0.2, 0.2, 0.2, 1),
+ TextureAssignerShader(4)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
+
diff --git a/release/scripts/freestyle/style_modules/shaders.py b/release/scripts/freestyle/style_modules/shaders.py
new file mode 100755
index 00000000000..f95293b4b46
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/shaders.py
@@ -0,0 +1,1290 @@
+from freestyle_init import *
+from PredicatesU0D import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from logical_operators import *
+from ChainingIterators import *
+from random import *
+from math import *
+
+## thickness modifiers
+######################
+
+class pyDepthDiscontinuityThicknessShader(StrokeShader):
+ def __init__(self, min, max):
+ StrokeShader.__init__(self)
+ self.__min = float(min)
+ self.__max = float(max)
+ self.__func = ZDiscontinuityF0D()
+ def getName(self):
+ return "pyDepthDiscontinuityThicknessShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ z_min=0.0
+ z_max=1.0
+ a = (self.__max - self.__min)/(z_max-z_min)
+ b = (self.__min*z_max-self.__max*z_min)/(z_max-z_min)
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ z = self.__func(it.castToInterface0DIterator())
+ thickness = a*z+b
+ it.getObject().attribute().setThickness(thickness, thickness)
+ it.increment()
+
+class pyConstantThicknessShader(StrokeShader):
+ def __init__(self, thickness):
+ StrokeShader.__init__(self)
+ self._thickness = thickness
+
+ def getName(self):
+ return "pyConstantThicknessShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ t = self._thickness/2.0
+ att.setThickness(t, t)
+ it.increment()
+
+class pyFXSThicknessShader(StrokeShader):
+ def __init__(self, thickness):
+ StrokeShader.__init__(self)
+ self._thickness = thickness
+
+ def getName(self):
+ return "pyFXSThicknessShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ t = self._thickness/2.0
+ att.setThickness(t, t)
+ it.increment()
+
+class pyFXSVaryingThicknessWithDensityShader(StrokeShader):
+ def __init__(self, wsize, threshold_min, threshold_max, thicknessMin, thicknessMax):
+ StrokeShader.__init__(self)
+ self.wsize= wsize
+ self.threshold_min= threshold_min
+ self.threshold_max= threshold_max
+ self._thicknessMin = thicknessMin
+ self._thicknessMax = thicknessMax
+
+ def getName(self):
+ return "pyVaryingThicknessWithDensityShader"
+ def shade(self, stroke):
+ n = stroke.strokeVerticesSize()
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ func = DensityF0D(self.wsize)
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ toto = it.castToInterface0DIterator()
+ c= func(toto)
+ if (c < self.threshold_min ):
+ c = self.threshold_min
+ if (c > self.threshold_max ):
+ c = self.threshold_max
+## t = (c - self.threshold_min)/(self.threshold_max - self.threshold_min)*(self._thicknessMax-self._thicknessMin) + self._thicknessMin
+ t = (self.threshold_max - c )/(self.threshold_max - self.threshold_min)*(self._thicknessMax-self._thicknessMin) + self._thicknessMin
+ att.setThickness(t/2.0, t/2.0)
+ i = i+1
+ it.increment()
+class pyIncreasingThicknessShader(StrokeShader):
+ def __init__(self, thicknessMin, thicknessMax):
+ StrokeShader.__init__(self)
+ self._thicknessMin = thicknessMin
+ self._thicknessMax = thicknessMax
+
+ def getName(self):
+ return "pyIncreasingThicknessShader"
+ def shade(self, stroke):
+ n = stroke.strokeVerticesSize()
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ c = float(i)/float(n)
+ if(i < float(n)/2.0):
+ t = (1.0 - c)*self._thicknessMin + c * self._thicknessMax
+ else:
+ t = (1.0 - c)*self._thicknessMax + c * self._thicknessMin
+ att.setThickness(t/2.0, t/2.0)
+ i = i+1
+ it.increment()
+
+class pyConstrainedIncreasingThicknessShader(StrokeShader):
+ def __init__(self, thicknessMin, thicknessMax, ratio):
+ StrokeShader.__init__(self)
+ self._thicknessMin = thicknessMin
+ self._thicknessMax = thicknessMax
+ self._ratio = ratio
+
+ def getName(self):
+ return "pyConstrainedIncreasingThicknessShader"
+ def shade(self, stroke):
+ slength = stroke.getLength2D()
+ tmp = self._ratio*slength
+ maxT = 0.0
+ if(tmp < self._thicknessMax):
+ maxT = tmp
+ else:
+ maxT = self._thicknessMax
+ n = stroke.strokeVerticesSize()
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ c = float(i)/float(n)
+ if(i < float(n)/2.0):
+ t = (1.0 - c)*self._thicknessMin + c * maxT
+ else:
+ t = (1.0 - c)*maxT + c * self._thicknessMin
+ att.setThickness(t/2.0, t/2.0)
+ if(i == n-1):
+ att.setThickness(self._thicknessMin/2.0, self._thicknessMin/2.0)
+ i = i+1
+ it.increment()
+
+class pyDecreasingThicknessShader(StrokeShader):
+ def __init__(self, thicknessMax, thicknessMin):
+ StrokeShader.__init__(self)
+ self._thicknessMin = thicknessMin
+ self._thicknessMax = thicknessMax
+
+ def getName(self):
+ return "pyDecreasingThicknessShader"
+ def shade(self, stroke):
+ l = stroke.getLength2D()
+ tMax = self._thicknessMax
+ if(self._thicknessMax > 0.33*l):
+ tMax = 0.33*l
+ tMin = self._thicknessMin
+ if(self._thicknessMin > 0.1*l):
+ tMin = 0.1*l
+ n = stroke.strokeVerticesSize()
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ c = float(i)/float(n)
+ t = (1.0 - c)*tMax +c*tMin
+ att.setThickness(t/2.0, t/2.0)
+ i = i+1
+ it.increment()
+
+def smoothC( a, exp ):
+ c = pow(float(a),exp)*pow(2.0,exp)
+ return c
+
+class pyNonLinearVaryingThicknessShader(StrokeShader):
+ def __init__(self, thicknessExtremity, thicknessMiddle, exponent):
+ StrokeShader.__init__(self)
+ self._thicknessMin = thicknessMiddle
+ self._thicknessMax = thicknessExtremity
+ self._exponent = exponent
+
+ def getName(self):
+ return "pyNonLinearVaryingThicknessShader"
+ def shade(self, stroke):
+ n = stroke.strokeVerticesSize()
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ if(i < float(n)/2.0):
+ c = float(i)/float(n)
+ else:
+ c = float(n-i)/float(n)
+ c = smoothC(c, self._exponent)
+ t = (1.0 - c)*self._thicknessMax + c * self._thicknessMin
+ att.setThickness(t/2.0, t/2.0)
+ i = i+1
+ it.increment()
+
+## Spherical linear interpolation (cos)
+class pySLERPThicknessShader(StrokeShader):
+ def __init__(self, thicknessMin, thicknessMax, omega=1.2):
+ StrokeShader.__init__(self)
+ self._thicknessMin = thicknessMin
+ self._thicknessMax = thicknessMax
+ self._omega = omega
+
+ def getName(self):
+ return "pySLERPThicknessShader"
+ def shade(self, stroke):
+ slength = stroke.getLength2D()
+ tmp = 0.33*slength
+ maxT = self._thicknessMax
+ if(tmp < self._thicknessMax):
+ maxT = tmp
+
+ n = stroke.strokeVerticesSize()
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ c = float(i)/float(n)
+ if(i < float(n)/2.0):
+ t = sin((1-c)*self._omega)/sinh(self._omega)*self._thicknessMin + sin(c*self._omega)/sinh(self._omega) * maxT
+ else:
+ t = sin((1-c)*self._omega)/sinh(self._omega)*maxT + sin(c*self._omega)/sinh(self._omega) * self._thicknessMin
+ att.setThickness(t/2.0, t/2.0)
+ i = i+1
+ it.increment()
+
+class pyTVertexThickenerShader(StrokeShader): ## FIXME
+ def __init__(self, a=1.5, n=3):
+ StrokeShader.__init__(self)
+ self._a = a
+ self._n = n
+
+ def getName(self):
+ return "pyTVertexThickenerShader"
+
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ predTVertex = pyVertexNatureUP0D(Nature.T_VERTEX)
+ while it.isEnd() == 0:
+ if(predTVertex(it) == 1):
+ it2 = StrokeVertexIterator(it)
+ it2.increment()
+ if not(it.isBegin() or it2.isEnd()):
+ it.increment()
+ continue
+ n = self._n
+ a = self._a
+ if(it.isBegin()):
+ it3 = StrokeVertexIterator(it)
+ count = 0
+ while (it3.isEnd() == 0 and count < n):
+ att = it3.getObject().attribute()
+ tr = att.getThicknessR();
+ tl = att.getThicknessL();
+ r = (a-1.0)/float(n-1)*(float(n)/float(count+1) - 1) + 1
+ #r = (1.0-a)/float(n-1)*count + a
+ att.setThickness(r*tr, r*tl)
+ it3.increment()
+ count = count + 1
+ if(it2.isEnd()):
+ it4 = StrokeVertexIterator(it)
+ count = 0
+ while (it4.isBegin() == 0 and count < n):
+ att = it4.getObject().attribute()
+ tr = att.getThicknessR();
+ tl = att.getThicknessL();
+ r = (a-1.0)/float(n-1)*(float(n)/float(count+1) - 1) + 1
+ #r = (1.0-a)/float(n-1)*count + a
+ att.setThickness(r*tr, r*tl)
+ it4.decrement()
+ count = count + 1
+ if ((it4.isBegin() == 1)):
+ att = it4.getObject().attribute()
+ tr = att.getThicknessR();
+ tl = att.getThicknessL();
+ r = (a-1.0)/float(n-1)*(float(n)/float(count+1) - 1) + 1
+ #r = (1.0-a)/float(n-1)*count + a
+ att.setThickness(r*tr, r*tl)
+ it.increment()
+
+class pyImportance2DThicknessShader(StrokeShader):
+ def __init__(self, x, y, w, kmin, kmax):
+ StrokeShader.__init__(self)
+ self._x = x
+ self._y = y
+ self._w = float(w)
+ self._kmin = float(kmin)
+ self._kmax = float(kmax)
+
+ def getName(self):
+ return "pyImportanceThicknessShader"
+ def shade(self, stroke):
+ origin = Vector([self._x, self._y])
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v = it.getObject()
+ p = Vector([v.getProjectedX(), v.getProjectedY()])
+ d = (p-origin).length
+ if(d>self._w):
+ k = self._kmin
+ else:
+ k = (self._kmax*(self._w-d) + self._kmin*d)/self._w
+ att = v.attribute()
+ tr = att.getThicknessR()
+ tl = att.getThicknessL()
+ att.setThickness(k*tr/2.0, k*tl/2.0)
+ it.increment()
+
+class pyImportance3DThicknessShader(StrokeShader):
+ def __init__(self, x, y, z, w, kmin, kmax):
+ StrokeShader.__init__(self)
+ self._x = x
+ self._y = y
+ self._z = z
+ self._w = float(w)
+ self._kmin = float(kmin)
+ self._kmax = float(kmax)
+
+ def getName(self):
+ return "pyImportance3DThicknessShader"
+ def shade(self, stroke):
+ origin = Vector([self._x, self._y, self._z])
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v = it.getObject()
+ p = Vector([v.getX(), v.getY(), v.getZ()])
+ d = (p-origin).length
+ if(d>self._w):
+ k = self._kmin
+ else:
+ k = (self._kmax*(self._w-d) + self._kmin*d)/self._w
+ att = v.attribute()
+ tr = att.getThicknessR()
+ tl = att.getThicknessL()
+ att.setThickness(k*tr/2.0, k*tl/2.0)
+ it.increment()
+
+class pyZDependingThicknessShader(StrokeShader):
+ def __init__(self, min, max):
+ StrokeShader.__init__(self)
+ self.__min = min
+ self.__max = max
+ self.__func = GetProjectedZF0D()
+ def getName(self):
+ return "pyZDependingThicknessShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ z_min = 1
+ z_max = 0
+ while it.isEnd() == 0:
+ z = self.__func(it.castToInterface0DIterator())
+ if z < z_min:
+ z_min = z
+ if z > z_max:
+ z_max = z
+ it.increment()
+ z_diff = 1 / (z_max - z_min)
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ z = (self.__func(it.castToInterface0DIterator()) - z_min) * z_diff
+ thickness = (1 - z) * self.__max + z * self.__min
+ it.getObject().attribute().setThickness(thickness, thickness)
+ it.increment()
+
+
+## color modifiers
+##################
+
+class pyConstantColorShader(StrokeShader):
+ def __init__(self,r,g,b, a = 1):
+ StrokeShader.__init__(self)
+ self._r = r
+ self._g = g
+ self._b = b
+ self._a = a
+ def getName(self):
+ return "pyConstantColorShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ att.setColor(self._r, self._g, self._b)
+ att.setAlpha(self._a)
+ it.increment()
+
+#c1->c2
+class pyIncreasingColorShader(StrokeShader):
+ def __init__(self,r1,g1,b1,a1, r2,g2,b2,a2):
+ StrokeShader.__init__(self)
+ self._c1 = [r1,g1,b1,a1]
+ self._c2 = [r2,g2,b2,a2]
+ def getName(self):
+ return "pyIncreasingColorShader"
+ def shade(self, stroke):
+ n = stroke.strokeVerticesSize() - 1
+ inc = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ c = float(inc)/float(n)
+
+ att.setColor( (1-c)*self._c1[0] + c*self._c2[0],
+ (1-c)*self._c1[1] + c*self._c2[1],
+ (1-c)*self._c1[2] + c*self._c2[2],)
+ att.setAlpha((1-c)*self._c1[3] + c*self._c2[3],)
+ inc = inc+1
+ it.increment()
+
+# c1->c2->c1
+class pyInterpolateColorShader(StrokeShader):
+ def __init__(self,r1,g1,b1,a1, r2,g2,b2,a2):
+ StrokeShader.__init__(self)
+ self._c1 = [r1,g1,b1,a1]
+ self._c2 = [r2,g2,b2,a2]
+ def getName(self):
+ return "pyInterpolateColorShader"
+ def shade(self, stroke):
+ n = stroke.strokeVerticesSize() - 1
+ inc = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ u = float(inc)/float(n)
+ c = 1-2*(fabs(u-0.5))
+ att.setColor( (1-c)*self._c1[0] + c*self._c2[0],
+ (1-c)*self._c1[1] + c*self._c2[1],
+ (1-c)*self._c1[2] + c*self._c2[2],)
+ att.setAlpha((1-c)*self._c1[3] + c*self._c2[3],)
+ inc = inc+1
+ it.increment()
+
+class pyMaterialColorShader(StrokeShader):
+ def __init__(self, threshold=50):
+ StrokeShader.__init__(self)
+ self._threshold = threshold
+
+ def getName(self):
+ return "pyMaterialColorShader"
+
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ func = MaterialF0D()
+ xn = 0.312713
+ yn = 0.329016
+ Yn = 1.0
+ un = 4.* xn/ ( -2.*xn + 12.*yn + 3. )
+ vn= 9.* yn/ ( -2.*xn + 12.*yn +3. )
+ while it.isEnd() == 0:
+ toto = it.castToInterface0DIterator()
+ mat = func(toto)
+
+ r = mat.diffuseR()
+ g = mat.diffuseG()
+ b = mat.diffuseB()
+
+ X = 0.412453*r + 0.35758 *g + 0.180423*b
+ Y = 0.212671*r + 0.71516 *g + 0.072169*b
+ Z = 0.019334*r + 0.119193*g + 0.950227*b
+
+ if((X == 0) and (Y == 0) and (Z == 0)):
+ X = 0.01
+ Y = 0.01
+ Z = 0.01
+ u = 4.*X / (X + 15.*Y + 3.*Z)
+ v = 9.*Y / (X + 15.*Y + 3.*Z)
+
+ L= 116. * pow((Y/Yn),(1./3.)) -16
+ U = 13. * L * (u - un)
+ V = 13. * L * (v - vn)
+
+ if (L > self._threshold):
+ L = L/1.3
+ U = U+10
+ else:
+ L = L +2.5*(100-L)/5.
+ U = U/3.0
+ V = V/3.0
+ u = U / (13. * L) + un
+ v = V / (13. * L) + vn
+
+ Y = Yn * pow( ((L+16.)/116.), 3.)
+ X = -9. * Y * u / ((u - 4.)* v - u * v)
+ Z = (9. * Y - 15*v*Y - v*X) /( 3. * v)
+
+ r = 3.240479 * X - 1.53715 * Y - 0.498535 * Z
+ g = -0.969256 * X + 1.875991 * Y + 0.041556 * Z
+ b = 0.055648 * X - 0.204043 * Y + 1.057311 * Z
+
+ r = max(0,r)
+ g = max(0,g)
+ b = max(0,b)
+
+ att = it.getObject().attribute()
+ att.setColor(r, g, b)
+ it.increment()
+
+class pyRandomColorShader(StrokeShader):
+ def getName(self):
+ return "pyRandomColorShader"
+ def __init__(self, s=1):
+ StrokeShader.__init__(self)
+ seed(s)
+ def shade(self, stroke):
+ ## pick a random color
+ c0 = float(uniform(15,75))/100.0
+ c1 = float(uniform(15,75))/100.0
+ c2 = float(uniform(15,75))/100.0
+ print(c0, c1, c2)
+ it = stroke.strokeVerticesBegin()
+ while(it.isEnd() == 0):
+ it.getObject().attribute().setColor(c0,c1,c2)
+ it.increment()
+
+class py2DCurvatureColorShader(StrokeShader):
+ def getName(self):
+ return "py2DCurvatureColorShader"
+
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ func = Curvature2DAngleF0D()
+ while it.isEnd() == 0:
+ toto = it.castToInterface0DIterator()
+ sv = it.getObject()
+ att = sv.attribute()
+ c = func(toto)
+ if (c<0):
+ print("negative 2D curvature")
+ color = 10.0 * c/3.1415
+ print(color)
+ att.setColor(color,color,color);
+ it.increment()
+
+class pyTimeColorShader(StrokeShader):
+ def __init__(self, step=0.01):
+ StrokeShader.__init__(self)
+ self._t = 0
+ self._step = step
+ def shade(self, stroke):
+ c = self._t*1.0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ att.setColor(c,c,c)
+ it.increment()
+ self._t = self._t+self._step
+
+## geometry modifiers
+
+class pySamplingShader(StrokeShader):
+ def __init__(self, sampling):
+ StrokeShader.__init__(self)
+ self._sampling = sampling
+ def getName(self):
+ return "pySamplingShader"
+ def shade(self, stroke):
+ stroke.Resample(float(self._sampling))
+
+class pyBackboneStretcherShader(StrokeShader):
+ def __init__(self, l):
+ StrokeShader.__init__(self)
+ self._l = l
+ def getName(self):
+ return "pyBackboneStretcherShader"
+ def shade(self, stroke):
+ it0 = stroke.strokeVerticesBegin()
+ it1 = StrokeVertexIterator(it0)
+ it1.increment()
+ itn = stroke.strokeVerticesEnd()
+ itn.decrement()
+ itn_1 = StrokeVertexIterator(itn)
+ itn_1.decrement()
+ v0 = it0.getObject()
+ v1 = it1.getObject()
+ vn_1 = itn_1.getObject()
+ vn = itn.getObject()
+ p0 = Vector([v0.getProjectedX(), v0.getProjectedY()])
+ pn = Vector([vn.getProjectedX(), vn.getProjectedY()])
+ p1 = Vector([v1.getProjectedX(), v1.getProjectedY()])
+ pn_1 = Vector([vn_1.getProjectedX(), vn_1.getProjectedY()])
+ d1 = p0-p1
+ d1.normalize()
+ dn = pn-pn_1
+ dn.normalize()
+ newFirst = p0+d1*float(self._l)
+ newLast = pn+dn*float(self._l)
+ v0.setPoint(newFirst)
+ vn.setPoint(newLast)
+
+class pyLengthDependingBackboneStretcherShader(StrokeShader):
+ def __init__(self, l):
+ StrokeShader.__init__(self)
+ self._l = l
+ def getName(self):
+ return "pyBackboneStretcherShader"
+ def shade(self, stroke):
+ l = stroke.getLength2D()
+ stretch = self._l*l
+ it0 = stroke.strokeVerticesBegin()
+ it1 = StrokeVertexIterator(it0)
+ it1.increment()
+ itn = stroke.strokeVerticesEnd()
+ itn.decrement()
+ itn_1 = StrokeVertexIterator(itn)
+ itn_1.decrement()
+ v0 = it0.getObject()
+ v1 = it1.getObject()
+ vn_1 = itn_1.getObject()
+ vn = itn.getObject()
+ p0 = Vector([v0.getProjectedX(), v0.getProjectedY()])
+ pn = Vector([vn.getProjectedX(), vn.getProjectedY()])
+ p1 = Vector([v1.getProjectedX(), v1.getProjectedY()])
+ pn_1 = Vector([vn_1.getProjectedX(), vn_1.getProjectedY()])
+ d1 = p0-p1
+ d1.normalize()
+ dn = pn-pn_1
+ dn.normalize()
+ newFirst = p0+d1*float(stretch)
+ newLast = pn+dn*float(stretch)
+ v0.setPoint(newFirst)
+ vn.setPoint(newLast)
+
+
+## Shader to replace a stroke by its corresponding tangent
+class pyGuidingLineShader(StrokeShader):
+ def getName(self):
+ return "pyGuidingLineShader"
+ ## shading method
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin() ## get the first vertex
+ itlast = stroke.strokeVerticesEnd() ##
+ itlast.decrement() ## get the last one
+ t = itlast.getObject().getPoint() - it.getObject().getPoint() ## tangent direction
+ itmiddle = StrokeVertexIterator(it) ##
+ while(itmiddle.getObject().u()<0.5): ## look for the stroke middle vertex
+ itmiddle.increment() ##
+ it = StrokeVertexIterator(itmiddle)
+ it.increment()
+ while(it.isEnd() == 0): ## position all the vertices along the tangent for the right part
+ it.getObject().setPoint(itmiddle.getObject().getPoint() \
+ +t*(it.getObject().u()-itmiddle.getObject().u()))
+ it.increment()
+ it = StrokeVertexIterator(itmiddle)
+ it.decrement()
+ while(it.isBegin() == 0): ## position all the vertices along the tangent for the left part
+ it.getObject().setPoint(itmiddle.getObject().getPoint() \
+ -t*(itmiddle.getObject().u()-it.getObject().u()))
+ it.decrement()
+ it.getObject().setPoint(itmiddle.getObject().getPoint()-t*(itmiddle.getObject().u())) ## first vertex
+
+
+class pyBackboneStretcherNoCuspShader(StrokeShader):
+ def __init__(self, l):
+ StrokeShader.__init__(self)
+ self._l = l
+ def getName(self):
+ return "pyBackboneStretcherNoCuspShader"
+ def shade(self, stroke):
+ it0 = stroke.strokeVerticesBegin()
+ it1 = StrokeVertexIterator(it0)
+ it1.increment()
+ itn = stroke.strokeVerticesEnd()
+ itn.decrement()
+ itn_1 = StrokeVertexIterator(itn)
+ itn_1.decrement()
+ v0 = it0.getObject()
+ v1 = it1.getObject()
+ if((v0.getNature() & Nature.CUSP == 0) and (v1.getNature() & Nature.CUSP == 0)):
+ p0 = v0.getPoint()
+ p1 = v1.getPoint()
+ d1 = p0-p1
+ d1.normalize()
+ newFirst = p0+d1*float(self._l)
+ v0.setPoint(newFirst)
+ vn_1 = itn_1.getObject()
+ vn = itn.getObject()
+ if((vn.getNature() & Nature.CUSP == 0) and (vn_1.getNature() & Nature.CUSP == 0)):
+ pn = vn.getPoint()
+ pn_1 = vn_1.getPoint()
+ dn = pn-pn_1
+ dn.normalize()
+ newLast = pn+dn*float(self._l)
+ vn.setPoint(newLast)
+
+normalInfo=Normal2DF0D()
+curvatureInfo=Curvature2DAngleF0D()
+
+def edgestopping(x, sigma):
+ return exp(- x*x/(2*sigma*sigma))
+
+class pyDiffusion2Shader(StrokeShader):
+ def __init__(self, lambda1, nbIter):
+ StrokeShader.__init__(self)
+ self._lambda = lambda1
+ self._nbIter = nbIter
+ self._normalInfo = Normal2DF0D()
+ self._curvatureInfo = Curvature2DAngleF0D()
+ def getName(self):
+ return "pyDiffusionShader"
+ def shade(self, stroke):
+ for i in range (1, self._nbIter):
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v=it.getObject()
+ p1 = v.getPoint()
+ p2 = self._normalInfo(it.castToInterface0DIterator())*self._lambda*self._curvatureInfo(it.castToInterface0DIterator())
+ v.setPoint(p1+p2)
+ it.increment()
+
+class pyTipRemoverShader(StrokeShader):
+ def __init__(self, l):
+ StrokeShader.__init__(self)
+ self._l = l
+ def getName(self):
+ return "pyTipRemoverShader"
+ def shade(self, stroke):
+ originalSize = stroke.strokeVerticesSize()
+ if(originalSize<4):
+ return
+ verticesToRemove = []
+ oldAttributes = []
+ it = stroke.strokeVerticesBegin()
+ while(it.isEnd() == 0):
+ v = it.getObject()
+ if((v.curvilinearAbscissa() < self._l) or (v.strokeLength()-v.curvilinearAbscissa() < self._l)):
+ verticesToRemove.append(v)
+ oldAttributes.append(StrokeAttribute(v.attribute()))
+ it.increment()
+ if(originalSize-len(verticesToRemove) < 2):
+ return
+ for sv in verticesToRemove:
+ stroke.RemoveVertex(sv)
+ stroke.Resample(originalSize)
+ if(stroke.strokeVerticesSize() != originalSize):
+ print("pyTipRemover: Warning: resampling problem")
+ it = stroke.strokeVerticesBegin()
+ for a in oldAttributes:
+ if(it.isEnd() == 1):
+ break
+ v = it.getObject()
+ v.setAttribute(a)
+ it.increment()
+
+class pyTVertexRemoverShader(StrokeShader):
+ def getName(self):
+ return "pyTVertexRemoverShader"
+ def shade(self, stroke):
+ if(stroke.strokeVerticesSize() <= 3 ):
+ return
+ predTVertex = pyVertexNatureUP0D(Nature.T_VERTEX)
+ it = stroke.strokeVerticesBegin()
+ itlast = stroke.strokeVerticesEnd()
+ itlast.decrement()
+ if(predTVertex(it) == 1):
+ stroke.RemoveVertex(it.getObject())
+ if(predTVertex(itlast) == 1):
+ stroke.RemoveVertex(itlast.getObject())
+
+class pyExtremitiesOrientationShader(StrokeShader):
+ def __init__(self, x1,y1,x2=0,y2=0):
+ StrokeShader.__init__(self)
+ self._v1 = Vector([x1,y1])
+ self._v2 = Vector([x2,y2])
+ def getName(self):
+ return "pyExtremitiesOrientationShader"
+ def shade(self, stroke):
+ print(self._v1.x,self._v1.y)
+ stroke.setBeginningOrientation(self._v1.x,self._v1.y)
+ stroke.setEndingOrientation(self._v2.x,self._v2.y)
+
+def getFEdge(it1, it2):
+ return it1.getFEdge(it2)
+
+class pyHLRShader(StrokeShader):
+ def getName(self):
+ return "pyHLRShader"
+ def shade(self, stroke):
+ originalSize = stroke.strokeVerticesSize()
+ if(originalSize<4):
+ return
+ it = stroke.strokeVerticesBegin()
+ invisible = 0
+ it2 = StrokeVertexIterator(it)
+ it2.increment()
+ fe = getFEdge(it.getObject(), it2.getObject())
+ if(fe.viewedge().qi() != 0):
+ invisible = 1
+ while(it2.isEnd() == 0):
+ v = it.getObject()
+ vnext = it2.getObject()
+ if(v.getNature() & Nature.VIEW_VERTEX):
+ #if(v.getNature() & Nature.T_VERTEX):
+ fe = getFEdge(v,vnext)
+ qi = fe.viewedge().qi()
+ if(qi != 0):
+ invisible = 1
+ else:
+ invisible = 0
+ if(invisible == 1):
+ v.attribute().setVisible(0)
+ it.increment()
+ it2.increment()
+
+class pyTVertexOrientationShader(StrokeShader):
+ def __init__(self):
+ StrokeShader.__init__(self)
+ self._Get2dDirection = Orientation2DF1D()
+ def getName(self):
+ return "pyTVertexOrientationShader"
+ ## finds the TVertex orientation from the TVertex and
+ ## the previous or next edge
+ def findOrientation(self, tv, ve):
+ mateVE = tv.mate(ve)
+ if((ve.qi() != 0) or (mateVE.qi() != 0)):
+ ait = AdjacencyIterator(tv,1,0)
+ winner = None
+ incoming = 1
+ while(ait.isEnd() == 0):
+ ave = ait.getObject()
+ if((ave.getId() != ve.getId()) and (ave.getId() != mateVE.getId())):
+ winner = ait.getObject()
+ if(ait.isIncoming() == 0):
+ incoming = 0
+ break
+ ait.increment()
+ if(winner != None):
+ if(incoming != 0):
+ direction = self._Get2dDirection(winner.fedgeB())
+ else:
+ direction = self._Get2dDirection(winner.fedgeA())
+ return direction
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it2 = StrokeVertexIterator(it)
+ it2.increment()
+ ## case where the first vertex is a TVertex
+ v = it.getObject()
+ if(v.getNature() & Nature.T_VERTEX):
+ tv = v.castToTVertex()
+ ve = getFEdge(v, it2.getObject()).viewedge()
+ if(tv != None):
+ dir = self.findOrientation(tv, ve)
+ #print(dir.x, dir.y)
+ v.attribute().setAttributeVec2f("orientation", dir)
+ while(it2.isEnd() == 0):
+ vprevious = it.getObject()
+ v = it2.getObject()
+ if(v.getNature() & Nature.T_VERTEX):
+ tv = v.castToTVertex()
+ ve = getFEdge(vprevious, v).viewedge()
+ if(tv != None):
+ dir = self.findOrientation(tv, ve)
+ #print(dir.x, dir.y)
+ v.attribute().setAttributeVec2f("orientation", dir)
+ it.increment()
+ it2.increment()
+ ## case where the last vertex is a TVertex
+ v = it.getObject()
+ if(v.getNature() & Nature.T_VERTEX):
+ itPrevious = StrokeVertexIterator(it)
+ itPrevious.decrement()
+ tv = v.castToTVertex()
+ ve = getFEdge(itPrevious.getObject(), v).viewedge()
+ if(tv != None):
+ dir = self.findOrientation(tv, ve)
+ #print(dir.x, dir.y)
+ v.attribute().setAttributeVec2f("orientation", dir)
+
+class pySinusDisplacementShader(StrokeShader):
+ def __init__(self, f, a):
+ StrokeShader.__init__(self)
+ self._f = f
+ self._a = a
+ self._getNormal = Normal2DF0D()
+
+ def getName(self):
+ return "pySinusDisplacementShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v = it.getObject()
+ #print(self._getNormal.getName())
+ n = self._getNormal(it.castToInterface0DIterator())
+ p = v.getPoint()
+ u = v.u()
+ a = self._a*(1-2*(fabs(u-0.5)))
+ n = n*a*cos(self._f*u*6.28)
+ #print(n.x, n.y)
+ v.setPoint(p+n)
+ #v.setPoint(v.getPoint()+n*a*cos(f*v.u()))
+ it.increment()
+
+class pyPerlinNoise1DShader(StrokeShader):
+ def __init__(self, freq = 10, amp = 10, oct = 4, seed = -1):
+ StrokeShader.__init__(self)
+ self.__noise = Noise(seed)
+ self.__freq = freq
+ self.__amp = amp
+ self.__oct = oct
+ def getName(self):
+ return "pyPerlinNoise1DShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v = it.getObject()
+ i = v.getProjectedX() + v.getProjectedY()
+ nres = self.__noise.turbulence1(i, self.__freq, self.__amp, self.__oct)
+ v.setPoint(v.getProjectedX() + nres, v.getProjectedY() + nres)
+ it.increment()
+
+class pyPerlinNoise2DShader(StrokeShader):
+ def __init__(self, freq = 10, amp = 10, oct = 4, seed = -1):
+ StrokeShader.__init__(self)
+ self.__noise = Noise(seed)
+ self.__freq = freq
+ self.__amp = amp
+ self.__oct = oct
+ def getName(self):
+ return "pyPerlinNoise2DShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v = it.getObject()
+ vec = Vector([v.getProjectedX(), v.getProjectedY()])
+ nres = self.__noise.turbulence2(vec, self.__freq, self.__amp, self.__oct)
+ v.setPoint(v.getProjectedX() + nres, v.getProjectedY() + nres)
+ it.increment()
+
+class pyBluePrintCirclesShader(StrokeShader):
+ def __init__(self, turns = 1):
+ StrokeShader.__init__(self)
+ self.__turns = turns
+ def getName(self):
+ return "pyBluePrintCirclesShader"
+ def shade(self, stroke):
+ p_min = Vector([10000, 10000])
+ p_max = Vector([0, 0])
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ p = it.getObject().getPoint()
+ if (p.x < p_min.x):
+ p_min.x = p.x
+ if (p.x > p_max.x):
+ p_max.x = p.x
+ if (p.y < p_min.y):
+ p_min.y = p.y
+ if (p.y > p_max.y):
+ p_max.y = p.y
+ it.increment()
+ stroke.Resample(32 * self.__turns)
+ sv_nb = stroke.strokeVerticesSize()
+# print("min :", p_min.x, p_min.y) # DEBUG
+# print("mean :", p_sum.x, p_sum.y) # DEBUG
+# print("max :", p_max.x, p_max.y) # DEBUG
+# print("----------------------") # DEBUG
+#######################################################
+ sv_nb = sv_nb / self.__turns
+ center = (p_min + p_max) / 2
+ radius = (center.x - p_min.x + center.y - p_min.y) / 2
+ p_new = Vector([0, 0])
+#######################################################
+ it = stroke.strokeVerticesBegin()
+ for j in range(self.__turns):
+ radius = radius + randint(-3, 3)
+ center.x = center.x + randint(-5, 5)
+ center.y = center.y + randint(-5, 5)
+ i = 0
+ while i < sv_nb:
+ p_new.x = center.x + radius * cos(2 * pi * float(i) / float(sv_nb - 1))
+ p_new.y = center.y + radius * sin(2 * pi * float(i) / float(sv_nb - 1))
+ it.getObject().setPoint(p_new)
+ i = i + 1
+ it.increment()
+ while it.isEnd() == 0:
+ stroke.RemoveVertex(it.getObject())
+ it.increment()
+
+class pyBluePrintEllipsesShader(StrokeShader):
+ def __init__(self, turns = 1):
+ StrokeShader.__init__(self)
+ self.__turns = turns
+ def getName(self):
+ return "pyBluePrintEllipsesShader"
+ def shade(self, stroke):
+ p_min = Vector([10000, 10000])
+ p_max = Vector([0, 0])
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ p = it.getObject().getPoint()
+ if (p.x < p_min.x):
+ p_min.x = p.x
+ if (p.x > p_max.x):
+ p_max.x = p.x
+ if (p.y < p_min.y):
+ p_min.y = p.y
+ if (p.y > p_max.y):
+ p_max.y = p.y
+ it.increment()
+ stroke.Resample(32 * self.__turns)
+ sv_nb = stroke.strokeVerticesSize()
+ sv_nb = sv_nb / self.__turns
+ center = (p_min + p_max) / 2
+ radius_x = center.x - p_min.x
+ radius_y = center.y - p_min.y
+ p_new = Vector([0, 0])
+#######################################################
+ it = stroke.strokeVerticesBegin()
+ for j in range(self.__turns):
+ radius_x = radius_x + randint(-3, 3)
+ radius_y = radius_y + randint(-3, 3)
+ center.x = center.x + randint(-5, 5)
+ center.y = center.y + randint(-5, 5)
+ i = 0
+ while i < sv_nb and it.isEnd() == 0:
+ p_new.x = center.x + radius_x * cos(2 * pi * float(i) / float(sv_nb - 1))
+ p_new.y = center.y + radius_y * sin(2 * pi * float(i) / float(sv_nb - 1))
+ it.getObject().setPoint(p_new)
+ i = i + 1
+ it.increment()
+ while it.isEnd() == 0:
+ stroke.RemoveVertex(it.getObject())
+ it.increment()
+
+
+class pyBluePrintSquaresShader(StrokeShader):
+ def __init__(self, turns = 1, bb_len = 10):
+ StrokeShader.__init__(self)
+ self.__turns = turns
+ self.__bb_len = bb_len
+
+ def getName(self):
+ return "pyBluePrintSquaresShader"
+
+ def shade(self, stroke):
+ p_min = Vector([10000, 10000])
+ p_max = Vector([0, 0])
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ p = it.getObject().getPoint()
+ if (p.x < p_min.x):
+ p_min.x = p.x
+ if (p.x > p_max.x):
+ p_max.x = p.x
+ if (p.y < p_min.y):
+ p_min.y = p.y
+ if (p.y > p_max.y):
+ p_max.y = p.y
+ it.increment()
+ stroke.Resample(32 * self.__turns)
+ sv_nb = stroke.strokeVerticesSize()
+#######################################################
+ sv_nb = sv_nb / self.__turns
+ first = sv_nb / 4
+ second = 2 * first
+ third = 3 * first
+ fourth = sv_nb
+ vec_first = Vector([p_max.x - p_min.x + 2 * self.__bb_len, 0])
+ vec_second = Vector([0, p_max.y - p_min.y + 2 * self.__bb_len])
+ vec_third = vec_first * -1
+ vec_fourth = vec_second * -1
+ p_first = Vector([p_min.x - self.__bb_len, p_min.y])
+ p_second = Vector([p_max.x, p_min.y - self.__bb_len])
+ p_third = Vector([p_max.x + self.__bb_len, p_max.y])
+ p_fourth = Vector([p_min.x, p_max.y + self.__bb_len])
+#######################################################
+ it = stroke.strokeVerticesBegin()
+ visible = 1
+ for j in range(self.__turns):
+ i = 0
+ while i < sv_nb and it.isEnd() == 0:
+ if i < first:
+ p_new = p_first + vec_first * float(i)/float(first - 1)
+ if i == first - 1:
+ visible = 0
+ elif i < second:
+ p_new = p_second + vec_second * float(i - first)/float(second - first - 1)
+ if i == second - 1:
+ visible = 0
+ elif i < third:
+ p_new = p_third + vec_third * float(i - second)/float(third - second - 1)
+ if i == third - 1:
+ visible = 0
+ else:
+ p_new = p_fourth + vec_fourth * float(i - third)/float(fourth - third - 1)
+ if i == fourth - 1:
+ visible = 0
+ if it.getObject() == None:
+ i = i + 1
+ it.increment()
+ if visible == 0:
+ visible = 1
+ continue
+ it.getObject().setPoint(p_new)
+ it.getObject().attribute().setVisible(visible)
+ if visible == 0:
+ visible = 1
+ i = i + 1
+ it.increment()
+ while it.isEnd() == 0:
+ stroke.RemoveVertex(it.getObject())
+ it.increment()
+
+
+class pyBluePrintDirectedSquaresShader(StrokeShader):
+ def __init__(self, turns = 1, bb_len = 10, mult = 1):
+ StrokeShader.__init__(self)
+ self.__mult = mult
+ self.__turns = turns
+ self.__bb_len = 1 + float(bb_len) / 100
+ def getName(self):
+ return "pyBluePrintDirectedSquaresShader"
+ def shade(self, stroke):
+ stroke.Resample(32 * self.__turns)
+ p_mean = Vector([0, 0])
+ p_min = Vector([10000, 10000])
+ p_max = Vector([0, 0])
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ p = it.getObject().getPoint()
+ p_mean = p_mean + p
+## if (p.x < p_min.x):
+## p_min.x = p.x
+## if (p.x > p_max.x):
+## p_max.x = p.x
+## if (p.y < p_min.y):
+## p_min.y = p.y
+## if (p.y > p_max.y):
+## p_max.y = p.y
+ it.increment()
+ sv_nb = stroke.strokeVerticesSize()
+ p_mean = p_mean / sv_nb
+ p_var_xx = 0
+ p_var_yy = 0
+ p_var_xy = 0
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ p = it.getObject().getPoint()
+ p_var_xx = p_var_xx + pow(p.x - p_mean.x, 2)
+ p_var_yy = p_var_yy + pow(p.y - p_mean.y, 2)
+ p_var_xy = p_var_xy + (p.x - p_mean.x) * (p.y - p_mean.y)
+ it.increment()
+ p_var_xx = p_var_xx / sv_nb
+ p_var_yy = p_var_yy / sv_nb
+ p_var_xy = p_var_xy / sv_nb
+## print(p_var_xx, p_var_yy, p_var_xy)
+ trace = p_var_xx + p_var_yy
+ det = p_var_xx * p_var_yy - p_var_xy * p_var_xy
+ sqrt_coeff = sqrt(trace * trace - 4 * det)
+ lambda1 = (trace + sqrt_coeff) / 2
+ lambda2 = (trace - sqrt_coeff) / 2
+## print(lambda1, lambda2)
+ theta = atan(2 * p_var_xy / (p_var_xx - p_var_yy)) / 2
+## print(theta)
+ if p_var_yy > p_var_xx:
+ e1 = Vector([cos(theta + pi / 2), sin(theta + pi / 2)]) * sqrt(lambda1) * self.__mult
+ e2 = Vector([cos(theta + pi), sin(theta + pi)]) * sqrt(lambda2) * self.__mult
+ else:
+ e1 = Vector([cos(theta), sin(theta)]) * sqrt(lambda1) * self.__mult
+ e2 = Vector([cos(theta + pi / 2), sin(theta + pi / 2)]) * sqrt(lambda2) * self.__mult
+#######################################################
+ sv_nb = sv_nb / self.__turns
+ first = sv_nb / 4
+ second = 2 * first
+ third = 3 * first
+ fourth = sv_nb
+ bb_len1 = self.__bb_len
+ bb_len2 = 1 + (bb_len1 - 1) * sqrt(lambda1 / lambda2)
+ p_first = p_mean - e1 - e2 * bb_len2
+ p_second = p_mean - e1 * bb_len1 + e2
+ p_third = p_mean + e1 + e2 * bb_len2
+ p_fourth = p_mean + e1 * bb_len1 - e2
+ vec_first = e2 * bb_len2 * 2
+ vec_second = e1 * bb_len1 * 2
+ vec_third = vec_first * -1
+ vec_fourth = vec_second * -1
+#######################################################
+ it = stroke.strokeVerticesBegin()
+ visible = 1
+ for j in range(self.__turns):
+ i = 0
+ while i < sv_nb:
+ if i < first:
+ p_new = p_first + vec_first * float(i)/float(first - 1)
+ if i == first - 1:
+ visible = 0
+ elif i < second:
+ p_new = p_second + vec_second * float(i - first)/float(second - first - 1)
+ if i == second - 1:
+ visible = 0
+ elif i < third:
+ p_new = p_third + vec_third * float(i - second)/float(third - second - 1)
+ if i == third - 1:
+ visible = 0
+ else:
+ p_new = p_fourth + vec_fourth * float(i - third)/float(fourth - third - 1)
+ if i == fourth - 1:
+ visible = 0
+ it.getObject().setPoint(p_new)
+ it.getObject().attribute().setVisible(visible)
+ if visible == 0:
+ visible = 1
+ i = i + 1
+ it.increment()
+ while it.isEnd() == 0:
+ stroke.RemoveVertex(it.getObject())
+ it.increment()
+
+class pyModulateAlphaShader(StrokeShader):
+ def __init__(self, min = 0, max = 1):
+ StrokeShader.__init__(self)
+ self.__min = min
+ self.__max = max
+ def getName(self):
+ return "pyModulateAlphaShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ alpha = it.getObject().attribute().getAlpha()
+ p = it.getObject().getPoint()
+ alpha = alpha * p.y / 400
+ if alpha < self.__min:
+ alpha = self.__min
+ elif alpha > self.__max:
+ alpha = self.__max
+ it.getObject().attribute().setAlpha(alpha)
+ it.increment()
+
+
+## various
+class pyDummyShader(StrokeShader):
+ def getName(self):
+ return "pyDummyShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ toto = it.castToInterface0DIterator()
+ att = it.getObject().attribute()
+ att.setColor(0.3, 0.4, 0.4)
+ att.setThickness(0, 5)
+ it.increment()
+
+class pyDebugShader(StrokeShader):
+ def getName(self):
+ return "pyDebugShader"
+
+ def shade(self, stroke):
+ fe = GetSelectedFEdgeCF()
+ id1=fe.vertexA().getId()
+ id2=fe.vertexB().getId()
+ #print(id1.getFirst(), id1.getSecond())
+ #print(id2.getFirst(), id2.getSecond())
+ it = stroke.strokeVerticesBegin()
+ found = 0
+ foundfirst = 0
+ foundsecond = 0
+ while it.isEnd() == 0:
+ cp = it.getObject()
+ if((cp.A().getId() == id1) or (cp.B().getId() == id1)):
+ foundfirst = 1
+ if((cp.A().getId() == id2) or (cp.B().getId() == id2)):
+ foundsecond = 1
+ if((foundfirst != 0) and (foundsecond != 0)):
+ found = 1
+ break
+ it.increment()
+ if(found != 0):
+ print("The selected Stroke id is: ", stroke.getId().getFirst(), stroke.getId().getSecond())
diff --git a/release/scripts/freestyle/style_modules/sketchy_multiple_parameterization.py b/release/scripts/freestyle/style_modules/sketchy_multiple_parameterization.py
new file mode 100755
index 00000000000..163c891fa90
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/sketchy_multiple_parameterization.py
@@ -0,0 +1,48 @@
+#
+# Filename : sketchy_multiple_parameterization.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Builds sketchy strokes whose topology relies on a
+# parameterization that covers the complete lines (visible+invisible)
+# whereas only the visible portions are actually drawn
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+## 0: don't restrict to selection
+Operators.bidirectionalChain(pySketchyChainSilhouetteIterator(3,0))
+shaders_list = [
+ SamplingShader(2),
+ SpatialNoiseShader(15, 120, 2, 1, 1),
+ IncreasingThicknessShader(5, 30),
+ SmoothingShader(100, 0.05, 0, 0.2, 0, 0, 0, 1),
+ IncreasingColorShader(0,0.2,0,1,0.2,0.7,0.2,1),
+ TextureAssignerShader(6),
+ pyHLRShader()
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/sketchy_topology_broken.py b/release/scripts/freestyle/style_modules/sketchy_topology_broken.py
new file mode 100755
index 00000000000..9ec0cffcfec
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/sketchy_topology_broken.py
@@ -0,0 +1,89 @@
+#
+# Filename : sketchy_topology_broken.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : The topology of the strokes is, first, built
+# independantly from the 3D topology of objects,
+# and, second, so as to chain several times the same ViewEdge.
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+## Backbone stretcher that leaves cusps intact to avoid cracks
+class pyBackboneStretcherNoCuspShader(StrokeShader):
+ def __init__(self, l):
+ StrokeShader.__init__(self)
+ self._l = l
+ def getName(self):
+ return "pyBackboneStretcherNoCuspShader"
+ def shade(self, stroke):
+ it0 = stroke.strokeVerticesBegin()
+ it1 = StrokeVertexIterator(it0)
+ it1.increment()
+ itn = stroke.strokeVerticesEnd()
+ itn.decrement()
+ itn_1 = StrokeVertexIterator(itn)
+ itn_1.decrement()
+ v0 = it0.getObject()
+ v1 = it1.getObject()
+ if((v0.getNature() & Nature.CUSP == 0) and (v1.getNature() & Nature.CUSP == 0)):
+ p0 = v0.getPoint()
+ p1 = v1.getPoint()
+ d1 = p0-p1
+ d1.normalize()
+ newFirst = p0+d1*float(self._l)
+ v0.setPoint(newFirst)
+ else:
+ print("got a v0 cusp")
+ vn_1 = itn_1.getObject()
+ vn = itn.getObject()
+ if((vn.getNature() & Nature.CUSP == 0) and (vn_1.getNature() & Nature.CUSP == 0)):
+ pn = vn.getPoint()
+ pn_1 = vn_1.getPoint()
+ dn = pn-pn_1
+ dn.normalize()
+ newLast = pn+dn*float(self._l)
+ vn.setPoint(newLast)
+ else:
+ print("got a vn cusp")
+
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+## Chain 3 times each ViewEdge indpendantly from the
+## initial objects topology
+Operators.bidirectionalChain(pySketchyChainingIterator(3))
+shaders_list = [
+ SamplingShader(4),
+ SpatialNoiseShader(6, 120, 2, 1, 1),
+ IncreasingThicknessShader(4, 10),
+ SmoothingShader(100, 0.1, 0, 0.2, 0, 0, 0, 1),
+ pyBackboneStretcherNoCuspShader(20),
+ #ConstantColorShader(0.0,0.0,0.0)
+ IncreasingColorShader(0.2,0.2,0.2,1,0.5,0.5,0.5,1),
+ #IncreasingColorShader(1,0,0,1,0,1,0,1),
+ TextureAssignerShader(4)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/sketchy_topology_preserved.py b/release/scripts/freestyle/style_modules/sketchy_topology_preserved.py
new file mode 100755
index 00000000000..85e11af38b9
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/sketchy_topology_preserved.py
@@ -0,0 +1,49 @@
+#
+# Filename : sketchy_topology_preserved.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : The topology of the strokes is built
+# so as to chain several times the same ViewEdge.
+# The topology of the objects is preserved
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = QuantitativeInvisibilityUP1D(0)
+Operators.select(upred)
+Operators.bidirectionalChain(pySketchyChainSilhouetteIterator(3,1))
+shaders_list = [
+ SamplingShader(4),
+ SpatialNoiseShader(20, 220, 2, 1, 1),
+ IncreasingThicknessShader(4, 8),
+ SmoothingShader(300, 0.05, 0, 0.2, 0, 0, 0, 0.5),
+ ConstantColorShader(0.6,0.2,0.0),
+ TextureAssignerShader(4),
+ ]
+
+Operators.create(TrueUP1D(), shaders_list)
+
diff --git a/release/scripts/freestyle/style_modules/split_at_highest_2d_curvatures.py b/release/scripts/freestyle/style_modules/split_at_highest_2d_curvatures.py
new file mode 100755
index 00000000000..52cc10a9c60
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/split_at_highest_2d_curvatures.py
@@ -0,0 +1,41 @@
+#
+# Filename : split_at_highest_2d_curvature.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the visible lines (chaining follows same nature lines)
+# (most basic style module)
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU0D import *
+from PredicatesU1D import *
+from Functions0D import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+func = pyInverseCurvature2DAngleF0D()
+Operators.recursiveSplit(func, pyParameterUP0D(0.4,0.6), NotUP1D(pyHigherLengthUP1D(100)), 2)
+shaders_list = [ConstantThicknessShader(10), IncreasingColorShader(1,0,0,1,0,1,0,1), TextureAssignerShader(3)]
+Operators.create(TrueUP1D(), shaders_list)
+
diff --git a/release/scripts/freestyle/style_modules/split_at_tvertices.py b/release/scripts/freestyle/style_modules/split_at_tvertices.py
new file mode 100755
index 00000000000..78f781dd290
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/split_at_tvertices.py
@@ -0,0 +1,42 @@
+#
+# Filename : split_at_tvertices.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws strokes that starts and stops at Tvertices (visible or not)
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from PredicatesU0D import *
+from Functions0D import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+start = pyVertexNatureUP0D(Nature.T_VERTEX)
+## use the same predicate to decide where to start and where to stop
+## the strokes:
+Operators.sequentialSplit(start, start, 10)
+shaders_list = [ConstantThicknessShader(5), IncreasingColorShader(1,0,0,1,0,1,0,1), TextureAssignerShader(3)]
+Operators.create(TrueUP1D(), shaders_list)
+
diff --git a/release/scripts/freestyle/style_modules/stroke_texture.py b/release/scripts/freestyle/style_modules/stroke_texture.py
new file mode 100755
index 00000000000..afebbe30a90
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/stroke_texture.py
@@ -0,0 +1,43 @@
+#
+# Filename : stroke_texture.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws textured strokes (illustrate the StrokeTextureShader shader)
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+from ChainingIterators import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ SamplingShader(3),
+ BezierCurveShader(4),
+ StrokeTextureShader("washbrushAlpha.bmp", Stroke.DRY_MEDIUM, 1),
+ ConstantThicknessShader(40),
+ ConstantColorShader(0,0,0,1),
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/suggestive.py b/release/scripts/freestyle/style_modules/suggestive.py
new file mode 100755
index 00000000000..39d8515ed6c
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/suggestive.py
@@ -0,0 +1,43 @@
+#
+# Filename : suggestive.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the suggestive contours.
+# ***** The suggestive contours must be enabled
+# in the options dialog *****
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = AndUP1D(pyNatureUP1D(Nature.SUGGESTIVE_CONTOUR), QuantitativeInvisibilityUP1D(0))
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+shaders_list = [
+ IncreasingThicknessShader(1, 3),
+ ConstantColorShader(0.2,0.2,0.2, 1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/thickness_fof_depth_discontinuity.py b/release/scripts/freestyle/style_modules/thickness_fof_depth_discontinuity.py
new file mode 100755
index 00000000000..21f6c7bdf35
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/thickness_fof_depth_discontinuity.py
@@ -0,0 +1,62 @@
+#
+# Filename : thickness_fof_depth_discontinuity.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Assigns to strokes a thickness that depends on the depth discontinuity
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+class pyDepthDiscontinuityThicknessShader(StrokeShader):
+ def __init__(self, min, max):
+ StrokeShader.__init__(self)
+ self.__min = float(min)
+ self.__max = float(max)
+ self.__func = ZDiscontinuityF0D()
+ def getName(self):
+ return "pyDepthDiscontinuityThicknessShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ z_min=0.0
+ z_max=1.0
+ a = (self.__max - self.__min)/(z_max-z_min)
+ b = (self.__min*z_max-self.__max*z_min)/(z_max-z_min)
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ z = self.__func(it.castToInterface0DIterator())
+ thickness = a*z+b
+ it.getObject().attribute().setThickness(thickness, thickness)
+ it.increment()
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ SamplingShader(1),
+ ConstantThicknessShader(3),
+ ConstantColorShader(0.0,0.0,0.0),
+ pyDepthDiscontinuityThicknessShader(0.8, 6)
+ ]
+Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file
diff --git a/release/scripts/freestyle/style_modules/tipremover.py b/release/scripts/freestyle/style_modules/tipremover.py
new file mode 100755
index 00000000000..3e495b7d332
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/tipremover.py
@@ -0,0 +1,42 @@
+#
+# Filename : tipremover.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Removes strokes extremities
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ SamplingShader(5),
+ ConstantThicknessShader(3),
+ ConstantColorShader(0,0,0),
+ TipRemoverShader(20)
+ ]
+Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file
diff --git a/release/scripts/freestyle/style_modules/tvertex_remover.py b/release/scripts/freestyle/style_modules/tvertex_remover.py
new file mode 100755
index 00000000000..c328f4c98ec
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/tvertex_remover.py
@@ -0,0 +1,42 @@
+#
+# Filename : tvertex_remover.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Removes TVertices
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ IncreasingThicknessShader(3, 5),
+ ConstantColorShader(0.2,0.2,0.2, 1),
+ SamplingShader(10.0),
+ pyTVertexRemoverShader()
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/uniformpruning_zsort.py b/release/scripts/freestyle/style_modules/uniformpruning_zsort.py
new file mode 100755
index 00000000000..50a2f6423fd
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/uniformpruning_zsort.py
@@ -0,0 +1,40 @@
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from PredicatesU0D import *
+from PredicatesB1D import *
+from Functions0D import *
+from Functions1D import *
+from shaders import *
+
+class pyDensityUP1D(UnaryPredicate1D):
+ def __init__(self,wsize,threshold, integration = IntegrationType.MEAN, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._wsize = wsize
+ self._threshold = threshold
+ self._integration = integration
+ self._func = DensityF1D(self._wsize, self._integration, sampling)
+
+ def getName(self):
+ return "pyDensityUP1D"
+
+ def __call__(self, inter):
+ d = self._func(inter)
+ print("For Chain ", inter.getId().getFirst(), inter.getId().getSecond(), "density is ", d)
+ if(d < self._threshold):
+ return 1
+ return 0
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator())
+#Operators.sequentialSplit(pyVertexNatureUP0D(Nature.VIEW_VERTEX), 2)
+Operators.sort(pyZBP1D())
+shaders_list = [
+ StrokeTextureShader("smoothAlpha.bmp", Stroke.OPAQUE_MEDIUM, 0),
+ ConstantThicknessShader(3),
+ SamplingShader(5.0),
+ ConstantColorShader(0,0,0,1)
+ ]
+Operators.create(pyDensityUP1D(2,0.05, IntegrationType.MEAN,4), shaders_list)
+#Operators.create(pyDensityFunctorUP1D(8,0.03, pyGetInverseProjectedZF1D(), 0,1, IntegrationType.MEAN), shaders_list)
+
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index d5f7a63366a..53991526844 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -25,6 +25,7 @@ if "bpy" in locals():
_modules = (
"add_mesh_torus",
"animsys_update",
+ "freestyle",
"image",
"mesh",
"nla",
diff --git a/release/scripts/startup/bl_operators/freestyle.py b/release/scripts/startup/bl_operators/freestyle.py
new file mode 100644
index 00000000000..6d0cac65e8e
--- /dev/null
+++ b/release/scripts/startup/bl_operators/freestyle.py
@@ -0,0 +1,71 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# 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.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+
+from bpy.props import (EnumProperty, StringProperty)
+
+
+class SCENE_OT_freestyle_fill_range_by_selection(bpy.types.Operator):
+ '''Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object (either a user-specified object or the active camera).'''
+ bl_idname = "scene.freestyle_fill_range_by_selection"
+ bl_label = "Fill Range by Selection"
+
+ type = EnumProperty(name="Type", description="Type of the modifier to work on.",
+ items=[("COLOR", "Color", "Color modifier type."),
+ ("ALPHA", "Alpha", "Alpha modifier type."),
+ ("THICKNESS", "Thickness", "Thickness modifier type.")])
+ name = StringProperty(name="Name", description="Name of the modifier to work on.")
+
+ def execute(self, context):
+ rl = context.scene.render.layers.active
+ lineset = rl.freestyle_settings.linesets.active
+ linestyle = lineset.linestyle
+ # Find the modifier to work on
+ if self.type == 'COLOR':
+ m = linestyle.color_modifiers[self.name]
+ elif self.type == 'ALPHA':
+ m = linestyle.alpha_modifiers[self.name]
+ else:
+ m = linestyle.thickness_modifiers[self.name]
+ # Find the source object
+ if m.type == 'DISTANCE_FROM_CAMERA':
+ source = context.scene.camera
+ elif m.type == 'DISTANCE_FROM_OBJECT':
+ if m.target is None:
+ self.report({'ERROR'}, "Target object not specified")
+ return {'CANCELLED'}
+ source = m.target
+ else:
+ self.report({'ERROR'}, "Unexpected modifier type: " + m.type)
+ return {'CANCELLED'}
+ # Find selected mesh objects
+ selection = [ob for ob in context.scene.objects if ob.select and ob.type == 'MESH' and ob.name != source.name]
+ if len(selection) > 0:
+ # Compute the min/max distance between selected mesh objects and the source
+ min_dist = float('inf')
+ max_dist = -min_dist
+ for ob in selection:
+ for vert in ob.data.vertices:
+ dist = (ob.matrix_world * vert.co - source.location).length
+ min_dist = min(dist, min_dist)
+ max_dist = max(dist, max_dist)
+ # Fill the Range Min/Max entries with the computed distances
+ m.range_min = min_dist
+ m.range_max = max_dist
+ return {'FINISHED'}
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 395cfc6934e..5a1ddb4b9df 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -123,11 +123,12 @@ class RENDER_PT_layers(RenderButtonsPanel, Panel):
col.prop(rl, "use_solid")
col.prop(rl, "use_halo")
col.prop(rl, "use_ztransp")
+ col.prop(rl, "use_sky")
col = split.column()
- col.prop(rl, "use_sky")
col.prop(rl, "use_edge_enhance")
col.prop(rl, "use_strand")
+ col.prop(rl, "use_freestyle")
layout.separator()
@@ -174,6 +175,406 @@ class RENDER_PT_layers(RenderButtonsPanel, Panel):
row.prop(rl, "exclude_refraction", text="")
+class RENDER_PT_freestyle(RenderButtonsPanel, Panel):
+ bl_label = "Freestyle"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ rd = context.scene.render
+ rl = rd.layers.active
+ return rl and rl.use_freestyle
+
+ def draw(self, context):
+ layout = self.layout
+
+ rd = context.scene.render
+ rl = rd.layers.active
+ freestyle = rl.freestyle_settings
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(freestyle, "raycasting_algorithm", text="Raycasting Algorithm")
+ col.prop(freestyle, "mode", text="Control Mode")
+
+ if freestyle.mode == "EDITOR":
+ col.label(text="Edge Detection Options:")
+ col.prop(freestyle, "use_smoothness")
+ col.prop(freestyle, "crease_angle")
+ col.prop(freestyle, "sphere_radius")
+ col.prop(freestyle, "kr_derivative_epsilon")
+
+ lineset = freestyle.linesets.active
+
+ col.label(text="Line Sets:")
+ row = col.row()
+ rows = 2
+ if lineset:
+ rows = 5
+ row.template_list(freestyle, "linesets", freestyle.linesets, "active_index", rows=rows)
+
+ sub = row.column()
+ subsub = sub.column(align=True)
+ subsub.operator("scene.freestyle_lineset_add", icon='ZOOMIN', text="")
+ subsub.operator("scene.freestyle_lineset_remove", icon='ZOOMOUT', text="")
+ if lineset:
+ sub.separator()
+ subsub = sub.column(align=True)
+ subsub.operator("scene.freestyle_lineset_move", icon='TRIA_UP', text="").direction = 'UP'
+ subsub.operator("scene.freestyle_lineset_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+
+ if lineset:
+ col.prop(lineset, "name")
+
+ col.prop(lineset, "select_by_visibility")
+ if lineset.select_by_visibility:
+ sub = col.row(align=True)
+ sub.prop(lineset, "visibility", expand=True)
+ if lineset.visibility == "RANGE":
+ sub = col.row(align=True)
+ sub.prop(lineset, "qi_start")
+ sub.prop(lineset, "qi_end")
+ col.separator() # XXX
+
+ col.prop(lineset, "select_by_edge_types")
+ if lineset.select_by_edge_types:
+ row = col.row()
+ row.prop(lineset, "edge_type_negation", expand=True)
+ row = col.row()
+ row.prop(lineset, "edge_type_combination", expand=True)
+
+ row = col.row()
+ sub = row.column()
+ sub.prop(lineset, "select_silhouette")
+ sub.prop(lineset, "select_border")
+ sub.prop(lineset, "select_crease")
+ sub.prop(lineset, "select_ridge")
+ sub.prop(lineset, "select_valley")
+ sub.prop(lineset, "select_suggestive_contour")
+ sub.prop(lineset, "select_material_boundary")
+ sub = row.column()
+ sub.prop(lineset, "select_contour")
+ sub.prop(lineset, "select_external_contour")
+ col.separator() # XXX
+
+ col.prop(lineset, "select_by_group")
+ if lineset.select_by_group:
+ col.prop(lineset, "group")
+ row = col.row()
+ row.prop(lineset, "group_negation", expand=True)
+ col.separator() # XXX
+
+ col.prop(lineset, "select_by_image_border")
+
+ else: # freestyle.mode == "SCRIPT"
+
+ col.prop(freestyle, "use_smoothness")
+ col.prop(freestyle, "crease_angle")
+ col.prop(freestyle, "sphere_radius")
+ col.prop(freestyle, "use_ridges_and_valleys")
+ col.prop(freestyle, "use_suggestive_contours")
+ sub = col.row()
+ sub.prop(freestyle, "kr_derivative_epsilon")
+ sub.active = freestyle.use_suggestive_contours
+ col.prop(freestyle, "use_material_boundaries")
+ col.operator("scene.freestyle_module_add")
+
+ for i, module in enumerate(freestyle.modules):
+ box = layout.box()
+ box.context_pointer_set("freestyle_module", module)
+ row = box.row(align=True)
+ row.prop(module, "use", text="")
+ row.prop(module, "module_path", text="")
+ row.operator("scene.freestyle_module_remove", icon='X', text="")
+ row.operator("scene.freestyle_module_move", icon='TRIA_UP', text="").direction = 'UP'
+ row.operator("scene.freestyle_module_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+
+
+class RENDER_PT_freestyle_linestyle(RenderButtonsPanel, Panel):
+ bl_label = "Freestyle: Line Style"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ rd = context.scene.render
+ rl = rd.layers.active
+ if rl and rl.use_freestyle:
+ freestyle = rl.freestyle_settings
+ return freestyle.mode == "EDITOR" and freestyle.linesets.active
+ return False
+
+ def draw_modifier_box_header(self, box, modifier):
+ row = box.row()
+ row.context_pointer_set("modifier", modifier)
+ if modifier.expanded:
+ icon = "TRIA_DOWN"
+ else:
+ icon = "TRIA_RIGHT"
+ row.prop(modifier, "expanded", text="", icon=icon, emboss=False)
+ row.label(text=modifier.rna_type.name)
+ row.prop(modifier, "name", text="")
+ row.prop(modifier, "use", text="")
+ sub = row.row(align=True)
+ sub.operator("scene.freestyle_modifier_move", icon='TRIA_UP', text="").direction = 'UP'
+ sub.operator("scene.freestyle_modifier_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+ row.operator("scene.freestyle_modifier_remove", icon='X', text="")
+
+ def draw_modifier_common(self, box, modifier):
+ row = box.row()
+ row.prop(modifier, "blend", text="")
+ row.prop(modifier, "influence")
+
+ def draw_modifier_color_ramp_common(self, box, modifier, has_range):
+ box.template_color_ramp(modifier, "color_ramp", expand=True)
+ if has_range:
+ row = box.row(align=True)
+ row.prop(modifier, "range_min")
+ row.prop(modifier, "range_max")
+
+ def draw_modifier_curve_common(self, box, modifier, has_range, has_value):
+ row = box.row()
+ row.prop(modifier, "mapping", text="")
+ sub = row.column()
+ sub.prop(modifier, "invert")
+ if modifier.mapping == "CURVE":
+ sub.enabled = False
+ box.template_curve_mapping(modifier, "curve")
+ if has_range:
+ row = box.row(align=True)
+ row.prop(modifier, "range_min")
+ row.prop(modifier, "range_max")
+ if has_value:
+ row = box.row(align=True)
+ row.prop(modifier, "value_min")
+ row.prop(modifier, "value_max")
+
+ def draw_color_modifier(self, context, modifier):
+ layout = self.layout
+
+ col = layout.column(align=True)
+ self.draw_modifier_box_header(col.box(), modifier)
+ if modifier.expanded:
+ box = col.box()
+ self.draw_modifier_common(box, modifier)
+
+ if modifier.type == "ALONG_STROKE":
+ self.draw_modifier_color_ramp_common(box, modifier, False)
+
+ elif modifier.type == "DISTANCE_FROM_OBJECT":
+ box.prop(modifier, "target")
+ self.draw_modifier_color_ramp_common(box, modifier, True)
+ prop = box.operator("scene.freestyle_fill_range_by_selection")
+ prop.type = 'COLOR'
+ prop.name = modifier.name
+
+ elif modifier.type == "DISTANCE_FROM_CAMERA":
+ self.draw_modifier_color_ramp_common(box, modifier, True)
+ prop = box.operator("scene.freestyle_fill_range_by_selection")
+ prop.type = 'COLOR'
+ prop.name = modifier.name
+
+ elif modifier.type == "MATERIAL":
+ row = box.row()
+ row.prop(modifier, "material_attr", text="")
+ sub = row.column()
+ sub.prop(modifier, "use_ramp")
+ if modifier.material_attr in ["DIFF", "SPEC"]:
+ sub.enabled = True
+ show_ramp = modifier.use_ramp
+ else:
+ sub.enabled = False
+ show_ramp = True
+ if show_ramp:
+ self.draw_modifier_color_ramp_common(box, modifier, False)
+
+ def draw_alpha_modifier(self, context, modifier):
+ layout = self.layout
+
+ col = layout.column(align=True)
+ self.draw_modifier_box_header(col.box(), modifier)
+ if modifier.expanded:
+ box = col.box()
+ self.draw_modifier_common(box, modifier)
+
+ if modifier.type == "ALONG_STROKE":
+ self.draw_modifier_curve_common(box, modifier, False, False)
+
+ elif modifier.type == "DISTANCE_FROM_OBJECT":
+ box.prop(modifier, "target")
+ self.draw_modifier_curve_common(box, modifier, True, False)
+ prop = box.operator("scene.freestyle_fill_range_by_selection")
+ prop.type = 'ALPHA'
+ prop.name = modifier.name
+
+ elif modifier.type == "DISTANCE_FROM_CAMERA":
+ self.draw_modifier_curve_common(box, modifier, True, False)
+ prop = box.operator("scene.freestyle_fill_range_by_selection")
+ prop.type = 'ALPHA'
+ prop.name = modifier.name
+
+ elif modifier.type == "MATERIAL":
+ box.prop(modifier, "material_attr", text="")
+ self.draw_modifier_curve_common(box, modifier, False, False)
+
+ def draw_thickness_modifier(self, context, modifier):
+ layout = self.layout
+
+ col = layout.column(align=True)
+ self.draw_modifier_box_header(col.box(), modifier)
+ if modifier.expanded:
+ box = col.box()
+ self.draw_modifier_common(box, modifier)
+
+ if modifier.type == "ALONG_STROKE":
+ self.draw_modifier_curve_common(box, modifier, False, True)
+
+ elif modifier.type == "DISTANCE_FROM_OBJECT":
+ box.prop(modifier, "target")
+ self.draw_modifier_curve_common(box, modifier, True, True)
+ prop = box.operator("scene.freestyle_fill_range_by_selection")
+ prop.type = 'THICKNESS'
+ prop.name = modifier.name
+
+ elif modifier.type == "DISTANCE_FROM_CAMERA":
+ self.draw_modifier_curve_common(box, modifier, True, True)
+ prop = box.operator("scene.freestyle_fill_range_by_selection")
+ prop.type = 'THICKNESS'
+ prop.name = modifier.name
+
+ elif modifier.type == "MATERIAL":
+ box.prop(modifier, "material_attr", text="")
+ self.draw_modifier_curve_common(box, modifier, False, True)
+
+ def draw_geometry_modifier(self, context, modifier):
+ layout = self.layout
+
+ col = layout.column(align=True)
+ self.draw_modifier_box_header(col.box(), modifier)
+ if modifier.expanded:
+ box = col.box()
+
+ if modifier.type == "SAMPLING":
+ box.prop(modifier, "sampling")
+
+ elif modifier.type == "BEZIER_CURVE":
+ box.prop(modifier, "error")
+
+ elif modifier.type == "SINUS_DISPLACEMENT":
+ box.prop(modifier, "wavelength")
+ box.prop(modifier, "amplitude")
+ box.prop(modifier, "phase")
+
+ elif modifier.type == "SPATIAL_NOISE":
+ box.prop(modifier, "amplitude")
+ box.prop(modifier, "scale")
+ box.prop(modifier, "octaves")
+ sub = box.row()
+ sub.prop(modifier, "smooth")
+ sub.prop(modifier, "pure_random")
+
+ elif modifier.type == "PERLIN_NOISE_1D":
+ box.prop(modifier, "frequency")
+ box.prop(modifier, "amplitude")
+ box.prop(modifier, "octaves")
+ box.prop(modifier, "angle")
+ box.prop(modifier, "seed")
+
+ elif modifier.type == "PERLIN_NOISE_2D":
+ box.prop(modifier, "frequency")
+ box.prop(modifier, "amplitude")
+ box.prop(modifier, "octaves")
+ box.prop(modifier, "angle")
+ box.prop(modifier, "seed")
+
+ elif modifier.type == "BACKBONE_STRETCHER":
+ box.prop(modifier, "amount")
+
+ elif modifier.type == "TIP_REMOVER":
+ box.prop(modifier, "tip_length")
+
+ def draw(self, context):
+ layout = self.layout
+
+ rd = context.scene.render
+ rl = rd.layers.active
+ lineset = rl.freestyle_settings.linesets.active
+ linestyle = lineset.linestyle
+
+ layout.template_ID(lineset, "linestyle", new="scene.freestyle_linestyle_new")
+ row = layout.row(align=True)
+ row.prop(linestyle, "panel", expand=True)
+ if linestyle.panel == "STROKES":
+ col = layout.column()
+ col.label(text="Chaining:")
+ col.prop(linestyle, "same_object")
+ col = layout.column()
+ col.label(text="Splitting:")
+ row = col.row(align=True)
+ row.prop(linestyle, "material_boundary")
+ col = layout.column()
+ col.label(text="Caps:")
+ row = col.row(align=True)
+ row.prop(linestyle, "caps", expand=True)
+ col = layout.column()
+ col.prop(linestyle, "use_dashed_line")
+ split = col.split()
+ split.enabled = linestyle.use_dashed_line
+ sub = split.column()
+ sub.label(text="Dash")
+ sub.prop(linestyle, "dash1", text="")
+ sub = split.column()
+ sub.label(text="Gap")
+ sub.prop(linestyle, "gap1", text="")
+ sub = split.column()
+ sub.label(text="Dash")
+ sub.prop(linestyle, "dash2", text="")
+ sub = split.column()
+ sub.label(text="Gap")
+ sub.prop(linestyle, "gap2", text="")
+ sub = split.column()
+ sub.label(text="Dash")
+ sub.prop(linestyle, "dash3", text="")
+ sub = split.column()
+ sub.label(text="Gap")
+ sub.prop(linestyle, "gap3", text="")
+ elif linestyle.panel == "COLOR":
+ col = layout.column()
+ col.label(text="Base Color:")
+ col.prop(linestyle, "color", text="")
+ col = layout.column()
+ col.label(text="Modifiers:")
+ col.operator_menu_enum("scene.freestyle_color_modifier_add", "type", text="Add Modifier")
+ for modifier in linestyle.color_modifiers:
+ self.draw_color_modifier(context, modifier)
+ elif linestyle.panel == "ALPHA":
+ col = layout.column()
+ col.label(text="Base Transparency:")
+ col.prop(linestyle, "alpha")
+ col = layout.column()
+ col.label(text="Modifiers:")
+ col.operator_menu_enum("scene.freestyle_alpha_modifier_add", "type", text="Add Modifier")
+ for modifier in linestyle.alpha_modifiers:
+ self.draw_alpha_modifier(context, modifier)
+ elif linestyle.panel == "THICKNESS":
+ col = layout.column()
+ col.label(text="Base Thickness:")
+ col.prop(linestyle, "thickness")
+ col = layout.column()
+ col.label(text="Modifiers:")
+ col.operator_menu_enum("scene.freestyle_thickness_modifier_add", "type", text="Add Modifier")
+ for modifier in linestyle.thickness_modifiers:
+ self.draw_thickness_modifier(context, modifier)
+ elif linestyle.panel == "GEOMETRY":
+ col = layout.column()
+ col.label(text="Modifiers:")
+ col.operator_menu_enum("scene.freestyle_geometry_modifier_add", "type", text="Add Modifier")
+ for modifier in linestyle.geometry_modifiers:
+ self.draw_geometry_modifier(context, modifier)
+ elif linestyle.panel == "MISC":
+ pass
+
+
class RENDER_PT_dimensions(RenderButtonsPanel, Panel):
bl_label = "Dimensions"
COMPAT_ENGINES = {'BLENDER_RENDER'}
@@ -398,6 +799,11 @@ class RENDER_PT_post_processing(RenderButtonsPanel, Panel):
sub.prop(rd, "edge_threshold", text="Threshold", slider=True)
sub.prop(rd, "edge_color", text="")
+ layout.separator()
+
+ split = layout.split()
+ col = split.column()
+ col.prop(rd, "use_freestyle", text="Freestyle")
class RENDER_PT_stamp(RenderButtonsPanel, Panel):
bl_label = "Stamp"