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 'source/blender/freestyle')
-rw-r--r--source/blender/freestyle/CMakeLists.txt45
-rw-r--r--source/blender/freestyle/FRS_freestyle.h87
-rw-r--r--source/blender/freestyle/FRS_freestyle_config.h48
-rw-r--r--source/blender/freestyle/SConscript75
-rw-r--r--source/blender/freestyle/intern/application/AppCanvas.cpp218
-rw-r--r--source/blender/freestyle/intern/application/AppCanvas.h101
-rw-r--r--source/blender/freestyle/intern/application/AppConfig.cpp112
-rw-r--r--source/blender/freestyle/intern/application/AppConfig.h112
-rw-r--r--source/blender/freestyle/intern/application/AppView.cpp198
-rw-r--r--source/blender/freestyle/intern/application/AppView.h245
-rw-r--r--source/blender/freestyle/intern/application/Controller.cpp1073
-rw-r--r--source/blender/freestyle/intern/application/Controller.h261
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp766
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h138
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp513
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h76
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h70
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderTextureManager.cpp104
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderTextureManager.h53
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp869
-rw-r--r--source/blender/freestyle/intern/geometry/BBox.h154
-rw-r--r--source/blender/freestyle/intern/geometry/Bezier.cpp127
-rw-r--r--source/blender/freestyle/intern/geometry/Bezier.h96
-rw-r--r--source/blender/freestyle/intern/geometry/FastGrid.cpp87
-rw-r--r--source/blender/freestyle/intern/geometry/FastGrid.h86
-rw-r--r--source/blender/freestyle/intern/geometry/FitCurve.cpp602
-rw-r--r--source/blender/freestyle/intern/geometry/FitCurve.h125
-rw-r--r--source/blender/freestyle/intern/geometry/Geom.h84
-rw-r--r--source/blender/freestyle/intern/geometry/GeomCleaner.cpp240
-rw-r--r--source/blender/freestyle/intern/geometry/GeomCleaner.h227
-rw-r--r--source/blender/freestyle/intern/geometry/GeomUtils.cpp780
-rw-r--r--source/blender/freestyle/intern/geometry/GeomUtils.h277
-rw-r--r--source/blender/freestyle/intern/geometry/Grid.cpp390
-rw-r--r--source/blender/freestyle/intern/geometry/Grid.h384
-rw-r--r--source/blender/freestyle/intern/geometry/GridHelpers.cpp59
-rw-r--r--source/blender/freestyle/intern/geometry/GridHelpers.h215
-rw-r--r--source/blender/freestyle/intern/geometry/HashGrid.cpp53
-rw-r--r--source/blender/freestyle/intern/geometry/HashGrid.h116
-rw-r--r--source/blender/freestyle/intern/geometry/Noise.cpp285
-rw-r--r--source/blender/freestyle/intern/geometry/Noise.h83
-rw-r--r--source/blender/freestyle/intern/geometry/Polygon.h221
-rw-r--r--source/blender/freestyle/intern/geometry/SweepLine.h332
-rw-r--r--source/blender/freestyle/intern/geometry/VecMat.h976
-rw-r--r--source/blender/freestyle/intern/geometry/matrix_util.cpp266
-rw-r--r--source/blender/freestyle/intern/geometry/matrix_util.h72
-rw-r--r--source/blender/freestyle/intern/geometry/normal_cycle.cpp100
-rw-r--r--source/blender/freestyle/intern/geometry/normal_cycle.h144
-rw-r--r--source/blender/freestyle/intern/image/GaussianFilter.cpp112
-rw-r--r--source/blender/freestyle/intern/image/GaussianFilter.h161
-rw-r--r--source/blender/freestyle/intern/image/Image.h415
-rw-r--r--source/blender/freestyle/intern/image/ImagePyramid.cpp192
-rw-r--r--source/blender/freestyle/intern/image/ImagePyramid.h116
-rw-r--r--source/blender/freestyle/intern/python/BPy_BBox.cpp100
-rw-r--r--source/blender/freestyle/intern/python/BPy_BBox.h38
-rw-r--r--source/blender/freestyle/intern/python/BPy_BinaryPredicate0D.cpp166
-rw-r--r--source/blender/freestyle/intern/python/BPy_BinaryPredicate0D.h36
-rw-r--r--source/blender/freestyle/intern/python/BPy_BinaryPredicate1D.cpp193
-rw-r--r--source/blender/freestyle/intern/python/BPy_BinaryPredicate1D.h35
-rw-r--r--source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp262
-rw-r--r--source/blender/freestyle/intern/python/BPy_ContextFunctions.h18
-rw-r--r--source/blender/freestyle/intern/python/BPy_Convert.cpp609
-rw-r--r--source/blender/freestyle/intern/python/BPy_Convert.h147
-rw-r--r--source/blender/freestyle/intern/python/BPy_Freestyle.cpp509
-rw-r--r--source/blender/freestyle/intern/python/BPy_Freestyle.h22
-rw-r--r--source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp599
-rw-r--r--source/blender/freestyle/intern/python/BPy_FrsMaterial.h37
-rw-r--r--source/blender/freestyle/intern/python/BPy_FrsNoise.cpp280
-rw-r--r--source/blender/freestyle/intern/python/BPy_FrsNoise.h36
-rw-r--r--source/blender/freestyle/intern/python/BPy_Id.cpp222
-rw-r--r--source/blender/freestyle/intern/python/BPy_Id.h36
-rw-r--r--source/blender/freestyle/intern/python/BPy_IntegrationType.cpp250
-rw-r--r--source/blender/freestyle/intern/python/BPy_IntegrationType.h28
-rw-r--r--source/blender/freestyle/intern/python/BPy_Interface0D.cpp354
-rw-r--r--source/blender/freestyle/intern/python/BPy_Interface0D.h35
-rw-r--r--source/blender/freestyle/intern/python/BPy_Interface1D.cpp337
-rw-r--r--source/blender/freestyle/intern/python/BPy_Interface1D.h36
-rw-r--r--source/blender/freestyle/intern/python/BPy_Iterator.cpp229
-rw-r--r--source/blender/freestyle/intern/python/BPy_Iterator.h35
-rw-r--r--source/blender/freestyle/intern/python/BPy_MediumType.cpp99
-rw-r--r--source/blender/freestyle/intern/python/BPy_MediumType.h42
-rw-r--r--source/blender/freestyle/intern/python/BPy_Nature.cpp312
-rw-r--r--source/blender/freestyle/intern/python/BPy_Nature.h33
-rw-r--r--source/blender/freestyle/intern/python/BPy_Operators.cpp682
-rw-r--r--source/blender/freestyle/intern/python/BPy_Operators.h34
-rw-r--r--source/blender/freestyle/intern/python/BPy_SShape.cpp330
-rw-r--r--source/blender/freestyle/intern/python/BPy_SShape.h35
-rw-r--r--source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp662
-rw-r--r--source/blender/freestyle/intern/python/BPy_StrokeAttribute.h35
-rw-r--r--source/blender/freestyle/intern/python/BPy_StrokeShader.cpp297
-rw-r--r--source/blender/freestyle/intern/python/BPy_StrokeShader.h40
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp126
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryFunction0D.h34
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp117
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryFunction1D.h34
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryPredicate0D.cpp184
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryPredicate0D.h34
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryPredicate1D.cpp236
-rw-r--r--source/blender/freestyle/intern/python/BPy_UnaryPredicate1D.h34
-rw-r--r--source/blender/freestyle/intern/python/BPy_ViewMap.cpp195
-rw-r--r--source/blender/freestyle/intern/python/BPy_ViewMap.h34
-rw-r--r--source/blender/freestyle/intern/python/BPy_ViewShape.cpp353
-rw-r--r--source/blender/freestyle/intern/python/BPy_ViewShape.h35
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_FalseBP1D.cpp79
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_FalseBP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_Length2DBP1D.cpp81
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_Length2DBP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.cpp80
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_TrueBP1D.cpp80
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_TrueBP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.cpp92
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/Director.cpp304
-rw-r--r--source/blender/freestyle/intern/python/Director.h49
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp278
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.h31
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp338
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.h32
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp195
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.h31
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp400
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.h31
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp153
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.h31
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp249
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.h31
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp416
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.h31
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp202
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.h31
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp517
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.h31
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp463
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.h32
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp171
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.h31
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp373
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.h31
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp240
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.h31
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp167
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.h32
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp205
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.h35
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp131
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.h33
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp236
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.h33
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp171
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.h32
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp151
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.h33
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp181
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.h33
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp197
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.h33
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp266
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.h33
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp140
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.h34
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_BackboneStretcherShader.cpp91
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_BackboneStretcherShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_BezierCurveShader.cpp93
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_BezierCurveShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_CalligraphicShader.cpp113
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_CalligraphicShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ColorNoiseShader.cpp92
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ColorNoiseShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.cpp98
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantColorShader.cpp96
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantColorShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantThicknessShader.cpp90
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantThicknessShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.cpp96
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_GuidingLinesShader.cpp98
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_GuidingLinesShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingColorShader.cpp106
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingColorShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingThicknessShader.cpp96
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingThicknessShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_PolygonalizationShader.cpp97
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_PolygonalizationShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_SamplingShader.cpp90
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_SamplingShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp108
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_SpatialNoiseShader.cpp102
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_SpatialNoiseShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.cpp117
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.cpp106
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessNoiseShader.cpp92
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessNoiseShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.cpp103
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_TipRemoverShader.cpp91
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_TipRemoverShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.cpp90
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.h31
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.cpp84
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.h31
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DDouble.cpp215
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DDouble.h34
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DEdgeNature.cpp159
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DEdgeNature.h36
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DFloat.cpp189
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DFloat.h34
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DId.cpp158
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DId.h36
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DMaterial.cpp160
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DMaterial.h36
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.cpp159
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.h34
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec2f.cpp165
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec2f.h37
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec3f.cpp159
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec3f.h37
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp172
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.h37
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DViewShape.cpp165
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DViewShape.h36
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.cpp92
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp96
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.cpp87
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.cpp89
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.cpp89
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.cpp89
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.cpp86
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.cpp86
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.cpp89
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.cpp96
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.cpp86
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.cpp86
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.cpp86
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.cpp86
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.cpp86
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.cpp86
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.cpp92
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp91
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.cpp87
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.cpp86
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.cpp93
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.cpp91
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.cpp94
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp95
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.cpp92
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.cpp87
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.cpp289
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.h34
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.cpp210
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.h36
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.cpp203
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.h34
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp210
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.h34
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.cpp216
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.h37
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.cpp210
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.h37
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp235
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.h37
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.cpp222
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.h34
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.cpp99
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.cpp94
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.cpp96
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.cpp94
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.cpp94
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.cpp109
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.cpp110
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp114
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.cpp95
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.cpp94
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.cpp94
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.cpp107
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.h29
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.cpp107
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.cpp95
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.cpp93
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.cpp94
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.cpp101
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp99
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.cpp99
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.cpp86
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.cpp86
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.cpp86
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.cpp84
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.cpp84
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.cpp84
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.h30
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_FalseUP0D.cpp78
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_FalseUP0D.h29
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_TrueUP0D.cpp78
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_TrueUP0D.h29
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp79
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.cpp95
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp89
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp89
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp81
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_FalseUP1D.cpp78
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_FalseUP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.cpp92
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp92
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_TrueUP1D.cpp78
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_TrueUP1D.h29
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.cpp88
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.h29
-rw-r--r--source/blender/freestyle/intern/scene_graph/DrawingStyle.h128
-rw-r--r--source/blender/freestyle/intern/scene_graph/FrsMaterial.h379
-rw-r--r--source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp331
-rw-r--r--source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h322
-rw-r--r--source/blender/freestyle/intern/scene_graph/LineRep.cpp71
-rw-r--r--source/blender/freestyle/intern/scene_graph/LineRep.h158
-rw-r--r--source/blender/freestyle/intern/scene_graph/Node.h115
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeCamera.cpp143
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeCamera.h216
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeDrawingStyle.cpp46
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeDrawingStyle.h111
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeGroup.cpp126
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeGroup.h89
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeLight.cpp86
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeLight.h113
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeShape.cpp63
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeShape.h103
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeTransform.cpp178
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeTransform.h110
-rw-r--r--source/blender/freestyle/intern/scene_graph/OrientedLineRep.cpp46
-rw-r--r--source/blender/freestyle/intern/scene_graph/OrientedLineRep.h66
-rw-r--r--source/blender/freestyle/intern/scene_graph/Rep.cpp35
-rw-r--r--source/blender/freestyle/intern/scene_graph/Rep.h173
-rw-r--r--source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.cpp110
-rw-r--r--source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.h109
-rw-r--r--source/blender/freestyle/intern/scene_graph/SceneVisitor.cpp35
-rw-r--r--source/blender/freestyle/intern/scene_graph/SceneVisitor.h102
-rw-r--r--source/blender/freestyle/intern/scene_graph/TriangleRep.cpp69
-rw-r--r--source/blender/freestyle/intern/scene_graph/TriangleRep.h150
-rw-r--r--source/blender/freestyle/intern/scene_graph/VertexRep.cpp41
-rw-r--r--source/blender/freestyle/intern/scene_graph/VertexRep.h141
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedFunctions0D.cpp117
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedFunctions0D.h229
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp138
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h294
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h95
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp404
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h226
-rw-r--r--source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp1134
-rw-r--r--source/blender/freestyle/intern/stroke/BasicStrokeShaders.h902
-rw-r--r--source/blender/freestyle/intern/stroke/Canvas.cpp477
-rw-r--r--source/blender/freestyle/intern/stroke/Canvas.h249
-rw-r--r--source/blender/freestyle/intern/stroke/Chain.cpp156
-rw-r--r--source/blender/freestyle/intern/stroke/Chain.h116
-rw-r--r--source/blender/freestyle/intern/stroke/ChainingIterators.cpp202
-rw-r--r--source/blender/freestyle/intern/stroke/ChainingIterators.h407
-rw-r--r--source/blender/freestyle/intern/stroke/ContextFunctions.cpp87
-rw-r--r--source/blender/freestyle/intern/stroke/ContextFunctions.h120
-rw-r--r--source/blender/freestyle/intern/stroke/Curve.cpp931
-rw-r--r--source/blender/freestyle/intern/stroke/Curve.h589
-rw-r--r--source/blender/freestyle/intern/stroke/CurveAdvancedIterators.h383
-rw-r--r--source/blender/freestyle/intern/stroke/CurveIterators.h302
-rw-r--r--source/blender/freestyle/intern/stroke/Modifiers.h74
-rw-r--r--source/blender/freestyle/intern/stroke/Module.h82
-rw-r--r--source/blender/freestyle/intern/stroke/Operators.cpp1286
-rw-r--r--source/blender/freestyle/intern/stroke/Operators.h274
-rw-r--r--source/blender/freestyle/intern/stroke/PSStrokeRenderer.cpp106
-rw-r--r--source/blender/freestyle/intern/stroke/PSStrokeRenderer.h69
-rw-r--r--source/blender/freestyle/intern/stroke/Predicates0D.h186
-rw-r--r--source/blender/freestyle/intern/stroke/Predicates1D.h589
-rw-r--r--source/blender/freestyle/intern/stroke/QInformationMap.h73
-rw-r--r--source/blender/freestyle/intern/stroke/Stroke.cpp954
-rw-r--r--source/blender/freestyle/intern/stroke/Stroke.h822
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeAdvancedIterators.h191
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeIO.cpp73
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeIO.h53
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeIterators.h229
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeLayer.cpp70
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeLayer.h106
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeRenderer.cpp138
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeRenderer.h145
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeRep.cpp789
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeRep.h217
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeShader.h107
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeTesselator.cpp94
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeTesselator.h78
-rw-r--r--source/blender/freestyle/intern/stroke/StyleModule.h184
-rw-r--r--source/blender/freestyle/intern/stroke/TextStrokeRenderer.cpp73
-rw-r--r--source/blender/freestyle/intern/stroke/TextStrokeRenderer.h68
-rw-r--r--source/blender/freestyle/intern/system/BaseIterator.h97
-rw-r--r--source/blender/freestyle/intern/system/BaseObject.cpp36
-rw-r--r--source/blender/freestyle/intern/system/BaseObject.h77
-rw-r--r--source/blender/freestyle/intern/system/Cast.h49
-rw-r--r--source/blender/freestyle/intern/system/Exception.cpp37
-rw-r--r--source/blender/freestyle/intern/system/Exception.h70
-rw-r--r--source/blender/freestyle/intern/system/FreestyleConfig.h96
-rw-r--r--source/blender/freestyle/intern/system/Id.h142
-rw-r--r--source/blender/freestyle/intern/system/Interpreter.h65
-rw-r--r--source/blender/freestyle/intern/system/Iterator.cpp32
-rw-r--r--source/blender/freestyle/intern/system/Iterator.h75
-rw-r--r--source/blender/freestyle/intern/system/PointerSequence.h96
-rw-r--r--source/blender/freestyle/intern/system/Precision.h44
-rw-r--r--source/blender/freestyle/intern/system/ProgressBar.h96
-rw-r--r--source/blender/freestyle/intern/system/PseudoNoise.cpp116
-rw-r--r--source/blender/freestyle/intern/system/PseudoNoise.h60
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.cpp38
-rw-r--r--source/blender/freestyle/intern/system/PythonInterpreter.h198
-rw-r--r--source/blender/freestyle/intern/system/RandGen.cpp132
-rw-r--r--source/blender/freestyle/intern/system/RandGen.h54
-rw-r--r--source/blender/freestyle/intern/system/RenderMonitor.h63
-rw-r--r--source/blender/freestyle/intern/system/StringUtils.cpp89
-rw-r--r--source/blender/freestyle/intern/system/StringUtils.h75
-rw-r--r--source/blender/freestyle/intern/system/TimeStamp.cpp38
-rw-r--r--source/blender/freestyle/intern/system/TimeStamp.h78
-rw-r--r--source/blender/freestyle/intern/system/TimeUtils.h64
-rw-r--r--source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp124
-rw-r--r--source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.h75
-rw-r--r--source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp138
-rw-r--r--source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.h72
-rw-r--r--source/blender/freestyle/intern/view_map/BoxGrid.cpp241
-rw-r--r--source/blender/freestyle/intern/view_map/BoxGrid.h417
-rw-r--r--source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp287
-rw-r--r--source/blender/freestyle/intern/view_map/CulledOccluderSource.h69
-rw-r--r--source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp761
-rw-r--r--source/blender/freestyle/intern/view_map/FEdgeXDetector.h241
-rw-r--r--source/blender/freestyle/intern/view_map/Functions0D.cpp376
-rw-r--r--source/blender/freestyle/intern/view_map/Functions0D.h532
-rw-r--r--source/blender/freestyle/intern/view_map/Functions1D.cpp271
-rw-r--r--source/blender/freestyle/intern/view_map/Functions1D.h627
-rw-r--r--source/blender/freestyle/intern/view_map/GridDensityProvider.h152
-rw-r--r--source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp84
-rw-r--r--source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.h60
-rw-r--r--source/blender/freestyle/intern/view_map/Interface0D.h390
-rw-r--r--source/blender/freestyle/intern/view_map/Interface1D.h230
-rw-r--r--source/blender/freestyle/intern/view_map/OccluderSource.cpp150
-rw-r--r--source/blender/freestyle/intern/view_map/OccluderSource.h76
-rw-r--r--source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp123
-rw-r--r--source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.h75
-rw-r--r--source/blender/freestyle/intern/view_map/Silhouette.cpp414
-rw-r--r--source/blender/freestyle/intern/view_map/Silhouette.h1876
-rw-r--r--source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp322
-rw-r--r--source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.h136
-rw-r--r--source/blender/freestyle/intern/view_map/SphericalGrid.cpp249
-rw-r--r--source/blender/freestyle/intern/view_map/SphericalGrid.h423
-rw-r--r--source/blender/freestyle/intern/view_map/SteerableViewMap.cpp302
-rw-r--r--source/blender/freestyle/intern/view_map/SteerableViewMap.h154
-rw-r--r--source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp753
-rw-r--r--source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.h288
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMap.cpp753
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMap.h1779
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h789
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp2390
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapBuilder.h257
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapIO.cpp1258
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapIO.h129
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapIterators.h574
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapTesselator.cpp49
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMapTesselator.h211
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.cpp642
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.h143
-rw-r--r--source/blender/freestyle/intern/winged_edge/Nature.h79
-rw-r--r--source/blender/freestyle/intern/winged_edge/WEdge.cpp713
-rw-r--r--source/blender/freestyle/intern/winged_edge/WEdge.h1344
-rw-r--r--source/blender/freestyle/intern/winged_edge/WFillGrid.cpp68
-rw-r--r--source/blender/freestyle/intern/winged_edge/WFillGrid.h88
-rw-r--r--source/blender/freestyle/intern/winged_edge/WSFillGrid.cpp67
-rw-r--r--source/blender/freestyle/intern/winged_edge/WSFillGrid.h87
-rw-r--r--source/blender/freestyle/intern/winged_edge/WXEdge.cpp301
-rw-r--r--source/blender/freestyle/intern/winged_edge/WXEdge.h809
-rw-r--r--source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp58
-rw-r--r--source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.h54
-rw-r--r--source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp373
-rw-r--r--source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.h157
529 files changed, 87805 insertions, 0 deletions
diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt
new file mode 100644
index 00000000000..71bdb6aaf9e
--- /dev/null
+++ b/source/blender/freestyle/CMakeLists.txt
@@ -0,0 +1,45 @@
+# ***** 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.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+file(GLOB_RECURSE SRC *.cpp *.h)
+
+set(INC
+ ../blenkernel ../blenloader ../blenlib ../imbuf ../makesdna ../makesrna
+ ../python ../python/intern ../render/extern/include ../render/intern/include
+ ../../../extern/glew/include ../../../intern/guardedalloc ../freestyle
+)
+
+set(INC_SYS
+ ${PYTHON_INCLUDE_DIRS}
+ ${PNG_INC}
+)
+
+add_definitions(-DWITH_FREESTYLE)
+
+if(WIN32)
+ set(INC_SYS ${INC_SYS} ${PTHREADS_INC})
+endif(WIN32)
+
+blender_add_lib(bf_freestyle "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/freestyle/FRS_freestyle.h b/source/blender/freestyle/FRS_freestyle.h
new file mode 100644
index 00000000000..ece51d20048
--- /dev/null
+++ b/source/blender/freestyle/FRS_freestyle.h
@@ -0,0 +1,87 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FRS_FREESTYLE_H__
+#define __FRS_FREESTYLE_H__
+
+/** \file blender/freestyle/FRS_freestyle.h
+ * \ingroup freestyle
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "DNA_listBase.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_context.h"
+#include "BKE_object.h"
+
+struct Render;
+
+extern Scene *freestyle_scene;
+extern float freestyle_viewpoint[3];
+extern float freestyle_mv[4][4];
+extern float freestyle_proj[4][4];
+extern int freestyle_viewport[4];
+
+/* Rendering */
+void FRS_initialize(void);
+void FRS_set_context(bContext* C);
+void FRS_read_file(bContext* C);
+int FRS_is_freestyle_enabled(struct SceneRenderLayer* srl);
+void FRS_init_stroke_rendering(struct Render* re);
+struct Render* FRS_do_stroke_rendering(struct Render* re, struct SceneRenderLayer* srl);
+void FRS_finish_stroke_rendering(struct Render* re);
+void FRS_composite_result(struct Render* re, struct SceneRenderLayer* srl, struct Render* freestyle_render);
+void FRS_exit(void);
+
+/* Panel configuration */
+void FRS_add_module(FreestyleConfig *config);
+void FRS_delete_module(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
+void FRS_move_module_up(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
+void FRS_move_module_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
+
+FreestyleLineSet *FRS_add_lineset(FreestyleConfig *config);
+void FRS_copy_active_lineset(FreestyleConfig *config);
+void FRS_paste_active_lineset(FreestyleConfig *config);
+void FRS_delete_active_lineset(FreestyleConfig *config);
+void FRS_move_active_lineset_up(FreestyleConfig *config);
+void FRS_move_active_lineset_down(FreestyleConfig *config);
+
+FreestyleLineSet *FRS_get_active_lineset(FreestyleConfig *config);
+short FRS_get_active_lineset_index(FreestyleConfig *config);
+void FRS_set_active_lineset_index(FreestyleConfig *config, short index);
+
+void FRS_unlink_target_object(FreestyleConfig *config, struct Object *ob);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __FRS_FREESTYLE_H__
diff --git a/source/blender/freestyle/FRS_freestyle_config.h b/source/blender/freestyle/FRS_freestyle_config.h
new file mode 100644
index 00000000000..0aceffcee1d
--- /dev/null
+++ b/source/blender/freestyle/FRS_freestyle_config.h
@@ -0,0 +1,48 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FRS_FREESTYLE_CONFIG_H__
+#define __FRS_FREESTYLE_CONFIG_H__
+
+/** \file FRS_freestyle_config.h
+ * \ingroup freestyle
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "DNA_scene_types.h"
+
+void FRS_add_freestyle_config(SceneRenderLayer* srl);
+void FRS_free_freestyle_config(SceneRenderLayer* srl);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __FRS_FREESTYLE_CONFIG_H__
diff --git a/source/blender/freestyle/SConscript b/source/blender/freestyle/SConscript
new file mode 100644
index 00000000000..d5ccf12d2db
--- /dev/null
+++ b/source/blender/freestyle/SConscript
@@ -0,0 +1,75 @@
+#!/usr/bin/python
+import sys
+Import ('env')
+
+sources = []
+defs = ['WITH_FREESTYLE']
+incs = ''
+
+incs += '../blenkernel ../blenloader ../blenlib ../imbuf ../makesdna ../makesrna'
+incs += ' ../python ../python/intern ../render/extern/include ../render/intern/include'
+incs += ' #/extern/glew/include #/intern/guardedalloc ../freestyle'
+incs += ' ' + env['BF_PYTHON_INC']
+incs += ' ' + env['BF_PNG_INC']
+
+if env['OURPLATFORM'] == 'linux2':
+ cflags='-pthread'
+ incs += ' ../../../extern/binreloc/include'
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'):
+ incs += ' ' + env['BF_PTHREADS_INC']
+
+########################################################
+# folders sources
+########################################################
+
+# system
+prefix = 'intern/system'
+system_sources = env.Glob(prefix + '/*.cpp')
+
+# image
+prefix = 'intern/image'
+image_sources = env.Glob(prefix + '/*.cpp')
+
+# geometry
+prefix = 'intern/geometry'
+geometry_sources = env.Glob(prefix + '/*.cpp')
+
+# scene_graph
+prefix = 'intern/scene_graph'
+scene_graph_sources = env.Glob(prefix + '/*.cpp')
+
+# winged_edge
+prefix = 'intern/winged_edge'
+winged_edge_sources = env.Glob(prefix + '/*.cpp')
+
+# view_map
+prefix = 'intern/view_map'
+view_map_sources = env.Glob(prefix + '/*.cpp')
+
+# stroke
+prefix = 'intern/stroke'
+stroke_sources = env.Glob(prefix + '/*.cpp')
+
+# application
+prefix = 'intern/application'
+application_sources = env.Glob(prefix + '/*.cpp')
+
+# blender_interface
+prefix = 'intern/blender_interface'
+interface_sources = env.Glob(prefix + '/*.cpp')
+
+# Python
+prefix = 'intern/python'
+python_sources = env.Glob(prefix + '/*.cpp') + \
+ env.Glob(prefix + '/*/*.cpp') + \
+ env.Glob(prefix + '/*/*/*.cpp') + \
+ env.Glob(prefix + '/*/*/*/*.cpp')
+
+sources = system_sources + image_sources + geometry_sources + scene_graph_sources + \
+ winged_edge_sources + view_map_sources + stroke_sources + \
+ application_sources + interface_sources + python_sources
+
+env.BlenderLib(libname="bf_freestyle", sources=sources, includes=Split(incs),
+ defines=defs, libtype=['core'], priority = [370] # bf_python is 361
+)
diff --git a/source/blender/freestyle/intern/application/AppCanvas.cpp b/source/blender/freestyle/intern/application/AppCanvas.cpp
new file mode 100644
index 00000000000..06391717bb9
--- /dev/null
+++ b/source/blender/freestyle/intern/application/AppCanvas.cpp
@@ -0,0 +1,218 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/application/AppCanvas.cpp
+ * \ingroup freestyle
+ */
+
+#include "Controller.h"
+#include "AppView.h"
+#include "../image/Image.h"
+#include "../system/TimeStamp.h"
+#include "../stroke/StrokeRenderer.h"
+#include "AppCanvas.h"
+#include "AppConfig.h"
+#include "../stroke/StyleModule.h"
+
+#include "../system/StringUtils.h"
+
+AppCanvas::AppCanvas()
+:Canvas()
+{
+ _pViewer = 0;
+ _MapsPath = StringUtils::toAscii(Config::Path::getInstance()->getMapsDir()).c_str();
+}
+
+AppCanvas::AppCanvas(AppView* iViewer)
+:Canvas()
+{
+ _pViewer = iViewer;
+}
+
+AppCanvas::AppCanvas(const AppCanvas& iBrother)
+:Canvas(iBrother)
+{
+ _pViewer = iBrother._pViewer;
+}
+
+AppCanvas::~AppCanvas()
+{
+ _pViewer = 0;
+}
+
+void AppCanvas::setViewer(AppView *iViewer)
+{
+ _pViewer = iViewer;
+}
+
+int AppCanvas::width() const
+{
+ return _pViewer->width();
+}
+
+int AppCanvas::height() const
+{
+ return _pViewer->height();
+}
+
+BBox<Vec2i> AppCanvas::border() const
+{
+ return _pViewer->border();
+}
+
+float AppCanvas::thickness() const
+{
+ return _pViewer->thickness();
+}
+
+BBox<Vec3r> AppCanvas::scene3DBBox() const
+{
+ return _pViewer->scene3DBBox();
+}
+
+void AppCanvas::preDraw()
+{
+ Canvas::preDraw();
+}
+
+void AppCanvas::init()
+{
+#if 0
+ static bool firsttime = true;
+ if (firsttime) {
+ _Renderer = new BlenderStrokeRenderer;
+ if(!StrokeRenderer::loadTextures()) {
+ cerr << "unable to load stroke textures" << endl;
+ return;
+ }
+ }
+#endif
+}
+
+void AppCanvas::postDraw()
+{
+ for (unsigned int i = 0; i < _StyleModules.size(); i++) {
+ if(!_StyleModules[i]->getDisplayed() || !_Layers[i])
+ continue;
+ _Layers[i]->ScaleThickness(thickness());
+ }
+ Canvas::postDraw();
+}
+
+void AppCanvas::Erase()
+{
+ Canvas::Erase();
+}
+
+// Abstract
+
+void AppCanvas::readColorPixels(int x,int y,int w, int h, RGBImage& oImage) const
+{
+ float *rgb = new float[3*w*h];
+ memset(rgb, 0, sizeof(float) * 3 * w * h);
+ int xsch = width();
+ int ysch = height();
+ if (_pass_diffuse.buf) {
+ int xmin = border().getMin().x();
+ int ymin = border().getMin().y();
+ int xmax = border().getMax().x();
+ int ymax = border().getMax().y();
+ int rectx = _pass_z.width;
+ int recty = _pass_z.height;
+ float xfac = ((float)rectx) / ((float)(xmax - xmin));
+ float yfac = ((float)recty) / ((float)(ymax - ymin));
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("readColorPixels %d x %d @ (%d, %d) in %d x %d [%d x %d] -- %d x %d @ %d%%\n", w, h, x, y, xsch, ysch,
+ xmax - xmin, ymax - ymin, rectx, recty, (int)(xfac * 100.0f));
+ }
+#endif
+ int ii, jj;
+ for (int j = 0; j < h; j++) {
+ jj = (int)((y - ymin + j) * yfac);
+ if (jj < 0 || jj >= recty)
+ continue;
+ for (int i = 0; i < w; i++) {
+ ii = (int)((x - xmin + i) * xfac);
+ if (ii < 0 || ii >= rectx)
+ continue;
+ memcpy(rgb + (w * j + i) * 3, _pass_diffuse.buf + (rectx * jj + ii) * 3, sizeof(float) * 3);
+ }
+ }
+ }
+ oImage.setArray(rgb, xsch, ysch, w, h, x, y, false);
+}
+
+void AppCanvas::readDepthPixels(int x,int y,int w, int h, GrayImage& oImage) const
+{
+ float *z = new float[w*h];
+ memset(z, 0, sizeof(float) * w * h);
+ int xsch = width();
+ int ysch = height();
+ if (_pass_z.buf) {
+ int xmin = border().getMin().x();
+ int ymin = border().getMin().y();
+ int xmax = border().getMax().x();
+ int ymax = border().getMax().y();
+ int rectx = _pass_z.width;
+ int recty = _pass_z.height;
+ float xfac = ((float)rectx) / ((float)(xmax - xmin));
+ float yfac = ((float)recty) / ((float)(ymax - ymin));
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("readDepthPixels %d x %d @ (%d, %d) in %d x %d [%d x %d] -- %d x %d @ %d%%\n", w, h, x, y, xsch, ysch,
+ xmax - xmin, ymax - ymin, rectx, recty, (int)(xfac * 100.0f));
+ }
+#endif
+ int ii, jj;
+ for (int j = 0; j < h; j++) {
+ jj = (int)((y - ymin + j) * yfac);
+ if (jj < 0 || jj >= recty)
+ continue;
+ for (int i = 0; i < w; i++) {
+ ii = (int)((x - xmin + i) * xfac);
+ if (ii < 0 || ii >= rectx)
+ continue;
+ z[w * j + i] = _pass_z.buf[rectx * jj + ii];
+ }
+ }
+ }
+ oImage.setArray(z, xsch, ysch, w, h, x, y, false);
+}
+
+void AppCanvas::RenderStroke(Stroke *iStroke)
+{
+ if(_basic)
+ iStroke->RenderBasic(_Renderer);
+ else
+ iStroke->Render(_Renderer);
+}
+
+
+void AppCanvas::update()
+{
+}
diff --git a/source/blender/freestyle/intern/application/AppCanvas.h b/source/blender/freestyle/intern/application/AppCanvas.h
new file mode 100644
index 00000000000..3a65020463c
--- /dev/null
+++ b/source/blender/freestyle/intern/application/AppCanvas.h
@@ -0,0 +1,101 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __APPCANVAS_H__
+#define __APPCANVAS_H__
+
+/** \file blender/freestyle/intern/application/AppCanvas.h
+ * \ingroup freestyle
+ */
+
+#include "../stroke/Canvas.h"
+#include "AppView.h"
+
+class AppCanvas : public Canvas
+{
+public:
+ AppCanvas();
+ AppCanvas(AppView *iViewer);
+ AppCanvas(const AppCanvas& iBrother);
+ virtual ~AppCanvas();
+
+ /*! operations that need to be done before a draw */
+ virtual void preDraw();
+
+ /*! operations that need to be done after a draw */
+ virtual void postDraw();
+
+ /*! Erases the layers and clears the canvas */
+ virtual void Erase();
+
+ /* init the canvas */
+ virtual void init();
+
+ /*! Reads a pixel area from the canvas */
+ virtual void readColorPixels(int x,int y,int w, int h, RGBImage& oImage) const;
+ /*! Reads a depth pixel area from the canvas */
+ virtual void readDepthPixels(int x,int y,int w, int h, GrayImage& oImage) const;
+
+ virtual BBox<Vec3r> scene3DBBox() const;
+
+ /* abstract */
+ virtual void RenderStroke(Stroke*);
+ virtual void update();
+
+
+ /*! accessors */
+ virtual int width() const;
+ virtual int height() const;
+ virtual BBox<Vec2i> border() const;
+ virtual float thickness() const;
+
+ AppView *_pViewer;
+ inline const AppView * viewer() const {return _pViewer;}
+
+ /*! modifiers */
+ void setViewer(AppView *iViewer);
+
+ /* soc */
+ void setPassDiffuse(float *buf, int width, int height) {
+ _pass_diffuse.buf = buf;
+ _pass_diffuse.width = width;
+ _pass_diffuse.height = height;
+ }
+ void setPassZ(float *buf, int width, int height) {
+ _pass_z.buf = buf;
+ _pass_z.width = width;
+ _pass_z.height = height;
+ }
+
+private:
+ struct {
+ float *buf;
+ int width, height;
+ } _pass_diffuse, _pass_z;
+};
+
+#endif // __APPCANVAS_H__
diff --git a/source/blender/freestyle/intern/application/AppConfig.cpp b/source/blender/freestyle/intern/application/AppConfig.cpp
new file mode 100644
index 00000000000..f687117c762
--- /dev/null
+++ b/source/blender/freestyle/intern/application/AppConfig.cpp
@@ -0,0 +1,112 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/application/AppConfig.cpp
+ * \ingroup freestyle
+ */
+
+#include "AppConfig.h"
+#include <iostream>
+
+#include "../system/StringUtils.h"
+
+using namespace std;
+
+extern "C" {
+#include "BLI_path_util.h"
+}
+
+namespace Config {
+
+Path* Path::_pInstance = 0;
+Path::Path()
+{
+ // get the root directory
+ // soc
+ setRootDir(BLI_get_folder(BLENDER_SYSTEM_SCRIPTS, NULL));
+
+ _pInstance = this;
+}
+
+void Path::setRootDir(const string& iRootDir)
+{
+ _ProjectDir = iRootDir + string(DIR_SEP.c_str()) + "freestyle";
+ _ModelsPath = "";
+ _PatternsPath = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "textures" +
+ string(DIR_SEP.c_str()) + "variation_patterns" + string(DIR_SEP.c_str());
+ _BrushesPath = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "textures" +
+ string(DIR_SEP.c_str()) + "brushes" + string(DIR_SEP.c_str());
+ _PythonPath = _ProjectDir + string(DIR_SEP.c_str()) + "style_modules" + string(DIR_SEP.c_str());
+ if (getenv("PYTHONPATH")) {
+ _PythonPath += string(PATH_SEP.c_str()) + string(getenv("PYTHONPATH"));
+ }
+#ifdef WIN32
+ _BrowserCmd = "C:\\Program Files\\Internet Explorer\\iexplore.exe %s";
+#else
+ _BrowserCmd = "mozilla %s";
+#endif
+ _HelpIndexPath = _ProjectDir + string(DIR_SEP.c_str()) + "doc" + string(DIR_SEP.c_str()) + "html" +
+ string(DIR_SEP.c_str()) + "index.html";
+ _EnvMapDir = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "env_map" +
+ string(DIR_SEP.c_str());
+ _MapsDir = _ProjectDir + string(DIR_SEP.c_str()) + "data" + string(DIR_SEP.c_str()) + "maps" +
+ string(DIR_SEP.c_str());
+}
+
+void Path::setHomeDir(const string& iHomeDir)
+{
+ _HomeDir = iHomeDir;
+}
+
+Path::~Path()
+{
+ _pInstance = 0;
+}
+
+Path* Path::getInstance()
+{
+ return _pInstance;
+}
+
+string Path::getEnvVar(const string& iEnvVarName)
+{
+ string value;
+ if (!getenv(StringUtils::toAscii(iEnvVarName).c_str())) {
+ cerr << "Warning: You may want to set the $"
+ << StringUtils::toAscii(iEnvVarName)
+ << " environment variable to use Freestyle." << endl
+ << " Otherwise, the current directory will be used instead."
+ << endl;
+ value = ".";
+ }
+ else {
+ value = getenv(StringUtils::toAscii(iEnvVarName).c_str());
+ }
+ return value;
+}
+
+} // End of namepace Config
diff --git a/source/blender/freestyle/intern/application/AppConfig.h b/source/blender/freestyle/intern/application/AppConfig.h
new file mode 100644
index 00000000000..ebd6f85db70
--- /dev/null
+++ b/source/blender/freestyle/intern/application/AppConfig.h
@@ -0,0 +1,112 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __APP_CONFIG_H__
+#define __APP_CONFIG_H__
+
+/** \file blender/freestyle/intern/application/AppConfig.h
+ * \ingroup freestyle
+ * \brief Configuration file
+ * \author Emmanuel Turquin
+ * \date 26/02/2003
+ */
+
+#include <string>
+#include "../system/FreestyleConfig.h"
+#include "../system/Precision.h"
+
+using namespace std;
+
+namespace Config {
+
+class Path{
+protected:
+ static Path * _pInstance;
+ string _ProjectDir;
+ string _ModelsPath;
+ string _PatternsPath;
+ string _BrushesPath;
+ string _PythonPath;
+ string _BrowserCmd;
+ string _HelpIndexPath;
+ string _EnvMapDir;
+ string _MapsDir;
+ string _HomeDir;
+
+public:
+ Path();
+ virtual ~Path();
+ static Path* getInstance();
+
+ void setRootDir(const string& iRootDir);
+ void setHomeDir(const string& iHomeDir);
+
+ const string& getProjectDir() const {return _ProjectDir;}
+ const string& getModelsPath() const {return _ModelsPath;}
+ const string& getPatternsPath() const {return _PatternsPath;}
+ const string& getBrushesPath() const {return _BrushesPath;}
+ const string& getPythonPath() const {return _PythonPath;}
+ const string& getBrowserCmd() const {return _BrowserCmd;}
+ const string& getHelpIndexpath() const {return _HelpIndexPath;}
+ const string& getEnvMapDir() const {return _EnvMapDir;}
+ const string& getMapsDir() const {return _MapsDir;}
+ const string& getHomeDir() const {return _HomeDir;}
+
+ static string getEnvVar(const string& iEnvVarName);
+};
+
+//
+// Configuration, default values
+//
+//////////////////////////////////////////////////////////////
+
+// Application
+static const string APPLICATION_NAME("APPNAME");
+static const string APPLICATION_VERSION("APPVERSION");
+
+// ViewMap
+static const string VIEWMAP_EXTENSION("vm");
+static const string VIEWMAP_MAGIC("ViewMap File");
+static const string VIEWMAP_VERSION("1.9");
+
+// Style modules
+static const string STYLE_MODULE_EXTENSION("py");
+static const string STYLE_MODULES_LIST_EXTENSION("sml");
+
+// Options
+static const string OPTIONS_DIR("." + APPLICATION_NAME);
+static const string OPTIONS_FILE("options.xml");
+static const string OPTIONS_CURRENT_DIRS_FILE("current_dirs.xml");
+static const string OPTIONS_QGLVIEWER_FILE("qglviewer.xml");
+
+// Default options
+static const real DEFAULT_SPHERE_RADIUS = 1.0;
+static const real DEFAULT_DKR_EPSILON = 0.0;
+
+} // End of namepace Config
+
+#endif // __APP_CONFIG_H__
diff --git a/source/blender/freestyle/intern/application/AppView.cpp b/source/blender/freestyle/intern/application/AppView.cpp
new file mode 100644
index 00000000000..e09d958d564
--- /dev/null
+++ b/source/blender/freestyle/intern/application/AppView.cpp
@@ -0,0 +1,198 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/application/AppView.cpp
+ * \ingroup freestyle
+ */
+
+/* This header file needs to be included first, in order to avoid a
+ compilation with MinGW (see the commit log of revision 28253) */
+extern "C" {
+#include "BLI_jitter.h"
+}
+
+#include <iostream>
+
+#include "Controller.h"
+#include "AppConfig.h"
+#include "AppView.h"
+#include "../view_map/Silhouette.h"
+#include "../view_map/ViewMap.h"
+#include "../scene_graph/LineRep.h"
+#include "../scene_graph/NodeLight.h"
+#include "../scene_graph/NodeShape.h"
+#include "../scene_graph/VertexRep.h"
+#include "../stroke/Canvas.h"
+#include "../system/StringUtils.h"
+
+extern "C" {
+#include "BLI_blenlib.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#if 1 // FRS_antialiasing
+# include "BKE_global.h"
+# include "DNA_scene_types.h"
+#endif
+
+#include "FRS_freestyle.h"
+}
+
+AppView::AppView(const char *iName)
+{
+ _Fovy = DEG2RADF(30.0f);
+ _ModelRootNode = new NodeDrawingStyle;
+ _SilhouetteRootNode = new NodeDrawingStyle;
+ _DebugRootNode = new NodeDrawingStyle;
+
+ _RootNode.AddChild(_ModelRootNode);
+ _SilhouetteRootNode->setStyle(DrawingStyle::LINES);
+ _SilhouetteRootNode->setLightingEnabled(false);
+ _SilhouetteRootNode->setLineWidth(2.0f);
+ _SilhouetteRootNode->setPointSize(3.0f);
+
+ _RootNode.AddChild(_SilhouetteRootNode);
+
+ _DebugRootNode->setStyle(DrawingStyle::LINES);
+ _DebugRootNode->setLightingEnabled(false);
+ _DebugRootNode->setLineWidth(1.0f);
+
+ _RootNode.AddChild(_DebugRootNode);
+
+ _minBBox = __min(__min(_ModelRootNode->bbox().getMin()[0], _ModelRootNode->bbox().getMin()[1]),
+ _ModelRootNode->bbox().getMin()[2]);
+ _maxBBox = __max(__max(_ModelRootNode->bbox().getMax()[0], _ModelRootNode->bbox().getMax()[1]),
+ _ModelRootNode->bbox().getMax()[2]);
+
+ _maxAbs = __max(rabs(_minBBox), rabs(_maxBBox));
+ _minAbs = __min(rabs(_minBBox), rabs(_maxBBox));
+
+ _p2DSelectionNode = new NodeDrawingStyle;
+ _p2DSelectionNode->setLightingEnabled(false);
+ _p2DSelectionNode->setStyle(DrawingStyle::LINES);
+ _p2DSelectionNode->setLineWidth(5.0f);
+
+ _p2DNode.AddChild(_p2DSelectionNode);
+
+ NodeLight *light = new NodeLight;
+ _Light.AddChild(light);
+}
+
+AppView::~AppView()
+{
+ /*int ref =*/ /* UNUSED */ _RootNode.destroy();
+
+ _Light.destroy();
+ /*ref =*/ /* UNUSED */ _p2DNode.destroy();
+}
+
+real AppView::distanceToSceneCenter()
+{
+ BBox<Vec3r> bbox = _ModelRootNode->bbox();
+
+ Vec3r v(freestyle_viewpoint[0], freestyle_viewpoint[1], freestyle_viewpoint[2]);
+ v -= 0.5 * (bbox.getMin() + bbox.getMax());
+
+ return v.norm();
+}
+
+real AppView::znear()
+{
+ BBox<Vec3r> bbox = _ModelRootNode->bbox();
+ Vec3r u = bbox.getMin();
+ Vec3r v = bbox.getMax();
+ Vec3r cameraCenter(freestyle_viewpoint[0], freestyle_viewpoint[1], freestyle_viewpoint[2]);
+
+ Vec3r w1(u[0], u[1], u[2]);
+ Vec3r w2(v[0], u[1], u[2]);
+ Vec3r w3(u[0], v[1], u[2]);
+ Vec3r w4(v[0], v[1], u[2]);
+ Vec3r w5(u[0], u[1], v[2]);
+ Vec3r w6(v[0], u[1], v[2]);
+ Vec3r w7(u[0], v[1], v[2]);
+ Vec3r w8(v[0], v[1], v[2]);
+
+ real _znear = __min((w1 - cameraCenter).norm(),
+ __min((w2 - cameraCenter).norm(),
+ __min((w3 - cameraCenter).norm(),
+ __min((w4 - cameraCenter).norm(),
+ __min((w5 - cameraCenter).norm(),
+ __min((w6 - cameraCenter).norm(),
+ __min((w7 - cameraCenter).norm(),
+ (w8 - cameraCenter).norm()
+ )
+ )
+ )
+ )
+ )
+ )
+ );
+
+ return __max(_znear, 0.001);
+}
+
+real AppView::zfar()
+{
+ BBox<Vec3r> bbox = _ModelRootNode->bbox();
+ Vec3r u = bbox.getMin();
+ Vec3r v = bbox.getMax();
+ Vec3r cameraCenter(freestyle_viewpoint[0], freestyle_viewpoint[1], freestyle_viewpoint[2]);
+
+ Vec3r w1(u[0], u[1], u[2]);
+ Vec3r w2(v[0], u[1], u[2]);
+ Vec3r w3(u[0], v[1], u[2]);
+ Vec3r w4(v[0], v[1], u[2]);
+ Vec3r w5(u[0], u[1], v[2]);
+ Vec3r w6(v[0], u[1], v[2]);
+ Vec3r w7(u[0], v[1], v[2]);
+ Vec3r w8(v[0], v[1], v[2]);
+
+ real _zfar = __max((w1 - cameraCenter).norm(),
+ __max((w2 - cameraCenter).norm(),
+ __max((w3 - cameraCenter).norm(),
+ __max((w4 - cameraCenter).norm(),
+ __max((w5 - cameraCenter).norm(),
+ __max((w6 - cameraCenter).norm(),
+ __max((w7 - cameraCenter).norm(),
+ (w8 - cameraCenter).norm()
+ )
+ )
+ )
+ )
+ )
+ )
+ );
+
+ return _zfar;
+}
+
+real AppView::GetFocalLength()
+{
+ real Near = __max(0.1, (real)(-2.0f * _maxAbs + distanceToSceneCenter()));
+ return Near;
+}
diff --git a/source/blender/freestyle/intern/application/AppView.h b/source/blender/freestyle/intern/application/AppView.h
new file mode 100644
index 00000000000..0763a33a212
--- /dev/null
+++ b/source/blender/freestyle/intern/application/AppView.h
@@ -0,0 +1,245 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __APPVIEW_H__
+#define __APPVIEW_H__
+
+/** \file blender/freestyle/intern/application/AppView.h
+ * \ingroup freestyle
+ */
+
+#if !defined(WIN32) || defined(__GNUC__)
+# include <algorithm>
+# define __min(x,y) (min(x,y))
+# define __max(x,y) (max(x,y))
+ using namespace std;
+#endif // WIN32
+
+#include "AppConfig.h"
+#include "../geometry/Geom.h"
+#include "../geometry/BBox.h"
+#include "../scene_graph/NodeDrawingStyle.h"
+#include "../system/Precision.h"
+
+using namespace Geometry;
+
+class AppView
+{
+public:
+ AppView(const char *iName = 0);
+ virtual ~AppView();
+
+public:
+ //inherited
+ inline unsigned int width() {return _width;}
+ inline unsigned int height() {return _height;}
+ inline BBox<Vec2i> border() {return _border;}
+ inline float thickness() {return _thickness;}
+ inline void setWidth(unsigned int width) {_width = width;}
+ inline void setHeight(unsigned int height) {_height = height;}
+ inline void setBorder(int xmin, int ymin, int xmax, int ymax) {
+ _border = BBox<Vec2i>(Vec2i(xmin, ymin), Vec2i(xmax, ymax));
+ }
+ inline void setThickness(float thickness) {_thickness = thickness;}
+
+protected:
+ unsigned int _width, _height;
+ BBox<Vec2i> _border;
+ float _thickness;
+
+public:
+ /*! Sets the model to draw in the viewer
+ * iModel
+ * The Root Node of the model
+ */
+ inline void setModel(NodeGroup *iModel)
+ {
+ if (0 != _ModelRootNode->numberOfChildren()) {
+ _ModelRootNode->DetachChildren();
+ _ModelRootNode->clearBBox();
+ }
+
+ AddModel(iModel);
+ }
+
+ /*! Adds a model for displaying in the viewer */
+ inline void AddModel(NodeGroup *iModel)
+ {
+ _ModelRootNode->AddChild(iModel);
+ _ModelRootNode->UpdateBBox();
+
+ _minBBox = __min(__min(_ModelRootNode->bbox().getMin()[0], _ModelRootNode->bbox().getMin()[1]),
+ _ModelRootNode->bbox().getMin()[2]);
+ _maxBBox = __max(__max(_ModelRootNode->bbox().getMax()[0], _ModelRootNode->bbox().getMax()[1]),
+ _ModelRootNode->bbox().getMax()[2]);
+
+ _maxAbs = __max(rabs(_minBBox), rabs(_maxBBox));
+ _minAbs = __min(rabs(_minBBox), rabs(_maxBBox));
+ }
+
+ inline void AddSilhouette(NodeGroup* iSilhouette)
+ {
+ _SilhouetteRootNode->AddChild(iSilhouette);
+ }
+
+ inline void Add2DSilhouette(NodeGroup *iSilhouette)
+ {
+ //_pFENode->AddChild(iSilhouette);
+ }
+
+ inline void Add2DVisibleSilhouette(NodeGroup *iVSilhouette)
+ {
+ //_pVisibleSilhouetteNode->AddChild(iVSilhouette);
+ }
+
+ inline void setDebug(NodeGroup* iDebug)
+ {
+ if (0 != _DebugRootNode->numberOfChildren()) {
+ _DebugRootNode->DetachChildren();
+ _DebugRootNode->clearBBox();
+ }
+
+ AddDebug(iDebug);
+ }
+
+ inline void AddDebug(NodeGroup* iDebug)
+ {
+ _DebugRootNode->AddChild(iDebug);
+ }
+
+ inline void DetachModel(Node *iModel)
+ {
+ _ModelRootNode->DetachChild(iModel);
+ _ModelRootNode->UpdateBBox();
+
+ _minBBox = __min(__min(_ModelRootNode->bbox().getMin()[0], _ModelRootNode->bbox().getMin()[1]),
+ _ModelRootNode->bbox().getMin()[2]);
+ _maxBBox = __max(__max(_ModelRootNode->bbox().getMax()[0], _ModelRootNode->bbox().getMax()[1]),
+ _ModelRootNode->bbox().getMax()[2]);
+
+ _maxAbs = __max(rabs(_minBBox), rabs(_maxBBox));
+ _minAbs = __min(rabs(_minBBox), rabs(_maxBBox));
+ }
+
+ inline void DetachModel()
+ {
+ _ModelRootNode->DetachChildren();
+ _ModelRootNode->clearBBox();
+
+#if 0
+ // 2D Scene
+ _p2DNode.DetachChildren();
+ _pFENode->DetachChildren();
+ _pVisibleSilhouetteNode->DetachChildren();
+#endif
+ }
+
+ inline void DetachSilhouette()
+ {
+ _SilhouetteRootNode->DetachChildren();
+#if 0
+ _pFENode->DetachChildren();
+ _pVisibleSilhouetteNode->DetachChildren();
+#endif
+ _p2DSelectionNode->destroy();
+ }
+
+ inline void DetachVisibleSilhouette()
+ {
+ //_pVisibleSilhouetteNode->DetachChildren();
+ _p2DSelectionNode->destroy();
+ }
+
+ inline void DetachDebug()
+ {
+ _DebugRootNode->DetachChildren();
+ }
+
+ real distanceToSceneCenter();
+ real GetFocalLength();
+
+ inline real GetAspect() const
+ {
+ return ((real)_width / (real)_height);
+ }
+
+ void setHorizontalFov(float hfov)
+ {
+ _Fovy = 2.0 * atan (tan(hfov / 2.0) / GetAspect());
+ }
+
+ inline real GetFovyRadian() const
+ {
+ return _Fovy;
+ }
+
+ inline real GetFovyDegrees() const
+ {
+ return _Fovy * 180.0 / M_PI; // TODO Use RAD2DEG here too?
+ }
+
+ BBox<Vec3r> scene3DBBox() const {return _ModelRootNode->bbox();}
+
+ real znear();
+ real zfar();
+
+public:
+ /*! Core scene drawing */
+ void DrawScene(SceneVisitor *iRenderer);
+
+ /*! 2D Scene Drawing */
+ void Draw2DScene(SceneVisitor *iRenderer);
+
+protected:
+ /*! fabs or abs */
+ inline int rabs(int x) {return abs(x);}
+ inline real rabs(real x) {return fabs(x);}
+
+protected:
+ float _Fovy;
+
+ //The root node container
+ NodeGroup _RootNode;
+ NodeDrawingStyle *_ModelRootNode;
+ NodeDrawingStyle *_SilhouetteRootNode;
+ NodeDrawingStyle *_DebugRootNode;
+
+ NodeGroup _Light;
+
+ real _minBBox;
+ real _maxBBox;
+ real _maxAbs;
+ real _minAbs;
+
+ // 2D Scene
+ bool _Draw2DScene;
+ bool _Draw3DScene;
+ NodeGroup _p2DNode;
+ NodeDrawingStyle *_p2DSelectionNode;
+};
+
+#endif // __APPVIEW_H__
diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
new file mode 100644
index 00000000000..662686c2524
--- /dev/null
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -0,0 +1,1073 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/application/Controller.cpp
+ * \ingroup freestyle
+ */
+
+#include <string>
+#include <fstream>
+#include <float.h>
+
+#include "AppView.h"
+#include "AppCanvas.h"
+#include "AppConfig.h"
+#include "Controller.h"
+
+#include "../image/Image.h"
+
+#include "../scene_graph/NodeDrawingStyle.h"
+#include "../scene_graph/NodeShape.h"
+#include "../scene_graph/NodeTransform.h"
+#include "../scene_graph/ScenePrettyPrinter.h"
+#include "../scene_graph/VertexRep.h"
+
+#include "../stroke/PSStrokeRenderer.h"
+#include "../stroke/TextStrokeRenderer.h"
+#include "../stroke/StrokeTesselator.h"
+#include "../stroke/StyleModule.h"
+
+#include "../system/StringUtils.h"
+#include "../system/PythonInterpreter.h"
+
+#include "../view_map/SteerableViewMap.h"
+#include "../view_map/ViewMap.h"
+#include "../view_map/ViewMapIO.h"
+#include "../view_map/ViewMapTesselator.h"
+
+#include "../winged_edge/Curvature.h"
+#include "../winged_edge/WEdge.h"
+#include "../winged_edge/WingedEdgeBuilder.h"
+#include "../winged_edge/WXEdgeBuilder.h"
+
+#include "../blender_interface/BlenderFileLoader.h"
+#include "../blender_interface/BlenderStrokeRenderer.h"
+#include "../blender_interface/BlenderStyleModule.h"
+
+#include "BKE_global.h"
+
+// XXX Not inside an "extern C" block???
+#include "DNA_freestyle_types.h"
+
+// XXX Are those "ifdef __cplusplus" useful here?
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "FRS_freestyle.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+Controller::Controller()
+{
+ const string sep(Config::DIR_SEP.c_str());
+#if 0
+ const string filename = Config::Path::getInstance()->getHomeDir() + sep + Config::OPTIONS_DIR + sep +
+ Config::OPTIONS_CURRENT_DIRS_FILE;
+ _current_dirs = new ConfigIO(filename, Config::APPLICATION_NAME + "CurrentDirs", true);
+#endif
+
+ _RootNode = new NodeGroup;
+ _RootNode->addRef();
+
+ _SilhouetteNode = NULL;
+#if 0
+ _ProjectedSilhouette = NULL;
+ _VisibleProjectedSilhouette = NULL;
+#endif
+
+ _DebugNode = new NodeGroup;
+ _DebugNode->addRef();
+
+ _winged_edge = NULL;
+
+ _pView = NULL;
+ _pRenderMonitor = NULL;
+
+ _edgeTesselationNature = (Nature::SILHOUETTE | Nature::BORDER | Nature::CREASE);
+
+ _ProgressBar = new ProgressBar;
+ _SceneNumFaces = 0;
+ _minEdgeSize = DBL_MAX;
+ _EPSILON = 1.0e-6;
+ _bboxDiag = 0;
+
+ _ViewMap = 0;
+
+ _Canvas = 0;
+
+ _VisibilityAlgo = ViewMapBuilder::ray_casting_adaptive_traditional;
+ //_VisibilityAlgo = ViewMapBuilder::ray_casting;
+
+ _Canvas = new AppCanvas;
+
+ _inter = new PythonInterpreter();
+ _EnableQI = true;
+ _EnableFaceSmoothness = false;
+ _ComputeRidges = true;
+ _ComputeSteerableViewMap = false;
+ _ComputeSuggestive = true;
+ _ComputeMaterialBoundaries = true;
+ _sphereRadius = 1.0;
+ _creaseAngle = 134.43;
+
+ init_options();
+}
+
+Controller::~Controller()
+{
+ if (NULL != _RootNode) {
+ int ref = _RootNode->destroy();
+ if (0 == ref)
+ delete _RootNode;
+ }
+
+ if (NULL != _SilhouetteNode) {
+ int ref = _SilhouetteNode->destroy();
+ if (0 == ref)
+ delete _SilhouetteNode;
+ }
+
+ if (NULL != _DebugNode) {
+ int ref = _DebugNode->destroy();
+ if (0 == ref)
+ delete _DebugNode;
+ }
+
+ if (_winged_edge) {
+ delete _winged_edge;
+ _winged_edge = NULL;
+ }
+
+ if (0 != _ViewMap) {
+ delete _ViewMap;
+ _ViewMap = 0;
+ }
+
+ if (0 != _Canvas) {
+ delete _Canvas;
+ _Canvas = 0;
+ }
+
+ if (_inter) {
+ delete _inter;
+ _inter = NULL;
+ }
+
+ //delete _current_dirs;
+}
+
+void Controller::setView(AppView *iView)
+{
+ if(NULL == iView)
+ return;
+
+ _pView = iView;
+ _Canvas->setViewer(_pView);
+}
+
+void Controller::setRenderMonitor(RenderMonitor *iRenderMonitor)
+{
+ _pRenderMonitor = iRenderMonitor;
+}
+
+void Controller::setPassDiffuse(float *buf, int width, int height)
+{
+ AppCanvas *app_canvas = dynamic_cast<AppCanvas *>(_Canvas);
+ assert(app_canvas != 0);
+ app_canvas->setPassDiffuse(buf, width, height);
+}
+
+void Controller::setPassZ(float *buf, int width, int height)
+{
+ AppCanvas *app_canvas = dynamic_cast<AppCanvas *>(_Canvas);
+ assert(app_canvas != 0);
+ app_canvas->setPassZ(buf, width, height);
+}
+
+void Controller::setContext(bContext *C)
+{
+ PythonInterpreter* py_inter = dynamic_cast<PythonInterpreter*>(_inter);
+ assert(py_inter != 0);
+ py_inter->setContext(C);
+}
+
+int Controller::LoadMesh(Render *re, SceneRenderLayer* srl)
+{
+ BlenderFileLoader loader(re, srl);
+
+ loader.setRenderMonitor(_pRenderMonitor);
+
+ _Chrono.start();
+
+ NodeGroup *blenderScene = loader.Load();
+
+ if (blenderScene == NULL) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Cannot load scene" << endl;
+ }
+ return 1;
+ }
+
+ if (blenderScene->numberOfChildren() < 1) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Empty scene" << endl;
+ }
+ blenderScene->destroy();
+ delete blenderScene;
+ return 1;
+ }
+
+ real duration = _Chrono.stop();
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Scene loaded" << endl;
+ printf("Mesh cleaning : %lf\n", duration);
+ }
+ _SceneNumFaces += loader.numFacesRead();
+
+ if (loader.minEdgeSize() < _minEdgeSize) {
+ _minEdgeSize = loader.minEdgeSize();
+ }
+
+#if 0 // DEBUG
+ ScenePrettyPrinter spp;
+ blenderScene->accept(spp);
+#endif
+
+ _RootNode->AddChild(blenderScene);
+ _RootNode->UpdateBBox(); // FIXME: Correct that by making a Renderer to compute the bbox
+
+ _pView->setModel(_RootNode);
+ //_pView->FitBBox();
+
+ if (_pRenderMonitor->testBreak())
+ return 0;
+
+ _Chrono.start();
+
+ WXEdgeBuilder wx_builder;
+ wx_builder.setRenderMonitor(_pRenderMonitor);
+ blenderScene->accept(wx_builder);
+ _winged_edge = wx_builder.getWingedEdge();
+
+ duration = _Chrono.stop();
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("WEdge building : %lf\n", duration);
+ }
+
+#if 0
+ _pView->setDebug(_DebugNode);
+
+ // delete stuff
+ if (0 != ws_builder) {
+ delete ws_builder;
+ ws_builder = 0;
+ }
+
+ soc QFileInfo qfi(iFileName);
+ soc string basename((const char*)qfi.fileName().toAscii().data());
+ char cleaned[FILE_MAX];
+ BLI_strncpy(cleaned, iFileName, FILE_MAX);
+ BLI_cleanup_file(NULL, cleaned);
+ string basename = StringUtils::toAscii(string(cleaned));
+#endif
+
+ _ListOfModels.push_back("Blender_models");
+
+ _bboxDiag = (_RootNode->bbox().getMax()-_RootNode->bbox().getMin()).norm();
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Triangles nb : " << _SceneNumFaces << endl;
+ cout << "Bounding Box : " << _bboxDiag << endl;
+ }
+
+ ClearRootNode();
+
+ return 0;
+}
+
+void Controller::CloseFile()
+{
+ WShape::setCurrentId(0);
+ _ListOfModels.clear();
+
+ // We deallocate the memory:
+ ClearRootNode();
+ DeleteWingedEdge();
+ DeleteViewMap();
+
+ // clears the canvas
+ _Canvas->Clear();
+
+ // soc: reset passes
+ setPassDiffuse(NULL, 0, 0);
+ setPassZ(NULL, 0, 0);
+}
+
+void Controller::ClearRootNode()
+{
+ _pView->DetachModel();
+ if (NULL != _RootNode) {
+ int ref = _RootNode->destroy();
+ if (0 == ref)
+ _RootNode->addRef();
+ _RootNode->clearBBox();
+ }
+}
+
+void Controller::DeleteWingedEdge()
+{
+ if (_winged_edge) {
+ delete _winged_edge;
+ _winged_edge = NULL;
+ }
+
+ // clears the grid
+ _Grid.clear();
+ _SceneNumFaces = 0;
+ _minEdgeSize = DBL_MAX;
+}
+
+void Controller::DeleteViewMap()
+{
+ _pView->DetachSilhouette();
+ if (NULL != _SilhouetteNode) {
+ int ref = _SilhouetteNode->destroy();
+ if (0 == ref) {
+ delete _SilhouetteNode;
+ _SilhouetteNode = NULL;
+ }
+ }
+
+#if 0
+ if (NULL != _ProjectedSilhouette) {
+ int ref = _ProjectedSilhouette->destroy();
+ if (0 == ref) {
+ delete _ProjectedSilhouette;
+ _ProjectedSilhouette = NULL;
+ }
+ }
+ if (NULL != _VisibleProjectedSilhouette) {
+ int ref = _VisibleProjectedSilhouette->destroy();
+ if (0 == ref) {
+ delete _VisibleProjectedSilhouette;
+ _VisibleProjectedSilhouette = NULL;
+ }
+ }
+#endif
+
+ _pView->DetachDebug();
+ if (NULL != _DebugNode) {
+ int ref = _DebugNode->destroy();
+ if (0 == ref)
+ _DebugNode->addRef();
+ }
+
+ if (NULL != _ViewMap) {
+ delete _ViewMap;
+ _ViewMap = NULL;
+ }
+}
+
+void Controller::ComputeViewMap()
+{
+ if (!_ListOfModels.size())
+ return;
+
+ if (NULL != _ViewMap) {
+ delete _ViewMap;
+ _ViewMap = NULL;
+ }
+
+ _pView->DetachDebug();
+ if (NULL != _DebugNode) {
+ int ref = _DebugNode->destroy();
+ if (0 == ref)
+ _DebugNode->addRef();
+ }
+
+ _pView->DetachSilhouette();
+ if (NULL != _SilhouetteNode) {
+ int ref = _SilhouetteNode->destroy();
+ if (0 == ref)
+ delete _SilhouetteNode;
+ }
+
+#if 0
+ if (NULL != _ProjectedSilhouette) {
+ int ref = _ProjectedSilhouette->destroy();
+ if (0 == ref)
+ delete _ProjectedSilhouette;
+ }
+
+ if (NULL != _VisibleProjectedSilhouette) {
+ int ref = _VisibleProjectedSilhouette->destroy();
+ if (0 == ref) {
+ delete _VisibleProjectedSilhouette;
+ _VisibleProjectedSilhouette = NULL;
+ }
+ }
+#endif
+
+ // retrieve the 3D viewpoint and transformations information
+ //----------------------------------------------------------
+ // Save the viewpoint context at the view level in order
+ // to be able to restore it later:
+
+ // Restore the context of view:
+ // we need to perform all these operations while the
+ // 3D context is on.
+ Vec3r vp(freestyle_viewpoint[0], freestyle_viewpoint[1], freestyle_viewpoint[2]);
+
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "mv" << endl;
+ }
+#endif
+ real mv[4][4];
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ mv[i][j] = freestyle_mv[i][j];
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << mv[i][j] << " ";
+ }
+#endif
+ }
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << endl;
+ }
+#endif
+ }
+
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "\nproj" << endl;
+ }
+#endif
+ real proj[4][4];
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ proj[i][j] = freestyle_proj[i][j];
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << proj[i][j] << " ";
+ }
+#endif
+ }
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << endl;
+ }
+#endif
+ }
+
+ int viewport[4];
+ for (int i = 0; i < 4; i++)
+ viewport[i] = freestyle_viewport[i];
+
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "\nfocal:" << _pView->GetFocalLength() << endl << endl;
+ }
+#endif
+
+ // Flag the WXEdge structure for silhouette edge detection:
+ //----------------------------------------------------------
+
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "\n=== Detecting silhouette edges ===" << endl;
+ }
+ _Chrono.start();
+
+ edgeDetector.setViewpoint(Vec3r(vp));
+ edgeDetector.enableOrthographicProjection(proj[3][3] != 0.0);
+ edgeDetector.enableRidgesAndValleysFlag(_ComputeRidges);
+ edgeDetector.enableSuggestiveContours(_ComputeSuggestive);
+ edgeDetector.enableMaterialBoundaries(_ComputeMaterialBoundaries);
+ edgeDetector.enableFaceSmoothness(_EnableFaceSmoothness);
+ edgeDetector.setCreaseAngle(_creaseAngle);
+ edgeDetector.setSphereRadius(_sphereRadius);
+ edgeDetector.setSuggestiveContourKrDerivativeEpsilon(_suggestiveContourKrDerivativeEpsilon);
+ edgeDetector.setRenderMonitor(_pRenderMonitor);
+ edgeDetector.processShapes(*_winged_edge);
+
+ real duration = _Chrono.stop();
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("Feature lines : %lf\n", duration);
+ }
+
+ if (_pRenderMonitor->testBreak())
+ return;
+
+ // Builds the view map structure from the flagged WSEdge structure:
+ //----------------------------------------------------------
+ ViewMapBuilder vmBuilder;
+ vmBuilder.setEnableQI(_EnableQI);
+ vmBuilder.setViewpoint(Vec3r(vp));
+ vmBuilder.setTransform( mv, proj,viewport, _pView->GetFocalLength(), _pView->GetAspect(), _pView->GetFovyRadian());
+ vmBuilder.setFrustum(_pView->znear(), _pView->zfar());
+ vmBuilder.setGrid(&_Grid);
+ vmBuilder.setRenderMonitor(_pRenderMonitor);
+
+ // Builds a tesselated form of the silhouette for display purpose:
+ //---------------------------------------------------------------
+ ViewMapTesselator3D sTesselator3d;
+#if 0
+ ViewMapTesselator2D sTesselator2d;
+ sTesselator2d.setNature(_edgeTesselationNature);
+#endif
+ sTesselator3d.setNature(_edgeTesselationNature);
+
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "\n=== Building the view map ===" << endl;
+ }
+ _Chrono.start();
+ // Build View Map
+ _ViewMap = vmBuilder.BuildViewMap(*_winged_edge, _VisibilityAlgo, _EPSILON, _RootNode->bbox(), _SceneNumFaces);
+ _ViewMap->setScene3dBBox(_RootNode->bbox());
+
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("ViewMap edge count : %i\n", _ViewMap->viewedges_size());
+ }
+
+ // Tesselate the 3D edges:
+ _SilhouetteNode = sTesselator3d.Tesselate(_ViewMap);
+ _SilhouetteNode->addRef();
+
+ // Tesselate 2D edges
+#if 0
+ _ProjectedSilhouette = sTesselator2d.Tesselate(_ViewMap);
+ _ProjectedSilhouette->addRef();
+#endif
+
+ duration = _Chrono.stop();
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("ViewMap building : %lf\n", duration);
+ }
+
+ _pView->AddSilhouette(_SilhouetteNode);
+#if 0
+ _pView->AddSilhouette(_WRoot);
+ _pView->Add2DSilhouette(_ProjectedSilhouette);
+ _pView->Add2DVisibleSilhouette(_VisibleProjectedSilhouette);
+#endif
+ _pView->AddDebug(_DebugNode);
+
+ // Draw the steerable density map:
+ //--------------------------------
+ if (_ComputeSteerableViewMap) {
+ ComputeSteerableViewMap();
+ }
+ // Reset Style modules modification flags
+ resetModified(true);
+
+ DeleteWingedEdge();
+}
+
+void Controller::ComputeSteerableViewMap()
+{
+#if 0 //soc
+ if ((!_Canvas) || (!_ViewMap))
+ return;
+
+ // Build 4 nodes containing the edges in the 4 directions
+ NodeGroup *ng[Canvas::NB_STEERABLE_VIEWMAP];
+ unsigned i;
+ real c = 32.0f/255.0f; // see SteerableViewMap::readSteerableViewMapPixel() for information about this 32.
+ for (i = 0; i < Canvas::NB_STEERABLE_VIEWMAP; ++i) {
+ ng[i] = new NodeGroup;
+ }
+ NodeShape *completeNS = new NodeShape;
+ completeNS->material().setDiffuse(c,c,c,1);
+ ng[Canvas::NB_STEERABLE_VIEWMAP-1]->AddChild(completeNS);
+ SteerableViewMap * svm = _Canvas->getSteerableViewMap();
+ svm->Reset();
+
+ ViewMap::fedges_container& fedges = _ViewMap->FEdges();
+ LineRep * fRep;
+ NodeShape *ns;
+ for (ViewMap::fedges_container::iterator f = fedges.begin(), fend = fedges.end();
+ f != fend;
+ ++f)
+ {
+ if ((*f)->viewedge()->qi() != 0)
+ continue;
+ fRep = new LineRep((*f)->vertexA()->point2d(), (*f)->vertexB()->point2d());
+ completeNS->AddRep(fRep); // add to the complete map anyway
+ double *oweights = svm->AddFEdge(*f);
+ for (i = 0; i < (Canvas::NB_STEERABLE_VIEWMAP - 1); ++i) {
+ ns = new NodeShape;
+ double wc = oweights[i]*c;
+ if (oweights[i] == 0)
+ continue;
+ ns->material().setDiffuse(wc, wc, wc, 1);
+ ns->AddRep(fRep);
+ ng[i]->AddChild(ns);
+ }
+ }
+
+ GrayImage *img[Canvas::NB_STEERABLE_VIEWMAP];
+ //#ifdef WIN32
+ QGLBasicWidget offscreenBuffer(_pView, "SteerableViewMap", _pView->width(), _pView->height());
+ QPixmap pm;
+ QImage qimg;
+ for (i = 0; i < Canvas::NB_STEERABLE_VIEWMAP; ++i) {
+ offscreenBuffer.AddNode(ng[i]);
+#if 0
+ img[i] = new GrayImage(_pView->width(), _pView->height());
+ offscreenBuffer.readPixels(0,0,_pView->width(), _pView->height(), img[i]->getArray());
+#endif
+ pm = offscreenBuffer.renderPixmap(_pView->width(), _pView->height());
+
+ if (pm.isNull()) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "BuildViewMap Warning: couldn't render the steerable ViewMap" << endl;
+ }
+ }
+ //pm.save(QString("steerable") + QString::number(i) + QString(".bmp"), "BMP");
+ // FIXME!! Lost of time !
+ qimg = pm.toImage();
+ // FIXME !! again!
+ img[i] = new GrayImage(_pView->width(), _pView->height());
+ for (unsigned int y = 0; y < img[i]->height(); ++y) {
+ for(unsigned int x = 0; x < img[i]->width(); ++x) {
+ //img[i]->setPixel(x, y, (float)qGray(qimg.pixel(x, y)) / 255.0f);
+ img[i]->setPixel(x, y, (float)qGray(qimg.pixel(x, y)));
+ //float c = qGray(qimg.pixel(x, y));
+ //img[i]->setPixel(x, y, qGray(qimg.pixel(x, y)));
+ }
+ }
+ offscreenBuffer.DetachNode(ng[i]);
+ ng[i]->destroy();
+ delete ng[i];
+ // check
+#if 0
+ qimg = QImage(_pView->width(), _pView->height(), 32);
+ for (unsigned int y = 0; y < img[i]->height(); ++y) {
+ for(unsigned int x = 0; x < img[i]->width(); ++x) {
+ float v = img[i]->pixel(x, y);
+ qimg.setPixel(x, y, qRgb(v, v, v));
+ }
+ }
+ qimg.save(QString("newsteerable") + QString::number(i) + QString(".bmp"), "BMP");
+#endif
+ }
+
+
+ svm->buildImagesPyramids(img, false, 0, 1.0f);
+#endif
+}
+
+void Controller::saveSteerableViewMapImages()
+{
+ SteerableViewMap * svm = _Canvas->getSteerableViewMap();
+ if (!svm) {
+ cerr << "the Steerable ViewMap has not been computed yet" << endl;
+ return;
+ }
+ svm->saveSteerableViewMap();
+}
+
+void Controller::toggleVisibilityAlgo()
+{
+ if (_VisibilityAlgo == ViewMapBuilder::ray_casting) {
+ _VisibilityAlgo = ViewMapBuilder::ray_casting_fast;
+ }
+ else if (_VisibilityAlgo == ViewMapBuilder::ray_casting_fast) {
+ _VisibilityAlgo = ViewMapBuilder::ray_casting_very_fast;
+ }
+ else {
+ _VisibilityAlgo = ViewMapBuilder::ray_casting;
+ }
+}
+
+void Controller::setVisibilityAlgo(int algo)
+{
+ switch (algo) {
+ case FREESTYLE_ALGO_REGULAR:
+ _VisibilityAlgo = ViewMapBuilder::ray_casting;
+ break;
+ case FREESTYLE_ALGO_FAST:
+ _VisibilityAlgo = ViewMapBuilder::ray_casting_fast;
+ break;
+ case FREESTYLE_ALGO_VERYFAST:
+ _VisibilityAlgo = ViewMapBuilder::ray_casting_very_fast;
+ break;
+ case FREESTYLE_ALGO_CULLED_ADAPTIVE_TRADITIONAL:
+ _VisibilityAlgo = ViewMapBuilder::ray_casting_culled_adaptive_traditional;
+ break;
+ case FREESTYLE_ALGO_ADAPTIVE_TRADITIONAL:
+ _VisibilityAlgo = ViewMapBuilder::ray_casting_adaptive_traditional;
+ break;
+ case FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE:
+ _VisibilityAlgo = ViewMapBuilder::ray_casting_culled_adaptive_cumulative;
+ break;
+ case FREESTYLE_ALGO_ADAPTIVE_CUMULATIVE:
+ _VisibilityAlgo = ViewMapBuilder::ray_casting_adaptive_cumulative;
+ break;
+ }
+}
+
+int Controller::getVisibilityAlgo()
+{
+ switch (_VisibilityAlgo) {
+ case ViewMapBuilder::ray_casting:
+ return FREESTYLE_ALGO_REGULAR;
+ case ViewMapBuilder::ray_casting_fast:
+ return FREESTYLE_ALGO_FAST;
+ case ViewMapBuilder::ray_casting_very_fast:
+ return FREESTYLE_ALGO_VERYFAST;
+ case ViewMapBuilder::ray_casting_culled_adaptive_traditional:
+ return FREESTYLE_ALGO_CULLED_ADAPTIVE_TRADITIONAL;
+ case ViewMapBuilder::ray_casting_adaptive_traditional:
+ return FREESTYLE_ALGO_ADAPTIVE_TRADITIONAL;
+ case ViewMapBuilder::ray_casting_culled_adaptive_cumulative:
+ return FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE;
+ case ViewMapBuilder::ray_casting_adaptive_cumulative:
+ return FREESTYLE_ALGO_ADAPTIVE_CUMULATIVE;
+ }
+
+ // ray_casting_adaptive_traditional is the most exact replacement
+ // for legacy code
+ return FREESTYLE_ALGO_ADAPTIVE_TRADITIONAL;
+}
+
+void Controller::setQuantitativeInvisibility(bool iBool)
+{
+ _EnableQI = iBool;
+}
+
+bool Controller::getQuantitativeInvisibility() const
+{
+ return _EnableQI;
+}
+
+void Controller::setFaceSmoothness(bool iBool)
+{
+ _EnableFaceSmoothness = iBool;
+}
+
+bool Controller::getFaceSmoothness() const
+{
+ return _EnableFaceSmoothness;
+}
+
+void Controller::setComputeRidgesAndValleysFlag(bool iBool)
+{
+ _ComputeRidges = iBool;
+}
+
+bool Controller::getComputeRidgesAndValleysFlag() const
+{
+ return _ComputeRidges;
+}
+
+void Controller::setComputeSuggestiveContoursFlag(bool b)
+{
+ _ComputeSuggestive = b;
+}
+
+bool Controller::getComputeSuggestiveContoursFlag() const
+{
+ return _ComputeSuggestive;
+}
+
+void Controller::setComputeMaterialBoundariesFlag(bool b)
+{
+ _ComputeMaterialBoundaries = b;
+}
+
+bool Controller::getComputeMaterialBoundariesFlag() const
+{
+ return _ComputeMaterialBoundaries;
+}
+
+void Controller::setComputeSteerableViewMapFlag(bool iBool)
+{
+ _ComputeSteerableViewMap = iBool;
+}
+
+bool Controller::getComputeSteerableViewMapFlag() const
+{
+ return _ComputeSteerableViewMap;
+}
+
+void Controller::DrawStrokes()
+{
+ if (_ViewMap == 0)
+ return;
+
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "\n=== Stroke drawing ===" << endl;
+ }
+ _Chrono.start();
+ _Canvas->Draw();
+ real d = _Chrono.stop();
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Strokes generation : " << d << endl;
+ cout << "Stroke count : " << _Canvas->stroke_count << endl;
+ }
+ resetModified();
+ DeleteViewMap();
+}
+
+void Controller::ResetRenderCount()
+{
+ _render_count = 0;
+}
+
+Render* Controller::RenderStrokes(Render *re)
+{
+ _Chrono.start();
+ BlenderStrokeRenderer* blenderRenderer = new BlenderStrokeRenderer(re, ++_render_count);
+ _Canvas->Render(blenderRenderer);
+ real d = _Chrono.stop();
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Temporary scene generation: " << d << endl;
+ }
+ _Chrono.start();
+ Render* freestyle_render = blenderRenderer->RenderScene(re);
+ d = _Chrono.stop();
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Stroke rendering : " << d << endl;
+ }
+ delete blenderRenderer;
+
+ return freestyle_render;
+}
+
+void Controller::InsertStyleModule(unsigned index, const char *iFileName)
+{
+ if (!BLI_testextensie(iFileName, ".py")) {
+ cerr << "Error: Cannot load \"" << StringUtils::toAscii(string(iFileName))
+ << "\", unknown extension" << endl;
+ return;
+ }
+
+ StyleModule* sm = new StyleModule(iFileName, _inter);
+ _Canvas->InsertStyleModule(index, sm);
+}
+
+void Controller::InsertStyleModule(unsigned index, const char *iName, struct Text *iText)
+{
+ StyleModule* sm = new BlenderStyleModule(iText, iName, _inter);
+ _Canvas->InsertStyleModule(index, sm);
+}
+
+void Controller::AddStyleModule(const char *iFileName)
+{
+ //_pStyleWindow->Add(iFileName);
+}
+
+void Controller::RemoveStyleModule(unsigned index)
+{
+ _Canvas->RemoveStyleModule(index);
+}
+
+void Controller::Clear()
+{
+ _Canvas->Clear();
+}
+
+void Controller::ReloadStyleModule(unsigned index, const char * iFileName)
+{
+ StyleModule* sm = new StyleModule(iFileName, _inter);
+ _Canvas->ReplaceStyleModule(index, sm);
+}
+
+void Controller::SwapStyleModules(unsigned i1, unsigned i2)
+{
+ _Canvas->SwapStyleModules(i1, i2);
+}
+
+void Controller::toggleLayer(unsigned index, bool iDisplay)
+{
+ _Canvas->setVisible(index, iDisplay);
+}
+
+void Controller::setModified(unsigned index, bool iMod)
+{
+ //_pStyleWindow->setModified(index, iMod);
+ _Canvas->setModified(index, iMod);
+ updateCausalStyleModules(index + 1);
+}
+
+void Controller::updateCausalStyleModules(unsigned index)
+{
+ vector<unsigned> vec;
+ _Canvas->causalStyleModules(vec, index);
+ for (vector<unsigned>::const_iterator it = vec.begin(); it != vec.end(); it++) {
+ //_pStyleWindow->setModified(*it, true);
+ _Canvas->setModified(*it, true);
+ }
+}
+
+void Controller::resetModified(bool iMod)
+{
+ //_pStyleWindow->resetModified(iMod);
+ _Canvas->resetModified(iMod);
+}
+
+NodeGroup * Controller::BuildRep(vector<ViewEdge*>::iterator vedges_begin, vector<ViewEdge*>::iterator vedges_end)
+{
+ ViewMapTesselator2D tesselator2D;
+ FrsMaterial mat;
+ mat.setDiffuse(1, 1, 0.3, 1);
+ tesselator2D.setFrsMaterial(mat);
+
+ return (tesselator2D.Tesselate(vedges_begin, vedges_end));
+}
+
+void Controller::toggleEdgeTesselationNature(Nature::EdgeNature iNature)
+{
+ _edgeTesselationNature ^= (iNature);
+ ComputeViewMap();
+}
+
+void Controller::setModelsDir(const string& dir)
+{
+ //_current_dirs->setValue("models/dir", dir);
+}
+
+string Controller::getModelsDir() const
+{
+ string dir = ".";
+ //_current_dirs->getValue("models/dir", dir);
+ return dir;
+}
+
+void Controller::setModulesDir(const string& dir)
+{
+ //_current_dirs->setValue("modules/dir", dir);
+}
+
+string Controller::getModulesDir() const
+{
+ string dir = ".";
+ //_current_dirs->getValue("modules/dir", dir);
+ return dir;
+}
+
+void Controller::setHelpIndex(const string& index)
+{
+ _help_index = index;
+}
+
+string Controller::getHelpIndex() const
+{
+ return _help_index;
+}
+
+void Controller::setBrowserCmd(const string& cmd)
+{
+ _browser_cmd = cmd;
+}
+
+string Controller::getBrowserCmd() const
+{
+ return _browser_cmd;
+}
+
+void Controller::resetInterpreter()
+{
+ if (_inter)
+ _inter->reset();
+}
+
+
+void Controller::displayDensityCurves(int x, int y)
+{
+ SteerableViewMap * svm = _Canvas->getSteerableViewMap();
+ if (!svm)
+ return;
+
+ unsigned int i, j;
+ typedef vector<Vec3r> densityCurve;
+ vector<densityCurve> curves(svm->getNumberOfOrientations() + 1);
+ vector<densityCurve> curvesDirection(svm->getNumberOfPyramidLevels());
+
+ // collect the curves values
+ unsigned nbCurves = svm->getNumberOfOrientations() + 1;
+ unsigned nbPoints = svm->getNumberOfPyramidLevels();
+ if (!nbPoints)
+ return;
+
+ // build the density/nbLevels curves for each orientation
+ for (i = 0; i < nbCurves; ++i) {
+ for (j = 0; j < nbPoints; ++j) {
+ curves[i].push_back(Vec3r(j, svm->readSteerableViewMapPixel(i, j, x, y), 0));
+ }
+ }
+ // build the density/nbOrientations curves for each level
+ for (i = 0; i < nbPoints; ++i) {
+ for (j = 0; j < nbCurves; ++j) {
+ curvesDirection[i].push_back(Vec3r(j, svm->readSteerableViewMapPixel(j, i, x, y), 0));
+ }
+ }
+
+ // display the curves
+#if 0
+ for (i = 0; i < nbCurves; ++i)
+ _pDensityCurvesWindow->setOrientationCurve(i, Vec2d(0, 0), Vec2d(nbPoints, 1), curves[i], "scale", "density");
+ for (i = 1; i <= 8; ++i)
+ _pDensityCurvesWindow->setLevelCurve(i, Vec2d(0, 0), Vec2d(nbCurves, 1), curvesDirection[i],
+ "orientation", "density");
+ _pDensityCurvesWindow->show();
+#endif
+}
+
+void Controller::init_options()
+{
+ // from AppOptionsWindow.cpp
+ // Default init options
+
+ Config::Path * cpath = Config::Path::getInstance();
+
+ // Directories
+ ViewMapIO::Options::setModelsPath(StringUtils::toAscii(cpath->getModelsPath()));
+ PythonInterpreter::Options::setPythonPath(StringUtils::toAscii(cpath->getPythonPath()));
+ TextureManager::Options::setPatternsPath(StringUtils::toAscii(cpath->getPatternsPath()));
+ TextureManager::Options::setBrushesPath(StringUtils::toAscii(cpath->getModelsPath()));
+
+ // ViewMap Format
+ ViewMapIO::Options::rmFlags(ViewMapIO::Options::FLOAT_VECTORS);
+ ViewMapIO::Options::rmFlags(ViewMapIO::Options::NO_OCCLUDERS);
+ setComputeSteerableViewMapFlag(false);
+
+ // Visibility
+ setQuantitativeInvisibility(true);
+
+ // soc: initialize canvas
+ _Canvas->init();
+
+ // soc: initialize passes
+ setPassDiffuse(NULL, 0, 0);
+ setPassZ(NULL, 0, 0);
+}
diff --git a/source/blender/freestyle/intern/application/Controller.h b/source/blender/freestyle/intern/application/Controller.h
new file mode 100644
index 00000000000..475d9c6efd3
--- /dev/null
+++ b/source/blender/freestyle/intern/application/Controller.h
@@ -0,0 +1,261 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __CONTROLLER_H__
+#define __CONTROLLER_H__
+
+/** \file blender/freestyle/intern/application/Controller.h
+ * \ingroup freestyle
+ * \brief The spinal tap of the system.
+ * \author Stephane Grabli
+ * \date 01/07/2002
+ */
+
+#include <string>
+
+//#include "ConfigIO.h"
+#include "../geometry/FastGrid.h"
+#include "../system/Interpreter.h"
+#include "../system/ProgressBar.h"
+#include "../system/Precision.h"
+#include "../system/RenderMonitor.h"
+#include "../system/TimeUtils.h"
+#include "../view_map/FEdgeXDetector.h"
+#include "../view_map/ViewMapBuilder.h"
+
+class AppView;
+class NodeGroup;
+class WShape;
+class SShape;
+class ViewMap;
+class ViewEdge;
+class AppCanvas;
+class InteractiveShader;
+class Shader;
+class StrokeRenderer;
+
+// XXX Are those "ifdef __cplusplus" useful here?
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "render_types.h"
+#include "DNA_scene_types.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+class Controller
+{
+public:
+ Controller();
+ ~Controller();
+
+ void setView(AppView *iView);
+ void setRenderMonitor(RenderMonitor *iRenderMonitor);
+ void setPassDiffuse(float *buf, int width, int height);
+ void setPassZ(float *buf, int width, int height);
+ void setContext(bContext *C);
+
+ //soc
+ void init_options();
+
+ int LoadMesh(Render *re, SceneRenderLayer *srl);
+ int Load3DSFile(const char *iFileName);
+ void CloseFile();
+ void ComputeViewMap();
+ void ComputeSteerableViewMap();
+ void saveSteerableViewMapImages();
+ void toggleEdgeTesselationNature(Nature::EdgeNature iNature);
+ void DrawStrokes();
+ void ResetRenderCount();
+ Render *RenderStrokes(Render *re);
+ void SwapStyleModules(unsigned i1, unsigned i2);
+ void InsertStyleModule(unsigned index, const char *iFileName);
+ void InsertStyleModule(unsigned index, const char *iName, struct Text *iText);
+ void AddStyleModule(const char *iFileName);
+ void RemoveStyleModule(unsigned index);
+ void ReloadStyleModule(unsigned index, const char * iFileName);
+ void Clear();
+ void ClearRootNode();
+ void DeleteWingedEdge();
+ void DeleteViewMap();
+ void toggleLayer(unsigned index, bool iDisplay);
+ void setModified(unsigned index, bool iMod);
+ void resetModified(bool iMod=false);
+ void updateCausalStyleModules(unsigned index);
+ void displayDensityCurves(int x, int y);
+
+ ViewEdge *SelectViewEdge(real x, real y);
+ FEdge *SelectFEdge(real x, real y);
+ NodeGroup *BuildRep(vector<ViewEdge*>::iterator vedges_begin, vector<ViewEdge*>::iterator vedges_end) ;
+
+#if 0
+ NodeGroup *debugNode() {return _DebugNode;}
+ AppView *view() {return _pView;}
+ NodeGroup *debugScene() {return _DebugNode;}
+ Grid& grid() {return _Grid;}
+#endif
+
+ void toggleVisibilityAlgo();
+ void setVisibilityAlgo(int algo);
+ int getVisibilityAlgo();
+
+ void setQuantitativeInvisibility(bool iBool); // if true, we compute quantitativeInvisibility
+ bool getQuantitativeInvisibility() const;
+ void setFaceSmoothness(bool iBool);
+ bool getFaceSmoothness() const;
+
+ void setComputeRidgesAndValleysFlag(bool b);
+ bool getComputeRidgesAndValleysFlag() const;
+ void setComputeSuggestiveContoursFlag(bool b);
+ bool getComputeSuggestiveContoursFlag() const;
+ void setComputeMaterialBoundariesFlag(bool b);
+ bool getComputeMaterialBoundariesFlag() const;
+
+ void setComputeSteerableViewMapFlag(bool iBool);
+ bool getComputeSteerableViewMapFlag() const;
+ void setCreaseAngle(real angle) {_creaseAngle = angle;}
+ real getCreaseAngle() const {return _creaseAngle;}
+ void setSphereRadius(real s) {_sphereRadius = s;}
+ real getSphereRadius() const {return _sphereRadius;}
+ void setSuggestiveContourKrDerivativeEpsilon(real dkr) {_suggestiveContourKrDerivativeEpsilon = dkr;}
+ real getSuggestiveContourKrDerivativeEpsilon() const {return _suggestiveContourKrDerivativeEpsilon;}
+
+ void setModelsDir(const string& dir);
+ string getModelsDir() const;
+ void setModulesDir(const string& dir);
+ string getModulesDir() const;
+ void setHelpIndex(const string& dir);
+ string getHelpIndex() const;
+ void setBrowserCmd(const string& cmd);
+ string getBrowserCmd() const;
+
+ void resetInterpreter();
+
+public:
+ // Viewmap data structure
+ ViewMap *_ViewMap;
+
+ // Canvas
+ AppCanvas *_Canvas;
+
+private:
+ // Main Window:
+ //AppMainWindow *_pMainWindow;
+
+ // List of models currently loaded
+ vector<string> _ListOfModels;
+
+ // Current directories
+ //ConfigIO* _current_dirs;
+
+ //View
+ // 3D
+ AppView *_pView;
+
+ // 2D
+#if 0
+ Viewer2DWindow *_pView2DWindow;
+ Viewer2D *_pView2D;
+#endif
+
+ RenderMonitor *_pRenderMonitor;
+
+ //Model
+ // Drawing Structure
+ NodeGroup *_RootNode;
+
+ // Winged-Edge structure
+ WingedEdge *_winged_edge;
+
+ // Silhouette structure:
+#if 0
+ std::vector<SShape*> _SShapes;
+ NodeGroup *_SRoot;
+#endif
+
+ // Silhouette
+ NodeGroup *_SilhouetteNode;
+ NodeGroup *_ProjectedSilhouette;
+ NodeGroup *_VisibleProjectedSilhouette;
+
+ // more Debug info
+ NodeGroup *_DebugNode;
+
+ // debug
+ //NodeUser<ViewMap> *_ViewMapNode; // FIXME
+
+ // Chronometer:
+ Chronometer _Chrono;
+
+ // Progress Bar
+ ProgressBar *_ProgressBar;
+
+ // edges tesselation nature
+ int _edgeTesselationNature;
+
+ FastGrid _Grid;
+ //HashGrid _Grid;
+
+ unsigned int _SceneNumFaces;
+ real _minEdgeSize;
+ real _EPSILON;
+ real _bboxDiag;
+
+ int _render_count;
+
+ //AppStyleWindow *_pStyleWindow;
+ //AppOptionsWindow *_pOptionsWindow;
+ //AppDensityCurvesWindow *_pDensityCurvesWindow;
+
+ ViewMapBuilder::visibility_algo _VisibilityAlgo;
+
+ // Script Interpreter
+ Interpreter *_inter;
+
+ string _help_index;
+ string _browser_cmd;
+
+ bool _EnableQI;
+ bool _EnableFaceSmoothness;
+ bool _ComputeRidges;
+ bool _ComputeSuggestive;
+ bool _ComputeMaterialBoundaries;
+ real _creaseAngle;
+ real _sphereRadius;
+ real _suggestiveContourKrDerivativeEpsilon;
+
+ bool _ComputeSteerableViewMap;
+
+ FEdgeXDetector edgeDetector;
+};
+
+extern Controller *g_pController;
+
+#endif // __CONTROLLER_H__
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
new file mode 100644
index 00000000000..e9586e347a2
--- /dev/null
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -0,0 +1,766 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+ * \ingroup freestyle
+ */
+
+#include <assert.h>
+
+#include "BlenderFileLoader.h"
+
+#include "BKE_global.h"
+
+BlenderFileLoader::BlenderFileLoader(Render *re, SceneRenderLayer* srl)
+{
+ _re = re;
+ _srl = srl;
+ _Scene = NULL;
+ _numFacesRead = 0;
+ _minEdgeSize = DBL_MAX;
+ _smooth = (srl->freestyleConfig.flags & FREESTYLE_FACE_SMOOTHNESS_FLAG) != 0;
+}
+
+BlenderFileLoader::~BlenderFileLoader()
+{
+ _Scene = NULL;
+}
+
+NodeGroup* BlenderFileLoader::Load()
+{
+ ObjectInstanceRen *obi;
+
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "\n=== Importing triangular meshes into Blender ===" << endl;
+ }
+
+ // creation of the scene root node
+ _Scene = new NodeGroup;
+
+ _viewplane_left = _re->viewplane.xmin;
+ _viewplane_right = _re->viewplane.xmax;
+ _viewplane_bottom = _re->viewplane.ymin;
+ _viewplane_top = _re->viewplane.ymax;
+ _z_near = -_re->clipsta;
+ _z_far = -_re->clipend;
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Frustum: l " << _viewplane_left << " r " << _viewplane_right
+ << " b " << _viewplane_bottom << " t " << _viewplane_top
+ << " n " << _z_near << " f " << _z_far << endl;
+ }
+#endif
+
+ int id = 0;
+ for (obi = (ObjectInstanceRen *)_re->instancetable.first; obi; obi = obi->next) {
+ if (_pRenderMonitor && _pRenderMonitor->testBreak())
+ break;
+ if (!(obi->lay & _srl->lay))
+ continue;
+ char *name = obi->ob->id.name;
+ //cout << name[0] << name[1] << ":" << (name+2) <<;
+ //print_m4("obi->mat", obi->mat);
+
+ if (obi->obr->totvlak > 0) {
+ insertShapeNode(obi, ++id);
+ }
+ else if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Warning: " << (name + 2) << " is not a vlak-based object (ignored)" << endl;
+ }
+ }
+
+ // Return the built scene.
+ return _Scene;
+}
+
+#define CLIPPED_BY_NEAR -1
+#define NOT_CLIPPED 0
+#define CLIPPED_BY_FAR 1
+
+// check if each vertex of a triangle (V1, V2, V3) is clipped by the near/far plane
+// and calculate the number of triangles to be generated by clipping
+int BlenderFileLoader::countClippedFaces(float v1[3], float v2[3], float v3[3], int clip[3])
+{
+ float *v[3];
+ int numClipped, sum, numTris = 0;
+
+ v[0] = v1;
+ v[1] = v2;
+ v[2] = v3;
+ numClipped = sum = 0;
+ for (int i = 0; i < 3; i++) {
+ if (v[i][2] > _z_near) {
+ clip[i] = CLIPPED_BY_NEAR;
+ numClipped++;
+ }
+ else if (v[i][2] < _z_far) {
+ clip[i] = CLIPPED_BY_FAR;
+ numClipped++;
+ }
+ else {
+ clip[i] = NOT_CLIPPED;
+ }
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("%d %s\n", i, (clip[i] == NOT_CLIPPED) ? "not" : (clip[i] == CLIPPED_BY_NEAR) ? "near" : "far");
+ }
+#endif
+ sum += clip[i];
+ }
+ switch (numClipped) {
+ case 0:
+ numTris = 1; // triangle
+ break;
+ case 1:
+ numTris = 2; // tetragon
+ break;
+ case 2:
+ if (sum == 0)
+ numTris = 3; // pentagon
+ else
+ numTris = 1; // triangle
+ break;
+ case 3:
+ if (sum == 3 || sum == -3)
+ numTris = 0;
+ else
+ numTris = 2; // tetragon
+ break;
+ }
+ return numTris;
+}
+
+// find the intersection point C between the line segment from V1 to V2 and
+// a clipping plane at depth Z (i.e., the Z component of C is known, while
+// the X and Y components are unknown).
+void BlenderFileLoader::clipLine(float v1[3], float v2[3], float c[3], float z)
+{
+ // Order v1 and v2 by Z values to make sure that clipLine(P, Q, c, z)
+ // and clipLine(Q, P, c, z) gives exactly the same numerical result.
+ float *p, *q;
+ if (v1[2] < v2[2]) {
+ p = v1;
+ q = v2;
+ }
+ else {
+ p = v2;
+ q = v1;
+ }
+ double d[3];
+ for (int i = 0; i < 3; i++)
+ d[i] = q[i] - p[i];
+ double t = (z - p[2]) / d[2];
+ c[0] = p[0] + t * d[0];
+ c[1] = p[1] + t * d[1];
+ c[2] = z;
+}
+
+// clip the triangle (V1, V2, V3) by the near and far clipping plane and
+// obtain a set of vertices after the clipping. The number of vertices
+// is at most 5.
+void BlenderFileLoader::clipTriangle(int numTris, float triCoords[][3], float v1[3], float v2[3], float v3[3],
+ float triNormals[][3], float n1[3], float n2[3], float n3[3],
+ bool edgeMarks[], bool em1, bool em2, bool em3, int clip[3])
+{
+ float *v[3], *n[3];
+ bool em[3];
+ int i, j, k;
+
+ v[0] = v1; n[0] = n1;
+ v[1] = v2; n[1] = n2;
+ v[2] = v3; n[2] = n3;
+ em[0] = em1; /* edge mark of the edge between v1 and v2 */
+ em[1] = em2; /* edge mark of the edge between v2 and v3 */
+ em[2] = em3; /* edge mark of the edge between v3 and v1 */
+ k = 0;
+ for (i = 0; i < 3; i++) {
+ j = (i + 1) % 3;
+ if (clip[i] == NOT_CLIPPED) {
+ copy_v3_v3(triCoords[k], v[i]);
+ copy_v3_v3(triNormals[k], n[i]);
+ edgeMarks[k] = em[i];
+ k++;
+ if (clip[j] != NOT_CLIPPED) {
+ clipLine(v[i], v[j], triCoords[k], (clip[j] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
+ copy_v3_v3(triNormals[k], n[j]);
+ edgeMarks[k] = false;
+ k++;
+ }
+ }
+ else if (clip[i] != clip[j]) {
+ if (clip[j] == NOT_CLIPPED) {
+ clipLine(v[i], v[j], triCoords[k], (clip[i] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
+ copy_v3_v3(triNormals[k], n[i]);
+ edgeMarks[k] = em[i];
+ k++;
+ }
+ else {
+ clipLine(v[i], v[j], triCoords[k], (clip[i] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
+ copy_v3_v3(triNormals[k], n[i]);
+ edgeMarks[k] = em[i];
+ k++;
+ clipLine(v[i], v[j], triCoords[k], (clip[j] == CLIPPED_BY_NEAR) ? _z_near : _z_far);
+ copy_v3_v3(triNormals[k], n[j]);
+ edgeMarks[k] = false;
+ k++;
+ }
+ }
+ }
+ assert(k == 2 + numTris);
+}
+
+void BlenderFileLoader::addTriangle(struct LoaderState *ls, float v1[3], float v2[3], float v3[3],
+ float n1[3], float n2[3], float n3[3],
+ bool fm, bool em1, bool em2, bool em3)
+{
+ float *fv[3], *fn[3], len;
+ unsigned int i, j;
+ IndexedFaceSet::FaceEdgeMark marks = 0;
+
+ // initialize the bounding box by the first vertex
+ if (ls->currentIndex == 0) {
+ copy_v3_v3(ls->minBBox, v1);
+ copy_v3_v3(ls->maxBBox, v1);
+ }
+
+ fv[0] = v1; fn[0] = n1;
+ fv[1] = v2; fn[1] = n2;
+ fv[2] = v3; fn[2] = n3;
+ for (i = 0; i < 3; i++) {
+
+ copy_v3_v3(ls->pv, fv[i]);
+ copy_v3_v3(ls->pn, fn[i]);
+
+ // update the bounding box
+ for (j = 0; j < 3; j++) {
+ if (ls->minBBox[j] > ls->pv[j])
+ ls->minBBox[j] = ls->pv[j];
+
+ if (ls->maxBBox[j] < ls->pv[j])
+ ls->maxBBox[j] = ls->pv[j];
+ }
+
+ len = len_v3v3(fv[i], fv[(i + 1) % 3]);
+ if (_minEdgeSize > len)
+ _minEdgeSize = len;
+
+ *ls->pvi = ls->currentIndex;
+ *ls->pni = ls->currentIndex;
+ *ls->pmi = ls->currentMIndex;
+
+ ls->currentIndex += 3;
+ ls->pv += 3;
+ ls->pn += 3;
+
+ ls->pvi++;
+ ls->pni++;
+ ls->pmi++;
+ }
+
+ if (fm)
+ marks |= IndexedFaceSet::FACE_MARK;
+ if (em1)
+ marks |= IndexedFaceSet::EDGE_MARK_V1V2;
+ if (em2)
+ marks |= IndexedFaceSet::EDGE_MARK_V2V3;
+ if (em3)
+ marks |= IndexedFaceSet::EDGE_MARK_V3V1;
+ *(ls->pm++) = marks;
+}
+
+// With A, B and P indicating the three vertices of a given triangle, returns:
+// 1 if points A and B are in the same position in the 3D space;
+// 2 if the distance between point P and line segment AB is zero; and
+// zero otherwise.
+int BlenderFileLoader::testDegenerateTriangle(float v1[3], float v2[3], float v3[3])
+{
+#if 0
+ float area = area_tri_v3(v1, v2, v3);
+ bool verbose = (area < 1.0e-6);
+#endif
+
+ if (equals_v3v3(v1, v2) || equals_v3v3(v2, v3) || equals_v3v3(v1, v3)) {
+#if 0
+ if (verbose && G.debug & G_DEBUG_FREESTYLE) {
+ printf("BlenderFileLoader::testDegenerateTriangle = 1\n");
+ }
+#endif
+ return 1;
+ }
+ if (dist_to_line_segment_v3(v1, v2, v3) < 1.0e-6 ||
+ dist_to_line_segment_v3(v2, v1, v3) < 1.0e-6 ||
+ dist_to_line_segment_v3(v3, v1, v2) < 1.0e-6)
+ {
+#if 0
+ if (verbose && G.debug & G_DEBUG_FREESTYLE) {
+ printf("BlenderFileLoader::testDegenerateTriangle = 2\n");
+ }
+#endif
+ return 2;
+ }
+#if 0
+ if (verbose && G.debug & G_DEBUG_FREESTYLE) {
+ printf("BlenderFileLoader::testDegenerateTriangle = 0\n");
+ }
+#endif
+ return 0;
+}
+
+// Checks if edge rotation (if necessary) can prevent the given quad from
+// being decomposed into a degenerate triangle
+bool BlenderFileLoader::testEdgeRotation(float v1[3], float v2[3], float v3[3], float v4[3])
+{
+ if (testDegenerateTriangle(v1, v2, v3) == 2 || testDegenerateTriangle(v1, v3, v4) == 2) {
+ if (testDegenerateTriangle(v1, v2, v4) == 2 || testDegenerateTriangle(v2, v3, v4) == 2) {
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("BlenderFileLoader::testEdgeRotation: edge rotation is unsuccessful.\n");
+ }
+#endif
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
+{
+ ObjectRen *obr = obi->obr;
+ char *name = obi->ob->id.name + 2;
+
+ // We parse vlak nodes and count the number of faces after the clipping by
+ // the near and far view planes is applied (Note: mesh vertices are in the
+ // camera coordinate system).
+ VlakRen *vlr = NULL;
+ unsigned numFaces = 0;
+ float v1[3], v2[3], v3[3], v4[3];
+ float n1[3], n2[3], n3[3], n4[3], facenormal[3];
+ int clip_1[3], clip_2[3];
+ int wire_material = 0;
+ for (int a = 0; a < obr->totvlak; a++) {
+ if ((a & 255) == 0)
+ vlr = obr->vlaknodes[a>>8].vlak;
+ else
+ vlr++;
+ if (vlr->mat->material_type == MA_TYPE_WIRE) {
+ wire_material = 1;
+ continue;
+ }
+ copy_v3_v3(v1, vlr->v1->co);
+ copy_v3_v3(v2, vlr->v2->co);
+ copy_v3_v3(v3, vlr->v3->co);
+ if (vlr->v4)
+ copy_v3_v3(v4, vlr->v4->co);
+ if (obi->flag & R_TRANSFORMED) {
+ mul_m4_v3(obi->mat, v1);
+ mul_m4_v3(obi->mat, v2);
+ mul_m4_v3(obi->mat, v3);
+ if (vlr->v4)
+ mul_m4_v3(obi->mat, v4);
+ }
+#if 0
+ print_v3("v1", v1);
+ print_v3("v2", v2);
+ print_v3("v3", v3);
+ if (vlr->v4)
+ print_v3("v4", v4);
+#endif
+ if (!vlr->v4 || !testEdgeRotation(v1, v2, v3, v4)) {
+ numFaces += countClippedFaces(v1, v2, v3, clip_1);
+ if (vlr->v4)
+ numFaces += countClippedFaces(v1, v3, v4, clip_2);
+ }
+ else {
+ numFaces += countClippedFaces(v1, v2, v4, clip_1);
+ numFaces += countClippedFaces(v2, v3, v4, clip_2);
+ }
+ }
+ if (wire_material) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Warning: Object " << name << " has wire materials (ignored)" << endl;
+ }
+ }
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "numFaces " << numFaces << endl;
+ }
+#endif
+ if (numFaces == 0)
+ return;
+
+ // We allocate memory for the meshes to be imported
+ NodeTransform *currentMesh = new NodeTransform;
+ NodeShape *shape = new NodeShape;
+
+ unsigned vSize = 3 * 3 * numFaces;
+ float *vertices = new float[vSize];
+ unsigned nSize = vSize;
+ float *normals = new float[nSize];
+ unsigned *numVertexPerFaces = new unsigned[numFaces];
+ vector<FrsMaterial> meshFrsMaterials;
+
+ IndexedFaceSet::TRIANGLES_STYLE *faceStyle = new IndexedFaceSet::TRIANGLES_STYLE[numFaces];
+ unsigned i;
+ for (i = 0; i <numFaces; i++) {
+ faceStyle[i] = IndexedFaceSet::TRIANGLES;
+ numVertexPerFaces[i] = 3;
+ }
+
+ IndexedFaceSet::FaceEdgeMark *faceEdgeMarks = new IndexedFaceSet::FaceEdgeMark[numFaces];
+
+ unsigned viSize = 3 * numFaces;
+ unsigned *VIndices = new unsigned[viSize];
+ unsigned niSize = viSize;
+ unsigned *NIndices = new unsigned[niSize];
+ unsigned *MIndices = new unsigned[viSize]; // Material Indices
+
+ struct LoaderState ls;
+ ls.pv = vertices;
+ ls.pn = normals;
+ ls.pm = faceEdgeMarks;
+ ls.pvi = VIndices;
+ ls.pni = NIndices;
+ ls.pmi = MIndices;
+ ls.currentIndex = 0;
+ ls.currentMIndex = 0;
+
+ FrsMaterial tmpMat;
+
+ // We parse the vlak nodes again and import meshes while applying the clipping
+ // by the near and far view planes.
+ int p;
+ for (p = 0; p < obr->totvlak; ++p) { // we parse the faces of the mesh
+#if 0
+ Lib3dsFace *f = &mesh->faceL[p];
+ Lib3dsMaterial *mat = NULL;
+#endif
+ if ((p & 255) == 0)
+ vlr = obr->vlaknodes[p>>8].vlak;
+ else
+ vlr++;
+ copy_v3_v3(v1, vlr->v1->co);
+ copy_v3_v3(v2, vlr->v2->co);
+ copy_v3_v3(v3, vlr->v3->co);
+ if (vlr->v4)
+ copy_v3_v3(v4, vlr->v4->co);
+ if (obi->flag & R_TRANSFORMED) {
+ mul_m4_v3(obi->mat, v1);
+ mul_m4_v3(obi->mat, v2);
+ mul_m4_v3(obi->mat, v3);
+ if (vlr->v4)
+ mul_m4_v3(obi->mat, v4);
+ }
+ if (_smooth && (vlr->flag & R_SMOOTH)) {
+ copy_v3_v3(n1, vlr->v1->n);
+ copy_v3_v3(n2, vlr->v2->n);
+ copy_v3_v3(n3, vlr->v3->n);
+ if (vlr->v4)
+ copy_v3_v3(n4, vlr->v4->n);
+ if (obi->flag & R_TRANSFORMED) {
+ mul_m3_v3(obi->nmat, n1);
+ mul_m3_v3(obi->nmat, n2);
+ mul_m3_v3(obi->nmat, n3);
+ normalize_v3(n1);
+ normalize_v3(n2);
+ normalize_v3(n3);
+ if (vlr->v4) {
+ mul_m3_v3(obi->nmat, n4);
+ normalize_v3(n4);
+ }
+ }
+ }
+ else {
+ RE_vlakren_get_normal(_re, obi, vlr, facenormal);
+ copy_v3_v3(n1, facenormal);
+ copy_v3_v3(n2, facenormal);
+ copy_v3_v3(n3, facenormal);
+ if (vlr->v4)
+ copy_v3_v3(n4, facenormal);
+ }
+
+ unsigned int numTris_1, numTris_2;
+ bool edge_rotation;
+ if (!vlr->v4 || !testEdgeRotation(v1, v2, v3, v4)) {
+ numTris_1 = countClippedFaces(v1, v2, v3, clip_1);
+ numTris_2 = (!vlr->v4) ? 0 : countClippedFaces(v1, v3, v4, clip_2);
+ edge_rotation = false;
+ }
+ else {
+ numTris_1 = countClippedFaces(v1, v2, v4, clip_1);
+ numTris_2 = countClippedFaces(v2, v3, v4, clip_2);
+ edge_rotation = true;
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("BlenderFileLoader::insertShapeNode: edge rotation is performed.\n");
+ }
+ }
+ if (numTris_1 == 0 && numTris_2 == 0)
+ continue;
+ bool fm, em1, em2, em3, em4;
+ fm = (vlr->flag & ME_FREESTYLE_FACE) != 0;
+ em1 = (vlr->freestyle_edge_mark & R_EDGE_V1V2) != 0;
+ em2 = (vlr->freestyle_edge_mark & R_EDGE_V2V3) != 0;
+ if (!vlr->v4) {
+ em3 = (vlr->freestyle_edge_mark & R_EDGE_V3V1) != 0;
+ em4 = false;
+ }
+ else {
+ em3 = (vlr->freestyle_edge_mark & R_EDGE_V3V4) != 0;
+ em4 = (vlr->freestyle_edge_mark & R_EDGE_V4V1) != 0;
+ }
+
+ Material *mat = vlr->mat;
+ if (mat) {
+ tmpMat.setDiffuse(mat->r, mat->g, mat->b, mat->alpha);
+ tmpMat.setSpecular(mat->specr, mat->specg, mat->specb, mat->spectra);
+ float s = 1.0 * (mat->har + 1) / 4 ; // in Blender: [1;511] => in OpenGL: [0;128]
+ if (s > 128.f)
+ s = 128.f;
+ tmpMat.setShininess(s);
+ }
+
+ if (meshFrsMaterials.empty()) {
+ meshFrsMaterials.push_back(tmpMat);
+ shape->setFrsMaterial(tmpMat);
+ }
+ else {
+ // find if the material is aleady in the list
+ unsigned int i = 0;
+ bool found = false;
+
+ for (vector<FrsMaterial>::iterator it = meshFrsMaterials.begin(), itend = meshFrsMaterials.end();
+ it != itend;
+ it++, i++)
+ {
+ if (*it == tmpMat) {
+ ls.currentMIndex = i;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ meshFrsMaterials.push_back(tmpMat);
+ ls.currentMIndex = meshFrsMaterials.size() - 1;
+ }
+ }
+
+ float triCoords[5][3], triNormals[5][3];
+ bool edgeMarks[5]; // edgeMarks[i] is for the edge between i-th and (i+1)-th vertices
+
+ if (numTris_1 > 0) {
+ if (!edge_rotation) {
+ clipTriangle(numTris_1, triCoords, v1, v2, v3, triNormals, n1, n2, n3,
+ edgeMarks, em1, em2, (!vlr->v4) ? em3 : false, clip_1);
+ }
+ else {
+ clipTriangle(numTris_1, triCoords, v1, v2, v4, triNormals, n1, n2, n4,
+ edgeMarks, em1, false, em4, clip_1);
+ }
+ for (i = 0; i < numTris_1; i++) {
+ addTriangle(&ls, triCoords[0], triCoords[i+1], triCoords[i+2],
+ triNormals[0], triNormals[i+1], triNormals[i+2],
+ fm, (i == 0) ? edgeMarks[0] : false, edgeMarks[i+1],
+ (i == numTris_1 - 1) ? edgeMarks[i+2] : false);
+ _numFacesRead++;
+ }
+ }
+
+ if (numTris_2 > 0) {
+ if (!edge_rotation) {
+ clipTriangle(numTris_2, triCoords, v1, v3, v4, triNormals, n1, n3, n4,
+ edgeMarks, false, em3, em4, clip_2);
+ }
+ else {
+ clipTriangle(numTris_2, triCoords, v2, v3, v4, triNormals, n2, n3, n4,
+ edgeMarks, em2, em3, false, clip_2);
+ }
+ for (i = 0; i < numTris_2; i++) {
+ addTriangle(&ls, triCoords[0], triCoords[i+1], triCoords[i+2],
+ triNormals[0], triNormals[i+1], triNormals[i+2],
+ fm, (i == 0) ? edgeMarks[0] : false, edgeMarks[i+1],
+ (i == numTris_2 - 1) ? edgeMarks[i+2] : false);
+ _numFacesRead++;
+ }
+ }
+ }
+
+ // We might have several times the same vertex. We want a clean
+ // shape with no real-vertex. Here, we are making a cleaning pass.
+ real *cleanVertices = NULL;
+ unsigned int cvSize;
+ unsigned int *cleanVIndices = NULL;
+
+ GeomCleaner::CleanIndexedVertexArray(vertices, vSize, VIndices, viSize, &cleanVertices, &cvSize, &cleanVIndices);
+
+ real *cleanNormals = NULL;
+ unsigned int cnSize;
+ unsigned int *cleanNIndices = NULL;
+
+ GeomCleaner::CleanIndexedVertexArray(normals, nSize, NIndices, niSize, &cleanNormals, &cnSize, &cleanNIndices);
+
+ // format materials array
+ FrsMaterial** marray = new FrsMaterial*[meshFrsMaterials.size()];
+ unsigned int mindex = 0;
+ for (vector<FrsMaterial>::iterator m = meshFrsMaterials.begin(), mend = meshFrsMaterials.end();
+ m!=mend;
+ ++m)
+ {
+ marray[mindex] = new FrsMaterial(*m);
+ ++mindex;
+ }
+
+ // deallocates memory:
+ delete [] vertices;
+ delete [] normals;
+ delete [] VIndices;
+ delete [] NIndices;
+
+ // Fix for degenerated triangles
+ // A degenerate triangle is a triangle such that
+ // 1) A and B are in the same position in the 3D space; or
+ // 2) the distance between point P and line segment AB is zero.
+ // Only those degenerate triangles in the second form are resolved here
+ // by adding a small offset to P, whereas those in the first form are
+ // addressed later in WShape::MakeFace().
+ vector<detri_t> detriList;
+ Vec3r zero(0.0, 0.0, 0.0);
+ unsigned vi0, vi1, vi2;
+ for (i = 0; i < viSize; i += 3) {
+ detri_t detri;
+ vi0 = cleanVIndices[i];
+ vi1 = cleanVIndices[i+1];
+ vi2 = cleanVIndices[i+2];
+ Vec3r v0(cleanVertices[vi0], cleanVertices[vi0+1], cleanVertices[vi0+2]);
+ Vec3r v1(cleanVertices[vi1], cleanVertices[vi1+1], cleanVertices[vi1+2]);
+ Vec3r v2(cleanVertices[vi2], cleanVertices[vi2+1], cleanVertices[vi2+2]);
+ if (v0 == v1 || v0 == v2 || v1 == v2) {
+ continue; // do nothing for now
+ }
+ else if (GeomUtils::distPointSegment<Vec3r>(v0, v1, v2) < 1.0e-6) {
+ detri.viP = vi0;
+ detri.viA = vi1;
+ detri.viB = vi2;
+ }
+ else if (GeomUtils::distPointSegment<Vec3r>(v1, v0, v2) < 1.0e-6) {
+ detri.viP = vi1;
+ detri.viA = vi0;
+ detri.viB = vi2;
+ }
+ else if (GeomUtils::distPointSegment<Vec3r>(v2, v0, v1) < 1.0e-6) {
+ detri.viP = vi2;
+ detri.viA = vi0;
+ detri.viB = vi1;
+ }
+ else {
+ continue;
+ }
+
+ detri.v = zero;
+ detri.n = 0;
+ for (unsigned int j = 0; j < viSize; j += 3) {
+ if (i == j)
+ continue;
+ vi0 = cleanVIndices[j];
+ vi1 = cleanVIndices[j+1];
+ vi2 = cleanVIndices[j+2];
+ Vec3r v0(cleanVertices[vi0], cleanVertices[vi0+1], cleanVertices[vi0+2]);
+ Vec3r v1(cleanVertices[vi1], cleanVertices[vi1+1], cleanVertices[vi1+2]);
+ Vec3r v2(cleanVertices[vi2], cleanVertices[vi2+1], cleanVertices[vi2+2]);
+ if (detri.viP == vi0 && (detri.viA == vi1 || detri.viB == vi1)) {
+ detri.v += (v2 - v0);
+ detri.n++;
+ }
+ else if (detri.viP == vi0 && (detri.viA == vi2 || detri.viB == vi2)) {
+ detri.v += (v1 - v0);
+ detri.n++;
+ }
+ else if (detri.viP == vi1 && (detri.viA == vi0 || detri.viB == vi0)) {
+ detri.v += (v2 - v1);
+ detri.n++;
+ }
+ else if (detri.viP == vi1 && (detri.viA == vi2 || detri.viB == vi2)) {
+ detri.v += (v0 - v1);
+ detri.n++;
+ }
+ else if (detri.viP == vi2 && (detri.viA == vi0 || detri.viB == vi0)) {
+ detri.v += (v1 - v2);
+ detri.n++;
+ }
+ else if (detri.viP == vi2 && (detri.viA == vi1 || detri.viB == vi1)) {
+ detri.v += (v0 - v2);
+ detri.n++;
+ }
+ }
+ if (detri.n > 0) {
+ detri.v.normalizeSafe();
+ }
+ detriList.push_back(detri);
+ }
+
+ if (detriList.size() > 0) {
+ vector<detri_t>::iterator v;
+ for (v = detriList.begin(); v != detriList.end(); v++) {
+ detri_t detri = (*v);
+ if (detri.n == 0) {
+ cleanVertices[detri.viP] = cleanVertices[detri.viA];
+ cleanVertices[detri.viP+1] = cleanVertices[detri.viA+1];
+ cleanVertices[detri.viP+2] = cleanVertices[detri.viA+2];
+ }
+ else if (detri.v.norm() > 0.0) {
+ cleanVertices[detri.viP] += 1.0e-5 * detri.v.x();
+ cleanVertices[detri.viP+1] += 1.0e-5 * detri.v.y();
+ cleanVertices[detri.viP+2] += 1.0e-5 * detri.v.z();
+ }
+ }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("Warning: Object %s contains %lu degenerated triangle%s (strokes may be incorrect)\n",
+ name, detriList.size(), (detriList.size() > 1) ? "s" : "");
+ }
+ }
+
+ // Create the IndexedFaceSet with the retrieved attributes
+ IndexedFaceSet *rep;
+ rep = new IndexedFaceSet(cleanVertices, cvSize, cleanNormals, cnSize, marray, meshFrsMaterials.size(), 0, 0,
+ numFaces, numVertexPerFaces, faceStyle, faceEdgeMarks, cleanVIndices, viSize,
+ cleanNIndices, niSize, MIndices, viSize, 0, 0, 0);
+ // sets the id of the rep
+ rep->setId(Id(id, 0));
+ rep->setName(obi->ob->id.name + 2);
+
+ const BBox<Vec3r> bbox = BBox<Vec3r>(Vec3r(ls.minBBox[0], ls.minBBox[1], ls.minBBox[2]),
+ Vec3r(ls.maxBBox[0], ls.maxBBox[1], ls.maxBBox[2]));
+ rep->setBBox(bbox);
+ shape->AddRep(rep);
+
+ Matrix44r meshMat = Matrix44r::identity();
+ currentMesh->setMatrix(meshMat);
+ currentMesh->Translate(0, 0, 0);
+
+ currentMesh->AddChild(shape);
+ _Scene->AddChild(currentMesh);
+}
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
new file mode 100644
index 00000000000..316cf93a617
--- /dev/null
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.h
@@ -0,0 +1,138 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLENDER_FILE_LOADER_H__
+#define __BLENDER_FILE_LOADER_H__
+
+/** \file blender/freestyle/intern/blender_interface/BlenderFileLoader.h
+ * \ingroup freestyle
+ */
+
+#include <string.h>
+#include <float.h>
+
+#include "../geometry/BBox.h"
+#include "../geometry/Geom.h"
+#include "../geometry/GeomCleaner.h"
+#include "../geometry/GeomUtils.h"
+#include "../scene_graph/IndexedFaceSet.h"
+#include "../scene_graph/NodeGroup.h"
+#include "../scene_graph/NodeTransform.h"
+#include "../scene_graph/NodeShape.h"
+#include "../system/FreestyleConfig.h"
+#include "../system/RenderMonitor.h"
+
+// XXX Are those "ifdef __cplusplus" useful here?
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+
+#include "renderdatabase.h"
+#include "render_types.h"
+
+#include "BKE_mesh.h"
+#include "BKE_scene.h"
+
+#include "BLI_math.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+
+class NodeGroup;
+
+struct LoaderState {
+ float *pv;
+ float *pn;
+ IndexedFaceSet::FaceEdgeMark *pm;
+ unsigned *pvi;
+ unsigned *pni;
+ unsigned *pmi;
+ unsigned currentIndex;
+ unsigned currentMIndex;
+ float minBBox[3];
+ float maxBBox[3];
+};
+
+class LIB_SCENE_GRAPH_EXPORT BlenderFileLoader
+{
+public:
+ /*! Builds a MaxFileLoader */
+ BlenderFileLoader(Render *re, SceneRenderLayer* srl);
+ virtual ~BlenderFileLoader();
+
+ /*! Loads the 3D scene and returns a pointer to the scene root node */
+ NodeGroup * Load();
+
+ /*! Gets the number of read faces */
+ inline unsigned int numFacesRead() {return _numFacesRead;}
+
+ /*! Gets the smallest edge size read */
+ inline real minEdgeSize() {return _minEdgeSize;}
+
+ /*! Modifiers */
+ inline void setRenderMonitor(RenderMonitor *iRenderMonitor) {_pRenderMonitor = iRenderMonitor;}
+
+protected:
+ void insertShapeNode(ObjectInstanceRen *obi, int id);
+ int testDegenerateTriangle(float v1[3], float v2[3], float v3[3]);
+ bool testEdgeRotation(float v1[3], float v2[3], float v3[3], float v4[3]);
+ int countClippedFaces(float v1[3], float v2[3], float v3[3], int clip[3]);
+ void clipLine(float v1[3], float v2[3], float c[3], float z);
+ void clipTriangle(int numTris, float triCoords[][3], float v1[3], float v2[3], float v3[3],
+ float triNormals[][3], float n1[3], float n2[3], float n3[3],
+ bool edgeMarks[5], bool em1, bool em2, bool em3, int clip[3]);
+ void addTriangle(struct LoaderState *ls, float v1[3], float v2[3], float v3[3],
+ float n1[3], float n2[3], float n3[3], bool fm, bool em1, bool em2, bool em3);
+
+protected:
+ struct detri_t {
+ unsigned viA, viB, viP; // 0 <= viA, viB, viP < viSize
+ Vec3r v;
+ unsigned n;
+ };
+ Render *_re;
+ SceneRenderLayer *_srl;
+ NodeGroup *_Scene;
+ unsigned _numFacesRead;
+ real _minEdgeSize;
+ bool _smooth; /* if true, face smoothness is taken into account */
+ float _viewplane_left;
+ float _viewplane_right;
+ float _viewplane_bottom;
+ float _viewplane_top;
+ float _z_near, _z_far;
+
+ RenderMonitor *_pRenderMonitor;
+};
+
+#endif // __BLENDER_FILE_LOADER_H__
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
new file mode 100644
index 00000000000..ca4cbd35edc
--- /dev/null
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -0,0 +1,513 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+ * \ingroup freestyle
+ */
+
+#include "BlenderStrokeRenderer.h"
+#include "BlenderTextureManager.h"
+
+#include "../application/AppConfig.h"
+#include "../stroke/Canvas.h"
+
+#include "BKE_global.h"
+
+// XXX Are those "ifdef __cplusplus" useful here?
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_library.h" /* free_libblock */
+#include "BKE_main.h" /* struct Main */
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+
+#include "RE_pipeline.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+BlenderStrokeRenderer::BlenderStrokeRenderer(Render* re, int render_count) : StrokeRenderer()
+{
+ // TEMPORARY - need a texture manager
+ _textureManager = new BlenderTextureManager;
+ _textureManager->load();
+
+ // for stroke mesh generation
+ _width = re->winx;
+ _height = re->winy;
+
+ //Scene.New("FreestyleStrokes")
+ old_scene = re->scene;
+
+ char name[22];
+ BLI_snprintf(name, sizeof(name), "FRS%d_%s", render_count, re->scene->id.name + 2);
+ freestyle_scene = BKE_scene_add(G.main, name);
+ freestyle_scene->r.cfra = old_scene->r.cfra;
+ freestyle_scene->r.mode = old_scene->r.mode &
+ ~(R_EDGE_FRS | R_SHADOW | R_SSS | R_PANORAMA | R_ENVMAP | R_MBLUR | R_BORDER);
+ freestyle_scene->r.xsch = re->rectx; // old_scene->r.xsch
+ freestyle_scene->r.ysch = re->recty; // old_scene->r.ysch
+ freestyle_scene->r.xasp = 1.0f; // old_scene->r.xasp;
+ freestyle_scene->r.yasp = 1.0f; // old_scene->r.yasp;
+ freestyle_scene->r.tilex = old_scene->r.tilex;
+ freestyle_scene->r.tiley = old_scene->r.tiley;
+ freestyle_scene->r.size = 100; // old_scene->r.size
+ freestyle_scene->r.maximsize = old_scene->r.maximsize;
+ freestyle_scene->r.ocres = old_scene->r.ocres;
+ freestyle_scene->r.color_mgt_flag = 0; // old_scene->r.color_mgt_flag;
+ freestyle_scene->r.scemode = old_scene->r.scemode & ~(R_SINGLE_LAYER);
+ freestyle_scene->r.flag = old_scene->r.flag;
+ freestyle_scene->r.threads = old_scene->r.threads;
+ freestyle_scene->r.border.xmin = old_scene->r.border.xmin;
+ freestyle_scene->r.border.ymin = old_scene->r.border.ymin;
+ freestyle_scene->r.border.xmax = old_scene->r.border.xmax;
+ freestyle_scene->r.border.ymax = old_scene->r.border.ymax;
+ strcpy(freestyle_scene->r.pic, old_scene->r.pic);
+ freestyle_scene->r.safety.xmin = old_scene->r.safety.xmin;
+ freestyle_scene->r.safety.ymin = old_scene->r.safety.ymin;
+ freestyle_scene->r.safety.xmax = old_scene->r.safety.xmax;
+ freestyle_scene->r.safety.ymax = old_scene->r.safety.ymax;
+ freestyle_scene->r.osa = old_scene->r.osa;
+ freestyle_scene->r.filtertype = old_scene->r.filtertype;
+ freestyle_scene->r.gauss = old_scene->r.gauss;
+ freestyle_scene->r.dither_intensity = old_scene->r.dither_intensity;
+ BLI_strncpy(freestyle_scene->r.engine, old_scene->r.engine, sizeof(freestyle_scene->r.engine));
+ freestyle_scene->r.im_format.planes = R_IMF_PLANES_RGBA;
+ freestyle_scene->r.im_format.imtype = R_IMF_IMTYPE_PNG;
+ BKE_scene_disable_color_management(freestyle_scene);
+
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("%s: %d threads\n", __func__, freestyle_scene->r.threads);
+ }
+
+ // Render layer
+ SceneRenderLayer *srl = (SceneRenderLayer *)freestyle_scene->r.layers.first;
+ srl->layflag = SCE_LAY_SOLID | SCE_LAY_ZTRA;
+
+ BKE_scene_set_background(G.main, freestyle_scene);
+
+ // Camera
+ Object* object_camera = BKE_object_add(freestyle_scene, OB_CAMERA);
+
+ Camera* camera = (Camera *)object_camera->data;
+ camera->type = CAM_ORTHO;
+ camera->ortho_scale = max(re->rectx, re->recty);
+ camera->clipsta = 0.1f;
+ camera->clipend = 100.0f;
+
+ _z_delta = 0.00001f;
+ _z = camera->clipsta + _z_delta;
+
+ // test
+ //_z = 999.90f; _z_delta = 0.01f;
+
+ object_camera->loc[0] = re->disprect.xmin + 0.5f * re->rectx;
+ object_camera->loc[1] = re->disprect.ymin + 0.5f * re->recty;
+ object_camera->loc[2] = 1.0f;
+
+ freestyle_scene->camera = object_camera;
+
+ // Material
+ material = BKE_material_add("stroke_material");
+ material->mode |= MA_VERTEXCOLP;
+ material->mode |= MA_TRANSP;
+ material->mode |= MA_SHLESS;
+ material->vcol_alpha = 1;
+}
+
+BlenderStrokeRenderer::~BlenderStrokeRenderer()
+{
+ if (0 != _textureManager) {
+ delete _textureManager;
+ _textureManager = NULL;
+ }
+
+ // The freestyle_scene object is not released here. Instead,
+ // the scene is released in free_all_freestyle_renders() in
+ // source/blender/render/intern/source/pipeline.c, after the
+ // compositor has finished.
+
+ // release objects and data blocks
+ for (Base *b = (Base*)freestyle_scene->base.first; b; b = b->next) {
+ Object *ob = b->object;
+ void *data = ob->data;
+ char name[24];
+ strcpy(name, ob->id.name);
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "removing " << name[0] << name[1] << ":" << (name+2) << endl;
+ }
+#endif
+ switch (ob->type) {
+ case OB_MESH:
+ BKE_libblock_free(&G.main->object, ob);
+ BKE_libblock_free(&G.main->mesh, data);
+ break;
+ case OB_CAMERA:
+ BKE_libblock_free(&G.main->object, ob);
+ BKE_libblock_free(&G.main->camera, data);
+ freestyle_scene->camera = NULL;
+ break;
+ default:
+ cerr << "Warning: unexpected object in the scene: " << name[0] << name[1] << ":" << (name+2) << endl;
+ }
+ }
+ BLI_freelistN(&freestyle_scene->base);
+
+ // release material
+ BKE_libblock_free(&G.main->mat, material);
+
+ BKE_scene_set_background(G.main, old_scene);
+}
+
+float BlenderStrokeRenderer::get_stroke_vertex_z(void) const
+{
+ float z = _z;
+ BlenderStrokeRenderer *self = const_cast<BlenderStrokeRenderer *>(this);
+ if (!(_z < _z_delta * 100000.0f))
+ self->_z_delta *= 10.0f;
+ self->_z += _z_delta;
+ return -z;
+}
+
+void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
+{
+ RenderStrokeRepBasic(iStrokeRep);
+}
+
+void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
+{
+ ////////////////////
+ // Build up scene
+ ////////////////////
+
+ vector<Strip*>& strips = iStrokeRep->getStrips();
+ Strip::vertex_container::iterator v[3];
+ StrokeVertexRep *svRep[3];
+ /* Vec3r color[3]; */ /* UNUSED */
+ unsigned int vertex_index, edge_index, loop_index;
+ Vec2r p;
+
+ for (vector<Strip*>::iterator s = strips.begin(), send = strips.end();
+ s != send;
+ ++s){
+ Strip::vertex_container& strip_vertices = (*s)->vertices();
+ int strip_vertex_count = (*s)->sizeStrip();
+ int xl, xu, yl, yu, n, visible_faces, visible_segments;
+ bool visible;
+
+ // iterate over all vertices and count visible faces and strip segments
+ // (note: a strip segment is a series of visible faces, while two strip
+ // segments are separated by one or more invisible faces)
+ v[0] = strip_vertices.begin();
+ v[1] = v[0] + 1;
+ v[2] = v[0] + 2;
+ visible_faces = visible_segments = 0;
+ visible = false;
+ for (n = 2; n < strip_vertex_count; n++, v[0]++, v[1]++, v[2]++) {
+ svRep[0] = *(v[0]);
+ svRep[1] = *(v[1]);
+ svRep[2] = *(v[2]);
+ xl = xu = yl = yu = 0;
+ for (int j = 0; j < 3; j++) {
+ p = svRep[j]->point2d();
+ if (p[0] < 0.0)
+ xl++;
+ else if (p[0] > _width)
+ xu++;
+ if (p[1] < 0.0)
+ yl++;
+ else if (p[1] > _height)
+ yu++;
+ }
+ if (xl == 3 || xu == 3 || yl == 3 || yu == 3) {
+ visible = false;
+ }
+ else {
+ visible_faces++;
+ if (!visible)
+ visible_segments++;
+ visible = true;
+ }
+ }
+ if (visible_faces == 0)
+ continue;
+
+ //me = Mesh.New()
+#if 0
+ Object* object_mesh = BKE_object_add(freestyle_scene, OB_MESH);
+#else
+ Object* object_mesh = NewMesh();
+#endif
+ Mesh* mesh = (Mesh*)object_mesh->data;
+#if 0
+ MEM_freeN(mesh->bb);
+ mesh->bb = NULL;
+ mesh->id.us = 0;
+#endif
+#if 1
+ //me.materials = [mat]
+ mesh->mat = (Material**)MEM_mallocN(1 * sizeof(Material*), "MaterialList");
+ mesh->mat[0] = material;
+ mesh->totcol = 1;
+ test_object_materials((ID*)mesh);
+#else
+ assign_material(object_mesh, material, object_mesh->totcol + 1);
+ object_mesh->actcol = object_mesh->totcol;
+#endif
+
+ // vertices allocation
+ mesh->totvert = visible_faces + visible_segments * 2;
+ mesh->mvert = (MVert*)CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
+
+ // edges allocation
+ mesh->totedge = visible_faces * 2 + visible_segments;
+ mesh->medge = (MEdge*)CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
+
+ // faces allocation
+ mesh->totpoly = visible_faces;
+ mesh->mpoly = (MPoly*)CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
+
+ // loops allocation
+ mesh->totloop = visible_faces * 3;
+ mesh->mloop = (MLoop*)CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
+
+ // colors allocation
+ mesh->mloopcol = (MLoopCol*)CustomData_add_layer(&mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop);
+
+ ////////////////////
+ // Data copy
+ ////////////////////
+
+ MVert *vertices = mesh->mvert;
+ MEdge *edges = mesh->medge;
+ MPoly *polys = mesh->mpoly;
+ MLoop *loops = mesh->mloop;
+ MLoopCol *colors = mesh->mloopcol;
+
+ v[0] = strip_vertices.begin();
+ v[1] = v[0] + 1;
+ v[2] = v[0] + 2;
+
+ vertex_index = edge_index = loop_index = 0;
+ visible = false;
+
+ // Note: Mesh generation in the following loop assumes stroke strips
+ // to be triangle strips.
+ for (n = 2; n < strip_vertex_count; n++, v[0]++, v[1]++, v[2]++) {
+ svRep[0] = *(v[0]);
+ svRep[1] = *(v[1]);
+ svRep[2] = *(v[2]);
+ xl = xu = yl = yu = 0;
+ for (int j = 0; j < 3; j++) {
+ p = svRep[j]->point2d();
+ if (p[0] < 0.0)
+ xl++;
+ else if (p[0] > _width)
+ xu++;
+ if (p[1] < 0.0)
+ yl++;
+ else if (p[1] > _height)
+ yu++;
+ }
+ if (xl == 3 || xu == 3 || yl == 3 || yu == 3) {
+ visible = false;
+ }
+ else {
+ if (!visible) {
+ // first vertex
+ vertices->co[0] = svRep[0]->point2d()[0];
+ vertices->co[1] = svRep[0]->point2d()[1];
+ vertices->co[2] = get_stroke_vertex_z();
+ ++vertices;
+ ++vertex_index;
+
+ // second vertex
+ vertices->co[0] = svRep[1]->point2d()[0];
+ vertices->co[1] = svRep[1]->point2d()[1];
+ vertices->co[2] = get_stroke_vertex_z();
+ ++vertices;
+ ++vertex_index;
+
+ // first edge
+ edges->v1 = vertex_index - 2;
+ edges->v2 = vertex_index - 1;
+ ++edges;
+ ++edge_index;
+ }
+ visible = true;
+
+ // vertex
+ vertices->co[0] = svRep[2]->point2d()[0];
+ vertices->co[1] = svRep[2]->point2d()[1];
+ vertices->co[2] = get_stroke_vertex_z();
+ ++vertices;
+ ++vertex_index;
+
+ // edges
+ edges->v1 = vertex_index - 1;
+ edges->v2 = vertex_index - 3;
+ ++edges;
+ ++edge_index;
+
+ edges->v1 = vertex_index - 1;
+ edges->v2 = vertex_index - 2;
+ ++edges;
+ ++edge_index;
+
+ // poly
+ polys->loopstart = loop_index;
+ polys->totloop = 3;
+ ++polys;
+
+ // loops
+ if (n % 2 == 0) {
+ loops[0].v = vertex_index - 1;
+ loops[0].e = edge_index - 1;
+
+ loops[1].v = vertex_index - 2;
+ loops[1].e = edge_index - 3;
+
+ loops[2].v = vertex_index - 3;
+ loops[2].e = edge_index - 2;
+ }
+ else {
+ loops[0].v = vertex_index - 1;
+ loops[0].e = edge_index - 2;
+
+ loops[1].v = vertex_index - 3;
+ loops[1].e = edge_index - 3;
+
+ loops[2].v = vertex_index - 2;
+ loops[2].e = edge_index - 1;
+ }
+ loops += 3;
+ loop_index += 3;
+
+ // colors
+ if (n % 2 == 0) {
+ colors[0].r = (short)(255.0f * svRep[2]->color()[0]);
+ colors[0].g = (short)(255.0f * svRep[2]->color()[1]);
+ colors[0].b = (short)(255.0f * svRep[2]->color()[2]);
+ colors[0].a = (short)(255.0f * svRep[2]->alpha());
+
+ colors[1].r = (short)(255.0f * svRep[1]->color()[0]);
+ colors[1].g = (short)(255.0f * svRep[1]->color()[1]);
+ colors[1].b = (short)(255.0f * svRep[1]->color()[2]);
+ colors[1].a = (short)(255.0f * svRep[1]->alpha());
+
+ colors[2].r = (short)(255.0f * svRep[0]->color()[0]);
+ colors[2].g = (short)(255.0f * svRep[0]->color()[1]);
+ colors[2].b = (short)(255.0f * svRep[0]->color()[2]);
+ colors[2].a = (short)(255.0f * svRep[0]->alpha());
+ }
+ else {
+ colors[0].r = (short)(255.0f * svRep[2]->color()[0]);
+ colors[0].g = (short)(255.0f * svRep[2]->color()[1]);
+ colors[0].b = (short)(255.0f * svRep[2]->color()[2]);
+ colors[0].a = (short)(255.0f * svRep[2]->alpha());
+
+ colors[1].r = (short)(255.0f * svRep[0]->color()[0]);
+ colors[1].g = (short)(255.0f * svRep[0]->color()[1]);
+ colors[1].b = (short)(255.0f * svRep[0]->color()[2]);
+ colors[1].a = (short)(255.0f * svRep[0]->alpha());
+
+ colors[2].r = (short)(255.0f * svRep[1]->color()[0]);
+ colors[2].g = (short)(255.0f * svRep[1]->color()[1]);
+ colors[2].b = (short)(255.0f * svRep[1]->color()[2]);
+ colors[2].a = (short)(255.0f * svRep[1]->alpha());
+ }
+ colors += 3;
+ }
+ } // loop over strip vertices
+#if 0
+ BKE_mesh_validate(mesh, TRUE);
+#endif
+ } // loop over strips
+}
+
+// A replacement of BKE_object_add() for better performance.
+Object *BlenderStrokeRenderer::NewMesh() const
+{
+ Object *ob;
+ Base *base;
+ char name[MAX_ID_NAME];
+ static unsigned int mesh_id = 0xffffffff;
+
+ BLI_snprintf(name, MAX_ID_NAME, "0%08xOB", mesh_id);
+ ob = BKE_object_add_only_object(OB_MESH, name);
+ BLI_snprintf(name, MAX_ID_NAME, "0%08xME", mesh_id);
+ ob->data = BKE_mesh_add(name);
+ ob->lay = 1;
+
+ base = BKE_scene_base_add(freestyle_scene, ob);
+#if 0
+ BKE_scene_base_deselect_all(scene);
+ BKE_scene_base_select(scene, base);
+#else
+ (void)base;
+#endif
+ ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
+
+ --mesh_id;
+
+ return ob;
+}
+
+Render* BlenderStrokeRenderer::RenderScene(Render *re)
+{
+ Camera *camera = (Camera*)freestyle_scene->camera->data;
+ if (camera->clipend < _z)
+ camera->clipend = _z + _z_delta * 100.0f;
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "clipsta " << camera->clipsta << ", clipend " << camera->clipend << endl;
+ }
+#endif
+
+ Render *freestyle_render = RE_NewRender(freestyle_scene->id.name);
+
+ RE_RenderFreestyleStrokes(freestyle_render, G.main, freestyle_scene);
+ return freestyle_render;
+}
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
new file mode 100644
index 00000000000..89bb20b4bed
--- /dev/null
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
@@ -0,0 +1,76 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLENDER_STROKE_RENDERER_H__
+#define __BLENDER_STROKE_RENDERER_H__
+
+/** \file blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
+ * \ingroup freestyle
+ */
+
+#include "../stroke/StrokeRenderer.h"
+#include "../system/FreestyleConfig.h"
+
+// XXX Are those "ifdef __cplusplus" useful here?
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "DNA_material_types.h"
+#include "DNA_scene_types.h"
+
+#include "render_types.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+class LIB_STROKE_EXPORT BlenderStrokeRenderer : public StrokeRenderer
+{
+public:
+ BlenderStrokeRenderer(Render *re, int render_count);
+ virtual ~BlenderStrokeRenderer();
+
+ /*! Renders a stroke rep */
+ virtual void RenderStrokeRep(StrokeRep *iStrokeRep) const;
+ virtual void RenderStrokeRepBasic(StrokeRep *iStrokeRep) const;
+
+ Object *NewMesh() const;
+
+ Render *RenderScene(Render *re);
+
+protected:
+ Scene *old_scene;
+ Scene *freestyle_scene;
+ Material *material;
+ float _width, _height;
+ float _z, _z_delta;
+
+ float get_stroke_vertex_z(void) const;
+};
+
+#endif // __BLENDER_STROKE_RENDERER_H__
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h b/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
new file mode 100644
index 00000000000..4c6f7e02722
--- /dev/null
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
@@ -0,0 +1,70 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLENDERSTYLEMODULE_H__
+#define __BLENDERSTYLEMODULE_H__
+
+/** \file blender/freestyle/intern/blender_interface/BlenderStyleModule.h
+ * \ingroup freestyle
+ */
+
+#include "../stroke/StyleModule.h"
+#include "../system/PythonInterpreter.h"
+
+extern "C" {
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_text.h"
+}
+
+class BlenderStyleModule : public StyleModule
+{
+public:
+ BlenderStyleModule(struct Text *text, const string &name, Interpreter *inter) : StyleModule(name, inter)
+ {
+ _text = text;
+ }
+
+ virtual ~BlenderStyleModule()
+ {
+ BKE_text_unlink(G.main, _text);
+ BKE_libblock_free(&G.main->text, _text);
+ }
+
+protected:
+ virtual int interpret()
+ {
+ PythonInterpreter* py_inter = dynamic_cast<PythonInterpreter*>(_inter);
+ assert(py_inter != 0);
+ return py_inter->interpretText(_text, getFileName());
+ }
+
+private:
+ struct Text *_text;
+};
+
+#endif // __BLENDERSTYLEMODULE_H__
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderTextureManager.cpp b/source/blender/freestyle/intern/blender_interface/BlenderTextureManager.cpp
new file mode 100644
index 00000000000..aa8f8809cea
--- /dev/null
+++ b/source/blender/freestyle/intern/blender_interface/BlenderTextureManager.cpp
@@ -0,0 +1,104 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/blender_interface/BlenderTextureManager.cpp
+ * \ingroup freestyle
+ */
+
+#include "BlenderTextureManager.h"
+
+#include "BKE_global.h"
+
+BlenderTextureManager::BlenderTextureManager()
+: TextureManager()
+{
+ //_brushes_path = Config::getInstance()...
+}
+
+BlenderTextureManager::~BlenderTextureManager()
+{
+}
+
+void BlenderTextureManager::loadStandardBrushes()
+{
+#if 0
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/charcoalAlpha.bmp", Stroke::HUMID_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/washbrushAlpha.bmp", Stroke::HUMID_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/oil.bmp", Stroke::HUMID_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/oilnoblend.bmp", Stroke::HUMID_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/charcoalAlpha.bmp", Stroke::DRY_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/washbrushAlpha.bmp", Stroke::DRY_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/opaqueDryBrushAlpha.bmp", Stroke::OPAQUE_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/opaqueBrushAlpha.bmp", Stroke::OPAQUE_MEDIUM);
+ _defaultTextureId = getBrushTextureIndex("smoothAlpha.bmp", Stroke::OPAQUE_MEDIUM);
+#endif
+}
+
+unsigned int BlenderTextureManager::loadBrush(string sname, Stroke::MediumType mediumType)
+{
+#if 0
+ GLuint texId;
+ glGenTextures(1, &texId);
+ bool found = false;
+ vector<string> pathnames;
+ string path; //soc
+ StringUtils::getPathName(TextureManager::Options::getBrushesPath(), sname, pathnames);
+ for (vector<string>::const_iterator j = pathnames.begin(); j != pathnames.end(); j++) {
+ path = j->c_str();
+ //soc if (QFile::exists(path)) {
+ if (BLI_exists( const_cast<char *>(path.c_str()))) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ return 0;
+ // Brush texture
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Loading brush texture..." << endl;
+ }
+ switch (mediumType) {
+ case Stroke::DRY_MEDIUM:
+ //soc prepareTextureLuminance((const char*)path.toAscii(), texId);
+ prepareTextureLuminance(StringUtils::toAscii(path), texId);
+ break;
+ case Stroke::HUMID_MEDIUM:
+ case Stroke::OPAQUE_MEDIUM:
+ default:
+ //soc prepareTextureAlpha((const char*)path.toAscii(), texId);
+ prepareTextureAlpha(StringUtils::toAscii(path), texId);
+ break;
+ }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Done." << endl << endl;
+ }
+
+ return texId;
+#else
+ return 0;
+#endif
+}
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderTextureManager.h b/source/blender/freestyle/intern/blender_interface/BlenderTextureManager.h
new file mode 100644
index 00000000000..bd6f377b1eb
--- /dev/null
+++ b/source/blender/freestyle/intern/blender_interface/BlenderTextureManager.h
@@ -0,0 +1,53 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLENDERTEXTUREMANAGER_H__
+#define __BLENDERTEXTUREMANAGER_H__
+
+/** \file blender/freestyle/intern/blender_interface/BlenderTextureManager.h
+ * \ingroup freestyle
+ */
+
+# include "../stroke/StrokeRenderer.h"
+# include "../stroke/StrokeRep.h"
+# include "../system/FreestyleConfig.h"
+
+/*! Class to load textures */
+class LIB_RENDERING_EXPORT BlenderTextureManager : public TextureManager
+{
+public:
+ BlenderTextureManager();
+ virtual ~BlenderTextureManager();
+
+protected:
+ virtual unsigned int loadBrush(string fileName, Stroke::MediumType=Stroke::OPAQUE_MEDIUM);
+
+protected:
+ virtual void loadStandardBrushes();
+};
+
+#endif // __BLENDERTEXTUREMANAGER_H__
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
new file mode 100644
index 00000000000..97a84a284e0
--- /dev/null
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -0,0 +1,869 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+ * \ingroup freestyle
+ */
+
+#include <iostream>
+#include <map>
+#include <set>
+
+#include "../application/AppCanvas.h"
+#include "../application/AppConfig.h"
+#include "../application/AppView.h"
+#include "../application/Controller.h"
+
+#include "BKE_global.h"
+
+using namespace std;
+
+// XXX Are those "ifdef __cplusplus" useful here?
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_freestyle_types.h"
+#include "DNA_group_types.h"
+#include "DNA_text_types.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_linestyle.h"
+#include "BKE_main.h"
+#include "BKE_text.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+#include "BPY_extern.h"
+
+#include "renderpipeline.h"
+#include "pixelblending.h"
+
+#include "FRS_freestyle.h"
+#include "FRS_freestyle_config.h"
+
+#define DEFAULT_SPHERE_RADIUS 1.0f
+#define DEFAULT_DKR_EPSILON 0.0f
+
+// Freestyle configuration
+static short freestyle_is_initialized = 0;
+static Config::Path *pathconfig = NULL;
+static Controller *controller = NULL;
+static AppView *view = NULL;
+
+// line set buffer for copy & paste
+static FreestyleLineSet lineset_buffer;
+static bool lineset_copied = false;
+
+// camera information
+float freestyle_viewpoint[3];
+float freestyle_mv[4][4];
+float freestyle_proj[4][4];
+int freestyle_viewport[4];
+
+// current scene
+Scene *freestyle_scene;
+
+string default_module_path;
+
+//=======================================================
+// Initialization
+//=======================================================
+
+void FRS_initialize()
+{
+ if (freestyle_is_initialized)
+ return;
+
+ pathconfig = new Config::Path;
+ controller = new Controller();
+ view = new AppView;
+ controller->setView(view);
+ controller->Clear();
+ freestyle_scene = NULL;
+ lineset_copied = false;
+
+ default_module_path = pathconfig->getProjectDir() + Config::DIR_SEP + "style_modules" +
+ Config::DIR_SEP + "contour.py";
+
+ freestyle_is_initialized = 1;
+}
+
+void FRS_set_context(bContext *C)
+{
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "FRS_set_context: context 0x" << C << " scene 0x" << CTX_data_scene(C) << endl;
+ }
+ controller->setContext(C);
+}
+
+void FRS_read_file(bContext *C)
+{
+ lineset_copied = false;
+}
+
+void FRS_exit()
+{
+ delete pathconfig;
+ delete controller;
+ delete view;
+}
+
+//=======================================================
+// Rendering
+//=======================================================
+
+static void init_view(Render *re)
+{
+ int width = re->winx;
+ int height = re->winy;
+ int xmin = re->disprect.xmin;
+ int ymin = re->disprect.ymin;
+ int xmax = re->disprect.xmax;
+ int ymax = re->disprect.ymax;
+
+ float thickness = 1.0f;
+ switch (re->r.line_thickness_mode) {
+ case R_LINE_THICKNESS_ABSOLUTE:
+ thickness = re->r.unit_line_thickness * (re->r.size / 100.f);
+ break;
+ case R_LINE_THICKNESS_RELATIVE:
+ thickness = height / 480.f;
+ break;
+ }
+
+ freestyle_viewport[0] = freestyle_viewport[1] = 0;
+ freestyle_viewport[2] = width;
+ freestyle_viewport[3] = height;
+
+ view->setWidth(width);
+ view->setHeight(height);
+ view->setBorder(xmin, ymin, xmax, ymax);
+ view->setThickness(thickness);
+
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "\n=== Dimensions of the 2D image coordinate system ===" << endl;
+ cout << "Width : " << width << endl;
+ cout << "Height : " << height << endl;
+ if (re->r.mode & R_BORDER)
+ cout << "Border : (" << xmin << ", " << ymin << ") - (" << xmax << ", " << ymax << ")" << endl;
+ cout << "Unit line thickness : " << thickness << " pixel(s)" << endl;
+ }
+}
+
+static void init_camera(Render *re)
+{
+ // It is assumed that imported meshes are in the camera coordinate system.
+ // Therefore, the view point (i.e., camera position) is at the origin, and
+ // the the model-view matrix is simply the identity matrix.
+
+ freestyle_viewpoint[0] = 0.0;
+ freestyle_viewpoint[1] = 0.0;
+ freestyle_viewpoint[2] = 0.0;
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++)
+ freestyle_mv[i][j] = (i == j) ? 1.0 : 0.0;
+ }
+
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++)
+ freestyle_proj[i][j] = re->winmat[i][j];
+ }
+
+#if 0
+ print_m4("mv", freestyle_mv);
+ print_m4("proj", freestyle_proj);
+#endif
+}
+
+static char *escape_quotes(char *name)
+{
+ char *s = (char*)MEM_mallocN(strlen(name) * 2 + 1, "escape_quotes");
+ char *p = s;
+ while (*name) {
+ if (*name == '\'')
+ *(p++) = '\\';
+ *(p++) = *(name++);
+ }
+ *p = '\0';
+ return s;
+}
+
+static Text *create_lineset_handler(char *layer_name, char *lineset_name)
+{
+ char *s1 = escape_quotes(layer_name);
+ char *s2 = escape_quotes(lineset_name);
+ Text *text = BKE_text_add(lineset_name);
+ BKE_text_write(text, "import parameter_editor; parameter_editor.process('");
+ BKE_text_write(text, s1);
+ BKE_text_write(text, "', '");
+ BKE_text_write(text, s2);
+ BKE_text_write(text, "')\n");
+ MEM_freeN(s1);
+ MEM_freeN(s2);
+ return text;
+}
+
+struct edge_type_condition
+{
+ int edge_type, value;
+};
+
+// examines the conditions and returns true if the target edge type needs to be computed
+static bool test_edge_type_conditions(struct edge_type_condition *conditions,
+ int num_edge_types, bool logical_and, int target, bool distinct)
+{
+ int target_condition = 0;
+ int num_non_target_positive_conditions = 0;
+ int num_non_target_negative_conditions = 0;
+
+ for (int i = 0; i < num_edge_types; i++) {
+ if (conditions[i].edge_type == target)
+ target_condition = conditions[i].value;
+ else if (conditions[i].value > 0)
+ ++num_non_target_positive_conditions;
+ else if (conditions[i].value < 0)
+ ++num_non_target_negative_conditions;
+ }
+ if (distinct) {
+ // In this case, the 'target' edge type is assumed to appear on distinct edge
+ // of its own and never together with other edge types.
+ if (logical_and) {
+ if (num_non_target_positive_conditions > 0)
+ return false;
+ if (target_condition > 0)
+ return true;
+ if (target_condition < 0)
+ return false;
+ if (num_non_target_negative_conditions > 0)
+ return true;
+ }
+ else {
+ if (target_condition > 0)
+ return true;
+ if (num_non_target_negative_conditions > 0)
+ return true;
+ if (target_condition < 0)
+ return false;
+ if (num_non_target_positive_conditions > 0)
+ return false;
+ }
+ }
+ else {
+ // In this case, the 'target' edge type may appear together with other edge types.
+ if (target_condition > 0)
+ return true;
+ if (target_condition < 0)
+ return true;
+ if (logical_and) {
+ if (num_non_target_positive_conditions > 0)
+ return false;
+ if (num_non_target_negative_conditions > 0)
+ return true;
+ }
+ else {
+ if (num_non_target_negative_conditions > 0)
+ return true;
+ if (num_non_target_positive_conditions > 0)
+ return false;
+ }
+ }
+ return true;
+}
+
+static void prepare(Render *re, SceneRenderLayer *srl)
+{
+ // load mesh
+ re->i.infostr = "Freestyle: Mesh loading";
+ re->stats_draw(re->sdh, &re->i);
+ re->i.infostr = NULL;
+ if (controller->LoadMesh(re, srl)) // returns if scene cannot be loaded or if empty
+ return;
+ if (re->test_break(re->tbh))
+ return;
+
+ // add style modules
+ FreestyleConfig *config = &srl->freestyleConfig;
+
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "\n=== Rendering options ===" << endl;
+ }
+ int layer_count = 0;
+
+ switch (config->mode) {
+ case FREESTYLE_CONTROL_SCRIPT_MODE:
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Modules :" << endl;
+ }
+ for (FreestyleModuleConfig *module_conf = (FreestyleModuleConfig*)config->modules.first;
+ module_conf;
+ module_conf = module_conf->next)
+ {
+ if(module_conf->is_displayed) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << " " << layer_count+1 << ": " << module_conf->module_path << endl;
+ }
+ controller->InsertStyleModule(layer_count, module_conf->module_path);
+ controller->toggleLayer(layer_count, true);
+ layer_count++;
+ }
+ }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << endl;
+ }
+ controller->setComputeRidgesAndValleysFlag((config->flags & FREESTYLE_RIDGES_AND_VALLEYS_FLAG) ? true : false);
+ controller->setComputeSuggestiveContoursFlag((config->flags & FREESTYLE_SUGGESTIVE_CONTOURS_FLAG) ? true : false);
+ controller->setComputeMaterialBoundariesFlag((config->flags & FREESTYLE_MATERIAL_BOUNDARIES_FLAG) ? true : false);
+ break;
+ case FREESTYLE_CONTROL_EDITOR_MODE:
+ int use_ridges_and_valleys = 0;
+ int use_suggestive_contours = 0;
+ int use_material_boundaries = 0;
+ struct edge_type_condition conditions[] = {
+ {FREESTYLE_FE_SILHOUETTE, 0},
+ {FREESTYLE_FE_BORDER, 0},
+ {FREESTYLE_FE_CREASE, 0},
+ {FREESTYLE_FE_RIDGE_VALLEY, 0},
+ {FREESTYLE_FE_SUGGESTIVE_CONTOUR, 0},
+ {FREESTYLE_FE_MATERIAL_BOUNDARY, 0},
+ {FREESTYLE_FE_CONTOUR, 0},
+ {FREESTYLE_FE_EXTERNAL_CONTOUR, 0},
+ {FREESTYLE_FE_EDGE_MARK, 0}
+ };
+ int num_edge_types = sizeof(conditions) / sizeof(struct edge_type_condition);
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Linesets:" << endl;
+ }
+ for (FreestyleLineSet *lineset = (FreestyleLineSet*)config->linesets.first;
+ lineset;
+ lineset = lineset->next)
+ {
+ if (lineset->flags & FREESTYLE_LINESET_ENABLED) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << " " << layer_count+1 << ": " << lineset->name << " - "
+ << lineset->linestyle->id.name+2 << endl;
+ }
+ Text *text = create_lineset_handler(srl->name, lineset->name);
+ controller->InsertStyleModule(layer_count, lineset->name, text);
+ controller->toggleLayer(layer_count, true);
+ if (!(lineset->selection & FREESTYLE_SEL_EDGE_TYPES) || !lineset->edge_types) {
+ ++use_ridges_and_valleys;
+ ++use_suggestive_contours;
+ ++use_material_boundaries;
+ }
+ else {
+ // conditions for feature edge selection by edge types
+ for (int i = 0; i < num_edge_types; i++) {
+ if (!(lineset->edge_types & conditions[i].edge_type))
+ conditions[i].value = 0; // no condition specified
+ else if (!(lineset->exclude_edge_types & conditions[i].edge_type))
+ conditions[i].value = 1; // condition: X
+ else
+ conditions[i].value = -1; // condition: NOT X
+ }
+ // logical operator for the selection conditions
+ bool logical_and = ((lineset->flags & FREESTYLE_LINESET_FE_AND) != 0);
+ // negation operator
+ if (lineset->flags & FREESTYLE_LINESET_FE_NOT) {
+ // convert an Exclusive condition into an Inclusive equivalent using De Morgan's laws:
+ // NOT (X OR Y) --> (NOT X) AND (NOT Y)
+ // NOT (X AND Y) --> (NOT X) OR (NOT Y)
+ for (int i = 0; i < num_edge_types; i++)
+ conditions[i].value *= -1;
+ logical_and = !logical_and;
+ }
+ if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
+ FREESTYLE_FE_RIDGE_VALLEY, true))
+ {
+ ++use_ridges_and_valleys;
+ }
+ if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
+ FREESTYLE_FE_SUGGESTIVE_CONTOUR, true))
+ {
+ ++use_suggestive_contours;
+ }
+ if (test_edge_type_conditions(conditions, num_edge_types, logical_and,
+ FREESTYLE_FE_MATERIAL_BOUNDARY, true))
+ {
+ ++use_material_boundaries;
+ }
+ }
+ layer_count++;
+ }
+ }
+ controller->setComputeRidgesAndValleysFlag(use_ridges_and_valleys > 0);
+ controller->setComputeSuggestiveContoursFlag(use_suggestive_contours > 0);
+ controller->setComputeMaterialBoundariesFlag(use_material_boundaries > 0);
+ break;
+ }
+
+ // set parameters
+ if (config->flags & FREESTYLE_ADVANCED_OPTIONS_FLAG) {
+ controller->setSphereRadius(config->sphere_radius);
+ controller->setSuggestiveContourKrDerivativeEpsilon(config->dkr_epsilon);
+ }
+ else {
+ controller->setSphereRadius(DEFAULT_SPHERE_RADIUS);
+ controller->setSuggestiveContourKrDerivativeEpsilon(DEFAULT_DKR_EPSILON);
+ }
+ controller->setFaceSmoothness((config->flags & FREESTYLE_FACE_SMOOTHNESS_FLAG) ? true : false);
+ controller->setCreaseAngle(RAD2DEGF(config->crease_angle));
+ controller->setVisibilityAlgo((config->flags & FREESTYLE_CULLING) ?
+ FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE :
+ FREESTYLE_ALGO_ADAPTIVE_CUMULATIVE);
+
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Crease angle : " << controller->getCreaseAngle() << endl;
+ cout << "Sphere radius : " << controller->getSphereRadius() << endl;
+ cout << "Face smoothness : " << (controller->getFaceSmoothness() ? "enabled" : "disabled") << endl;
+ cout << "Redges and valleys : " << (controller->getComputeRidgesAndValleysFlag() ? "enabled" : "disabled")
+ << endl;
+ cout << "Suggestive contours : " << (controller->getComputeSuggestiveContoursFlag() ? "enabled" : "disabled")
+ << endl;
+ cout << "Suggestive contour Kr derivative epsilon : " << controller->getSuggestiveContourKrDerivativeEpsilon()
+ << endl;
+ cout << "Material boundaries : " << (controller->getComputeMaterialBoundariesFlag() ? "enabled" : "disabled")
+ << endl;
+ cout << endl;
+ }
+
+ // set diffuse and z depth passes
+ RenderLayer *rl = RE_GetRenderLayer(re->result, srl->name);
+ bool diffuse = false, z = false;
+ for (RenderPass *rpass = (RenderPass*)rl->passes.first; rpass; rpass = rpass->next) {
+ switch (rpass->passtype) {
+ case SCE_PASS_DIFFUSE:
+ controller->setPassDiffuse(rpass->rect, rpass->rectx, rpass->recty);
+ diffuse = true;
+ break;
+ case SCE_PASS_Z:
+ controller->setPassZ(rpass->rect, rpass->rectx, rpass->recty);
+ z = true;
+ break;
+ }
+ }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Passes :" << endl;
+ cout << " Diffuse = " << (diffuse ? "enabled" : "disabled") << endl;
+ cout << " Z = " << (z ? "enabled" : "disabled") << endl;
+ }
+
+ // compute view map
+ re->i.infostr = "Freestyle: View map creation";
+ re->stats_draw(re->sdh, &re->i);
+ re->i.infostr = NULL;
+ controller->ComputeViewMap();
+}
+
+void FRS_composite_result(Render* re, SceneRenderLayer* srl, Render* freestyle_render)
+{
+ RenderLayer *rl;
+ float *src, *dest, *pixSrc, *pixDest;
+ int x, y, rectx, recty;
+
+ if (freestyle_render == NULL || freestyle_render->result == NULL)
+ return;
+
+ rl = render_get_active_layer( freestyle_render, freestyle_render->result );
+ if (!rl || rl->rectf == NULL) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Cannot find Freestyle result image" << endl;
+ }
+ return;
+ }
+ src = rl->rectf;
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "src: " << rl->rectx << " x " << rl->recty << endl;
+ }
+#endif
+
+ rl = RE_GetRenderLayer(re->result, srl->name);
+ if (!rl || rl->rectf == NULL) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "No layer to composite to" << endl;
+ }
+ return;
+ }
+ dest = rl->rectf;
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "dest: " << rl->rectx << " x " << rl->recty << endl;
+ }
+#endif
+
+ rectx = re->rectx;
+ recty = re->recty;
+ for (y = 0; y < recty; y++) {
+ for (x = 0; x < rectx; x++) {
+ pixSrc = src + 4 * (rectx * y + x);
+ if (pixSrc[3] > 0.0) {
+ pixDest = dest + 4 * (rectx * y + x);
+ addAlphaOverFloat(pixDest, pixSrc);
+ }
+ }
+ }
+}
+
+static int displayed_layer_count(SceneRenderLayer *srl)
+{
+ int count = 0;
+
+ switch (srl->freestyleConfig.mode) {
+ case FREESTYLE_CONTROL_SCRIPT_MODE:
+ for (FreestyleModuleConfig *module = (FreestyleModuleConfig*)srl->freestyleConfig.modules.first;
+ module;
+ module = module->next)
+ {
+ if (module->is_displayed)
+ count++;
+ }
+ break;
+ case FREESTYLE_CONTROL_EDITOR_MODE:
+ for (FreestyleLineSet *lineset = (FreestyleLineSet*)srl->freestyleConfig.linesets.first;
+ lineset;
+ lineset = lineset->next)
+ {
+ if (lineset->flags & FREESTYLE_LINESET_ENABLED)
+ count++;
+ }
+ break;
+ }
+ return count;
+}
+
+int FRS_is_freestyle_enabled(SceneRenderLayer *srl)
+{
+ return (!(srl->layflag & SCE_LAY_DISABLE) && srl->layflag & SCE_LAY_FRS && displayed_layer_count(srl) > 0);
+}
+
+void FRS_init_stroke_rendering(Render *re)
+{
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << endl;
+ cout << "#===============================================================" << endl;
+ cout << "# Freestyle" << endl;
+ cout << "#===============================================================" << endl;
+ }
+
+ init_view(re);
+ init_camera(re);
+
+ controller->ResetRenderCount();
+}
+
+Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl)
+{
+ Render *freestyle_render = NULL;
+
+ RenderMonitor monitor(re);
+ controller->setRenderMonitor(&monitor);
+
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << endl;
+ cout << "----------------------------------------------------------" << endl;
+ cout << "| " << (re->scene->id.name + 2) << "|" << srl->name << endl;
+ cout << "----------------------------------------------------------" << endl;
+ }
+
+ // prepare Freestyle:
+ // - load mesh
+ // - add style modules
+ // - set parameters
+ // - compute view map
+ prepare(re, srl);
+
+ if (re->test_break(re->tbh)) {
+ controller->CloseFile();
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Break" << endl;
+ }
+ return NULL;
+ }
+
+ // render and composite Freestyle result
+ if (controller->_ViewMap) {
+ // render strokes
+ re->i.infostr = "Freestyle: Stroke rendering";
+ re->stats_draw(re->sdh, &re->i);
+ re->i.infostr = NULL;
+ freestyle_scene = re->scene;
+ controller->DrawStrokes();
+ freestyle_render = controller->RenderStrokes(re);
+ controller->CloseFile();
+ freestyle_scene = NULL;
+
+ // composite result
+ FRS_composite_result(re, srl, freestyle_render);
+ RE_FreeRenderResult(freestyle_render->result);
+ freestyle_render->result = NULL;
+ }
+
+ return freestyle_render;
+}
+
+void FRS_finish_stroke_rendering(Render *re) {
+ // clear canvas
+ controller->Clear();
+}
+
+//=======================================================
+// Freestyle Panel Configuration
+//=======================================================
+
+void FRS_add_freestyle_config(SceneRenderLayer *srl)
+{
+ FreestyleConfig *config = &srl->freestyleConfig;
+
+ config->mode = FREESTYLE_CONTROL_SCRIPT_MODE;
+
+ config->modules.first = config->modules.last = NULL;
+ config->flags = 0;
+ config->sphere_radius = DEFAULT_SPHERE_RADIUS;
+ config->dkr_epsilon = DEFAULT_DKR_EPSILON;
+ config->crease_angle = DEG2RADF(120.0f);
+
+ config->linesets.first = config->linesets.last = NULL;
+}
+
+void FRS_free_freestyle_config(SceneRenderLayer *srl)
+{
+ FreestyleLineSet *lineset;
+
+ for (lineset = (FreestyleLineSet*)srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ if (lineset->group) {
+ lineset->group->id.us--;
+ lineset->group = NULL;
+ }
+ lineset->linestyle->id.us--;
+ lineset->linestyle = NULL;
+ }
+ BLI_freelistN(&srl->freestyleConfig.linesets);
+ BLI_freelistN(&srl->freestyleConfig.modules);
+}
+
+void FRS_add_module(FreestyleConfig *config)
+{
+ FreestyleModuleConfig *module_conf = (FreestyleModuleConfig*)MEM_callocN(sizeof(FreestyleModuleConfig),
+ "style module configuration");
+ BLI_addtail(&config->modules, (void*)module_conf);
+
+ strcpy(module_conf->module_path, default_module_path.c_str());
+ module_conf->is_displayed = 1;
+}
+
+void FRS_delete_module(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
+{
+ BLI_freelinkN(&config->modules, module_conf);
+}
+
+void FRS_move_module_up(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
+{
+ BLI_remlink(&config->modules, module_conf);
+ BLI_insertlinkbefore(&config->modules, module_conf->prev, module_conf);
+}
+
+void FRS_move_module_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
+{
+ BLI_remlink(&config->modules, module_conf);
+ BLI_insertlinkafter(&config->modules, module_conf->next, module_conf);
+}
+
+static void unique_lineset_name(FreestyleConfig *config, FreestyleLineSet *lineset)
+{
+ BLI_uniquename(&config->linesets, lineset, "FreestyleLineSet", '.', offsetof(FreestyleLineSet, name),
+ sizeof(lineset->name));
+}
+
+FreestyleLineSet *FRS_add_lineset(FreestyleConfig *config)
+{
+ int lineset_index = BLI_countlist(&config->linesets);
+
+ FreestyleLineSet *lineset = (FreestyleLineSet*)MEM_callocN(sizeof(FreestyleLineSet), "Freestyle line set");
+ BLI_addtail(&config->linesets, (void*)lineset);
+ FRS_set_active_lineset_index(config, lineset_index);
+
+ lineset->linestyle = FRS_new_linestyle("LineStyle", NULL);
+ lineset->flags |= FREESTYLE_LINESET_ENABLED;
+ lineset->selection = FREESTYLE_SEL_IMAGE_BORDER;
+ lineset->qi = FREESTYLE_QI_VISIBLE;
+ lineset->qi_start = 0;
+ lineset->qi_end = 100;
+ lineset->edge_types = FREESTYLE_FE_SILHOUETTE | FREESTYLE_FE_BORDER | FREESTYLE_FE_CREASE;
+ lineset->exclude_edge_types = 0;
+ lineset->group = NULL;
+ if (lineset_index > 0)
+ sprintf(lineset->name, "LineSet %i", lineset_index + 1);
+ else
+ strcpy(lineset->name, "LineSet");
+ unique_lineset_name(config, lineset);
+
+ return lineset;
+}
+
+void FRS_copy_active_lineset(FreestyleConfig *config)
+{
+ FreestyleLineSet *lineset = FRS_get_active_lineset(config);
+
+ if (lineset) {
+ lineset_buffer.linestyle = lineset->linestyle;
+ lineset_buffer.flags = lineset->flags;
+ lineset_buffer.selection = lineset->selection;
+ lineset_buffer.qi = lineset->qi;
+ lineset_buffer.qi_start = lineset->qi_start;
+ lineset_buffer.qi_end = lineset->qi_end;
+ lineset_buffer.edge_types = lineset->edge_types;
+ lineset_buffer.exclude_edge_types = lineset->exclude_edge_types;
+ lineset_buffer.group = lineset->group;
+ strcpy(lineset_buffer.name, lineset->name);
+ lineset_copied = true;
+ }
+}
+
+void FRS_paste_active_lineset(FreestyleConfig *config)
+{
+ if (!lineset_copied)
+ return;
+
+ FreestyleLineSet *lineset = FRS_get_active_lineset(config);
+
+ if (lineset) {
+ lineset->linestyle->id.us--;
+ lineset->linestyle = lineset_buffer.linestyle;
+ lineset->linestyle->id.us++;
+ lineset->flags = lineset_buffer.flags;
+ lineset->selection = lineset_buffer.selection;
+ lineset->qi = lineset_buffer.qi;
+ lineset->qi_start = lineset_buffer.qi_start;
+ lineset->qi_end = lineset_buffer.qi_end;
+ lineset->edge_types = lineset_buffer.edge_types;
+ lineset->exclude_edge_types = lineset_buffer.exclude_edge_types;
+ if (lineset->group) {
+ lineset->group->id.us--;
+ lineset->group = NULL;
+ }
+ if (lineset_buffer.group) {
+ lineset->group = lineset_buffer.group;
+ lineset->group->id.us++;
+ }
+ strcpy(lineset->name, lineset_buffer.name);
+ unique_lineset_name(config, lineset);
+ lineset->flags |= FREESTYLE_LINESET_CURRENT;
+ }
+}
+
+void FRS_delete_active_lineset(FreestyleConfig *config)
+{
+ FreestyleLineSet *lineset = FRS_get_active_lineset(config);
+
+ if (lineset) {
+ if (lineset->group) {
+ lineset->group->id.us--;
+ lineset->group = NULL;
+ }
+ lineset->linestyle->id.us--;
+ lineset->linestyle = NULL;
+ BLI_remlink(&config->linesets, lineset);
+ MEM_freeN(lineset);
+ FRS_set_active_lineset_index(config, 0);
+ }
+}
+
+void FRS_move_active_lineset_up(FreestyleConfig *config)
+{
+ FreestyleLineSet *lineset = FRS_get_active_lineset(config);
+
+ if (lineset) {
+ BLI_remlink(&config->linesets, lineset);
+ BLI_insertlinkbefore(&config->linesets, lineset->prev, lineset);
+ }
+}
+
+void FRS_move_active_lineset_down(FreestyleConfig *config)
+{
+ FreestyleLineSet *lineset = FRS_get_active_lineset(config);
+
+ if (lineset) {
+ BLI_remlink(&config->linesets, lineset);
+ BLI_insertlinkafter(&config->linesets, lineset->next, lineset);
+ }
+}
+
+FreestyleLineSet *FRS_get_active_lineset(FreestyleConfig *config)
+{
+ FreestyleLineSet *lineset;
+
+ for (lineset = (FreestyleLineSet*)config->linesets.first; lineset; lineset = lineset->next) {
+ if (lineset->flags & FREESTYLE_LINESET_CURRENT)
+ return lineset;
+ }
+ return NULL;
+}
+
+short FRS_get_active_lineset_index(FreestyleConfig *config)
+{
+ FreestyleLineSet *lineset;
+ short i;
+
+ for (lineset = (FreestyleLineSet*)config->linesets.first, i = 0; lineset; lineset = lineset->next, i++) {
+ if (lineset->flags & FREESTYLE_LINESET_CURRENT)
+ return i;
+ }
+ return 0;
+}
+
+void FRS_set_active_lineset_index(FreestyleConfig *config, short index)
+{
+ FreestyleLineSet *lineset;
+ short i;
+
+ for (lineset = (FreestyleLineSet*)config->linesets.first, i = 0; lineset; lineset = lineset->next, i++) {
+ if (i == index)
+ lineset->flags |= FREESTYLE_LINESET_CURRENT;
+ else
+ lineset->flags &= ~FREESTYLE_LINESET_CURRENT;
+ }
+}
+
+void FRS_unlink_target_object(FreestyleConfig *config, Object *ob)
+{
+ FreestyleLineSet *lineset;
+
+ for (lineset = (FreestyleLineSet*)config->linesets.first; lineset; lineset = lineset->next) {
+ FRS_unlink_linestyle_target_object(lineset->linestyle, ob);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/source/blender/freestyle/intern/geometry/BBox.h b/source/blender/freestyle/intern/geometry/BBox.h
new file mode 100644
index 00000000000..b13960a4d2e
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/BBox.h
@@ -0,0 +1,154 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BBOX_H__
+#define __BBOX_H__
+
+/** \file blender/freestyle/intern/geometry/BBox.h
+ * \ingroup freestyle
+ * \brief A class to hold a bounding box
+ * \author Stephane Grabli
+ * \date 22/05/2003
+ */
+
+template <class Point>
+class BBox
+{
+public:
+ inline BBox()
+ {
+ _empty = true;
+ }
+
+ template <class T>
+ inline BBox(const T& min_in, const T& max_in) : _min(min_in), _max(max_in)
+ {
+ _empty = false;
+ }
+
+ template <class T>
+ inline BBox(const BBox<T>& b) : _min(b.getMin()), _max(b.getMax())
+ {
+ _empty = false;
+ }
+
+ template <class T>
+ inline void extendToContain(const T& p)
+ {
+ if (_empty) {
+ _min = p;
+ _max = p;
+ _empty = false;
+ return;
+ }
+ for (unsigned int i = 0; i < Point::dim(); i++) {
+ if (p[i] < _min[i])
+ _min[i] = p[i];
+ else if (p[i] > _max[i])
+ _max[i] = p[i];
+ }
+ _empty = false;
+ }
+
+ inline void clear()
+ {
+ _empty = true;
+ }
+
+ inline bool empty() const
+ {
+ return _empty;
+ }
+
+ inline const Point& getMin() const
+ {
+ return _min;
+ }
+
+ inline const Point& getMax() const
+ {
+ return _max;
+ }
+
+ inline BBox<Point>& operator=(const BBox<Point>& b)
+ {
+ _min = b.getMin();
+ _max = b.getMax();
+ _empty = false;
+ return *this;
+ }
+
+ inline BBox<Point>& operator+=(const BBox<Point>& b)
+ {
+ if (_empty) {
+ _min = b.getMin();
+ _max = b.getMax();
+ _empty = false;
+ }
+ else {
+ for (unsigned int i = 0; i < Point::dim(); i++) {
+ if (b.getMin()[i] < _min[i])
+ _min[i] = b.getMin()[i];
+ if (b.getMax()[i] > _max[i])
+ _max[i] = b.getMax()[i];
+ }
+ }
+ return *this;
+ }
+
+ inline bool inside(const Point& p)
+ {
+ if (empty())
+ return false;
+ for (unsigned int i = 0; i < Point::dim(); i++) {
+ if ((_min[i]>p[i]) || (_max[i]<p[i]))
+ return false;
+ }
+ return true;
+ }
+
+private:
+ Point _min;
+ Point _max;
+ bool _empty;
+};
+
+template <class Point>
+BBox<Point>& operator+(const BBox<Point> &b1, const BBox<Point> &b2)
+{
+ Point new_min;
+ Point new_max;
+
+ for (unsigned int i = 0; i < Point::dim(); i++) {
+ new_min[i] = b1.getMin()[i] < b2.getMin()[i] ? b1.getMin()[i] : b2.getMin()[i];
+ new_max[i] = b1.getMax()[i] > b2.getMax()[i] ? b1.getMax()[i] : b2.getMax()[i];
+ }
+
+ return BBox<Point>(new_min, new_max);
+}
+
+#endif // __BBOX_H__
diff --git a/source/blender/freestyle/intern/geometry/Bezier.cpp b/source/blender/freestyle/intern/geometry/Bezier.cpp
new file mode 100644
index 00000000000..9140f1f947d
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/Bezier.cpp
@@ -0,0 +1,127 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/geometry/Bezier.cpp
+ * \ingroup freestyle
+ * \brief Class to define a Bezier curve of order 4.
+ * \author Stephane Grabli
+ * \date 04/06/2003
+ */
+
+#include "Bezier.h"
+#include "FitCurve.h"
+
+using namespace std;
+
+BezierCurveSegment::BezierCurveSegment()
+{
+}
+
+BezierCurveSegment::~BezierCurveSegment()
+{
+}
+
+void BezierCurveSegment::AddControlPoint(const Vec2d& iPoint)
+{
+ _ControlPolygon.push_back(iPoint);
+ if (_ControlPolygon.size() == 4)
+ Build();
+}
+
+void BezierCurveSegment::Build()
+{
+ if (_ControlPolygon.size() != 4)
+ return;
+
+ // Compute the rightmost part of the matrix:
+ vector<Vec2d>::const_iterator p0,p1,p2,p3;
+ p0 = _ControlPolygon.begin();
+ p1 = p0;
+ ++p1;
+ p2 = p1;
+ ++p2;
+ p3 = p2;
+ ++p3;
+ float x[4], y[4];
+
+ x[0] = -p0->x() + 3 * p1->x() - 3 * p2->x() + p3->x();
+ x[1] = 3 * p0->x() - 6 * p1->x() + 3 * p2->x();
+ x[2] = -3 * p0->x() + 3 * p1->x();
+ x[3] = p0->x();
+
+ y[0] = -p0->y() + 3 * p1->y() - 3 * p2->y() + p3->y();
+ y[1] = 3 * p0->y() - 6 * p1->y() + 3 * p2->y();
+ y[2] = -3 * p0->y() + 3 * p1->y();
+ y[3] = p0->y();
+
+ int nvertices = 12;
+ float increment = 1.0 / (float)nvertices;
+ float t = 0.0f;
+ for (int i = 0; i <= nvertices; ++i) {
+ _Vertices.push_back(Vec2d((x[3] + t * (x[2] + t * (x[1] + t * x[0]))),
+ (y[3] + t * (y[2] + t * (y[1] + t * y[0])))));
+ t += increment;
+ }
+}
+
+BezierCurve::BezierCurve()
+{
+ _currentSegment = new BezierCurveSegment;
+}
+
+BezierCurve::BezierCurve(vector<Vec2d>& iPoints, double error)
+{
+ FitCurveWrapper fitcurve;
+ _currentSegment = new BezierCurveSegment;
+ vector<Vec2d> curve;
+
+ fitcurve.FitCurve(iPoints, curve, error);
+ int i = 0;
+ vector<Vec2d>::iterator v,vend;
+ for (v = curve.begin(), vend = curve.end(); v != vend; ++v) {
+ if ((i == 0) || (i % 4 != 0))
+ AddControlPoint(*v);
+ ++i;
+ }
+}
+
+BezierCurve::~BezierCurve()
+{
+ if(_currentSegment)
+ delete _currentSegment;
+}
+
+void BezierCurve::AddControlPoint(const Vec2d& iPoint)
+{
+ _ControlPolygon.push_back(iPoint);
+ _currentSegment->AddControlPoint(iPoint);
+ if (_currentSegment->size() == 4) {
+ _Segments.push_back(_currentSegment);
+ _currentSegment = new BezierCurveSegment;
+ _currentSegment->AddControlPoint(iPoint);
+ }
+}
diff --git a/source/blender/freestyle/intern/geometry/Bezier.h b/source/blender/freestyle/intern/geometry/Bezier.h
new file mode 100644
index 00000000000..51f32e9e0b3
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/Bezier.h
@@ -0,0 +1,96 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BEZIER_H__
+#define __BEZIER_H__
+
+/** \file blender/freestyle/intern/geometry/Bezier.h
+ * \ingroup freestyle
+ * \brief Class to define a Bezier curve of order 4.
+ * \author Stephane Grabli
+ * \date 04/06/2003
+ */
+
+#include <vector>
+
+#include "Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace Geometry;
+
+class LIB_GEOMETRY_EXPORT BezierCurveSegment
+{
+private:
+ std::vector<Vec2d> _ControlPolygon;
+ std::vector<Vec2d> _Vertices;
+
+public:
+ BezierCurveSegment();
+ virtual ~BezierCurveSegment();
+
+ void AddControlPoint(const Vec2d& iPoint);
+ void Build();
+
+ inline int size() const
+ {
+ return _ControlPolygon.size();
+ }
+
+ inline std::vector<Vec2d>& vertices()
+ {
+ return _Vertices;
+ }
+};
+
+
+class LIB_GEOMETRY_EXPORT BezierCurve
+{
+private:
+ std::vector<Vec2d> _ControlPolygon;
+ std::vector<BezierCurveSegment*> _Segments;
+ BezierCurveSegment *_currentSegment;
+
+public:
+ BezierCurve();
+ BezierCurve(std::vector<Vec2d>& iPoints, double error=4.0);
+ virtual ~BezierCurve();
+
+ void AddControlPoint(const Vec2d& iPoint);
+
+ std::vector<Vec2d>& controlPolygon()
+ {
+ return _ControlPolygon;
+ }
+
+ std::vector<BezierCurveSegment*>& segments()
+ {
+ return _Segments;
+ }
+};
+
+#endif // __BEZIER_H__
diff --git a/source/blender/freestyle/intern/geometry/FastGrid.cpp b/source/blender/freestyle/intern/geometry/FastGrid.cpp
new file mode 100644
index 00000000000..7051d960346
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/FastGrid.cpp
@@ -0,0 +1,87 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/geometry/FastGrid.h
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the bounding box of the scene
+ * \author Stephane Grabli
+ * \date 30/07/2002
+ */
+
+#include "FastGrid.h"
+
+#include "BKE_global.h"
+
+void FastGrid::clear()
+{
+ if (!_cells)
+ return;
+
+ for (unsigned int i = 0; i < _cells_size; i++) {
+ if (_cells[i])
+ delete _cells[i];
+ }
+ delete[] _cells;
+ _cells = NULL;
+ _cells_size = 0;
+
+ Grid::clear();
+}
+
+void FastGrid::configure(const Vec3r& orig, const Vec3r& size, unsigned nb)
+{
+ Grid::configure(orig, size, nb);
+ _cells_size = _cells_nb[0] * _cells_nb[1] * _cells_nb[2];
+ _cells = new Cell*[_cells_size];
+ memset(_cells, 0, _cells_size * sizeof(*_cells));
+}
+
+Cell *FastGrid::getCell(const Vec3u& p)
+{
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << _cells << " " << p << " " << _cells_nb[0] << "-" << _cells_nb[1] << "-" << _cells_nb[2]
+ << " " << _cells_size << endl;
+ }
+#endif
+ assert(_cells || ("_cells is a null pointer"));
+ assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]) < _cells_size);
+ assert(p[0] < _cells_nb[0]);
+ assert(p[1] < _cells_nb[1]);
+ assert(p[2] < _cells_nb[2]);
+ return _cells[_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]];
+}
+
+void FastGrid::fillCell(const Vec3u& p, Cell& cell)
+{
+ assert(_cells || ("_cells is a null pointer"));
+ assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]) < _cells_size);
+ assert(p[0] < _cells_nb[0]);
+ assert(p[1] < _cells_nb[1]);
+ assert(p[2] < _cells_nb[2]);
+ _cells[_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]] = &cell;
+}
diff --git a/source/blender/freestyle/intern/geometry/FastGrid.h b/source/blender/freestyle/intern/geometry/FastGrid.h
new file mode 100644
index 00000000000..3a2ed392533
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/FastGrid.h
@@ -0,0 +1,86 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FASTGRID_H__
+#define __FASTGRID_H__
+
+/** \file blender/freestyle/intern/geometry/FastGrid.h
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the bounding box of the scene
+ * \author Stephane Grabli
+ * \date 30/07/2002
+ */
+
+#include <cassert>
+
+#include "Grid.h"
+
+/*! Class to define a regular grid used for ray casting computations
+ * We don't use a hashtable here. The grid is explicitly stored for faster computations.
+ * However, this might result in significant increase in memory usage (compared to the regular grid)
+ */
+class LIB_GEOMETRY_EXPORT FastGrid : public Grid
+{
+public:
+ FastGrid() : Grid()
+ {
+ _cells = NULL;
+ _cells_size = 0;
+ }
+
+ virtual ~FastGrid()
+ {
+ clear();
+ }
+
+ /*! clears the grid
+ * Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells.
+ */
+ virtual void clear();
+
+ /*! Sets the different parameters of the grid
+ * orig
+ * The grid origin
+ * size
+ * The grid's dimensions
+ * nb
+ * The number of cells of the grid
+ */
+ virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb);
+
+ /*! returns the cell whose coordinates are pased as argument */
+ Cell* getCell(const Vec3u& p);
+
+ /*! Fills the case p with the cell iCell */
+ virtual void fillCell(const Vec3u& p, Cell& cell);
+
+protected:
+ Cell **_cells;
+ unsigned _cells_size;
+};
+
+#endif // __FASTGRID_H__
diff --git a/source/blender/freestyle/intern/geometry/FitCurve.cpp b/source/blender/freestyle/intern/geometry/FitCurve.cpp
new file mode 100644
index 00000000000..4eae543c9f9
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/FitCurve.cpp
@@ -0,0 +1,602 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/geometry/FitCurve.cpp
+ * \ingroup freestyle
+ * \brief An Algorithm for Automatically Fitting Digitized Curves by Philip J. Schneider,
+ * \brief from "Graphics Gems", Academic Press, 1990
+ * \author Stephane Grabli
+ * \date 06/06/2003
+ */
+
+#include <cstdlib> // for malloc and free
+#include <stdio.h>
+#include <math.h>
+
+#include "FitCurve.h"
+
+using namespace std;
+
+typedef Vector2 *BezierCurve;
+
+// XXX Do we need "#ifdef __cplusplus" at all here???
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Forward declarations */
+static double *Reparameterize(Vector2 *d, int first, int last, double *u, BezierCurve bezCurve);
+static double NewtonRaphsonRootFind(BezierCurve Q, Vector2 P, double u);
+static Vector2 BezierII(int degree, Vector2 *V, double t);
+static double B0(double u);
+static double B1(double u);
+static double B2(double u);
+static double B3(double u);
+static Vector2 ComputeLeftTangent(Vector2 *d, int end);
+static Vector2 ComputeLeftTangent(Vector2 *d, int end);
+static Vector2 ComputeLeftTangent(Vector2 *d, int end);
+static double ComputeMaxError(Vector2 *d, int first, int last, BezierCurve bezCurve, double *u, int *splitPoint);
+static double *ChordLengthParameterize(Vector2 *d, int first, int last);
+static BezierCurve GenerateBezier(Vector2 *d, int first, int last, double *uPrime, Vector2 tHat1, Vector2 tHat2);
+static Vector2 V2AddII(Vector2 a, Vector2 b);
+static Vector2 V2ScaleIII(Vector2 v, double s);
+static Vector2 V2SubII(Vector2 a, Vector2 b);
+
+#define MAXPOINTS 1000 /* The most points you can have */
+
+/* returns squared length of input vector */
+static double V2SquaredLength(Vector2 *a)
+{
+ return (((*a)[0] * (*a)[0]) + ((*a)[1] * (*a)[1]));
+}
+
+/* returns length of input vector */
+static double V2Length(Vector2 *a)
+{
+ return (sqrt(V2SquaredLength(a)));
+}
+
+static Vector2 *V2Scale(Vector2 *v, double newlen)
+{
+ double len = V2Length(v);
+ if (len != 0.0) {
+ (*v)[0] *= newlen / len;
+ (*v)[1] *= newlen / len;
+ }
+ return v;
+}
+
+/* return the dot product of vectors a and b */
+static double V2Dot(Vector2 *a, Vector2 *b)
+{
+ return (((*a)[0] * (*b)[0]) + ((*a)[1] * (*b)[1]));
+}
+
+/* return the distance between two points */
+static double V2DistanceBetween2Points(Vector2 *a, Vector2 *b)
+{
+ double dx = (*a)[0] - (*b)[0];
+ double dy = (*a)[1] - (*b)[1];
+ return (sqrt((dx * dx) + (dy * dy)));
+}
+
+/* return vector sum c = a+b */
+static Vector2 *V2Add(Vector2 *a, Vector2 *b, Vector2 *c)
+{
+ (*c)[0] = (*a)[0] + (*b)[0];
+ (*c)[1] = (*a)[1] + (*b)[1];
+ return c;
+}
+
+/* normalizes the input vector and returns it */
+static Vector2 *V2Normalize(Vector2 *v)
+{
+ double len = V2Length(v);
+ if (len != 0.0) {
+ (*v)[0] /= len;
+ (*v)[1] /= len;
+ }
+ return v;
+}
+
+/* negates the input vector and returns it */
+static Vector2 *V2Negate(Vector2 *v)
+{
+ (*v)[0] = -(*v)[0];
+ (*v)[1] = -(*v)[1];
+ return v;
+}
+
+/* GenerateBezier:
+ * Use least-squares method to find Bezier control points for region.
+ * Vector2 *d; Array of digitized points
+ * int first, last; Indices defining region
+ * double *uPrime; Parameter values for region
+ * Vector2 tHat1, tHat2; Unit tangents at endpoints
+ */
+static BezierCurve GenerateBezier(Vector2 *d, int first, int last, double *uPrime, Vector2 tHat1, Vector2 tHat2)
+{
+ int i;
+ Vector2 A[MAXPOINTS][2]; /* Precomputed rhs for eqn */
+ int nPts; /* Number of pts in sub-curve */
+ double C[2][2]; /* Matrix C */
+ double X[2]; /* Matrix X */
+ double det_C0_C1; /* Determinants of matrices */
+ double det_C0_X;
+ double det_X_C1;
+ double alpha_l; /* Alpha values, left and right */
+ double alpha_r;
+ Vector2 tmp; /* Utility variable */
+ BezierCurve bezCurve; /* RETURN bezier curve ctl pts */
+
+ bezCurve = (Vector2*)malloc(4 * sizeof(Vector2));
+ nPts = last - first + 1;
+
+ /* Compute the A's */
+ for (i = 0; i < nPts; i++) {
+ Vector2 v1, v2;
+ v1 = tHat1;
+ v2 = tHat2;
+ V2Scale(&v1, B1(uPrime[i]));
+ V2Scale(&v2, B2(uPrime[i]));
+ A[i][0] = v1;
+ A[i][1] = v2;
+ }
+
+ /* Create the C and X matrices */
+ C[0][0] = 0.0;
+ C[0][1] = 0.0;
+ C[1][0] = 0.0;
+ C[1][1] = 0.0;
+ X[0] = 0.0;
+ X[1] = 0.0;
+ for (i = 0; i < nPts; i++) {
+ C[0][0] += V2Dot(&A[i][0], &A[i][0]);
+ C[0][1] += V2Dot(&A[i][0], &A[i][1]);
+// C[1][0] += V2Dot(&A[i][0], &A[i][1]);
+ C[1][0] = C[0][1];
+ C[1][1] += V2Dot(&A[i][1], &A[i][1]);
+
+ tmp = V2SubII(d[first + i],
+ V2AddII(V2ScaleIII(d[first], B0(uPrime[i])),
+ V2AddII(V2ScaleIII(d[first], B1(uPrime[i])),
+ V2AddII(V2ScaleIII(d[last], B2(uPrime[i])),
+ V2ScaleIII(d[last], B3(uPrime[i]))
+ )
+ )
+ )
+ );
+
+ X[0] += V2Dot(&((A[i])[0]), &tmp);
+ X[1] += V2Dot(&((A[i])[1]), &tmp);
+ }
+
+ /* Compute the determinants of C and X */
+ det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1];
+ det_C0_X = C[0][0] * X[1] - C[0][1] * X[0];
+ det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1];
+
+ /* Finally, derive alpha values */
+ if (det_C0_C1 == 0.0) {
+ det_C0_C1 = (C[0][0] * C[1][1]) * 10.0e-12;
+ }
+ alpha_l = det_X_C1 / det_C0_C1;
+ alpha_r = det_C0_X / det_C0_C1;
+
+
+ /* If alpha negative, use the Wu/Barsky heuristic (see text) (if alpha is 0, you get coincident control points
+ * that lead to divide by zero in any subsequent NewtonRaphsonRootFind() call).
+ */
+ if (alpha_l < 1.0e-6 || alpha_r < 1.0e-6) {
+ double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0;
+
+ bezCurve[0] = d[first];
+ bezCurve[3] = d[last];
+ V2Add(&(bezCurve[0]), V2Scale(&(tHat1), dist), &(bezCurve[1]));
+ V2Add(&(bezCurve[3]), V2Scale(&(tHat2), dist), &(bezCurve[2]));
+ return bezCurve;
+ }
+
+ /* First and last control points of the Bezier curve are positioned exactly at the first and last data points
+ * Control points 1 and 2 are positioned an alpha distance out on the tangent vectors, left and right, respectively
+ */
+ bezCurve[0] = d[first];
+ bezCurve[3] = d[last];
+ V2Add(&bezCurve[0], V2Scale(&tHat1, alpha_l), &bezCurve[1]);
+ V2Add(&bezCurve[3], V2Scale(&tHat2, alpha_r), &bezCurve[2]);
+ return (bezCurve);
+}
+
+/*
+ * Reparameterize:
+ * Given set of points and their parameterization, try to find a better parameterization.
+ * Vector2 *d; Array of digitized points
+ * int first, last; Indices defining region
+ * double *u; Current parameter values
+ * BezierCurve bezCurve; Current fitted curve
+ */
+static double *Reparameterize(Vector2 *d, int first, int last, double *u, BezierCurve bezCurve)
+{
+ int nPts = last - first + 1;
+ int i;
+ double *uPrime; /* New parameter values */
+
+ uPrime = (double*)malloc(nPts * sizeof(double));
+ for (i = first; i <= last; i++) {
+ uPrime[i-first] = NewtonRaphsonRootFind(bezCurve, d[i], u[i - first]);
+ }
+ return (uPrime);
+}
+
+/*
+ * NewtonRaphsonRootFind:
+ * Use Newton-Raphson iteration to find better root.
+ * BezierCurve Q; Current fitted curve
+ * Vector2 P; Digitized point
+ * double u; Parameter value for "P"
+ */
+static double NewtonRaphsonRootFind(BezierCurve Q, Vector2 P, double u)
+{
+ double numerator, denominator;
+ Vector2 Q1[3], Q2[2]; /* Q' and Q'' */
+ Vector2 Q_u, Q1_u, Q2_u; /* u evaluated at Q, Q', & Q'' */
+ double uPrime; /* Improved u */
+ int i;
+
+ /* Compute Q(u) */
+ Q_u = BezierII(3, Q, u);
+
+ /* Generate control vertices for Q' */
+ for (i = 0; i <= 2; i++) {
+ Q1[i][0] = (Q[i + 1][0] - Q[i][0]) * 3.0;
+ Q1[i][1] = (Q[i + 1][1] - Q[i][1]) * 3.0;
+ }
+
+ /* Generate control vertices for Q'' */
+ for (i = 0; i <= 1; i++) {
+ Q2[i][0] = (Q1[i + 1][0] - Q1[i][0]) * 2.0;
+ Q2[i][1] = (Q1[i + 1][1] - Q1[i][1]) * 2.0;
+ }
+
+ /* Compute Q'(u) and Q''(u) */
+ Q1_u = BezierII(2, Q1, u);
+ Q2_u = BezierII(1, Q2, u);
+
+ /* Compute f(u)/f'(u) */
+ numerator = (Q_u[0] - P[0]) * (Q1_u[0]) + (Q_u[1] - P[1]) * (Q1_u[1]);
+ denominator = (Q1_u[0]) * (Q1_u[0]) + (Q1_u[1]) * (Q1_u[1]) +
+ (Q_u[0] - P[0]) * (Q2_u[0]) + (Q_u[1] - P[1]) * (Q2_u[1]);
+
+ /* u = u - f(u)/f'(u) */
+ if (denominator == 0) // FIXME
+ return u;
+ uPrime = u - (numerator / denominator);
+ return uPrime;
+}
+
+/*
+ * Bezier:
+ * Evaluate a Bezier curve at a particular parameter value
+ * int degree; The degree of the bezier curve
+ * Vector2 *V; Array of control points
+ * double t; Parametric value to find point for
+ */
+static Vector2 BezierII(int degree, Vector2 *V, double t)
+{
+ int i, j;
+ Vector2 Q; /* Point on curve at parameter t */
+ Vector2 *Vtemp; /* Local copy of control points */
+
+ /* Copy array */
+ Vtemp = (Vector2*)malloc((unsigned)((degree + 1) * sizeof (Vector2)));
+ for (i = 0; i <= degree; i++) {
+ Vtemp[i] = V[i];
+ }
+
+ /* Triangle computation */
+ for (i = 1; i <= degree; i++) {
+ for (j = 0; j <= degree-i; j++) {
+ Vtemp[j][0] = (1.0 - t) * Vtemp[j][0] + t * Vtemp[j + 1][0];
+ Vtemp[j][1] = (1.0 - t) * Vtemp[j][1] + t * Vtemp[j + 1][1];
+ }
+ }
+
+ Q = Vtemp[0];
+ free((void*)Vtemp);
+ return Q;
+}
+
+/*
+ * B0, B1, B2, B3:
+ * Bezier multipliers
+ */
+static double B0(double u)
+{
+ double tmp = 1.0 - u;
+ return (tmp * tmp * tmp);
+}
+
+
+static double B1(double u)
+{
+ double tmp = 1.0 - u;
+ return (3 * u * (tmp * tmp));
+}
+
+static double B2(double u)
+{
+ double tmp = 1.0 - u;
+ return (3 * u * u * tmp);
+}
+
+static double B3(double u)
+{
+ return (u * u * u);
+}
+
+/*
+ * ComputeLeftTangent, ComputeRightTangent, ComputeCenterTangent:
+ * Approximate unit tangents at endpoints and "center" of digitized curve
+ */
+/* Vector2 *d; Digitized points
+ * int end; Index to "left" end of region
+ */
+static Vector2 ComputeLeftTangent(Vector2 *d, int end)
+{
+ Vector2 tHat1;
+ tHat1 = V2SubII(d[end + 1], d[end]);
+ tHat1 = *V2Normalize(&tHat1);
+ return tHat1;
+}
+
+/* Vector2 *d; Digitized points
+ * int end; Index to "right" end of region
+ */
+static Vector2 ComputeRightTangent(Vector2 *d, int end)
+{
+ Vector2 tHat2;
+ tHat2 = V2SubII(d[end - 1], d[end]);
+ tHat2 = *V2Normalize(&tHat2);
+ return tHat2;
+}
+
+/* Vector2 *d; Digitized points
+ * int end; Index to point inside region
+ */
+static Vector2 ComputeCenterTangent(Vector2 *d, int center)
+{
+ Vector2 V1, V2, tHatCenter;
+
+ V1 = V2SubII(d[center - 1], d[center]);
+ V2 = V2SubII(d[center], d[center + 1]);
+ tHatCenter[0] = (V1[0] + V2[0]) / 2.0;
+ tHatCenter[1] = (V1[1] + V2[1]) / 2.0;
+ tHatCenter = *V2Normalize(&tHatCenter);
+ return tHatCenter;
+}
+
+/*
+ * ChordLengthParameterize:
+ * Assign parameter values to digitized points using relative distances between points.
+ * Vector2 *d; Array of digitized points
+ * int first, last; Indices defining region
+ */
+static double *ChordLengthParameterize(Vector2 *d, int first, int last)
+{
+ int i;
+ double *u; /* Parameterization */
+
+ u = (double*)malloc((unsigned)(last - first + 1) * sizeof(double));
+
+ u[0] = 0.0;
+ for (i = first + 1; i <= last; i++) {
+ u[i - first] = u[i - first - 1] + V2DistanceBetween2Points(&d[i], &d[i - 1]);
+ }
+
+ for (i = first + 1; i <= last; i++) {
+ u[i - first] = u[i - first] / u[last - first];
+ }
+
+ return u;
+}
+
+
+
+
+/*
+ * ComputeMaxError :
+ * Find the maximum squared distance of digitized points to fitted curve.
+ * Vector2 *d; Array of digitized points
+ * int first, last; Indices defining region
+ * BezierCurve bezCurve; Fitted Bezier curve
+ * double *u; Parameterization of points
+ * int *splitPoint; Point of maximum error
+ */
+static double ComputeMaxError(Vector2 *d, int first, int last, BezierCurve bezCurve, double *u, int *splitPoint)
+{
+ int i;
+ double maxDist; /* Maximum error */
+ double dist; /* Current error */
+ Vector2 P; /* Point on curve */
+ Vector2 v; /* Vector from point to curve */
+
+ *splitPoint = (last - first + 1) / 2;
+ maxDist = 0.0;
+ for (i = first + 1; i < last; i++) {
+ P = BezierII(3, bezCurve, u[i - first]);
+ v = V2SubII(P, d[i]);
+ dist = V2SquaredLength(&v);
+ if (dist >= maxDist) {
+ maxDist = dist;
+ *splitPoint = i;
+ }
+ }
+ return maxDist;
+}
+
+static Vector2 V2AddII(Vector2 a, Vector2 b)
+{
+ Vector2 c;
+ c[0] = a[0] + b[0];
+ c[1] = a[1] + b[1];
+ return c;
+}
+
+static Vector2 V2ScaleIII(Vector2 v, double s)
+{
+ Vector2 result;
+ result[0] = v[0] * s;
+ result[1] = v[1] * s;
+ return result;
+}
+
+static Vector2 V2SubII(Vector2 a, Vector2 b)
+{
+ Vector2 c;
+ c[0] = a[0] - b[0];
+ c[1] = a[1] - b[1];
+ return c;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
+//------------------------- WRAPPER -----------------------------//
+
+FitCurveWrapper::FitCurveWrapper()
+{
+}
+
+FitCurveWrapper::~FitCurveWrapper()
+{
+ _vertices.clear();
+}
+
+void FitCurveWrapper::DrawBezierCurve(int n, Vector2 *curve)
+{
+ for (int i = 0; i < n + 1; ++i)
+ _vertices.push_back(curve[i]);
+}
+
+void FitCurveWrapper::FitCurve(vector<Vec2d>& data, vector<Vec2d>& oCurve, double error)
+{
+ int size = data.size();
+ Vector2 *d = new Vector2[size];
+ for (int i = 0; i < size; ++i) {
+ d[i][0] = data[i][0];
+ d[i][1] = data[i][1];
+ }
+
+ FitCurve(d, size, error);
+
+ // copy results
+ for (vector<Vector2>::iterator v = _vertices.begin(), vend = _vertices.end(); v != vend; ++v) {
+ oCurve.push_back(Vec2d(v->x(), v->y())) ;
+ }
+}
+
+void FitCurveWrapper::FitCurve(Vector2 *d, int nPts, double error)
+{
+ Vector2 tHat1, tHat2; /* Unit tangent vectors at endpoints */
+
+ tHat1 = ComputeLeftTangent(d, 0);
+ tHat2 = ComputeRightTangent(d, nPts - 1);
+ FitCubic(d, 0, nPts - 1, tHat1, tHat2, error);
+}
+
+void FitCurveWrapper::FitCubic(Vector2 *d, int first, int last, Vector2 tHat1, Vector2 tHat2, double error)
+{
+ BezierCurve bezCurve; /* Control points of fitted Bezier curve */
+ double *u; /* Parameter values for point */
+ double *uPrime; /* Improved parameter values */
+ double maxError; /* Maximum fitting error */
+ int splitPoint; /* Point to split point set at */
+ int nPts; /* Number of points in subset */
+ double iterationError; /* Error below which you try iterating */
+ int maxIterations = 4; /* Max times to try iterating */
+ Vector2 tHatCenter; /* Unit tangent vector at splitPoint */
+ int i;
+
+ iterationError = error * error;
+ nPts = last - first + 1;
+
+ /* Use heuristic if region only has two points in it */
+ if (nPts == 2) {
+ double dist = V2DistanceBetween2Points(&d[last], &d[first]) / 3.0;
+
+ bezCurve = (Vector2*)malloc(4 * sizeof(Vector2));
+ bezCurve[0] = d[first];
+ bezCurve[3] = d[last];
+ V2Add(&bezCurve[0], V2Scale(&tHat1, dist), &bezCurve[1]);
+ V2Add(&bezCurve[3], V2Scale(&tHat2, dist), &bezCurve[2]);
+ DrawBezierCurve(3, bezCurve);
+ free((void*)bezCurve);
+ return;
+ }
+
+ /* Parameterize points, and attempt to fit curve */
+ u = ChordLengthParameterize(d, first, last);
+ bezCurve = GenerateBezier(d, first, last, u, tHat1, tHat2);
+
+ /* Find max deviation of points to fitted curve */
+ maxError = ComputeMaxError(d, first, last, bezCurve, u, &splitPoint);
+ if (maxError < error) {
+ DrawBezierCurve(3, bezCurve);
+ free((void*)u);
+ free((void*)bezCurve);
+ return;
+ }
+
+ /* If error not too large, try some reparameterization and iteration */
+ if (maxError < iterationError) {
+ for (i = 0; i < maxIterations; i++) {
+ uPrime = Reparameterize(d, first, last, u, bezCurve);
+ bezCurve = GenerateBezier(d, first, last, uPrime, tHat1, tHat2);
+ maxError = ComputeMaxError(d, first, last,
+ bezCurve, uPrime, &splitPoint);
+ if (maxError < error) {
+ DrawBezierCurve(3, bezCurve);
+ free((void*)u);
+ free((void*)bezCurve);
+ return;
+ }
+ free((void*)u);
+ u = uPrime;
+ }
+ }
+
+ /* Fitting failed -- split at max error point and fit recursively */
+ free((void*)u);
+ free((void*)bezCurve);
+ tHatCenter = ComputeCenterTangent(d, splitPoint);
+ FitCubic(d, first, splitPoint, tHat1, tHatCenter, error);
+ V2Negate(&tHatCenter);
+ FitCubic(d, splitPoint, last, tHatCenter, tHat2, error);
+}
diff --git a/source/blender/freestyle/intern/geometry/FitCurve.h b/source/blender/freestyle/intern/geometry/FitCurve.h
new file mode 100644
index 00000000000..0a80c2f28f9
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/FitCurve.h
@@ -0,0 +1,125 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FITCURVE_H__
+#define __FITCURVE_H__
+
+/** \file blender/freestyle/intern/geometry/FitCurve.h
+ * \ingroup freestyle
+ * \brief An Algorithm for Automatically Fitting Digitized Curves by Philip J. Schneider,
+ * \brief from "Graphics Gems", Academic Press, 1990
+ * \author Stephane Grabli
+ * \date 06/06/2003
+ */
+
+#include <vector>
+
+#include "Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace Geometry;
+
+/* 2d point */
+typedef struct Point2Struct
+{
+ double coordinates[2];
+
+ Point2Struct()
+ {
+ coordinates[0] = 0;
+ coordinates[1] = 0;
+ }
+
+ inline double operator[](const int i) const
+ {
+ return coordinates[i];
+ }
+
+ inline double& operator[](const int i)
+ {
+ return coordinates[i];
+ }
+
+ inline double x() const
+ {
+ return coordinates[0];
+ }
+
+ inline double y() const
+ {
+ return coordinates[1];
+ }
+} Point2;
+
+typedef Point2 Vector2;
+
+
+class LIB_GEOMETRY_EXPORT FitCurveWrapper
+{
+private:
+ std::vector<Vector2> _vertices;
+
+public:
+ FitCurveWrapper();
+ ~FitCurveWrapper();
+
+ /*! Fits a set of 2D data points to a set of Bezier Curve segments
+ * data
+ * Input data points
+ * oCurve
+ * Control points of the sets of bezier curve segments.
+ * Each segment is made of 4 points (polynomial degree of curve = 3)
+ * error
+ * max error tolerance between resulting curve and input data
+ */
+ void FitCurve(std::vector<Vec2d>& data, std::vector<Vec2d>& oCurve, double error);
+
+protected:
+ /* Vec2d *d; Array of digitized points
+ * int nPts; Number of digitized points
+ * double error; User-defined error squared
+ */
+ void FitCurve(Vector2 *d, int nPts, double error);
+
+ /*! Draws a Bezier curve segment
+ * n
+ * degree of curve (=3)
+ * curve
+ * bezier segments control points
+ */
+ void DrawBezierCurve(int n, Vector2 *curve);
+
+ /* Vec2d *d; Array of digitized points
+ * int first, last; Indices of first and last pts in region
+ * Vec2d tHat1, tHat2; Unit tangent vectors at endpoints
+ * double error; User-defined error squared
+ */
+ void FitCubic(Vector2 *d, int first, int last, Vector2 tHat1, Vector2 tHat2, double error);
+};
+
+#endif // __FITCURVE_H__
diff --git a/source/blender/freestyle/intern/geometry/Geom.h b/source/blender/freestyle/intern/geometry/Geom.h
new file mode 100644
index 00000000000..f241346ec85
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/Geom.h
@@ -0,0 +1,84 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __GEOM_H__
+#define __GEOM_H__
+
+/** \file blender/freestyle/intern/geometry/Geom.h
+ * \ingroup freestyle
+ * \brief Vectors and Matrices (useful type definitions)
+ * \author Sylvain Paris
+ * \author Emmanuel Turquin
+ * \author Stephane Grabli
+ * \date 20/05/2003
+ */
+
+#include "VecMat.h"
+
+#include "../system/Precision.h"
+
+namespace Geometry {
+
+typedef VecMat::Vec2<unsigned> Vec2u;
+typedef VecMat::Vec2<int> Vec2i;
+typedef VecMat::Vec2<float> Vec2f;
+typedef VecMat::Vec2<double> Vec2d;
+typedef VecMat::Vec2<real> Vec2r;
+
+typedef VecMat::Vec3<unsigned> Vec3u;
+typedef VecMat::Vec3<int> Vec3i;
+typedef VecMat::Vec3<float> Vec3f;
+typedef VecMat::Vec3<double> Vec3d;
+typedef VecMat::Vec3<real> Vec3r;
+
+typedef VecMat::HVec3<unsigned> HVec3u;
+typedef VecMat::HVec3<int> HVec3i;
+typedef VecMat::HVec3<float> HVec3f;
+typedef VecMat::HVec3<double> HVec3d;
+typedef VecMat::HVec3<real> HVec3r;
+
+typedef VecMat::SquareMatrix<unsigned, 2> Matrix22u;
+typedef VecMat::SquareMatrix<int, 2> Matrix22i;
+typedef VecMat::SquareMatrix<float, 2> Matrix22f;
+typedef VecMat::SquareMatrix<double, 2> Matrix22d;
+typedef VecMat::SquareMatrix<real, 2> Matrix22r;
+
+typedef VecMat::SquareMatrix<unsigned, 3> Matrix33u;
+typedef VecMat::SquareMatrix<int, 3> Matrix33i;
+typedef VecMat::SquareMatrix<float, 3> Matrix33f;
+typedef VecMat::SquareMatrix<double, 3> Matrix33d;
+typedef VecMat::SquareMatrix<real, 3> Matrix33r;
+
+typedef VecMat::SquareMatrix<unsigned, 4> Matrix44u;
+typedef VecMat::SquareMatrix<int, 4> Matrix44i;
+typedef VecMat::SquareMatrix<float, 4> Matrix44f;
+typedef VecMat::SquareMatrix<double, 4> Matrix44d;
+typedef VecMat::SquareMatrix<real, 4> Matrix44r;
+
+} // end of namespace Geometry
+
+#endif // __GEOM_H__
diff --git a/source/blender/freestyle/intern/geometry/GeomCleaner.cpp b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp
new file mode 100644
index 00000000000..c90513c6294
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/GeomCleaner.cpp
@@ -0,0 +1,240 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/geometry/GeomCleaner.cpp
+ * \ingroup freestyle
+ * \brief Class to define a cleaner of geometry providing a set of useful tools
+ * \author Stephane Grabli
+ * \date 04/03/2002
+ */
+
+#if 0
+#if defined(__GNUC__) && (__GNUC__ >= 3)
+// hash_map is not part of the C++ standard anymore;
+// hash_map.h has been kept though for backward compatibility
+# include <hash_map.h>
+#else
+# include <hash_map>
+#endif
+#endif
+
+#include <stdio.h>
+#include <list>
+#include <map>
+
+#include "GeomCleaner.h"
+
+#include "../system/TimeUtils.h"
+
+#include "BKE_global.h"
+
+using namespace std;
+
+
+void GeomCleaner::SortIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices,
+ unsigned iISize, real **oVertices, unsigned **oIndices)
+{
+ // First, we build a list of IndexVertex:
+ list<IndexedVertex> indexedVertices;
+ unsigned i;
+ for (i = 0; i < iVSize; i += 3) {
+ indexedVertices.push_back(IndexedVertex(Vec3r(iVertices[i], iVertices[i + 1], iVertices[i + 2]), i / 3));
+ }
+
+ // q-sort
+ indexedVertices.sort();
+
+ // build the indices mapping array:
+ unsigned *mapIndices = new unsigned[iVSize / 3];
+ *oVertices = new real[iVSize];
+ list<IndexedVertex>::iterator iv;
+ unsigned newIndex = 0;
+ unsigned vIndex = 0;
+ for (iv = indexedVertices.begin(); iv != indexedVertices.end(); iv++) {
+ // Build the final results:
+ (*oVertices)[vIndex] = iv->x();
+ (*oVertices)[vIndex + 1] = iv->y();
+ (*oVertices)[vIndex + 2] = iv->z();
+
+ mapIndices[iv->index()] = newIndex;
+ newIndex++;
+ vIndex += 3;
+ }
+
+ // Build the final index array:
+ *oIndices = new unsigned[iISize];
+ for (i = 0; i < iISize; i++) {
+ (*oIndices)[i] = 3 * mapIndices[iIndices[i] / 3];
+ }
+
+ delete [] mapIndices;
+}
+
+void GeomCleaner::CompressIndexedVertexArray(const real *iVertices, unsigned iVSize, const unsigned *iIndices,
+ unsigned iISize, real **oVertices, unsigned *oVSize, unsigned **oIndices)
+{
+ // First, we build a list of IndexVertex:
+ vector<Vec3r> vertices;
+ unsigned i;
+ for (i = 0; i < iVSize; i += 3) {
+ vertices.push_back(Vec3r(iVertices[i], iVertices[i + 1], iVertices[i + 2]));
+ }
+
+ unsigned *mapVertex = new unsigned[iVSize];
+ vector<Vec3r>::iterator v = vertices.begin();
+
+ vector<Vec3r> compressedVertices;
+ Vec3r previous = *v;
+ mapVertex[0] = 0;
+ compressedVertices.push_back(vertices.front());
+
+ v++;
+ Vec3r current;
+ i = 1;
+ for (; v != vertices.end(); v++) {
+ current = *v;
+ if (current == previous)
+ mapVertex[i] = compressedVertices.size() - 1;
+ else {
+ compressedVertices.push_back(current);
+ mapVertex[i] = compressedVertices.size() - 1;
+ }
+ previous = current;
+ i++;
+ }
+
+ // Builds the resulting vertex array:
+ *oVSize = 3 * compressedVertices.size();
+ *oVertices = new real[*oVSize];
+ i = 0;
+ for (v = compressedVertices.begin(); v != compressedVertices.end(); v++) {
+ (*oVertices)[i] = (*v)[0];
+ (*oVertices)[i + 1] = (*v)[1];
+ (*oVertices)[i + 2] = (*v)[2];
+ i += 3;
+ }
+
+ // Map the index array:
+ *oIndices = new unsigned[iISize];
+ for (i = 0; i < iISize; i++) {
+ (*oIndices)[i] = 3 * mapVertex[iIndices[i] / 3];
+ }
+
+ delete [] mapVertex;
+}
+
+void GeomCleaner::SortAndCompressIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices,
+ unsigned iISize, real **oVertices, unsigned *oVSize,
+ unsigned **oIndices)
+{
+ // tmp arrays used to store the sorted data:
+ real *tmpVertices;
+ unsigned *tmpIndices;
+
+ Chronometer chrono;
+ // Sort data
+ chrono.start();
+ GeomCleaner::SortIndexedVertexArray(iVertices, iVSize, iIndices, iISize, &tmpVertices, &tmpIndices);
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("Sorting: %lf\n", chrono.stop());
+ }
+
+ // compress data
+ chrono.start();
+ GeomCleaner::CompressIndexedVertexArray(tmpVertices, iVSize, tmpIndices, iISize, oVertices, oVSize, oIndices);
+ real duration = chrono.stop();
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("Merging: %lf\n", duration);
+ }
+
+ // deallocates memory:
+ delete [] tmpVertices;
+ delete [] tmpIndices;
+}
+
+/*! Defines a hash table used for searching the Cells */
+struct GeomCleanerHasher{
+#define _MUL 950706376UL
+#define _MOD 2147483647UL
+ inline size_t operator() (const Vec3r& p) const
+ {
+ size_t res = ((unsigned long) (p[0] * _MUL)) % _MOD;
+ res = ((res + (unsigned long) (p[1]) * _MUL)) % _MOD;
+ return ((res +(unsigned long) (p[2]) * _MUL)) % _MOD;
+ }
+#undef _MUL
+#undef _MOD
+};
+
+void GeomCleaner::CleanIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices,
+ unsigned iISize, real **oVertices, unsigned *oVSize, unsigned **oIndices)
+{
+ typedef map<Vec3r, unsigned> cleanHashTable;
+ vector<Vec3r> vertices;
+ unsigned i;
+ for (i = 0; i < iVSize; i += 3)
+ vertices.push_back(Vec3r(iVertices[i], iVertices[i + 1], iVertices[i + 2]));
+
+ cleanHashTable ht;
+ vector<unsigned> newIndices;
+ vector<Vec3r> newVertices;
+
+ // elimination of needless points
+ unsigned currentIndex = 0;
+ vector<Vec3r>::const_iterator v = vertices.begin();
+ vector<Vec3r>::const_iterator end = vertices.end();
+ cleanHashTable::const_iterator found;
+ for (; v != end; v++) {
+ found = ht.find(*v);
+ if (found != ht.end()) {
+ // The vertex is already in the new array.
+ newIndices.push_back((*found).second);
+ }
+ else {
+ newVertices.push_back(*v);
+ newIndices.push_back(currentIndex);
+ ht[*v] = currentIndex;
+ currentIndex++;
+ }
+ }
+
+ // creation of oVertices array:
+ *oVSize = 3 * newVertices.size();
+ *oVertices = new real[*oVSize];
+ currentIndex = 0;
+ end = newVertices.end();
+ for (v = newVertices.begin(); v != end ; v++) {
+ (*oVertices)[currentIndex++] = (*v)[0];
+ (*oVertices)[currentIndex++] = (*v)[1];
+ (*oVertices)[currentIndex++] = (*v)[2];
+ }
+
+ // map new indices:
+ *oIndices = new unsigned[iISize];
+ for (i = 0; i < iISize; i++)
+ (*oIndices)[i] = 3 * newIndices[iIndices[i] / 3];
+}
diff --git a/source/blender/freestyle/intern/geometry/GeomCleaner.h b/source/blender/freestyle/intern/geometry/GeomCleaner.h
new file mode 100644
index 00000000000..334145f3bcd
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/GeomCleaner.h
@@ -0,0 +1,227 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __GEOMCLEANER_H__
+#define __GEOMCLEANER_H__
+
+/** \file blender/freestyle/intern/geometry/GeomCleaner.h
+ * \ingroup freestyle
+ * \brief Class to define a cleaner of geometry providing a set of useful tools
+ * \author Stephane Grabli
+ * \date 04/03/2002
+ */
+
+#include "Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace Geometry;
+
+class LIB_GEOMETRY_EXPORT GeomCleaner
+{
+public:
+ inline GeomCleaner() {}
+ inline ~GeomCleaner() {}
+
+ /*! Sorts an array of Indexed vertices
+ * iVertices
+ * Array of vertices to sort. It is organized as a float series of vertex coordinates: XYZXYZXYZ...
+ * iVSize
+ * The size of iVertices array.
+ * iIndices
+ * The array containing the vertex indices (used to refer to the vertex coordinates in an indexed face). Each
+ * element is an unsignedeger multiple of 3.
+ * iISize
+ * The size of iIndices array
+ * oVertices
+ * Output of sorted vertices. A vertex v1 precedes another one v2 in this array if v1.x<v2.x,
+ * or v1.x=v2.x && v1.y < v2.y or v1.x=v2.y && v1.y=v2.y && v1.z < v2.z.
+ * The array is organized as a 3-float serie giving the vertices coordinates: XYZXYZXYZ...
+ * oIndices
+ * Output corresponding to the iIndices array but reorganized in order to match the sorted vertex array.
+ */
+ static void SortIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices,
+ unsigned iISize, real **oVertices, unsigned **oIndices);
+
+ /*! Compress a SORTED indexed vertex array by eliminating multiple appearing occurences of a single vertex.
+ * iVertices
+ * The SORTED vertex array to compress. It is organized as a float series of vertex coordinates: XYZXYZXYZ...
+ * iVSize
+ * The size of iVertices array.
+ * iIndices
+ * The array containing the vertex indices (used to refer to the vertex coordinates in an indexed face).
+ * Each element is an unsignedeger multiple of 3.
+ * iISize
+ * The size of iIndices array
+ * oVertices
+ * The vertex array, result of the compression.
+ * The array is organized as a 3-float serie giving the vertices coordinates: XYZXYZXYZ...
+ * oVSize
+ * The size of oVertices.
+ * oIndices
+ * The indices array, reorganized to match the compressed oVertices array.
+ */
+ static void CompressIndexedVertexArray(const real *iVertices, unsigned iVSize, const unsigned *iIndices,
+ unsigned iISize, real **oVertices, unsigned *oVSize, unsigned **oIndices);
+
+ /*! Sorts and compress an array of indexed vertices.
+ * iVertices
+ * The vertex array to sort then compress. It is organized as a float series of
+ * vertex coordinates: XYZXYZXYZ...
+ * iVSize
+ * The size of iVertices array.
+ * iIndices
+ * The array containing the vertex indices (used to refer to the vertex coordinates in an indexed face).
+ * Each element is an unsignedeger multiple of 3.
+ * iISize
+ * The size of iIndices array
+ * oVertices
+ * The vertex array, result of the sorting-compression.
+ * The array is organized as a 3-float serie giving the vertices coordinates: XYZXYZXYZ...
+ * oVSize
+ * The size of oVertices.
+ * oIndices
+ * The indices array, reorganized to match the sorted and compressed oVertices array.
+ */
+ static void SortAndCompressIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices,
+ unsigned iISize, real **oVertices, unsigned *oVSize,
+ unsigned **oIndices);
+
+ /*! Cleans an indexed vertex array. (Identical to SortAndCompress except that we use here a hash table
+ * to create the new array.)
+ * iVertices
+ * The vertex array to sort then compress. It is organized as a float series of
+ * vertex coordinates: XYZXYZXYZ...
+ * iVSize
+ * The size of iVertices array.
+ * iIndices
+ * The array containing the vertex indices (used to refer to the vertex coordinates in an indexed face).
+ * Each element is an unsignedeger multiple of 3.
+ * iISize
+ * The size of iIndices array
+ * oVertices
+ * The vertex array, result of the sorting-compression.
+ * The array is organized as a 3-float serie giving the vertices coordinates: XYZXYZXYZ...
+ * oVSize
+ * The size of oVertices.
+ * oIndices
+ * The indices array, reorganized to match the sorted and compressed oVertices array.
+ */
+ static void CleanIndexedVertexArray(const float *iVertices, unsigned iVSize, const unsigned *iIndices,
+ unsigned iISize, real **oVertices, unsigned *oVSize, unsigned **oIndices);
+};
+
+
+/*! Binary operators */
+//inline bool operator<(const IndexedVertex& iv1, const IndexedVertex& iv2);
+
+/*! Class Indexed Vertex. Used to represent an indexed vertex by storing the vertex coordinates as well as its index */
+class IndexedVertex
+{
+private:
+ Vec3r _Vector;
+ unsigned _index;
+
+public:
+ inline IndexedVertex() {}
+
+ inline IndexedVertex(Vec3r iVector, unsigned iIndex)
+ {
+ _Vector = iVector;
+ _index = iIndex;
+ }
+
+ /*! accessors */
+ inline const Vec3r& vector() const
+ {
+ return _Vector;
+ }
+
+ inline unsigned index()
+ {
+ return _index;
+ }
+
+ inline real x()
+ {
+ return _Vector[0];
+ }
+
+ inline real y()
+ {
+ return _Vector[1];
+ }
+
+ inline real z()
+ {
+ return _Vector[2];
+ }
+
+ /*! modifiers */
+ inline void setVector(const Vec3r& iVector)
+ {
+ _Vector = iVector;
+ }
+
+ inline void setIndex(unsigned iIndex)
+ {
+ _index = iIndex;
+ }
+
+ /*! operators */
+ IndexedVertex& operator=(const IndexedVertex& iv)
+ {
+ _Vector = iv._Vector;
+ _index = iv._index;
+ return *this;
+ }
+
+ inline real operator[](const unsigned i)
+ {
+ return _Vector[i];
+ }
+
+ //friend inline bool operator<(const IndexedVertex& iv1, const IndexedVertex& iv2);
+ inline bool operator<(const IndexedVertex& v) const
+ {
+ return (_Vector < v._Vector);
+ }
+
+ inline bool operator==(const IndexedVertex& v)
+ {
+ return (_Vector == v._Vector);
+ }
+};
+
+#if 0
+bool operator<(const IndexedVertex& iv1, const IndexedVertex& iv2)
+{
+ return iv1.operator<(iv2);
+}
+#endif
+
+#endif // __GEOMCLEANER_H__
diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.cpp b/source/blender/freestyle/intern/geometry/GeomUtils.cpp
new file mode 100644
index 00000000000..c0cd9450480
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/GeomUtils.cpp
@@ -0,0 +1,780 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/geometry/GeomUtils.cpp
+ * \ingroup freestyle
+ * \brief Various tools for geometry
+ * \author Stephane Grabli
+ * \date 12/04/2002
+ */
+
+#include "GeomUtils.h"
+
+namespace GeomUtils {
+
+// This internal procedure is defined below.
+bool intersect2dSegPoly(Vec2r* seg, Vec2r* poly, unsigned n);
+
+bool intersect2dSeg2dArea(const Vec2r& min, const Vec2r& max, const Vec2r& A, const Vec2r& B)
+{
+ Vec2r seg[2];
+ seg[0] = A;
+ seg[1] = B;
+
+ Vec2r poly[5];
+ poly[0][0] = min[0];
+ poly[0][1] = min[1];
+ poly[1][0] = max[0];
+ poly[1][1] = min[1];
+ poly[2][0] = max[0];
+ poly[2][1] = max[1];
+ poly[3][0] = min[0];
+ poly[3][1] = max[1];
+ poly[4][0] = min[0];
+ poly[4][1] = min[1];
+
+ return intersect2dSegPoly(seg, poly, 4);
+}
+
+bool include2dSeg2dArea(const Vec2r& min, const Vec2r& max, const Vec2r& A, const Vec2r& B)
+{
+ if ((((max[0] > A[0]) && (A[0] > min[0])) && ((max[0] > B[0]) && (B[0] > min[0]))) &&
+ (((max[1] > A[1]) && (A[1] > min[1])) && ((max[1] > B[1]) && (B[1] > min[1]))))
+ return true;
+ return false;
+}
+
+intersection_test intersect2dSeg2dSeg(const Vec2r& p1, const Vec2r& p2, const Vec2r& p3, const Vec2r& p4, Vec2r& res)
+{
+ real a1, a2, b1, b2, c1, c2; // Coefficients of line eqns
+ real r1, r2, r3, r4; // 'Sign' values
+ real denom, num; // Intermediate values
+
+ // Compute a1, b1, c1, where line joining points p1 and p2 is "a1 x + b1 y + c1 = 0".
+ a1 = p2[1] - p1[1];
+ b1 = p1[0] - p2[0];
+ c1 = p2[0] * p1[1] - p1[0] * p2[1];
+
+ // Compute r3 and r4.
+ r3 = a1 * p3[0] + b1 * p3[1] + c1;
+ r4 = a1 * p4[0] + b1 * p4[1] + c1;
+
+ // Check signs of r3 and r4. If both point 3 and point 4 lie on same side of line 1,
+ // the line segments do not intersect.
+ if ( r3 != 0 && r4 != 0 && r3 * r4 > 0.0)
+ return (DONT_INTERSECT);
+
+ // Compute a2, b2, c2
+ a2 = p4[1] - p3[1];
+ b2 = p3[0] - p4[0];
+ c2 = p4[0] * p3[1] - p3[0] * p4[1];
+
+ // Compute r1 and r2
+ r1 = a2 * p1[0] + b2 * p1[1] + c2;
+ r2 = a2 * p2[0] + b2 * p2[1] + c2;
+
+ // Check signs of r1 and r2. If both point 1 and point 2 lie on same side of second line segment,
+ // the line segments do not intersect.
+ if (r1 != 0 && r2 != 0 && r1 * r2 > 0.0)
+ return (DONT_INTERSECT);
+
+ // Line segments intersect: compute intersection point.
+ denom = a1 * b2 - a2 * b1;
+ if (fabs(denom) < M_EPSILON)
+ return (COLINEAR);
+
+ num = b1 * c2 - b2 * c1;
+ res[0] = num / denom;
+
+ num = a2 * c1 - a1 * c2;
+ res[1] = num / denom;
+
+ return (DO_INTERSECT);
+}
+
+intersection_test intersect2dLine2dLine(const Vec2r& p1, const Vec2r& p2, const Vec2r& p3, const Vec2r& p4, Vec2r& res)
+{
+ real a1, a2, b1, b2, c1, c2; // Coefficients of line eqns
+ real denom, num; // Intermediate values
+
+ // Compute a1, b1, c1, where line joining points p1 and p2 is "a1 x + b1 y + c1 = 0".
+ a1 = p2[1] - p1[1];
+ b1 = p1[0] - p2[0];
+ c1 = p2[0] * p1[1] - p1[0] * p2[1];
+
+ // Compute a2, b2, c2
+ a2 = p4[1] - p3[1];
+ b2 = p3[0] - p4[0];
+ c2 = p4[0] * p3[1] - p3[0] * p4[1];
+
+ // Line segments intersect: compute intersection point.
+ denom = a1 * b2 - a2 * b1;
+ if (fabs(denom) < M_EPSILON)
+ return (COLINEAR);
+
+ num = b1 * c2 - b2 * c1;
+ res[0] = num / denom;
+
+ num = a2 * c1 - a1 * c2;
+ res[1] = num / denom;
+
+ return (DO_INTERSECT);
+}
+
+intersection_test intersect2dSeg2dSegParametric(const Vec2r& p1, const Vec2r& p2, const Vec2r& p3, const Vec2r& p4,
+ real& t, real& u, real epsilon)
+{
+ real a1, a2, b1, b2, c1, c2; // Coefficients of line eqns
+ real r1, r2, r3, r4; // 'Sign' values
+ real denom, num; // Intermediate values
+
+ // Compute a1, b1, c1, where line joining points p1 and p2 is "a1 x + b1 y + c1 = 0".
+ a1 = p2[1] - p1[1];
+ b1 = p1[0] - p2[0];
+ c1 = p2[0] * p1[1] - p1[0] * p2[1];
+
+ // Compute r3 and r4.
+ r3 = a1 * p3[0] + b1 * p3[1] + c1;
+ r4 = a1 * p4[0] + b1 * p4[1] + c1;
+
+ // Check signs of r3 and r4. If both point 3 and point 4 lie on same side of line 1,
+ // the line segments do not intersect.
+ if (r3 != 0 && r4 != 0 && r3 * r4 > 0.0)
+ return (DONT_INTERSECT);
+
+ // Compute a2, b2, c2
+ a2 = p4[1] - p3[1];
+ b2 = p3[0] - p4[0];
+ c2 = p4[0] * p3[1] - p3[0] * p4[1];
+
+ // Compute r1 and r2
+ r1 = a2 * p1[0] + b2 * p1[1] + c2;
+ r2 = a2 * p2[0] + b2 * p2[1] + c2;
+
+ // Check signs of r1 and r2. If both point 1 and point 2 lie on same side of second line segment,
+ // the line segments do not intersect.
+ if (r1 != 0 && r2 != 0 && r1 * r2 > 0.0)
+ return (DONT_INTERSECT);
+
+ // Line segments intersect: compute intersection point.
+ denom = a1 * b2 - a2 * b1;
+ if (fabs(denom) < epsilon)
+ return (COLINEAR);
+
+ real d1, e1;
+
+ d1 = p1[1] - p3[1];
+ e1 = p1[0] - p3[0];
+
+ num = -b2 * d1 - a2 * e1;
+ t = num / denom;
+
+ num = -b1 * d1 - a1 * e1;
+ u = num / denom;
+
+ return (DO_INTERSECT);
+}
+
+// AABB-triangle overlap test code by Tomas Akenine-Möller
+// Function: int triBoxOverlap(real boxcenter[3], real boxhalfsize[3],real triverts[3][3]);
+// History:
+// 2001-03-05: released the code in its first version
+// 2001-06-18: changed the order of the tests, faster
+//
+// Acknowledgement: Many thanks to Pierre Terdiman for suggestions and discussions on how to optimize code.
+// Thanks to David Hunt for finding a ">="-bug!
+
+#define X 0
+#define Y 1
+#define Z 2
+
+#define FINDMINMAX(x0, x1, x2, min, max) \
+ { \
+ min = max = x0; \
+ if (x1 < min) \
+ min = x1; \
+ if (x1 > max) \
+ max = x1; \
+ if (x2 < min) \
+ min = x2; \
+ if (x2 > max) \
+ max = x2; \
+ } (void)0
+
+//======================== X-tests ========================//
+#define AXISTEST_X01(a, b, fa, fb) \
+ { \
+ p0 = a * v0[Y] - b * v0[Z]; \
+ p2 = a * v2[Y] - b * v2[Z]; \
+ if (p0 < p2) { \
+ min = p0; \
+ max = p2; \
+ } \
+ else { \
+ min = p2; \
+ max = p0; \
+ } \
+ rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z]; \
+ if (min > rad || max < -rad) \
+ return 0; \
+ } (void)0
+
+#define AXISTEST_X2(a, b, fa, fb) \
+ { \
+ p0 = a * v0[Y] - b * v0[Z]; \
+ p1 = a * v1[Y] - b * v1[Z]; \
+ if (p0 < p1) { \
+ min = p0; \
+ max = p1; \
+ } \
+ else { \
+ min = p1; \
+ max = p0; \
+ } \
+ rad = fa * boxhalfsize[Y] + fb * boxhalfsize[Z]; \
+ if (min > rad || max < -rad) \
+ return 0; \
+ } (void)0
+
+//======================== Y-tests ========================//
+#define AXISTEST_Y02(a, b, fa, fb) \
+ { \
+ p0 = -a * v0[X] + b * v0[Z]; \
+ p2 = -a * v2[X] + b * v2[Z]; \
+ if (p0 < p2) { \
+ min = p0; \
+ max = p2; \
+ } \
+ else { \
+ min = p2; \
+ max = p0; \
+ } \
+ rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z]; \
+ if (min > rad || max < -rad) \
+ return 0; \
+ } (void)0
+
+#define AXISTEST_Y1(a, b, fa, fb) \
+ { \
+ p0 = -a * v0[X] + b * v0[Z]; \
+ p1 = -a * v1[X] + b * v1[Z]; \
+ if (p0 < p1) { \
+ min = p0; \
+ max = p1; \
+ } \
+ else { \
+ min = p1; \
+ max = p0; \
+ } \
+ rad = fa * boxhalfsize[X] + fb * boxhalfsize[Z]; \
+ if (min > rad || max < -rad) \
+ return 0; \
+ } (void)0
+
+//======================== Z-tests ========================//
+#define AXISTEST_Z12(a, b, fa, fb) \
+ { \
+ p1 = a * v1[X] - b * v1[Y]; \
+ p2 = a * v2[X] - b * v2[Y]; \
+ if (p2 < p1) { \
+ min = p2; \
+ max = p1; \
+ } \
+ else { \
+ min = p1; \
+ max = p2; \
+ } \
+ rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y]; \
+ if (min > rad || max < -rad) \
+ return 0; \
+ } (void)0
+
+#define AXISTEST_Z0(a, b, fa, fb) \
+ { \
+ p0 = a * v0[X] - b * v0[Y]; \
+ p1 = a * v1[X] - b * v1[Y]; \
+ if (p0 < p1) { \
+ min = p0; \
+ max = p1; \
+ } \
+ else { \
+ min = p1; \
+ max = p0; \
+ } \
+ rad = fa * boxhalfsize[X] + fb * boxhalfsize[Y]; \
+ if (min > rad || max < -rad) \
+ return 0; \
+ } (void)0
+
+// This internal procedure is defined below.
+bool overlapPlaneBox(Vec3r& normal, real d, Vec3r& maxbox);
+
+// Use separating axis theorem to test overlap between triangle and box need to test for overlap in these directions:
+// 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle we do not even need to test these)
+// 2) normal of the triangle
+// 3) crossproduct(edge from tri, {x,y,z}-directin) this gives 3x3=9 more tests
+bool overlapTriangleBox(Vec3r& boxcenter, Vec3r& boxhalfsize, Vec3r triverts[3])
+{
+ Vec3r v0, v1, v2, normal, e0, e1, e2;
+ real min, max, d, p0, p1, p2, rad, fex, fey, fez;
+
+ // This is the fastest branch on Sun
+ // move everything so that the boxcenter is in (0, 0, 0)
+ v0 = triverts[0] - boxcenter;
+ v1 = triverts[1] - boxcenter;
+ v2 = triverts[2] - boxcenter;
+
+ // compute triangle edges
+ e0 = v1 - v0;
+ e1 = v2 - v1;
+ e2 = v0 - v2;
+
+ // Bullet 3:
+ // Do the 9 tests first (this was faster)
+ fex = fabs(e0[X]);
+ fey = fabs(e0[Y]);
+ fez = fabs(e0[Z]);
+ AXISTEST_X01(e0[Z], e0[Y], fez, fey);
+ AXISTEST_Y02(e0[Z], e0[X], fez, fex);
+ AXISTEST_Z12(e0[Y], e0[X], fey, fex);
+
+ fex = fabs(e1[X]);
+ fey = fabs(e1[Y]);
+ fez = fabs(e1[Z]);
+ AXISTEST_X01(e1[Z], e1[Y], fez, fey);
+ AXISTEST_Y02(e1[Z], e1[X], fez, fex);
+ AXISTEST_Z0(e1[Y], e1[X], fey, fex);
+
+ fex = fabs(e2[X]);
+ fey = fabs(e2[Y]);
+ fez = fabs(e2[Z]);
+ AXISTEST_X2(e2[Z], e2[Y], fez, fey);
+ AXISTEST_Y1(e2[Z], e2[X], fez, fex);
+ AXISTEST_Z12(e2[Y], e2[X], fey, fex);
+
+ // Bullet 1:
+ // first test overlap in the {x,y,z}-directions
+ // find min, max of the triangle each direction, and test for overlap in that direction -- this is equivalent
+ // to testing a minimal AABB around the triangle against the AABB
+
+ // test in X-direction
+ FINDMINMAX(v0[X], v1[X], v2[X], min, max);
+ if (min > boxhalfsize[X] || max < -boxhalfsize[X])
+ return false;
+
+ // test in Y-direction
+ FINDMINMAX(v0[Y], v1[Y], v2[Y], min, max);
+ if (min > boxhalfsize[Y] || max < -boxhalfsize[Y])
+ return false;
+
+ // test in Z-direction
+ FINDMINMAX(v0[Z], v1[Z], v2[Z], min, max);
+ if (min > boxhalfsize[Z] || max < -boxhalfsize[Z])
+ return false;
+
+ // Bullet 2:
+ // test if the box intersects the plane of the triangle
+ // compute plane equation of triangle: normal * x + d = 0
+ normal = e0 ^ e1;
+ d = -(normal * v0); // plane eq: normal.x + d = 0
+ if (!overlapPlaneBox(normal, d, boxhalfsize))
+ return false;
+
+ return true; // box and triangle overlaps
+}
+
+// Fast, Minimum Storage Ray-Triangle Intersection
+//
+// Tomas Möller
+// Prosolvia Clarus AB
+// Sweden
+// tompa@clarus.se
+//
+// Ben Trumbore
+// Cornell University
+// Ithaca, New York
+// wbt@graphics.cornell.edu
+bool intersectRayTriangle(const Vec3r& orig, const Vec3r& dir, const Vec3r& v0, const Vec3r& v1, const Vec3r& v2,
+ real& t, real& u, real& v, const real epsilon)
+{
+ Vec3r edge1, edge2, tvec, pvec, qvec;
+ real det, inv_det;
+
+ // find vectors for two edges sharing v0
+ edge1 = v1 - v0;
+ edge2 = v2 - v0;
+
+ // begin calculating determinant - also used to calculate U parameter
+ pvec = dir ^ edge2;
+
+ // if determinant is near zero, ray lies in plane of triangle
+ det = edge1 * pvec;
+
+ // calculate distance from v0 to ray origin
+ tvec = orig - v0;
+ inv_det = 1.0 / det;
+
+ qvec = tvec ^ edge1;
+
+ if (det > epsilon) {
+ u = tvec * pvec;
+ if (u < 0.0 || u > det)
+ return false;
+
+ // calculate V parameter and test bounds
+ v = dir * qvec;
+ if (v < 0.0 || u + v > det)
+ return false;
+ }
+ else if (det < -epsilon) {
+ // calculate U parameter and test bounds
+ u = tvec * pvec;
+ if (u > 0.0 || u < det)
+ return false;
+
+ // calculate V parameter and test bounds
+ v = dir * qvec;
+ if (v > 0.0 || u + v < det)
+ return false;
+ }
+ else {
+ return false; // ray is parallell to the plane of the triangle
+ }
+
+ u *= inv_det;
+ v *= inv_det;
+ t = (edge2 * qvec) * inv_det;
+
+ return true;
+}
+
+// Intersection between plane and ray, adapted from Graphics Gems, Didier Badouel
+intersection_test intersectRayPlane(const Vec3r& orig, const Vec3r& dir, const Vec3r& norm, const real d,
+ real& t, const real epsilon)
+{
+ real denom = norm * dir;
+
+ if (fabs(denom) <= epsilon) { // plane and ray are parallel
+ if (fabs((norm * orig) + d) <= epsilon)
+ return COINCIDENT; // plane and ray are coincident
+ else
+ return COLINEAR;
+ }
+
+ t = -(d + (norm * orig)) / denom;
+
+ if (t < 0.0f)
+ return DONT_INTERSECT;
+
+ return DO_INTERSECT;
+}
+
+bool intersectRayBBox(const Vec3r& orig, const Vec3r& dir, // ray origin and direction
+ const Vec3r& boxMin, const Vec3r& boxMax, // the bbox
+ real t0, real t1,
+ real& tmin, // I0 = orig + tmin * dir is the first intersection
+ real& tmax, // I1 = orig + tmax * dir is the second intersection
+ real epsilon)
+{
+ float tymin, tymax, tzmin, tzmax;
+ Vec3r inv_direction(1.0 / dir[0], 1.0 / dir[1], 1.0 / dir[2]);
+ int sign[3];
+ sign[0] = (inv_direction.x() < 0);
+ sign[1] = (inv_direction.y() < 0);
+ sign[2] = (inv_direction.z() < 0);
+
+ Vec3r bounds[2];
+ bounds[0] = boxMin;
+ bounds[1] = boxMax;
+
+ tmin = (bounds[sign[0]].x() - orig.x()) * inv_direction.x();
+ tmax = (bounds[1-sign[0]].x() - orig.x()) * inv_direction.x();
+ tymin = (bounds[sign[1]].y() - orig.y()) * inv_direction.y();
+ tymax = (bounds[1-sign[1]].y() - orig.y()) * inv_direction.y();
+ if ((tmin > tymax) || (tymin > tmax))
+ return false;
+ if (tymin > tmin)
+ tmin = tymin;
+ if (tymax < tmax)
+ tmax = tymax;
+ tzmin = (bounds[sign[2]].z() - orig.z()) * inv_direction.z();
+ tzmax = (bounds[1-sign[2]].z() - orig.z()) * inv_direction.z();
+ if ((tmin > tzmax) || (tzmin > tmax))
+ return false;
+ if (tzmin > tmin)
+ tmin = tzmin;
+ if (tzmax < tmax)
+ tmax = tzmax;
+ return ((tmin < t1) && (tmax > t0));
+}
+
+// Checks whether 3D points p lies inside or outside of the triangle ABC
+bool includePointTriangle(const Vec3r& P, const Vec3r& A, const Vec3r& B, const Vec3r& C)
+{
+ Vec3r AB(B - A);
+ Vec3r BC(C - B);
+ Vec3r CA(A - C);
+ Vec3r AP(P - A);
+ Vec3r BP(P - B);
+ Vec3r CP(P - C);
+
+ Vec3r N(AB ^ BC); // triangle's normal
+
+ N.normalize();
+
+ Vec3r J(AB ^ AP), K(BC ^ BP), L(CA ^ CP);
+ J.normalize();
+ K.normalize();
+ L.normalize();
+
+ if (J * N < 0)
+ return false; // on the right of AB
+
+ if (K * N < 0)
+ return false; // on the right of BC
+
+ if (L * N < 0)
+ return false; // on the right of CA
+
+ return true;
+}
+
+void transformVertex(const Vec3r& vert, const Matrix44r& matrix, Vec3r& res)
+{
+ HVec3r hvert(vert), res_tmp;
+ real scale;
+ for (unsigned int j = 0; j < 4; j++) {
+ scale = hvert[j];
+ for (unsigned int i = 0; i < 4; i++)
+ res_tmp[i] += matrix(i, j) * scale;
+ }
+
+ res[0] = res_tmp.x();
+ res[1] = res_tmp.y();
+ res[2] = res_tmp.z();
+}
+
+void transformVertices(const vector<Vec3r>& vertices, const Matrix44r& trans, vector<Vec3r>& res)
+{
+ for (vector<Vec3r>::const_iterator v = vertices.begin(); v != vertices.end(); v++) {
+ Vec3r *res_tmp = new Vec3r;
+ transformVertex(*v, trans, *res_tmp);
+ res.push_back(*res_tmp);
+ }
+}
+
+Vec3r rotateVector(const Matrix44r& mat, const Vec3r& v) {
+ Vec3r res;
+ for (unsigned int i = 0; i < 3; i++) {
+ res[i] = 0;
+ for (unsigned int j = 0; j < 3; j++)
+ res[i] += mat(i, j) * v[j];
+ }
+ res.normalize();
+ return res;
+}
+
+// This internal procedure is defined below.
+void fromCoordAToCoordB(const Vec3r& p, Vec3r& q, const real transform[4][4]);
+
+void fromWorldToCamera(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4])
+{
+ fromCoordAToCoordB(p, q, model_view_matrix);
+}
+
+void fromCameraToRetina(const Vec3r& p, Vec3r& q, const real projection_matrix[4][4])
+{
+ fromCoordAToCoordB(p, q, projection_matrix);
+}
+
+void fromRetinaToImage(const Vec3r& p, Vec3r& q, const int viewport[4])
+{
+ // winX:
+ q[0] = viewport[0] + viewport[2] * (p[0] + 1.0) / 2.0;
+
+ // winY:
+ q[1] = viewport[1] + viewport[3] * (p[1] + 1.0) / 2.0;
+
+ // winZ:
+ q[2] = (p[2] + 1.0) / 2.0;
+}
+
+void fromWorldToImage(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4],
+ const real projection_matrix[4][4], const int viewport[4])
+{
+ Vec3r p1, p2;
+ fromWorldToCamera(p, p1, model_view_matrix);
+ fromCameraToRetina(p1, p2, projection_matrix);
+ fromRetinaToImage(p2, q, viewport);
+ q[2] = p1[2];
+}
+
+void fromWorldToImage(const Vec3r& p, Vec3r& q, const real transform[4][4], const int viewport[4])
+{
+ fromCoordAToCoordB(p, q, transform);
+
+ // winX:
+ q[0] = viewport[0] + viewport[2] * (q[0] + 1.0) / 2.0;
+
+ //winY:
+ q[1] = viewport[1] + viewport[3] * (q[1] + 1.0) / 2.0;
+}
+
+void fromImageToRetina(const Vec3r& p, Vec3r& q, const int viewport[4])
+{
+ q = p;
+ q[0] = 2.0 * (q[0] - viewport[0]) / viewport[2] - 1.0;
+ q[1] = 2.0 * (q[1] - viewport[1]) / viewport[3] - 1.0;
+}
+
+void fromRetinaToCamera(const Vec3r& p, Vec3r& q, real focal, const real projection_matrix[4][4])
+{
+ if (projection_matrix[3][3] == 0.0) { // perspective
+ q[0] = (-p[0] * focal) / projection_matrix[0][0];
+ q[1] = (-p[1] * focal) / projection_matrix[1][1];
+ q[2] = focal;
+ }
+ else { // orthogonal
+ q[0] = p[0] / projection_matrix[0][0];
+ q[1] = p[1] / projection_matrix[1][1];
+ q[2] = focal;
+ }
+}
+
+void fromCameraToWorld(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4])
+{
+ real translation[3] = {
+ model_view_matrix[0][3],
+ model_view_matrix[1][3],
+ model_view_matrix[2][3]
+ };
+ for (unsigned short i = 0; i < 3; i++) {
+ q[i] = 0.0;
+ for (unsigned short j = 0; j < 3; j++)
+ q[i] += model_view_matrix[j][i] * (p[j] - translation[j]);
+ }
+}
+
+
+//
+// Internal code
+//
+/////////////////////////////////////////////////////////////////////////////
+
+// Copyright 2001, softSurfer (www.softsurfer.com)
+// This code may be freely used and modified for any purpose providing that this copyright notice is included with it.
+// SoftSurfer makes no warranty for this code, and cannot be held liable for any real or imagined damage resulting
+// from its use.
+// Users of this code must verify correctness for their application.
+
+#define PERP(u, v) ((u)[0] * (v)[1] - (u)[1] * (v)[0]) // 2D perp product
+
+inline bool intersect2dSegPoly(Vec2r* seg, Vec2r* poly, unsigned n)
+{
+ if (seg[0] == seg[1])
+ return false;
+
+ real tE = 0; // the maximum entering segment parameter
+ real tL = 1; // the minimum leaving segment parameter
+ real t, N, D; // intersect parameter t = N / D
+ Vec2r dseg = seg[1] - seg[0]; // the segment direction vector
+ Vec2r e; // edge vector
+
+ for (unsigned int i = 0; i < n; i++) { // process polygon edge poly[i]poly[i+1]
+ e = poly[i+1] - poly[i];
+ N = PERP(e, seg[0] - poly[i]);
+ D = -PERP(e, dseg);
+ if (fabs(D) < M_EPSILON) {
+ if (N < 0)
+ return false;
+ else
+ continue;
+ }
+
+ t = N / D;
+ if (D < 0) { // segment seg is entering across this edge
+ if (t > tE) { // new max tE
+ tE = t;
+ if (tE > tL) // seg enters after leaving polygon
+ return false;
+ }
+ }
+ else { // segment seg is leaving across this edge
+ if (t < tL) { // new min tL
+ tL = t;
+ if (tL < tE) // seg leaves before entering polygon
+ return false;
+ }
+ }
+ }
+
+ // tE <= tL implies that there is a valid intersection subsegment
+ return true;
+}
+
+inline bool overlapPlaneBox(Vec3r& normal, real d, Vec3r& maxbox)
+{
+ Vec3r vmin, vmax;
+
+ for (unsigned int q = X; q <= Z; q++) {
+ if (normal[q] > 0.0f) {
+ vmin[q] = -maxbox[q];
+ vmax[q] = maxbox[q];
+ }
+ else {
+ vmin[q] = maxbox[q];
+ vmax[q] = -maxbox[q];
+ }
+ }
+ if ((normal * vmin) + d > 0.0f)
+ return false;
+ if ((normal * vmax) + d >= 0.0f)
+ return true;
+ return false;
+}
+
+inline void fromCoordAToCoordB(const Vec3r&p, Vec3r& q, const real transform[4][4])
+{
+ HVec3r hp(p);
+ HVec3r hq(0, 0, 0, 0);
+
+ for (unsigned int i = 0; i < 4; i++) {
+ for (unsigned int j = 0; j < 4; j++) {
+ hq[i] += transform[i][j] * hp[j];
+ }
+ }
+
+ if (hq[3] == 0) {
+ q = p;
+ return;
+ }
+
+ for (unsigned int k = 0; k < 3; k++)
+ q[k] = hq[k] / hq[3];
+}
+
+} // end of namespace GeomUtils
diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.h b/source/blender/freestyle/intern/geometry/GeomUtils.h
new file mode 100644
index 00000000000..1b90f99c2ed
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/GeomUtils.h
@@ -0,0 +1,277 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __GEOMUTILS_H__
+#define __GEOMUTILS_H__
+
+/** \file blender/freestyle/intern/geometry/GeomUtils.h
+ * \ingroup freestyle
+ * \brief Various tools for geometry
+ * \author Stephane Grabli
+ * \date 12/04/2002
+ */
+
+#include <vector>
+
+#include "Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace std;
+using namespace Geometry;
+
+namespace GeomUtils {
+
+//
+// Templated procedures
+//
+/////////////////////////////////////////////////////////////////////////////
+
+/*! Computes the distance from a point P to a segment AB */
+template<class T>
+real distPointSegment( const T& P, const T& A , const T& B)
+{
+ T AB, AP, BP;
+ AB = B - A;
+ AP = P - A;
+ BP = P - B;
+
+ real c1(AB * AP);
+ if (c1 <= 0)
+ return AP.norm();
+
+ real c2(AB * AB);
+ if (c2 <= c1)
+ return BP.norm();
+
+ real b = c1 / c2;
+ T Pb, PPb;
+ Pb = A + b * AB;
+ PPb = P - Pb;
+
+ return PPb.norm();
+}
+
+//
+// Non-templated procedures
+//
+/////////////////////////////////////////////////////////////////////////////
+typedef enum {
+ DONT_INTERSECT,
+ DO_INTERSECT,
+ COLINEAR,
+ COINCIDENT,
+} intersection_test;
+
+LIB_GEOMETRY_EXPORT
+intersection_test intersect2dSeg2dSeg(const Vec2r& p1, const Vec2r& p2, // first segment
+ const Vec2r& p3, const Vec2r& p4, // second segment
+ Vec2r& res); // found intersection point
+
+LIB_GEOMETRY_EXPORT
+intersection_test intersect2dLine2dLine(const Vec2r& p1, const Vec2r& p2, // first segment
+ const Vec2r& p3, const Vec2r& p4, // second segment
+ Vec2r& res); // found intersection point
+
+LIB_GEOMETRY_EXPORT
+intersection_test intersect2dSeg2dSegParametric(const Vec2r& p1, const Vec2r& p2, // first segment
+ const Vec2r& p3, const Vec2r& p4, // second segment
+ real& t, // I = P1 + t * P1P2)
+ real& u, // I = P3 + u * P3P4
+ real epsilon = M_EPSILON);
+
+/*! check whether a 2D segment intersect a 2D region or not */
+LIB_GEOMETRY_EXPORT
+bool intersect2dSeg2dArea(const Vec2r& min, const Vec2r& max, const Vec2r& A, const Vec2r& B);
+
+/*! check whether a 2D segment is included in a 2D region or not */
+LIB_GEOMETRY_EXPORT
+bool include2dSeg2dArea(const Vec2r& min, const Vec2r& max, const Vec2r& A, const Vec2r& B);
+
+/*! Box-triangle overlap test, adapted from Tomas Akenine-Möller code */
+LIB_GEOMETRY_EXPORT
+bool overlapTriangleBox(Vec3r& boxcenter, Vec3r& boxhalfsize, Vec3r triverts[3]);
+
+/*! Fast, Minimum Storage Ray-Triangle Intersection, adapted from Tomas Möller and Ben Trumbore code. */
+LIB_GEOMETRY_EXPORT
+bool intersectRayTriangle(const Vec3r& orig, const Vec3r& dir, const Vec3r& v0, const Vec3r& v1, const Vec3r& v2,
+ real& t, // I = orig + t * dir
+ real& u, real& v, // I = (1 - u - v) * v0 + u * v1 + v * v2
+ const real epsilon = M_EPSILON); // the epsilon to use
+
+/*! Intersection between plane and ray adapted from Graphics Gems, Didier Badouel */
+LIB_GEOMETRY_EXPORT
+intersection_test intersectRayPlane(const Vec3r& orig, const Vec3r& dir, // ray origin and direction
+ // plane's normal and offset (plane = { P / P.N + d = 0 })
+ const Vec3r& norm, const real d,
+ real& t, // I = orig + t * dir
+ const real epsilon = M_EPSILON); // the epsilon to use
+
+/*! Intersection Ray-Bounding box (axis aligned).
+ * Adapted from Williams et al, "An Efficient Robust Ray-Box Intersection Algorithm", JGT 10:1 (2005), pp. 49-54.
+ */
+LIB_GEOMETRY_EXPORT
+bool intersectRayBBox(const Vec3r& orig, const Vec3r& dir, // ray origin and direction
+ const Vec3r& boxMin, const Vec3r& boxMax, // the bbox
+ // the interval in which at least on of the intersections must happen
+ real t0, real t1,
+ real& tmin, // Imin = orig + tmin * dir is the first intersection
+ real& tmax, // Imax = orig + tmax * dir is the second intersection
+ real epsilon = M_EPSILON); // the epsilon to use
+
+/*! Checks whether 3D point P lies inside or outside of the triangle ABC */
+LIB_GEOMETRY_EXPORT
+bool includePointTriangle(const Vec3r& P, const Vec3r& A, const Vec3r& B, const Vec3r& C);
+
+LIB_GEOMETRY_EXPORT
+void transformVertex(const Vec3r& vert, const Matrix44r& matrix, Vec3r& res);
+
+LIB_GEOMETRY_EXPORT
+void transformVertices(const vector<Vec3r>& vertices, const Matrix44r& trans, vector<Vec3r>& res);
+
+LIB_GEOMETRY_EXPORT
+Vec3r rotateVector(const Matrix44r& mat, const Vec3r& v);
+
+//
+// Coordinates systems changing procedures
+//
+/////////////////////////////////////////////////////////////////////////////
+
+/*! From world to image
+ * p
+ * point's coordinates expressed in world coordinates system
+ * q
+ * vector in which the result will be stored
+ * model_view_matrix
+ * The model view matrix expressed in line major order (OpenGL
+ * matrices are column major ordered)
+ * projection_matrix
+ * The projection matrix expressed in line major order (OpenGL
+ * matrices are column major ordered)
+ * viewport
+ * The viewport: x,y coordinates followed by width and height (OpenGL like viewport)
+ */
+LIB_GEOMETRY_EXPORT
+void fromWorldToImage(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4], const real projection_matrix[4][4],
+ const int viewport[4]);
+
+/*! From world to image
+ * p
+ * point's coordinates expressed in world coordinates system
+ * q
+ * vector in which the result will be stored
+ * transform
+ * The transformation matrix (gathering model view and projection),
+ * expressed in line major order (OpenGL matrices are column major ordered)
+ * viewport
+ * The viewport: x,y coordinates followed by width and height (OpenGL like viewport)
+ */
+LIB_GEOMETRY_EXPORT
+void fromWorldToImage(const Vec3r& p, Vec3r& q, const real transform[4][4], const int viewport[4]);
+
+/*! Projects from world coordinates to camera coordinates
+ * Returns the point's coordinates expressed in the camera's
+ * coordinates system.
+ * p
+ * point's coordinates expressed in world coordinates system
+ * q
+ * vector in which the result will be stored
+ * model_view_matrix
+ * The model view matrix expressed in line major order (OpenGL
+ * matrices are column major ordered)
+ */
+LIB_GEOMETRY_EXPORT
+void fromWorldToCamera(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4]);
+
+/*! Projects from World Coordinates to retina coordinates
+ * Returns the point's coordinates expressed in Retina system.
+ * p
+ * point's coordinates expressed in camera system
+ * q
+ * vector in which the result will be stored
+ * projection_matrix
+ * The projection matrix expressed in line major order (OpenGL
+ * matrices are column major ordered)
+ */
+LIB_GEOMETRY_EXPORT
+void fromCameraToRetina(const Vec3r& p, Vec3r& q, const real projection_matrix[4][4]);
+
+/*! From retina to image.
+ * Returns the coordinates expressed in Image coorinates system.
+ * p
+ * point's coordinates expressed in retina system
+ * q
+ * vector in which the result will be stored
+ * viewport
+ * The viewport: x,y coordinates followed by width and height (OpenGL like viewport).
+ */
+LIB_GEOMETRY_EXPORT
+void fromRetinaToImage(const Vec3r& p, Vec3r& q, const int viewport[4]);
+
+/*! From image to retina
+ * p
+ * point's coordinates expressed in image system
+ * q
+ * vector in which the result will be stored
+ * viewport
+ * The viewport: x,y coordinates followed by width and height (OpenGL like viewport).
+ */
+LIB_GEOMETRY_EXPORT
+void fromImageToRetina(const Vec3r& p, Vec3r& q, const int viewport[4]);
+
+/*! computes the coordinates of q in the camera coordinates system,
+ * using the known z coordinates of the 3D point.
+ * That means that this method does not inverse any matrices,
+ * it only computes X and Y from x,y and Z)
+ * p
+ * point's coordinates expressed in retina system
+ * q
+ * vector in which the result will be stored
+ * projection_matrix
+ * The projection matrix expressed in line major order (OpenGL
+ * matrices are column major ordered)
+ */
+LIB_GEOMETRY_EXPORT
+void fromRetinaToCamera(const Vec3r& p, Vec3r& q, real z, const real projection_matrix[4][4]);
+
+/*! Projects from camera coordinates to world coordinates
+ * Returns the point's coordinates expressed in the world's
+ * coordinates system.
+ * p
+ * point's coordinates expressed in the camera coordinates system
+ * q
+ * vector in which the result will be stored
+ * model_view_matrix
+ * The model view matrix expressed in line major order (OpenGL
+ * matrices are column major ordered)
+ */
+LIB_GEOMETRY_EXPORT
+void fromCameraToWorld(const Vec3r& p, Vec3r& q, const real model_view_matrix[4][4]);
+
+} // end of namespace GeomUtils
+
+#endif // __GEOMUTILS_H__
diff --git a/source/blender/freestyle/intern/geometry/Grid.cpp b/source/blender/freestyle/intern/geometry/Grid.cpp
new file mode 100644
index 00000000000..11c4f11b281
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/Grid.cpp
@@ -0,0 +1,390 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/geometry/Grid.cpp
+ * \ingroup freestyle
+ * \brief Base class to define a cell grid surrounding the bounding box of the scene
+ * \author Stephane Grabli
+ * \date 30/07/2002
+ */
+
+#include <cassert>
+#include <stdexcept>
+
+#include "BBox.h"
+#include "Grid.h"
+
+// Grid Visitors
+/////////////////
+void allOccludersGridVisitor::examineOccluder(Polygon3r *occ)
+{
+ occluders_.push_back(occ);
+}
+
+static bool inBox(const Vec3r& inter, const Vec3r& box_min, const Vec3r& box_max)
+{
+ if (((inter.x() >= box_min.x()) && (inter.x() < box_max.x())) &&
+ ((inter.y() >= box_min.y()) && (inter.y() < box_max.y())) &&
+ ((inter.z() >= box_min.z()) && (inter.z() < box_max.z())))
+ {
+ return true;
+ }
+ return false;
+}
+
+void firstIntersectionGridVisitor::examineOccluder(Polygon3r *occ)
+{
+ // check whether the edge and the polygon plane are coincident:
+ //-------------------------------------------------------------
+ //first let us compute the plane equation.
+ Vec3r v1(((occ)->getVertices())[0]);
+ Vec3d normal((occ)->getNormal());
+ //soc unused - double d = -(v1 * normal);
+
+ double tmp_u, tmp_v, tmp_t;
+ if ((occ)->rayIntersect(ray_org_, ray_dir_, tmp_t, tmp_u, tmp_v)) {
+ if (fabs(ray_dir_ * normal) > 0.0001) {
+ // Check whether the intersection is in the cell:
+ if (inBox(ray_org_ + tmp_t * ray_dir_ / ray_dir_.norm(), current_cell_->getOrigin(),
+ current_cell_->getOrigin() + cell_size_))
+ {
+#if 0
+ Vec3d bboxdiag(_scene3d->bbox().getMax() - _scene3d->bbox().getMin());
+ if ((t > 1.0e-06 * (min(min(bboxdiag.x(), bboxdiag.y()), bboxdiag.z()))) && (t < raylength)) {
+#else
+ if (tmp_t < t_) {
+#endif
+ occluder_ = occ;
+ u_ = tmp_u;
+ v_ = tmp_v;
+ t_ = tmp_t;
+ }
+ }
+ else {
+ occ->userdata2 = 0;
+ }
+ }
+ }
+}
+
+bool firstIntersectionGridVisitor::stop()
+{
+ if (occluder_)
+ return true;
+ return false;
+}
+
+// Grid
+/////////////////
+void Grid::clear()
+{
+ if (_occluders.size() != 0) {
+ for (OccludersSet::iterator it = _occluders.begin(); it != _occluders.end(); it++) {
+ delete (*it);
+ }
+ _occluders.clear();
+ }
+
+ _size = Vec3r(0, 0, 0);
+ _cell_size = Vec3r(0, 0, 0);
+ _orig = Vec3r(0, 0, 0);
+ _cells_nb = Vec3u(0, 0, 0);
+ //_ray_occluders.clear();
+}
+
+void Grid::configure(const Vec3r& orig, const Vec3r& size, unsigned nb)
+{
+ _orig = orig;
+ Vec3r tmpSize = size;
+ // Compute the volume of the desired grid
+ real grid_vol = size[0] * size[1] * size[2];
+
+ if (grid_vol == 0) {
+ double min = DBL_MAX;
+ int index = 0;
+ int nzeros = 0;
+ for (int i = 0; i < 3; ++i) {
+ if (size[i] == 0) {
+ ++nzeros;
+ index = i;
+ }
+ if ((size[i] != 0) && (min > size[i])) {
+ min = size[i];
+ }
+ }
+ if (nzeros > 1) {
+ throw std::runtime_error("Warning: the 3D grid has more than one null dimension");
+ }
+ tmpSize[index] = min;
+ _orig[index] = _orig[index] - min / 2;
+ }
+ // Compute the desired volume of a single cell
+ real cell_vol = grid_vol / nb;
+ // The edge of such a cubic cell is cubic root of cellVolume
+ real edge = pow(cell_vol, 1.0 / 3.0);
+
+ // We compute the number of cells par edge such as we cover at least the whole box.
+ unsigned i;
+ for (i = 0; i < 3; i++)
+ _cells_nb[i] = (unsigned)floor(tmpSize[i] / edge) + 1;
+
+ _size = tmpSize;
+
+ for (i = 0; i < 3; i++)
+ _cell_size[i] = _size[i] / _cells_nb[i];
+}
+
+void Grid::insertOccluder(Polygon3r* occluder)
+{
+ const vector<Vec3r> vertices = occluder->getVertices();
+ if (vertices.size() == 0)
+ return;
+
+ // add this occluder to the grid's occluders list
+ addOccluder(occluder);
+
+ // find the bbox associated to this polygon
+ Vec3r min, max;
+ occluder->getBBox(min, max);
+
+ // Retrieve the cell x, y, z cordinates associated with these min and max
+ Vec3u imax, imin;
+ getCellCoordinates(max, imax);
+ getCellCoordinates(min, imin);
+
+ // We are now going to fill in the cells overlapping with the polygon bbox.
+ // If the polygon is a triangle (most of cases), we also check for each of these cells if it is overlapping with
+ // the triangle in order to only fill in the ones really overlapping the triangle.
+
+ unsigned i, x, y, z;
+ vector<Vec3r>::const_iterator it;
+ Vec3u coord;
+
+ if (vertices.size() == 3) { // Triangle case
+ Vec3r triverts[3];
+ i = 0;
+ for (it = vertices.begin(); it != vertices.end(); it++) {
+ triverts[i] = Vec3r(*it);
+ i++;
+ }
+
+ Vec3r boxmin, boxmax;
+
+ for (z = imin[2]; z <= imax[2]; z++) {
+ for (y = imin[1]; y <= imax[1]; y++) {
+ for (x = imin[0]; x <= imax[0]; x++) {
+ coord[0] = x;
+ coord[1] = y;
+ coord[2] = z;
+ // We retrieve the box coordinates of the current cell
+ getCellBox(coord, boxmin, boxmax);
+ // We check whether the triangle and the box ovewrlap:
+ Vec3r boxcenter((boxmin + boxmax) / 2.0);
+ Vec3r boxhalfsize(_cell_size / 2.0);
+ if (GeomUtils::overlapTriangleBox(boxcenter, boxhalfsize, triverts)) {
+ // We must then create the Cell and add it to the cells list if it does not exist yet.
+ // We must then add the occluder to the occluders list of this cell.
+ Cell* cell = getCell(coord);
+ if (!cell) {
+ cell = new Cell(boxmin);
+ fillCell(coord, *cell);
+ }
+ cell->addOccluder(occluder);
+ }
+ }
+ }
+ }
+ }
+ else { // The polygon is not a triangle, we add all the cells overlapping the polygon bbox.
+ for (z = imin[2]; z <= imax[2]; z++) {
+ for (y = imin[1]; y <= imax[1]; y++) {
+ for (x = imin[0]; x <= imax[0]; x++) {
+ coord[0] = x;
+ coord[1] = y;
+ coord[2] = z;
+ Cell* cell = getCell(coord);
+ if (!cell) {
+ Vec3r orig;
+ getCellOrigin(coord, orig);
+ cell = new Cell(orig);
+ fillCell(coord, *cell);
+ }
+ cell->addOccluder(occluder);
+ }
+ }
+ }
+ }
+}
+
+bool Grid::nextRayCell(Vec3u& current_cell, Vec3u& next_cell)
+{
+ next_cell = current_cell;
+ real t_min, t;
+ unsigned i;
+
+ t_min = FLT_MAX; // init tmin with handle of the case where one or 2 _u[i] = 0.
+ unsigned coord = 0; // predominant coord(0=x, 1=y, 2=z)
+
+
+ // using a parametric equation of a line : B = A + t u, we find the tx, ty and tz respectively coresponding
+ // to the intersections with the plans:
+ // x = _cell_size[0], y = _cell_size[1], z = _cell_size[2]
+ for (i = 0; i < 3; i++) {
+ if (_ray_dir[i] == 0)
+ continue;
+ if (_ray_dir[i] > 0)
+ t = (_cell_size[i] - _pt[i]) / _ray_dir[i];
+ else
+ t = -_pt[i] / _ray_dir[i];
+ if (t < t_min) {
+ t_min = t;
+ coord = i;
+ }
+ }
+
+ // We use the parametric line equation and the found t (tamx) to compute the B coordinates:
+ Vec3r pt_tmp(_pt);
+ _pt = pt_tmp + t_min * _ray_dir;
+
+ // We express B coordinates in the next cell coordinates system. We just have to
+ // set the coordinate coord of B to 0 of _CellSize[coord] depending on the sign of _u[coord]
+ if (_ray_dir[coord] > 0) {
+ next_cell[coord]++;
+ _pt[coord] -= _cell_size[coord];
+ // if we are out of the grid, we must stop
+ if (next_cell[coord] >= _cells_nb[coord])
+ return false;
+ }
+ else {
+ int tmp = next_cell[coord] - 1;
+ _pt[coord] = _cell_size[coord];
+ if (tmp < 0)
+ return false;
+ next_cell[coord]--;
+ }
+
+ _t += t_min;
+ if (_t >= _t_end)
+ return false;
+
+ return true;
+}
+
+void Grid::castRay(const Vec3r& orig, const Vec3r& end, OccludersSet& occluders, unsigned timestamp)
+{
+ initRay(orig, end, timestamp);
+ allOccludersGridVisitor visitor(occluders);
+ castRayInternal(visitor);
+}
+
+void Grid::castInfiniteRay(const Vec3r& orig, const Vec3r& dir, OccludersSet& occluders, unsigned timestamp)
+{
+ Vec3r end = Vec3r(orig + FLT_MAX * dir / dir.norm());
+ bool inter = initInfiniteRay(orig, dir, timestamp);
+ if (!inter)
+ return;
+ allOccludersGridVisitor visitor(occluders);
+ castRayInternal(visitor);
+}
+
+Polygon3r* Grid::castRayToFindFirstIntersection(const Vec3r& orig, const Vec3r& dir, double& t,
+ double& u, double& v, unsigned timestamp)
+{
+ Polygon3r *occluder = 0;
+ Vec3r end = Vec3r(orig + FLT_MAX * dir / dir.norm());
+ bool inter = initInfiniteRay(orig, dir, timestamp);
+ if (!inter) {
+ return 0;
+ }
+ firstIntersectionGridVisitor visitor(orig, dir, _cell_size);
+ castRayInternal(visitor);
+ // ARB: This doesn't work, because occluders are unordered within any cell
+ // visitor.occluder() will be an occluder, but we have no guarantee it will be the *first* occluder.
+ // I assume that is the reason this code is not actually used for FindOccludee.
+ occluder = visitor.occluder();
+ t = visitor.t_;
+ u = visitor.u_;
+ v = visitor.v_;
+ return occluder;
+}
+
+void Grid::initRay (const Vec3r &orig, const Vec3r& end, unsigned timestamp)
+{
+ _ray_dir = end - orig;
+ _t_end = _ray_dir.norm();
+ _t = 0;
+ _ray_dir.normalize();
+ _timestamp = timestamp;
+
+ for (unsigned i = 0; i < 3; i++) {
+ _current_cell[i] = (unsigned)floor((orig[i] - _orig[i]) / _cell_size[i]);
+ //soc unused - unsigned u = _current_cell[i];
+ _pt[i] = orig[i] - _orig[i] - _current_cell[i] * _cell_size[i];
+ }
+ //_ray_occluders.clear();
+}
+
+bool Grid::initInfiniteRay (const Vec3r &orig, const Vec3r& dir, unsigned timestamp) {
+ _ray_dir = dir;
+ _t_end = FLT_MAX;
+ _t = 0;
+ _ray_dir.normalize();
+ _timestamp = timestamp;
+
+ // check whether the origin is in or out the box:
+ Vec3r boxMin(_orig);
+ Vec3r boxMax(_orig + _size);
+ BBox<Vec3r> box(boxMin, boxMax);
+ if (box.inside(orig)) {
+ for (unsigned int i = 0; i < 3; i++) {
+ _current_cell[i] = (unsigned int)floor((orig[i] - _orig[i]) / _cell_size[i]);
+ //soc unused - unsigned u = _current_cell[i];
+ _pt[i] = orig[i] - _orig[i] - _current_cell[i] * _cell_size[i];
+ }
+ }
+ else {
+ // is the ray intersecting the box?
+ real tmin(-1.0), tmax(-1.0);
+ if (GeomUtils::intersectRayBBox(orig, _ray_dir, boxMin, boxMax, 0, _t_end, tmin, tmax)) {
+ assert(tmin != -1.0);
+ Vec3r newOrig = orig + tmin * _ray_dir;
+ for (unsigned int i = 0; i < 3; i++) {
+ _current_cell[i] = (unsigned)floor((newOrig[i] - _orig[i]) / _cell_size[i]);
+ if (_current_cell[i] == _cells_nb[i])
+ _current_cell[i] = _cells_nb[i] - 1;
+ //soc unused - unsigned u = _current_cell[i];
+ _pt[i] = newOrig[i] - _orig[i] - _current_cell[i] * _cell_size[i];
+ }
+ }
+ else {
+ return false;
+ }
+ }
+ //_ray_occluders.clear();
+
+ return true;
+}
diff --git a/source/blender/freestyle/intern/geometry/Grid.h b/source/blender/freestyle/intern/geometry/Grid.h
new file mode 100644
index 00000000000..8b237673b8a
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/Grid.h
@@ -0,0 +1,384 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __GRID_H__
+#define __GRID_H__
+
+/** \file blender/freestyle/intern/geometry/Grid.h
+ * \ingroup freestyle
+ * \brief Base class to define a cell grid surrounding the bounding box of the scene
+ * \author Stephane Grabli
+ * \date 30/07/2002
+ */
+
+#include <cstring> // for memset
+#include <float.h>
+#ifndef _MSC_VER
+#include <stdint.h> // For SET_UINT_IN_POINTER, i.e. uintptr_t.
+#endif
+#include <vector>
+
+#include "Geom.h"
+#include "GeomUtils.h"
+#include "Polygon.h"
+
+#include "../system/FreestyleConfig.h"
+
+extern "C" {
+ #include "BLI_utildefines.h"
+}
+
+using namespace std;
+using namespace Geometry;
+
+typedef vector<Polygon3r*> OccludersSet;
+
+//
+// Class to define cells used by the regular grid
+//
+///////////////////////////////////////////////////////////////////////////////
+
+class LIB_GEOMETRY_EXPORT Cell
+{
+public:
+ Cell(Vec3r& orig) {
+ _orig = orig;
+ }
+
+ virtual ~Cell() {}
+
+ inline void addOccluder(Polygon3r* o) {
+ if (o)
+ _occluders.push_back(o);
+ }
+
+ inline const Vec3r& getOrigin() {
+ return _orig;
+ }
+
+ inline OccludersSet& getOccluders() {
+ return _occluders;
+ }
+
+private:
+ Vec3r _orig;
+ OccludersSet _occluders;
+};
+
+
+class GridVisitor
+{
+public:
+ virtual ~GridVisitor() {}; //soc
+
+ virtual void discoverCell(Cell *cell) {}
+
+ virtual void examineOccluder(Polygon3r *occ) {}
+
+ virtual void finishCell(Cell *cell) {}
+
+ virtual bool stop() {
+ return false;
+ }
+};
+
+/*! Gathers all the occluders belonging to the cells traversed by the ray */
+class allOccludersGridVisitor : public GridVisitor
+{
+public:
+ allOccludersGridVisitor(OccludersSet& occluders) : GridVisitor(), occluders_(occluders) {}
+
+ virtual void examineOccluder(Polygon3r *occ);
+
+ OccludersSet& occluders() {
+ return occluders_;
+ }
+
+ void clear() {
+ occluders_.clear();
+ }
+
+private:
+ OccludersSet& occluders_;
+};
+
+/*! Finds the first intersection and breaks.
+ * The occluder and the intersection information are stored and accessible.
+ */
+class firstIntersectionGridVisitor : public GridVisitor
+{
+//soc - changed order to remove warnings
+public:
+ double u_, v_, t_;
+
+private:
+ Polygon3r *occluder_;
+ Vec3r ray_org_, ray_dir_, cell_size_;
+ Cell *current_cell_;
+
+public:
+ firstIntersectionGridVisitor(const Vec3r& ray_org, const Vec3r& ray_dir, const Vec3r& cell_size) :
+ GridVisitor(), u_(0),v_(0),t_(DBL_MAX), occluder_(0), ray_org_(ray_org), ray_dir_(ray_dir),
+ cell_size_(cell_size), current_cell_(0)
+ {
+ }
+
+ virtual ~firstIntersectionGridVisitor() {}
+
+ virtual void discoverCell(Cell *cell) {
+ current_cell_ = cell;
+ }
+
+ virtual void examineOccluder(Polygon3r *occ);
+
+ virtual bool stop();
+
+ Polygon3r *occluder() {
+ return occluder_;
+ }
+};
+
+//
+// Class to define a regular grid used for ray casting computations
+//
+///////////////////////////////////////////////////////////////////////////////
+
+class LIB_GEOMETRY_EXPORT Grid
+{
+public:
+ /*! Builds a Grid. Must be followed by a call to configure() */
+ Grid() {}
+
+ virtual ~Grid() {
+ clear();
+ }
+
+ /*! clears the grid
+ * Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells.
+ */
+ virtual void clear();
+
+ /*! Sets the different parameters of the grid
+ * orig
+ * The grid origin
+ * size
+ * The grid's dimensions
+ * nb
+ * The number of cells of the grid
+ */
+ virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb);
+
+ /*! returns a vector of integer containing the coordinates of the cell containing the point passed as argument
+ * p
+ * The point for which we're looking the cell
+ */
+ inline void getCellCoordinates(const Vec3r& p, Vec3u& res) {
+ int tmp;
+ for (int i = 0; i < 3; i++) {
+ tmp = (int)((p[i] - _orig[i]) / _cell_size[i]);
+ if (tmp < 0)
+ res[i] = 0;
+ else if ((unsigned int)tmp >= _cells_nb[i])
+ res[i] = _cells_nb[i] - 1;
+ else
+ res[i] = tmp;
+ }
+ }
+
+ /*! Fills the case corresponding to coord with the cell */
+ virtual void fillCell(const Vec3u& coord, Cell& cell) = 0;
+
+ /*! returns the cell whose coordinates are pased as argument */
+ virtual Cell* getCell(const Vec3u& coord) = 0;
+
+ /*! returns the cell containing the point passed as argument. If the cell is empty (contains no occluder),
+ * NULL is returned
+ * p
+ * The point for which we're looking the cell
+ */
+ inline Cell* getCell(const Vec3r& p) {
+ Vec3u coord;
+ getCellCoordinates(p, coord);
+ return getCell(coord);
+ }
+
+ /*! Retrieves the x,y,z coordinates of the origin of the cell whose coordinates (i,j,k) is passed as argument
+ * cell_coord
+ * i,j,k integer coordinates for the cell
+ * orig
+ * x,y,x vector to be filled in with the cell origin's coordinates
+ */
+ inline void getCellOrigin(const Vec3u& cell_coord, Vec3r& orig) {
+ for (unsigned int i = 0; i < 3; i++)
+ orig[i] = _orig[i] + cell_coord[i] * _cell_size[i];
+ }
+
+ /*! Retrieves the box corresponding to the cell whose coordinates are passed as argument.
+ * cell_coord
+ * i,j,k integer coordinates for the cell
+ * min_out
+ * The min x,y,x vector of the box. Filled in by the method.
+ * max_out
+ * The max x,y,z coordinates of the box. Filled in by the method.
+ */
+ inline void getCellBox(const Vec3u& cell_coord, Vec3r& min_out, Vec3r& max_out) {
+ getCellOrigin(cell_coord, min_out);
+ max_out = min_out + _cell_size;
+ }
+
+ /*! inserts a convex polygon occluder
+ * This method is quite coarse insofar as it adds all cells intersecting the polygon bounding box
+ * convex_poly
+ * The list of 3D points constituing a convex polygon
+ */
+ void insertOccluder(Polygon3r * convex_poly);
+
+ /*! Adds an occluder to the list of occluders */
+ void addOccluder(Polygon3r* occluder) {
+ _occluders.push_back(occluder);
+ }
+
+ /*! Casts a ray between a starting point and an ending point
+ * Returns the list of occluders contained in the cells intersected by this ray
+ * Starts with a call to InitRay.
+ */
+ void castRay(const Vec3r& orig, const Vec3r& end, OccludersSet& occluders, unsigned timestamp);
+
+ // Prepares to cast ray without generating OccludersSet
+ void initAcceleratedRay(const Vec3r& orig, const Vec3r& end, unsigned timestamp);
+
+ /*! Casts an infinite ray (still finishing at the end of the grid) from a starting point and in a given direction.
+ * Returns the list of occluders contained in the cells intersected by this ray
+ * Starts with a call to InitRay.
+ */
+ void castInfiniteRay(const Vec3r& orig, const Vec3r& dir, OccludersSet& occluders, unsigned timestamp);
+
+ // Prepares to cast ray without generating OccludersSet.
+ bool initAcceleratedInfiniteRay(const Vec3r& orig, const Vec3r& dir, unsigned timestamp);
+
+ /*! Casts an infinite ray (still finishing at the end of the grid) from a starting point and in a given direction.
+ * Returns the first intersection (occluder,t,u,v) or null.
+ * Starts with a call to InitRay.
+ */
+ Polygon3r * castRayToFindFirstIntersection(const Vec3r& orig, const Vec3r& dir, double& t,
+ double& u, double& v, unsigned timestamp);
+
+
+ /*! Init all structures and values for computing the cells intersected by this new ray */
+ void initRay(const Vec3r &orig, const Vec3r& end, unsigned timestamp);
+
+ /*! Init all structures and values for computing the cells intersected by this infinite ray.
+ * Returns false if the ray doesn't intersect the grid.
+ */
+ bool initInfiniteRay(const Vec3r &orig, const Vec3r& dir, unsigned timestamp);
+
+
+ /*! Accessors */
+ inline const Vec3r& getOrigin() const {
+ return _orig;
+ }
+
+ inline Vec3r gridSize() const {
+ return _size;
+ }
+
+ inline Vec3r getCellSize() const {
+ return _cell_size;
+ }
+
+ //ARB profiling only:
+ inline OccludersSet* getOccluders() {
+ return &_occluders;
+ }
+
+ void displayDebug() {
+ cerr << "Cells nb : " << _cells_nb << endl;
+ cerr << "Cell size : " << _cell_size << endl;
+ cerr << "Origin : " << _orig << endl;
+ cerr << "Occluders nb : " << _occluders.size() << endl;
+ }
+
+protected:
+ /*! Core of castRay and castInfiniteRay, find occluders along the given ray */
+ inline void castRayInternal(GridVisitor& visitor) {
+ Cell *current_cell = NULL;
+ do {
+ current_cell = getCell(_current_cell);
+ if (current_cell) {
+ visitor.discoverCell(current_cell);
+ OccludersSet& occluders = current_cell->getOccluders(); // FIXME: I had forgotten the ref &
+ for (OccludersSet::iterator it = occluders.begin(); it != occluders.end(); it++) {
+ if (GET_UINT_FROM_POINTER((*it)->userdata2) != _timestamp) {
+ (*it)->userdata2 = SET_UINT_IN_POINTER(_timestamp);
+ visitor.examineOccluder(*it);
+ }
+ }
+ visitor.finishCell(current_cell);
+ }
+ } while ((!visitor.stop()) && (nextRayCell(_current_cell, _current_cell)));
+ }
+
+
+ /*! returns the cell next to the cell passed as argument. */
+ bool nextRayCell(Vec3u& current_cell, Vec3u& next_cell);
+
+ unsigned int _timestamp;
+
+ Vec3u _cells_nb; // number of cells for x,y,z axis
+ Vec3r _cell_size; // cell x,y,z dimensions
+ Vec3r _size; // grid x,y,x dimensions
+ Vec3r _orig; // grid origin
+
+ Vec3r _ray_dir; // direction vector for the ray
+ Vec3u _current_cell; // The current cell being processed (designated by its 3 coordinates)
+ Vec3r _pt; // Points corresponding to the incoming and outgoing intersections of one cell with the ray
+ real _t_end; // To know when we are at the end of the ray
+ real _t;
+
+ //OccludersSet _ray_occluders; // Set storing the occluders contained in the cells traversed by a ray
+ OccludersSet _occluders; // List of all occluders inserted in the grid
+};
+
+//
+// Class to walk through occluders in grid without building intermediate data structures
+//
+///////////////////////////////////////////////////////////////////////////////
+
+class VirtualOccludersSet {
+public:
+ VirtualOccludersSet(Grid& _grid) : grid (_grid) {};
+ Polygon3r* begin();
+ Polygon3r* next();
+ Polygon3r* next(bool stopOnNewCell);
+
+private:
+ Polygon3r* firstOccluderFromNextCell();
+ Grid& grid;
+ OccludersSet::iterator it, end;
+};
+
+#endif // __GRID_H__
diff --git a/source/blender/freestyle/intern/geometry/GridHelpers.cpp b/source/blender/freestyle/intern/geometry/GridHelpers.cpp
new file mode 100644
index 00000000000..055a47f6bd5
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/GridHelpers.cpp
@@ -0,0 +1,59 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/geometry/GridHelpers.cpp
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2010-12-21
+ */
+
+#include <math.h>
+
+#include "GridHelpers.h"
+
+void GridHelpers::getDefaultViewProscenium(real viewProscenium[4])
+{
+ // Get proscenium boundary for culling
+ // bufferZone determines the amount by which the area processed should exceed the actual image area.
+ // This is intended to avoid visible artifacts generated along the proscenium edge.
+ // Perhaps this is no longer needed now that entire view edges are culled at once, since that theoretically
+ // should eliminate visible artifacts.
+ // To the extent it is still useful, bufferZone should be put into the UI as configurable percentage value
+ const real bufferZone = 0.05;
+ // borderZone describes a blank border outside the proscenium, but still inside the image area.
+ // Only intended for exposing possible artifacts along or outside the proscenium edge during debugging.
+ const real borderZone = 0.0;
+ viewProscenium[0] = freestyle_viewport[2] * (borderZone - bufferZone);
+ viewProscenium[1] = freestyle_viewport[2] * (1.0f - borderZone + bufferZone);
+ viewProscenium[2] = freestyle_viewport[3] * (borderZone - bufferZone);
+ viewProscenium[3] = freestyle_viewport[3] * (1.0f - borderZone + bufferZone);
+}
+
+GridHelpers::Transform::~Transform ()
+{
+}
diff --git a/source/blender/freestyle/intern/geometry/GridHelpers.h b/source/blender/freestyle/intern/geometry/GridHelpers.h
new file mode 100644
index 00000000000..4391b4f61a3
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/GridHelpers.h
@@ -0,0 +1,215 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __GRIDHELPERS_H__
+#define __GRIDHELPERS_H__
+
+/** \file blender/freestyle/intern/geometry/GridHelpers.h
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2010-12-13
+ */
+
+#include <vector>
+
+#include "FRS_freestyle.h"
+
+#include "GeomUtils.h"
+#include "Polygon.h"
+
+#include "../winged_edge/WEdge.h"
+
+namespace GridHelpers {
+
+/*! Computes the distance from a point P to a segment AB */
+template<class T>
+T closestPointToSegment(const T& P, const T& A , const T& B, real& distance)
+{
+ T AB, AP, BP;
+ AB = B - A;
+ AP = P - A;
+ BP = P - B;
+
+ real c1(AB * AP);
+ if (c1 <= 0) {
+ distance = AP.norm();
+ return A; // A is closest point
+ }
+
+ real c2(AB * AB);
+ if (c2 <= c1) {
+ distance = BP.norm();
+ return B; // B is closest point
+ }
+
+ real b = c1 / c2;
+ T Pb, PPb;
+ Pb = A + b * AB;
+ PPb = P - Pb;
+
+ distance = PPb.norm();
+ return Pb; // closest point lies on AB
+}
+
+inline Vec3r closestPointOnPolygon(const Vec3r& point, const Polygon3r& poly)
+{
+ // First cast a ray from the point onto the polygon plane
+ // If the ray intersects the polygon, then the intersection point
+ // is the closest point on the polygon
+ real t, u, v;
+ if (poly.rayIntersect(point, poly.getNormal(), t, u, v)) {
+ return point + poly.getNormal() * t;
+ }
+
+ // Otherwise, get the nearest point on each edge, and take the closest
+ real distance;
+ Vec3r closest = closestPointToSegment(point, poly.getVertices()[2], poly.getVertices()[0], distance);
+ for (unsigned int i = 0; i < 2; ++i) {
+ real t;
+ Vec3r p = closestPointToSegment(point, poly.getVertices()[i], poly.getVertices()[i + 1], t);
+ if (t < distance) {
+ distance = t;
+ closest = p;
+ }
+ }
+ return closest;
+}
+
+inline real distancePointToPolygon(const Vec3r& point, const Polygon3r& poly)
+{
+ // First cast a ray from the point onto the polygon plane
+ // If the ray intersects the polygon, then the intersection point
+ // is the closest point on the polygon
+ real t, u, v;
+ if (poly.rayIntersect(point, poly.getNormal(), t, u, v)) {
+ return (t > 0.0) ? t : -t;
+ }
+
+ // Otherwise, get the nearest point on each edge, and take the closest
+ real distance = GeomUtils::distPointSegment(point, poly.getVertices()[2], poly.getVertices()[0]);
+ for (unsigned int i = 0; i < 2; ++i) {
+ real t = GeomUtils::distPointSegment(point, poly.getVertices()[i], poly.getVertices()[i + 1]);
+ if (t < distance) {
+ distance = t;
+ }
+ }
+ return distance;
+}
+
+class Transform
+{
+public:
+ virtual ~Transform () = 0;
+ virtual Vec3r operator()(const Vec3r& point) const = 0;
+};
+
+inline bool insideProscenium (const real proscenium[4], const Polygon3r& polygon)
+{
+ // N.B. The bounding box check is redundant for inserting occluders into cells, because the cell selection code
+ // in insertOccluders has already guaranteed that the bounding boxes will overlap.
+ // First check the viewport edges, since they are the easiest case
+ // Check if the bounding box is entirely outside the proscenium
+ Vec3r bbMin, bbMax;
+ polygon.getBBox(bbMin, bbMax);
+ if (bbMax[0] < proscenium[0] || bbMin[0] > proscenium[1] || bbMax[1] < proscenium[2] || bbMin[1] > proscenium[3]) {
+ return false;
+ }
+
+ Vec3r boxCenter(proscenium[0] + (proscenium[1] - proscenium[0]) / 2.0,
+ proscenium[2] + (proscenium[3] - proscenium[2]) / 2.0, 0.0);
+ Vec3r boxHalfSize((proscenium[1] - proscenium[0]) / 2.0,
+ (proscenium[3] - proscenium[2]) / 2.0, 1.0);
+ Vec3r triverts[3] = {
+ Vec3r(polygon.getVertices()[0][0], polygon.getVertices()[0][1], 0.0),
+ Vec3r(polygon.getVertices()[1][0], polygon.getVertices()[1][1], 0.0),
+ Vec3r(polygon.getVertices()[2][0], polygon.getVertices()[2][1], 0.0)
+ };
+ return GeomUtils::overlapTriangleBox(boxCenter, boxHalfSize, triverts);
+}
+
+inline vector<Vec3r> enumerateVertices(const vector<WOEdge*>& fedges)
+{
+ vector<Vec3r> points;
+ // Iterate over vertices, storing projections in points
+ for (vector<WOEdge*>::const_iterator woe = fedges.begin(), woend = fedges.end(); woe != woend; woe++) {
+ points.push_back((*woe)->GetaVertex()->GetVertex());
+ }
+
+ return points;
+}
+
+void getDefaultViewProscenium(real viewProscenium[4]);
+
+inline void expandProscenium (real proscenium[4], const Polygon3r& polygon)
+{
+ Vec3r bbMin, bbMax;
+ polygon.getBBox(bbMin, bbMax);
+
+ const real epsilon = 1.0e-6;
+
+ if (bbMin[0] <= proscenium[0]) {
+ proscenium[0] = bbMin[0] - epsilon;
+ }
+
+ if (bbMin[1] <= proscenium[2]) {
+ proscenium[2] = bbMin[1] - epsilon;
+ }
+
+ if (bbMax[0] >= proscenium[1]) {
+ proscenium[1] = bbMax[0] + epsilon;
+ }
+
+ if (bbMax[1] >= proscenium[3]) {
+ proscenium[3] = bbMax[1] + epsilon;
+ }
+}
+
+inline void expandProscenium (real proscenium[4], const Vec3r& point)
+{
+ const real epsilon = 1.0e-6;
+
+ if (point[0] <= proscenium[0]) {
+ proscenium[0] = point[0] - epsilon;
+ }
+
+ if (point[1] <= proscenium[2]) {
+ proscenium[2] = point[1] - epsilon;
+ }
+
+ if (point[0] >= proscenium[1]) {
+ proscenium[1] = point[0] + epsilon;
+ }
+
+ if (point[1] >= proscenium[3]) {
+ proscenium[3] = point[1] + epsilon;
+ }
+}
+
+}; // GridHelpers namespace
+
+#endif // __GRIDHELPERS_H__
diff --git a/source/blender/freestyle/intern/geometry/HashGrid.cpp b/source/blender/freestyle/intern/geometry/HashGrid.cpp
new file mode 100644
index 00000000000..b0ad9e0f276
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/HashGrid.cpp
@@ -0,0 +1,53 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/geometry/HashGrid.cpp
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the bounding box of the scene
+ * \author Stephane Grabli
+ * \date 30/07/2002
+ */
+
+#include "HashGrid.h"
+
+void HashGrid::clear()
+{
+ if (!_cells.empty()) {
+ for (GridHashTable::iterator it = _cells.begin(); it !=_cells.end(); it++) {
+ Cell* cell = (*it).second;
+ delete cell;
+ }
+ _cells.clear();
+ }
+
+ Grid::clear();
+}
+
+void HashGrid::configure(const Vec3r& orig, const Vec3r& size, unsigned nb)
+{
+ Grid::configure(orig, size, nb);
+}
diff --git a/source/blender/freestyle/intern/geometry/HashGrid.h b/source/blender/freestyle/intern/geometry/HashGrid.h
new file mode 100644
index 00000000000..ca6edb258a9
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/HashGrid.h
@@ -0,0 +1,116 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __HASHGRID_H__
+#define __HASHGRID_H__
+
+/** \file blender/freestyle/intern/geometry/HashGrid.h
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the bounding box of the scene
+ * \author Stephane Grabli
+ * \date 30/07/2002
+ */
+
+#if 0
+# if defined(__GNUC__) && (__GNUC__ >= 3)
+// hash_map is not part of the C++ standard anymore;
+// hash_map.h has been kept though for backward compatibility
+# include <hash_map.h>
+# else
+# include <hash_map>
+# endif
+#endif
+
+#include <map>
+
+#include "Grid.h"
+
+/*! Defines a hash table used for searching the Cells */
+struct GridHasher
+{
+#define _MUL 950706376UL
+#define _MOD 2147483647UL
+ inline size_t operator() (const Vec3u& p) const
+ {
+ size_t res = ((unsigned long) (p[0] * _MUL)) % _MOD;
+ res = ((res + (unsigned long) (p[1]) * _MUL)) % _MOD;
+ return ((res +(unsigned long) (p[2]) * _MUL)) % _MOD;
+ }
+#undef _MUL
+#undef _MOD
+};
+
+/*! Class to define a regular grid used for ray casting computations */
+class LIB_GEOMETRY_EXPORT HashGrid : public Grid
+{
+public:
+ typedef map<Vec3u, Cell*> GridHashTable;
+
+ HashGrid() : Grid() {}
+
+ virtual ~HashGrid()
+ {
+ clear();
+ }
+
+ /*! clears the grid
+ * Deletes all the cells, clears the hashtable, resets size, size of cell, number of cells.
+ */
+ virtual void clear();
+
+ /*! Sets the different parameters of the grid
+ * orig
+ * The grid origin
+ * size
+ * The grid's dimensions
+ * nb
+ * The number of cells of the grid
+ */
+ virtual void configure(const Vec3r& orig, const Vec3r& size, unsigned nb);
+
+ /*! returns the cell whose coordinates are pased as argument */
+ virtual Cell* getCell(const Vec3u& p)
+ {
+ Cell* found_cell = NULL;
+
+ GridHashTable::const_iterator found = _cells.find(p);
+ if (found != _cells.end())
+ found_cell = (*found).second;
+ return found_cell;
+ }
+
+ /*! Fills the case p with the cell iCell */
+ virtual void fillCell(const Vec3u& p, Cell& cell)
+ {
+ _cells[p] = &cell;
+ }
+
+protected:
+ GridHashTable _cells;
+};
+
+#endif // __HASHGRID_H__
diff --git a/source/blender/freestyle/intern/geometry/Noise.cpp b/source/blender/freestyle/intern/geometry/Noise.cpp
new file mode 100644
index 00000000000..0769664fcbb
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/Noise.cpp
@@ -0,0 +1,285 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/geometry/Noise.cpp
+ * \ingroup freestyle
+ * \brief Class to define Perlin noise
+ * \author Emmanuel Turquin
+ * \date 12/01/2004
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "Noise.h"
+
+#define MINX -1000000
+#define MINY MINX
+#define MINZ MINX
+
+#define SCURVE(a) ((a) * (a) * (3.0 - 2.0 * (a)))
+
+#define REALSCALE (2.0 / 65536.0)
+#define NREALSCALE (2.0 / 4096.0)
+
+#define HASH3D(a, b, c) hashTable[hashTable[hashTable[(a) & 0xfff] ^ ((b) & 0xfff)] ^ ((c) & 0xfff)]
+#define HASH(a, b, c) (xtab[(xtab[(xtab[(a) & 0xff] ^ (b)) & 0xff] ^ (c)) & 0xff] & 0xff)
+
+#define INCRSUM(m, s, x, y, z) \
+ ((s) * (RTable[m] * 0.5 + RTable[m + 1] * (x) + RTable[m + 2] * (y) + RTable[m + 3] * (z)))
+
+#define MAXSIZE 500
+
+#if 0 // XXX Unused
+#define NRAND() ((float)rand() / (float)RAND_MAX)
+#endif
+#define SEEDNRAND(x) (srand(x * RAND_MAX))
+
+#define BM 0xff
+#define N 0x1000
+#define NP 12 /* 2^N */
+#define NM 0xfff
+
+#define LERP(t, a, b) ((a) + (t) * ((b) - (a)))
+
+#define SETUP(i, b0, b1, r0, r1) \
+ { \
+ (t) = (i) + (N); \
+ (b0) = ((int)(t)) & BM; \
+ (b1) = ((b0) + 1) & BM; \
+ (r0) = (t) - (int)(t); \
+ (r1) = (r0) - 1.0; \
+ } (void)0
+
+static void normalize2(float v[2])
+{
+ float s;
+
+ s = sqrt(v[0] * v[0] + v[1] * v[1]);
+ v[0] = v[0] / s;
+ v[1] = v[1] / s;
+}
+
+static void normalize3(float v[3])
+{
+ float s;
+
+ s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ v[0] = v[0] / s;
+ v[1] = v[1] / s;
+ v[2] = v[2] / s;
+}
+
+float Noise::turbulence1(float arg, float freq, float amp, unsigned oct)
+{
+ float t;
+ float vec;
+
+ for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) {
+ vec = freq * arg;
+ t += smoothNoise1(vec) * amp;
+ }
+ return t;
+}
+
+float Noise::turbulence2(Vec2f& v, float freq, float amp, unsigned oct)
+{
+ float t;
+ Vec2f vec;
+
+ for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) {
+ vec.x() = freq * v.x();
+ vec.y() = freq * v.y();
+ t += smoothNoise2(vec) * amp;
+ }
+ return t;
+}
+
+float Noise::turbulence3(Vec3f& v, float freq, float amp, unsigned oct)
+{
+ float t;
+ Vec3f vec;
+
+ for (t = 0; oct > 0 && freq > 0; freq *= 2, amp /= 2, --oct) {
+ vec.x() = freq * v.x();
+ vec.y() = freq * v.y();
+ vec.z() = freq * v.z();
+ t += smoothNoise3(vec) * amp;
+ }
+ return t;
+}
+
+// Noise functions over 1, 2, and 3 dimensions
+float Noise::smoothNoise1(float arg)
+{
+ int bx0, bx1;
+ float rx0, rx1, sx, t, u, v, vec;
+
+ vec = arg;
+ SETUP(vec, bx0, bx1, rx0, rx1);
+
+ sx = SCURVE(rx0);
+
+ u = rx0 * g1[p[bx0]];
+ v = rx1 * g1[p[bx1]];
+
+ return LERP(sx, u, v);
+}
+
+float Noise::smoothNoise2(Vec2f& vec)
+{
+ int bx0, bx1, by0, by1, b00, b10, b01, b11;
+ float rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
+ register int i, j;
+
+ SETUP(vec.x(), bx0, bx1, rx0, rx1);
+ SETUP(vec.y(), by0, by1, ry0, ry1);
+
+ i = p[bx0];
+ j = p[bx1];
+
+ b00 = p[i + by0];
+ b10 = p[j + by0];
+ b01 = p[i + by1];
+ b11 = p[j + by1];
+
+ sx = SCURVE(rx0);
+ sy = SCURVE(ry0);
+
+#define AT2(rx, ry) ((rx) * q[0] + (ry) * q[1])
+
+ q = g2[b00];
+ u = AT2(rx0, ry0);
+ q = g2[b10];
+ v = AT2(rx1, ry0);
+ a = LERP(sx, u, v);
+
+ q = g2[b01];
+ u = AT2(rx0, ry1);
+ q = g2[b11];
+ v = AT2(rx1, ry1);
+ b = LERP(sx, u, v);
+
+#undef AT2
+
+ return LERP(sy, a, b);
+}
+
+float Noise::smoothNoise3(Vec3f& vec)
+{
+ int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
+ float rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v;
+ register int i, j;
+
+ SETUP(vec.x(), bx0, bx1, rx0, rx1);
+ SETUP(vec.y(), by0, by1, ry0, ry1);
+ SETUP(vec.z(), bz0, bz1, rz0, rz1);
+
+ i = p[bx0];
+ j = p[bx1];
+
+ b00 = p[i + by0];
+ b10 = p[j + by0];
+ b01 = p[i + by1];
+ b11 = p[j + by1];
+
+ t = SCURVE(rx0);
+ sy = SCURVE(ry0);
+ sz = SCURVE(rz0);
+
+#define AT3(rx, ry, rz) ((rx) * q[0] + (ry) * q[1] + (rz) * q[2])
+
+ q = g3[b00 + bz0];
+ u = AT3(rx0, ry0, rz0);
+ q = g3[b10 + bz0];
+ v = AT3(rx1, ry0, rz0);
+ a = LERP(t, u, v);
+
+ q = g3[b01 + bz0];
+ u = AT3(rx0, ry1, rz0);
+ q = g3[b11 + bz0];
+ v = AT3(rx1, ry1, rz0);
+ b = LERP(t, u, v);
+
+ c = LERP(sy, a, b);
+
+ q = g3[b00 + bz1];
+ u = AT3(rx0, ry0, rz1);
+ q = g3[b10 + bz1];
+ v = AT3(rx1, ry0, rz1);
+ a = LERP(t, u, v);
+
+ q = g3[b01 + bz1];
+ u = AT3(rx0, ry1, rz1);
+ q = g3[b11 + bz1];
+ v = AT3(rx1, ry1, rz1);
+ b = LERP(t, u, v);
+
+ d = LERP(sy, a, b);
+
+#undef AT3
+
+ return LERP(sz, c, d);
+}
+
+Noise::Noise(long seed)
+{
+ int i, j, k;
+
+ SEEDNRAND((seed < 0) ? time(NULL) : seed);
+ for (i = 0 ; i < _NOISE_B ; i++) {
+ p[i] = i;
+ g1[i] = (float)((rand() % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B;
+
+ for (j = 0 ; j < 2 ; j++)
+ g2[i][j] = (float)((rand() % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B;
+ normalize2(g2[i]);
+
+ for (j = 0 ; j < 3 ; j++)
+ g3[i][j] = (float)((rand() % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B;
+ normalize3(g3[i]);
+ }
+
+ while (--i) {
+ k = p[i];
+ p[i] = p[j = rand() % _NOISE_B];
+ p[j] = k;
+ }
+
+ for (i = 0 ; i < _NOISE_B + 2 ; i++) {
+ p[_NOISE_B + i] = p[i];
+ g1[_NOISE_B + i] = g1[i];
+
+ for (j = 0 ; j < 2 ; j++)
+ g2[_NOISE_B + i][j] = g2[i][j];
+
+ for (j = 0 ; j < 3 ; j++)
+ g3[_NOISE_B + i][j] = g3[i][j];
+ }
+}
diff --git a/source/blender/freestyle/intern/geometry/Noise.h b/source/blender/freestyle/intern/geometry/Noise.h
new file mode 100644
index 00000000000..35d1af3712f
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/Noise.h
@@ -0,0 +1,83 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __NOISE_H__
+#define __NOISE_H__
+
+/** \file blender/freestyle/intern/geometry/Noise.h
+ * \ingroup freestyle
+ * \brief Class to define Perlin noise
+ * \author Emmanuel Turquin
+ * \date 12/01/2004
+ */
+
+#include "Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+#define _NOISE_B 0x100
+
+using namespace Geometry;
+using namespace std;
+
+/*! Class to provide Perlin Noise functionalities */
+class LIB_GEOMETRY_EXPORT Noise
+{
+public:
+ /*! Builds a Noise object */
+ Noise(long seed = -1);
+
+ /*! Destructor */
+ ~Noise() {}
+
+ /*! Returns a noise value for a 1D element */
+ float turbulence1(float arg, float freq, float amp, unsigned oct = 4);
+
+ /*! Returns a noise value for a 2D element */
+ float turbulence2(Vec2f& v, float freq, float amp, unsigned oct = 4);
+
+ /*! Returns a noise value for a 3D element */
+ float turbulence3(Vec3f& v, float freq, float amp, unsigned oct = 4);
+
+ /*! Returns a smooth noise value for a 1D element */
+ float smoothNoise1(float arg);
+
+ /*! Returns a smooth noise value for a 2D element */
+ float smoothNoise2(Vec2f& vec);
+
+ /*! Returns a smooth noise value for a 3D element */
+ float smoothNoise3(Vec3f& vec);
+
+private:
+ int p[_NOISE_B + _NOISE_B + 2];
+ float g3[_NOISE_B + _NOISE_B + 2][3];
+ float g2[_NOISE_B + _NOISE_B + 2][2];
+ float g1[_NOISE_B + _NOISE_B + 2];
+ int start;
+};
+
+#endif // __NOISE_H__
diff --git a/source/blender/freestyle/intern/geometry/Polygon.h b/source/blender/freestyle/intern/geometry/Polygon.h
new file mode 100644
index 00000000000..5ee4353ef5a
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/Polygon.h
@@ -0,0 +1,221 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __POLYGON_H__
+#define __POLYGON_H__
+
+/** \file blender/freestyle/intern/geometry/Polygon.h
+ * \ingroup freestyle
+ * \brief Class to define a polygon
+ * \author Stephane Grabli
+ * \date 30/07/2002
+ */
+
+#include <vector>
+
+#include "Geom.h"
+#include "GeomUtils.h"
+
+using namespace std;
+
+namespace Geometry {
+
+template <class Point>
+class Polygon
+{
+public:
+ inline Polygon()
+ {
+ _id = 0;
+ userdata = 0;
+ userdata2 = 0;
+ }
+
+ inline Polygon(const vector<Point>& vertices)
+ {
+ _vertices = vertices;
+ computeBBox();
+ _id = 0;
+ userdata = 0;
+ userdata2 = 0;
+ }
+
+ inline Polygon(const Polygon<Point>& poly)
+ {
+ Point p;
+ for (typename vector<Point>::const_iterator it = poly.getVertices().begin();
+ it != poly.getVertices().end();
+ it++)
+ {
+ p = *it;
+ _vertices.push_back(p);
+ }
+
+ _id = poly.getId();
+ poly.getBBox(_min, _max);
+ userdata = 0;
+ userdata2 = 0;
+ }
+
+ virtual ~Polygon() {}
+
+ //
+ // Accessors
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ inline const vector<Point>& getVertices() const
+ {
+ return _vertices;
+ }
+
+ inline void getBBox(Point& min, Point& max) const
+ {
+ min = _min;
+ max = _max;
+ }
+
+ inline Point& getBBoxCenter()
+ {
+ Point result;
+ result = (_min + _max) / 2;
+ return result;
+ }
+
+ inline Point& getCenter()
+ {
+ Point result;
+ for (typename vector<Point>::iterator it = _vertices.begin(); it != _vertices.end(); it++)
+ result += *it;
+ result /= _vertices.size();
+ return result;
+ }
+
+ inline unsigned getId() const
+ {
+ return _id;
+ }
+
+ //
+ // Modifiers
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ inline void setVertices(const vector<Point>& vertices)
+ {
+ _vertices.clear();
+ Point p;
+ for (typename vector<Point>::const_iterator it = vertices.begin(); it != vertices.end(); it++) {
+ p = *it;
+ _vertices.push_back(p);
+ }
+ computeBBox();
+ }
+
+ inline void setId(unsigned id)
+ {
+ _id = id;
+ }
+
+ //
+ // Other methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ inline void computeBBox()
+ {
+ if (_vertices.empty())
+ return;
+
+ _max = _vertices[0];
+ _min = _vertices[0];
+
+ for (typename vector<Point>::iterator it = _vertices.begin(); it != _vertices.end(); it++) {
+ for (unsigned int i = 0; i < Point::dim(); i++) {
+ if ((*it)[i] > _max[i])
+ _max[i] = (*it)[i];
+ if ((*it)[i] < _min[i])
+ _min[i] = (*it)[i];
+ }
+ }
+ }
+
+ // FIXME Is it possible to get rid of userdatas ?
+ void* userdata;
+ void* userdata2; // Used during ray casting
+
+protected:
+ vector<Point> _vertices;
+ Point _min;
+ Point _max;
+ unsigned _id;
+};
+
+
+//
+// Polygon3r class
+//
+///////////////////////////////////////////////////////////////////////////////
+class Polygon3r : public Polygon<Vec3r>
+{
+public:
+ inline Polygon3r() : Polygon<Vec3r>() {}
+
+ inline Polygon3r(const vector<Vec3r>& vertices, const Vec3r& normal) : Polygon<Vec3r>(vertices)
+ {
+ setNormal(normal);
+ }
+
+ inline Polygon3r(const Polygon3r& poly) : Polygon<Vec3r>(poly), _normal(poly._normal) {}
+
+ virtual ~Polygon3r() {}
+
+ void setNormal(const Vec3r& normal)
+ {
+ _normal = normal;
+ }
+
+ inline Vec3r getNormal() const
+ {
+ return _normal;
+ }
+
+ /*! Check whether the Polygon intersects with the ray or not */
+ inline bool rayIntersect(const Vec3r& orig, const Vec3r& dir, real& t, real& u, real& v,
+ real epsilon = M_EPSILON) const
+ {
+#if 0
+ if (_vertices.size() < 3)
+ return false;
+#endif
+ return GeomUtils::intersectRayTriangle(orig, dir, _vertices[0], _vertices[1], _vertices[2], t, u, v, epsilon);
+ }
+
+private:
+ Vec3r _normal;
+};
+
+} // end of namespace Geometry
+
+#endif // __POLYGON_H__
diff --git a/source/blender/freestyle/intern/geometry/SweepLine.h b/source/blender/freestyle/intern/geometry/SweepLine.h
new file mode 100644
index 00000000000..ec81507c5c6
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/SweepLine.h
@@ -0,0 +1,332 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __SWEEPLINE_H__
+#define __SWEEPLINE_H__
+
+/** \file blender/freestyle/intern/geometry/SweepLine.h
+ * \ingroup freestyle
+ * \brief Class to define a Sweep Line
+ * \author Stephane Grabli
+ * \date 29/08/2002
+ */
+
+#include <list>
+#include <vector>
+
+/*! Class to define the intersection berween two segments*/
+template<class Edge>
+class Intersection
+{
+public:
+ template<class EdgeClass>
+ Intersection(EdgeClass* eA, real ta, EdgeClass* eB, real tb)
+ {
+ EdgeA = eA;
+ EdgeB = eB;
+ tA = ta;
+ tB = tb;
+ userdata = 0;
+ }
+
+ Intersection(const Intersection& iBrother)
+ {
+ EdgeA = iBrother.EdgeA;
+ EdgeB = iBrother.EdgeB;
+ tA = iBrother.tA;
+ tB = iBrother.tB;
+ userdata = 0;
+ }
+
+ /*! returns the parameter giving the intersection, for the edge iEdge */
+ real getParameter(Edge *iEdge)
+ {
+ if (iEdge == EdgeA)
+ return tA;
+ if (iEdge == EdgeB)
+ return tB;
+ return 0;
+ }
+
+public:
+ void * userdata; // FIXME
+
+ Edge *EdgeA; // first segment
+ Edge *EdgeB; // second segment
+ real tA; // parameter defining the intersection point with respect to the segment EdgeA.
+ real tB; // parameter defining the intersection point with respect to the segment EdgeB.
+};
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4521) // disable warning C4521: multiple copy constructors specified
+#endif
+
+template<class T, class Point>
+class Segment
+{
+public:
+ Segment()
+ {
+ }
+
+ Segment(T& s, const Point& iA, const Point& iB)
+ {
+ _edge = s;
+ if (iA < iB) {
+ A = iA;
+ B = iB;
+ _order = true;
+ }
+ else {
+ A = iB;
+ B = iA;
+ _order = false;
+ }
+ }
+
+ Segment(Segment<T,Point>& iBrother)
+ {
+ _edge = iBrother.edge();
+ A = iBrother.A;
+ B = iBrother.B;
+ _Intersections = iBrother._Intersections;
+ _order = iBrother._order;
+ }
+
+ Segment(const Segment<T,Point>& iBrother)
+ {
+ _edge = iBrother._edge;
+ A = iBrother.A;
+ B = iBrother.B;
+ _Intersections = iBrother._Intersections;
+ _order = iBrother._order;
+ }
+
+ ~Segment()
+ {
+ _Intersections.clear();
+ }
+
+ inline Point operator[](const unsigned short int& i) const
+ {
+ return (i % 2 == 0) ? A : B;
+ }
+
+ inline bool operator==(const Segment<T,Point>& iBrother)
+ {
+ if (_edge == iBrother._edge)
+ return true;
+ return false;
+ }
+
+ /* Adds an intersection for this segment */
+ inline void AddIntersection(Intersection<Segment<T,Point> > *i)
+ {
+ _Intersections.push_back(i);
+ }
+
+ /*! Checks for a common vertex with another edge */
+ inline bool CommonVertex(const Segment<T,Point>& S, Point& CP)
+ {
+ if ((A == S[0]) || (A == S[1])) {
+ CP = A;
+ return true;
+ }
+ if ((B == S[0]) || (B == S[1])) {
+ CP = B;
+ return true;
+ }
+ return false;
+ }
+
+ inline vector<Intersection<Segment<T,Point> >*>& intersections()
+ {
+ return _Intersections;
+ }
+
+ inline bool order()
+ {
+ return _order;
+ }
+
+ inline T& edge()
+ {
+ return _edge;
+ }
+
+private:
+ T _edge;
+ Point A;
+ Point B;
+ std::vector<Intersection<Segment<T,Point> >*> _Intersections; // list of intersections parameters
+ bool _order; // true if A and B are in the same order than _edge.A and _edge.B. false otherwise.
+};
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+/*! defines a binary function that can be overload by the user to specify at each condition the intersection
+ * between 2 edges must be computed
+ */
+template<class T1, class T2>
+struct binary_rule
+{
+ binary_rule() {}
+ template<class T3,class T4> binary_rule(const binary_rule<T3,T4>& brother) {}
+ virtual ~binary_rule() {}
+
+ virtual bool operator()(T1&, T2&)
+ {
+ return true;
+ }
+};
+
+
+template<class T,class Point>
+class SweepLine
+{
+public:
+ SweepLine() {}
+ ~SweepLine()
+ {
+ for (typename vector<Intersection<Segment<T,Point> >*>::iterator i = _Intersections.begin(),
+ iend = _Intersections.end();
+ i != iend;
+ i++)
+ {
+ delete (*i);
+ }
+ }
+
+ inline void process(Point& p, vector<Segment<T,Point>*>& segments,
+#if 0
+ binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule = \
+ binary_rule<Segment<T,Point>,Segment<T,Point> >(),
+#else
+ binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule,
+#endif
+ real epsilon = M_EPSILON)
+ {
+ // first we remove the segments that need to be removed and then we add the segments to add
+ vector<Segment<T,Point>*> toadd;
+ typename vector<Segment<T,Point>*>::iterator s, send;
+ for (s = segments.begin(), send = segments.end(); s != send; s++) {
+ if (p == (*(*s))[0])
+ toadd.push_back((*s));
+ else
+ remove((*s));
+ }
+ for (s = toadd.begin(), send = toadd.end(); s != send; s++) {
+ add((*s), binrule, epsilon);
+ }
+ }
+
+ inline void add(Segment<T,Point>* S,
+#if 0
+ binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule = \
+ binary_rule<Segment<T,Point>, Segment<T,Point> >(),
+#else
+ binary_rule<Segment<T,Point>,Segment<T,Point> >& binrule,
+#endif
+ real epsilon)
+ {
+ real t,u;
+ Point CP;
+ Vec2r v0, v1, v2, v3;
+ if (true == S->order()) {
+ v0[0] = ((*S)[0])[0];
+ v0[1] = ((*S)[0])[1];
+ v1[0] = ((*S)[1])[0];
+ v1[1] = ((*S)[1])[1];
+ }
+ else {
+ v1[0] = ((*S)[0])[0];
+ v1[1] = ((*S)[0])[1];
+ v0[0] = ((*S)[1])[0];
+ v0[1] = ((*S)[1])[1];
+ }
+ for (typename std::list<Segment<T,Point>* >::iterator s = _set.begin(), send = _set.end(); s != send; s++) {
+ Segment<T,Point>* currentS = (*s);
+ if (true != binrule(*S, *currentS))
+ continue;
+
+ if (true == currentS->order()) {
+ v2[0] = ((*currentS)[0])[0];
+ v2[1] = ((*currentS)[0])[1];
+ v3[0] = ((*currentS)[1])[0];
+ v3[1] = ((*currentS)[1])[1];
+ }
+ else {
+ v3[0] = ((*currentS)[0])[0];
+ v3[1] = ((*currentS)[0])[1];
+ v2[0] = ((*currentS)[1])[0];
+ v2[1] = ((*currentS)[1])[1];
+ }
+ if (S->CommonVertex(*currentS, CP))
+ continue; // the two edges have a common vertex->no need to check
+
+ if (GeomUtils::intersect2dSeg2dSegParametric(v0, v1, v2, v3, t, u, epsilon) == GeomUtils::DO_INTERSECT) {
+ // create the intersection
+ Intersection<Segment<T,Point> > *inter = new Intersection<Segment<T,Point> >(S,t,currentS,u);
+ // add it to the intersections list
+ _Intersections.push_back(inter);
+ // add this intersection to the first edge intersections list
+ S->AddIntersection(inter);
+ // add this intersection to the second edge intersections list
+ currentS->AddIntersection(inter);
+ }
+ }
+ // add the added segment to the list of active segments
+ _set.push_back(S);
+ }
+
+ inline void remove(Segment<T,Point>* s)
+ {
+ if (s->intersections().size() > 0)
+ _IntersectedEdges.push_back(s);
+ _set.remove(s);
+ }
+
+ vector<Segment<T,Point>* >& intersectedEdges()
+ {
+ return _IntersectedEdges;
+ }
+
+ vector<Intersection<Segment<T,Point> >*>& intersections()
+ {
+ return _Intersections;
+ }
+
+private:
+ std::list<Segment<T,Point>* > _set; // set of active edges for a given position of the sweep line
+ std::vector<Segment<T,Point>* > _IntersectedEdges; // the list of intersected edges
+ std::vector<Intersection<Segment<T,Point> >*> _Intersections; // the list of all intersections.
+};
+
+#endif // __SWEEPLINE_H__
diff --git a/source/blender/freestyle/intern/geometry/VecMat.h b/source/blender/freestyle/intern/geometry/VecMat.h
new file mode 100644
index 00000000000..5b64a6e4502
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/VecMat.h
@@ -0,0 +1,976 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __VECMAT_H__
+#define __VECMAT_H__
+
+/** \file blender/freestyle/intern/geometry/VecMat.h
+ * \ingroup freestyle
+ * \brief Vectors and Matrices definition and manipulation
+ * \author Sylvain Paris
+ * \author Emmanuel Turquin
+ * \author Stephane Grabli
+ * \date 12/06/2003
+ */
+
+#include <iostream>
+#include <math.h>
+#include <vector>
+
+namespace VecMat {
+
+namespace Internal {
+ template <bool B>
+ struct is_false {};
+
+ template <>
+ struct is_false<false>
+ {
+ static inline void ensure() {}
+ };
+} // end of namespace Internal
+
+//
+// Vector class
+// - T: value type
+// - N: dimension
+//
+/////////////////////////////////////////////////////////////////////////////
+
+template <class T, unsigned N>
+class Vec
+{
+public:
+ typedef T value_type;
+
+ // constructors
+ inline Vec()
+ {
+ for (unsigned int i = 0; i < N; i++)
+ this->_coord[i] = 0;
+ }
+
+ ~Vec()
+ {
+ Internal::is_false<(N == 0)>::ensure();
+ }
+
+ template <class U>
+ explicit inline Vec(const U tab[N])
+ {
+ for (unsigned int i = 0; i < N; i++)
+ this->_coord[i] = (T)tab[i];
+ }
+
+ template <class U>
+ explicit inline Vec(const std::vector<U>& tab)
+ {
+ for (unsigned int i = 0; i < N; i++)
+ this->_coord[i] = (T)tab[i];
+ }
+
+ template <class U>
+ explicit inline Vec(const Vec<U, N>& v)
+ {
+ for (unsigned int i = 0; i < N; i++)
+ this->_coord[i] = (T)v[i];
+ }
+
+ // accessors
+ inline value_type operator[](const unsigned i) const
+ {
+ return this->_coord[i];
+ }
+
+ inline value_type& operator[](const unsigned i)
+ {
+ return this->_coord[i];
+ }
+
+ static inline unsigned dim()
+ {
+ return N;
+ }
+
+ // various useful methods
+ inline value_type norm() const
+ {
+ return (T)sqrt((float)squareNorm());
+ }
+
+ inline value_type squareNorm() const
+ {
+ return (*this) * (*this);
+ }
+
+ inline Vec<T, N>& normalize()
+ {
+ value_type n = norm();
+ for (unsigned int i = 0; i < N; i++)
+ this->_coord[i] /= n;
+ return *this;
+ }
+
+ inline Vec<T, N>& normalizeSafe()
+ {
+ value_type n = norm();
+ if (n) {
+ for (unsigned int i = 0; i < N; i++)
+ this->_coord[i] /= n;
+ }
+ return *this;
+ }
+
+ // classical operators
+ inline Vec<T, N> operator+(const Vec<T, N>& v) const
+ {
+ Vec<T, N> res(v);
+ res += *this;
+ return res;
+ }
+
+ inline Vec<T, N> operator-(const Vec<T,N>& v) const
+ {
+ Vec<T, N> res(*this);
+ res -= v;
+ return res;
+ }
+
+ inline Vec<T, N> operator*(const typename Vec<T,N>::value_type r) const
+ {
+ Vec<T, N> res(*this);
+ res *= r;
+ return res;
+ }
+
+ inline Vec<T, N> operator/(const typename Vec<T,N>::value_type r) const
+ {
+ Vec<T, N> res(*this);
+ if (r)
+ res /= r;
+ return res;
+ }
+
+ // dot product
+ inline value_type operator*(const Vec<T, N>& v) const
+ {
+ value_type sum = 0;
+ for (unsigned int i = 0; i < N; i++)
+ sum += (*this)[i] * v[i];
+ return sum;
+ }
+
+ template <class U>
+ inline Vec<T, N>& operator=(const Vec<U, N>& v)
+ {
+ if (this != &v) {
+ for (unsigned int i = 0; i < N; i++)
+ this->_coord[i] = (T)v[i];
+ }
+ return *this;
+ }
+
+ template <class U>
+ inline Vec<T, N>& operator+=(const Vec<U, N>& v)
+ {
+ for (unsigned int i = 0 ; i < N; i++)
+ this->_coord[i] += (T)v[i];
+ return *this;
+ }
+
+ template <class U>
+ inline Vec<T, N>& operator-=(const Vec<U, N>& v)
+ {
+ for (unsigned int i = 0 ; i < N; i++)
+ this->_coord[i] -= (T)v[i];
+ return *this;
+ }
+
+ template <class U>
+ inline Vec<T, N>& operator*=(const U r)
+ {
+ for (unsigned int i = 0 ; i < N; i++)
+ this->_coord[i] *= r;
+ return *this;
+ }
+
+ template <class U>
+ inline Vec<T, N>& operator/=(const U r)
+ {
+ if (r) {
+ for (unsigned int i = 0 ; i < N; i++)
+ this->_coord[i] /= r;
+ }
+ return *this;
+ }
+
+ inline bool operator==(const Vec<T, N>& v) const
+ {
+ for (unsigned int i = 0; i < N; i++) {
+ if (this->_coord[i] != v[i])
+ return false;
+ }
+ return true;
+ }
+
+ inline bool operator!=(const Vec<T, N>& v) const
+ {
+ for (unsigned int i = 0; i < N; i++) {
+ if (this->_coord[i] != v[i])
+ return true;
+ }
+ return false;
+ }
+
+ inline bool operator<(const Vec<T, N>& v) const
+ {
+ for (unsigned int i = 0; i < N; i++) {
+ if (this->_coord[i] < v[i])
+ return true;
+ if (this->_coord[i] > v[i])
+ return false;
+ if (this->_coord[i] == v[i])
+ continue;
+ }
+ return false;
+ }
+
+ inline bool operator>(const Vec<T, N>& v) const
+ {
+ for (unsigned int i = 0; i < N; i++) {
+ if (this->_coord[i] > v[i])
+ return true;
+ if (this->_coord[i] < v[i])
+ return false;
+ if (this->_coord[i] == v[i])
+ continue;
+ }
+ return false;
+ }
+
+protected:
+ value_type _coord[N];
+ enum {
+ _dim = N,
+ };
+};
+
+
+//
+// Vec2 class (2D Vector)
+// - T: value type
+//
+/////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+class Vec2 : public Vec<T, 2>
+{
+public:
+ typedef typename Vec<T, 2>::value_type value_type;
+
+ inline Vec2() : Vec<T, 2>() {}
+
+ template <class U>
+ explicit inline Vec2(const U tab[2]) : Vec<T, 2>(tab) {}
+
+ template <class U>
+ explicit inline Vec2(const std::vector<U>& tab) : Vec<T, 2>(tab) {}
+
+ template <class U>
+ inline Vec2(const Vec<U, 2>& v) : Vec<T, 2>(v) {}
+
+ inline Vec2(const value_type x, const value_type y = 0) : Vec<T, 2>()
+ {
+ this->_coord[0] = (T)x;
+ this->_coord[1] = (T)y;
+ }
+
+ inline value_type x() const
+ {
+ return this->_coord[0];
+ }
+
+ inline value_type& x()
+ {
+ return this->_coord[0];
+ }
+
+ inline value_type y() const
+ {
+ return this->_coord[1];
+ }
+
+ inline value_type& y()
+ {
+ return this->_coord[1];
+ }
+
+ inline void setX(const value_type v)
+ {
+ this->_coord[0] = v;
+ }
+
+ inline void setY(const value_type v)
+ {
+ this->_coord[1] = v;
+ }
+
+ // FIXME: hack swig -- no choice
+ inline Vec2<T> operator+(const Vec2<T>& v) const
+ {
+ Vec2<T> res(v);
+ res += *this;
+ return res;
+ }
+
+ inline Vec2<T> operator-(const Vec2<T>& v) const
+ {
+ Vec2<T> res(*this);
+ res -= v;
+ return res;
+ }
+
+ inline Vec2<T> operator*(const value_type r) const
+ {
+ Vec2<T> res(*this);
+ res *= r;
+ return res;
+ }
+
+ inline Vec2<T> operator/(const value_type r) const
+ {
+ Vec2<T> res(*this);
+ if (r)
+ res /= r;
+ return res;
+ }
+
+ // dot product
+ inline value_type operator*(const Vec2<T>& v) const
+ {
+ value_type sum = 0;
+ for (unsigned int i = 0; i < 2; i++)
+ sum += (*this)[i] * v[i];
+ return sum;
+ }
+};
+
+
+//
+// HVec3 class (3D Vector in homogeneous coordinates)
+// - T: value type
+//
+/////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+class HVec3 : public Vec<T, 4>
+{
+public:
+ typedef typename Vec<T, 4>::value_type value_type;
+
+ inline HVec3() : Vec<T, 4>() {}
+
+ template <class U>
+ explicit inline HVec3(const U tab[4]) : Vec<T, 4>(tab) {}
+
+ template <class U>
+ explicit inline HVec3(const std::vector<U>& tab) : Vec<T, 4>(tab) {}
+
+ template<class U>
+ inline HVec3(const Vec<U, 4>& v) : Vec<T, 4>(v) {}
+
+ inline HVec3(const value_type sx, const value_type sy = 0, const value_type sz = 0, const value_type s = 1)
+ {
+ this->_coord[0] = sx;
+ this->_coord[1] = sy;
+ this->_coord[2] = sz;
+ this->_coord[3] = s;
+ }
+
+ template <class U>
+ inline HVec3(const Vec<U, 3>& sv, const U s = 1)
+ {
+ this->_coord[0] = (T)sv[0];
+ this->_coord[1] = (T)sv[1];
+ this->_coord[2] = (T)sv[2];
+ this->_coord[3] = (T)s;
+ }
+
+ inline value_type sx() const
+ {
+ return this->_coord[0];
+ }
+
+ inline value_type& sx()
+ {
+ return this->_coord[0];
+ }
+
+ inline value_type sy() const
+ {
+ return this->_coord[1];
+ }
+
+ inline value_type& sy(){
+ return this->_coord[1];
+ }
+
+ inline value_type sz() const
+ {
+ return this->_coord[2];
+ }
+
+ inline value_type& sz()
+ {
+ return this->_coord[2];
+ }
+
+ inline value_type s() const
+ {
+ return this->_coord[3];
+ }
+
+ inline value_type& s()
+ {
+ return this->_coord[3];
+ }
+
+ // Acces to non-homogeneous coordinates in 3D
+ inline value_type x() const
+ {
+ return this->_coord[0] / this->_coord[3];
+ }
+
+ inline value_type y() const
+ {
+ return this->_coord[1] / this->_coord[3];
+ }
+
+ inline value_type z() const
+ {
+ return this->_coord[2] / this->_coord[3];
+ }
+};
+
+
+//
+// Vec3 class (3D Vec)
+// - T: value type
+//
+/////////////////////////////////////////////////////////////////////////////
+template <class T>
+class Vec3 : public Vec<T, 3>
+{
+public:
+ typedef typename Vec<T, 3>::value_type value_type;
+
+ inline Vec3() : Vec<T, 3>() {}
+
+ template <class U>
+ explicit inline Vec3(const U tab[3]) : Vec<T, 3>(tab) {}
+
+ template <class U>
+ explicit inline Vec3(const std::vector<U>& tab) : Vec<T, 3>(tab) {}
+
+ template<class U>
+ inline Vec3(const Vec<U, 3>& v) : Vec<T, 3>(v) {}
+
+ template<class U>
+ inline Vec3(const HVec3<U>& v)
+ {
+ this->_coord[0] = (T)v.x();
+ this->_coord[1] = (T)v.y();
+ this->_coord[2] = (T)v.z();
+ }
+
+ inline Vec3(const value_type x, const value_type y = 0, const value_type z = 0) : Vec<T, 3>()
+ {
+ this->_coord[0] = x;
+ this->_coord[1] = y;
+ this->_coord[2] = z;
+ }
+
+ inline value_type x() const
+ {
+ return this->_coord[0];
+ }
+
+ inline value_type& x()
+ {
+ return this->_coord[0];
+ }
+
+ inline value_type y() const
+ {
+ return this->_coord[1];
+ }
+
+ inline value_type& y()
+ {
+ return this->_coord[1];
+ }
+
+ inline value_type z() const
+ {
+ return this->_coord[2];
+ }
+
+ inline value_type& z()
+ {
+ return this->_coord[2];
+ }
+
+ inline void setX(const value_type v)
+ {
+ this->_coord[0] = v;
+ }
+
+ inline void setY(const value_type v)
+ {
+ this->_coord[1] = v;
+ }
+
+ inline void setZ(const value_type v)
+ {
+ this->_coord[2] = v;
+ }
+
+ // classical operators
+ // FIXME: hack swig -- no choice
+ inline Vec3<T> operator+(const Vec3<T>& v) const
+ {
+ Vec3<T> res(v);
+ res += *this;
+ return res;
+ }
+
+ inline Vec3<T> operator-(const Vec3<T>& v) const
+ {
+ Vec3<T> res(*this);
+ res -= v;
+ return res;
+ }
+
+ inline Vec3<T> operator*(const value_type r) const
+ {
+ Vec3<T> res(*this);
+ res *= r;
+ return res;
+ }
+
+ inline Vec3<T> operator/(const value_type r) const
+ {
+ Vec3<T> res(*this);
+ if (r)
+ res /= r;
+ return res;
+ }
+
+ // dot product
+ inline value_type operator*(const Vec3<T>& v) const
+ {
+ value_type sum = 0;
+ for (unsigned int i = 0; i < 3; i++)
+ sum += (*this)[i] * v[i];
+ return sum;
+ }
+
+ // cross product for 3D Vectors
+ // FIXME: hack swig -- no choice
+ inline Vec3<T> operator^(const Vec3<T>& v) const
+ {
+ Vec3<T> res((*this)[1] * v[2] - (*this)[2] * v[1],
+ (*this)[2] * v[0] - (*this)[0] * v[2],
+ (*this)[0] * v[1] - (*this)[1] * v[0]);
+ return res;
+ }
+
+ // cross product for 3D Vectors
+ template <typename U>
+ inline Vec3<T> operator^(const Vec<U, 3>& v) const
+ {
+ Vec3<T> res((*this)[1] * v[2] - (*this)[2] * v[1],
+ (*this)[2] * v[0] - (*this)[0] * v[2],
+ (*this)[0] * v[1] - (*this)[1] * v[0]);
+ return res;
+ }
+};
+
+
+//
+// Matrix class
+// - T: value type
+// - M: rows
+// - N: cols
+//
+/////////////////////////////////////////////////////////////////////////////
+
+// Dirty, but icc under Windows needs this
+#define _SIZE (M * N)
+
+template <class T, unsigned M, unsigned N>
+class Matrix
+{
+public:
+ typedef T value_type;
+
+ inline Matrix()
+ {
+ for (unsigned int i = 0; i < _SIZE; i++)
+ this->_coord[i] = 0;
+ }
+
+ ~Matrix()
+ {
+ Internal::is_false<(M == 0)>::ensure();
+ Internal::is_false<(N == 0)>::ensure();
+ }
+
+ template <class U>
+ explicit inline Matrix(const U tab[_SIZE])
+ {
+ for (unsigned int i = 0; i < _SIZE; i++)
+ this->_coord[i] = tab[i];
+ }
+
+ template <class U>
+ explicit inline Matrix(const std::vector<U>& tab)
+ {
+ for (unsigned int i = 0; i < _SIZE; i++)
+ this->_coord[i] = tab[i];
+ }
+
+ template <class U>
+ inline Matrix(const Matrix<U, M, N>& m)
+ {
+ for (unsigned int i = 0; i < M; i++) {
+ for (unsigned int j = 0; j < N; j++)
+ this->_coord[i * N + j] = (T)m(i, j);
+ }
+ }
+
+ inline value_type operator()(const unsigned i, const unsigned j) const
+ {
+ return this->_coord[i * N + j];
+ }
+
+ inline value_type& operator()(const unsigned i, const unsigned j)
+ {
+ return this->_coord[i * N + j];
+ }
+
+ static inline unsigned rows()
+ {
+ return M;
+ }
+
+ static inline unsigned cols()
+ {
+ return N;
+ }
+
+ inline Matrix<T, M, N>& transpose() const
+ {
+ Matrix<T, N, M> res;
+ for (unsigned int i = 0; i < M; i++) {
+ for (unsigned int j = 0; j < N; j++)
+ res(j, i) = this->_coord[i * N + j];
+ }
+ return res;
+ }
+
+ template <class U>
+ inline Matrix<T, M, N>& operator=(const Matrix<U, M, N>& m)
+ {
+ if (this != &m) {
+ for (unsigned int i = 0; i < M; i++) {
+ for (unsigned int j = 0; j < N; j++)
+ this->_coord[i * N + j] = (T)m(i, j);
+ }
+ }
+ return *this;
+ }
+
+ template <class U>
+ inline Matrix<T, M, N>& operator+=(const Matrix<U, M, N>& m)
+ {
+ for (unsigned int i = 0; i < M; i++) {
+ for (unsigned int j = 0; j < N; j++)
+ this->_coord[i * N + j] += (T)m(i, j);
+ }
+ return *this;
+ }
+
+ template <class U>
+ inline Matrix<T, M, N>& operator-=(const Matrix<U, M, N>& m)
+ {
+ for (unsigned int i = 0; i < M; i++) {
+ for (unsigned int j = 0; j < N; j++)
+ this->_coord[i * N + j] -= (T)m(i, j);
+ }
+ return *this;
+ }
+
+ template <class U>
+ inline Matrix<T, M, N>& operator*=(const U lambda)
+ {
+ for (unsigned int i = 0; i < M; i++) {
+ for (unsigned int j = 0; j < N; j++)
+ this->_coord[i * N + j] *= lambda;
+ }
+ return *this;
+ }
+
+ template <class U>
+ inline Matrix<T, M, N>& operator/=(const U lambda)
+ {
+ if (lambda) {
+ for (unsigned int i = 0; i < M; i++) {
+ for (unsigned int j = 0; j < N; j++)
+ this->_coord[i * N + j] /= lambda;
+ }
+ }
+ return *this;
+ }
+
+protected:
+ value_type _coord[_SIZE];
+};
+
+#undef _SIZE
+
+//
+// SquareMatrix class
+// - T: value type
+// - N: rows & cols
+//
+/////////////////////////////////////////////////////////////////////////////
+
+// Dirty, but icc under Windows needs this
+#define _SIZE (N * N)
+
+template <class T, unsigned N>
+class SquareMatrix : public Matrix<T, N, N>
+{
+public:
+ typedef T value_type;
+
+ inline SquareMatrix() : Matrix<T, N, N>() {}
+
+ template <class U>
+ explicit inline SquareMatrix(const U tab[_SIZE]) : Matrix<T, N, N>(tab) {}
+
+ template <class U>
+ explicit inline SquareMatrix(const std::vector<U>& tab) : Matrix<T, N, N>(tab) {}
+
+ template <class U>
+ inline SquareMatrix(const Matrix<U, N, N>& m) : Matrix<T, N, N>(m) {}
+
+ static inline SquareMatrix<T, N> identity()
+ {
+ SquareMatrix<T, N> res;
+ for (unsigned int i = 0; i < N; i++)
+ res(i, i) = 1;
+ return res;
+ }
+};
+
+#undef _SIZE
+
+//
+// Vector external functions
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#if 0
+template <class T, unsigned N>
+inline Vec<T, N> operator+(const Vec<T, N>& v1, const Vec<T, N>& v2)
+{
+ Vec<T, N> res(v1);
+ res += v2;
+ return res;
+}
+
+template <class T, unsigned N>
+inline Vec<T, N> operator-(const Vec<T, N>& v1, const Vec<T, N>& v2)
+{
+ Vec<T, N> res(v1);
+ res -= v2;
+ return res;
+}
+
+template <class T, unsigned N>
+inline Vec<T, N> operator*(const Vec<T, N>& v, const typename Vec<T, N>::value_type r)
+{
+ Vec<T, N> res(v);
+ res *= r;
+ return res;
+}
+#endif
+
+template <class T, unsigned N>
+inline Vec<T, N> operator*(const typename Vec<T, N>::value_type r, const Vec<T, N>& v)
+{
+ Vec<T, N> res(v);
+ res *= r;
+ return res;
+}
+
+#if 0
+template <class T, unsigned N>
+inline Vec<T, N> operator/(const Vec<T, N>& v, const typename Vec<T, N>::value_type r)
+{
+ Vec<T, N> res(v);
+ if (r)
+ res /= r;
+ return res;
+}
+
+// dot product
+template <class T, unsigned N>
+inline typename Vec<T, N>::value_type operator*(const Vec<T, N>& v1, const Vec<T, N>& v2)
+{
+ typename Vec<T, N>::value_type sum = 0;
+ for (unsigned int i = 0; i < N; i++)
+ sum += v1[i] * v2[i];
+ return sum;
+}
+
+// cross product for 3D Vectors
+template <typename T>
+inline Vec3<T> operator^(const Vec<T, 3>& v1, const Vec<T, 3>& v2)
+{
+ Vec3<T> res(v1[1] * v2[2] - v1[2] * v2[1], v1[2] * v2[0] - v1[0] * v2[2], v1[0] * v2[1] - v1[1] * v2[0]);
+ return res;
+}
+#endif
+
+// stream operator
+template <class T, unsigned N>
+inline std::ostream& operator<<(std::ostream& s, const Vec<T, N>& v)
+{
+ unsigned int i;
+ s << "[";
+ for (i = 0; i < N - 1; i++)
+ s << v[i] << ", ";
+ s << v[i] << "]";
+ return s;
+}
+
+//
+// Matrix external functions
+//
+/////////////////////////////////////////////////////////////////////////////
+
+template <class T, unsigned M, unsigned N>
+inline Matrix<T, M, N> operator+(const Matrix<T, M, N>& m1, const Matrix<T, M, N>& m2)
+{
+ Matrix<T, M, N> res(m1);
+ res += m2;
+ return res;
+}
+
+template <class T, unsigned M, unsigned N>
+inline Matrix<T, M, N> operator-(const Matrix<T, M, N>& m1, const Matrix<T, M, N>& m2)
+{
+ Matrix<T, M, N> res(m1);
+ res -= m2;
+ return res;
+}
+
+template <class T, unsigned M, unsigned N>
+inline Matrix<T, M, N> operator*(const Matrix<T, M, N>& m1, const typename Matrix<T, M, N>::value_type lambda)
+{
+ Matrix<T, M, N> res(m1);
+ res *= lambda;
+ return res;
+}
+
+template <class T, unsigned M, unsigned N>
+inline Matrix<T, M, N> operator*(const typename Matrix<T, M, N>::value_type lambda, const Matrix<T, M, N>& m1)
+{
+ Matrix<T, M, N> res(m1);
+ res *= lambda;
+ return res;
+}
+
+template <class T, unsigned M, unsigned N>
+inline Matrix<T, M, N> operator/(const Matrix<T, M, N>& m1, const typename Matrix<T, M, N>::value_type lambda)
+{
+ Matrix<T, M, N> res(m1);
+ res /= lambda;
+ return res;
+}
+
+template <class T, unsigned M, unsigned N, unsigned P>
+inline Matrix<T, M, P> operator*(const Matrix<T, M, N>& m1, const Matrix<T, N, P>& m2)
+{
+ unsigned int i, j, k;
+ Matrix<T, M, P> res;
+ typename Matrix<T, N, P>::value_type scale;
+
+ for (j = 0; j < P; j++) {
+ for (k = 0; k < N; k++) {
+ scale = m2(k, j);
+ for (i = 0; i < N; i++)
+ res(i, j) += m1(i, k) * scale;
+ }
+ }
+ return res;
+}
+
+template <class T, unsigned M, unsigned N>
+inline Vec<T, M> operator*(const Matrix<T, M, N>& m, const Vec<T, N>& v)
+{
+ Vec<T, M> res;
+ typename Matrix<T, M, N>::value_type scale;
+
+ for (unsigned int j = 0; j < M; j++) {
+ scale = v[j];
+ for (unsigned int i = 0; i < N; i++)
+ res[i] += m(i, j) * scale;
+ }
+ return res;
+}
+
+// stream operator
+template <class T, unsigned M, unsigned N>
+inline std::ostream& operator<<(std::ostream& s, const Matrix<T, M, N>& m)
+{
+ unsigned int i, j;
+ for (i = 0; i < M; i++) {
+ s << "[";
+ for (j = 0; j < N - 1; j++)
+ s << m(i, j) << ", ";
+ s << m(i, j) << "]" << std::endl;
+ }
+ return s;
+}
+
+} // end of namespace VecMat
+
+#endif // __VECMAT_H__
diff --git a/source/blender/freestyle/intern/geometry/matrix_util.cpp b/source/blender/freestyle/intern/geometry/matrix_util.cpp
new file mode 100644
index 00000000000..089535561d7
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/matrix_util.cpp
@@ -0,0 +1,266 @@
+/*
+ * ***** 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.
+ *
+ * This Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is:
+ * GXML/Graphite: Geometry and Graphics Programming Library + Utilities
+ * Copyright (C) 2000 Bruno Levy
+ * Contact: Bruno Levy
+ * levy@loria.fr
+ * ISA Project
+ * LORIA, INRIA Lorraine,
+ * Campus Scientifique, BP 239
+ * 54506 VANDOEUVRE LES NANCY CEDEX
+ * FRANCE
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/geometry/matrix_util.cpp
+ * \ingroup freestyle
+ * \author Bruno Levy
+ */
+
+#include <math.h>
+
+#include "matrix_util.h"
+
+namespace OGF {
+
+namespace MatrixUtil {
+
+ static const double EPS = 0.00001;
+ static int MAX_ITER = 100;
+
+ void semi_definite_symmetric_eigen(const double *mat, int n, double *eigen_vec, double *eigen_val)
+ {
+ double *a, *v;
+ double a_norm, a_normEPS, thr, thr_nn;
+ int nb_iter = 0;
+ int jj;
+ int i, j, k, ij, ik, l, m, lm, mq, lq, ll, mm, imv, im, iq, ilv, il, nn;
+ int *index;
+ double a_ij, a_lm, a_ll, a_mm, a_im, a_il;
+ double a_lm_2;
+ double v_ilv, v_imv;
+ double x;
+ double sinx, sinx_2, cosx, cosx_2, sincos;
+ double delta;
+
+ // Number of entries in mat
+ nn = (n * (n + 1)) / 2;
+
+ // Step 1: Copy mat to a
+ a = new double[nn];
+
+ for (ij = 0; ij < nn; ij++) {
+ a[ij] = mat[ij];
+ }
+
+ // Ugly Fortran-porting trick: indices for a are between 1 and n
+ a--;
+
+ // Step 2 : Init diagonalization matrix as the unit matrix
+ v = new double[n * n];
+
+ ij = 0;
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < n; j++) {
+ if (i == j) {
+ v[ij++] = 1.0;
+ }
+ else {
+ v[ij++] = 0.0;
+ }
+ }
+ }
+
+ // Ugly Fortran-porting trick: indices for v are between 1 and n
+ v--;
+
+ // Step 3 : compute the weight of the non diagonal terms
+ ij = 1;
+ a_norm = 0.0;
+ for (i = 1; i <= n; i++) {
+ for (j = 1; j <= i; j++) {
+ if (i != j) {
+ a_ij = a[ij];
+ a_norm += a_ij * a_ij;
+ }
+ ij++;
+ }
+ }
+
+ if (a_norm != 0.0) {
+ a_normEPS = a_norm * EPS;
+ thr = a_norm;
+
+ // Step 4 : rotations
+ while (thr > a_normEPS && nb_iter < MAX_ITER) {
+ nb_iter++;
+ thr_nn = thr / nn;
+
+ for (l = 1; l < n; l++) {
+ for (m = l + 1; m <= n; m++) {
+ // compute sinx and cosx
+ lq = (l * l - l) / 2;
+ mq = (m * m - m) / 2;
+
+ lm = l + mq;
+ a_lm = a[lm];
+ a_lm_2 = a_lm * a_lm;
+
+ if (a_lm_2 < thr_nn) {
+ continue;
+ }
+
+ ll = l + lq;
+ mm = m + mq;
+ a_ll = a[ll];
+ a_mm = a[mm];
+
+ delta = a_ll - a_mm;
+
+ if (delta == 0.0) {
+ x = -M_PI / 4;
+ }
+ else {
+ x = -atan((a_lm + a_lm) / delta) / 2.0;
+ }
+
+ sinx = sin(x);
+ cosx = cos(x);
+ sinx_2 = sinx * sinx;
+ cosx_2 = cosx * cosx;
+ sincos = sinx * cosx;
+
+ // rotate L and M columns
+ ilv = n * (l - 1);
+ imv = n * (m - 1);
+
+ for (i = 1; i <= n; i++) {
+ if ((i != l) && (i != m)) {
+ iq = (i * i - i) / 2;
+
+ if (i < m) {
+ im = i + mq;
+ }
+ else {
+ im = m + iq;
+ }
+ a_im = a[im];
+
+ if (i < l) {
+ il = i + lq;
+ }
+ else {
+ il = l + iq;
+ }
+ a_il = a[il];
+
+ a[il] = a_il * cosx - a_im * sinx;
+ a[im] = a_il * sinx + a_im * cosx;
+ }
+
+ ilv++;
+ imv++;
+
+ v_ilv = v[ilv];
+ v_imv = v[imv];
+
+ v[ilv] = cosx * v_ilv - sinx * v_imv;
+ v[imv] = sinx * v_ilv + cosx * v_imv;
+ }
+
+ x = a_lm * sincos;
+ x += x;
+
+ a[ll] = a_ll * cosx_2 + a_mm * sinx_2 - x;
+ a[mm] = a_ll * sinx_2 + a_mm * cosx_2 + x;
+ a[lm] = 0.0;
+
+ thr = fabs(thr - a_lm_2);
+ }
+ }
+ }
+ }
+
+ // Step 5: index conversion and copy eigen values
+
+ // back from Fortran to C++
+ a++;
+
+ for (i = 0; i < n; i++) {
+ k = i + (i * (i + 1)) / 2;
+ eigen_val[i] = a[k];
+ }
+
+ delete[] a;
+
+ // Step 6: sort the eigen values and eigen vectors
+
+ index = new int[n];
+ for (i = 0; i < n; i++) {
+ index[i] = i;
+ }
+
+ for (i = 0; i < (n - 1); i++) {
+ x = eigen_val[i];
+ k = i;
+
+ for (j = i + 1; j < n; j++) {
+ if (x < eigen_val[j]) {
+ k = j;
+ x = eigen_val[j];
+ }
+ }
+
+ eigen_val[k] = eigen_val[i];
+ eigen_val[i] = x;
+
+ jj = index[k];
+ index[k] = index[i];
+ index[i] = jj;
+ }
+
+ // Step 7: save the eigen vectors
+
+ // back from Fortran to to C++
+ v++;
+
+ ij = 0;
+ for (k = 0; k < n; k++) {
+ ik = index[k] * n;
+ for (i = 0; i < n; i++) {
+ eigen_vec[ij++] = v[ik++];
+ }
+ }
+
+ delete[] v;
+ delete[] index;
+ return;
+ }
+
+//_________________________________________________________
+
+} // MatrixUtil namespace
+
+} // OGF namespace
diff --git a/source/blender/freestyle/intern/geometry/matrix_util.h b/source/blender/freestyle/intern/geometry/matrix_util.h
new file mode 100644
index 00000000000..1cf58a8e1fd
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/matrix_util.h
@@ -0,0 +1,72 @@
+/*
+ * ***** 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.
+ *
+ * This Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is:
+ * GXML/Graphite: Geometry and Graphics Programming Library + Utilities
+ * Copyright (C) 2000 Bruno Levy
+ * Contact: Bruno Levy
+ * levy@loria.fr
+ * ISA Project
+ * LORIA, INRIA Lorraine,
+ * Campus Scientifique, BP 239
+ * 54506 VANDOEUVRE LES NANCY CEDEX
+ * FRANCE
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __MATRIX_UTIL__
+#define __MATRIX_UTIL__
+
+/** \file blender/freestyle/intern/geometry/matrix_util.h
+ * \ingroup freestyle
+ * \author Bruno Levy
+ */
+
+#include "../system/FreestyleConfig.h"
+
+namespace OGF {
+
+namespace MatrixUtil {
+
+ /**
+ * computes the eigen values and eigen vectors of a semi definite symmetric matrix
+ *
+ * @param matrix is stored in column symmetric storage, i.e.
+ * matrix = { m11, m12, m22, m13, m23, m33, m14, m24, m34, m44 ... }
+ * size = n(n+1)/2
+ *
+ * @param eigen_vectors (return) = { v1, v2, v3, ..., vn }
+ * where vk = vk0, vk1, ..., vkn
+ * size = n^2, must be allocated by caller
+ *
+ * @param eigen_values (return) are in decreasing order
+ * size = n, must be allocated by caller
+ */
+ LIB_GEOMETRY_EXPORT
+ void semi_definite_symmetric_eigen(const double *mat, int n, double *eigen_vec, double *eigen_val);
+
+} // MatrixUtil namespace
+
+} // OGF namespace
+
+#endif // __MATRIX_UTIL__
diff --git a/source/blender/freestyle/intern/geometry/normal_cycle.cpp b/source/blender/freestyle/intern/geometry/normal_cycle.cpp
new file mode 100644
index 00000000000..2f0aa268c9f
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/normal_cycle.cpp
@@ -0,0 +1,100 @@
+/*
+ * ***** 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.
+ *
+ * This Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is:
+ * OGF/Graphite: Geometry and Graphics Programming Library + Utilities
+ * Copyright (C) 2000 Bruno Levy
+ * Contact: Bruno Levy
+ * levy@loria.fr
+ * ISA Project
+ * LORIA, INRIA Lorraine,
+ * Campus Scientifique, BP 239
+ * 54506 VANDOEUVRE LES NANCY CEDEX
+ * FRANCE
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/geometry/normal_cycle.cpp
+ * \ingroup freestyle
+ * \author Bruno Levy
+ */
+
+#include "matrix_util.h"
+#include "normal_cycle.h"
+
+namespace OGF {
+
+//_________________________________________________________
+
+
+NormalCycle::NormalCycle()
+{
+}
+
+void NormalCycle::begin()
+{
+ M_[0] = M_[1] = M_[2] = M_[3] = M_[4] = M_[5] = 0;
+}
+
+void NormalCycle::end()
+{
+ double eigen_vectors[9];
+ MatrixUtil::semi_definite_symmetric_eigen(M_, 3, eigen_vectors, eigen_value_);
+
+ axis_[0] = Vec3r(eigen_vectors[0], eigen_vectors[1], eigen_vectors[2]);
+
+ axis_[1] = Vec3r(eigen_vectors[3], eigen_vectors[4], eigen_vectors[5]);
+
+ axis_[2] = Vec3r(eigen_vectors[6], eigen_vectors[7], eigen_vectors[8]);
+
+ // Normalize the eigen vectors
+ for (int i = 0; i < 3; i++) {
+ axis_[i].normalize();
+ }
+
+ // Sort the eigen vectors
+ i_[0] = 0;
+ i_[1] = 1;
+ i_[2] = 2;
+
+ double l0 = ::fabs(eigen_value_[0]);
+ double l1 = ::fabs(eigen_value_[1]);
+ double l2 = ::fabs(eigen_value_[2]);
+
+ if (l1 > l0) {
+ ogf_swap(l0 , l1 );
+ ogf_swap(i_[0], i_[1]);
+ }
+ if (l2 > l1) {
+ ogf_swap(l1 , l2 );
+ ogf_swap(i_[1], i_[2]);
+ }
+ if (l1 > l0) {
+ ogf_swap(l0 , l1 );
+ ogf_swap(i_[0], i_[1]);
+ }
+}
+
+//_________________________________________________________
+
+} // OGF namespace
diff --git a/source/blender/freestyle/intern/geometry/normal_cycle.h b/source/blender/freestyle/intern/geometry/normal_cycle.h
new file mode 100644
index 00000000000..3fbf4fb58ae
--- /dev/null
+++ b/source/blender/freestyle/intern/geometry/normal_cycle.h
@@ -0,0 +1,144 @@
+/*
+ * ***** 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.
+ *
+ * This Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is:
+ * OGF/Graphite: Geometry and Graphics Programming Library + Utilities
+ * Copyright (C) 2000 Bruno Levy
+ * Contact: Bruno Levy
+ * levy@loria.fr
+ * ISA Project
+ * LORIA, INRIA Lorraine,
+ * Campus Scientifique, BP 239
+ * 54506 VANDOEUVRE LES NANCY CEDEX
+ * FRANCE
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __MESH_TOOLS_MATH_NORMAL_CYCLE__
+#define __MESH_TOOLS_MATH_NORMAL_CYCLE__
+
+/** \file blender/freestyle/intern/geometry/normal_cycle.h
+ * \ingroup freestyle
+ * \author Bruno Levy
+ */
+
+#include "Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace Geometry;
+
+namespace OGF {
+
+template <class T> inline void ogf_swap(T& x, T& y)
+{
+ T z = x ;
+ x = y ;
+ y = z ;
+}
+
+//_________________________________________________________
+
+/**
+* NormalCycle evaluates the curvature tensor in function
+* of a set of dihedral angles and associated vectors.
+* Reference:
+* Restricted Delaunay Triangulation and Normal Cycle,
+* D. Cohen-Steiner and J.M. Morvan,
+* SOCG 2003
+*/
+class LIB_GEOMETRY_EXPORT NormalCycle {
+public:
+ NormalCycle();
+ void begin();
+ void end();
+ /**
+ * Note: the specified edge vector needs to be pre-clipped by the neighborhood.
+ */
+ void accumulate_dihedral_angle(const Vec3r& edge, real angle, real neigh_area = 1.0);
+
+ const Vec3r& eigen_vector(int i) const
+ {
+ return axis_[i_[i]];
+ }
+
+ real eigen_value(int i) const
+ {
+ return eigen_value_[i_[i]];
+ }
+
+ const Vec3r& N() const
+ {
+ return eigen_vector(2);
+ }
+
+ const Vec3r& Kmax() const
+ {
+ return eigen_vector(1);
+ }
+
+ const Vec3r& Kmin() const
+ {
+ return eigen_vector(0);
+ }
+
+ real n() const
+ {
+ return eigen_value(2);
+ }
+
+ real kmax() const
+ {
+ return eigen_value(1);
+ }
+
+ real kmin() const
+ {
+ return eigen_value(0);
+ }
+
+private:
+ real center_[3];
+ Vec3r axis_[3];
+ real eigen_value_[3];
+ real M_[6];
+ int i_[3];
+};
+
+inline void NormalCycle::accumulate_dihedral_angle(const Vec3r& edge, const double beta, double neigh_area)
+{
+ double s = beta * neigh_area / edge.norm();
+
+ M_[0] += s * edge.x() * edge.x();
+ M_[1] += s * edge.x() * edge.y();
+ M_[2] += s * edge.y() * edge.y();
+ M_[3] += s * edge.x() * edge.z();
+ M_[4] += s * edge.y() * edge.z();
+ M_[5] += s * edge.z() * edge.z();
+}
+
+//_________________________________________________________
+
+} // OGF namespace
+
+#endif // __MESH_TOOLS_MATH_NORMAL_CYCLE__
diff --git a/source/blender/freestyle/intern/image/GaussianFilter.cpp b/source/blender/freestyle/intern/image/GaussianFilter.cpp
new file mode 100644
index 00000000000..be0bef8115c
--- /dev/null
+++ b/source/blender/freestyle/intern/image/GaussianFilter.cpp
@@ -0,0 +1,112 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/image/GaussianFilter.cpp
+ * \ingroup freestyle
+ * \brief Class to perform gaussian filtering operations on an image
+ * \author Stephane Grabli
+ * \date 20/05/2003
+ */
+
+#include <stdlib.h>
+
+#include "GaussianFilter.h"
+
+GaussianFilter::GaussianFilter(float iSigma)
+{
+ _sigma = iSigma;
+ _mask = 0;
+ computeMask();
+}
+
+GaussianFilter::GaussianFilter(const GaussianFilter& iBrother)
+{
+ _sigma = iBrother._sigma;
+ _maskSize = iBrother._maskSize;
+ _bound = iBrother._bound;
+ _storedMaskSize = iBrother._storedMaskSize;
+ _mask = new float[_maskSize * _maskSize];
+ memcpy(_mask, iBrother._mask, _maskSize * _maskSize * sizeof(float));
+}
+
+GaussianFilter& GaussianFilter::operator=(const GaussianFilter& iBrother)
+{
+ _sigma = iBrother._sigma;
+ _maskSize = iBrother._maskSize;
+ _bound = iBrother._bound;
+ _storedMaskSize = iBrother._storedMaskSize;
+ _mask = new float[_storedMaskSize * _storedMaskSize];
+ memcpy(_mask, iBrother._mask, _storedMaskSize * _storedMaskSize * sizeof(float));
+ return *this;
+}
+
+
+GaussianFilter::~GaussianFilter()
+{
+ if (0 != _mask) {
+ delete[] _mask;
+ }
+}
+
+int GaussianFilter::computeMaskSize(float sigma)
+{
+ int maskSize = (int)floor(4 * sigma) + 1;
+ if (0 == (maskSize % 2))
+ ++maskSize;
+
+ return maskSize;
+}
+
+void GaussianFilter::setSigma(float sigma)
+{
+ _sigma = sigma;
+ computeMask();
+}
+
+void GaussianFilter::computeMask()
+{
+ if (0 != _mask) {
+ delete[] _mask;
+ }
+
+ _maskSize = computeMaskSize(_sigma);
+ _storedMaskSize = (_maskSize + 1) >> 1;
+ _bound = _storedMaskSize - 1;
+
+ float norm = _sigma * _sigma * 2.0f * M_PI;
+ float invNorm = 1.0f / norm;
+ _mask = new float[_storedMaskSize * _storedMaskSize * sizeof(float)];
+ for (int i = 0; i < _storedMaskSize; ++i) {
+ for (int j = 0; j < _storedMaskSize; ++j) {
+#if 0
+ _mask[i * _storedMaskSize + j] = exp(-(i * i + j * j) / (2.0 * _sigma * _sigma));
+#else
+ _mask[i * _storedMaskSize + j] = invNorm * exp(-(i * i + j * j) / (2.0 * _sigma * _sigma));
+#endif
+ }
+ }
+}
diff --git a/source/blender/freestyle/intern/image/GaussianFilter.h b/source/blender/freestyle/intern/image/GaussianFilter.h
new file mode 100644
index 00000000000..9890e615a7c
--- /dev/null
+++ b/source/blender/freestyle/intern/image/GaussianFilter.h
@@ -0,0 +1,161 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __GAUSSIANFILTER_H__
+#define __GAUSSIANFILTER_H__
+
+/** \file blender/freestyle/intern/image/GaussianFilter.h
+ * \ingroup freestyle
+ * \brief Class to perform gaussian filtering operations on an image
+ * \author Stephane Grabli
+ * \date 20/05/2003
+ */
+
+#include <cstdlib> // for abs
+#include <string.h> // for memcpy
+
+#include "../system/FreestyleConfig.h"
+
+class LIB_IMAGE_EXPORT GaussianFilter
+{
+protected:
+ /* The mask is a symetrical 2d array (with respect to the middle point).
+ * Thus, M(i,j) = M(-i,j) = M(i,-j) = M(-i,-j).
+ * For this reason, to represent a NxN array (N odd), we only store a ((N+1)/2)x((N+1)/2) array.
+ */
+ float _sigma;
+ float *_mask;
+ int _bound;
+ int _maskSize; // the real mask size (must be odd)(the size of the mask we store is ((_maskSize+1)/2)*((_maskSize+1)/2))
+ int _storedMaskSize; // (_maskSize+1)/2)
+
+public:
+ GaussianFilter(float iSigma = 1.0f);
+ GaussianFilter(const GaussianFilter&);
+ GaussianFilter& operator=(const GaussianFilter&);
+ virtual ~GaussianFilter();
+
+ /*! Returns the value for pixel x,y of image "map" after a gaussian blur, made using the sigma value.
+ * The sigma value determines the mask size (~ 2 x sigma).
+ * \param map
+ * The image we wish to work on. The Map template must implement the following methods:
+ * - float pixel(unsigned int x,unsigned int y) const;
+ * - unsigned width() const;
+ * - unsigned height() const;
+ * \param x
+ * The abscissa of the pixel where we want to evaluate the gaussian blur.
+ * \param y
+ * The ordinate of the pixel where we want to evaluate the gaussian blur.
+ * \param sigma
+ * The sigma value of the gaussian function.
+ */
+ template<class Map>
+ float getSmoothedPixel(Map *map, int x, int y);
+
+ /*! Compute the mask size and returns the REAL mask size ((2*_maskSize)-1)
+ * This method is provided for convenience.
+ */
+ static int computeMaskSize(float sigma);
+
+ /*! accessors */
+ inline float sigma() const
+ {
+ return _sigma;
+ }
+
+ inline int maskSize() const
+ {
+ return _maskSize;
+ }
+
+ inline int getBound()
+ {
+ return _bound;
+ }
+
+ /*! modifiers */
+ void setSigma(float sigma);
+#if 0
+ void SetMaskSize(int size)
+ {
+ _maskSize = size;
+ _storedMaskSize = (_maskSize + 1) >> 1;
+ }
+#endif
+
+protected:
+ void computeMask();
+};
+
+/*
+
+ #############################################
+ #############################################
+ #############################################
+ ###### ######
+ ###### I M P L E M E N T A T I O N ######
+ ###### ######
+ #############################################
+ #############################################
+ #############################################
+
+*/
+
+#include <math.h>
+
+#ifdef __MACH__
+# define sqrtf(x) (sqrt(x))
+#endif
+
+template<class Map>
+float GaussianFilter::getSmoothedPixel(Map *map, int x, int y)
+{
+ float sum = 0.0f;
+ float L = 0.0f;
+ int w = (int)map->width(); //soc
+ int h = (int)map->height(); //soc
+
+ // Current pixel is x,y
+ // Sum surrounding pixels L value:
+ for (int i = -_bound; i <= _bound; ++i) {
+ if ((y + i < 0) || (y + i >= h))
+ continue;
+ for (int j = -_bound; j <= _bound; ++j) {
+ if ((x + j < 0) || (x + j >= w))
+ continue;
+
+ float tmpL = map->pixel(x + j, y + i);
+ float m = _mask[abs(i) * _storedMaskSize + abs(j)];
+ L += m * tmpL;
+ sum += m;
+ }
+ }
+ //L /= sum;
+ return L;
+}
+
+#endif // __GAUSSIANFILTER_H__
diff --git a/source/blender/freestyle/intern/image/Image.h b/source/blender/freestyle/intern/image/Image.h
new file mode 100644
index 00000000000..1487e43a0b0
--- /dev/null
+++ b/source/blender/freestyle/intern/image/Image.h
@@ -0,0 +1,415 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __IMAGE_H__
+#define __IMAGE_H__
+
+/** \file blender/freestyle/intern/image/Image.h
+ * \ingroup freestyle
+ * \brief Class to encapsulate an array of RGB or Gray level values
+ * \author Stephane Grabli
+ * \date 20/05/2003
+ */
+
+#include <string.h> // for memcpy
+
+//
+// Image base class, for all types of images
+//
+///////////////////////////////////////////////////////////////////////////////
+
+/*! This class allows the storing of part of an image, while allowing a normal access to its pixel values.
+ * You can for example only a rectangle of sw*sh, whose lower-left corner is at (ox, oy), of an image of
+ * size w*h, and access these pixels using x,y coordinates specified in the whole image coordinate system.
+ */
+class FrsImage
+{
+public:
+ /*! Default constructor */
+ FrsImage()
+ {
+ _storedWidth = 0;
+ _storedHeight = 0;
+ _width = 0;
+ _height = 0;
+ _Ox = 0;
+ _Oy = 0;
+ }
+
+ /*! Copy constructor */
+ FrsImage(const FrsImage& brother)
+ {
+ _storedWidth = brother._storedWidth;
+ _storedHeight = brother._storedHeight;
+ _width = brother._width;
+ _height = brother._height;
+ _Ox = brother._Ox;
+ _Oy = brother._Oy;
+ }
+
+ /*! Builds an FrsImage from its width and height.
+ * The memory is allocated consequently.
+ */
+ FrsImage(unsigned w, unsigned h)
+ {
+ _width = w;
+ _height = h;
+ _storedWidth = w;
+ _storedHeight = h;
+ _Ox = 0;
+ _Oy = 0;
+ }
+
+ /*! Builds a partial-storing image.
+ * \param w
+ * The width of the complete image
+ * \param h
+ * The height of the complete image
+ * \param sw
+ * The width of the rectangle that will actually be stored.
+ * \param sh
+ * The height of the rectangle that will actually be stored.
+ * \param ox
+ * The x-abscissa of the origin of the rectangle that will actually be stored.
+ * \param oy
+ * The x-abscissa of the origin of the rectangle that will actually be stored.
+ */
+ FrsImage(unsigned w, unsigned h, unsigned sw, unsigned sh, unsigned ox, unsigned oy)
+ {
+ _width = w;
+ _height = h;
+ _storedWidth = sw;
+ _storedHeight = sh;
+ _Ox = ox;
+ _Oy = oy;
+ }
+
+ /*! Operator= */
+ FrsImage& operator=(const FrsImage& brother)
+ {
+ _width = brother._width;
+ _height = brother._height;
+ _storedWidth = brother._storedWidth;
+ _storedHeight = brother._storedHeight;
+ _Ox = brother._Ox;
+ _Oy = brother._Oy;
+ return *this;
+ }
+
+ /*! Destructor */
+ virtual ~FrsImage() {}
+
+ /*! Returns the width of the complete image */
+ inline unsigned width() const
+ {
+ return _width;
+ }
+
+ /*! Returns the height of the complete image */
+ inline unsigned height() const
+ {
+ return _height;
+ }
+
+ /*! Returns the grey value for pixel x,y */
+ virtual float pixel(unsigned x, unsigned y) const = 0;
+
+ /*! Sets the array.
+ * \param array
+ * The array containing the values we wish to store.
+ * Its size is sw*sh.
+ * \param width
+ * The width of the complete image
+ * \param height
+ * The height of the complete image
+ * \param sw
+ * The width of the rectangle that will actually be stored.
+ * \param sh
+ * The height of the rectangle that will actually be stored.
+ * \param ox
+ * The x-abscissa of the origin of the rectangle that will actually be stored.
+ * \param oy
+ * The x-abscissa of the origin of the rectangle that will actually be stored.
+ * \param copy
+ * If true, the array is copied, otherwise the pointer is copied
+ */
+ virtual void setArray(float *array, unsigned width, unsigned height, unsigned sw, unsigned sh,
+ unsigned x, unsigned y, bool copy = true) = 0;
+
+ /*! Returns the array containing the pixels values.
+ * Its size is sw*sh, i.e. potentially a smaller rectangular part of the complete image.
+ */
+ virtual float *getArray() = 0;
+
+protected:
+ unsigned _width;
+ unsigned _height;
+ unsigned _storedWidth;
+ unsigned _storedHeight;
+ unsigned _Ox; // origin of the stored part
+ unsigned _Oy; // origin of the stored part
+};
+
+
+//
+// RGBImage
+//
+///////////////////////////////////////////////////////////////////////////////
+class RGBImage : public FrsImage
+{
+public:
+ RGBImage() : FrsImage()
+ {
+ _rgb = 0;
+ }
+
+ RGBImage(const RGBImage& brother) : FrsImage(brother)
+ {
+ _rgb = new float[3 * _storedWidth * _storedHeight];
+ memcpy(_rgb, brother._rgb, 3 * _storedWidth * _storedHeight * sizeof(float));
+ }
+
+ RGBImage(unsigned w, unsigned h) : FrsImage(w, h)
+ {
+ _rgb = new float[3 * _width * _height];
+ }
+
+ RGBImage(float *rgb, unsigned w, unsigned h) : FrsImage(w, h)
+ {
+ _rgb = new float[3 * _width * _height];
+ memcpy(_rgb, rgb, 3 * _width * _height * sizeof(float));
+ }
+
+ /*! Builds an RGB partial image from the useful part buffer.
+ * \param rgb
+ * The array of size 3*sw*sh containing the RGB values of the sw*sh pixels we need to stored.
+ * These sw*sh pixels constitute a rectangular part of a bigger RGB image containing w*h pixels.
+ * \param w
+ * The width of the complete image
+ * \param h
+ * The height of the complete image
+ * \param sw
+ * The width of the part of the image we want to store and work on
+ * \param sh
+ * The height of the part of the image we want to store and work on
+ */
+ RGBImage(float *rgb, unsigned w, unsigned h, unsigned sw, unsigned sh, unsigned ox, unsigned oy)
+ : FrsImage(w, h, sw, sh, ox, oy)
+ {
+ _rgb = new float[3 * _storedWidth * _storedHeight];
+ memcpy(_rgb, rgb, 3 * _storedWidth * _storedHeight * sizeof(float));
+ }
+
+ RGBImage& operator=(const RGBImage& brother)
+ {
+ dynamic_cast<FrsImage&>(*this) = brother;
+ _rgb = new float[3 * _storedWidth * _storedHeight];
+ memcpy(_rgb, brother._rgb, 3 * _storedWidth * _storedHeight * sizeof(float));
+ return *this;
+ }
+
+ virtual ~RGBImage()
+ {
+ if(_rgb)
+ delete[] _rgb;
+ }
+
+ inline float getR(unsigned x, unsigned y) const
+ {
+ return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3];
+ }
+
+ inline float getG(unsigned x, unsigned y) const
+ {
+ return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3 + 1];
+ }
+
+ inline float getB(unsigned x, unsigned y) const
+ {
+ return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3 + 2];
+ }
+
+ virtual void setPixel(unsigned x, unsigned y, float r, float g, float b)
+ {
+ float *tmp = &(_rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3]);
+ *tmp = r;
+ tmp++;
+ *tmp = g;
+ tmp++;
+ *tmp = b;
+ }
+
+ virtual float pixel(unsigned x, unsigned y) const
+ {
+ float res = 0.0f;
+ float *tmp = &(_rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3]);
+ res += 11.0f * (*tmp);
+ tmp++;
+ res += 16.0f * (*tmp);
+ tmp++;
+ res += 5.0f * (*tmp);
+ return res / 32.0f;
+ }
+
+ /*! Sets the RGB array.
+ * copy
+ * If true, the array is copied, otherwise the pointer is copied
+ */
+ virtual void setArray(float *rgb, unsigned width, unsigned height, unsigned sw, unsigned sh,
+ unsigned x, unsigned y, bool copy = true)
+ {
+ _width = width;
+ _height = height;
+ _storedWidth = sw;
+ _storedHeight = sh;
+ _Ox = x;
+ _Oy = y;
+ if (!copy) {
+ _rgb = rgb;
+ return;
+ }
+
+ memcpy(_rgb, rgb, 3 * _storedWidth * _storedHeight * sizeof(float));
+ }
+
+ virtual float *getArray()
+ {
+ return _rgb;
+ }
+
+protected:
+ float *_rgb;
+};
+
+
+//
+// GrayImage
+//
+///////////////////////////////////////////////////////////////////////////////
+
+class GrayImage : public FrsImage
+{
+public:
+ GrayImage() : FrsImage()
+ {
+ _lvl = 0;
+ }
+
+ GrayImage(const GrayImage& brother) : FrsImage(brother)
+ {
+ _lvl = new float[_storedWidth * _storedHeight];
+ memcpy(_lvl, brother._lvl, _storedWidth * _storedHeight * sizeof(*_lvl));
+ }
+
+ /*! Builds an empty gray image */
+ GrayImage(unsigned w, unsigned h) : FrsImage(w, h)
+ {
+ _lvl = new float[_width * _height];
+ }
+
+ GrayImage(float *lvl, unsigned w, unsigned h) : FrsImage(w, h)
+ {
+ _lvl = new float[_width * _height];
+ memcpy(_lvl, lvl, _width * _height * sizeof(*_lvl));
+ }
+
+ /*! Builds a partial image from the useful part buffer.
+ * \param lvl
+ * The array of size sw*sh containing the gray values of the sw*sh pixels we need to stored.
+ * These sw*sh pixels constitute a rectangular part of a bigger gray image containing w*h pixels.
+ * \param w
+ * The width of the complete image
+ * \param h
+ * The height of the complete image
+ * \param sw
+ * The width of the part of the image we want to store and work on
+ * \param sh
+ * The height of the part of the image we want to store and work on
+ */
+ GrayImage(float *lvl, unsigned w, unsigned h, unsigned sw, unsigned sh, unsigned ox, unsigned oy)
+ : FrsImage(w, h, sw, sh, ox, oy)
+ {
+ _lvl = new float[_storedWidth * _storedHeight];
+ memcpy(_lvl, lvl, _storedWidth * _storedHeight * sizeof(float));
+ }
+
+ GrayImage& operator=(const GrayImage& brother)
+ {
+ dynamic_cast<FrsImage&>(*this) = brother;
+ _lvl = new float[_storedWidth * _storedHeight];
+ memcpy(_lvl, brother._lvl, _storedWidth * _storedHeight * sizeof(float));
+ return *this;
+ }
+
+ virtual ~GrayImage()
+ {
+ if (_lvl)
+ delete[] _lvl;
+ }
+
+ inline void setPixel(unsigned x, unsigned y, float v)
+ {
+ _lvl[(y - _Oy) * _storedWidth + (x - _Ox)] = v;
+ }
+
+ inline float pixel(unsigned x, unsigned y) const
+ {
+ return _lvl[(y - _Oy) * _storedWidth + (x - _Ox)];
+ }
+
+ /*! Sets the array.
+ * copy
+ * If true, the array is copie, otherwise the pounsigneder is copied
+ */
+ void setArray(float *lvl, unsigned width, unsigned height, unsigned sw, unsigned sh,
+ unsigned x, unsigned y, bool copy = true)
+ {
+ _width = width;
+ _height = height;
+ _storedWidth = sw;
+ _storedHeight = sh;
+ _Ox = x;
+ _Oy = y;
+ if (!copy) {
+ _lvl = lvl;
+ return;
+ }
+
+ memcpy(_lvl, lvl, _storedWidth * _storedHeight * sizeof(float));
+ }
+
+ /*! Returns the array containing the gray values. */
+ virtual float *getArray()
+ {
+ return _lvl;
+ }
+
+protected:
+ float *_lvl;
+};
+
+#endif // __IMAGE_H__
diff --git a/source/blender/freestyle/intern/image/ImagePyramid.cpp b/source/blender/freestyle/intern/image/ImagePyramid.cpp
new file mode 100644
index 00000000000..c7616fbce23
--- /dev/null
+++ b/source/blender/freestyle/intern/image/ImagePyramid.cpp
@@ -0,0 +1,192 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/image/ImagePyramid.cpp
+ * \ingroup freestyle
+ * \brief Class to represent a pyramid of images
+ * \author Stephane Grabli
+ * \date 25/12/2003
+ */
+
+#include <iostream>
+
+#include "GaussianFilter.h"
+#include "Image.h"
+#include "ImagePyramid.h"
+
+using namespace std;
+
+#if 0
+ImagePyramid::ImagePyramid(const GrayImage& level0, unsigned nbLevels)
+{
+ BuildPyramid(level0,nbLevels);
+}
+#endif
+
+ImagePyramid::ImagePyramid(const ImagePyramid& iBrother)
+{
+ if (!_levels.empty()) {
+ for (vector<GrayImage*>::iterator im = _levels.begin(), imend = _levels.end(); im != imend; ++im) {
+ _levels.push_back(new GrayImage(**im));
+ }
+ }
+}
+
+ImagePyramid::~ImagePyramid()
+{
+ if (!_levels.empty()) {
+ for (vector<GrayImage*>::iterator im = _levels.begin(), imend = _levels.end(); im != imend; ++im) {
+ delete (*im);
+ }
+ _levels.clear();
+ }
+}
+
+GrayImage * ImagePyramid::getLevel(int l)
+{
+ return _levels[l];
+}
+
+float ImagePyramid::pixel(int x, int y, int level)
+{
+ GrayImage *img = _levels[level];
+ if (0 == level) {
+ return img->pixel(x, y);
+ }
+ unsigned int i = 1 << level;
+ unsigned int sx = x >> level;
+ unsigned int sy = y >> level;
+ if (sx >= img->width())
+ sx = img->width() - 1;
+ if (sy >= img->height())
+ sy = img->height() - 1;
+
+ // bilinear interpolation
+ float A = i * (sx + 1) - x;
+ float B = x - i * sx;
+ float C = i * (sy + 1) - y;
+ float D = y - i * sy;
+
+ float P1(0), P2(0);
+ P1 = A * img->pixel(sx, sy);
+ if (sx < img->width() - 1) {
+ if (x % i != 0)
+ P1 += B * img->pixel(sx + 1, sy);
+ }
+ else {
+ P1 += B * img->pixel(sx, sy);
+ }
+ if (sy < img->height() - 1) {
+ if (y % i != 0) {
+ P2 = A * img->pixel(sx, sy + 1);
+ if (sx < img->width() - 1) {
+ if (x % i != 0)
+ P2 += B * img->pixel(sx + 1, sy + 1);
+ }
+ else {
+ P2 += B * img->pixel(sx, sy + 1);
+ }
+ }
+ }
+ else {
+ P2 = P1;
+ }
+ return (1.0f / (float)(1 << (2 * level))) * (C * P1 + D * P2);
+}
+
+int ImagePyramid::width(int level)
+{
+ return _levels[level]->width();
+}
+
+int ImagePyramid::height(int level)
+{
+ return _levels[level]->height();
+}
+
+GaussianPyramid::GaussianPyramid(const GrayImage& level0, unsigned nbLevels, float iSigma) : ImagePyramid()
+{
+ _sigma = iSigma;
+ BuildPyramid(level0, nbLevels);
+}
+
+GaussianPyramid::GaussianPyramid(GrayImage* level0, unsigned nbLevels, float iSigma) : ImagePyramid()
+{
+ _sigma = iSigma;
+ BuildPyramid(level0, nbLevels);
+}
+
+GaussianPyramid::GaussianPyramid(const GaussianPyramid& iBrother) : ImagePyramid(iBrother)
+{
+ _sigma = iBrother._sigma;
+}
+
+void GaussianPyramid::BuildPyramid(const GrayImage& level0, unsigned nbLevels)
+{
+ GrayImage *pLevel = new GrayImage(level0);
+ BuildPyramid(pLevel, nbLevels);
+}
+
+void GaussianPyramid::BuildPyramid(GrayImage* level0, unsigned nbLevels)
+{
+ GrayImage *pLevel = level0;
+ _levels.push_back(pLevel);
+ GaussianFilter gf(_sigma);
+ // build the nbLevels:
+ unsigned w = pLevel->width();
+ unsigned h = pLevel->height();
+ if (nbLevels != 0) {
+ for (unsigned int i = 0; i < nbLevels; ++i) { //soc
+ w = pLevel->width() >> 1;
+ h = pLevel->height() >> 1;
+ GrayImage *img = new GrayImage(w, h);
+ for (unsigned int y = 0; y < h; ++y) {
+ for (unsigned int x = 0; x < w; ++x) {
+ float v = gf.getSmoothedPixel<GrayImage>(pLevel, 2 * x, 2 * y);
+ img->setPixel(x, y, v);
+ }
+ }
+ _levels.push_back(img);
+ pLevel = img;
+ }
+ }
+ else {
+ while ((w > 1) && (h > 1)) {
+ w = pLevel->width() >> 1;
+ h = pLevel->height() >> 1;
+ GrayImage *img = new GrayImage(w, h);
+ for (unsigned int y = 0; y < h; ++y) {
+ for (unsigned int x = 0; x < w; ++x) {
+ float v = gf.getSmoothedPixel<GrayImage>(pLevel, 2 * x, 2 * y);
+ img->setPixel(x, y, v);
+ }
+ }
+ _levels.push_back(img);
+ pLevel = img;
+ }
+ }
+}
diff --git a/source/blender/freestyle/intern/image/ImagePyramid.h b/source/blender/freestyle/intern/image/ImagePyramid.h
new file mode 100644
index 00000000000..4bab663318e
--- /dev/null
+++ b/source/blender/freestyle/intern/image/ImagePyramid.h
@@ -0,0 +1,116 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __IMAGEPYRAMID_H__
+#define __IMAGEPYRAMID_H__
+
+/** \file blender/freestyle/intern/image/ImagePyramid.h
+ * \ingroup freestyle
+ * \brief Class to represent a pyramid of images
+ * \author Stephane Grabli
+ * \date 25/12/2003
+ */
+
+#include <vector>
+
+#include "../system/FreestyleConfig.h"
+
+class GrayImage;
+
+class LIB_IMAGE_EXPORT ImagePyramid
+{
+protected:
+ std::vector<GrayImage*> _levels;
+
+public:
+ ImagePyramid(){}
+ ImagePyramid(const ImagePyramid& iBrother);
+ //ImagePyramid(const GrayImage& level0, unsigned nbLevels);
+ virtual ~ImagePyramid();
+
+ /*! Builds the pyramid.
+ * must be overloaded by inherited classes.
+ * if nbLevels==0, the complete pyramid is built
+ */
+ virtual void BuildPyramid(const GrayImage& level0, unsigned nbLevels) = 0;
+
+ /*! Builds a pyramid without copying the base level */
+ virtual void BuildPyramid(GrayImage* level0, unsigned nbLevels) = 0;
+
+ virtual GrayImage * getLevel(int l);
+ /*! Returns the pixel x,y using bilinear interpolation.
+ * \param x
+ * the abscissa specified in the finest level coordinate system
+ * \param y
+ * the ordinate specified in the finest level coordinate system
+ * \param level
+ * the level from which we want the pixel to be evaluated
+ */
+ virtual float pixel(int x, int y, int level=0);
+
+ /*! Returns the width of the level-th level image */
+ virtual int width(int level=0);
+
+ /*! Returns the height of the level-th level image */
+ virtual int height(int level=0);
+
+ /*! Returns the number of levels in the pyramid */
+ inline int getNumberOfLevels() const
+ {
+ return _levels.size();
+ }
+};
+
+class LIB_IMAGE_EXPORT GaussianPyramid : public ImagePyramid
+{
+protected:
+ float _sigma;
+
+public:
+ GaussianPyramid(float iSigma=1.f) : ImagePyramid()
+ {
+ _sigma = iSigma;
+ }
+
+ GaussianPyramid(const GrayImage& level0, unsigned nbLevels, float iSigma=1.0f);
+ GaussianPyramid(GrayImage* level0, unsigned nbLevels, float iSigma=1.0f);
+ GaussianPyramid(const GaussianPyramid& iBrother);
+ virtual ~GaussianPyramid() {}
+
+ virtual void BuildPyramid(const GrayImage& level0, unsigned nbLevels);
+ virtual void BuildPyramid(GrayImage* level0, unsigned nbLevels);
+
+ /* accessors */
+ inline float getSigma() const
+ {
+ return _sigma;
+ }
+
+ /* modifiers */
+};
+
+#endif // __IMAGEPYRAMID_H__
diff --git a/source/blender/freestyle/intern/python/BPy_BBox.cpp b/source/blender/freestyle/intern/python/BPy_BBox.cpp
new file mode 100644
index 00000000000..0acd32bad58
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_BBox.cpp
@@ -0,0 +1,100 @@
+#include "BPy_BBox.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int BBox_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &BBox_Type ) < 0 )
+ return -1;
+
+ Py_INCREF( &BBox_Type );
+ PyModule_AddObject(module, "BBox", (PyObject *)&BBox_Type);
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char BBox___doc__[] =
+"Class for representing a bounding box.\n";
+
+static int BBox___init__(BPy_BBox *self, PyObject *args, PyObject *kwds)
+{
+ if(!( PyArg_ParseTuple(args, "") ))
+ return -1;
+ self->bb = new BBox< Vec3r>();
+ return 0;
+}
+
+static void BBox___dealloc__(BPy_BBox* self)
+{
+ delete self->bb;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+
+static PyObject * BBox___repr__(BPy_BBox* self)
+{
+ return PyUnicode_FromFormat("BBox - address: %p", self->bb );
+}
+
+/*----------------------BBox instance definitions ----------------------------*/
+static PyMethodDef BPy_BBox_methods[] = {
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_BBox type definition ------------------------------*/
+
+PyTypeObject BBox_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BBox", /* tp_name */
+ sizeof(BPy_BBox), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)BBox___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)BBox___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ BBox___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_BBox_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)BBox___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_BBox.h b/source/blender/freestyle/intern/python/BPy_BBox.h
new file mode 100644
index 00000000000..f8282187da0
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_BBox.h
@@ -0,0 +1,38 @@
+#ifndef FREESTYLE_PYTHON_BBOX_H
+#define FREESTYLE_PYTHON_BBOX_H
+
+#include <Python.h>
+
+#include "../geometry/BBox.h"
+#include "../geometry/Geom.h"
+using namespace Geometry;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject BBox_Type;
+
+#define BPy_BBox_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &BBox_Type) )
+
+/*---------------------------Python BPy_BBox structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ BBox<Vec3r> *bb;
+} BPy_BBox;
+
+/*---------------------------Python BPy_BBox visible prototypes-----------*/
+
+int BBox_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_BBOX_H */
diff --git a/source/blender/freestyle/intern/python/BPy_BinaryPredicate0D.cpp b/source/blender/freestyle/intern/python/BPy_BinaryPredicate0D.cpp
new file mode 100644
index 00000000000..693d35b1f60
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_BinaryPredicate0D.cpp
@@ -0,0 +1,166 @@
+#include "BPy_BinaryPredicate0D.h"
+
+#include "BPy_Convert.h"
+#include "BPy_Interface0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int BinaryPredicate0D_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &BinaryPredicate0D_Type ) < 0 )
+ return -1;
+
+ Py_INCREF( &BinaryPredicate0D_Type );
+ PyModule_AddObject(module, "BinaryPredicate0D", (PyObject *)&BinaryPredicate0D_Type);
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char BinaryPredicate0D___doc__[] =
+"Base class for binary predicates working on :class:`Interface0D`\n"
+"objects. A BinaryPredicate0D is typically an ordering relation\n"
+"between two Interface0D objects. The predicate evaluates a relation\n"
+"between the two Interface0D instances and returns a boolean value (true\n"
+"or false). It is used by invoking the __call__() method.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __call__(inter1, inter2)\n"
+"\n"
+" Must be overload by inherited classes. It evaluates a relation\n"
+" between two Interface0D objects.\n"
+"\n"
+" :arg inter1: The first Interface0D object.\n"
+" :type inter1: :class:`Interface0D`\n"
+" :arg inter2: The second Interface0D object.\n"
+" :type inter2: :class:`Interface0D`\n"
+" :return: True or false.\n"
+" :rtype: bool\n";
+
+static int BinaryPredicate0D___init__(BPy_BinaryPredicate0D *self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->bp0D = new BinaryPredicate0D();
+ self->bp0D->py_bp0D = (PyObject *) self;
+
+ return 0;
+}
+
+static void BinaryPredicate0D___dealloc__(BPy_BinaryPredicate0D* self)
+{
+ if (self->bp0D)
+ delete self->bp0D;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+
+static PyObject * BinaryPredicate0D___repr__(BPy_BinaryPredicate0D* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->bp0D->getName().c_str(), self->bp0D );
+}
+
+static char BinaryPredicate0D_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the binary 0D predicate.\n"
+"\n"
+" :return: The name of the binary 0D predicate.\n"
+" :rtype: str\n";
+
+static PyObject * BinaryPredicate0D_getName( BPy_BinaryPredicate0D *self, PyObject *args)
+{
+ return PyUnicode_FromString( self->bp0D->getName().c_str() );
+}
+
+static PyObject * BinaryPredicate0D___call__( BPy_BinaryPredicate0D *self, PyObject *args, PyObject *kwds)
+{
+ BPy_Interface0D *obj1, *obj2;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if( !PyArg_ParseTuple(args, "O!O!", &Interface0D_Type, &obj1, &Interface0D_Type, &obj2) )
+ return NULL;
+
+ if( typeid(*(self->bp0D)) == typeid(BinaryPredicate0D) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->bp0D->operator()( *(obj1->if0D) , *(obj2->if0D) ) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->bp0D->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return PyBool_from_bool( self->bp0D->result );
+
+}
+
+/*----------------------BinaryPredicate0D instance definitions ----------------------------*/
+static PyMethodDef BPy_BinaryPredicate0D_methods[] = {
+ {"getName", ( PyCFunction ) BinaryPredicate0D_getName, METH_NOARGS, BinaryPredicate0D_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_BinaryPredicate0D type definition ------------------------------*/
+
+PyTypeObject BinaryPredicate0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BinaryPredicate0D", /* tp_name */
+ sizeof(BPy_BinaryPredicate0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)BinaryPredicate0D___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)BinaryPredicate0D___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)BinaryPredicate0D___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ BinaryPredicate0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_BinaryPredicate0D_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)BinaryPredicate0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_BinaryPredicate0D.h b/source/blender/freestyle/intern/python/BPy_BinaryPredicate0D.h
new file mode 100644
index 00000000000..6a9a0775608
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_BinaryPredicate0D.h
@@ -0,0 +1,36 @@
+#ifndef FREESTYLE_PYTHON_BINARYPREDICATE0D_H
+#define FREESTYLE_PYTHON_BINARYPREDICATE0D_H
+
+#include <Python.h>
+
+#include "../stroke/Predicates0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject BinaryPredicate0D_Type;
+
+#define BPy_BinaryPredicate0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &BinaryPredicate0D_Type) )
+
+/*---------------------------Python BPy_BinaryPredicate0D structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ BinaryPredicate0D *bp0D;
+} BPy_BinaryPredicate0D;
+
+/*---------------------------Python BPy_BinaryPredicate0D visible prototypes-----------*/
+
+int BinaryPredicate0D_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_BINARYPREDICATE0D_H */
diff --git a/source/blender/freestyle/intern/python/BPy_BinaryPredicate1D.cpp b/source/blender/freestyle/intern/python/BPy_BinaryPredicate1D.cpp
new file mode 100644
index 00000000000..e690a6d51c1
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_BinaryPredicate1D.cpp
@@ -0,0 +1,193 @@
+#include "BPy_BinaryPredicate1D.h"
+
+#include "BPy_Convert.h"
+#include "BPy_Interface1D.h"
+
+#include "BinaryPredicate1D/BPy_FalseBP1D.h"
+#include "BinaryPredicate1D/BPy_Length2DBP1D.h"
+#include "BinaryPredicate1D/BPy_SameShapeIdBP1D.h"
+#include "BinaryPredicate1D/BPy_TrueBP1D.h"
+#include "BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int BinaryPredicate1D_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &BinaryPredicate1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &BinaryPredicate1D_Type );
+ PyModule_AddObject(module, "BinaryPredicate1D", (PyObject *)&BinaryPredicate1D_Type);
+
+ if( PyType_Ready( &FalseBP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &FalseBP1D_Type );
+ PyModule_AddObject(module, "FalseBP1D", (PyObject *)&FalseBP1D_Type);
+
+ if( PyType_Ready( &Length2DBP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Length2DBP1D_Type );
+ PyModule_AddObject(module, "Length2DBP1D", (PyObject *)&Length2DBP1D_Type);
+
+ if( PyType_Ready( &SameShapeIdBP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &SameShapeIdBP1D_Type );
+ PyModule_AddObject(module, "SameShapeIdBP1D", (PyObject *)&SameShapeIdBP1D_Type);
+
+ if( PyType_Ready( &TrueBP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &TrueBP1D_Type );
+ PyModule_AddObject(module, "TrueBP1D", (PyObject *)&TrueBP1D_Type);
+
+ if( PyType_Ready( &ViewMapGradientNormBP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ViewMapGradientNormBP1D_Type );
+ PyModule_AddObject(module, "ViewMapGradientNormBP1D", (PyObject *)&ViewMapGradientNormBP1D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char BinaryPredicate1D___doc__[] =
+"Base class for binary predicates working on :class:`Interface1D`\n"
+"objects. A BinaryPredicate1D is typically an ordering relation\n"
+"between two Interface1D objects. The predicate evaluates a relation\n"
+"between the two Interface1D instances and returns a boolean value (true\n"
+"or false). It is used by invoking the __call__() method.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __call__(inter1, inter2)\n"
+"\n"
+" Must be overload by inherited classes. It evaluates a relation\n"
+" between two Interface1D objects.\n"
+"\n"
+" :arg inter1: The first Interface1D object.\n"
+" :type inter1: :class:`Interface1D`\n"
+" :arg inter2: The second Interface1D object.\n"
+" :type inter2: :class:`Interface1D`\n"
+" :return: True or false.\n"
+" :rtype: bool\n";
+
+static int BinaryPredicate1D___init__(BPy_BinaryPredicate1D *self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->bp1D = new BinaryPredicate1D();
+ self->bp1D->py_bp1D = (PyObject *) self;
+ return 0;
+}
+
+static void BinaryPredicate1D___dealloc__(BPy_BinaryPredicate1D* self)
+{
+ if (self->bp1D)
+ delete self->bp1D;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * BinaryPredicate1D___repr__(BPy_BinaryPredicate1D* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->bp1D->getName().c_str(), self->bp1D );
+}
+
+static char BinaryPredicate1D_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the binary 1D predicate.\n"
+"\n"
+" :return: The name of the binary 1D predicate.\n"
+" :rtype: str\n";
+
+static PyObject *BinaryPredicate1D_getName( BPy_BinaryPredicate1D *self, PyObject *args)
+{
+ return PyUnicode_FromString( self->bp1D->getName().c_str() );
+}
+
+static PyObject *BinaryPredicate1D___call__( BPy_BinaryPredicate1D *self, PyObject *args, PyObject *kwds)
+{
+ BPy_Interface1D *obj1, *obj2;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if( !PyArg_ParseTuple(args, "O!O!", &Interface1D_Type, &obj1, &Interface1D_Type, &obj2) )
+ return NULL;
+
+ if( typeid(*(self->bp1D)) == typeid(BinaryPredicate1D) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->bp1D->operator()( *(obj1->if1D) , *(obj2->if1D) ) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->bp1D->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return PyBool_from_bool( self->bp1D->result );
+}
+
+/*----------------------BinaryPredicate1D instance definitions ----------------------------*/
+static PyMethodDef BPy_BinaryPredicate1D_methods[] = {
+ {"getName", ( PyCFunction ) BinaryPredicate1D_getName, METH_NOARGS, BinaryPredicate1D_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_BinaryPredicate1D type definition ------------------------------*/
+PyTypeObject BinaryPredicate1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BinaryPredicate1D", /* tp_name */
+ sizeof(BPy_BinaryPredicate1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)BinaryPredicate1D___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)BinaryPredicate1D___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)BinaryPredicate1D___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ BinaryPredicate1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_BinaryPredicate1D_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)BinaryPredicate1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_BinaryPredicate1D.h b/source/blender/freestyle/intern/python/BPy_BinaryPredicate1D.h
new file mode 100644
index 00000000000..5a993f84f5b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_BinaryPredicate1D.h
@@ -0,0 +1,35 @@
+#ifndef FREESTYLE_PYTHON_BINARYPREDICATE1D_H
+#define FREESTYLE_PYTHON_BINARYPREDICATE1D_H
+
+#include <Python.h>
+
+#include "../stroke/Predicates1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject BinaryPredicate1D_Type;
+
+#define BPy_BinaryPredicate1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &BinaryPredicate1D_Type) )
+
+/*---------------------------Python BPy_BinaryPredicate1D structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ BinaryPredicate1D *bp1D;
+} BPy_BinaryPredicate1D;
+
+/*---------------------------Python BPy_BinaryPredicate1D visible prototypes-----------*/
+
+int BinaryPredicate1D_Init( PyObject *module );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_BINARYPREDICATE1D_H */
diff --git a/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp
new file mode 100644
index 00000000000..5c824981aa3
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_ContextFunctions.cpp
@@ -0,0 +1,262 @@
+#include "BPy_ContextFunctions.h"
+#include "BPy_Convert.h"
+
+#include "../stroke/ContextFunctions.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------ MODULE FUNCTIONS ----------------------------------
+
+static char ContextFunctions_GetTimeStampCF___doc__[] =
+".. function:: GetTimeStampCF()\n"
+"\n"
+" Returns the system time stamp.\n"
+"\n"
+" :return: The system time stamp.\n"
+" :rtype: int\n";
+
+static PyObject *
+ContextFunctions_GetTimeStampCF( PyObject* self )
+{
+ return PyLong_FromLong( ContextFunctions::GetTimeStampCF() );
+}
+
+static char ContextFunctions_GetCanvasWidthCF___doc__[] =
+".. method:: GetCanvasWidthCF()\n"
+"\n"
+" Returns the canvas width.\n"
+"\n"
+" :return: The canvas width.\n"
+" :rtype: int\n";
+
+static PyObject *
+ContextFunctions_GetCanvasWidthCF( PyObject* self )
+{
+ return PyLong_FromLong( ContextFunctions::GetCanvasWidthCF() );
+}
+
+static char ContextFunctions_GetCanvasHeightCF___doc__[] =
+".. method:: GetCanvasHeightCF()\n"
+"\n"
+" Returns the canvas height.\n"
+"\n"
+" :return: The canvas height.\n"
+" :rtype: int\n";
+
+static PyObject *
+ContextFunctions_GetCanvasHeightCF( PyObject* self )
+{
+ return PyLong_FromLong( ContextFunctions::GetCanvasHeightCF() );
+}
+
+static char ContextFunctions_LoadMapCF___doc__[] =
+".. function:: LoadMapCF(iFileName, iMapName, iNbLevels=4, iSigma=1.0)\n"
+"\n"
+" Loads an image map for further reading.\n"
+"\n"
+" :arg iFileName: The name of the image file.\n"
+" :type iFileName: str\n"
+" :arg iMapName: The name that will be used to access this image.\n"
+" :type iMapName: str\n"
+" :arg iNbLevels: The number of levels in the map pyramid\n"
+" (default = 4). If iNbLevels == 0, the complete pyramid is\n"
+" built.\n"
+" :type iNbLevels: int\n"
+" :arg iSigma: The sigma value of the gaussian function.\n"
+" :type iSigma: float\n";
+
+static PyObject *
+ContextFunctions_LoadMapCF( PyObject *self, PyObject *args )
+{
+ char *fileName, *mapName;
+ unsigned nbLevels;
+ float sigma;
+
+ if( !PyArg_ParseTuple(args, "ssIf", &fileName, &mapName, &nbLevels, &sigma) )
+ return NULL;
+
+ ContextFunctions::LoadMapCF(fileName, mapName, nbLevels, sigma);
+
+ Py_RETURN_NONE;
+}
+
+static char ContextFunctions_ReadMapPixelCF___doc__[] =
+".. function:: ReadMapPixelCF(iMapName, level, x, y)\n"
+"\n"
+" Reads a pixel in a user-defined map.\n"
+"\n"
+" :arg iMapName: The name of the map.\n"
+" :type iMapName: str\n"
+" :arg level: The level of the pyramid in which we wish to read the\n"
+" pixel.\n"
+" :type level: int\n"
+" :arg x: The x coordinate of the pixel we wish to read. The origin\n"
+" is in the lower-left corner.\n"
+" :type x: int\n"
+" :arg y: The y coordinate of the pixel we wish to read. The origin\n"
+" is in the lower-left corner.\n"
+" :type y: int\n"
+" :return: The floating-point value stored for that pixel.\n"
+" :rtype: float\n";
+
+static PyObject *
+ContextFunctions_ReadMapPixelCF( PyObject *self, PyObject *args )
+{
+ char *mapName;
+ int level;
+ unsigned x, y;
+
+ if( !PyArg_ParseTuple(args, "siII", &mapName, &level, &x, &y) )
+ return NULL;
+
+ float f = ContextFunctions::ReadMapPixelCF(mapName, level, x, y);
+
+ return PyFloat_FromDouble( f );
+}
+
+static char ContextFunctions_ReadCompleteViewMapPixelCF___doc__[] =
+".. function:: ReadCompleteViewMapPixelCF(level, x, y)\n"
+"\n"
+" Reads a pixel in the complete view map.\n"
+"\n"
+" :arg level: The level of the pyramid in which we wish to read the\n"
+" pixel.\n"
+" :type level: int\n"
+" :arg x: The x coordinate of the pixel we wish to read. The origin\n"
+" is in the lower-left corner.\n"
+" :type x: int\n"
+" :arg y: The y coordinate of the pixel we wish to read. The origin\n"
+" is in the lower-left corner.\n"
+" :type y: int\n"
+" :return: The floating-point value stored for that pixel.\n"
+" :rtype: float\n";
+
+static PyObject *
+ContextFunctions_ReadCompleteViewMapPixelCF( PyObject *self, PyObject *args )
+{
+ int level;
+ unsigned x, y;
+
+ if( !PyArg_ParseTuple(args, "iII", &level, &x, &y) )
+ return NULL;
+
+ float f = ContextFunctions::ReadCompleteViewMapPixelCF(level, x, y);
+
+ return PyFloat_FromDouble( f );
+}
+
+static char ContextFunctions_ReadDirectionalViewMapPixelCF___doc__[] =
+".. function:: ReadDirectionalViewMapPixelCF(iOrientation, level, x, y)\n"
+"\n"
+" Reads a pixel in one of the oriented view map images.\n"
+"\n"
+" :arg iOrientation: The number telling which orientation we want to\n"
+" check.\n"
+" :type iOrientation: int\n"
+" :arg level: The level of the pyramid in which we wish to read the\n"
+" pixel.\n"
+" :type level: int\n"
+" :arg x: The x coordinate of the pixel we wish to read. The origin\n"
+" is in the lower-left corner.\n"
+" :type x: int\n"
+" :arg y: The y coordinate of the pixel we wish to read. The origin\n"
+" is in the lower-left corner.\n"
+" :type y: int\n"
+" :return: The floating-point value stored for that pixel.\n"
+" :rtype: float\n";
+
+static PyObject *
+ContextFunctions_ReadDirectionalViewMapPixelCF( PyObject *self, PyObject *args )
+{
+ int orientation, level;
+ unsigned x, y;
+
+ if( !PyArg_ParseTuple(args, "iiII", &orientation, &level, &x, &y) )
+ return NULL;
+
+ float f = ContextFunctions::ReadDirectionalViewMapPixelCF(orientation, level, x, y);
+
+ return PyFloat_FromDouble( f );
+}
+
+static char ContextFunctions_GetSelectedFEdgeCF___doc__[] =
+".. function:: GetSelectedFEdgeCF()\n"
+"\n"
+" Returns the selected FEdge.\n"
+"\n"
+" :return: The selected FEdge.\n"
+" :rtype: :class:`FEdge`\n";
+
+static PyObject *
+ContextFunctions_GetSelectedFEdgeCF( PyObject *self )
+{
+ FEdge *fe = ContextFunctions::GetSelectedFEdgeCF();
+ if( fe )
+ return Any_BPy_FEdge_from_FEdge( *fe );
+
+ Py_RETURN_NONE;
+}
+
+/*-----------------------ContextFunctions module docstring-------------------------------*/
+
+static char module_docstring[] = "The Blender Freestyle.ContextFunctions submodule\n\n";
+
+/*-----------------------ContextFunctions module functions definitions-------------------*/
+
+static PyMethodDef module_functions[] = {
+ {"GetTimeStampCF", (PyCFunction)ContextFunctions_GetTimeStampCF, METH_NOARGS, ContextFunctions_GetTimeStampCF___doc__},
+ {"GetCanvasWidthCF", (PyCFunction)ContextFunctions_GetCanvasWidthCF, METH_NOARGS, ContextFunctions_GetCanvasWidthCF___doc__},
+ {"GetCanvasHeightCF", (PyCFunction)ContextFunctions_GetCanvasHeightCF, METH_NOARGS, ContextFunctions_GetCanvasHeightCF___doc__},
+ {"LoadMapCF", (PyCFunction)ContextFunctions_LoadMapCF, METH_VARARGS, ContextFunctions_LoadMapCF___doc__},
+ {"ReadMapPixelCF", (PyCFunction)ContextFunctions_ReadMapPixelCF, METH_VARARGS, ContextFunctions_ReadMapPixelCF___doc__},
+ {"ReadCompleteViewMapPixelCF", (PyCFunction)ContextFunctions_ReadCompleteViewMapPixelCF, METH_VARARGS, ContextFunctions_ReadCompleteViewMapPixelCF___doc__},
+ {"ReadDirectionalViewMapPixelCF", (PyCFunction)ContextFunctions_ReadDirectionalViewMapPixelCF, METH_VARARGS, ContextFunctions_ReadDirectionalViewMapPixelCF___doc__},
+ {"GetSelectedFEdgeCF", (PyCFunction)ContextFunctions_GetSelectedFEdgeCF, METH_NOARGS, ContextFunctions_GetSelectedFEdgeCF___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------ContextFunctions module definition--------------------------------*/
+
+static PyModuleDef module_definition = {
+ PyModuleDef_HEAD_INIT,
+ "Freestyle.ContextFunctions",
+ module_docstring,
+ -1,
+ module_functions
+};
+
+//------------------- MODULE INITIALIZATION --------------------------------
+
+int ContextFunctions_Init( PyObject *module )
+{
+ PyObject *m, *d, *f;
+
+ if( module == NULL )
+ return -1;
+
+ m = PyModule_Create(&module_definition);
+ if (m == NULL)
+ return -1;
+ Py_INCREF(m);
+ PyModule_AddObject(module, "ContextFunctions", m);
+
+ // from ContextFunctions import *
+ d = PyModule_GetDict(m);
+ for (PyMethodDef *p = module_functions; p->ml_name; p++) {
+ f = PyDict_GetItemString(d, p->ml_name);
+ Py_INCREF(f);
+ PyModule_AddObject(module, p->ml_name, f);
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_ContextFunctions.h b/source/blender/freestyle/intern/python/BPy_ContextFunctions.h
new file mode 100644
index 00000000000..fafeff3e974
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_ContextFunctions.h
@@ -0,0 +1,18 @@
+#ifndef FREESTYLE_PYTHON_CONTEXTFUNCTIONS_H
+#define FREESTYLE_PYTHON_CONTEXTFUNCTIONS_H
+
+#include <Python.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*---------------------------Python BPy_ContextFunctions visible prototypes-----------*/
+
+int ContextFunctions_Init( PyObject *module );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CONTEXTFUNCTIONS_H */
diff --git a/source/blender/freestyle/intern/python/BPy_Convert.cpp b/source/blender/freestyle/intern/python/BPy_Convert.cpp
new file mode 100644
index 00000000000..01567b18142
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Convert.cpp
@@ -0,0 +1,609 @@
+#include "BPy_Convert.h"
+
+#include "BPy_BBox.h"
+#include "BPy_FrsMaterial.h"
+#include "BPy_Id.h"
+#include "BPy_IntegrationType.h"
+#include "BPy_Interface0D.h"
+#include "Interface0D/BPy_CurvePoint.h"
+#include "Interface0D/CurvePoint/BPy_StrokeVertex.h"
+#include "Interface0D/BPy_SVertex.h"
+#include "Interface0D/BPy_ViewVertex.h"
+#include "Interface0D/ViewVertex/BPy_NonTVertex.h"
+#include "Interface0D/ViewVertex/BPy_TVertex.h"
+#include "BPy_Interface1D.h"
+#include "Interface1D/BPy_FEdge.h"
+#include "Interface1D/BPy_Stroke.h"
+#include "Interface1D/BPy_ViewEdge.h"
+#include "Interface1D/Curve/BPy_Chain.h"
+#include "Interface1D/FEdge/BPy_FEdgeSharp.h"
+#include "Interface1D/FEdge/BPy_FEdgeSmooth.h"
+#include "BPy_Nature.h"
+#include "BPy_MediumType.h"
+#include "BPy_SShape.h"
+#include "BPy_StrokeAttribute.h"
+#include "BPy_ViewShape.h"
+
+#include "Iterator/BPy_AdjacencyIterator.h"
+#include "Iterator/BPy_ChainPredicateIterator.h"
+#include "Iterator/BPy_ChainSilhouetteIterator.h"
+#include "Iterator/BPy_ChainingIterator.h"
+#include "Iterator/BPy_CurvePointIterator.h"
+#include "Iterator/BPy_Interface0DIterator.h"
+#include "Iterator/BPy_SVertexIterator.h"
+#include "Iterator/BPy_StrokeVertexIterator.h"
+#include "Iterator/BPy_ViewEdgeIterator.h"
+#include "Iterator/BPy_orientedViewEdgeIterator.h"
+
+#include "../stroke/StrokeRep.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//==============================
+// C++ => Python
+//==============================
+
+
+PyObject * PyBool_from_bool( bool b ){
+ return PyBool_FromLong( b ? 1 : 0);
+}
+
+
+PyObject * Vector_from_Vec2f( Vec2f& vec ) {
+ float vec_data[2]; // because vec->_coord is protected
+
+ vec_data[0] = vec.x(); vec_data[1] = vec.y();
+ return Vector_CreatePyObject( vec_data, 2, Py_NEW, NULL);
+}
+
+PyObject * Vector_from_Vec3f( Vec3f& vec ) {
+ float vec_data[3]; // because vec->_coord is protected
+
+ vec_data[0] = vec.x(); vec_data[1] = vec.y(); vec_data[2] = vec.z();
+ return Vector_CreatePyObject( vec_data, 3, Py_NEW, NULL);
+}
+
+PyObject * Vector_from_Vec3r( Vec3r& vec ) {
+ float vec_data[3]; // because vec->_coord is protected
+
+ vec_data[0] = vec.x(); vec_data[1] = vec.y(); vec_data[2] = vec.z();
+ return Vector_CreatePyObject( vec_data, 3, Py_NEW, NULL);
+}
+
+PyObject * BPy_Id_from_Id( Id& id ) {
+ PyObject *py_id = Id_Type.tp_new( &Id_Type, 0, 0 );
+ ((BPy_Id *) py_id)->id = new Id( id.getFirst(), id.getSecond() );
+
+ return py_id;
+}
+
+PyObject * Any_BPy_Interface0D_from_Interface0D( Interface0D& if0D ) {
+ if (typeid(if0D) == typeid(CurvePoint)) {
+ return BPy_CurvePoint_from_CurvePoint(dynamic_cast<CurvePoint&>(if0D));
+ } else if (typeid(if0D) == typeid(StrokeVertex)) {
+ return BPy_StrokeVertex_from_StrokeVertex(dynamic_cast<StrokeVertex&>(if0D));
+ } else if (typeid(if0D) == typeid(SVertex)) {
+ return BPy_SVertex_from_SVertex(dynamic_cast<SVertex&>(if0D));
+ } else if (typeid(if0D) == typeid(ViewVertex)) {
+ return BPy_ViewVertex_from_ViewVertex(dynamic_cast<ViewVertex&>(if0D));
+ } else if (typeid(if0D) == typeid(NonTVertex)) {
+ return BPy_NonTVertex_from_NonTVertex(dynamic_cast<NonTVertex&>(if0D));
+ } else if (typeid(if0D) == typeid(TVertex)) {
+ return BPy_TVertex_from_TVertex(dynamic_cast<TVertex&>(if0D));
+ } else if (typeid(if0D) == typeid(Interface0D)) {
+ return BPy_Interface0D_from_Interface0D(if0D);
+ }
+ string msg("unexpected type: " + if0D.getExactTypeName());
+ PyErr_SetString(PyExc_TypeError, msg.c_str());
+ return NULL;
+}
+
+PyObject * Any_BPy_Interface1D_from_Interface1D( Interface1D& if1D ) {
+ if (typeid(if1D) == typeid(ViewEdge)) {
+ return BPy_ViewEdge_from_ViewEdge(dynamic_cast<ViewEdge&>(if1D));
+ } else if (typeid(if1D) == typeid(Chain)) {
+ return BPy_Chain_from_Chain(dynamic_cast<Chain&>(if1D));
+ } else if (typeid(if1D) == typeid(Stroke)) {
+ return BPy_Stroke_from_Stroke(dynamic_cast<Stroke&>(if1D));
+ } else if (typeid(if1D) == typeid(FEdgeSharp)) {
+ return BPy_FEdgeSharp_from_FEdgeSharp(dynamic_cast<FEdgeSharp&>(if1D));
+ } else if (typeid(if1D) == typeid(FEdgeSmooth)) {
+ return BPy_FEdgeSmooth_from_FEdgeSmooth(dynamic_cast<FEdgeSmooth&>(if1D));
+ } else if (typeid(if1D) == typeid(FEdge)) {
+ return BPy_FEdge_from_FEdge(dynamic_cast<FEdge&>(if1D));
+ } else if (typeid(if1D) == typeid(Interface1D)) {
+ return BPy_Interface1D_from_Interface1D( if1D );
+ }
+ string msg("unexpected type: " + if1D.getExactTypeName());
+ PyErr_SetString(PyExc_TypeError, msg.c_str());
+ return NULL;
+}
+
+PyObject * Any_BPy_FEdge_from_FEdge( FEdge& fe ) {
+ if (typeid(fe) == typeid(FEdgeSharp)) {
+ return BPy_FEdgeSharp_from_FEdgeSharp( dynamic_cast<FEdgeSharp&>(fe) );
+ } else if (typeid(fe) == typeid(FEdgeSmooth)) {
+ return BPy_FEdgeSmooth_from_FEdgeSmooth( dynamic_cast<FEdgeSmooth&>(fe) );
+ } else if (typeid(fe) == typeid(FEdge)) {
+ return BPy_FEdge_from_FEdge( fe );
+ }
+ string msg("unexpected type: " + fe.getExactTypeName());
+ PyErr_SetString(PyExc_TypeError, msg.c_str());
+ return NULL;
+}
+
+PyObject * Any_BPy_ViewVertex_from_ViewVertex( ViewVertex& vv ) {
+ if (typeid(vv) == typeid(NonTVertex)) {
+ return BPy_NonTVertex_from_NonTVertex( dynamic_cast<NonTVertex&>(vv) );
+ } else if (typeid(vv) == typeid(TVertex)) {
+ return BPy_TVertex_from_TVertex( dynamic_cast<TVertex&>(vv) );
+ } else if (typeid(vv) == typeid(ViewVertex)) {
+ return BPy_ViewVertex_from_ViewVertex( vv );
+ }
+ string msg("unexpected type: " + vv.getExactTypeName());
+ PyErr_SetString(PyExc_TypeError, msg.c_str());
+ return NULL;
+}
+
+PyObject * BPy_Interface0D_from_Interface0D( Interface0D& if0D ) {
+ PyObject *py_if0D = Interface0D_Type.tp_new( &Interface0D_Type, 0, 0 );
+ ((BPy_Interface0D *) py_if0D)->if0D = &if0D;
+ ((BPy_Interface0D *) py_if0D)->borrowed = 1;
+
+ return py_if0D;
+}
+
+PyObject * BPy_Interface1D_from_Interface1D( Interface1D& if1D ) {
+ PyObject *py_if1D = Interface1D_Type.tp_new( &Interface1D_Type, 0, 0 );
+ ((BPy_Interface1D *) py_if1D)->if1D = &if1D;
+ ((BPy_Interface1D *) py_if1D)->borrowed = 1;
+
+ return py_if1D;
+}
+
+PyObject * BPy_SVertex_from_SVertex( SVertex& sv ) {
+ PyObject *py_sv = SVertex_Type.tp_new( &SVertex_Type, 0, 0 );
+ ((BPy_SVertex *) py_sv)->sv = &sv;
+ ((BPy_SVertex *) py_sv)->py_if0D.if0D = ((BPy_SVertex *) py_sv)->sv;
+ ((BPy_SVertex *) py_sv)->py_if0D.borrowed = 1;
+
+ return py_sv;
+}
+
+PyObject * BPy_FEdgeSharp_from_FEdgeSharp( FEdgeSharp& fes ) {
+ PyObject *py_fe = FEdgeSharp_Type.tp_new( &FEdgeSharp_Type, 0, 0 );
+ ((BPy_FEdgeSharp *) py_fe)->fes = &fes;
+ ((BPy_FEdgeSharp *) py_fe)->py_fe.fe = ((BPy_FEdgeSharp *) py_fe)->fes;
+ ((BPy_FEdgeSharp *) py_fe)->py_fe.py_if1D.if1D = ((BPy_FEdgeSharp *) py_fe)->fes;
+ ((BPy_FEdgeSharp *) py_fe)->py_fe.py_if1D.borrowed = 1;
+
+ return py_fe;
+}
+
+PyObject * BPy_FEdgeSmooth_from_FEdgeSmooth( FEdgeSmooth& fes ) {
+ PyObject *py_fe = FEdgeSmooth_Type.tp_new( &FEdgeSmooth_Type, 0, 0 );
+ ((BPy_FEdgeSmooth *) py_fe)->fes = &fes;
+ ((BPy_FEdgeSmooth *) py_fe)->py_fe.fe = ((BPy_FEdgeSmooth *) py_fe)->fes;
+ ((BPy_FEdgeSmooth *) py_fe)->py_fe.py_if1D.if1D = ((BPy_FEdgeSmooth *) py_fe)->fes;
+ ((BPy_FEdgeSmooth *) py_fe)->py_fe.py_if1D.borrowed = 1;
+
+ return py_fe;
+}
+
+PyObject * BPy_FEdge_from_FEdge( FEdge& fe ) {
+ PyObject *py_fe = FEdge_Type.tp_new( &FEdge_Type, 0, 0 );
+ ((BPy_FEdge *) py_fe)->fe = &fe;
+ ((BPy_FEdge *) py_fe)->py_if1D.if1D = ((BPy_FEdge *) py_fe)->fe;
+ ((BPy_FEdge *) py_fe)->py_if1D.borrowed = 1;
+
+ return py_fe;
+}
+
+PyObject * BPy_Nature_from_Nature( unsigned short n ) {
+ PyObject *py_n;
+
+ PyObject *args = PyTuple_New(1);
+ PyTuple_SetItem( args, 0, PyLong_FromLong(n) );
+ py_n = Nature_Type.tp_new(&Nature_Type, args, NULL);
+ Py_DECREF(args);
+
+ return py_n;
+}
+
+PyObject * BPy_Stroke_from_Stroke( Stroke& s ) {
+ PyObject *py_s = Stroke_Type.tp_new( &Stroke_Type, 0, 0 );
+ ((BPy_Stroke *) py_s)->s = &s;
+ ((BPy_Stroke *) py_s)->py_if1D.if1D = ((BPy_Stroke *) py_s)->s;
+ ((BPy_Stroke *) py_s)->py_if1D.borrowed = 1;
+
+ return py_s;
+}
+
+PyObject * BPy_StrokeAttribute_from_StrokeAttribute( StrokeAttribute& sa ) {
+ PyObject *py_sa = StrokeAttribute_Type.tp_new( &StrokeAttribute_Type, 0, 0 );
+ ((BPy_StrokeAttribute *) py_sa)->sa = &sa;
+ ((BPy_StrokeAttribute *) py_sa)->borrowed = 1;
+ return py_sa;
+}
+
+PyObject * BPy_MediumType_from_MediumType( Stroke::MediumType n ) {
+ PyObject *py_mt;
+
+ PyObject *args = PyTuple_New(1);
+ PyTuple_SetItem( args, 0, PyLong_FromLong(n) );
+ py_mt = MediumType_Type.tp_new( &MediumType_Type, args, NULL );
+ Py_DECREF(args);
+
+ return py_mt;
+}
+
+PyObject * BPy_StrokeVertex_from_StrokeVertex( StrokeVertex& sv ) {
+ PyObject *py_sv = StrokeVertex_Type.tp_new( &StrokeVertex_Type, 0, 0 );
+ ((BPy_StrokeVertex *) py_sv)->sv = &sv;
+ ((BPy_StrokeVertex *) py_sv)->py_cp.cp = ((BPy_StrokeVertex *) py_sv)->sv;
+ ((BPy_StrokeVertex *) py_sv)->py_cp.py_if0D.if0D = ((BPy_StrokeVertex *) py_sv)->sv;
+ ((BPy_StrokeVertex *) py_sv)->py_cp.py_if0D.borrowed = 1;
+
+ return py_sv;
+}
+
+PyObject * BPy_ViewVertex_from_ViewVertex( ViewVertex& vv ) {
+ PyObject *py_vv = ViewVertex_Type.tp_new( &ViewVertex_Type, 0, 0 );
+ ((BPy_ViewVertex *) py_vv)->vv = &vv;
+ ((BPy_ViewVertex *) py_vv)->py_if0D.if0D = ((BPy_ViewVertex *) py_vv)->vv;
+ ((BPy_ViewVertex *) py_vv)->py_if0D.borrowed = 1;
+
+ return py_vv;
+}
+
+PyObject * BPy_NonTVertex_from_NonTVertex( NonTVertex& ntv ) {
+ PyObject *py_ntv = NonTVertex_Type.tp_new( &NonTVertex_Type, 0, 0 );
+ ((BPy_NonTVertex *) py_ntv)->ntv = &ntv;
+ ((BPy_NonTVertex *) py_ntv)->py_vv.vv = ((BPy_NonTVertex *) py_ntv)->ntv;
+ ((BPy_NonTVertex *) py_ntv)->py_vv.py_if0D.if0D = ((BPy_NonTVertex *) py_ntv)->ntv;
+ ((BPy_NonTVertex *) py_ntv)->py_vv.py_if0D.borrowed = 1;
+
+ return py_ntv;
+}
+
+PyObject * BPy_TVertex_from_TVertex( TVertex& tv ) {
+ PyObject *py_tv = TVertex_Type.tp_new( &TVertex_Type, 0, 0 );
+ ((BPy_TVertex *) py_tv)->tv = &tv;
+ ((BPy_TVertex *) py_tv)->py_vv.vv = ((BPy_TVertex *) py_tv)->tv;
+ ((BPy_TVertex *) py_tv)->py_vv.py_if0D.if0D = ((BPy_TVertex *) py_tv)->tv;
+ ((BPy_TVertex *) py_tv)->py_vv.py_if0D.borrowed = 1;
+
+ return py_tv;
+}
+
+PyObject * BPy_BBox_from_BBox( BBox< Vec3r > &bb ) {
+ PyObject *py_bb = BBox_Type.tp_new( &BBox_Type, 0, 0 );
+ ((BPy_BBox *) py_bb)->bb = new BBox< Vec3r >( bb );
+
+ return py_bb;
+}
+
+PyObject * BPy_ViewEdge_from_ViewEdge( ViewEdge& ve ) {
+ PyObject *py_ve = ViewEdge_Type.tp_new( &ViewEdge_Type, 0, 0 );
+ ((BPy_ViewEdge *) py_ve)->ve = &ve;
+ ((BPy_ViewEdge *) py_ve)->py_if1D.if1D = ((BPy_ViewEdge *) py_ve)->ve;
+ ((BPy_ViewEdge *) py_ve)->py_if1D.borrowed = 1;
+
+ return py_ve;
+}
+
+PyObject * BPy_Chain_from_Chain( Chain& c ) {
+ PyObject *py_c = Chain_Type.tp_new( &Chain_Type, 0, 0 );
+ ((BPy_Chain *) py_c)->c = &c;
+ ((BPy_Chain *) py_c)->py_c.c = ((BPy_Chain *) py_c)->c;
+ ((BPy_Chain *) py_c)->py_c.py_if1D.if1D = ((BPy_Chain *) py_c)->c;
+ ((BPy_Chain *) py_c)->py_c.py_if1D.borrowed = 1;
+ return py_c;
+}
+
+PyObject * BPy_SShape_from_SShape( SShape& ss ) {
+ PyObject *py_ss = SShape_Type.tp_new( &SShape_Type, 0, 0 );
+ ((BPy_SShape *) py_ss)->ss = &ss;
+ ((BPy_SShape *) py_ss)->borrowed = 1;
+
+ return py_ss;
+}
+
+PyObject * BPy_ViewShape_from_ViewShape( ViewShape& vs ) {
+ PyObject *py_vs = ViewShape_Type.tp_new( &ViewShape_Type, 0, 0 );
+ ((BPy_ViewShape *) py_vs)->vs = &vs;
+ ((BPy_ViewShape *) py_vs)->borrowed = 1;
+
+ return py_vs;
+}
+
+PyObject * BPy_FrsMaterial_from_FrsMaterial( FrsMaterial& m ){
+ PyObject *py_m = FrsMaterial_Type.tp_new( &FrsMaterial_Type, 0, 0 );
+ ((BPy_FrsMaterial*) py_m)->m = &m;
+ ((BPy_FrsMaterial*) py_m)->borrowed = 1;
+
+ return py_m;
+}
+
+PyObject * BPy_IntegrationType_from_IntegrationType( IntegrationType i ) {
+ PyObject *py_it;
+
+ PyObject *args = PyTuple_New(1);
+ PyTuple_SetItem( args, 0, PyLong_FromLong(i) );
+ py_it = IntegrationType_Type.tp_new( &IntegrationType_Type, args, NULL );
+ Py_DECREF(args);
+
+ return py_it;
+}
+
+PyObject * BPy_CurvePoint_from_CurvePoint( CurvePoint& cp ) {
+ PyObject *py_cp = CurvePoint_Type.tp_new( &CurvePoint_Type, 0, 0 );
+ ((BPy_CurvePoint*) py_cp)->cp = &cp;
+ ((BPy_CurvePoint*) py_cp)->py_if0D.if0D = ((BPy_CurvePoint*) py_cp)->cp;
+ ((BPy_CurvePoint*) py_cp)->py_if0D.borrowed = 1;
+
+ return py_cp;
+}
+
+PyObject * BPy_directedViewEdge_from_directedViewEdge( ViewVertex::directedViewEdge& dve ) {
+ PyObject *py_dve = PyTuple_New(2);
+
+ PyTuple_SetItem( py_dve, 0, BPy_ViewEdge_from_ViewEdge(*(dve.first)) );
+ PyTuple_SetItem( py_dve, 1, PyBool_from_bool(dve.second) );
+
+ return py_dve;
+}
+
+//==============================
+// Iterators
+//==============================
+
+PyObject * BPy_AdjacencyIterator_from_AdjacencyIterator( AdjacencyIterator& a_it ) {
+ PyObject *py_a_it = AdjacencyIterator_Type.tp_new( &AdjacencyIterator_Type, 0, 0 );
+ ((BPy_AdjacencyIterator *) py_a_it)->a_it = new AdjacencyIterator( a_it );
+ ((BPy_AdjacencyIterator *) py_a_it)->py_it.it = ((BPy_AdjacencyIterator *) py_a_it)->a_it;
+
+ return py_a_it;
+}
+
+PyObject * BPy_Interface0DIterator_from_Interface0DIterator( Interface0DIterator& if0D_it, int reversed ) {
+ PyObject *py_if0D_it = Interface0DIterator_Type.tp_new( &Interface0DIterator_Type, 0, 0 );
+ ((BPy_Interface0DIterator *) py_if0D_it)->if0D_it = new Interface0DIterator( if0D_it );
+ ((BPy_Interface0DIterator *) py_if0D_it)->py_it.it = ((BPy_Interface0DIterator *) py_if0D_it)->if0D_it;
+ ((BPy_Interface0DIterator *) py_if0D_it)->reversed = reversed;
+
+ return py_if0D_it;
+}
+
+PyObject * BPy_CurvePointIterator_from_CurvePointIterator( CurveInternal::CurvePointIterator& cp_it ) {
+ PyObject *py_cp_it = CurvePointIterator_Type.tp_new( &CurvePointIterator_Type, 0, 0 );
+ ((BPy_CurvePointIterator *) py_cp_it)->cp_it = new CurveInternal::CurvePointIterator( cp_it );
+ ((BPy_CurvePointIterator *) py_cp_it)->py_it.it = ((BPy_CurvePointIterator *) py_cp_it)->cp_it;
+
+ return py_cp_it;
+}
+
+PyObject * BPy_StrokeVertexIterator_from_StrokeVertexIterator( StrokeInternal::StrokeVertexIterator& sv_it, int reversed) {
+ PyObject *py_sv_it = StrokeVertexIterator_Type.tp_new( &StrokeVertexIterator_Type, 0, 0 );
+ ((BPy_StrokeVertexIterator *) py_sv_it)->sv_it = new StrokeInternal::StrokeVertexIterator( sv_it );
+ ((BPy_StrokeVertexIterator *) py_sv_it)->py_it.it = ((BPy_StrokeVertexIterator *) py_sv_it)->sv_it;
+ ((BPy_StrokeVertexIterator *) py_sv_it)->reversed = reversed;
+
+ return py_sv_it;
+}
+
+PyObject * BPy_SVertexIterator_from_SVertexIterator( ViewEdgeInternal::SVertexIterator& sv_it ) {
+ PyObject *py_sv_it = SVertexIterator_Type.tp_new( &SVertexIterator_Type, 0, 0 );
+ ((BPy_SVertexIterator *) py_sv_it)->sv_it = new ViewEdgeInternal::SVertexIterator( sv_it );
+ ((BPy_SVertexIterator *) py_sv_it)->py_it.it = ((BPy_SVertexIterator *) py_sv_it)->sv_it;
+
+ return py_sv_it;
+}
+
+
+PyObject * BPy_orientedViewEdgeIterator_from_orientedViewEdgeIterator( ViewVertexInternal::orientedViewEdgeIterator& ove_it, int reversed ) {
+ PyObject *py_ove_it = orientedViewEdgeIterator_Type.tp_new( &orientedViewEdgeIterator_Type, 0, 0 );
+ ((BPy_orientedViewEdgeIterator *) py_ove_it)->ove_it = new ViewVertexInternal::orientedViewEdgeIterator( ove_it );
+ ((BPy_orientedViewEdgeIterator *) py_ove_it)->py_it.it = ((BPy_orientedViewEdgeIterator *) py_ove_it)->ove_it;
+ ((BPy_orientedViewEdgeIterator *) py_ove_it)->reversed = reversed;
+
+ return py_ove_it;
+}
+
+PyObject * BPy_ViewEdgeIterator_from_ViewEdgeIterator( ViewEdgeInternal::ViewEdgeIterator& ve_it ) {
+ PyObject *py_ve_it = ViewEdgeIterator_Type.tp_new( &ViewEdgeIterator_Type, 0, 0 );
+ ((BPy_ViewEdgeIterator *) py_ve_it)->ve_it = new ViewEdgeInternal::ViewEdgeIterator( ve_it );
+ ((BPy_ViewEdgeIterator *) py_ve_it)->py_it.it = ((BPy_ViewEdgeIterator *) py_ve_it)->ve_it;
+
+ return py_ve_it;
+}
+
+PyObject * BPy_ChainingIterator_from_ChainingIterator( ChainingIterator& c_it ) {
+ PyObject *py_c_it = ChainingIterator_Type.tp_new( &ChainingIterator_Type, 0, 0 );
+ ((BPy_ChainingIterator *) py_c_it)->c_it = new ChainingIterator( c_it );
+ ((BPy_ChainingIterator *) py_c_it)->py_ve_it.py_it.it = ((BPy_ChainingIterator *) py_c_it)->c_it;
+
+ return py_c_it;
+}
+
+PyObject * BPy_ChainPredicateIterator_from_ChainPredicateIterator( ChainPredicateIterator& cp_it ) {
+ PyObject *py_cp_it = ChainPredicateIterator_Type.tp_new( &ChainPredicateIterator_Type, 0, 0 );
+ ((BPy_ChainPredicateIterator *) py_cp_it)->cp_it = new ChainPredicateIterator( cp_it );
+ ((BPy_ChainPredicateIterator *) py_cp_it)->py_c_it.py_ve_it.py_it.it = ((BPy_ChainPredicateIterator *) py_cp_it)->cp_it;
+
+ return py_cp_it;
+}
+
+PyObject * BPy_ChainSilhouetteIterator_from_ChainSilhouetteIterator( ChainSilhouetteIterator& cs_it ) {
+ PyObject *py_cs_it = ChainSilhouetteIterator_Type.tp_new( &ChainSilhouetteIterator_Type, 0, 0 );
+ ((BPy_ChainSilhouetteIterator *) py_cs_it)->cs_it = new ChainSilhouetteIterator( cs_it );
+ ((BPy_ChainSilhouetteIterator *) py_cs_it)->py_c_it.py_ve_it.py_it.it = ((BPy_ChainSilhouetteIterator *) py_cs_it)->cs_it;
+
+ return py_cs_it;
+}
+
+
+//==============================
+// Python => C++
+//==============================
+
+bool bool_from_PyBool( PyObject *b ) {
+ return PyObject_IsTrue(b) != 0;
+}
+
+IntegrationType IntegrationType_from_BPy_IntegrationType( PyObject* obj ) {
+ return static_cast<IntegrationType>( PyLong_AsLong(obj) );
+}
+
+Stroke::MediumType MediumType_from_BPy_MediumType( PyObject* obj ) {
+ return static_cast<Stroke::MediumType>( PyLong_AsLong(obj) );
+}
+
+Nature::EdgeNature EdgeNature_from_BPy_Nature( PyObject* obj ) {
+ return static_cast<Nature::EdgeNature>( PyLong_AsLong(obj) );
+}
+
+Vec2f * Vec2f_ptr_from_PyObject( PyObject* obj ) {
+ Vec2f *v;
+ if( (v = Vec2f_ptr_from_Vector( obj )) )
+ return v;
+ if( (v = Vec2f_ptr_from_PyList( obj )) )
+ return v;
+ if( (v = Vec2f_ptr_from_PyTuple( obj )) )
+ return v;
+ return NULL;
+}
+
+Vec3f * Vec3f_ptr_from_PyObject( PyObject* obj ) {
+ Vec3f *v;
+ if( (v = Vec3f_ptr_from_Vector( obj )) )
+ return v;
+ if( (v = Vec3f_ptr_from_PyList( obj )) )
+ return v;
+ if( (v = Vec3f_ptr_from_PyTuple( obj )) )
+ return v;
+ return NULL;
+}
+
+Vec3r * Vec3r_ptr_from_PyObject( PyObject* obj ) {
+ Vec3r *v;
+ if( (v = Vec3r_ptr_from_Vector( obj )) )
+ return v;
+ if( (v = Vec3r_ptr_from_PyList( obj )) )
+ return v;
+ if( (v = Vec3r_ptr_from_PyTuple( obj )) )
+ return v;
+ return NULL;
+}
+
+Vec2f * Vec2f_ptr_from_Vector( PyObject* obj ) {
+ PyObject *v;
+ if (!VectorObject_Check(obj) || ((VectorObject *)obj)->size != 2)
+ return NULL;
+ v = PyObject_GetAttrString(obj,"x");
+ float x = PyFloat_AsDouble( v );
+ Py_DECREF( v );
+ v = PyObject_GetAttrString(obj,"y");
+ float y = PyFloat_AsDouble( v );
+ Py_DECREF( v );
+
+ return new Vec2f(x,y);
+}
+
+Vec3f * Vec3f_ptr_from_Vector( PyObject* obj ) {
+ PyObject *v;
+ if (!VectorObject_Check(obj) || ((VectorObject *)obj)->size != 3)
+ return NULL;
+ v = PyObject_GetAttrString(obj,"x");
+ float x = PyFloat_AsDouble( v );
+ Py_DECREF( v );
+ v = PyObject_GetAttrString(obj,"y");
+ float y = PyFloat_AsDouble( v );
+ Py_DECREF( v );
+ v = PyObject_GetAttrString(obj,"z");
+ float z = PyFloat_AsDouble( v );
+ Py_DECREF( v );
+
+ return new Vec3f(x,y,z);
+}
+
+Vec3r * Vec3r_ptr_from_Vector( PyObject* obj ) {
+ PyObject *v;
+ if (!VectorObject_Check(obj) || ((VectorObject *)obj)->size != 3)
+ return NULL;
+ v = PyObject_GetAttrString(obj,"x");
+ double x = PyFloat_AsDouble( v );
+ Py_DECREF( v );
+ v = PyObject_GetAttrString(obj,"y");
+ double y = PyFloat_AsDouble( v );
+ Py_DECREF( v );
+ v = PyObject_GetAttrString(obj,"z");
+ double z = PyFloat_AsDouble( v );
+ Py_DECREF( v );
+
+ return new Vec3r(x,y,z);
+}
+
+Vec2f * Vec2f_ptr_from_PyList( PyObject* obj ) {
+ if( !PyList_Check(obj) || PyList_Size(obj) != 2 )
+ return NULL;
+ float x = PyFloat_AsDouble(PyList_GetItem(obj, 0));
+ float y = PyFloat_AsDouble(PyList_GetItem(obj, 1));
+ return new Vec2f(x,y);
+}
+
+Vec3f * Vec3f_ptr_from_PyList( PyObject* obj ) {
+ if( !PyList_Check(obj) || PyList_Size(obj) != 3 )
+ return NULL;
+ float x = PyFloat_AsDouble(PyList_GetItem(obj, 0));
+ float y = PyFloat_AsDouble(PyList_GetItem(obj, 1));
+ float z = PyFloat_AsDouble(PyList_GetItem(obj, 2));
+ return new Vec3f(x,y,z);
+}
+
+Vec3r * Vec3r_ptr_from_PyList( PyObject* obj ) {
+ if( !PyList_Check(obj) || PyList_Size(obj) != 3 )
+ return NULL;
+ float x = PyFloat_AsDouble(PyList_GetItem(obj, 0));
+ float y = PyFloat_AsDouble(PyList_GetItem(obj, 1));
+ float z = PyFloat_AsDouble(PyList_GetItem(obj, 2));
+ return new Vec3r(x,y,z);
+}
+
+Vec2f * Vec2f_ptr_from_PyTuple( PyObject* obj ) {
+ if( !PyTuple_Check(obj) || PyTuple_Size(obj) != 2 )
+ return NULL;
+ float x = PyFloat_AsDouble(PyTuple_GetItem(obj, 0));
+ float y = PyFloat_AsDouble(PyTuple_GetItem(obj, 1));
+ return new Vec2f(x,y);
+}
+
+Vec3f * Vec3f_ptr_from_PyTuple( PyObject* obj ) {
+ if( !PyTuple_Check(obj) || PyTuple_Size(obj) != 3 )
+ return NULL;
+ float x = PyFloat_AsDouble(PyTuple_GetItem(obj, 0));
+ float y = PyFloat_AsDouble(PyTuple_GetItem(obj, 1));
+ float z = PyFloat_AsDouble(PyTuple_GetItem(obj, 2));
+ return new Vec3f(x,y,z);
+}
+
+Vec3r * Vec3r_ptr_from_PyTuple( PyObject* obj ) {
+ if( !PyTuple_Check(obj) || PyTuple_Size(obj) != 3 )
+ return NULL;
+ float x = PyFloat_AsDouble(PyTuple_GetItem(obj, 0));
+ float y = PyFloat_AsDouble(PyTuple_GetItem(obj, 1));
+ float z = PyFloat_AsDouble(PyTuple_GetItem(obj, 2));
+ return new Vec3r(x,y,z);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_Convert.h b/source/blender/freestyle/intern/python/BPy_Convert.h
new file mode 100644
index 00000000000..ef5a64bde3f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Convert.h
@@ -0,0 +1,147 @@
+#ifndef FREESTYLE_PYTHON_CONVERT_H
+#define FREESTYLE_PYTHON_CONVERT_H
+
+#include <Python.h>
+#include <typeinfo>
+
+#include "../geometry/Geom.h"
+using namespace Geometry;
+
+// BBox
+#include "../geometry/BBox.h"
+
+// FEdge, FEdgeSharp, FEdgeSmooth, SShape, SVertex, FEdgeInternal::SVertexIterator
+#include "../view_map/Silhouette.h"
+
+// Id
+#include "../system/Id.h"
+
+// Interface0D, Interface0DIteratorNested, Interface0DIterator
+#include "../view_map/Interface0D.h"
+
+// Interface1D
+#include "../view_map/Interface1D.h"
+
+// FrsMaterial
+#include "../scene_graph/FrsMaterial.h"
+
+// Nature::VertexNature, Nature::EdgeNature
+#include "../winged_edge/Nature.h"
+
+// Stroke, StrokeAttribute, StrokeVertex
+#include "../stroke/Stroke.h"
+
+// NonTVertex, TVertex, ViewEdge, ViewMap, ViewShape, ViewVertex
+#include "../view_map/ViewMap.h"
+
+// CurvePoint, Curve
+#include "../stroke/Curve.h"
+
+// Chain
+#include "../stroke/Chain.h"
+
+//====== ITERATORS
+
+// AdjacencyIterator, ChainingIterator, ChainSilhouetteIterator, ChainPredicateIterator
+#include "../stroke/ChainingIterators.h"
+
+// ViewVertexInternal::orientedViewEdgeIterator
+// ViewEdgeInternal::SVertexIterator
+// ViewEdgeInternal::ViewEdgeIterator
+#include "../view_map/ViewMapIterators.h"
+
+// StrokeInternal::StrokeVertexIterator
+#include "../stroke/StrokeIterators.h"
+
+// CurveInternal::CurvePointIterator
+#include "../stroke/CurveIterators.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include "mathutils/mathutils.h"
+
+//==============================
+// C++ => Python
+//==============================
+
+PyObject * PyBool_from_bool( bool b );
+PyObject * Vector_from_Vec2f( Vec2f& v );
+PyObject * Vector_from_Vec3f( Vec3f& v );
+PyObject * Vector_from_Vec3r( Vec3r& v );
+
+PyObject * Any_BPy_Interface0D_from_Interface0D( Interface0D& if0D );
+PyObject * Any_BPy_Interface1D_from_Interface1D( Interface1D& if1D );
+PyObject * Any_BPy_FEdge_from_FEdge( FEdge& fe );
+PyObject * Any_BPy_ViewVertex_from_ViewVertex( ViewVertex& vv );
+
+PyObject * BPy_BBox_from_BBox( BBox< Vec3r > &bb );
+PyObject * BPy_CurvePoint_from_CurvePoint( CurvePoint& cp );
+PyObject * BPy_directedViewEdge_from_directedViewEdge( ViewVertex::directedViewEdge& dve );
+PyObject * BPy_FEdge_from_FEdge( FEdge& fe );
+PyObject * BPy_FEdgeSharp_from_FEdgeSharp( FEdgeSharp& fes );
+PyObject * BPy_FEdgeSmooth_from_FEdgeSmooth( FEdgeSmooth& fes );
+PyObject * BPy_Id_from_Id( Id& id );
+PyObject * BPy_Interface0D_from_Interface0D( Interface0D& if0D );
+PyObject * BPy_Interface1D_from_Interface1D( Interface1D& if1D );
+PyObject * BPy_IntegrationType_from_IntegrationType( IntegrationType i );
+PyObject * BPy_FrsMaterial_from_FrsMaterial( FrsMaterial& m );
+PyObject * BPy_Nature_from_Nature( unsigned short n );
+PyObject * BPy_MediumType_from_MediumType( Stroke::MediumType n );
+PyObject * BPy_SShape_from_SShape( SShape& ss );
+PyObject * BPy_Stroke_from_Stroke( Stroke& s );
+PyObject * BPy_StrokeAttribute_from_StrokeAttribute( StrokeAttribute& sa );
+PyObject * BPy_StrokeVertex_from_StrokeVertex( StrokeVertex& sv );
+PyObject * BPy_SVertex_from_SVertex( SVertex& sv );
+PyObject * BPy_ViewVertex_from_ViewVertex( ViewVertex& vv );
+PyObject * BPy_NonTVertex_from_NonTVertex( NonTVertex& ntv );
+PyObject * BPy_TVertex_from_TVertex( TVertex& tv );
+PyObject * BPy_ViewEdge_from_ViewEdge( ViewEdge& ve );
+PyObject * BPy_Chain_from_Chain( Chain& c );
+PyObject * BPy_ViewShape_from_ViewShape( ViewShape& vs );
+
+PyObject * BPy_AdjacencyIterator_from_AdjacencyIterator( AdjacencyIterator& a_it );
+PyObject * BPy_Interface0DIterator_from_Interface0DIterator( Interface0DIterator& if0D_it, int reversed );
+PyObject * BPy_CurvePointIterator_from_CurvePointIterator( CurveInternal::CurvePointIterator& cp_it );
+PyObject * BPy_StrokeVertexIterator_from_StrokeVertexIterator( StrokeInternal::StrokeVertexIterator& sv_it, int reversed);
+PyObject * BPy_SVertexIterator_from_SVertexIterator( ViewEdgeInternal::SVertexIterator& sv_it );
+PyObject * BPy_orientedViewEdgeIterator_from_orientedViewEdgeIterator( ViewVertexInternal::orientedViewEdgeIterator& ove_it, int reversed );
+PyObject * BPy_ViewEdgeIterator_from_ViewEdgeIterator( ViewEdgeInternal::ViewEdgeIterator& ve_it );
+PyObject * BPy_ChainingIterator_from_ChainingIterator( ChainingIterator& c_it );
+PyObject * BPy_ChainPredicateIterator_from_ChainPredicateIterator( ChainPredicateIterator& cp_it );
+PyObject * BPy_ChainSilhouetteIterator_from_ChainSilhouetteIterator( ChainSilhouetteIterator& cs_it );
+
+//==============================
+// Python => C++
+//==============================
+
+bool bool_from_PyBool( PyObject *b );
+IntegrationType IntegrationType_from_BPy_IntegrationType( PyObject* obj );
+Stroke::MediumType MediumType_from_BPy_MediumType( PyObject* obj );
+Nature::EdgeNature EdgeNature_from_BPy_Nature( PyObject* obj );
+Vec2f * Vec2f_ptr_from_PyObject( PyObject* obj );
+Vec3f * Vec3f_ptr_from_PyObject( PyObject* obj );
+Vec3r * Vec3r_ptr_from_PyObject( PyObject* obj );
+Vec2f * Vec2f_ptr_from_Vector( PyObject* obj );
+Vec3f * Vec3f_ptr_from_Vector( PyObject* obj );
+Vec3r * Vec3r_ptr_from_Vector( PyObject* obj );
+Vec2f * Vec2f_ptr_from_PyList( PyObject* obj );
+Vec3f * Vec3f_ptr_from_PyList( PyObject* obj );
+Vec3r * Vec3r_ptr_from_PyList( PyObject* obj );
+Vec2f * Vec2f_ptr_from_PyTuple( PyObject* obj );
+Vec3f * Vec3f_ptr_from_PyTuple( PyObject* obj );
+Vec3r * Vec3r_ptr_from_PyTuple( PyObject* obj );
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_CONVERT_H */
diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
new file mode 100644
index 00000000000..969eed06933
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
@@ -0,0 +1,509 @@
+#include "BPy_Freestyle.h"
+
+#include "BPy_BBox.h"
+#include "BPy_BinaryPredicate0D.h"
+#include "BPy_BinaryPredicate1D.h"
+#include "BPy_ContextFunctions.h"
+#include "BPy_Convert.h"
+#include "BPy_FrsMaterial.h"
+#include "BPy_FrsNoise.h"
+#include "BPy_Id.h"
+#include "BPy_IntegrationType.h"
+#include "BPy_Interface0D.h"
+#include "BPy_Interface1D.h"
+#include "BPy_Iterator.h"
+#include "BPy_MediumType.h"
+#include "BPy_Nature.h"
+#include "BPy_Operators.h"
+#include "BPy_SShape.h"
+#include "BPy_StrokeAttribute.h"
+#include "BPy_StrokeShader.h"
+#include "BPy_UnaryFunction0D.h"
+#include "BPy_UnaryFunction1D.h"
+#include "BPy_UnaryPredicate0D.h"
+#include "BPy_UnaryPredicate1D.h"
+#include "BPy_ViewMap.h"
+#include "BPy_ViewShape.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------ MODULE FUNCTIONS ----------------------------------
+
+#include "FRS_freestyle.h"
+#include "RNA_access.h"
+#include "bpy_rna.h" /* pyrna_struct_CreatePyObject() */
+
+static char Freestyle_getCurrentScene___doc__[] =
+".. function:: getCurrentScene()\n"
+"\n"
+" Returns the current scene.\n"
+"\n"
+" :return: The current scene.\n"
+" :rtype: :class:`bpy.types.Scene`\n";
+
+static PyObject *Freestyle_getCurrentScene( PyObject *self )
+{
+ if (!freestyle_scene) {
+ PyErr_SetString(PyExc_TypeError, "current scene not available");
+ return NULL;
+ }
+ PointerRNA ptr_scene;
+ RNA_pointer_create(NULL, &RNA_Scene, freestyle_scene, &ptr_scene);
+ return pyrna_struct_CreatePyObject(&ptr_scene);
+}
+
+#include "DNA_material_types.h"
+
+static int ramp_blend_type(const char *type)
+{
+ if (!strcmp(type, "MIX")) return MA_RAMP_BLEND;
+ if (!strcmp(type, "ADD")) return MA_RAMP_ADD;
+ if (!strcmp(type, "MULTIPLY")) return MA_RAMP_MULT;
+ if (!strcmp(type, "SUBTRACT")) return MA_RAMP_SUB;
+ if (!strcmp(type, "SCREEN")) return MA_RAMP_SCREEN;
+ if (!strcmp(type, "DIVIDE")) return MA_RAMP_DIV;
+ if (!strcmp(type, "DIFFERENCE")) return MA_RAMP_DIFF;
+ if (!strcmp(type, "DARKEN")) return MA_RAMP_DARK;
+ if (!strcmp(type, "LIGHTEN")) return MA_RAMP_LIGHT;
+ if (!strcmp(type, "OVERLAY")) return MA_RAMP_OVERLAY;
+ if (!strcmp(type, "DODGE")) return MA_RAMP_DODGE;
+ if (!strcmp(type, "BURN")) return MA_RAMP_BURN;
+ if (!strcmp(type, "HUE")) return MA_RAMP_HUE;
+ if (!strcmp(type, "SATURATION")) return MA_RAMP_SAT;
+ if (!strcmp(type, "VALUE")) return MA_RAMP_VAL;
+ if (!strcmp(type, "COLOR")) return MA_RAMP_COLOR;
+ if (!strcmp(type, "SOFT LIGHT")) return MA_RAMP_SOFT;
+ if (!strcmp(type, "LINEAR LIGHT")) return MA_RAMP_LINEAR;
+ return -1;
+}
+
+#include "BKE_material.h" /* ramp_blend() */
+
+static char Freestyle_blendRamp___doc__[] =
+".. function:: blendRamp(type, color1, fac, color2)\n"
+"\n"
+" Blend two colors according to a ramp blend type.\n"
+"\n"
+" :arg type: Ramp blend type.\n"
+" :type type: int\n"
+" :arg color1: 1st color.\n"
+" :type color1: :class:`mathutils.Vector`, list or tuple of 3 real numbers\n"
+" :arg fac: Blend factor.\n"
+" :type fac: float\n"
+" :arg color2: 1st color.\n"
+" :type color2: :class:`mathutils.Vector`, list or tuple of 3 real numbers\n"
+" :return: Blended color in RGB format.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static PyObject *Freestyle_blendRamp( PyObject *self, PyObject *args )
+{
+ PyObject *obj1, *obj2;
+ char *s;
+ int type;
+ Vec3f *v1 = NULL, *v2 = NULL;
+ float a[3], fac, b[3];
+
+ if (!PyArg_ParseTuple(args, "sOfO", &s, &obj1, &fac, &obj2))
+ return NULL;
+ type = ramp_blend_type(s);
+ if (type < 0) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 is an unknown ramp blend type");
+ goto error;
+ }
+ v1 = Vec3f_ptr_from_PyObject(obj1);
+ if (!v1) {
+ PyErr_SetString(PyExc_TypeError, "argument 2 must be a 3D vector (either a tuple/list of 3 elements or Vector)");
+ goto error;
+ }
+ v2 = Vec3f_ptr_from_PyObject(obj2);
+ if (!v2) {
+ PyErr_SetString(PyExc_TypeError, "argument 4 must be a 3D vector (either a tuple/list of 3 elements or Vector)");
+ goto error;
+ }
+ a[0] = v1->x(); b[0] = v2->x();
+ a[1] = v1->y(); b[1] = v2->y();
+ a[2] = v1->z(); b[2] = v2->z();
+ ramp_blend(type, a, fac, b);
+ delete v1;
+ delete v2;
+ return Vector_CreatePyObject( a, 3, Py_NEW, NULL);
+
+error:
+ if (v1) delete v1;
+ if (v2) delete v2;
+ return NULL;
+}
+
+#include "BKE_texture.h" /* do_colorband() */
+
+static char Freestyle_evaluateColorRamp___doc__[] =
+".. function:: evaluateColorRamp(ramp, in)\n"
+"\n"
+" Evaluate a color ramp at a point in the interval 0 to 1.\n"
+"\n"
+" :arg ramp: Color ramp object.\n"
+" :type ramp: :class:`bpy.types.ColorRamp`\n"
+" :arg in: Value in the interval 0 to 1.\n"
+" :type in: float\n"
+" :return: color in RGBA format.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static PyObject *Freestyle_evaluateColorRamp( PyObject *self, PyObject *args )
+{
+ BPy_StructRNA *py_srna;
+ ColorBand *coba;
+ float in, out[4];
+
+ if(!( PyArg_ParseTuple(args, "O!f", &pyrna_struct_Type, &py_srna, &in) ))
+ return NULL;
+ if(!RNA_struct_is_a(py_srna->ptr.type, &RNA_ColorRamp)) {
+ PyErr_SetString(PyExc_TypeError, "1st argument is not a ColorRamp object");
+ return NULL;
+ }
+ coba = (ColorBand *)py_srna->ptr.data;
+ if (!do_colorband(coba, in, out)) {
+ PyErr_SetString(PyExc_ValueError, "failed to evaluate the color ramp");
+ return NULL;
+ }
+ return Vector_CreatePyObject( out, 4, Py_NEW, NULL);
+}
+
+#include "DNA_color_types.h"
+#include "BKE_colortools.h" /* curvemapping_evaluateF() */
+
+static char Freestyle_evaluateCurveMappingF___doc__[] =
+".. function:: evaluateCurveMappingF(cumap, cur, value)\n"
+"\n"
+" Evaluate a curve mapping at a point in the interval 0 to 1.\n"
+"\n"
+" :arg cumap: Curve mapping object.\n"
+" :type cumap: :class:`bpy.types.CurveMapping`\n"
+" :arg cur: Index of the curve to be used (0 <= cur <= 3).\n"
+" :type cur: int\n"
+" :arg value: Input value in the interval 0 to 1.\n"
+" :type value: float\n"
+" :return: Mapped output value.\n"
+" :rtype: float\n";
+
+static PyObject *Freestyle_evaluateCurveMappingF( PyObject *self, PyObject *args )
+{
+ BPy_StructRNA *py_srna;
+ CurveMapping *cumap;
+ int cur;
+ float value;
+
+ if(!( PyArg_ParseTuple(args, "O!if", &pyrna_struct_Type, &py_srna, &cur, &value) ))
+ return NULL;
+ if(!RNA_struct_is_a(py_srna->ptr.type, &RNA_CurveMapping)) {
+ PyErr_SetString(PyExc_TypeError, "1st argument is not a CurveMapping object");
+ return NULL;
+ }
+ if (cur < 0 || cur > 3) {
+ PyErr_SetString(PyExc_ValueError, "2nd argument is out of range");
+ return NULL;
+ }
+ cumap = (CurveMapping *)py_srna->ptr.data;
+ curvemapping_initialize(cumap);
+ /* disable extrapolation if enabled */
+ if ((cumap->cm[cur].flag & CUMA_EXTEND_EXTRAPOLATE)) {
+ cumap->cm[cur].flag &= ~( CUMA_EXTEND_EXTRAPOLATE );
+ curvemapping_changed(cumap, 0);
+ }
+ return PyFloat_FromDouble(curvemapping_evaluateF(cumap, cur, value));
+}
+
+/*-----------------------Freestyle module docstring----------------------------*/
+
+static char module_docstring[] =
+"This module provides classes for defining line drawing rules (such as\n"
+"predicates, functions, chaining iterators, and stroke shaders), as well\n"
+"as helper functions for style module writing.\n"
+"\n"
+"Class hierarchy:\n"
+"\n"
+"- :class:`BBox`\n"
+"- :class:`BinaryPredicate0D`\n"
+"- :class:`BinaryPredicate1D`\n"
+"\n"
+" - :class:`FalseBP1D`\n"
+" - :class:`Length2DBP1D`\n"
+" - :class:`SameShapeIdBP1D`\n"
+" - :class:`TrueBP1D`\n"
+" - :class:`ViewMapGradientNormBP1D`\n"
+"\n"
+"- :class:`Id`\n"
+"- :class:`Interface0D`\n"
+"\n"
+" - :class:`CurvePoint`\n"
+"\n"
+" - :class:`StrokeVertex`\n"
+"\n"
+" - :class:`SVertex`\n"
+" - :class:`ViewVertex`\n"
+"\n"
+" - :class:`NonTVertex`\n"
+" - :class:`TVertex`\n"
+"\n"
+"- :class:`Interface1D`\n"
+"\n"
+" - :class:`Curve`\n"
+"\n"
+" - :class:`Chain`\n"
+"\n"
+" - :class:`FEdge`\n"
+"\n"
+" - :class:`FEdgeSharp`\n"
+" - :class:`FEdgeSmooth`\n"
+"\n"
+" - :class:`Stroke`\n"
+" - :class:`ViewEdge`\n"
+"\n"
+"- :class:`Iterator`\n"
+"\n"
+" - :class:`AdjacencyIterator`\n"
+" - :class:`CurvePointIterator`\n"
+" - :class:`Interface0DIterator`\n"
+" - :class:`SVertexIterator`\n"
+" - :class:`StrokeVertexIterator`\n"
+" - :class:`ViewEdgeIterator`\n"
+"\n"
+" - :class:`ChainingIterator`\n"
+"\n"
+" - :class:`ChainPredicateIterator`\n"
+" - :class:`ChainSilhouetteIterator`\n"
+"\n"
+" - :class:`orientedViewEdgeIterator`\n"
+"\n"
+"- :class:`Material`\n"
+"- :class:`Noise`\n"
+"- :class:`Operators`\n"
+"- :class:`SShape`\n"
+"- :class:`StrokeAttribute`\n"
+"- :class:`StrokeShader`\n"
+"\n"
+" - :class:`BackboneStretcherShader`\n"
+" - :class:`BezierCurveShader`\n"
+" - :class:`CalligraphicShader`\n"
+" - :class:`ColorNoiseShader`\n"
+" - :class:`ColorVariationPatternShader`\n"
+" - :class:`ConstantColorShader`\n"
+" - :class:`ConstantThicknessShader`\n"
+" - :class:`ConstrainedIncreasingThicknessShader`\n"
+" - :class:`GuidingLinesShader`\n"
+" - :class:`IncreasingColorShader`\n"
+" - :class:`IncreasingThicknessShader`\n"
+" - :class:`PolygonalizationShader`\n"
+" - :class:`SamplingShader`\n"
+" - :class:`SmoothingShader`\n"
+" - :class:`SpatialNoiseShader`\n"
+" - :class:`StrokeTextureShader`\n"
+" - :class:`TextureAssignerShader`\n"
+" - :class:`ThicknessNoiseShader`\n"
+" - :class:`ThicknessVariationPatternShader`\n"
+" - :class:`TipRemoverShader`\n"
+" - :class:`fstreamShader`\n"
+" - :class:`streamShader`\n"
+"\n"
+"- :class:`UnaryFunction0D`\n"
+"\n"
+" - :class:`UnaryFunction0DDouble`\n"
+"\n"
+" - :class:`Curvature2DAngleF0D`\n"
+" - :class:`DensityF0D`\n"
+" - :class:`GetProjectedXF0D`\n"
+" - :class:`GetProjectedYF0D`\n"
+" - :class:`GetProjectedZF0D`\n"
+" - :class:`GetXF0D`\n"
+" - :class:`GetYF0D`\n"
+" - :class:`GetZF0D`\n"
+" - :class:`LocalAverageDepthF0D`\n"
+" - :class:`ZDiscontinuityF0D`\n"
+"\n"
+" - :class:`UnaryFunction0DEdgeNature`\n"
+"\n"
+" - :class:`CurveNatureF0D`\n"
+"\n"
+" - :class:`UnaryFunction0DFloat`\n"
+"\n"
+" - :class:`GetCurvilinearAbscissaF0D`\n"
+" - :class:`GetParameterF0D`\n"
+" - :class:`GetViewMapGradientNormF0D`\n"
+" - :class:`ReadCompleteViewMapPixelF0D`\n"
+" - :class:`ReadMapPixelF0D`\n"
+" - :class:`ReadSteerableViewMapPixelF0D`\n"
+"\n"
+" - :class:`UnaryFunction0DId`\n"
+"\n"
+" - :class:`ShapeIdF0D`\n"
+"\n"
+" - :class:`UnaryFunction0DMaterial`\n"
+"\n"
+" - :class:`MaterialF0D`\n"
+"\n"
+" - :class:`UnaryFunction0DUnsigned`\n"
+"\n"
+" - :class:`QuantitativeInvisibilityF0D`\n"
+"\n"
+" - :class:`UnaryFunction0DVec2f`\n"
+"\n"
+" - :class:`Normal2DF0D`\n"
+" - :class:`VertexOrientation2DF0D`\n"
+"\n"
+" - :class:`UnaryFunction0DVec3f`\n"
+"\n"
+" - :class:`VertexOrientation3DF0D`\n"
+"\n"
+" - :class:`UnaryFunction0DVectorViewShape`\n"
+"\n"
+" - :class:`GetOccludersF0D`\n"
+"\n"
+" - :class:`UnaryFunction0DViewShape`\n"
+"\n"
+" - :class:`GetOccludeeF0D`\n"
+" - :class:`GetShapeF0D`\n"
+"\n"
+"- :class:`UnaryFunction1D`\n"
+"\n"
+" - :class:`UnaryFunction1DDouble`\n"
+"\n"
+" - :class:`Curvature2DAngleF1D`\n"
+" - :class:`DensityF1D`\n"
+" - :class:`GetCompleteViewMapDensityF1D`\n"
+" - :class:`GetDirectionalViewMapDensityF1D`\n"
+" - :class:`GetProjectedXF1D`\n"
+" - :class:`GetProjectedYF1D`\n"
+" - :class:`GetProjectedZF1D`\n"
+" - :class:`GetSteerableViewMapDensityF1D`\n"
+" - :class:`GetViewMapGradientNormF1D`\n"
+" - :class:`GetXF1D`\n"
+" - :class:`GetYF1D`\n"
+" - :class:`GetZF1D`\n"
+" - :class:`LocalAverageDepthF1D`\n"
+" - :class:`ZDiscontinuityF1D`\n"
+"\n"
+" - :class:`UnaryFunction1DEdgeNature`\n"
+"\n"
+" - :class:`CurveNatureF1D`\n"
+"\n"
+" - :class:`UnaryFunction1DFloat`\n"
+" - :class:`UnaryFunction1DUnsigned`\n"
+"\n"
+" - :class:`QuantitativeInvisibilityF1D`\n"
+"\n"
+" - :class:`UnaryFunction1DVec2f`\n"
+"\n"
+" - :class:`Normal2DF1D`\n"
+" - :class:`Orientation2DF1D`\n"
+"\n"
+" - :class:`UnaryFunction1DVec3f`\n"
+"\n"
+" - :class:`Orientation3DF1D`\n"
+"\n"
+" - :class:`UnaryFunction1DVectorViewShape`\n"
+"\n"
+" - :class:`GetOccludeeF1D`\n"
+" - :class:`GetOccludersF1D`\n"
+" - :class:`GetShapeF1D`\n"
+"\n"
+" - :class:`UnaryFunction1DVoid`\n"
+"\n"
+" - :class:`ChainingTimeStampF1D`\n"
+" - :class:`IncrementChainingTimeStampF1D`\n"
+" - :class:`TimeStampF1D`\n"
+"\n"
+"- :class:`UnaryPredicate0D`\n"
+"\n"
+" - :class:`FalseUP0D`\n"
+" - :class:`TrueUP0D`\n"
+"\n"
+"- :class:`UnaryPredicate1D`\n"
+"\n"
+" - :class:`ContourUP1D`\n"
+" - :class:`DensityLowerThanUP1D`\n"
+" - :class:`EqualToChainingTimeStampUP1D`\n"
+" - :class:`EqualToTimeStampUP1D`\n"
+" - :class:`ExternalContourUP1D`\n"
+" - :class:`FalseUP1D`\n"
+" - :class:`QuantitativeInvisibilityUP1D`\n"
+" - :class:`ShapeUP1D`\n"
+" - :class:`TrueUP1D`\n"
+"\n"
+"- :class:`ViewMap`\n"
+"- :class:`ViewShape`\n"
+"- :class:`IntegrationType`\n"
+"- :class:`MediumType`\n"
+"- :class:`Nature`\n"
+"\n";
+
+/*-----------------------Freestyle module method def---------------------------*/
+
+static PyMethodDef module_functions[] = {
+ {"getCurrentScene", ( PyCFunction ) Freestyle_getCurrentScene, METH_NOARGS, Freestyle_getCurrentScene___doc__},
+ {"blendRamp", ( PyCFunction ) Freestyle_blendRamp, METH_VARARGS, Freestyle_blendRamp___doc__},
+ {"evaluateColorRamp", ( PyCFunction ) Freestyle_evaluateColorRamp, METH_VARARGS, Freestyle_evaluateColorRamp___doc__},
+ {"evaluateCurveMappingF", ( PyCFunction ) Freestyle_evaluateCurveMappingF, METH_VARARGS, Freestyle_evaluateCurveMappingF___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------Freestyle module definition---------------------------*/
+
+static PyModuleDef module_definition = {
+ PyModuleDef_HEAD_INIT,
+ "Freestyle",
+ module_docstring,
+ -1,
+ module_functions
+};
+
+//-------------------MODULE INITIALIZATION--------------------------------
+PyObject *Freestyle_Init( void )
+{
+ PyObject *module;
+
+ // initialize modules
+ module = PyModule_Create(&module_definition);
+ if (!module)
+ return NULL;
+ PyDict_SetItemString(PySys_GetObject("modules"), module_definition.m_name, module);
+
+ // attach its classes (adding the object types to the module)
+
+ // those classes have to be initialized before the others
+ MediumType_Init( module );
+ Nature_Init( module );
+
+ BBox_Init( module );
+ BinaryPredicate0D_Init( module );
+ BinaryPredicate1D_Init( module );
+ ContextFunctions_Init( module );
+ FrsMaterial_Init( module );
+ FrsNoise_Init( module );
+ Id_Init( module );
+ IntegrationType_Init( module );
+ Interface0D_Init( module );
+ Interface1D_Init( module );
+ Iterator_Init( module );
+ Operators_Init( module );
+ SShape_Init( module );
+ StrokeAttribute_Init( module );
+ StrokeShader_Init( module );
+ UnaryFunction0D_Init( module );
+ UnaryFunction1D_Init( module );
+ UnaryPredicate0D_Init( module );
+ UnaryPredicate1D_Init( module );
+ ViewMap_Init( module );
+ ViewShape_Init( module );
+
+ return module;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.h b/source/blender/freestyle/intern/python/BPy_Freestyle.h
new file mode 100644
index 00000000000..8ade4b5ff4d
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Freestyle.h
@@ -0,0 +1,22 @@
+#ifndef FREESTYLE_PYTHON_FREESTYLE_H
+#define FREESTYLE_PYTHON_FREESTYLE_H
+
+#include <Python.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+/*---------------------------Python BPy_Freestyle visible prototypes-----------*/
+
+PyObject *Freestyle_Init( void );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_FREESTYLE_H */
diff --git a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
new file mode 100644
index 00000000000..377bed7be09
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
@@ -0,0 +1,599 @@
+#include "BPy_FrsMaterial.h"
+
+#include "BPy_Convert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int FrsMaterial_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &FrsMaterial_Type ) < 0 )
+ return -1;
+
+ Py_INCREF( &FrsMaterial_Type );
+ PyModule_AddObject(module, "Material", (PyObject *)&FrsMaterial_Type);
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char FrsMaterial___doc__[] =
+"Class defining a material.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(m)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg m: A Material object.\n"
+" :type m: :class:`Material`\n"
+"\n"
+".. method:: __init__(iDiffuse, iAmbiant, iSpecular, iEmission, iShininess)\n"
+"\n"
+" Builds a Material from its diffuse, ambiant, specular, emissive\n"
+" colors and a shininess coefficient.\n"
+"\n"
+" :arg iDiffuse: The diffuse color.\n"
+" :type iDiffuse: :class:`mathutils.Vector`, list or tuple of 4 float values\n"
+" :arg iAmbiant: The ambiant color.\n"
+" :type iAmbiant: :class:`mathutils.Vector`, list or tuple of 4 float values\n"
+" :arg iSpecular: The specular color.\n"
+" :type iSpecular: :class:`mathutils.Vector`, list or tuple of 4 float values\n"
+" :arg iEmission: The emissive color.\n"
+" :type iEmission: :class:`mathutils.Vector`, list or tuple of 4 float values\n"
+" :arg iShininess: The shininess coefficient.\n"
+" :type iShininess: :class:float\n";
+
+static int Vec4(PyObject *obj, float *v)
+{
+ if (VectorObject_Check(obj) && ((VectorObject *)obj)->size == 4) {
+ for (int i = 0; i < 4; i++)
+ v[i] = ((VectorObject *)obj)->vec[i];
+ } else if( PyList_Check(obj) && PyList_Size(obj) == 4 ) {
+ for (int i = 0; i < 4; i++)
+ v[i] = PyFloat_AsDouble(PyList_GetItem(obj, i));
+ } else if( PyTuple_Check(obj) && PyTuple_Size(obj) == 4 ) {
+ for (int i = 0; i < 4; i++)
+ v[i] = PyFloat_AsDouble(PyTuple_GetItem(obj, i));
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+static int FrsMaterial___init__(BPy_FrsMaterial *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0, *obj4 = 0;
+ float f1[4], f2[4], f3[4], f4[4], f5 = 0.;
+
+ if (! PyArg_ParseTuple(args, "|OOOOf", &obj1, &obj2, &obj3, &obj4, &f5) )
+ return -1;
+
+ if( !obj1 ){
+ self->m = new FrsMaterial();
+
+ } else if( BPy_FrsMaterial_Check(obj1) && !obj2 ) {
+ FrsMaterial *m = ((BPy_FrsMaterial *) obj1)->m;
+ if( !m ) {
+ PyErr_SetString(PyExc_RuntimeError, "invalid FrsMaterial object");
+ return -1;
+ }
+ self->m = new FrsMaterial( *m );
+
+ } else if( Vec4(obj1, f1) && obj2 && Vec4(obj2, f2) && obj3 && Vec4(obj3, f3) && obj4 && Vec4(obj4, f4) ) {
+ self->m = new FrsMaterial(f1, f2, f3, f4, f5);
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
+ return -1;
+ }
+ self->borrowed = 0;
+
+ return 0;
+}
+
+static void FrsMaterial___dealloc__( BPy_FrsMaterial* self)
+{
+ if( self->m && !self->borrowed )
+ delete self->m;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+
+static PyObject * FrsMaterial___repr__( BPy_FrsMaterial* self)
+{
+ return PyUnicode_FromFormat("Material - address: %p", self->m );
+}
+
+static char FrsMaterial_diffuse___doc__[] =
+".. method:: diffuse()\n"
+"\n"
+" Returns the diffuse color.\n"
+"\n"
+" :return: The diffuse color.\n"
+" :rtype: Tuple of 4 float values\n";
+
+static PyObject * FrsMaterial_diffuse( BPy_FrsMaterial* self) {
+ const float *diffuse = self->m->diffuse();
+ PyObject *py_diffuse = PyTuple_New(4);
+
+ PyTuple_SetItem( py_diffuse, 0, PyFloat_FromDouble( diffuse[0] ) );
+ PyTuple_SetItem( py_diffuse, 1, PyFloat_FromDouble( diffuse[1] ) );
+ PyTuple_SetItem( py_diffuse, 2, PyFloat_FromDouble( diffuse[2] ) );
+ PyTuple_SetItem( py_diffuse, 3, PyFloat_FromDouble( diffuse[3] ) );
+
+ return py_diffuse;
+}
+
+static char FrsMaterial_diffuseR___doc__[] =
+".. method:: diffuseR()\n"
+"\n"
+" Returns the red component of the diffuse color.\n"
+"\n"
+" :return: The red component of the diffuse color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_diffuseR( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->diffuseR() );
+}
+
+static char FrsMaterial_diffuseG___doc__[] =
+".. method:: diffuseG()\n"
+"\n"
+" Returns the green component of the diffuse color.\n"
+"\n"
+" :return: The green component of the diffuse color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_diffuseG( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->diffuseG() );
+}
+
+static char FrsMaterial_diffuseB___doc__[] =
+".. method:: diffuseB()\n"
+"\n"
+" Returns the blue component of the diffuse color.\n"
+"\n"
+" :return: The blue component of the diffuse color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_diffuseB( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->diffuseB() );
+}
+
+static char FrsMaterial_diffuseA___doc__[] =
+".. method:: diffuseA()\n"
+"\n"
+" Returns the alpha component of the diffuse color.\n"
+"\n"
+" :return: The alpha component of the diffuse color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_diffuseA( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->diffuseA() );
+}
+
+static char FrsMaterial_specular___doc__[] =
+".. method:: specular()\n"
+"\n"
+" Returns the specular color.\n"
+"\n"
+" :return: The specular color.\n"
+" :rtype: Tuple of 4 float values\n";
+
+static PyObject * FrsMaterial_specular( BPy_FrsMaterial* self) {
+ const float *specular = self->m->specular();
+ PyObject *py_specular = PyTuple_New(4);
+
+ PyTuple_SetItem( py_specular, 0, PyFloat_FromDouble( specular[0] ) );
+ PyTuple_SetItem( py_specular, 1, PyFloat_FromDouble( specular[1] ) );
+ PyTuple_SetItem( py_specular, 2, PyFloat_FromDouble( specular[2] ) );
+ PyTuple_SetItem( py_specular, 3, PyFloat_FromDouble( specular[3] ) );
+
+ return py_specular;
+}
+
+static char FrsMaterial_specularR___doc__[] =
+".. method:: specularR()\n"
+"\n"
+" Returns the red component of the specular color.\n"
+"\n"
+" :return: The red component of the specular color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_specularR( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->specularR() );
+}
+
+static char FrsMaterial_specularG___doc__[] =
+".. method:: specularG()\n"
+"\n"
+" Returns the green component of the specular color.\n"
+"\n"
+" :return: The green component of the specular color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_specularG( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->specularG() );
+}
+
+static char FrsMaterial_specularB___doc__[] =
+".. method:: specularB()\n"
+"\n"
+" Returns the blue component of the specular color.\n"
+"\n"
+" :return: The blue component of the specular color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_specularB( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->specularB() );
+}
+
+static char FrsMaterial_specularA___doc__[] =
+".. method:: specularA()\n"
+"\n"
+" Returns the alpha component of the specular color.\n"
+"\n"
+" :return: The alpha component of the specular color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_specularA( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->specularA() );
+}
+
+static char FrsMaterial_ambient___doc__[] =
+".. method:: ambient()\n"
+"\n"
+" Returns the ambiant color.\n"
+"\n"
+" :return: The ambiant color.\n"
+" :rtype: Tuple of 4 float values\n";
+
+static PyObject * FrsMaterial_ambient( BPy_FrsMaterial* self) {
+ const float *ambient = self->m->ambient();
+ PyObject *py_ambient = PyTuple_New(4);
+
+ PyTuple_SetItem( py_ambient, 0, PyFloat_FromDouble( ambient[0] ) );
+ PyTuple_SetItem( py_ambient, 1, PyFloat_FromDouble( ambient[1] ) );
+ PyTuple_SetItem( py_ambient, 2, PyFloat_FromDouble( ambient[2] ) );
+ PyTuple_SetItem( py_ambient, 3, PyFloat_FromDouble( ambient[3] ) );
+
+ return py_ambient;
+}
+
+static char FrsMaterial_ambientR___doc__[] =
+".. method:: ambientR()\n"
+"\n"
+" Returns the red component of the ambiant color.\n"
+"\n"
+" :return: The red component of the ambiant color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_ambientR( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->ambientR() );
+}
+
+static char FrsMaterial_ambientG___doc__[] =
+".. method:: ambientG()\n"
+"\n"
+" Returns the green component of the ambiant color.\n"
+"\n"
+" :return: The green component of the ambiant color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_ambientG( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->ambientG() );
+}
+
+static char FrsMaterial_ambientB___doc__[] =
+".. method:: ambientB()\n"
+"\n"
+" Returns the blue component of the ambiant color.\n"
+"\n"
+" :return: The blue component of the ambiant color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_ambientB( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->ambientB() );
+}
+
+static char FrsMaterial_ambientA___doc__[] =
+".. method:: ambientA()\n"
+"\n"
+" Returns the alpha component of the ambiant color.\n"
+"\n"
+" :return: The alpha component of the ambiant color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_ambientA( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->ambientA() );
+}
+
+static char FrsMaterial_emission___doc__[] =
+".. method:: emission()\n"
+"\n"
+" Returns the emissive color.\n"
+"\n"
+" :return: the emissive color.\n"
+" :rtype: Tuple of 4 float values\n";
+
+static PyObject * FrsMaterial_emission( BPy_FrsMaterial* self) {
+ const float *emission = self->m->emission();
+ PyObject *py_emission = PyTuple_New(4);
+
+ PyTuple_SetItem( py_emission, 0, PyFloat_FromDouble( emission[0] ) );
+ PyTuple_SetItem( py_emission, 1, PyFloat_FromDouble( emission[1] ) );
+ PyTuple_SetItem( py_emission, 2, PyFloat_FromDouble( emission[2] ) );
+ PyTuple_SetItem( py_emission, 3, PyFloat_FromDouble( emission[3] ) );
+
+ return py_emission;
+}
+
+static char FrsMaterial_emissionR___doc__[] =
+".. method:: emissionR()\n"
+"\n"
+" Returns the red component of the emissive color.\n"
+"\n"
+" :return: The red component of the emissive color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_emissionR( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->emissionR() );
+}
+
+static char FrsMaterial_emissionG___doc__[] =
+".. method:: emissionG()\n"
+"\n"
+" Returns the green component of the emissive color.\n"
+"\n"
+" :return: The green component of the emissive color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_emissionG( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->emissionG() );
+}
+
+static char FrsMaterial_emissionB___doc__[] =
+".. method:: emissionB()\n"
+"\n"
+" Returns the blue component of the emissive color.\n"
+"\n"
+" :return: The blue component of the emissive color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_emissionB( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->emissionB() );
+}
+
+static char FrsMaterial_emissionA___doc__[] =
+".. method:: emissionA()\n"
+"\n"
+" Returns the alpha component of the emissive color.\n"
+"\n"
+" :return: The alpha component of the emissive color.\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_emissionA( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->emissionA() );
+}
+
+static char FrsMaterial_shininess___doc__[] =
+".. method:: shininess()\n"
+"\n"
+" Returns the shininess coefficient.\n"
+"\n"
+" :return: Shininess\n"
+" :rtype: float\n";
+
+static PyObject * FrsMaterial_shininess( BPy_FrsMaterial* self) {
+ return PyFloat_FromDouble( self->m->shininess() );
+}
+
+static char FrsMaterial_setDiffuse___doc__[] =
+".. method:: setDiffuse(r, g, b, a)\n"
+"\n"
+" Sets the diffuse color.\n"
+"\n"
+" :arg r: Red component.\n"
+" :type r: float\n"
+" :arg g: Green component.\n"
+" :type g: float\n"
+" :arg b: Blue component.\n"
+" :type b: float\n"
+" :arg a: Alpha component.\n"
+" :type a: float\n";
+
+static PyObject * FrsMaterial_setDiffuse( BPy_FrsMaterial *self, PyObject *args ) {
+ float f1, f2, f3, f4;
+
+ if(!( PyArg_ParseTuple(args, "ffff", &f1, &f2, &f3, &f4) ))
+ return NULL;
+
+ self->m->setDiffuse(f1, f2, f3, f4);
+
+ Py_RETURN_NONE;
+}
+
+static char FrsMaterial_setSpecular___doc__[] =
+".. method:: setSpecular(r, g, b, a)\n"
+"\n"
+" Sets the specular color.\n"
+"\n"
+" :arg r: Red component.\n"
+" :type r: float\n"
+" :arg g: Green component.\n"
+" :type g: float\n"
+" :arg b: Blue component.\n"
+" :type b: float\n"
+" :arg a: Alpha component.\n"
+" :type a: float\n";
+
+static PyObject * FrsMaterial_setSpecular( BPy_FrsMaterial *self, PyObject *args ) {
+ float f1, f2, f3, f4;
+
+ if(!( PyArg_ParseTuple(args, "ffff", &f1, &f2, &f3, &f4) ))
+ return NULL;
+
+ self->m->setSpecular(f1, f2, f3, f4);
+
+ Py_RETURN_NONE;
+}
+
+static char FrsMaterial_setAmbient___doc__[] =
+".. method:: setAmbient(r, g, b, a)\n"
+"\n"
+" Sets the ambiant color.\n"
+"\n"
+" :arg r: Red component.\n"
+" :type r: float\n"
+" :arg g: Green component.\n"
+" :type g: float\n"
+" :arg b: Blue component.\n"
+" :type b: float\n"
+" :arg a: Alpha component.\n"
+" :type a: float\n";
+
+static PyObject * FrsMaterial_setAmbient( BPy_FrsMaterial *self, PyObject *args ) {
+ float f1, f2, f3, f4;
+
+ if(!( PyArg_ParseTuple(args, "ffff", &f1, &f2, &f3, &f4) ))
+ return NULL;
+
+ self->m->setAmbient(f1, f2, f3, f4);
+
+ Py_RETURN_NONE;
+}
+
+static char FrsMaterial_setEmission___doc__[] =
+".. method:: setEmission(r, g, b, a)\n"
+"\n"
+" Sets the emissive color.\n"
+"\n"
+" :arg r: Red component.\n"
+" :type r: float\n"
+" :arg g: Green component.\n"
+" :type g: float\n"
+" :arg b: Blue component.\n"
+" :type b: float\n"
+" :arg a: Alpha component.\n"
+" :type a: float\n";
+
+static PyObject * FrsMaterial_setEmission( BPy_FrsMaterial *self, PyObject *args ) {
+ float f1, f2, f3, f4;
+
+ if(!( PyArg_ParseTuple(args, "ffff", &f1, &f2, &f3, &f4) ))
+ return NULL;
+
+ self->m->setEmission(f1, f2, f3, f4);
+
+ Py_RETURN_NONE;
+}
+
+static char FrsMaterial_setShininess___doc__[] =
+".. method:: setShininess(s)\n"
+"\n"
+" Sets the shininess.\n"
+"\n"
+" :arg s: Shininess.\n"
+" :type s: float\n";
+
+static PyObject * FrsMaterial_setShininess( BPy_FrsMaterial *self, PyObject *args ) {
+ float f;
+
+ if(!( PyArg_ParseTuple(args, "f", &f) ))
+ return NULL;
+
+ self->m->setShininess(f);
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------FrsMaterial instance definitions ----------------------------*/
+static PyMethodDef BPy_FrsMaterial_methods[] = {
+ {"diffuse", ( PyCFunction ) FrsMaterial_diffuse, METH_NOARGS, FrsMaterial_diffuse___doc__},
+ {"diffuseR", ( PyCFunction ) FrsMaterial_diffuseR, METH_NOARGS, FrsMaterial_diffuseR___doc__},
+ {"diffuseG", ( PyCFunction ) FrsMaterial_diffuseG, METH_NOARGS, FrsMaterial_diffuseG___doc__},
+ {"diffuseB", ( PyCFunction ) FrsMaterial_diffuseB, METH_NOARGS, FrsMaterial_diffuseB___doc__},
+ {"diffuseA", ( PyCFunction ) FrsMaterial_diffuseA, METH_NOARGS, FrsMaterial_diffuseA___doc__},
+ {"specular", ( PyCFunction ) FrsMaterial_specular, METH_NOARGS, FrsMaterial_specular___doc__},
+ {"specularR", ( PyCFunction ) FrsMaterial_specularR, METH_NOARGS, FrsMaterial_specularR___doc__},
+ {"specularG", ( PyCFunction ) FrsMaterial_specularG, METH_NOARGS, FrsMaterial_specularG___doc__},
+ {"specularB", ( PyCFunction ) FrsMaterial_specularB, METH_NOARGS, FrsMaterial_specularB___doc__},
+ {"specularA", ( PyCFunction ) FrsMaterial_specularA, METH_NOARGS, FrsMaterial_specularA___doc__},
+ {"ambient", ( PyCFunction ) FrsMaterial_ambient, METH_NOARGS, FrsMaterial_ambient___doc__},
+ {"ambientR", ( PyCFunction ) FrsMaterial_ambientR, METH_NOARGS, FrsMaterial_ambientR___doc__},
+ {"ambientG", ( PyCFunction ) FrsMaterial_ambientG, METH_NOARGS, FrsMaterial_ambientG___doc__},
+ {"ambientB", ( PyCFunction ) FrsMaterial_ambientB, METH_NOARGS, FrsMaterial_ambientB___doc__},
+ {"ambientA", ( PyCFunction ) FrsMaterial_ambientA, METH_NOARGS, FrsMaterial_ambientA___doc__},
+ {"emission", ( PyCFunction ) FrsMaterial_emission, METH_NOARGS, FrsMaterial_emission___doc__},
+ {"emissionR", ( PyCFunction ) FrsMaterial_emissionR, METH_NOARGS, FrsMaterial_emissionR___doc__},
+ {"emissionG", ( PyCFunction ) FrsMaterial_emissionG, METH_NOARGS, FrsMaterial_emissionG___doc__},
+ {"emissionB", ( PyCFunction ) FrsMaterial_emissionB, METH_NOARGS, FrsMaterial_emissionB___doc__},
+ {"emissionA", ( PyCFunction ) FrsMaterial_emissionA, METH_NOARGS, FrsMaterial_emissionA___doc__},
+ {"shininess", ( PyCFunction ) FrsMaterial_shininess, METH_NOARGS, FrsMaterial_shininess___doc__},
+ {"setDiffuse", ( PyCFunction ) FrsMaterial_setDiffuse, METH_NOARGS, FrsMaterial_setDiffuse___doc__},
+ {"setSpecular", ( PyCFunction ) FrsMaterial_setSpecular, METH_NOARGS, FrsMaterial_setSpecular___doc__},
+ {"setAmbient", ( PyCFunction ) FrsMaterial_setAmbient, METH_NOARGS, FrsMaterial_setAmbient___doc__},
+ {"setEmission", ( PyCFunction ) FrsMaterial_setEmission, METH_NOARGS, FrsMaterial_setEmission___doc__},
+ {"setShininess", ( PyCFunction ) FrsMaterial_setShininess, METH_NOARGS, FrsMaterial_setShininess___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_FrsMaterial type definition ------------------------------*/
+
+PyTypeObject FrsMaterial_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Material", /* tp_name */
+ sizeof(BPy_FrsMaterial), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)FrsMaterial___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)FrsMaterial___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ FrsMaterial___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_FrsMaterial_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)FrsMaterial___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_FrsMaterial.h b/source/blender/freestyle/intern/python/BPy_FrsMaterial.h
new file mode 100644
index 00000000000..f541e1bb529
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_FrsMaterial.h
@@ -0,0 +1,37 @@
+#ifndef FREESTYLE_PYTHON_FRSMATERIAL_H
+#define FREESTYLE_PYTHON_FRSMATERIAL_H
+
+#include <Python.h>
+
+#include "../scene_graph/FrsMaterial.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject FrsMaterial_Type;
+
+#define BPy_FrsMaterial_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &FrsMaterial_Type) )
+
+/*---------------------------Python BPy_FrsMaterial structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ FrsMaterial *m;
+ int borrowed; /* non-zero if *m is a borrowed object */
+} BPy_FrsMaterial;
+
+/*---------------------------Python BPy_FrsMaterial visible prototypes-----------*/
+
+int FrsMaterial_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_FRSMATERIAL_H */
diff --git a/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp
new file mode 100644
index 00000000000..d58a37179ac
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp
@@ -0,0 +1,280 @@
+#include "BPy_FrsNoise.h"
+#include "BPy_Convert.h"
+
+#include <sstream>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int FrsNoise_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &FrsNoise_Type ) < 0 )
+ return -1;
+
+ Py_INCREF( &FrsNoise_Type );
+ PyModule_AddObject(module, "Noise", (PyObject *)&FrsNoise_Type);
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char FrsNoise___doc__[] =
+"Class to provide Perlin noise functionalities.\n"
+"\n"
+".. method:: __init__(seed = -1)\n"
+"\n"
+" Builds a Noise object. Seed is an optional argument. The seed value is used\n"
+" as a seed for random number generation if it is equal to or greater than zero;\n"
+" otherwise, time is used as a seed.\n"
+"\n"
+" :arg seed: Seed for random number generation.\n"
+" :type seed: int\n";
+
+static int FrsNoise___init__(BPy_FrsNoise *self, PyObject *args, PyObject *kwds)
+{
+ long seed = -1;
+ if(!( PyArg_ParseTuple(args, "|l", &seed) ))
+ return -1;
+ self->n = new Noise(seed);
+ return 0;
+}
+
+static void FrsNoise___dealloc__(BPy_FrsNoise* self)
+{
+ delete self->n;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+
+static PyObject * FrsNoise___repr__(BPy_FrsNoise* self)
+{
+ return PyUnicode_FromFormat("Noise - address: %p", self->n );
+}
+
+static char FrsNoise_turbulence1___doc__[] =
+".. method:: turbulence1(v, freq, amp, oct=4)\n"
+"\n"
+" Returns a noise value for a 1D element.\n"
+"\n"
+" :arg v: One-dimensional sample point.\n"
+" :type v: float\n"
+" :arg freq: Noise frequency.\n"
+" :type freq: float\n"
+" :arg amp: Amplitude.\n"
+" :type amp: float\n"
+" :arg oct: Number of octaves.\n"
+" :type oct: int\n"
+" :return: A noise value.\n"
+" :rtype: float\n";
+
+static PyObject * FrsNoise_turbulence1( BPy_FrsNoise *self , PyObject *args) {
+ float f1, f2, f3;
+ unsigned int i = 4;
+
+ if(!( PyArg_ParseTuple(args, "fff|I", &f1, &f2, &f3, &i) ))
+ return NULL;
+
+ return PyFloat_FromDouble( self->n->turbulence1(f1, f2, f3, i) );
+}
+
+static char FrsNoise_turbulence2___doc__[] =
+".. method:: turbulence2(v, freq, amp, oct=4)\n"
+"\n"
+" Returns a noise value for a 2D element.\n"
+"\n"
+" :arg v: Two-dimensional sample point.\n"
+" :type v: :class:`mathutils.Vector`, list or tuple of 2 real numbers\n"
+" :arg freq: Noise frequency.\n"
+" :type freq: float\n"
+" :arg amp: Amplitude.\n"
+" :type amp: float\n"
+" :arg oct: Number of octaves.\n"
+" :type oct: int\n"
+" :return: A noise value.\n"
+" :rtype: float\n";
+
+static PyObject * FrsNoise_turbulence2( BPy_FrsNoise *self , PyObject *args) {
+ PyObject *obj1;
+ float f2, f3;
+ unsigned int i = 4;
+
+ if(!( PyArg_ParseTuple(args, "Off|I", &obj1, &f2, &f3, &i) ))
+ return NULL;
+ Vec2f *v = Vec2f_ptr_from_PyObject(obj1);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 2D vector (either a list of 2 elements or Vector)");
+ return NULL;
+ }
+ float t = self->n->turbulence2(*v, f2, f3, i);
+ delete v;
+ return PyFloat_FromDouble( t );
+}
+
+static char FrsNoise_turbulence3___doc__[] =
+".. method:: turbulence3(v, freq, amp, oct=4)\n"
+"\n"
+" Returns a noise value for a 3D element.\n"
+"\n"
+" :arg v: Three-dimensional sample point.\n"
+" :type v: :class:`mathutils.Vector`, list or tuple of 3 real numbers\n"
+" :arg freq: Noise frequency.\n"
+" :type freq: float\n"
+" :arg amp: Amplitude.\n"
+" :type amp: float\n"
+" :arg oct: Number of octaves.\n"
+" :type oct: int\n"
+" :return: A noise value.\n"
+" :rtype: float\n";
+
+static PyObject * FrsNoise_turbulence3( BPy_FrsNoise *self , PyObject *args) {
+ PyObject *obj1;
+ float f2, f3;
+ unsigned int i = 4;
+
+ if(!( PyArg_ParseTuple(args, "Off|I", &obj1, &f2, &f3, &i) ))
+ return NULL;
+ Vec3f *v = Vec3f_ptr_from_PyObject(obj1);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 3D vector (either a list of 3 elements or Vector)");
+ return NULL;
+ }
+ float t = self->n->turbulence3(*v, f2, f3, i);
+ delete v;
+ return PyFloat_FromDouble( t );
+}
+
+static char FrsNoise_smoothNoise1___doc__[] =
+".. method:: smoothNoise1(v)\n"
+"\n"
+" Returns a smooth noise value for a 1D element.\n"
+"\n"
+" :arg v: One-dimensional sample point.\n"
+" :type v: float\n"
+" :return: A smooth noise value.\n"
+" :rtype: float\n";
+
+static PyObject * FrsNoise_smoothNoise1( BPy_FrsNoise *self , PyObject *args) {
+ float f;
+
+ if(!( PyArg_ParseTuple(args, "f", &f) ))
+ return NULL;
+
+ return PyFloat_FromDouble( self->n->smoothNoise1(f) );
+}
+
+static char FrsNoise_smoothNoise2___doc__[] =
+".. method:: smoothNoise2(v)\n"
+"\n"
+" Returns a smooth noise value for a 2D element.\n"
+"\n"
+" :arg v: Two-dimensional sample point.\n"
+" :type v: :class:`mathutils.Vector`, list or tuple of 2 real numbers\n"
+" :return: A smooth noise value.\n"
+" :rtype: float\n";
+
+static PyObject * FrsNoise_smoothNoise2( BPy_FrsNoise *self , PyObject *args) {
+ PyObject *obj;
+
+ if(!( PyArg_ParseTuple(args, "O", &obj) ))
+ return NULL;
+ Vec2f *v = Vec2f_ptr_from_PyObject(obj);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 2D vector (either a list of 2 elements or Vector)");
+ return NULL;
+ }
+ float t = self->n->smoothNoise2(*v);
+ delete v;
+ return PyFloat_FromDouble( t );
+}
+
+static char FrsNoise_smoothNoise3___doc__[] =
+".. method:: smoothNoise3(v)\n"
+"\n"
+" Returns a smooth noise value for a 3D element.\n"
+"\n"
+" :arg v: Three-dimensional sample point.\n"
+" :type v: :class:`mathutils.Vector`, list or tuple of 3 real numbers\n"
+" :return: A smooth noise value.\n"
+" :rtype: float\n";
+
+static PyObject * FrsNoise_smoothNoise3( BPy_FrsNoise *self , PyObject *args) {
+ PyObject *obj;
+
+ if(!( PyArg_ParseTuple(args, "O", &obj) ))
+ return NULL;
+ Vec3f *v = Vec3f_ptr_from_PyObject(obj);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 3D vector (either a list of 3 elements or Vector)");
+ return NULL;
+ }
+ float t = self->n->smoothNoise3(*v);
+ delete v;
+ return PyFloat_FromDouble( t );
+}
+
+/*----------------------FrsNoise instance definitions ----------------------------*/
+static PyMethodDef BPy_FrsNoise_methods[] = {
+ {"turbulence1", ( PyCFunction ) FrsNoise_turbulence1, METH_VARARGS, FrsNoise_turbulence1___doc__},
+ {"turbulence2", ( PyCFunction ) FrsNoise_turbulence2, METH_VARARGS, FrsNoise_turbulence2___doc__},
+ {"turbulence3", ( PyCFunction ) FrsNoise_turbulence3, METH_VARARGS, FrsNoise_turbulence3___doc__},
+ {"smoothNoise1", ( PyCFunction ) FrsNoise_smoothNoise1, METH_VARARGS, FrsNoise_smoothNoise1___doc__},
+ {"smoothNoise2", ( PyCFunction ) FrsNoise_smoothNoise2, METH_VARARGS, FrsNoise_smoothNoise2___doc__},
+ {"smoothNoise3", ( PyCFunction ) FrsNoise_smoothNoise3, METH_VARARGS, FrsNoise_smoothNoise3___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_FrsNoise type definition ------------------------------*/
+
+PyTypeObject FrsNoise_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Noise", /* tp_name */
+ sizeof(BPy_FrsNoise), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)FrsNoise___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)FrsNoise___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ FrsNoise___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_FrsNoise_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)FrsNoise___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_FrsNoise.h b/source/blender/freestyle/intern/python/BPy_FrsNoise.h
new file mode 100644
index 00000000000..00b4f3375bc
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_FrsNoise.h
@@ -0,0 +1,36 @@
+#ifndef FREESTYLE_PYTHON_FRSNOISE_H
+#define FREESTYLE_PYTHON_FRSNOISE_H
+
+#include <Python.h>
+
+#include "../geometry/Noise.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject FrsNoise_Type;
+
+#define BPy_FrsNoise_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &FrsNoise_Type) )
+
+/*---------------------------Python BPy_FrsNoise structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ Noise *n;
+} BPy_FrsNoise;
+
+/*---------------------------Python BPy_FrsNoise visible prototypes-----------*/
+
+int FrsNoise_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_FRSNOISE_H */
diff --git a/source/blender/freestyle/intern/python/BPy_Id.cpp b/source/blender/freestyle/intern/python/BPy_Id.cpp
new file mode 100644
index 00000000000..8f8336f6c17
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Id.cpp
@@ -0,0 +1,222 @@
+#include "BPy_Id.h"
+
+#include "BPy_Convert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int Id_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &Id_Type ) < 0 )
+ return -1;
+
+ Py_INCREF( &Id_Type );
+ PyModule_AddObject(module, "Id", (PyObject *)&Id_Type);
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Id___doc__[] =
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: An Id object.\n"
+" :type iBrother: :class:`Id`\n"
+"\n"
+".. method:: __init__(iFirst)\n"
+"\n"
+" Builds an Id from an integer. The second number is set to 0.\n"
+"\n"
+" :arg iFirst: The first Id number.\n"
+" :type iFirst: int\n"
+"\n"
+".. method:: __init__(iFirst, iSecond)\n"
+"\n"
+" Builds the Id from the two numbers.\n"
+"\n"
+" :arg iFirst: The first Id number.\n"
+" :type iFirst: int\n"
+" :arg iSecond: The second Id number.\n"
+" :type iSecond: int\n";
+
+static int Id___init__(BPy_Id *self, PyObject *args, PyObject *kwds)
+{
+ int first = 0, second = 0;
+ static const char *kwlist[] = {"first", "second", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "|ii", (char**)kwlist, &first, &second) )
+ return -1;
+
+ self->id = new Id( first, second );
+
+ return 0;
+}
+
+static void Id___dealloc__(BPy_Id* self)
+{
+ delete self->id;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * Id___repr__(BPy_Id* self)
+{
+ return PyUnicode_FromFormat("[ first: %i, second: %i ](BPy_Id)", self->id->getFirst(), self->id->getSecond() );
+}
+
+static char Id_getFirst___doc__[] =
+".. method:: getFirst()\n"
+"\n"
+" Returns the first Id number.\n"
+"\n"
+" :return: The first Id number.\n"
+" :rtype: int\n";
+
+static PyObject *Id_getFirst( BPy_Id *self ) {
+ return PyLong_FromLong( self->id->getFirst() );
+}
+
+static char Id_getSecond___doc__[] =
+".. method:: getSecond()\n"
+"\n"
+" Returns the second Id number.\n"
+"\n"
+" :return: The second Id number.\n"
+" :rtype: int\n";
+
+static PyObject *Id_getSecond( BPy_Id *self) {
+ return PyLong_FromLong( self->id->getSecond() );
+}
+
+static char Id_setFirst___doc__[] =
+".. method:: setFirst(iFirst)\n"
+"\n"
+" Sets the first number constituting the Id.\n"
+"\n"
+" :arg iFirst: The first number constituting the Id.\n"
+" :type iFirst: int\n";
+
+static PyObject *Id_setFirst( BPy_Id *self , PyObject *args) {
+ unsigned int i;
+
+ if( !PyArg_ParseTuple(args, "i", &i) )
+ return NULL;
+
+ self->id->setFirst( i );
+
+ Py_RETURN_NONE;
+}
+
+static char Id_setSecond___doc__[] =
+".. method:: setSecond(iSecond)\n"
+"\n"
+" Sets the second number constituting the Id.\n"
+"\n"
+" :arg iSecond: The second number constituting the Id.\n"
+" :type iSecond: int\n";
+
+static PyObject *Id_setSecond( BPy_Id *self , PyObject *args) {
+ unsigned int i;
+
+ if( !PyArg_ParseTuple(args, "i", &i) )
+ return NULL;
+
+ self->id->setSecond( i );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject * Id_RichCompare(BPy_Id *o1, BPy_Id *o2, int opid) {
+ switch(opid){
+ case Py_LT:
+ return PyBool_from_bool( o1->id->operator<(*(o2->id)) );
+ break;
+ case Py_LE:
+ return PyBool_from_bool( o1->id->operator<(*(o2->id)) || o1->id->operator<(*(o2->id)) );
+ break;
+ case Py_EQ:
+ return PyBool_from_bool( o1->id->operator==(*(o2->id)) );
+ break;
+ case Py_NE:
+ return PyBool_from_bool( o1->id->operator!=(*(o2->id)) );
+ break;
+ case Py_GT:
+ return PyBool_from_bool(!( o1->id->operator<(*(o2->id)) || o1->id->operator<(*(o2->id)) ));
+ break;
+ case Py_GE:
+ return PyBool_from_bool(!( o1->id->operator<(*(o2->id)) ));
+ break;
+ }
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------Id instance definitions ----------------------------*/
+static PyMethodDef BPy_Id_methods[] = {
+ {"getFirst", ( PyCFunction ) Id_getFirst, METH_NOARGS, Id_getFirst___doc__},
+ {"getSecond", ( PyCFunction ) Id_getSecond, METH_NOARGS, Id_getSecond___doc__},
+ {"setFirst", ( PyCFunction ) Id_setFirst, METH_VARARGS, Id_setFirst___doc__},
+ {"setSecond", ( PyCFunction ) Id_setSecond, METH_VARARGS, Id_setSecond___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_Id type definition ------------------------------*/
+
+PyTypeObject Id_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Id", /* tp_name */
+ sizeof(BPy_Id), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Id___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)Id___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Id___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ (richcmpfunc)Id_RichCompare, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_Id_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Id___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_Id.h b/source/blender/freestyle/intern/python/BPy_Id.h
new file mode 100644
index 00000000000..10f370f8a80
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Id.h
@@ -0,0 +1,36 @@
+#ifndef FREESTYLE_PYTHON_ID_H
+#define FREESTYLE_PYTHON_ID_H
+
+#include <Python.h>
+#include <iostream>
+using namespace std;
+
+#include "../system/Id.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject Id_Type;
+
+#define BPy_Id_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Id_Type) )
+
+/*---------------------------Python BPy_Id structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ Id *id;
+} BPy_Id;
+
+/*---------------------------Python BPy_Id visible prototypes-----------*/
+
+int Id_Init( PyObject *module );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_ID_H */
diff --git a/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp b/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp
new file mode 100644
index 00000000000..9ce20632a25
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_IntegrationType.cpp
@@ -0,0 +1,250 @@
+#include "BPy_IntegrationType.h"
+
+#include "BPy_Convert.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DDouble.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DFloat.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DUnsigned.h"
+#include "Iterator/BPy_Interface0DIterator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------ MODULE FUNCTIONS ----------------------------------
+
+static char Integrator_integrate___doc__[] =
+".. function:: integrate(fun, it, it_end, integration_type)\n"
+"\n"
+" Returns a single value from a set of values evaluated at each 0D\n"
+" element of this 1D element.\n"
+"\n"
+" :arg fun: The UnaryFunction0D used to compute a value at each\n"
+" Interface0D.\n"
+" :type fun: :class:`UnaryFunction0D`\n"
+" :arg it: The Interface0DIterator used to iterate over the 0D\n"
+" elements of this 1D element. The integration will occur over\n"
+" the 0D elements starting from the one pointed by it.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :arg it_end: The Interface0DIterator pointing the end of the 0D\n"
+" elements of the 1D element.\n"
+" :type it_end: :class:`Interface0DIterator`\n"
+" :arg integration_type: The integration method used to compute a\n"
+" single value from a set of values.\n"
+" :type integration_type: :class:`IntegrationType`\n"
+" :return: The single value obtained for the 1D element. The return\n"
+" value type is float if fun is of the :class:`UnaryFunction0DDouble`\n"
+" or :class:`UnaryFunction0DFloat` type, and int if fun is of the\n"
+" :class:`UnaryFunction0DUnsigned` type.\n"
+" :rtype: int or float\n";
+
+static PyObject * Integrator_integrate( PyObject *self, PyObject *args )
+{
+ PyObject *obj1, *obj4 = 0;
+ BPy_Interface0DIterator *obj2, *obj3;
+
+#if 1
+ if(!( PyArg_ParseTuple(args, "O!O!O!|O!", &UnaryFunction0D_Type, &obj1,
+ &Interface0DIterator_Type, &obj2, &Interface0DIterator_Type, &obj3,
+ &IntegrationType_Type, &obj4) ))
+ return NULL;
+#else
+ if(!( PyArg_ParseTuple(args, "OOO|O", &obj1, &obj2, &obj3, &obj4) ))
+ return NULL;
+ if(!BPy_UnaryFunction0D_Check(obj1)) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a UnaryFunction0D object");
+ return NULL;
+ }
+ if(!BPy_Interface0DIterator_Check(obj2)) {
+ PyErr_SetString(PyExc_TypeError, "argument 2 must be a Interface0DIterator object");
+ return NULL;
+ }
+ if(!BPy_Interface0DIterator_Check(obj3)) {
+ PyErr_SetString(PyExc_TypeError, "argument 3 must be a Interface0DIterator object");
+ return NULL;
+ }
+ if(obj4 && !BPy_IntegrationType_Check(obj4)) {
+ PyErr_SetString(PyExc_TypeError, "argument 4 must be a IntegrationType object");
+ return NULL;
+ }
+#endif
+
+ Interface0DIterator it(*(obj2->if0D_it)), it_end(*(obj3->if0D_it));
+ IntegrationType t = ( obj4 ) ? IntegrationType_from_BPy_IntegrationType( obj4 ) : MEAN;
+
+ if( BPy_UnaryFunction0DDouble_Check(obj1) ) {
+ UnaryFunction0D<double> *fun = ((BPy_UnaryFunction0DDouble *)obj1)->uf0D_double;
+ double res = integrate( *fun, it, it_end, t );
+ return PyFloat_FromDouble( res );
+
+ } else if( BPy_UnaryFunction0DFloat_Check(obj1) ) {
+ UnaryFunction0D<float> *fun = ((BPy_UnaryFunction0DFloat *)obj1)->uf0D_float;
+ float res = integrate( *fun, it, it_end, t );
+ return PyFloat_FromDouble( res );
+
+ } else if( BPy_UnaryFunction0DUnsigned_Check(obj1) ) {
+ UnaryFunction0D<unsigned int> *fun = ((BPy_UnaryFunction0DUnsigned *)obj1)->uf0D_unsigned;
+ unsigned int res = integrate( *fun, it, it_end, t );
+ return PyLong_FromLong( res );
+
+ } else {
+ string msg("unsupported function type: " + string(obj1->ob_type->tp_name));
+ PyErr_SetString(PyExc_TypeError, msg.c_str());
+ return NULL;
+ }
+}
+
+/*-----------------------Integrator module docstring---------------------------------------*/
+
+static char module_docstring[] = "The Blender Freestyle.Integrator submodule\n\n";
+
+/*-----------------------Integrator module functions definitions---------------------------*/
+
+static PyMethodDef module_functions[] = {
+ {"integrate", (PyCFunction) Integrator_integrate, METH_VARARGS, Integrator_integrate___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------Integrator module definition--------------------------------------*/
+
+static PyModuleDef module_definition = {
+ PyModuleDef_HEAD_INIT,
+ "Freestyle.Integrator",
+ module_docstring,
+ -1,
+ module_functions
+};
+
+/*-----------------------BPy_IntegrationType type definition ------------------------------*/
+
+static char IntegrationType___doc__[] =
+"Class hierarchy: int > :class:`IntegrationType`\n"
+"\n"
+"Different integration methods that can be invoked to integrate into a\n"
+"single value the set of values obtained from each 0D element of an 1D\n"
+"element:\n"
+"\n"
+"* IntegrationType.MEAN: The value computed for the 1D element is the\n"
+" mean of the values obtained for the 0D elements.\n"
+"* IntegrationType.MIN: The value computed for the 1D element is the\n"
+" minimum of the values obtained for the 0D elements.\n"
+"* IntegrationType.MAX: The value computed for the 1D element is the\n"
+" maximum of the values obtained for the 0D elements.\n"
+"* IntegrationType.FIRST: The value computed for the 1D element is the\n"
+" first of the values obtained for the 0D elements.\n"
+"* IntegrationType.LAST: The value computed for the 1D element is the\n"
+" last of the values obtained for the 0D elements.\n";
+
+PyTypeObject IntegrationType_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "IntegrationType", /* tp_name */
+ sizeof(PyLongObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ IntegrationType___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PyLong_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+/*-----------------------BPy_IntegrationType instance definitions -------------------------*/
+
+static PyLongObject _IntegrationType_MEAN = {
+ PyVarObject_HEAD_INIT(&IntegrationType_Type, 1)
+ { MEAN }
+};
+static PyLongObject _IntegrationType_MIN = {
+ PyVarObject_HEAD_INIT(&IntegrationType_Type, 1)
+ { MIN }
+};
+static PyLongObject _IntegrationType_MAX = {
+ PyVarObject_HEAD_INIT(&IntegrationType_Type, 1)
+ { MAX }
+};
+static PyLongObject _IntegrationType_FIRST = {
+ PyVarObject_HEAD_INIT(&IntegrationType_Type, 1)
+ { FIRST }
+};
+static PyLongObject _IntegrationType_LAST = {
+ PyVarObject_HEAD_INIT(&IntegrationType_Type, 1)
+ { LAST }
+};
+
+#define BPy_IntegrationType_MEAN ((PyObject *)&_IntegrationType_MEAN)
+#define BPy_IntegrationType_MIN ((PyObject *)&_IntegrationType_MIN)
+#define BPy_IntegrationType_MAX ((PyObject *)&_IntegrationType_MAX)
+#define BPy_IntegrationType_FIRST ((PyObject *)&_IntegrationType_FIRST)
+#define BPy_IntegrationType_LAST ((PyObject *)&_IntegrationType_LAST)
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int IntegrationType_Init( PyObject *module )
+{
+ PyObject *m, *d, *f;
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &IntegrationType_Type ) < 0 )
+ return -1;
+ Py_INCREF( &IntegrationType_Type );
+ PyModule_AddObject(module, "IntegrationType", (PyObject *)&IntegrationType_Type);
+
+ PyDict_SetItemString( IntegrationType_Type.tp_dict, "MEAN", BPy_IntegrationType_MEAN);
+ PyDict_SetItemString( IntegrationType_Type.tp_dict, "MIN", BPy_IntegrationType_MIN);
+ PyDict_SetItemString( IntegrationType_Type.tp_dict, "MAX", BPy_IntegrationType_MAX);
+ PyDict_SetItemString( IntegrationType_Type.tp_dict, "FIRST", BPy_IntegrationType_FIRST);
+ PyDict_SetItemString( IntegrationType_Type.tp_dict, "LAST", BPy_IntegrationType_LAST);
+
+ m = PyModule_Create(&module_definition);
+ if (m == NULL)
+ return -1;
+ Py_INCREF(m);
+ PyModule_AddObject(module, "Integrator", m);
+
+ // from Integrator import *
+ d = PyModule_GetDict(m);
+ for (PyMethodDef *p = module_functions; p->ml_name; p++) {
+ f = PyDict_GetItemString(d, p->ml_name);
+ Py_INCREF(f);
+ PyModule_AddObject(module, p->ml_name, f);
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/source/blender/freestyle/intern/python/BPy_IntegrationType.h b/source/blender/freestyle/intern/python/BPy_IntegrationType.h
new file mode 100644
index 00000000000..f15ae8309e3
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_IntegrationType.h
@@ -0,0 +1,28 @@
+#ifndef FREESTYLE_PYTHON_INTEGRATIONTYPE_H
+#define FREESTYLE_PYTHON_INTEGRATIONTYPE_H
+
+#include <Python.h>
+
+#include "../view_map/Interface1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject IntegrationType_Type;
+
+#define BPy_IntegrationType_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &IntegrationType_Type) )
+
+/*---------------------------Python BPy_IntegrationType visible prototypes-----------*/
+
+int IntegrationType_Init( PyObject *module );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_INTEGRATIONTYPE_H */
diff --git a/source/blender/freestyle/intern/python/BPy_Interface0D.cpp b/source/blender/freestyle/intern/python/BPy_Interface0D.cpp
new file mode 100644
index 00000000000..11af30439cf
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Interface0D.cpp
@@ -0,0 +1,354 @@
+#include "BPy_Interface0D.h"
+
+#include "BPy_Convert.h"
+#include "Interface0D/BPy_CurvePoint.h"
+#include "Interface0D/CurvePoint/BPy_StrokeVertex.h"
+#include "Interface0D/BPy_SVertex.h"
+#include "Interface0D/BPy_ViewVertex.h"
+#include "Interface0D/ViewVertex/BPy_NonTVertex.h"
+#include "Interface0D/ViewVertex/BPy_TVertex.h"
+#include "Interface1D/BPy_FEdge.h"
+#include "BPy_Nature.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int Interface0D_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &Interface0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Interface0D_Type );
+ PyModule_AddObject(module, "Interface0D", (PyObject *)&Interface0D_Type);
+
+ if( PyType_Ready( &CurvePoint_Type ) < 0 )
+ return -1;
+ Py_INCREF( &CurvePoint_Type );
+ PyModule_AddObject(module, "CurvePoint", (PyObject *)&CurvePoint_Type);
+
+ if( PyType_Ready( &SVertex_Type ) < 0 )
+ return -1;
+ Py_INCREF( &SVertex_Type );
+ PyModule_AddObject(module, "SVertex", (PyObject *)&SVertex_Type);
+
+ if( PyType_Ready( &ViewVertex_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ViewVertex_Type );
+ PyModule_AddObject(module, "ViewVertex", (PyObject *)&ViewVertex_Type);
+
+ if( PyType_Ready( &StrokeVertex_Type ) < 0 )
+ return -1;
+ Py_INCREF( &StrokeVertex_Type );
+ PyModule_AddObject(module, "StrokeVertex", (PyObject *)&StrokeVertex_Type);
+
+ if( PyType_Ready( &NonTVertex_Type ) < 0 )
+ return -1;
+ Py_INCREF( &NonTVertex_Type );
+ PyModule_AddObject(module, "NonTVertex", (PyObject *)&NonTVertex_Type);
+
+ if( PyType_Ready( &TVertex_Type ) < 0 )
+ return -1;
+ Py_INCREF( &TVertex_Type );
+ PyModule_AddObject(module, "TVertex", (PyObject *)&TVertex_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Interface0D___doc__[] =
+"Base class for any 0D element.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n";
+
+static int Interface0D___init__(BPy_Interface0D *self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->if0D = new Interface0D();
+ self->borrowed = 0;
+ return 0;
+}
+
+static void Interface0D___dealloc__(BPy_Interface0D* self)
+{
+ if( self->if0D && !self->borrowed )
+ delete self->if0D;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * Interface0D___repr__(BPy_Interface0D* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->if0D->getExactTypeName().c_str(), self->if0D );
+}
+
+static char Interface0D_getExactTypeName___doc__[] =
+".. method:: getExactTypeName()\n"
+"\n"
+" Returns the name of the 0D element.\n"
+"\n"
+" :return: Name of the interface.\n"
+" :rtype: str\n";
+
+static PyObject *Interface0D_getExactTypeName( BPy_Interface0D *self ) {
+ return PyUnicode_FromString( self->if0D->getExactTypeName().c_str() );
+}
+
+static char Interface0D_getX___doc__[] =
+".. method:: getX()\n"
+"\n"
+" Returns the X coordinate of the 3D point of the 0D element.\n"
+"\n"
+" :return: The X coordinate of the 3D point.\n"
+" :rtype: float\n";
+
+static PyObject *Interface0D_getX( BPy_Interface0D *self ) {
+ double x = self->if0D->getX();
+ if (PyErr_Occurred())
+ return NULL;
+ return PyFloat_FromDouble( x );
+}
+
+static char Interface0D_getY___doc__[] =
+".. method:: getY()\n"
+"\n"
+" Returns the Y coordinate of the 3D point of the 0D element.\n"
+"\n"
+" :return: The Y coordinate of the 3D point.\n"
+" :rtype: float\n";
+
+static PyObject *Interface0D_getY( BPy_Interface0D *self ) {
+ double y = self->if0D->getY();
+ if (PyErr_Occurred())
+ return NULL;
+ return PyFloat_FromDouble( y );
+}
+
+static char Interface0D_getZ___doc__[] =
+".. method:: getZ()\n"
+"\n"
+" Returns the Z coordinate of the 3D point of the 0D element.\n"
+"\n"
+" :return: The Z coordinate of the 3D point.\n"
+" :rtype: float\n";
+
+static PyObject *Interface0D_getZ( BPy_Interface0D *self ) {
+ double z = self->if0D->getZ();
+ if (PyErr_Occurred())
+ return NULL;
+ return PyFloat_FromDouble( z );
+}
+
+static char Interface0D_getPoint3D___doc__[] =
+".. method:: getPoint3D()\n"
+"\n"
+" Returns the location of the 0D element in the 3D space.\n"
+"\n"
+" :return: The 3D point of the 0D element.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static PyObject *Interface0D_getPoint3D( BPy_Interface0D *self ) {
+ Vec3f v( self->if0D->getPoint3D() );
+ if (PyErr_Occurred())
+ return NULL;
+ return Vector_from_Vec3f( v );
+}
+
+static char Interface0D_getProjectedX___doc__[] =
+".. method:: getProjectedX()\n"
+"\n"
+" Returns the X coordinate of the 2D point of the 0D element.\n"
+"\n"
+" :return: The X coordinate of the 2D point.\n"
+" :rtype: float\n";
+
+static PyObject *Interface0D_getProjectedX( BPy_Interface0D *self ) {
+ double x = self->if0D->getProjectedX();
+ if (PyErr_Occurred())
+ return NULL;
+ return PyFloat_FromDouble( x );
+}
+
+static char Interface0D_getProjectedY___doc__[] =
+".. method:: getProjectedY()\n"
+"\n"
+" Returns the Y coordinate of the 2D point of the 0D element.\n"
+"\n"
+" :return: The Y coordinate of the 2D point.\n"
+" :rtype: float\n";
+
+static PyObject *Interface0D_getProjectedY( BPy_Interface0D *self ) {
+ double y = self->if0D->getProjectedY();
+ if (PyErr_Occurred())
+ return NULL;
+ return PyFloat_FromDouble( y );
+}
+
+static char Interface0D_getProjectedZ___doc__[] =
+".. method:: getProjectedZ()\n"
+"\n"
+" Returns the Z coordinate of the 2D point of the 0D element.\n"
+"\n"
+" :return: The Z coordinate of the 2D point.\n"
+" :rtype: float\n";
+
+static PyObject *Interface0D_getProjectedZ( BPy_Interface0D *self ) {
+ double z = self->if0D->getProjectedZ();
+ if (PyErr_Occurred())
+ return NULL;
+ return PyFloat_FromDouble( z );
+}
+
+static char Interface0D_getPoint2D___doc__[] =
+".. method:: getPoint2D()\n"
+"\n"
+" Returns the location of the 0D element in the 2D space.\n"
+"\n"
+" :return: The 2D point of the 0D element.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static PyObject *Interface0D_getPoint2D( BPy_Interface0D *self ) {
+ Vec2f v( self->if0D->getPoint2D() );
+ if (PyErr_Occurred())
+ return NULL;
+ return Vector_from_Vec2f( v );
+}
+
+static char Interface0D_getFEdge___doc__[] =
+".. method:: getFEdge(inter)\n"
+"\n"
+" Returns the FEdge that lies between this 0D element and the 0D\n"
+" element given as the argument.\n"
+"\n"
+" :arg inter: A 0D element.\n"
+" :type inter: :class:`Interface0D`\n"
+" :return: The FEdge lying between the two 0D elements.\n"
+" :rtype: :class:`FEdge`\n";
+
+static PyObject *Interface0D_getFEdge( BPy_Interface0D *self, PyObject *args ) {
+ PyObject *py_if0D;
+
+ if(!( PyArg_ParseTuple(args, "O!", &Interface0D_Type, &py_if0D) ))
+ return NULL;
+
+ FEdge *fe = self->if0D->getFEdge(*( ((BPy_Interface0D *) py_if0D)->if0D ));
+ if (PyErr_Occurred())
+ return NULL;
+ if( fe )
+ return Any_BPy_FEdge_from_FEdge( *fe );
+
+ Py_RETURN_NONE;
+}
+
+static char Interface0D_getId___doc__[] =
+".. method:: getId()\n"
+"\n"
+" Returns the identifier of the 0D element.\n"
+"\n"
+" :return: The identifier of the 0D element.\n"
+" :rtype: :class:`Id`\n";
+
+static PyObject *Interface0D_getId( BPy_Interface0D *self ) {
+ Id id( self->if0D->getId() );
+ if (PyErr_Occurred())
+ return NULL;
+ return BPy_Id_from_Id( id );
+}
+
+static char Interface0D_getNature___doc__[] =
+".. method:: getNature()\n"
+"\n"
+" Returns the nature of the 0D element.\n"
+"\n"
+" :return: The nature of the 0D element.\n"
+" :rtype: :class:`Nature`\n";
+
+static PyObject *Interface0D_getNature( BPy_Interface0D *self ) {
+ Nature::VertexNature nature = self->if0D->getNature();
+ if (PyErr_Occurred())
+ return NULL;
+ return BPy_Nature_from_Nature( nature );
+}
+
+/*----------------------Interface0D instance definitions ----------------------------*/
+static PyMethodDef BPy_Interface0D_methods[] = {
+ {"getExactTypeName", ( PyCFunction ) Interface0D_getExactTypeName, METH_NOARGS, Interface0D_getExactTypeName___doc__},
+ {"getX", ( PyCFunction ) Interface0D_getX, METH_NOARGS, Interface0D_getX___doc__},
+ {"getY", ( PyCFunction ) Interface0D_getY, METH_NOARGS, Interface0D_getY___doc__},
+ {"getZ", ( PyCFunction ) Interface0D_getZ, METH_NOARGS, Interface0D_getZ___doc__},
+ {"getPoint3D", ( PyCFunction ) Interface0D_getPoint3D, METH_NOARGS, Interface0D_getPoint3D___doc__},
+ {"getProjectedX", ( PyCFunction ) Interface0D_getProjectedX, METH_NOARGS, Interface0D_getProjectedX___doc__},
+ {"getProjectedY", ( PyCFunction ) Interface0D_getProjectedY, METH_NOARGS, Interface0D_getProjectedY___doc__},
+ {"getProjectedZ", ( PyCFunction ) Interface0D_getProjectedZ, METH_NOARGS, Interface0D_getProjectedZ___doc__},
+ {"getPoint2D", ( PyCFunction ) Interface0D_getPoint2D, METH_NOARGS, Interface0D_getPoint2D___doc__},
+ {"getFEdge", ( PyCFunction ) Interface0D_getFEdge, METH_VARARGS, Interface0D_getFEdge___doc__},
+ {"getId", ( PyCFunction ) Interface0D_getId, METH_NOARGS, Interface0D_getId___doc__},
+ {"getNature", ( PyCFunction ) Interface0D_getNature, METH_NOARGS, Interface0D_getNature___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_Interface0D type definition ------------------------------*/
+
+PyTypeObject Interface0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Interface0D", /* tp_name */
+ sizeof(BPy_Interface0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Interface0D___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)Interface0D___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Interface0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_Interface0D_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Interface0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+ 0, /* tp_free */
+ 0, /* tp_is_gc */
+ 0, /* tp_bases */
+ 0, /* tp_mro */
+ 0, /* tp_cache */
+ 0, /* tp_subclasses */
+ 0, /* tp_weaklist */
+ 0 /* tp_del */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/source/blender/freestyle/intern/python/BPy_Interface0D.h b/source/blender/freestyle/intern/python/BPy_Interface0D.h
new file mode 100644
index 00000000000..25134db5352
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Interface0D.h
@@ -0,0 +1,35 @@
+#ifndef FREESTYLE_PYTHON_INTERFACE0D_H
+#define FREESTYLE_PYTHON_INTERFACE0D_H
+
+#include <Python.h>
+
+#include "../view_map/Interface0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject Interface0D_Type;
+
+#define BPy_Interface0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Interface0D_Type) )
+
+/*---------------------------Python BPy_Interface0D structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ Interface0D *if0D;
+ int borrowed; /* non-zero if *if0D is a borrowed object */
+} BPy_Interface0D;
+
+/*---------------------------Python BPy_Interface0D visible prototypes-----------*/
+
+int Interface0D_Init( PyObject *module );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_INTERFACE0D_H */
diff --git a/source/blender/freestyle/intern/python/BPy_Interface1D.cpp b/source/blender/freestyle/intern/python/BPy_Interface1D.cpp
new file mode 100644
index 00000000000..7b4bdddf70c
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Interface1D.cpp
@@ -0,0 +1,337 @@
+#include "BPy_Interface1D.h"
+
+#include "BPy_Convert.h"
+#include "Interface1D/BPy_FrsCurve.h"
+#include "Interface1D/Curve/BPy_Chain.h"
+#include "Interface1D/BPy_FEdge.h"
+#include "Interface1D/FEdge/BPy_FEdgeSharp.h"
+#include "Interface1D/FEdge/BPy_FEdgeSmooth.h"
+#include "Interface1D/BPy_Stroke.h"
+#include "Interface1D/BPy_ViewEdge.h"
+
+#include "BPy_MediumType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int Interface1D_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &Interface1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Interface1D_Type );
+ PyModule_AddObject(module, "Interface1D", (PyObject *)&Interface1D_Type);
+
+ if( PyType_Ready( &FrsCurve_Type ) < 0 )
+ return -1;
+ Py_INCREF( &FrsCurve_Type );
+ PyModule_AddObject(module, "Curve", (PyObject *)&FrsCurve_Type);
+
+ if( PyType_Ready( &Chain_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Chain_Type );
+ PyModule_AddObject(module, "Chain", (PyObject *)&Chain_Type);
+
+ if( PyType_Ready( &FEdge_Type ) < 0 )
+ return -1;
+ Py_INCREF( &FEdge_Type );
+ PyModule_AddObject(module, "FEdge", (PyObject *)&FEdge_Type);
+
+ if( PyType_Ready( &FEdgeSharp_Type ) < 0 )
+ return -1;
+ Py_INCREF( &FEdgeSharp_Type );
+ PyModule_AddObject(module, "FEdgeSharp", (PyObject *)&FEdgeSharp_Type);
+
+ if( PyType_Ready( &FEdgeSmooth_Type ) < 0 )
+ return -1;
+ Py_INCREF( &FEdgeSmooth_Type );
+ PyModule_AddObject(module, "FEdgeSmooth", (PyObject *)&FEdgeSmooth_Type);
+
+ if( PyType_Ready( &Stroke_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Stroke_Type );
+ PyModule_AddObject(module, "Stroke", (PyObject *)&Stroke_Type);
+
+ PyDict_SetItemString( Stroke_Type.tp_dict, "DRY_MEDIUM", BPy_MediumType_DRY_MEDIUM );
+ PyDict_SetItemString( Stroke_Type.tp_dict, "HUMID_MEDIUM", BPy_MediumType_HUMID_MEDIUM );
+ PyDict_SetItemString( Stroke_Type.tp_dict, "OPAQUE_MEDIUM", BPy_MediumType_OPAQUE_MEDIUM );
+
+ if( PyType_Ready( &ViewEdge_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ViewEdge_Type );
+ PyModule_AddObject(module, "ViewEdge", (PyObject *)&ViewEdge_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Interface1D___doc__[] =
+"Base class for any 1D element.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n";
+
+static int Interface1D___init__(BPy_Interface1D *self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->if1D = new Interface1D();
+ self->borrowed = 0;
+ return 0;
+}
+
+static void Interface1D___dealloc__(BPy_Interface1D* self)
+{
+ if( self->if1D && !self->borrowed )
+ delete self->if1D;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * Interface1D___repr__(BPy_Interface1D* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->if1D->getExactTypeName().c_str(), self->if1D );
+}
+
+static char Interface1D_getExactTypeName___doc__[] =
+".. method:: getExactTypeName()\n"
+"\n"
+" Returns the string of the name of the 1D element.\n"
+"\n"
+" :return: The name of the 1D element.\n"
+" :rtype: str\n";
+
+static PyObject *Interface1D_getExactTypeName( BPy_Interface1D *self ) {
+ return PyUnicode_FromString( self->if1D->getExactTypeName().c_str() );
+}
+
+#if 0
+static PyObject *Interface1D_getVertices( BPy_Interface1D *self ) {
+ return PyList_New(0);
+}
+
+static PyObject *Interface1D_getPoints( BPy_Interface1D *self ) {
+ return PyList_New(0);
+}
+#endif
+
+static char Interface1D_getLength2D___doc__[] =
+".. method:: getLength2D()\n"
+"\n"
+" Returns the 2D length of the 1D element.\n"
+"\n"
+" :return: The 2D length of the 1D element.\n"
+" :rtype: float\n";
+
+static PyObject *Interface1D_getLength2D( BPy_Interface1D *self ) {
+ return PyFloat_FromDouble( (double) self->if1D->getLength2D() );
+}
+
+static char Interface1D_getId___doc__[] =
+".. method:: getId()\n"
+"\n"
+" Returns the Id of the 1D element .\n"
+"\n"
+" :return: The Id of the 1D element .\n"
+" :rtype: :class:`Id`\n";
+
+static PyObject *Interface1D_getId( BPy_Interface1D *self ) {
+ Id id( self->if1D->getId() );
+ return BPy_Id_from_Id( id );
+}
+
+static char Interface1D_getNature___doc__[] =
+".. method:: getNature()\n"
+"\n"
+" Returns the nature of the 1D element.\n"
+"\n"
+" :return: The nature of the 1D element.\n"
+" :rtype: :class:`Nature`\n";
+
+static PyObject *Interface1D_getNature( BPy_Interface1D *self ) {
+ return BPy_Nature_from_Nature( self->if1D->getNature() );
+}
+
+static char Interface1D_getTimeStamp___doc__[] =
+".. method:: getTimeStamp()\n"
+"\n"
+" Returns the time stamp of the 1D element. Mainly used for selection.\n"
+"\n"
+" :return: The time stamp of the 1D element.\n"
+" :rtype: int\n";
+
+static PyObject *Interface1D_getTimeStamp( BPy_Interface1D *self ) {
+ return PyLong_FromLong( self->if1D->getTimeStamp() );
+}
+
+static char Interface1D_setTimeStamp___doc__[] =
+".. method:: setTimeStamp(iTimeStamp)\n"
+"\n"
+" Sets the time stamp for the 1D element.\n"
+"\n"
+" :arg iTimeStamp: A time stamp.\n"
+" :type iTimeStamp: int\n";
+
+static PyObject *Interface1D_setTimeStamp( BPy_Interface1D *self, PyObject *args) {
+ int timestamp = 0 ;
+
+ if( !PyArg_ParseTuple(args, "i", &timestamp) )
+ return NULL;
+
+ self->if1D->setTimeStamp( timestamp );
+
+ Py_RETURN_NONE;
+}
+
+static char Interface1D_verticesBegin___doc__[] =
+".. method:: verticesBegin()\n"
+"\n"
+" Returns an iterator over the Interface1D vertices, pointing to the\n"
+" first vertex.\n"
+"\n"
+" :return: An Interface0DIterator pointing to the first vertex.\n"
+" :rtype: :class:`Interface0DIterator`\n";
+
+static PyObject * Interface1D_verticesBegin( BPy_Interface1D *self ) {
+ Interface0DIterator if0D_it( self->if1D->verticesBegin() );
+ return BPy_Interface0DIterator_from_Interface0DIterator( if0D_it, 0 );
+}
+
+static char Interface1D_verticesEnd___doc__[] =
+".. method:: verticesEnd()\n"
+"\n"
+" Returns an iterator over the Interface1D vertices, pointing after\n"
+" the last vertex.\n"
+"\n"
+" :return: An Interface0DIterator pointing after the last vertex.\n"
+" :rtype: :class:`Interface0DIterator`\n";
+
+static PyObject * Interface1D_verticesEnd( BPy_Interface1D *self ) {
+ Interface0DIterator if0D_it( self->if1D->verticesEnd() );
+ return BPy_Interface0DIterator_from_Interface0DIterator( if0D_it, 1 );
+}
+
+static char Interface1D_pointsBegin___doc__[] =
+".. method:: pointsBegin(t=0.0)\n"
+"\n"
+" Returns an iterator over the Interface1D points, pointing to the\n"
+" first point. The difference with verticesBegin() is that here we can\n"
+" iterate over points of the 1D element at a any given sampling.\n"
+" Indeed, for each iteration, a virtual point is created.\n"
+"\n"
+" :arg t: A sampling with which we want to iterate over points of\n"
+" this 1D element.\n"
+" :type t: float\n"
+" :return: An Interface0DIterator pointing to the first point.\n"
+" :rtype: :class:`Interface0DIterator`\n";
+
+static PyObject * Interface1D_pointsBegin( BPy_Interface1D *self, PyObject *args ) {
+ float f = 0;
+
+ if(!( PyArg_ParseTuple(args, "|f", &f) ))
+ return NULL;
+
+ Interface0DIterator if0D_it( self->if1D->pointsBegin(f) );
+ return BPy_Interface0DIterator_from_Interface0DIterator( if0D_it, 0 );
+}
+
+static char Interface1D_pointsEnd___doc__[] =
+".. method:: pointsEnd(t=0.0)\n"
+"\n"
+" Returns an iterator over the Interface1D points, pointing after the\n"
+" last point. The difference with verticesEnd() is that here we can\n"
+" iterate over points of the 1D element at a given sampling. Indeed,\n"
+" for each iteration, a virtual point is created.\n"
+"\n"
+" :arg t: A sampling with which we want to iterate over points of\n"
+" this 1D element.\n"
+" :type t: float\n"
+" :return: An Interface0DIterator pointing after the last point.\n"
+" :rtype: :class:`Interface0DIterator`\n";
+
+static PyObject * Interface1D_pointsEnd( BPy_Interface1D *self, PyObject *args ) {
+ float f = 0;
+
+ if(!( PyArg_ParseTuple(args, "|f", &f) ))
+ return NULL;
+
+ Interface0DIterator if0D_it( self->if1D->pointsEnd(f) );
+ return BPy_Interface0DIterator_from_Interface0DIterator( if0D_it, 1 );
+}
+
+/*----------------------Interface1D instance definitions ----------------------------*/
+static PyMethodDef BPy_Interface1D_methods[] = {
+ {"getExactTypeName", ( PyCFunction ) Interface1D_getExactTypeName, METH_NOARGS, Interface1D_getExactTypeName___doc__},
+#if 0
+ {"getVertices", ( PyCFunction ) Interface1D_getVertices, METH_NOARGS, "Returns the vertices"},
+ {"getPoints", ( PyCFunction ) Interface1D_getPoints, METH_NOARGS, "Returns the points. The difference with getVertices() is that here we can iterate over points of the 1D element at any given sampling. At each call, a virtual point is created."},
+#endif
+ {"getLength2D", ( PyCFunction ) Interface1D_getLength2D, METH_NOARGS, Interface1D_getLength2D___doc__},
+ {"getId", ( PyCFunction ) Interface1D_getId, METH_NOARGS, Interface1D_getId___doc__},
+ {"getNature", ( PyCFunction ) Interface1D_getNature, METH_NOARGS, Interface1D_getNature___doc__},
+ {"getTimeStamp", ( PyCFunction ) Interface1D_getTimeStamp, METH_NOARGS, Interface1D_getTimeStamp___doc__},
+ {"setTimeStamp", ( PyCFunction ) Interface1D_setTimeStamp, METH_VARARGS, Interface1D_setTimeStamp___doc__},
+ {"verticesBegin", ( PyCFunction ) Interface1D_verticesBegin, METH_NOARGS, Interface1D_verticesBegin___doc__},
+ {"verticesEnd", ( PyCFunction ) Interface1D_verticesEnd, METH_NOARGS, Interface1D_verticesEnd___doc__},
+ {"pointsBegin", ( PyCFunction ) Interface1D_pointsBegin, METH_VARARGS, Interface1D_pointsBegin___doc__},
+ {"pointsEnd", ( PyCFunction ) Interface1D_pointsEnd, METH_VARARGS, Interface1D_pointsEnd___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_Interface1D type definition ------------------------------*/
+
+PyTypeObject Interface1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Interface1D", /* tp_name */
+ sizeof(BPy_Interface1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Interface1D___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)Interface1D___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Interface1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_Interface1D_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Interface1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/source/blender/freestyle/intern/python/BPy_Interface1D.h b/source/blender/freestyle/intern/python/BPy_Interface1D.h
new file mode 100644
index 00000000000..75eefa1836f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Interface1D.h
@@ -0,0 +1,36 @@
+#ifndef FREESTYLE_PYTHON_INTERFACE1D_H
+#define FREESTYLE_PYTHON_INTERFACE1D_H
+
+#include <Python.h>
+
+#include "../view_map/Interface1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject Interface1D_Type;
+
+#define BPy_Interface1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Interface1D_Type) )
+
+/*---------------------------Python BPy_Interface1D structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ Interface1D *if1D;
+ int borrowed; /* non-zero if *if1D is a borrowed object */
+} BPy_Interface1D;
+
+/*---------------------------Python BPy_Interface1D visible prototypes-----------*/
+
+int Interface1D_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_INTERFACE1D_H */
diff --git a/source/blender/freestyle/intern/python/BPy_Iterator.cpp b/source/blender/freestyle/intern/python/BPy_Iterator.cpp
new file mode 100644
index 00000000000..dd7d3783d81
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Iterator.cpp
@@ -0,0 +1,229 @@
+#include "BPy_Iterator.h"
+
+#include "BPy_Convert.h"
+#include "Iterator/BPy_AdjacencyIterator.h"
+#include "Iterator/BPy_Interface0DIterator.h"
+#include "Iterator/BPy_CurvePointIterator.h"
+#include "Iterator/BPy_StrokeVertexIterator.h"
+#include "Iterator/BPy_SVertexIterator.h"
+#include "Iterator/BPy_orientedViewEdgeIterator.h"
+#include "Iterator/BPy_ViewEdgeIterator.h"
+#include "Iterator/BPy_ChainingIterator.h"
+#include "Iterator/BPy_ChainPredicateIterator.h"
+#include "Iterator/BPy_ChainSilhouetteIterator.h"
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int Iterator_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &Iterator_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Iterator_Type );
+ PyModule_AddObject(module, "Iterator", (PyObject *)&Iterator_Type);
+
+ if( PyType_Ready( &AdjacencyIterator_Type ) < 0 )
+ return -1;
+ Py_INCREF( &AdjacencyIterator_Type );
+ PyModule_AddObject(module, "AdjacencyIterator", (PyObject *)&AdjacencyIterator_Type);
+
+ if( PyType_Ready( &Interface0DIterator_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Interface0DIterator_Type );
+ PyModule_AddObject(module, "Interface0DIterator", (PyObject *)&Interface0DIterator_Type);
+
+ if( PyType_Ready( &CurvePointIterator_Type ) < 0 )
+ return -1;
+ Py_INCREF( &CurvePointIterator_Type );
+ PyModule_AddObject(module, "CurvePointIterator", (PyObject *)&CurvePointIterator_Type);
+
+ if( PyType_Ready( &StrokeVertexIterator_Type ) < 0 )
+ return -1;
+ Py_INCREF( &StrokeVertexIterator_Type );
+ PyModule_AddObject(module, "StrokeVertexIterator", (PyObject *)&StrokeVertexIterator_Type);
+
+ if( PyType_Ready( &SVertexIterator_Type ) < 0 )
+ return -1;
+ Py_INCREF( &SVertexIterator_Type );
+ PyModule_AddObject(module, "SVertexIterator", (PyObject *)&SVertexIterator_Type);
+
+ if( PyType_Ready( &orientedViewEdgeIterator_Type ) < 0 )
+ return -1;
+ Py_INCREF( &orientedViewEdgeIterator_Type );
+ PyModule_AddObject(module, "orientedViewEdgeIterator", (PyObject *)&orientedViewEdgeIterator_Type);
+
+ if( PyType_Ready( &ViewEdgeIterator_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ViewEdgeIterator_Type );
+ PyModule_AddObject(module, "ViewEdgeIterator", (PyObject *)&ViewEdgeIterator_Type);
+
+ if( PyType_Ready( &ChainingIterator_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ChainingIterator_Type );
+ PyModule_AddObject(module, "ChainingIterator", (PyObject *)&ChainingIterator_Type);
+
+ if( PyType_Ready( &ChainPredicateIterator_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ChainPredicateIterator_Type );
+ PyModule_AddObject(module, "ChainPredicateIterator", (PyObject *)&ChainPredicateIterator_Type);
+
+ if( PyType_Ready( &ChainSilhouetteIterator_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ChainSilhouetteIterator_Type );
+ PyModule_AddObject(module, "ChainSilhouetteIterator", (PyObject *)&ChainSilhouetteIterator_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Iterator___doc__[] =
+"Base class to define iterators.\n";
+
+static void Iterator___dealloc__(BPy_Iterator* self)
+{
+ if (self->it)
+ delete self->it;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * Iterator___repr__(BPy_Iterator* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->it->getExactTypeName().c_str(), self->it );
+}
+
+static char Iterator_getExactTypeName___doc__[] =
+".. method:: getExactTypeName()\n"
+"\n"
+" Returns the name of the iterator.\n"
+"\n"
+" :return: The name of the iterator.\n"
+" :rtype: str\n";
+
+static PyObject * Iterator_getExactTypeName(BPy_Iterator* self) {
+ return PyUnicode_FromString( self->it->getExactTypeName().c_str() );
+}
+
+static char Iterator_increment___doc__[] =
+".. method:: increment()\n"
+"\n"
+" Makes the iterator point the next element.\n";
+
+static PyObject * Iterator_increment(BPy_Iterator* self) {
+ if (self->it->isEnd()) {
+ PyErr_SetString(PyExc_RuntimeError , "cannot increment any more");
+ return NULL;
+ }
+ self->it->increment();
+
+ Py_RETURN_NONE;
+}
+
+static char Iterator_decrement___doc__[] =
+".. method:: decrement()\n"
+"\n"
+" Makes the iterator point the previous element.\n";
+
+static PyObject * Iterator_decrement(BPy_Iterator* self) {
+ if (self->it->isBegin()) {
+ PyErr_SetString(PyExc_RuntimeError , "cannot decrement any more");
+ return NULL;
+ }
+ self->it->decrement();
+
+ Py_RETURN_NONE;
+}
+
+static char Iterator_isBegin___doc__[] =
+".. method:: isBegin()\n"
+"\n"
+" Returns true if the interator points the first element.\n"
+"\n"
+" :return: True if the interator points the first element.\n"
+" :rtype: bool\n";
+
+static PyObject * Iterator_isBegin(BPy_Iterator* self) {
+ return PyBool_from_bool( self->it->isBegin() );
+}
+
+static char Iterator_isEnd___doc__[] =
+".. method:: isEnd()\n"
+"\n"
+" Returns true if the interator points the last element.\n"
+"\n"
+" :return: True if the interator points the last element.\n"
+" :rtype: bool\n";
+
+static PyObject * Iterator_isEnd(BPy_Iterator* self) {
+ return PyBool_from_bool( self->it->isEnd() );
+}
+
+/*----------------------Iterator instance definitions ----------------------------*/
+static PyMethodDef BPy_Iterator_methods[] = {
+ {"getExactTypeName", ( PyCFunction ) Iterator_getExactTypeName, METH_NOARGS, Iterator_getExactTypeName___doc__},
+ {"increment", ( PyCFunction ) Iterator_increment, METH_NOARGS, Iterator_increment___doc__},
+ {"decrement", ( PyCFunction ) Iterator_decrement, METH_NOARGS, Iterator_decrement___doc__},
+ {"isBegin", ( PyCFunction ) Iterator_isBegin, METH_NOARGS, Iterator_isBegin___doc__},
+ {"isEnd", ( PyCFunction ) Iterator_isEnd, METH_NOARGS, Iterator_isEnd___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_Iterator type definition ------------------------------*/
+
+PyTypeObject Iterator_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Iterator", /* tp_name */
+ sizeof(BPy_Iterator), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Iterator___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)Iterator___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Iterator___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_Iterator_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/source/blender/freestyle/intern/python/BPy_Iterator.h b/source/blender/freestyle/intern/python/BPy_Iterator.h
new file mode 100644
index 00000000000..0bdb52ef9a5
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Iterator.h
@@ -0,0 +1,35 @@
+#ifndef FREESTYLE_PYTHON_ITERATOR_H
+#define FREESTYLE_PYTHON_ITERATOR_H
+
+#include <Python.h>
+
+#include "../system/Iterator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject Iterator_Type;
+
+#define BPy_Iterator_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Iterator_Type) )
+
+/*---------------------------Python BPy_Iterator structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ Iterator *it;
+} BPy_Iterator;
+
+/*---------------------------Python BPy_Iterator visible prototypes-----------*/
+
+int Iterator_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_ITERATOR_H */
diff --git a/source/blender/freestyle/intern/python/BPy_MediumType.cpp b/source/blender/freestyle/intern/python/BPy_MediumType.cpp
new file mode 100644
index 00000000000..111fb756ba2
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_MediumType.cpp
@@ -0,0 +1,99 @@
+#include "BPy_MediumType.h"
+
+#include "BPy_Convert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+/*-----------------------BPy_MediumType type definition ------------------------------*/
+
+static char MediumType___doc__[] =
+"Class hierarchy: int > :class:`MediumType`\n"
+"\n"
+"The different blending modes available to similate the interaction\n"
+"media-medium:\n"
+"\n"
+"* Stroke.DRY_MEDIUM: To simulate a dry medium such as Pencil or Charcoal.\n"
+"* Stroke.HUMID_MEDIUM: To simulate ink painting (color substraction blending).\n"
+"* Stroke.OPAQUE_MEDIUM: To simulate an opaque medium (oil, spray...).\n";
+
+PyTypeObject MediumType_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "MediumType", /* tp_name */
+ sizeof(PyLongObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ MediumType___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PyLong_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+/*-----------------------BPy_IntegrationType instance definitions -------------------------*/
+
+PyLongObject _BPy_MediumType_DRY_MEDIUM = {
+ PyVarObject_HEAD_INIT(&MediumType_Type, 1)
+ { Stroke::DRY_MEDIUM }
+};
+PyLongObject _BPy_MediumType_HUMID_MEDIUM = {
+ PyVarObject_HEAD_INIT(&MediumType_Type, 1)
+ { Stroke::HUMID_MEDIUM }
+};
+PyLongObject _BPy_MediumType_OPAQUE_MEDIUM = {
+ PyVarObject_HEAD_INIT(&MediumType_Type, 1)
+ { Stroke::OPAQUE_MEDIUM }
+};
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int MediumType_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &MediumType_Type ) < 0 )
+ return -1;
+ Py_INCREF( &MediumType_Type );
+ PyModule_AddObject(module, "MediumType", (PyObject *)&MediumType_Type);
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/source/blender/freestyle/intern/python/BPy_MediumType.h b/source/blender/freestyle/intern/python/BPy_MediumType.h
new file mode 100644
index 00000000000..3bc50477295
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_MediumType.h
@@ -0,0 +1,42 @@
+#ifndef FREESTYLE_PYTHON_MEDIUMTYPE_H
+#define FREESTYLE_PYTHON_MEDIUMTYPE_H
+
+#include <Python.h>
+
+#include "../stroke/Stroke.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject MediumType_Type;
+
+#define BPy_MediumType_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &MediumType_Type) )
+
+/*---------------------------Python BPy_MediumType structure definition----------*/
+typedef struct {
+ PyLongObject i;
+} BPy_MediumType;
+
+/*---------------------------Python BPy_MediumType visible prototypes-----------*/
+
+int MediumType_Init( PyObject *module );
+
+// internal constants
+extern PyLongObject _BPy_MediumType_DRY_MEDIUM;
+extern PyLongObject _BPy_MediumType_HUMID_MEDIUM;
+extern PyLongObject _BPy_MediumType_OPAQUE_MEDIUM;
+// public constants
+#define BPy_MediumType_DRY_MEDIUM ((PyObject *)&_BPy_MediumType_DRY_MEDIUM)
+#define BPy_MediumType_HUMID_MEDIUM ((PyObject *)&_BPy_MediumType_HUMID_MEDIUM)
+#define BPy_MediumType_OPAQUE_MEDIUM ((PyObject *)&_BPy_MediumType_OPAQUE_MEDIUM)
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_MEDIUMTYPE_H */
diff --git a/source/blender/freestyle/intern/python/BPy_Nature.cpp b/source/blender/freestyle/intern/python/BPy_Nature.cpp
new file mode 100644
index 00000000000..149baa9a7f3
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Nature.cpp
@@ -0,0 +1,312 @@
+#include "BPy_Nature.h"
+
+#include "BPy_Convert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+static PyObject *BPy_Nature___and__(PyObject *a, PyObject *b);
+static PyObject *BPy_Nature___xor__(PyObject *a, PyObject *b);
+static PyObject *BPy_Nature___or__(PyObject *a, PyObject *b);
+static int BPy_Nature_bool(PyObject *v);
+
+/*-----------------------BPy_Nature number method definitions --------------------*/
+
+PyNumberMethods nature_as_number = {
+ 0, /* binaryfunc nb_add */
+ 0, /* binaryfunc nb_subtract */
+ 0, /* binaryfunc nb_multiply */
+ 0, /* binaryfunc nb_remainder */
+ 0, /* binaryfunc nb_divmod */
+ 0, /* ternaryfunc nb_power */
+ 0, /* unaryfunc nb_negative */
+ 0, /* unaryfunc nb_positive */
+ 0, /* unaryfunc nb_absolute */
+ (inquiry)BPy_Nature_bool, /* inquiry nb_bool */
+ 0, /* unaryfunc nb_invert */
+ 0, /* binaryfunc nb_lshift */
+ 0, /* binaryfunc nb_rshift */
+ (binaryfunc)BPy_Nature___and__, /* binaryfunc nb_and */
+ (binaryfunc)BPy_Nature___xor__, /* binaryfunc nb_xor */
+ (binaryfunc)BPy_Nature___or__, /* binaryfunc nb_or */
+ 0, /* unaryfunc nb_int */
+ 0, /* void *nb_reserved */
+ 0, /* unaryfunc nb_float */
+ 0, /* binaryfunc nb_inplace_add */
+ 0, /* binaryfunc nb_inplace_subtract */
+ 0, /* binaryfunc nb_inplace_multiply */
+ 0, /* binaryfunc nb_inplace_remainder */
+ 0, /* ternaryfunc nb_inplace_power */
+ 0, /* binaryfunc nb_inplace_lshift */
+ 0, /* binaryfunc nb_inplace_rshift */
+ 0, /* binaryfunc nb_inplace_and */
+ 0, /* binaryfunc nb_inplace_xor */
+ 0, /* binaryfunc nb_inplace_or */
+ 0, /* binaryfunc nb_floor_divide */
+ 0, /* binaryfunc nb_true_divide */
+ 0, /* binaryfunc nb_inplace_floor_divide */
+ 0, /* binaryfunc nb_inplace_true_divide */
+ 0, /* unaryfunc nb_index */
+};
+
+/*-----------------------BPy_Nature docstring ------------------------------------*/
+
+static char Nature___doc__[] =
+"Class hierarchy: int > :class:`Nature`\n"
+"\n"
+"Different possible natures of 0D and 1D elements of the ViewMap.\n"
+"\n"
+"Vertex natures:\n"
+"\n"
+"* Nature.POINT: True for any 0D element.\n"
+"* Nature.S_VERTEX: True for SVertex.\n"
+"* Nature.VIEW_VERTEX: True for ViewVertex.\n"
+"* Nature.NON_T_VERTEX: True for NonTVertex.\n"
+"* Nature.T_VERTEX: True for TVertex.\n"
+"* Nature.CUSP: True for CUSP.\n"
+"\n"
+"Edge natures:\n"
+"\n"
+"* Nature.NO_FEATURE: True for non feature edges (always false for 1D\n"
+" elements of the ViewMap).\n"
+"* Nature.SILHOUETTE: True for silhouettes.\n"
+"* Nature.BORDER: True for borders.\n"
+"* Nature.CREASE: True for creases.\n"
+"* Nature.RIDGE: True for ridges.\n"
+"* Nature.VALLEY: True for valleys.\n"
+"* Nature.SUGGESTIVE_CONTOUR: True for suggestive contours.\n"
+"* Nature.MATERIAL_BOUNDARY: True for edges at material boundaries.\n"
+"* Nature.EDGE_MARK: True for edges having user-defined edge marks.\n";
+
+/*-----------------------BPy_Nature type definition ------------------------------*/
+
+PyTypeObject Nature_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Nature", /* tp_name */
+ sizeof(PyLongObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ &nature_as_number, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ Nature___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &PyLong_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+/*-----------------------BPy_Nature instance definitions ----------------------------------*/
+
+static PyLongObject _Nature_POINT = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::POINT }
+};
+static PyLongObject _Nature_S_VERTEX = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::S_VERTEX }
+};
+static PyLongObject _Nature_VIEW_VERTEX = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::VIEW_VERTEX }
+};
+static PyLongObject _Nature_NON_T_VERTEX = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::NON_T_VERTEX }
+};
+static PyLongObject _Nature_T_VERTEX = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::T_VERTEX }
+};
+static PyLongObject _Nature_CUSP = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::CUSP }
+};
+static PyLongObject _Nature_NO_FEATURE = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::NO_FEATURE }
+};
+static PyLongObject _Nature_SILHOUETTE = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::SILHOUETTE }
+};
+static PyLongObject _Nature_BORDER = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::BORDER }
+};
+static PyLongObject _Nature_CREASE = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::CREASE }
+};
+static PyLongObject _Nature_RIDGE = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::RIDGE }
+};
+static PyLongObject _Nature_VALLEY = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::VALLEY }
+};
+static PyLongObject _Nature_SUGGESTIVE_CONTOUR = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::SUGGESTIVE_CONTOUR }
+};
+static PyLongObject _Nature_MATERIAL_BOUNDARY = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::MATERIAL_BOUNDARY }
+};
+static PyLongObject _Nature_EDGE_MARK = {
+ PyVarObject_HEAD_INIT(&Nature_Type, 1)
+ { Nature::EDGE_MARK }
+};
+
+#define BPy_Nature_POINT ((PyObject *)&_Nature_POINT)
+#define BPy_Nature_S_VERTEX ((PyObject *)&_Nature_S_VERTEX)
+#define BPy_Nature_VIEW_VERTEX ((PyObject *)&_Nature_VIEW_VERTEX)
+#define BPy_Nature_NON_T_VERTEX ((PyObject *)&_Nature_NON_T_VERTEX)
+#define BPy_Nature_T_VERTEX ((PyObject *)&_Nature_T_VERTEX)
+#define BPy_Nature_CUSP ((PyObject *)&_Nature_CUSP)
+#define BPy_Nature_NO_FEATURE ((PyObject *)&_Nature_NO_FEATURE)
+#define BPy_Nature_SILHOUETTE ((PyObject *)&_Nature_SILHOUETTE)
+#define BPy_Nature_BORDER ((PyObject *)&_Nature_BORDER)
+#define BPy_Nature_CREASE ((PyObject *)&_Nature_CREASE)
+#define BPy_Nature_RIDGE ((PyObject *)&_Nature_RIDGE)
+#define BPy_Nature_VALLEY ((PyObject *)&_Nature_VALLEY)
+#define BPy_Nature_SUGGESTIVE_CONTOUR ((PyObject *)&_Nature_SUGGESTIVE_CONTOUR)
+#define BPy_Nature_MATERIAL_BOUNDARY ((PyObject *)&_Nature_MATERIAL_BOUNDARY)
+#define BPy_Nature_EDGE_MARK ((PyObject *)&_Nature_EDGE_MARK)
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int Nature_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &Nature_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Nature_Type );
+ PyModule_AddObject(module, "Nature", (PyObject *)&Nature_Type);
+
+ // VertexNature
+ PyDict_SetItemString( Nature_Type.tp_dict, "POINT", BPy_Nature_POINT);
+ PyDict_SetItemString( Nature_Type.tp_dict, "S_VERTEX", BPy_Nature_S_VERTEX);
+ PyDict_SetItemString( Nature_Type.tp_dict, "VIEW_VERTEX", BPy_Nature_VIEW_VERTEX );
+ PyDict_SetItemString( Nature_Type.tp_dict, "NON_T_VERTEX", BPy_Nature_NON_T_VERTEX );
+ PyDict_SetItemString( Nature_Type.tp_dict, "T_VERTEX", BPy_Nature_T_VERTEX );
+ PyDict_SetItemString( Nature_Type.tp_dict, "CUSP", BPy_Nature_CUSP );
+
+ // EdgeNature
+ PyDict_SetItemString( Nature_Type.tp_dict, "NO_FEATURE", BPy_Nature_NO_FEATURE );
+ PyDict_SetItemString( Nature_Type.tp_dict, "SILHOUETTE", BPy_Nature_SILHOUETTE );
+ PyDict_SetItemString( Nature_Type.tp_dict, "BORDER", BPy_Nature_BORDER );
+ PyDict_SetItemString( Nature_Type.tp_dict, "CREASE", BPy_Nature_CREASE );
+ PyDict_SetItemString( Nature_Type.tp_dict, "RIDGE", BPy_Nature_RIDGE );
+ PyDict_SetItemString( Nature_Type.tp_dict, "VALLEY", BPy_Nature_VALLEY );
+ PyDict_SetItemString( Nature_Type.tp_dict, "SUGGESTIVE_CONTOUR", BPy_Nature_SUGGESTIVE_CONTOUR );
+ PyDict_SetItemString( Nature_Type.tp_dict, "MATERIAL_BOUNDARY", BPy_Nature_MATERIAL_BOUNDARY );
+ PyDict_SetItemString( Nature_Type.tp_dict, "EDGE_MARK", BPy_Nature_EDGE_MARK );
+
+ return 0;
+}
+
+static PyObject *
+BPy_Nature_bitwise(PyObject *a, int op, PyObject *b)
+{
+ BPy_Nature *result;
+
+ if (!BPy_Nature_Check(a) || !BPy_Nature_Check(b)) {
+ PyErr_SetString(PyExc_TypeError, "operands must be a Nature object");
+ return NULL;
+ }
+ if (Py_SIZE(a) != 1) {
+ stringstream msg;
+ msg << "operand 1: unexpected Nature byte length: " << Py_SIZE(a);
+ PyErr_SetString(PyExc_TypeError, msg.str().c_str());
+ return NULL;
+ }
+ if (Py_SIZE(b) != 1) {
+ stringstream msg;
+ msg << "operand 2: unexpected Nature byte length: " << Py_SIZE(b);
+ PyErr_SetString(PyExc_TypeError, msg.str().c_str());
+ return NULL;
+ }
+ result = PyObject_NewVar(BPy_Nature, &Nature_Type, 1);
+ if (!result)
+ return NULL;
+ if (Py_SIZE(result) != 1) {
+ stringstream msg;
+ msg << "unexpected Nature byte length: " << Py_SIZE(result);
+ PyErr_SetString(PyExc_TypeError, msg.str().c_str());
+ return NULL;
+ }
+ switch (op) {
+ case '&':
+ result->i.ob_digit[0] = (((PyLongObject *)a)->ob_digit[0]) & (((PyLongObject *)b)->ob_digit)[0];
+ break;
+ case '^':
+ result->i.ob_digit[0] = (((PyLongObject *)a)->ob_digit[0]) ^ (((PyLongObject *)b)->ob_digit)[0];
+ break;
+ case '|':
+ result->i.ob_digit[0] = (((PyLongObject *)a)->ob_digit[0]) | (((PyLongObject *)b)->ob_digit)[0];
+ break;
+ }
+ return (PyObject *)result;
+}
+
+static PyObject *
+BPy_Nature___and__(PyObject *a, PyObject *b)
+{
+ return BPy_Nature_bitwise(a, '&', b);
+}
+
+static PyObject *
+BPy_Nature___xor__(PyObject *a, PyObject *b)
+{
+ return BPy_Nature_bitwise(a, '^', b);
+}
+
+static PyObject *
+BPy_Nature___or__(PyObject *a, PyObject *b)
+{
+ return BPy_Nature_bitwise(a, '|', b);
+}
+
+static int
+BPy_Nature_bool(PyObject *v)
+{
+ return ((PyLongObject *)v)->ob_digit[0] != 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/source/blender/freestyle/intern/python/BPy_Nature.h b/source/blender/freestyle/intern/python/BPy_Nature.h
new file mode 100644
index 00000000000..8c38415242e
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Nature.h
@@ -0,0 +1,33 @@
+#ifndef FREESTYLE_PYTHON_NATURE_H
+#define FREESTYLE_PYTHON_NATURE_H
+
+#include <Python.h>
+
+#include "../winged_edge/Nature.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject Nature_Type;
+
+#define BPy_Nature_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Nature_Type) )
+
+/*---------------------------Python BPy_Nature structure definition----------*/
+typedef struct {
+ PyLongObject i;
+} BPy_Nature;
+
+/*---------------------------Python BPy_Nature visible prototypes-----------*/
+
+int Nature_Init( PyObject *module );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_NATURE_H */
diff --git a/source/blender/freestyle/intern/python/BPy_Operators.cpp b/source/blender/freestyle/intern/python/BPy_Operators.cpp
new file mode 100644
index 00000000000..7d660054335
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Operators.cpp
@@ -0,0 +1,682 @@
+#include "BPy_Operators.h"
+
+#include "BPy_BinaryPredicate1D.h"
+#include "BPy_UnaryPredicate0D.h"
+#include "BPy_UnaryPredicate1D.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DDouble.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DVoid.h"
+#include "Iterator/BPy_ViewEdgeIterator.h"
+#include "Iterator/BPy_ChainingIterator.h"
+#include "BPy_StrokeShader.h"
+#include "BPy_Convert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int Operators_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &Operators_Type ) < 0 )
+ return -1;
+
+ Py_INCREF( &Operators_Type );
+ PyModule_AddObject(module, "Operators", (PyObject *)&Operators_Type);
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Operators___doc__[] =
+"Class defining the operators used in a style module. There are five\n"
+"types of operators: Selection, chaining, splitting, sorting and\n"
+"creation. All these operators are user controlled through functors,\n"
+"predicates and shaders that are taken as arguments.\n";
+
+static void Operators___dealloc__(BPy_Operators* self)
+{
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static char Operators_select___doc__[] =
+".. staticmethod:: select(pred)\n"
+"\n"
+" Selects the ViewEdges of the ViewMap verifying a specified\n"
+" condition.\n"
+"\n"
+" :arg pred: The predicate expressing this condition.\n"
+" :type pred: UnaryPredicate1D\n";
+
+static PyObject * Operators_select(BPy_Operators* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if ( !PyArg_ParseTuple(args, "O!", &UnaryPredicate1D_Type, &obj) )
+ return NULL;
+ if ( !((BPy_UnaryPredicate1D *) obj)->up1D ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.select(): 1st argument: invalid UnaryPredicate1D object");
+ return NULL;
+ }
+
+ if (Operators::select(*( ((BPy_UnaryPredicate1D *) obj)->up1D )) < 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_RuntimeError, "Operators.select() failed");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char Operators_chain___doc__[] =
+".. staticmethod:: chain(it, pred, modifier)\n"
+"\n"
+" Builds a set of chains from the current set of ViewEdges. Each\n"
+" ViewEdge of the current list starts a new chain. The chaining\n"
+" operator then iterates over the ViewEdges of the ViewMap using the\n"
+" user specified iterator. This operator only iterates using the\n"
+" increment operator and is therefore unidirectional.\n"
+"\n"
+" :arg it: The iterator on the ViewEdges of the ViewMap. It contains\n"
+" the chaining rule.\n"
+" :type it: :class:`ViewEdgeIterator`\n"
+" :arg pred: The predicate on the ViewEdge that expresses the\n"
+" stopping condition.\n"
+" :type pred: :class:`UnaryPredicate1D`\n"
+" :arg modifier: A function that takes a ViewEdge as argument and\n"
+" that is used to modify the processed ViewEdge state (the\n"
+" timestamp incrementation is a typical illustration of such a\n"
+" modifier).\n"
+" :type modifier: :class:`UnaryFunction1DVoid`\n"
+"\n"
+".. staticmethod:: chain(it, pred)\n"
+"\n"
+" Builds a set of chains from the current set of ViewEdges. Each\n"
+" ViewEdge of the current list starts a new chain. The chaining\n"
+" operator then iterates over the ViewEdges of the ViewMap using the\n"
+" user specified iterator. This operator only iterates using the\n"
+" increment operator and is therefore unidirectional. This chaining\n"
+" operator is different from the previous one because it doesn't take\n"
+" any modifier as argument. Indeed, the time stamp (insuring that a\n"
+" ViewEdge is processed one time) is automatically managed in this\n"
+" case.\n"
+"\n"
+" :arg it: The iterator on the ViewEdges of the ViewMap. It contains\n"
+" the chaining rule. \n"
+" :type it: :class:`ViewEdgeIterator`\n"
+" :arg pred: The predicate on the ViewEdge that expresses the\n"
+" stopping condition.\n"
+" :type pred: :class:`UnaryPredicate1D`\n";
+
+// CHANGE: first parameter is a chaining iterator, not just a view
+
+static PyObject * Operators_chain(BPy_Operators* self, PyObject *args)
+{
+ PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0;
+
+ if ( !PyArg_ParseTuple(args, "O!O!|O!", &ChainingIterator_Type, &obj1,
+ &UnaryPredicate1D_Type, &obj2,
+ &UnaryFunction1DVoid_Type, &obj3) )
+ return NULL;
+ if ( !((BPy_ChainingIterator *) obj1)->c_it ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.chain(): 1st argument: invalid ChainingIterator object");
+ return NULL;
+ }
+ if ( !((BPy_UnaryPredicate1D *) obj2)->up1D ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.chain(): 2nd argument: invalid UnaryPredicate1D object");
+ return NULL;
+ }
+
+ if( !obj3 ) {
+
+ if (Operators::chain( *( ((BPy_ChainingIterator *) obj1)->c_it ),
+ *( ((BPy_UnaryPredicate1D *) obj2)->up1D ) ) < 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_RuntimeError, "Operators.chain() failed");
+ return NULL;
+ }
+
+ } else {
+
+ if ( !((BPy_UnaryFunction1DVoid *) obj3)->uf1D_void ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.chain(): 3rd argument: invalid UnaryFunction1DVoid object");
+ return NULL;
+ }
+ if (Operators::chain( *( ((BPy_ChainingIterator *) obj1)->c_it ),
+ *( ((BPy_UnaryPredicate1D *) obj2)->up1D ),
+ *( ((BPy_UnaryFunction1DVoid *) obj3)->uf1D_void ) ) < 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_RuntimeError, "Operators.chain() failed");
+ return NULL;
+ }
+
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char Operators_bidirectionalChain___doc__[] =
+".. staticmethod:: bidirectionalChain(it, pred)\n"
+"\n"
+" Builds a set of chains from the current set of ViewEdges. Each\n"
+" ViewEdge of the current list potentially starts a new chain. The\n"
+" chaining operator then iterates over the ViewEdges of the ViewMap\n"
+" using the user specified iterator. This operator iterates both using\n"
+" the increment and decrement operators and is therefore bidirectional.\n"
+" This operator works with a ChainingIterator which contains the\n"
+" chaining rules. It is this last one which can be told to chain only\n"
+" edges that belong to the selection or not to process twice a ViewEdge\n"
+" during the chaining. Each time a ViewEdge is added to a chain, its\n"
+" chaining time stamp is incremented. This allows you to keep track of\n"
+" the number of chains to which a ViewEdge belongs to.\n"
+"\n"
+" :arg it: The ChainingIterator on the ViewEdges of the ViewMap. It\n"
+" contains the chaining rule.\n"
+" :type it: :class:`ChainingIterator`\n"
+" :arg pred: The predicate on the ViewEdge that expresses the\n"
+" stopping condition.\n"
+" :type pred: :class:`UnaryPredicate1D`\n"
+"\n"
+".. staticmethod:: bidirectionalChain(it)\n"
+"\n"
+" The only difference with the above bidirectional chaining algorithm\n"
+" is that we don't need to pass a stopping criterion. This might be\n"
+" desirable when the stopping criterion is already contained in the\n"
+" iterator definition. Builds a set of chains from the current set of\n"
+" ViewEdges. Each ViewEdge of the current list potentially starts a new\n"
+" chain. The chaining operator then iterates over the ViewEdges of the\n"
+" ViewMap using the user specified iterator. This operator iterates\n"
+" both using the increment and decrement operators and is therefore\n"
+" bidirectional. This operator works with a ChainingIterator which\n"
+" contains the chaining rules. It is this last one which can be told to\n"
+" chain only edges that belong to the selection or not to process twice\n"
+" a ViewEdge during the chaining. Each time a ViewEdge is added to a\n"
+" chain, its chaining time stamp is incremented. This allows you to\n"
+" keep track of the number of chains to which a ViewEdge belongs to.\n"
+"\n"
+" :arg it: The ChainingIterator on the ViewEdges of the ViewMap. It\n"
+" contains the chaining rule.\n"
+" :type it: :class:`ChainingIterator`\n";
+
+static PyObject * Operators_bidirectionalChain(BPy_Operators* self, PyObject *args)
+{
+ PyObject *obj1 = 0, *obj2 = 0;
+
+ if( !PyArg_ParseTuple(args, "O!|O!", &ChainingIterator_Type, &obj1, &UnaryPredicate1D_Type, &obj2) )
+ return NULL;
+ if ( !((BPy_ChainingIterator *) obj1)->c_it ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.bidirectionalChain(): 1st argument: invalid ChainingIterator object");
+ return NULL;
+ }
+
+ if( !obj2 ) {
+
+ if (Operators::bidirectionalChain( *( ((BPy_ChainingIterator *) obj1)->c_it ) ) < 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_RuntimeError, "Operators.bidirectionalChain() failed");
+ return NULL;
+ }
+
+ } else {
+
+ if ( !((BPy_UnaryPredicate1D *) obj2)->up1D ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.bidirectionalChain(): 2nd argument: invalid UnaryPredicate1D object");
+ return NULL;
+ }
+ if (Operators::bidirectionalChain( *( ((BPy_ChainingIterator *) obj1)->c_it ),
+ *( ((BPy_UnaryPredicate1D *) obj2)->up1D ) ) < 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_RuntimeError, "Operators.bidirectionalChain() failed");
+ return NULL;
+ }
+
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char Operators_sequentialSplit___doc__[] =
+".. staticmethod:: sequentialSplit(startingPred, stoppingPred, sampling=0.0)\n"
+"\n"
+" Splits each chain of the current set of chains in a sequential way.\n"
+" The points of each chain are processed (with a specified sampling)\n"
+" sequentially. Each time a user specified starting condition is\n"
+" verified, a new chain begins and ends as soon as a user-defined\n"
+" stopping predicate is verified. This allows chains overlapping rather\n"
+" than chains partitioning. The first point of the initial chain is the\n"
+" first point of one of the resulting chains. The splitting ends when\n"
+" no more chain can start.\n"
+"\n"
+" :arg startingPred: The predicate on a point that expresses the\n"
+" starting condition.\n"
+" :type startingPred: :class:`UnaryPredicate0D`\n"
+" :arg stoppingPred: The predicate on a point that expresses the\n"
+" stopping condition.\n"
+" :type stoppingPred: :class:`UnaryPredicate0D`\n"
+" :arg sampling: The resolution used to sample the chain for the\n"
+" predicates evaluation. (The chain is not actually resampled;\n"
+" a virtual point only progresses along the curve using this\n"
+" resolution.)\n"
+" :type sampling: float\n"
+"\n"
+".. staticmethod:: sequentialSplit(pred, sampling=0.0)\n"
+"\n"
+" Splits each chain of the current set of chains in a sequential way.\n"
+" The points of each chain are processed (with a specified sampling)\n"
+" sequentially and each time a user specified condition is verified,\n"
+" the chain is split into two chains. The resulting set of chains is a\n"
+" partition of the initial chain\n"
+"\n"
+" :arg pred: The predicate on a point that expresses the splitting\n"
+" condition.\n"
+" :type pred: :class:`UnaryPredicate0D`\n"
+" :arg sampling: The resolution used to sample the chain for the\n"
+" predicate evaluation. (The chain is not actually resampled; a\n"
+" virtual point only progresses along the curve using this\n"
+" resolution.)\n"
+" :type sampling: float\n";
+
+static PyObject * Operators_sequentialSplit(BPy_Operators* self, PyObject *args)
+{
+ PyObject *obj1 = 0, *obj2 = 0;
+ float f = 0.0;
+
+ if( !PyArg_ParseTuple(args, "O!|Of", &UnaryPredicate0D_Type, &obj1, &obj2, &f) )
+ return NULL;
+ if ( !((BPy_UnaryPredicate0D *) obj1)->up0D ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.sequentialSplit(): 1st argument: invalid UnaryPredicate0D object");
+ return NULL;
+ }
+
+ if( obj2 && BPy_UnaryPredicate0D_Check(obj2) ) {
+
+ if ( !((BPy_UnaryPredicate0D *) obj2)->up0D ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.sequentialSplit(): 2nd argument: invalid UnaryPredicate0D object");
+ return NULL;
+ }
+ if (Operators::sequentialSplit( *( ((BPy_UnaryPredicate0D *) obj1)->up0D ),
+ *( ((BPy_UnaryPredicate0D *) obj2)->up0D ),
+ f ) < 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_RuntimeError, "Operators.sequentialSplit() failed");
+ return NULL;
+ }
+
+ } else {
+
+ if ( obj2 ) {
+ if ( !PyFloat_Check(obj2) ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.sequentialSplit(): invalid 2nd argument");
+ return NULL;
+ }
+ f = PyFloat_AsDouble(obj2);
+ }
+ if (Operators::sequentialSplit( *( ((BPy_UnaryPredicate0D *) obj1)->up0D ), f ) < 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_RuntimeError, "Operators.sequentialSplit() failed");
+ return NULL;
+ }
+
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char Operators_recursiveSplit___doc__[] =
+".. staticmethod:: recursiveSplit(func, pred, sampling=0.0)\n"
+"\n"
+" Splits the current set of chains in a recursive way. We process the\n"
+" points of each chain (with a specified sampling) to find the point\n"
+" minimizing a specified function. The chain is split in two at this\n"
+" point and the two new chains are processed in the same way. The\n"
+" recursivity level is controlled through a predicate 1D that expresses\n"
+" a stopping condition on the chain that is about to be processed.\n"
+"\n"
+" :arg func: The Unary Function evaluated at each point of the chain.\n"
+" The splitting point is the point minimizing this function.\n"
+" :type func: :class:`UnaryFunction0DDouble`\n"
+" :arg pred: The Unary Predicate expressing the recursivity stopping\n"
+" condition. This predicate is evaluated for each curve before it\n"
+" actually gets split. If pred(chain) is true, the curve won't be\n"
+" split anymore.\n"
+" :type pred: :class:`UnaryPredicate1D`\n"
+" :arg sampling: The resolution used to sample the chain for the\n"
+" predicates evaluation. (The chain is not actually resampled, a\n"
+" virtual point only progresses along the curve using this\n"
+" resolution.)\n"
+" :type sampling: float\n"
+"\n"
+".. staticmethod:: recursiveSplit(func, pred0d, pred, sampling=0.0)\n"
+"\n"
+" Splits the current set of chains in a recursive way. We process the\n"
+" points of each chain (with a specified sampling) to find the point\n"
+" minimizing a specified function. The chain is split in two at this\n"
+" point and the two new chains are processed in the same way. The user\n"
+" can specify a 0D predicate to make a first selection on the points\n"
+" that can potentially be split. A point that doesn't verify the 0D\n"
+" predicate won't be candidate in realizing the min. The recursivity\n"
+" level is controlled through a predicate 1D that expresses a stopping\n"
+" condition on the chain that is about to be processed.\n"
+"\n"
+" :arg func: The Unary Function evaluated at each point of the chain.\n"
+" The splitting point is the point minimizing this function.\n"
+" :type func: :class:`UnaryFunction0DDouble`\n"
+" :arg pred0d: The Unary Predicate 0D used to select the candidate\n"
+" points where the split can occur. For example, it is very likely\n"
+" that would rather have your chain splitting around its middle\n"
+" point than around one of its extremities. A 0D predicate working\n"
+" on the curvilinear abscissa allows to add this kind of constraints.\n"
+" :type pred0d: :class:`UnaryPredicate0D`\n"
+" :arg pred: The Unary Predicate expressing the recursivity stopping\n"
+" condition. This predicate is evaluated for each curve before it\n"
+" actually gets split. If pred(chain) is true, the curve won't be\n"
+" split anymore.\n"
+" :type pred: :class:`UnaryPredicate1D`\n"
+" :arg sampling: The resolution used to sample the chain for the\n"
+" predicates evaluation. (The chain is not actually resampled; a\n"
+" virtual point only progresses along the curve using this\n"
+" resolution.)\n"
+" :type sampling: float\n";
+
+static PyObject * Operators_recursiveSplit(BPy_Operators* self, PyObject *args)
+{
+ PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0;
+ float f = 0.0;
+
+ if ( !PyArg_ParseTuple(args, "O!O|Of", &UnaryFunction0DDouble_Type, &obj1, &obj2, &obj3, &f) )
+ return NULL;
+ if ( !((BPy_UnaryFunction0DDouble *) obj1)->uf0D_double ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.recursiveSplit(): 1st argument: invalid UnaryFunction0DDouble object");
+ return NULL;
+ }
+
+ if ( BPy_UnaryPredicate1D_Check(obj2) ) {
+
+ if ( !((BPy_UnaryPredicate1D *) obj2)->up1D ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.recursiveSplit(): 2nd argument: invalid UnaryPredicate1D object");
+ return NULL;
+ }
+ if ( obj3 ) {
+ if ( !PyFloat_Check(obj3) ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.recursiveSplit(): invalid 3rd argument");
+ return NULL;
+ }
+ f = PyFloat_AsDouble(obj3);
+ }
+ if (Operators::recursiveSplit( *( ((BPy_UnaryFunction0DDouble *) obj1)->uf0D_double ),
+ *( ((BPy_UnaryPredicate1D *) obj2)->up1D ),
+ f ) < 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_RuntimeError, "Operators.recursiveSplit() failed");
+ return NULL;
+ }
+
+ } else {
+
+ if ( !BPy_UnaryPredicate0D_Check(obj2) || !((BPy_UnaryPredicate0D *) obj2)->up0D ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.recursiveSplit(): invalid 2nd argument");
+ return NULL;
+ }
+ if ( !BPy_UnaryPredicate1D_Check(obj3) || !((BPy_UnaryPredicate1D *) obj3)->up1D ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.recursiveSplit(): invalid 3rd argument");
+ return NULL;
+ }
+ if (Operators::recursiveSplit( *( ((BPy_UnaryFunction0DDouble *) obj1)->uf0D_double ),
+ *( ((BPy_UnaryPredicate0D *) obj2)->up0D ),
+ *( ((BPy_UnaryPredicate1D *) obj3)->up1D ),
+ f ) < 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_RuntimeError, "Operators.recursiveSplit() failed");
+ return NULL;
+ }
+
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char Operators_sort___doc__[] =
+".. staticmethod:: sort(pred)\n"
+"\n"
+" Sorts the current set of chains (or viewedges) according to the\n"
+" comparison predicate given as argument.\n"
+"\n"
+" :arg pred: The binary predicate used for the comparison.\n"
+" :type pred: BinaryPredicate1D\n";
+
+static PyObject * Operators_sort(BPy_Operators* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if ( !PyArg_ParseTuple(args, "O!", &BinaryPredicate1D_Type, &obj) )
+ return NULL;
+ if ( !((BPy_BinaryPredicate1D *) obj)->bp1D ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.sort(): 1st argument: invalid BinaryPredicate1D object");
+ return NULL;
+ }
+
+ if (Operators::sort(*( ((BPy_BinaryPredicate1D *) obj)->bp1D )) < 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_RuntimeError, "Operators.sort() failed");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static char Operators_create___doc__[] =
+".. staticmethod:: create(pred, shaders)\n"
+"\n"
+" Creates and shades the strokes from the current set of chains. A\n"
+" predicate can be specified to make a selection pass on the chains.\n"
+"\n"
+" :arg pred: The predicate that a chain must verify in order to be\n"
+" transform as a stroke.\n"
+" :type pred: :class:`UnaryPredicate1D`\n"
+" :arg shaders: The list of shaders used to shade the strokes.\n"
+" :type shaders: List of StrokeShader objects\n";
+
+static PyObject * Operators_create(BPy_Operators* self, PyObject *args)
+{
+ PyObject *obj1 = 0, *obj2 = 0;
+
+ if ( !PyArg_ParseTuple(args, "O!O!", &UnaryPredicate1D_Type, &obj1, &PyList_Type, &obj2) )
+ return NULL;
+ if ( !((BPy_UnaryPredicate1D *) obj1)->up1D ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.create(): 1st argument: invalid UnaryPredicate1D object");
+ return NULL;
+ }
+
+ vector<StrokeShader *> shaders;
+ for( int i = 0; i < PyList_Size(obj2); i++) {
+ PyObject *py_ss = PyList_GetItem(obj2,i);
+
+ if ( !BPy_StrokeShader_Check(py_ss) ) {
+ PyErr_SetString(PyExc_TypeError, "Operators.create() 2nd argument must be a list of StrokeShader objects");
+ return NULL;
+ }
+ shaders.push_back( ((BPy_StrokeShader *) py_ss)->ss );
+ }
+
+ if (Operators::create( *( ((BPy_UnaryPredicate1D *) obj1)->up1D ), shaders) < 0) {
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_RuntimeError, "Operators.create() failed");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char Operators_getViewEdgeFromIndex___doc__[] =
+".. staticmethod:: getViewEdgeFromIndex()\n"
+"\n"
+" Returns the ViewEdge at the index in the current set of ViewEdges.\n"
+"\n"
+" :arg i: index (0 <= i < Operators.getViewEdgesSize()).\n"
+" :type i: int\n"
+" :return: The ViewEdge object.\n"
+" :rtype: :class:`ViewEdge`\n";
+
+static PyObject * Operators_getViewEdgeFromIndex(BPy_Operators* self, PyObject *args) {
+ unsigned int i;
+
+ if (!PyArg_ParseTuple(args, "I", &i))
+ return NULL;
+ if (i >= Operators::getViewEdgesSize()) {
+ PyErr_SetString(PyExc_IndexError, "index out of range");
+ return NULL;
+ }
+ return BPy_ViewEdge_from_ViewEdge(*(Operators::getViewEdgeFromIndex(i)));
+}
+
+static char Operators_getChainFromIndex___doc__[] =
+".. staticmethod:: getChainFromIndex()\n"
+"\n"
+" Returns the Chain at the index in the current set of Chains.\n"
+"\n"
+" :arg i: index (0 <= i < Operators.getChainsSize()).\n"
+" :type i: int\n"
+" :return: The Chain object.\n"
+" :rtype: :class:`Chain`\n";
+
+static PyObject * Operators_getChainFromIndex(BPy_Operators* self, PyObject *args) {
+ unsigned int i;
+
+ if (!PyArg_ParseTuple(args, "I", &i))
+ return NULL;
+ if (i >= Operators::getChainsSize()) {
+ PyErr_SetString(PyExc_IndexError, "index out of range");
+ return NULL;
+ }
+ return BPy_Chain_from_Chain(*(Operators::getChainFromIndex(i)));
+}
+
+static char Operators_getStrokeFromIndex___doc__[] =
+".. staticmethod:: getStrokeFromIndex()\n"
+"\n"
+" Returns the Stroke at the index in the current set of Strokes.\n"
+"\n"
+" :arg i: index (0 <= i < Operators.getStrokesSize()).\n"
+" :type i: int\n"
+" :return: The Stroke object.\n"
+" :rtype: :class:`Stroke`\n";
+
+static PyObject * Operators_getStrokeFromIndex(BPy_Operators* self, PyObject *args) {
+ unsigned int i;
+
+ if (!PyArg_ParseTuple(args, "I", &i))
+ return NULL;
+ if (i >= Operators::getStrokesSize()) {
+ PyErr_SetString(PyExc_IndexError, "index out of range");
+ return NULL;
+ }
+ return BPy_Stroke_from_Stroke(*(Operators::getStrokeFromIndex(i)));
+}
+
+static char Operators_getViewEdgesSize___doc__[] =
+".. staticmethod:: getViewEdgesSize()\n"
+"\n"
+" Returns the number of ViewEdges.\n"
+"\n"
+" :return: The number of ViewEdges.\n"
+" :rtype: int\n";
+
+static PyObject * Operators_getViewEdgesSize( BPy_Operators* self) {
+ return PyLong_FromLong( Operators::getViewEdgesSize() );
+}
+
+static char Operators_getChainsSize___doc__[] =
+".. staticmethod:: getChainsSize()\n"
+"\n"
+" Returns the number of Chains.\n"
+"\n"
+" :return: The number of Chains.\n"
+" :rtype: int\n";
+
+static PyObject * Operators_getChainsSize( BPy_Operators* self ) {
+ return PyLong_FromLong( Operators::getChainsSize() );
+}
+
+static char Operators_getStrokesSize___doc__[] =
+".. staticmethod:: getStrokesSize()\n"
+"\n"
+" Returns the number of Strokes.\n"
+"\n"
+" :return: The number of Strokes.\n"
+" :rtype: int\n";
+
+static PyObject * Operators_getStrokesSize( BPy_Operators* self) {
+ return PyLong_FromLong( Operators::getStrokesSize() );
+}
+
+/*----------------------Operators instance definitions ----------------------------*/
+static PyMethodDef BPy_Operators_methods[] = {
+ {"select", ( PyCFunction ) Operators_select, METH_VARARGS | METH_STATIC, Operators_select___doc__},
+ {"chain", ( PyCFunction ) Operators_chain, METH_VARARGS | METH_STATIC, Operators_chain___doc__},
+ {"bidirectionalChain", ( PyCFunction ) Operators_bidirectionalChain, METH_VARARGS | METH_STATIC, Operators_bidirectionalChain___doc__},
+ {"sequentialSplit", ( PyCFunction ) Operators_sequentialSplit, METH_VARARGS | METH_STATIC, Operators_sequentialSplit___doc__},
+ {"recursiveSplit", ( PyCFunction ) Operators_recursiveSplit, METH_VARARGS | METH_STATIC, Operators_recursiveSplit___doc__},
+ {"sort", ( PyCFunction ) Operators_sort, METH_VARARGS | METH_STATIC, Operators_sort___doc__},
+ {"create", ( PyCFunction ) Operators_create, METH_VARARGS | METH_STATIC, Operators_create___doc__},
+ {"getViewEdgeFromIndex", ( PyCFunction ) Operators_getViewEdgeFromIndex, METH_VARARGS | METH_STATIC, Operators_getViewEdgeFromIndex___doc__},
+ {"getChainFromIndex", ( PyCFunction ) Operators_getChainFromIndex, METH_VARARGS | METH_STATIC, Operators_getChainFromIndex___doc__},
+ {"getStrokeFromIndex", ( PyCFunction ) Operators_getStrokeFromIndex, METH_VARARGS | METH_STATIC, Operators_getStrokeFromIndex___doc__},
+ {"getViewEdgesSize", ( PyCFunction ) Operators_getViewEdgesSize, METH_NOARGS | METH_STATIC, Operators_getViewEdgesSize___doc__},
+ {"getChainsSize", ( PyCFunction ) Operators_getChainsSize, METH_NOARGS | METH_STATIC, Operators_getChainsSize___doc__},
+ {"getStrokesSize", ( PyCFunction ) Operators_getStrokesSize, METH_NOARGS | METH_STATIC, Operators_getStrokesSize___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_Operators type definition ------------------------------*/
+
+PyTypeObject Operators_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Operators", /* tp_name */
+ sizeof(BPy_Operators), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)Operators___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ Operators___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_Operators_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/source/blender/freestyle/intern/python/BPy_Operators.h b/source/blender/freestyle/intern/python/BPy_Operators.h
new file mode 100644
index 00000000000..5e01d6bb1fe
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_Operators.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_OPERATORS_H
+#define FREESTYLE_PYTHON_OPERATORS_H
+
+#include <Python.h>
+
+#include "../stroke/Operators.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject Operators_Type;
+
+#define BPy_Operators_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Operators_Type) )
+
+/*---------------------------Python BPy_Operators structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+} BPy_Operators;
+
+/*---------------------------Python BPy_Operators visible prototypes-----------*/
+
+int Operators_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_OPERATORS_H */
diff --git a/source/blender/freestyle/intern/python/BPy_SShape.cpp b/source/blender/freestyle/intern/python/BPy_SShape.cpp
new file mode 100644
index 00000000000..65951182f10
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_SShape.cpp
@@ -0,0 +1,330 @@
+#include "BPy_SShape.h"
+
+#include "BPy_Convert.h"
+#include "BPy_BBox.h"
+#include "BPy_Id.h"
+#include "Interface0D/BPy_SVertex.h"
+#include "Interface1D/BPy_FEdge.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int SShape_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &SShape_Type ) < 0 )
+ return -1;
+
+ Py_INCREF( &SShape_Type );
+ PyModule_AddObject(module, "SShape", (PyObject *)&SShape_Type);
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char SShape___doc__[] =
+"Class to define a feature shape. It is the gathering of feature\n"
+"elements from an identified input shape.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: An SShape object.\n"
+" :type iBrother: :class:`SShape`\n";
+
+static int SShape___init__(BPy_SShape *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj = NULL;
+
+ if (! PyArg_ParseTuple(args, "|O!", &SShape_Type, &obj) )
+ return -1;
+
+ if( !obj ) {
+ self->ss = new SShape();
+
+ } else {
+ self->ss = new SShape(*( ((BPy_SShape *) obj)->ss ));
+ }
+ self->borrowed = 0;
+
+ return 0;
+}
+
+static void SShape___dealloc__(BPy_SShape *self)
+{
+ if( self->ss && !self->borrowed )
+ delete self->ss;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * SShape___repr__(BPy_SShape *self)
+{
+ return PyUnicode_FromFormat("SShape - address: %p", self->ss );
+}
+
+static char SShape_AddEdge___doc__[] =
+".. method:: AddEdge(iEdge)\n"
+"\n"
+" Adds an FEdge to the list of FEdges.\n"
+"\n"
+" :arg iEdge: An FEdge object.\n"
+" :type iEdge: :class:`FEdge`\n";
+
+static PyObject * SShape_AddEdge( BPy_SShape *self , PyObject *args) {
+ PyObject *py_fe = 0;
+
+ if(!( PyArg_ParseTuple(args, "O!", &FEdge_Type, &py_fe) ))
+ return NULL;
+
+ self->ss->AddEdge( ((BPy_FEdge *) py_fe)->fe );
+
+ Py_RETURN_NONE;
+}
+
+static char SShape_AddNewVertex___doc__[] =
+".. method:: AddNewVertex(iv)\n"
+"\n"
+" Adds an SVertex to the list of SVertex of this Shape. The SShape\n"
+" attribute of the SVertex is also set to this SShape.\n"
+"\n"
+" :arg iv: An SVertex object.\n"
+" :type iv: :class:`SVertex`\n";
+
+static PyObject * SShape_AddNewVertex( BPy_SShape *self , PyObject *args) {
+ PyObject *py_sv = 0;
+
+ if(!( PyArg_ParseTuple(args, "O!", &SVertex_Type, &py_sv) ))
+ return NULL;
+
+ self->ss->AddNewVertex( ((BPy_SVertex *) py_sv)->sv );
+
+ Py_RETURN_NONE;
+}
+
+static char SShape_setBBox___doc__[] =
+".. method:: setBBox(iBBox)\n"
+"\n"
+" Sets the bounding box of the SShape.\n"
+"\n"
+" :arg iBBox: The bounding box of the SShape.\n"
+" :type iBBox: :class:`BBox`\n";
+
+static PyObject * SShape_setBBox( BPy_SShape *self , PyObject *args) {
+ PyObject *py_bb = 0;
+
+ if(!( PyArg_ParseTuple(args, "O!", &BBox_Type, &py_bb) ))
+ return NULL;
+
+ self->ss->setBBox(*( ((BPy_BBox*) py_bb)->bb ));
+
+ Py_RETURN_NONE;
+}
+
+static char SShape_ComputeBBox___doc__[] =
+".. method:: ComputeBBox()\n"
+"\n"
+" Compute the bbox of the SShape.\n";
+
+static PyObject * SShape_ComputeBBox( BPy_SShape *self ) {
+ self->ss->ComputeBBox();
+
+ Py_RETURN_NONE;
+}
+
+static char SShape_bbox___doc__[] =
+".. method:: bbox()\n"
+"\n"
+" Returns the bounding box of the SShape.\n"
+"\n"
+" :return: the bounding box of the SShape.\n"
+" :rtype: :class:`BBox`\n";
+
+static PyObject * SShape_bbox( BPy_SShape *self ) {
+ BBox<Vec3r> bb( self->ss->bbox() );
+ return BPy_BBox_from_BBox( bb );
+}
+
+static char SShape_getVertexList___doc__[] =
+".. method:: getVertexList()\n"
+"\n"
+" Returns the list of vertices of the SShape.\n"
+"\n"
+" :return: The list of vertices objects.\n"
+" :rtype: List of :class:`SVertex` objects\n";
+
+static PyObject * SShape_getVertexList( BPy_SShape *self ) {
+ PyObject *py_vertices = PyList_New(0);
+
+ vector< SVertex * > vertices = self->ss->getVertexList();
+ vector< SVertex * >::iterator it;
+
+ for( it = vertices.begin(); it != vertices.end(); it++ ) {
+ PyList_Append( py_vertices, BPy_SVertex_from_SVertex(*( *it )) );
+ }
+
+ return py_vertices;
+}
+
+static char SShape_getEdgeList___doc__[] =
+".. method:: getEdgeList()\n"
+"\n"
+" Returns the list of edges of the SShape.\n"
+"\n"
+" :return: The list of edges of the SShape.\n"
+" :rtype: List of :class:`FEdge` objects\n";
+
+static PyObject * SShape_getEdgeList( BPy_SShape *self ) {
+ PyObject *py_edges = PyList_New(0);
+
+ vector< FEdge * > edges = self->ss->getEdgeList();
+ vector< FEdge * >::iterator it;
+
+ for( it = edges.begin(); it != edges.end(); it++ ) {
+ PyList_Append( py_edges, Any_BPy_FEdge_from_FEdge(*( *it )) );
+ }
+
+ return py_edges;
+}
+
+static char SShape_getId___doc__[] =
+".. method:: getId()\n"
+"\n"
+" Returns the Id of the SShape.\n"
+"\n"
+" :return: The Id of the SShape.\n"
+" :rtype: :class:`Id`\n";
+
+static PyObject * SShape_getId( BPy_SShape *self ) {
+ Id id( self->ss->getId() );
+ return BPy_Id_from_Id( id );
+}
+
+static char SShape_setId___doc__[] =
+".. method:: setId(id)\n"
+"\n"
+" Sets the Id of the SShape.\n"
+"\n"
+" :arg id: The Id of the SShape.\n"
+" :type id: :class:`Id`\n";
+
+static PyObject * SShape_setId( BPy_SShape *self , PyObject *args) {
+ PyObject *py_id;
+
+ if(!( PyArg_ParseTuple(args, "O!", &Id_Type, &py_id) ))
+ return NULL;
+
+ self->ss->setId(*( ((BPy_Id *) py_id)->id ));
+
+ Py_RETURN_NONE;
+}
+
+static char SShape_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the SShape.\n"
+"\n"
+" :return: The name string.\n"
+" :rtype: str\n";
+
+static PyObject * SShape_getName( BPy_SShape *self ) {
+ return PyUnicode_FromString( self->ss->getName().c_str() );
+}
+
+static char SShape_setName___doc__[] =
+".. method:: setName(name)\n"
+"\n"
+" Sets the name of the SShape.\n"
+"\n"
+" :arg name: A name string.\n"
+" :type name: str\n";
+
+static PyObject * SShape_setName( BPy_SShape *self , PyObject *args) {
+ char *s;
+
+ if(!( PyArg_ParseTuple(args, "s", &s) ))
+ return NULL;
+
+ self->ss->setName(s);
+
+ Py_RETURN_NONE;
+}
+
+// const Material & material (unsigned i) const
+// const vector< Material > & materials () const
+// void SetMaterials (const vector< Material > &iMaterials)
+
+/*----------------------SShape instance definitions ----------------------------*/
+static PyMethodDef BPy_SShape_methods[] = {
+ {"AddEdge", ( PyCFunction ) SShape_AddEdge, METH_VARARGS, SShape_AddEdge___doc__},
+ {"AddNewVertex", ( PyCFunction ) SShape_AddNewVertex, METH_VARARGS, SShape_AddNewVertex___doc__},
+ {"setBBox", ( PyCFunction ) SShape_setBBox, METH_VARARGS, SShape_setBBox___doc__},
+ {"ComputeBBox", ( PyCFunction ) SShape_ComputeBBox, METH_NOARGS, SShape_ComputeBBox___doc__},
+ {"bbox", ( PyCFunction ) SShape_bbox, METH_NOARGS, SShape_bbox___doc__},
+ {"getVertexList", ( PyCFunction ) SShape_getVertexList, METH_NOARGS, SShape_getVertexList___doc__},
+ {"getEdgeList", ( PyCFunction ) SShape_getEdgeList, METH_NOARGS, SShape_getEdgeList___doc__},
+ {"getId", ( PyCFunction ) SShape_getId, METH_NOARGS, SShape_getId___doc__},
+ {"setId", ( PyCFunction ) SShape_setId, METH_VARARGS, SShape_setId___doc__},
+ {"getName", ( PyCFunction ) SShape_getName, METH_NOARGS, SShape_getName___doc__},
+ {"setName", ( PyCFunction ) SShape_setName, METH_VARARGS, SShape_setName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_SShape type definition ------------------------------*/
+
+PyTypeObject SShape_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "SShape", /* tp_name */
+ sizeof(BPy_SShape), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)SShape___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)SShape___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ SShape___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_SShape_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)SShape___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_SShape.h b/source/blender/freestyle/intern/python/BPy_SShape.h
new file mode 100644
index 00000000000..e8d631f0538
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_SShape.h
@@ -0,0 +1,35 @@
+#ifndef FREESTYLE_PYTHON_SSHAPE_H
+#define FREESTYLE_PYTHON_SSHAPE_H
+
+#include <Python.h>
+
+#include "../view_map/Silhouette.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject SShape_Type;
+
+#define BPy_SShape_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &SShape_Type) )
+
+/*---------------------------Python BPy_SShape structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ SShape *ss;
+ int borrowed; /* non-zero if *ss is a borrowed object */
+} BPy_SShape;
+
+/*---------------------------Python BPy_SShape visible prototypes-----------*/
+
+int SShape_Init( PyObject *module );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_SSHAPE_H */
diff --git a/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp
new file mode 100644
index 00000000000..9e723d4236b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp
@@ -0,0 +1,662 @@
+#include "BPy_StrokeAttribute.h"
+
+#include "BPy_Convert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int StrokeAttribute_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &StrokeAttribute_Type ) < 0 )
+ return -1;
+ Py_INCREF( &StrokeAttribute_Type );
+ PyModule_AddObject(module, "StrokeAttribute", (PyObject *)&StrokeAttribute_Type);
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char StrokeAttribute___doc__[] =
+"Class to define a set of attributes associated with a :class:`StrokeVertex`.\n"
+"The attribute set stores the color, alpha and thickness values for a Stroke\n"
+"Vertex.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: A StrokeAttribute object.\n"
+" :type iBrother: :class:`StrokeAttribute`\n"
+"\n"
+".. method:: __init__(iRColor, iGColor, iBColor, iAlpha, iRThickness, iLThickness)\n"
+"\n"
+" Builds a stroke vertex attribute from a set of parameters.\n"
+"\n"
+" :arg iRColor: Red component of a stroke color.\n"
+" :type iRColor: float\n"
+" :arg iGColor: Green component of a stroke color.\n"
+" :type iGColor: float\n"
+" :arg iBColor: Blue component of a stroke color.\n"
+" :type iBColor: float\n"
+" :arg iAlpha: Alpha component of a stroke color.\n"
+" :type iAlpha: float\n"
+" :arg iRThickness: Stroke thickness on the right.\n"
+" :type iRThickness: float\n"
+" :arg iLThickness: Stroke thickness on the left.\n"
+" :type iLThickness: float\n"
+"\n"
+".. method:: __init__(a1, a2, t)\n"
+"\n"
+" Interpolation constructor. Builds a StrokeAttribute from two\n"
+" StrokeAttribute objects and an interpolation parameter.\n"
+"\n"
+" :arg a1: The first StrokeAttribute object.\n"
+" :type a1: :class:`StrokeAttribute`\n"
+" :arg a2: The second StrokeAttribute object.\n"
+" :type a2: :class:`StrokeAttribute`\n"
+" :arg t: The interpolation parameter.\n"
+" :type t: float\n";
+
+static int StrokeAttribute___init__(BPy_StrokeAttribute *self, PyObject *args, PyObject *kwds)
+{
+
+ PyObject *obj1 = 0, *obj2 = 0 , *obj3 = 0, *obj4 = 0, *obj5 = 0 , *obj6 = 0;
+
+ if (! PyArg_ParseTuple(args, "|OOOOOO", &obj1, &obj2, &obj3, &obj4, &obj5, &obj6) )
+ return -1;
+
+ if ( !obj1 ) {
+
+ self->sa = new StrokeAttribute();
+
+ } else if ( BPy_StrokeAttribute_Check(obj1) && !obj2 ) {
+
+ self->sa = new StrokeAttribute( *( ((BPy_StrokeAttribute *) obj1)->sa ) );
+
+ } else if ( BPy_StrokeAttribute_Check(obj1) &&
+ BPy_StrokeAttribute_Check(obj2) &&
+ PyFloat_Check(obj3) && !obj4 ) {
+
+ self->sa = new StrokeAttribute( *( ((BPy_StrokeAttribute *) obj1)->sa ),
+ *( ((BPy_StrokeAttribute *) obj2)->sa ),
+ PyFloat_AsDouble( obj3 ) );
+
+ } else if ( obj6 ) {
+
+ self->sa = new StrokeAttribute( PyFloat_AsDouble( obj1 ),
+ PyFloat_AsDouble( obj2 ),
+ PyFloat_AsDouble( obj3 ),
+ PyFloat_AsDouble( obj4 ),
+ PyFloat_AsDouble( obj5 ),
+ PyFloat_AsDouble( obj6 ) );
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid arguments");
+ return -1;
+ }
+
+ self->borrowed = 0;
+
+ return 0;
+
+}
+
+static void StrokeAttribute___dealloc__(BPy_StrokeAttribute* self)
+{
+ if( self->sa && !self->borrowed )
+ delete self->sa;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * StrokeAttribute___repr__(BPy_StrokeAttribute* self)
+{
+ stringstream repr("StrokeAttribute:");
+ repr << " r: " << self->sa->getColorR()
+ << " g: " << self->sa->getColorG()
+ << " b: " << self->sa->getColorB()
+ << " a: " << self->sa->getAlpha()
+ << " - R: " << self->sa->getThicknessR()
+ << " L: " << self->sa->getThicknessL();
+
+ return PyUnicode_FromString( repr.str().c_str() );
+}
+
+
+static char StrokeAttribute_getColorR___doc__[] =
+".. method:: getColorR()\n"
+"\n"
+" Returns the red component of the stroke color.\n"
+"\n"
+" :return: Red component of the stroke color.\n"
+" :rtype: float\n";
+
+static PyObject *StrokeAttribute_getColorR( BPy_StrokeAttribute *self ) {
+ return PyFloat_FromDouble( self->sa->getColorR() );
+}
+
+static char StrokeAttribute_getColorG___doc__[] =
+".. method:: getColorG()\n"
+"\n"
+" Returns the green component of the stroke color.\n"
+"\n"
+" :return: Green component of the stroke color.\n"
+" :rtype: float\n";
+
+static PyObject *StrokeAttribute_getColorG( BPy_StrokeAttribute *self ) {
+ return PyFloat_FromDouble( self->sa->getColorG() );
+}
+
+static char StrokeAttribute_getColorB___doc__[] =
+".. method:: getColorB()\n"
+"\n"
+" Returns the blue component of the stroke color.\n"
+"\n"
+" :return: Blue component of the stroke color.\n"
+" :rtype: float\n";
+
+static PyObject *StrokeAttribute_getColorB( BPy_StrokeAttribute *self ) {
+ return PyFloat_FromDouble( self->sa->getColorB() );
+}
+
+static char StrokeAttribute_getColorRGB___doc__[] =
+".. method:: getColorRGB()\n"
+"\n"
+" Returns the RGB components of the stroke color.\n"
+"\n"
+" :return: RGB components of the stroke color.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static PyObject *StrokeAttribute_getColorRGB( BPy_StrokeAttribute *self ) {
+ Vec3f v( self->sa->getColorRGB() );
+ return Vector_from_Vec3f( v );
+}
+
+static char StrokeAttribute_getAlpha___doc__[] =
+".. method:: getAlpha()\n"
+"\n"
+" Returns the alpha component of the stroke color.\n"
+"\n"
+" :return: Alpha component of the stroke color.\n"
+" :rtype: float\n";
+
+static PyObject *StrokeAttribute_getAlpha( BPy_StrokeAttribute *self ) {
+ return PyFloat_FromDouble( self->sa->getAlpha() );
+}
+
+static char StrokeAttribute_getThicknessR___doc__[] =
+".. method:: getThicknessR()\n"
+"\n"
+" Returns the thickness on the right of the vertex when following\n"
+" the stroke.\n"
+"\n"
+" :return: The thickness on the right of the vertex.\n"
+" :rtype: float\n";
+
+static PyObject *StrokeAttribute_getThicknessR( BPy_StrokeAttribute *self ) {
+ return PyFloat_FromDouble( self->sa->getThicknessR() );
+}
+
+static char StrokeAttribute_getThicknessL___doc__[] =
+".. method:: getThicknessL()\n"
+"\n"
+" Returns the thickness on the left of the vertex when following\n"
+" the stroke.\n"
+"\n"
+" :return: The thickness on the left of the vertex.\n"
+" :rtype: float\n";
+
+static PyObject *StrokeAttribute_getThicknessL( BPy_StrokeAttribute *self ) {
+ return PyFloat_FromDouble( self->sa->getThicknessL() );
+}
+
+static char StrokeAttribute_getThicknessRL___doc__[] =
+".. method:: getThicknessRL()\n"
+"\n"
+" Returns the thickness on the right and on the left of the vertex\n"
+" when following the stroke.\n"
+"\n"
+" :return: A two-dimensional vector. The first value is the\n"
+" thickness on the right of the vertex when following the stroke,\n"
+" and the second one is the thickness on the left.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static PyObject *StrokeAttribute_getThicknessRL( BPy_StrokeAttribute *self ) {
+ Vec2f v( self->sa->getThicknessRL() );
+ return Vector_from_Vec2f( v );
+}
+
+static char StrokeAttribute_isVisible___doc__[] =
+".. method:: isVisible()\n"
+"\n"
+" Returns true if the StrokeVertex is visible, false otherwise.\n"
+"\n"
+" :return: True if the StrokeVertex is visible, false otherwise.\n"
+" :rtype: bool\n";
+
+static PyObject *StrokeAttribute_isVisible( BPy_StrokeAttribute *self ) {
+ return PyBool_from_bool( self->sa->isVisible() );
+}
+
+static char StrokeAttribute_getAttributeReal___doc__[] =
+".. method:: getAttributeReal(iName)\n"
+"\n"
+" Returns an attribute of float type.\n"
+"\n"
+" :arg iName: The name of the attribute.\n"
+" :type iName: str\n"
+" :return: The attribute value.\n"
+" :rtype: float\n";
+
+static PyObject *StrokeAttribute_getAttributeReal( BPy_StrokeAttribute *self, PyObject *args ) {
+ char *attr;
+
+ if(!( PyArg_ParseTuple(args, "s", &attr) ))
+ return NULL;
+
+ double a = self->sa->getAttributeReal( attr );
+ return PyFloat_FromDouble( a );
+}
+
+static char StrokeAttribute_getAttributeVec2f___doc__[] =
+".. method:: getAttributeVec2f(iName)\n"
+"\n"
+" Returns an attribute of two-dimensional vector type.\n"
+"\n"
+" :arg iName: The name of the attribute.\n"
+" :type iName: str\n"
+" :return: The attribute value.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static PyObject *StrokeAttribute_getAttributeVec2f( BPy_StrokeAttribute *self, PyObject *args ) {
+ char *attr;
+
+ if(!( PyArg_ParseTuple(args, "s", &attr) ))
+ return NULL;
+
+ Vec2f a = self->sa->getAttributeVec2f( attr );
+ return Vector_from_Vec2f( a );
+}
+
+static char StrokeAttribute_getAttributeVec3f___doc__[] =
+".. method:: getAttributeVec3f(iName)\n"
+"\n"
+" Returns an attribute of three-dimensional vector type.\n"
+"\n"
+" :arg iName: The name of the attribute.\n"
+" :type iName: str\n"
+" :return: The attribute value.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static PyObject *StrokeAttribute_getAttributeVec3f( BPy_StrokeAttribute *self, PyObject *args ) {
+ char *attr;
+
+ if(!( PyArg_ParseTuple(args, "s", &attr) ))
+ return NULL;
+
+ Vec3f a = self->sa->getAttributeVec3f( attr );
+ return Vector_from_Vec3f( a );
+}
+
+static char StrokeAttribute_isAttributeAvailableReal___doc__[] =
+".. method:: isAttributeAvailableReal(iName)\n"
+"\n"
+" Checks whether the attribute iName of float type is available.\n"
+"\n"
+" :arg iName: The name of the attribute.\n"
+" :type iName: str\n"
+" :return: True if the attribute is availbale.\n"
+" :rtype: bool\n";
+
+static PyObject *StrokeAttribute_isAttributeAvailableReal( BPy_StrokeAttribute *self, PyObject *args ) {
+ char *attr;
+
+ if(!( PyArg_ParseTuple(args, "s", &attr) ))
+ return NULL;
+
+ return PyBool_from_bool( self->sa->isAttributeAvailableReal( attr ) );
+}
+
+static char StrokeAttribute_isAttributeAvailableVec2f___doc__[] =
+".. method:: isAttributeAvailableVec2f(iName)\n"
+"\n"
+" Checks whether the attribute iName of two-dimensional vector type\n"
+" is available.\n"
+"\n"
+" :arg iName: The name of the attribute.\n"
+" :type iName: str\n"
+" :return: True if the attribute is availbale.\n"
+" :rtype: bool\n";
+
+static PyObject *StrokeAttribute_isAttributeAvailableVec2f( BPy_StrokeAttribute *self, PyObject *args ) {
+ char *attr;
+
+ if(!( PyArg_ParseTuple(args, "s", &attr) ))
+ return NULL;
+
+ return PyBool_from_bool( self->sa->isAttributeAvailableVec2f( attr ) );
+}
+
+static char StrokeAttribute_isAttributeAvailableVec3f___doc__[] =
+".. method:: isAttributeAvailableVec3f(iName)\n"
+"\n"
+" Checks whether the attribute iName of three-dimensional vector\n"
+" type is available.\n"
+"\n"
+" :arg iName: The name of the attribute.\n"
+" :type iName: str\n"
+" :return: True if the attribute is availbale.\n"
+" :rtype: bool\n";
+
+static PyObject *StrokeAttribute_isAttributeAvailableVec3f( BPy_StrokeAttribute *self, PyObject *args ) {
+ char *attr;
+
+ if(!( PyArg_ParseTuple(args, "s", &attr) ))
+ return NULL;
+
+ return PyBool_from_bool( self->sa->isAttributeAvailableVec3f( attr ) );
+}
+
+
+static char StrokeAttribute_setColor___doc__[] =
+".. method:: setColor(r, g, b)\n"
+"\n"
+" Sets the stroke color.\n"
+"\n"
+" :arg r: Red component of the stroke color.\n"
+" :type r: float\n"
+" :arg g: Green component of the stroke color.\n"
+" :type g: float\n"
+" :arg b: Blue component of the stroke color.\n"
+" :type b: float\n"
+"\n"
+".. method:: setColor(iRGB)\n"
+"\n"
+" Sets the stroke color.\n"
+"\n"
+" :arg iRGB: The new RGB values.\n"
+" :type iRGB: :class:`mathutils.Vector`, list or tuple of 3 real numbers\n";
+
+static PyObject * StrokeAttribute_setColor( BPy_StrokeAttribute *self, PyObject *args ) {
+ PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0 ;
+
+ if(!( PyArg_ParseTuple(args, "O|OO", &obj1, &obj2, &obj3) ))
+ return NULL;
+
+ if( obj1 && !obj2 && !obj3 ){
+
+ Vec3f *v = Vec3f_ptr_from_PyObject(obj1);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 3D vector (either a list of 3 elements or Vector)");
+ return NULL;
+ }
+ self->sa->setColor( *v );
+ delete v;
+
+ } else if( obj1 && obj2 && obj3 ){
+
+ self->sa->setColor( PyFloat_AsDouble(obj1),
+ PyFloat_AsDouble(obj2),
+ PyFloat_AsDouble(obj3) );
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid arguments");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char StrokeAttribute_setAlpha___doc__[] =
+".. method:: setAlpha(alpha)\n"
+"\n"
+" Sets the alpha component of the stroke color.\n"
+"\n"
+" :arg alpha: The new alpha value.\n"
+" :type alpha: float\n";
+
+static PyObject * StrokeAttribute_setAlpha( BPy_StrokeAttribute *self, PyObject *args ){
+ float f = 0;
+
+ if(!( PyArg_ParseTuple(args, "f", &f) ))
+ return NULL;
+
+ self->sa->setAlpha( f );
+ Py_RETURN_NONE;
+}
+
+static char StrokeAttribute_setThickness___doc__[] =
+".. method:: setThickness(tr, tl)\n"
+"\n"
+" Sets the stroke thickness.\n"
+"\n"
+" :arg tr: The thickness on the right of the vertex when following\n"
+" the stroke.\n"
+" :type tr: float\n"
+" :arg tl: The thickness on the left of the vertex when following\n"
+" the stroke.\n"
+" :type tl: float\n"
+"\n"
+".. method:: setThickness(tRL)\n"
+"\n"
+" Sets the stroke thickness.\n"
+"\n"
+" :arg tRL: The thickness on the right and on the left of the vertex\n"
+" when following the stroke.\n"
+" :type tRL: :class:`mathutils.Vector`, list or tuple of 2 real numbers\n";
+
+static PyObject * StrokeAttribute_setThickness( BPy_StrokeAttribute *self, PyObject *args ) {
+ PyObject *obj1 = 0, *obj2 = 0;
+
+ if(!( PyArg_ParseTuple(args, "O|O", &obj1, &obj2) ))
+ return NULL;
+
+ if( obj1 && !obj2 ){
+
+ Vec2f *v = Vec2f_ptr_from_PyObject(obj1);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 2D vector (either a list of 2 elements or Vector)");
+ return NULL;
+ }
+ self->sa->setThickness( *v );
+ delete v;
+
+ } else if( obj1 && obj2 ){
+
+ self->sa->setThickness( PyFloat_AsDouble(obj1),
+ PyFloat_AsDouble(obj2) );
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid arguments");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char StrokeAttribute_setVisible___doc__[] =
+".. method:: setVisible(iVisible)\n"
+"\n"
+" Sets the visibility flag. True means the StrokeVertex is visible.\n"
+"\n"
+" :arg iVisible: True if the StrokeVertex is visible.\n"
+" :type iVisible: bool\n";
+
+static PyObject * StrokeAttribute_setVisible( BPy_StrokeAttribute *self, PyObject *args ) {
+ PyObject *py_b;
+
+ if(!( PyArg_ParseTuple(args, "O", &py_b) ))
+ return NULL;
+
+ self->sa->setVisible( bool_from_PyBool(py_b) );
+
+ Py_RETURN_NONE;
+}
+
+static char StrokeAttribute_setAttributeReal___doc__[] =
+".. method:: setAttributeReal(iName, att)\n"
+"\n"
+" Adds a user-defined attribute of float type. If there is no\n"
+" attribute of the given name, it is added. Otherwise, the new value\n"
+" replaces the old one.\n"
+"\n"
+" :arg iName: The name of the attribute.\n"
+" :type iName: str\n"
+" :arg att: The attribute value.\n"
+" :type att: float\n";
+
+static PyObject * StrokeAttribute_setAttributeReal( BPy_StrokeAttribute *self, PyObject *args ) {
+ char *s = 0;
+ double d = 0;
+
+ if(!( PyArg_ParseTuple(args, "sd", &s, &d) ))
+ return NULL;
+
+ self->sa->setAttributeReal( s, d );
+ Py_RETURN_NONE;
+}
+
+static char StrokeAttribute_setAttributeVec2f___doc__[] =
+".. method:: setAttributeVec2f(iName, att)\n"
+"\n"
+" Adds a user-defined attribute of two-dimensional vector type. If\n"
+" there is no attribute of the given name, it is added. Otherwise,\n"
+" the new value replaces the old one.\n"
+"\n"
+" :arg iName: The name of the attribute.\n"
+" :type iName: str\n"
+" :arg att: The attribute value.\n"
+" :type att: :class:`mathutils.Vector`, list or tuple of 2 real numbers\n";
+
+static PyObject * StrokeAttribute_setAttributeVec2f( BPy_StrokeAttribute *self, PyObject *args ) {
+ char *s;
+ PyObject *obj = 0;
+
+ if(!( PyArg_ParseTuple(args, "sO", &s, &obj) ))
+ return NULL;
+ Vec2f *v = Vec2f_ptr_from_PyObject(obj);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 2 must be a 2D vector (either a list of 2 elements or Vector)");
+ return NULL;
+ }
+ self->sa->setAttributeVec2f( s, *v );
+ delete v;
+
+ Py_RETURN_NONE;
+}
+
+static char StrokeAttribute_setAttributeVec3f___doc__[] =
+".. method:: setAttributeVec3f(iName, att)\n"
+"\n"
+" Adds a user-defined attribute of three-dimensional vector type.\n"
+" If there is no attribute of the given name, it is added.\n"
+" Otherwise, the new value replaces the old one.\n"
+"\n"
+" :arg iName: The name of the attribute.\n"
+" :type iName: str\n"
+" :arg att: The attribute value.\n"
+" :type att: :class:`mathutils.Vector`, list or tuple of 3 real numbers\n";
+
+static PyObject * StrokeAttribute_setAttributeVec3f( BPy_StrokeAttribute *self, PyObject *args ) {
+ char *s;
+ PyObject *obj = 0;
+
+ if(!( PyArg_ParseTuple(args, "sO", &s, &obj) ))
+ return NULL;
+ Vec3f *v = Vec3f_ptr_from_PyObject(obj);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 2 must be a 3D vector (either a list of 3 elements or Vector)");
+ return NULL;
+ }
+ self->sa->setAttributeVec3f( s, *v );
+ delete v;
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------StrokeAttribute instance definitions ----------------------------*/
+static PyMethodDef BPy_StrokeAttribute_methods[] = {
+ {"getColorR", ( PyCFunction ) StrokeAttribute_getColorR, METH_NOARGS, StrokeAttribute_getColorR___doc__},
+ {"getColorG", ( PyCFunction ) StrokeAttribute_getColorG, METH_NOARGS, StrokeAttribute_getColorG___doc__},
+ {"getColorB", ( PyCFunction ) StrokeAttribute_getColorB, METH_NOARGS, StrokeAttribute_getColorB___doc__},
+ {"getColorRGB", ( PyCFunction ) StrokeAttribute_getColorRGB, METH_NOARGS, StrokeAttribute_getColorRGB___doc__},
+ {"getAlpha", ( PyCFunction ) StrokeAttribute_getAlpha, METH_NOARGS, StrokeAttribute_getAlpha___doc__},
+ {"getThicknessR", ( PyCFunction ) StrokeAttribute_getThicknessR, METH_NOARGS, StrokeAttribute_getThicknessR___doc__},
+ {"getThicknessL", ( PyCFunction ) StrokeAttribute_getThicknessL, METH_NOARGS, StrokeAttribute_getThicknessL___doc__},
+ {"getThicknessRL", ( PyCFunction ) StrokeAttribute_getThicknessRL, METH_NOARGS, StrokeAttribute_getThicknessRL___doc__},
+ {"isVisible", ( PyCFunction ) StrokeAttribute_isVisible, METH_NOARGS, StrokeAttribute_isVisible___doc__},
+ {"getAttributeReal", ( PyCFunction ) StrokeAttribute_getAttributeReal, METH_VARARGS, StrokeAttribute_getAttributeReal___doc__},
+ {"getAttributeVec2f", ( PyCFunction ) StrokeAttribute_getAttributeVec2f, METH_VARARGS, StrokeAttribute_getAttributeVec2f___doc__},
+ {"getAttributeVec3f", ( PyCFunction ) StrokeAttribute_getAttributeVec3f, METH_VARARGS, StrokeAttribute_getAttributeVec3f___doc__},
+ {"isAttributeAvailableReal", ( PyCFunction ) StrokeAttribute_isAttributeAvailableReal, METH_VARARGS, StrokeAttribute_isAttributeAvailableReal___doc__},
+ {"isAttributeAvailableVec2f", ( PyCFunction ) StrokeAttribute_isAttributeAvailableVec2f, METH_VARARGS, StrokeAttribute_isAttributeAvailableVec2f___doc__},
+ {"isAttributeAvailableVec3f", ( PyCFunction ) StrokeAttribute_isAttributeAvailableVec3f, METH_VARARGS, StrokeAttribute_isAttributeAvailableVec3f___doc__},
+ {"setColor", ( PyCFunction ) StrokeAttribute_setColor, METH_VARARGS, StrokeAttribute_setColor___doc__},
+ {"setAlpha", ( PyCFunction ) StrokeAttribute_setAlpha, METH_VARARGS, StrokeAttribute_setAlpha___doc__},
+ {"setThickness", ( PyCFunction ) StrokeAttribute_setThickness, METH_VARARGS, StrokeAttribute_setThickness___doc__},
+ {"setVisible", ( PyCFunction ) StrokeAttribute_setVisible, METH_VARARGS, StrokeAttribute_setVisible___doc__},
+ {"setAttributeReal", ( PyCFunction ) StrokeAttribute_setAttributeReal, METH_VARARGS, StrokeAttribute_setAttributeReal___doc__},
+ {"setAttributeVec2f", ( PyCFunction ) StrokeAttribute_setAttributeVec2f, METH_VARARGS, StrokeAttribute_setAttributeVec2f___doc__},
+ {"setAttributeVec3f", ( PyCFunction ) StrokeAttribute_setAttributeVec3f, METH_VARARGS, StrokeAttribute_setAttributeVec3f___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_StrokeAttribute type definition ------------------------------*/
+
+PyTypeObject StrokeAttribute_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "StrokeAttribute", /* tp_name */
+ sizeof(BPy_StrokeAttribute), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)StrokeAttribute___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)StrokeAttribute___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ StrokeAttribute___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_StrokeAttribute_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)StrokeAttribute___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/source/blender/freestyle/intern/python/BPy_StrokeAttribute.h b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.h
new file mode 100644
index 00000000000..51e18c0a96f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.h
@@ -0,0 +1,35 @@
+#ifndef FREESTYLE_PYTHON_STROKEATTRIBUTE_H
+#define FREESTYLE_PYTHON_STROKEATTRIBUTE_H
+
+#include <Python.h>
+
+#include "../stroke/Stroke.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject StrokeAttribute_Type;
+
+#define BPy_StrokeAttribute_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &StrokeAttribute_Type) )
+
+/*---------------------------Python BPy_StrokeAttribute structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ StrokeAttribute *sa;
+ int borrowed; /* non-zero if *sa is a borrowed reference */
+} BPy_StrokeAttribute;
+
+/*---------------------------Python BPy_StrokeAttribute visible prototypes-----------*/
+
+int StrokeAttribute_Init( PyObject *module );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_STROKEATTRIBUTE_H */
diff --git a/source/blender/freestyle/intern/python/BPy_StrokeShader.cpp b/source/blender/freestyle/intern/python/BPy_StrokeShader.cpp
new file mode 100644
index 00000000000..202e33c3231
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_StrokeShader.cpp
@@ -0,0 +1,297 @@
+#include "BPy_StrokeShader.h"
+
+#include "BPy_Convert.h"
+#include "Interface1D/BPy_Stroke.h"
+
+#include "StrokeShader/BPy_BackboneStretcherShader.h"
+#include "StrokeShader/BPy_BezierCurveShader.h"
+#include "StrokeShader/BPy_CalligraphicShader.h"
+#include "StrokeShader/BPy_ColorNoiseShader.h"
+#include "StrokeShader/BPy_ColorVariationPatternShader.h"
+#include "StrokeShader/BPy_ConstantColorShader.h"
+#include "StrokeShader/BPy_ConstantThicknessShader.h"
+#include "StrokeShader/BPy_ConstrainedIncreasingThicknessShader.h"
+#include "StrokeShader/BPy_fstreamShader.h"
+#include "StrokeShader/BPy_GuidingLinesShader.h"
+#include "StrokeShader/BPy_IncreasingColorShader.h"
+#include "StrokeShader/BPy_IncreasingThicknessShader.h"
+#include "StrokeShader/BPy_PolygonalizationShader.h"
+#include "StrokeShader/BPy_SamplingShader.h"
+#include "StrokeShader/BPy_SmoothingShader.h"
+#include "StrokeShader/BPy_SpatialNoiseShader.h"
+#include "StrokeShader/BPy_streamShader.h"
+#include "StrokeShader/BPy_StrokeTextureShader.h"
+#include "StrokeShader/BPy_TextureAssignerShader.h"
+#include "StrokeShader/BPy_ThicknessNoiseShader.h"
+#include "StrokeShader/BPy_ThicknessVariationPatternShader.h"
+#include "StrokeShader/BPy_TipRemoverShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int StrokeShader_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &StrokeShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &StrokeShader_Type );
+ PyModule_AddObject(module, "StrokeShader", (PyObject *)&StrokeShader_Type);
+
+ if( PyType_Ready( &BackboneStretcherShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &BackboneStretcherShader_Type );
+ PyModule_AddObject(module, "BackboneStretcherShader", (PyObject *)&BackboneStretcherShader_Type);
+
+ if( PyType_Ready( &BezierCurveShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &BezierCurveShader_Type );
+ PyModule_AddObject(module, "BezierCurveShader", (PyObject *)&BezierCurveShader_Type);
+
+ if( PyType_Ready( &CalligraphicShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &CalligraphicShader_Type );
+ PyModule_AddObject(module, "CalligraphicShader", (PyObject *)&CalligraphicShader_Type);
+
+ if( PyType_Ready( &ColorNoiseShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ColorNoiseShader_Type );
+ PyModule_AddObject(module, "ColorNoiseShader", (PyObject *)&ColorNoiseShader_Type);
+
+ if( PyType_Ready( &ColorVariationPatternShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ColorVariationPatternShader_Type );
+ PyModule_AddObject(module, "ColorVariationPatternShader", (PyObject *)&ColorVariationPatternShader_Type);
+
+ if( PyType_Ready( &ConstantColorShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ConstantColorShader_Type );
+ PyModule_AddObject(module, "ConstantColorShader", (PyObject *)&ConstantColorShader_Type);
+
+ if( PyType_Ready( &ConstantThicknessShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ConstantThicknessShader_Type );
+ PyModule_AddObject(module, "ConstantThicknessShader", (PyObject *)&ConstantThicknessShader_Type);
+
+ if( PyType_Ready( &ConstrainedIncreasingThicknessShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ConstrainedIncreasingThicknessShader_Type );
+ PyModule_AddObject(module, "ConstrainedIncreasingThicknessShader", (PyObject *)&ConstrainedIncreasingThicknessShader_Type);
+
+ if( PyType_Ready( &fstreamShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &fstreamShader_Type );
+ PyModule_AddObject(module, "fstreamShader", (PyObject *)&fstreamShader_Type);
+
+ if( PyType_Ready( &GuidingLinesShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GuidingLinesShader_Type );
+ PyModule_AddObject(module, "GuidingLinesShader", (PyObject *)&GuidingLinesShader_Type);
+
+ if( PyType_Ready( &IncreasingColorShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &IncreasingColorShader_Type );
+ PyModule_AddObject(module, "IncreasingColorShader", (PyObject *)&IncreasingColorShader_Type);
+
+ if( PyType_Ready( &IncreasingThicknessShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &IncreasingThicknessShader_Type );
+ PyModule_AddObject(module, "IncreasingThicknessShader", (PyObject *)&IncreasingThicknessShader_Type);
+
+ if( PyType_Ready( &PolygonalizationShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &PolygonalizationShader_Type );
+ PyModule_AddObject(module, "PolygonalizationShader", (PyObject *)&PolygonalizationShader_Type);
+
+ if( PyType_Ready( &SamplingShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &SamplingShader_Type );
+ PyModule_AddObject(module, "SamplingShader", (PyObject *)&SamplingShader_Type);
+
+ if( PyType_Ready( &SmoothingShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &SmoothingShader_Type );
+ PyModule_AddObject(module, "SmoothingShader", (PyObject *)&SmoothingShader_Type);
+
+ if( PyType_Ready( &SpatialNoiseShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &SpatialNoiseShader_Type );
+ PyModule_AddObject(module, "SpatialNoiseShader", (PyObject *)&SpatialNoiseShader_Type);
+
+ if( PyType_Ready( &streamShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &streamShader_Type );
+ PyModule_AddObject(module, "streamShader", (PyObject *)&streamShader_Type);
+
+ if( PyType_Ready( &StrokeTextureShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &StrokeTextureShader_Type );
+ PyModule_AddObject(module, "StrokeTextureShader", (PyObject *)&StrokeTextureShader_Type);
+
+ if( PyType_Ready( &TextureAssignerShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &TextureAssignerShader_Type );
+ PyModule_AddObject(module, "TextureAssignerShader", (PyObject *)&TextureAssignerShader_Type);
+
+ if( PyType_Ready( &ThicknessNoiseShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ThicknessNoiseShader_Type );
+ PyModule_AddObject(module, "ThicknessNoiseShader", (PyObject *)&ThicknessNoiseShader_Type);
+
+ if( PyType_Ready( &ThicknessVariationPatternShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ThicknessVariationPatternShader_Type );
+ PyModule_AddObject(module, "ThicknessVariationPatternShader", (PyObject *)&ThicknessVariationPatternShader_Type);
+
+ if( PyType_Ready( &TipRemoverShader_Type ) < 0 )
+ return -1;
+ Py_INCREF( &TipRemoverShader_Type );
+ PyModule_AddObject(module, "TipRemoverShader", (PyObject *)&TipRemoverShader_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char StrokeShader___doc__[] =
+"Base class for stroke shaders. Any stroke shader must inherit from\n"
+"this class and overload the shade() method. A StrokeShader is\n"
+"designed to modify stroke attributes such as thickness, color,\n"
+"geometry, texture, blending mode, and so on. The basic way for this\n"
+"operation is to iterate over the stroke vertices of the :class:`Stroke`\n"
+"and to modify the :class:`StrokeAttribute` of each vertex. Here is a\n"
+"code example of such an iteration::\n"
+"\n"
+" it = ioStroke.strokeVerticesBegin()\n"
+" while it.isEnd() == 0:\n"
+" att = it.getObject().attribute()\n"
+" ## perform here any attribute modification\n"
+" it.increment()\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n";
+
+static int StrokeShader___init__(BPy_StrokeShader *self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->ss = new StrokeShader();
+ self->ss->py_ss = (PyObject *) self;
+ return 0;
+}
+
+static void StrokeShader___dealloc__(BPy_StrokeShader* self)
+{
+ if (self->ss)
+ delete self->ss;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+
+static PyObject * StrokeShader___repr__(BPy_StrokeShader* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->ss->getName().c_str(), self->ss );
+}
+
+static char StrokeShader_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of this stroke shader.\n"
+"\n"
+" :return: The name of this stroke shader.\n"
+" :rtype: str\n";
+
+static PyObject * StrokeShader_getName( BPy_StrokeShader *self, PyObject *args)
+{
+ return PyUnicode_FromString( self->ss->getName().c_str() );
+}
+
+static char StrokeShader_shade___doc__[] =
+".. method:: shade(s)\n"
+"\n"
+" The shading method. Must be overloaded by inherited classes.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static PyObject *StrokeShader_shade( BPy_StrokeShader *self , PyObject *args) {
+ PyObject *py_s = 0;
+
+ if(!( PyArg_ParseTuple(args, "O!", &Stroke_Type, &py_s) ))
+ return NULL;
+
+ if( typeid(*(self->ss)) == typeid(StrokeShader) ) {
+ PyErr_SetString(PyExc_TypeError, "shade method not properly overridden");
+ return NULL;
+ }
+ if (self->ss->shade(*( ((BPy_Stroke *) py_s)->s )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->ss->getName() + " shade method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+/*----------------------StrokeShader instance definitions ----------------------------*/
+static PyMethodDef BPy_StrokeShader_methods[] = {
+ {"getName", ( PyCFunction ) StrokeShader_getName, METH_NOARGS, StrokeShader_getName___doc__},
+ {"shade", ( PyCFunction ) StrokeShader_shade, METH_VARARGS, StrokeShader_shade___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_StrokeShader type definition ------------------------------*/
+
+PyTypeObject StrokeShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "StrokeShader", /* tp_name */
+ sizeof(BPy_StrokeShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)StrokeShader___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)StrokeShader___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ StrokeShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_StrokeShader_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)StrokeShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_StrokeShader.h b/source/blender/freestyle/intern/python/BPy_StrokeShader.h
new file mode 100644
index 00000000000..baa31a3100e
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_StrokeShader.h
@@ -0,0 +1,40 @@
+#ifndef FREESTYLE_PYTHON_STROKESHADER_H
+#define FREESTYLE_PYTHON_STROKESHADER_H
+
+#include <Python.h>
+
+#include "../system/FreestyleConfig.h"
+
+using namespace std;
+
+#include "../stroke/StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject StrokeShader_Type;
+
+#define BPy_StrokeShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &StrokeShader_Type) )
+
+/*---------------------------Python BPy_StrokeShader structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ StrokeShader *ss;
+} BPy_StrokeShader;
+
+/*---------------------------Python BPy_StrokeShader visible prototypes-----------*/
+
+int StrokeShader_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_STROKESHADER_H */
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp b/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp
new file mode 100644
index 00000000000..9cb855f32ae
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.cpp
@@ -0,0 +1,126 @@
+#include "BPy_UnaryFunction0D.h"
+
+#include "UnaryFunction0D/BPy_UnaryFunction0DDouble.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DEdgeNature.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DFloat.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DId.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DMaterial.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DUnsigned.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DVec2f.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DVec3f.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DViewShape.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int UnaryFunction0D_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction0D_Type );
+ PyModule_AddObject(module, "UnaryFunction0D", (PyObject *)&UnaryFunction0D_Type);
+
+ UnaryFunction0DDouble_Init( module );
+ UnaryFunction0DEdgeNature_Init( module );
+ UnaryFunction0DFloat_Init( module );
+ UnaryFunction0DId_Init( module );
+ UnaryFunction0DMaterial_Init( module );
+ UnaryFunction0DUnsigned_Init( module );
+ UnaryFunction0DVec2f_Init( module );
+ UnaryFunction0DVec3f_Init( module );
+ UnaryFunction0DVectorViewShape_Init( module );
+ UnaryFunction0DViewShape_Init( module );
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction0D___doc__[] =
+"Base class for Unary Functions (functors) working on\n"
+":class:`Interface0DIterator`. A unary function will be used by\n"
+"invoking __call__() on an Interface0DIterator. In Python, several\n"
+"different subclasses of UnaryFunction0D are used depending on the\n"
+"types of functors' return values. For example, you would inherit from\n"
+"a :class:`UnaryFunction0DDouble` if you wish to define a function that\n"
+"returns a double value. Available UnaryFunction0D subclasses are:\n"
+"\n"
+"* :class:`UnaryFunction0DDouble`\n"
+"* :class:`UnaryFunction0DEdgeNature`\n"
+"* :class:`UnaryFunction0DFloat`\n"
+"* :class:`UnaryFunction0DId`\n"
+"* :class:`UnaryFunction0DMaterial`\n"
+"* :class:`UnaryFunction0DUnsigned`\n"
+"* :class:`UnaryFunction0DVec2f`\n"
+"* :class:`UnaryFunction0DVec3f`\n"
+"* :class:`UnaryFunction0DVectorViewShape`\n"
+"* :class:`UnaryFunction0DViewShape`\n";
+
+static void UnaryFunction0D___dealloc__(BPy_UnaryFunction0D* self)
+{
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+
+static PyObject * UnaryFunction0D___repr__(BPy_UnaryFunction0D* self)
+{
+ return PyUnicode_FromString("UnaryFunction0D");
+}
+
+/*-----------------------BPy_UnaryFunction0D type definition ------------------------------*/
+
+PyTypeObject UnaryFunction0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction0D", /* tp_name */
+ sizeof(BPy_UnaryFunction0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction0D___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction0D___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.h b/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.h
new file mode 100644
index 00000000000..6d61c336662
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_UnaryFunction0D.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION0D_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION0D_H
+
+#include <Python.h>
+
+#include "../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject UnaryFunction0D_Type;
+
+#define BPy_UnaryFunction0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction0D_Type) )
+
+/*---------------------------Python BPy_UnaryFunction0D structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ PyObject *py_uf0D;
+} BPy_UnaryFunction0D;
+
+/*---------------------------Python BPy_UnaryFunction0D visible prototypes-----------*/
+
+int UnaryFunction0D_Init( PyObject *module );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION0D_H */
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp b/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp
new file mode 100644
index 00000000000..f4de9edb962
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.cpp
@@ -0,0 +1,117 @@
+#include "BPy_UnaryFunction1D.h"
+
+#include "UnaryFunction1D/BPy_UnaryFunction1DDouble.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DFloat.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DUnsigned.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DVec2f.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DVec3f.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DVoid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int UnaryFunction1D_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction1D_Type );
+ PyModule_AddObject(module, "UnaryFunction1D", (PyObject *)&UnaryFunction1D_Type);
+
+ UnaryFunction1DDouble_Init( module );
+ UnaryFunction1DEdgeNature_Init( module );
+ UnaryFunction1DFloat_Init( module );
+ UnaryFunction1DUnsigned_Init( module );
+ UnaryFunction1DVec2f_Init( module );
+ UnaryFunction1DVec3f_Init( module );
+ UnaryFunction1DVectorViewShape_Init( module );
+ UnaryFunction1DVoid_Init( module );
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction1D___doc__[] =
+"Base class for Unary Functions (functors) working on\n"
+":class:`Interface1D`. A unary function will be used by invoking\n"
+"__call__() on an Interface1D. In Python, several different subclasses\n"
+"of UnaryFunction1D are used depending on the types of functors' return\n"
+"values. For example, you would inherit from a\n"
+":class:`UnaryFunction1DDouble` if you wish to define a function that\n"
+"returns a double value. Available UnaryFunction1D subclasses are:\n"
+"\n"
+"* :class:`UnaryFunction1DDouble`\n"
+"* :class:`UnaryFunction1DEdgeNature`\n"
+"* :class:`UnaryFunction1DFloat`\n"
+"* :class:`UnaryFunction1DUnsigned`\n"
+"* :class:`UnaryFunction1DVec2f`\n"
+"* :class:`UnaryFunction1DVec3f`\n"
+"* :class:`UnaryFunction1DVectorViewShape`\n"
+"* :class:`UnaryFunction1DVoid`\n";
+
+static void UnaryFunction1D___dealloc__(BPy_UnaryFunction1D* self)
+{
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * UnaryFunction1D___repr__(BPy_UnaryFunction1D* self)
+{
+ return PyUnicode_FromString("UnaryFunction1D");
+}
+
+/*-----------------------BPy_UnaryFunction1D type definition ------------------------------*/
+
+PyTypeObject UnaryFunction1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction1D", /* tp_name */
+ sizeof(BPy_UnaryFunction1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction1D___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction1D___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.h b/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.h
new file mode 100644
index 00000000000..cb9df18ab75
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_UnaryFunction1D.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION1D_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION1D_H
+
+#include <Python.h>
+
+#include "../view_map/Functions1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject UnaryFunction1D_Type;
+
+#define BPy_UnaryFunction1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction1D_Type) )
+
+/*---------------------------Python BPy_UnaryFunction1D structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ PyObject *py_uf1D;
+} BPy_UnaryFunction1D;
+
+/*---------------------------Python BPy_UnaryFunction1D visible prototypes-----------*/
+
+int UnaryFunction1D_Init( PyObject *module );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION1D_H */
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryPredicate0D.cpp b/source/blender/freestyle/intern/python/BPy_UnaryPredicate0D.cpp
new file mode 100644
index 00000000000..81f39ef7ab7
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_UnaryPredicate0D.cpp
@@ -0,0 +1,184 @@
+#include "BPy_UnaryPredicate0D.h"
+
+#include "BPy_Convert.h"
+#include "Iterator/BPy_Interface0DIterator.h"
+#include "UnaryPredicate0D/BPy_FalseUP0D.h"
+#include "UnaryPredicate0D/BPy_TrueUP0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int UnaryPredicate0D_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryPredicate0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryPredicate0D_Type );
+ PyModule_AddObject(module, "UnaryPredicate0D", (PyObject *)&UnaryPredicate0D_Type);
+
+ if( PyType_Ready( &FalseUP0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &FalseUP0D_Type );
+ PyModule_AddObject(module, "FalseUP0D", (PyObject *)&FalseUP0D_Type);
+
+ if( PyType_Ready( &TrueUP0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &TrueUP0D_Type );
+ PyModule_AddObject(module, "TrueUP0D", (PyObject *)&TrueUP0D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryPredicate0D___doc__[] =
+"Base class for unary predicates that work on\n"
+":class:`Interface0DIterator`. A UnaryPredicate0D is a functor that\n"
+"evaluates a condition on an Interface0DIterator and returns true or\n"
+"false depending on whether this condition is satisfied or not. The\n"
+"UnaryPredicate0D is used by invoking its __call__() method. Any\n"
+"inherited class must overload the __call__() method.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Must be overload by inherited classes.\n"
+"\n"
+" :arg it: The Interface0DIterator pointing onto the Interface0D at\n"
+" which we wish to evaluate the predicate.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: True if the condition is satisfied, false otherwise.\n"
+" :rtype: bool\n";
+
+static int UnaryPredicate0D___init__(BPy_UnaryPredicate0D *self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->up0D = new UnaryPredicate0D();
+ self->up0D->py_up0D = (PyObject *) self;
+ return 0;
+}
+
+static void UnaryPredicate0D___dealloc__(BPy_UnaryPredicate0D* self)
+{
+ if (self->up0D)
+ delete self->up0D;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * UnaryPredicate0D___repr__(BPy_UnaryPredicate0D* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->up0D->getName().c_str(), self->up0D );
+}
+
+static char UnaryPredicate0D_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the UnaryPredicate0D.\n"
+"\n"
+" :return: The name of the UnaryPredicate0D.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryPredicate0D_getName( BPy_UnaryPredicate0D *self )
+{
+ return PyUnicode_FromString( self->up0D->getName().c_str() );
+}
+
+static PyObject * UnaryPredicate0D___call__( BPy_UnaryPredicate0D *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *py_if0D_it;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if( !PyArg_ParseTuple(args, "O!", &Interface0DIterator_Type, &py_if0D_it) )
+ return NULL;
+
+ Interface0DIterator *if0D_it = ((BPy_Interface0DIterator *) py_if0D_it)->if0D_it;
+
+ if( !if0D_it ) {
+ string msg(self->up0D->getName() + " has no Interface0DIterator");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ return NULL;
+ }
+ if( typeid(*(self->up0D)) == typeid(UnaryPredicate0D) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->up0D->operator()(*if0D_it) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->up0D->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return PyBool_from_bool( self->up0D->result );
+}
+
+/*----------------------UnaryPredicate0D instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryPredicate0D_methods[] = {
+ {"getName", ( PyCFunction ) UnaryPredicate0D_getName, METH_NOARGS, UnaryPredicate0D_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryPredicate0D type definition ------------------------------*/
+
+PyTypeObject UnaryPredicate0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryPredicate0D", /* tp_name */
+ sizeof(BPy_UnaryPredicate0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryPredicate0D___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryPredicate0D___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryPredicate0D___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryPredicate0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryPredicate0D_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryPredicate0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryPredicate0D.h b/source/blender/freestyle/intern/python/BPy_UnaryPredicate0D.h
new file mode 100644
index 00000000000..9f9bb0c1003
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_UnaryPredicate0D.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_UNARYPREDICATE0D_H
+#define FREESTYLE_PYTHON_UNARYPREDICATE0D_H
+
+#include <Python.h>
+
+#include "../stroke/Predicates0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject UnaryPredicate0D_Type;
+
+#define BPy_UnaryPredicate0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryPredicate0D_Type) )
+
+/*---------------------------Python BPy_UnaryPredicate0D structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ UnaryPredicate0D *up0D;
+} BPy_UnaryPredicate0D;
+
+/*---------------------------Python BPy_UnaryPredicate0D visible prototypes-----------*/
+
+int UnaryPredicate0D_Init( PyObject *module );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYPREDICATE0D_H */
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryPredicate1D.cpp b/source/blender/freestyle/intern/python/BPy_UnaryPredicate1D.cpp
new file mode 100644
index 00000000000..a0c59484486
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_UnaryPredicate1D.cpp
@@ -0,0 +1,236 @@
+#include "BPy_UnaryPredicate1D.h"
+
+#include "BPy_Convert.h"
+#include "BPy_Interface1D.h"
+
+#include "UnaryPredicate1D/BPy_ContourUP1D.h"
+#include "UnaryPredicate1D/BPy_DensityLowerThanUP1D.h"
+#include "UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.h"
+#include "UnaryPredicate1D/BPy_EqualToTimeStampUP1D.h"
+#include "UnaryPredicate1D/BPy_ExternalContourUP1D.h"
+#include "UnaryPredicate1D/BPy_FalseUP1D.h"
+#include "UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.h"
+#include "UnaryPredicate1D/BPy_ShapeUP1D.h"
+#include "UnaryPredicate1D/BPy_TrueUP1D.h"
+#include "UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int UnaryPredicate1D_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryPredicate1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryPredicate1D_Type );
+ PyModule_AddObject(module, "UnaryPredicate1D", (PyObject *)&UnaryPredicate1D_Type);
+
+ if( PyType_Ready( &ContourUP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ContourUP1D_Type );
+ PyModule_AddObject(module, "ContourUP1D", (PyObject *)&ContourUP1D_Type);
+
+ if( PyType_Ready( &DensityLowerThanUP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &DensityLowerThanUP1D_Type );
+ PyModule_AddObject(module, "DensityLowerThanUP1D", (PyObject *)&DensityLowerThanUP1D_Type);
+
+ if( PyType_Ready( &EqualToChainingTimeStampUP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &EqualToChainingTimeStampUP1D_Type );
+ PyModule_AddObject(module, "EqualToChainingTimeStampUP1D", (PyObject *)&EqualToChainingTimeStampUP1D_Type);
+
+ if( PyType_Ready( &EqualToTimeStampUP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &EqualToTimeStampUP1D_Type );
+ PyModule_AddObject(module, "EqualToTimeStampUP1D", (PyObject *)&EqualToTimeStampUP1D_Type);
+
+ if( PyType_Ready( &ExternalContourUP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ExternalContourUP1D_Type );
+ PyModule_AddObject(module, "ExternalContourUP1D", (PyObject *)&ExternalContourUP1D_Type);
+
+ if( PyType_Ready( &FalseUP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &FalseUP1D_Type );
+ PyModule_AddObject(module, "FalseUP1D", (PyObject *)&FalseUP1D_Type);
+
+ if( PyType_Ready( &QuantitativeInvisibilityUP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &QuantitativeInvisibilityUP1D_Type );
+ PyModule_AddObject(module, "QuantitativeInvisibilityUP1D", (PyObject *)&QuantitativeInvisibilityUP1D_Type);
+
+ if( PyType_Ready( &ShapeUP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ShapeUP1D_Type );
+ PyModule_AddObject(module, "ShapeUP1D", (PyObject *)&ShapeUP1D_Type);
+
+ if( PyType_Ready( &TrueUP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &TrueUP1D_Type );
+ PyModule_AddObject(module, "TrueUP1D", (PyObject *)&TrueUP1D_Type);
+
+ if( PyType_Ready( &WithinImageBoundaryUP1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &WithinImageBoundaryUP1D_Type );
+ PyModule_AddObject(module, "WithinImageBoundaryUP1D", (PyObject *)&WithinImageBoundaryUP1D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryPredicate1D___doc__[] =
+"Base class for unary predicates that work on :class:`Interface1D`. A\n"
+"UnaryPredicate1D is a functor that evaluates a condition on a\n"
+"Interface1D and returns true or false depending on whether this\n"
+"condition is satisfied or not. The UnaryPredicate1D is used by\n"
+"invoking its __call__() method. Any inherited class must overload the\n"
+"__call__() method.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Must be overload by inherited classes.\n"
+"\n"
+" :arg inter: The Interface1D on which we wish to evaluate the predicate.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: True if the condition is satisfied, false otherwise.\n"
+" :rtype: bool\n";
+
+static int UnaryPredicate1D___init__(BPy_UnaryPredicate1D *self, PyObject *args, PyObject *kwds)
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->up1D = new UnaryPredicate1D();
+ self->up1D->py_up1D = (PyObject *) self;
+ return 0;
+}
+
+static void UnaryPredicate1D___dealloc__(BPy_UnaryPredicate1D* self)
+{
+ if (self->up1D)
+ delete self->up1D;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * UnaryPredicate1D___repr__(BPy_UnaryPredicate1D* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->up1D->getName().c_str(), self->up1D );
+}
+
+static char UnaryPredicate1D_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the string of the name of the UnaryPredicate1D.\n"
+"\n"
+" Reimplemented in TrueUP1D, FalseUP1D, QuantitativeInvisibilityUP1D,\n"
+" ContourUP1D, ExternalContourUP1D, EqualToTimeStampUP1D,\n"
+" EqualToChainingTimeStampUP1D, ShapeUP1D, and DensityLowerThanUP1D.\n"
+"\n"
+" :return: \n"
+" :rtype: str\n";
+
+static PyObject * UnaryPredicate1D_getName( BPy_UnaryPredicate1D *self, PyObject *args)
+{
+ return PyUnicode_FromString( self->up1D->getName().c_str() );
+}
+
+static PyObject * UnaryPredicate1D___call__( BPy_UnaryPredicate1D *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *py_if1D;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if( !PyArg_ParseTuple(args, "O!", &Interface1D_Type, &py_if1D) )
+ return NULL;
+
+ Interface1D *if1D = ((BPy_Interface1D *) py_if1D)->if1D;
+
+ if( !if1D ) {
+ string msg(self->up1D->getName() + " has no Interface0DIterator");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ return NULL;
+ }
+ if( typeid(*(self->up1D)) == typeid(UnaryPredicate1D) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if( self->up1D->operator()(*if1D) < 0 ) {
+ if (!PyErr_Occurred()) {
+ string msg(self->up1D->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return PyBool_from_bool( self->up1D->result );
+}
+
+/*----------------------UnaryPredicate1D instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryPredicate1D_methods[] = {
+ {"getName", ( PyCFunction ) UnaryPredicate1D_getName, METH_NOARGS, UnaryPredicate1D_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryPredicate1D type definition ------------------------------*/
+
+PyTypeObject UnaryPredicate1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryPredicate1D", /* tp_name */
+ sizeof(BPy_UnaryPredicate1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryPredicate1D___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryPredicate1D___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryPredicate1D___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryPredicate1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryPredicate1D_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryPredicate1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/source/blender/freestyle/intern/python/BPy_UnaryPredicate1D.h b/source/blender/freestyle/intern/python/BPy_UnaryPredicate1D.h
new file mode 100644
index 00000000000..75953e7977b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_UnaryPredicate1D.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_UNARYPREDICATE1D_H
+#define FREESTYLE_PYTHON_UNARYPREDICATE1D_H
+
+#include <Python.h>
+
+#include "../stroke/Predicates1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject UnaryPredicate1D_Type;
+
+#define BPy_UnaryPredicate1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryPredicate1D_Type) )
+
+/*---------------------------Python BPy_UnaryPredicate1D structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ UnaryPredicate1D *up1D;
+} BPy_UnaryPredicate1D;
+
+/*---------------------------Python BPy_UnaryPredicate1D visible prototypes-----------*/
+
+int UnaryPredicate1D_Init( PyObject *module );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYPREDICATE1D_H */
diff --git a/source/blender/freestyle/intern/python/BPy_ViewMap.cpp b/source/blender/freestyle/intern/python/BPy_ViewMap.cpp
new file mode 100644
index 00000000000..c9667103e5a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_ViewMap.cpp
@@ -0,0 +1,195 @@
+#include "BPy_ViewMap.h"
+
+#include "BPy_Convert.h"
+#include "BPy_BBox.h"
+#include "Interface1D/BPy_FEdge.h"
+#include "Interface1D/BPy_ViewEdge.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int ViewMap_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &ViewMap_Type ) < 0 )
+ return -1;
+
+ Py_INCREF( &ViewMap_Type );
+ PyModule_AddObject(module, "ViewMap", (PyObject *)&ViewMap_Type);
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ViewMap___doc__[] =
+"Class defining the ViewMap.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n";
+
+static int ViewMap___init__(BPy_ViewMap *self, PyObject *args, PyObject *kwds)
+{
+ self->vm = new ViewMap();
+ return 0;
+}
+
+static void ViewMap___dealloc__(BPy_ViewMap *self)
+{
+ if( self->vm )
+ delete self->vm;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * ViewMap___repr__(BPy_ViewMap *self)
+{
+ return PyUnicode_FromFormat("ViewMap - address: %p", self->vm );
+}
+
+static char ViewMap_getClosestViewEdge___doc__[] =
+".. method:: getClosestViewEdge(x, y)\n"
+"\n"
+" Gets the ViewEdge nearest to the 2D point specified as arguments.\n"
+"\n"
+" :arg x: X coordinate of a 2D point.\n"
+" :type x: float\n"
+" :arg y: Y coordinate of a 2D point.\n"
+" :type y: float\n"
+" :return: The ViewEdge nearest to the specified 2D point.\n"
+" :rtype: :class:`ViewEdge`\n";
+
+static PyObject * ViewMap_getClosestViewEdge( BPy_ViewMap *self , PyObject *args) {
+ double x, y;
+
+ if(!( PyArg_ParseTuple(args, "dd", &x, &y) ))
+ return NULL;
+
+ ViewEdge *ve = const_cast<ViewEdge *>( self->vm->getClosestViewEdge(x,y) );
+ if( ve )
+ return BPy_ViewEdge_from_ViewEdge(*ve);
+
+ Py_RETURN_NONE;
+}
+
+static char ViewMap_getClosestFEdge___doc__[] =
+".. method:: getClosestFEdge(x, y)\n"
+"\n"
+" Gets the FEdge nearest to the 2D point specified as arguments.\n"
+"\n"
+" :arg x: X coordinate of a 2D point.\n"
+" :type x: float\n"
+" :arg y: Y coordinate of a 2D point.\n"
+" :type y: float\n"
+" :return: The FEdge nearest to the specified 2D point.\n"
+" :rtype: :class:`FEdge`\n";
+
+static PyObject * ViewMap_getClosestFEdge( BPy_ViewMap *self , PyObject *args) {
+ double x, y;
+
+ if(!( PyArg_ParseTuple(args, "dd", &x, &y) ))
+ return NULL;
+
+ FEdge *fe = const_cast<FEdge *>( self->vm->getClosestFEdge(x,y) );
+ if( fe )
+ return Any_BPy_FEdge_from_FEdge(*fe);
+
+ Py_RETURN_NONE;
+}
+
+static char ViewMap_getScene3dBBox___doc__[] =
+".. method:: getScene3dBBox()\n"
+"\n"
+" Returns the scene 3D bounding box.\n"
+"\n"
+" :return: The scene 3D bounding box.\n"
+" :rtype: :class:`BBox`\n";
+
+static PyObject * ViewMap_getScene3dBBox( BPy_ViewMap *self , PyObject *args) {
+ BBox<Vec3r> bb( self->vm->getScene3dBBox() );
+ return BPy_BBox_from_BBox( bb );
+}
+
+static char ViewMap_setScene3dBBox___doc__[] =
+".. method:: setScene3dBBox(bbox)\n"
+"\n"
+" Sets the scene 3D bounding box.\n"
+"\n"
+" :arg bbox: The scene 3D bounding box.\n"
+" :type bbox: :class:`BBox`\n";
+
+static PyObject * ViewMap_setScene3dBBox( BPy_ViewMap *self , PyObject *args) {
+ PyObject *py_bb = 0;
+
+ if(!( PyArg_ParseTuple(args, "O!", &BBox_Type, &py_bb) ))
+ return NULL;
+
+ self->vm->setScene3dBBox(*( ((BPy_BBox *) py_bb)->bb ));
+
+ Py_RETURN_NONE;
+}
+
+// static ViewMap *getInstance ();
+
+/*---------------------- BPy_ViewShape instance definitions ----------------------------*/
+static PyMethodDef BPy_ViewMap_methods[] = {
+ {"getClosestViewEdge", ( PyCFunction ) ViewMap_getClosestViewEdge, METH_VARARGS, ViewMap_getClosestViewEdge___doc__},
+ {"getClosestFEdge", ( PyCFunction ) ViewMap_getClosestFEdge, METH_VARARGS, ViewMap_getClosestFEdge___doc__},
+ {"getScene3dBBox", ( PyCFunction ) ViewMap_getScene3dBBox, METH_NOARGS, ViewMap_getScene3dBBox___doc__},
+ {"setScene3dBBox", ( PyCFunction ) ViewMap_setScene3dBBox, METH_VARARGS, ViewMap_setScene3dBBox___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_ViewMap type definition ------------------------------*/
+
+PyTypeObject ViewMap_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ViewMap", /* tp_name */
+ sizeof(BPy_ViewMap), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)ViewMap___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)ViewMap___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ViewMap___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_ViewMap_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ViewMap___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_ViewMap.h b/source/blender/freestyle/intern/python/BPy_ViewMap.h
new file mode 100644
index 00000000000..943aeb718fc
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_ViewMap.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_VIEWMAP_H
+#define FREESTYLE_PYTHON_VIEWMAP_H
+
+#include <Python.h>
+
+#include "../view_map/ViewMap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject ViewMap_Type;
+
+#define BPy_ViewMap_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ViewMap_Type) )
+
+/*---------------------------Python BPy_ViewMap structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ ViewMap *vm;
+} BPy_ViewMap;
+
+/*---------------------------Python BPy_ViewMap visible prototypes-----------*/
+
+int ViewMap_Init( PyObject *module );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_VIEWMAP_H */
diff --git a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
new file mode 100644
index 00000000000..eebfa88773c
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
@@ -0,0 +1,353 @@
+#include "BPy_ViewShape.h"
+
+#include "BPy_Convert.h"
+#include "Interface0D/BPy_ViewVertex.h"
+#include "Interface1D/BPy_ViewEdge.h"
+#include "BPy_SShape.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+int ViewShape_Init( PyObject *module )
+{
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &ViewShape_Type ) < 0 )
+ return -1;
+
+ Py_INCREF( &ViewShape_Type );
+ PyModule_AddObject(module, "ViewShape", (PyObject *)&ViewShape_Type);
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ViewShape___doc__[] =
+"Class gathering the elements of the ViewMap (i.e., :class:`ViewVertex`\n"
+"and :class:`ViewEdge`) that are issued from the same input shape.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: A ViewShape object.\n"
+" :type iBrother: :class:`ViewShape`\n"
+"\n"
+".. method:: __init__(iSShape)\n"
+"\n"
+" Builds a ViewShape from an SShape.\n"
+"\n"
+" :arg iSShape: An SShape object.\n"
+" :type iSShape: :class:`SShape`\n";
+
+static int ViewShape___init__(BPy_ViewShape *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if (! PyArg_ParseTuple(args, "|O", &obj) )
+ return -1;
+
+ if( !obj ) {
+ self->vs = new ViewShape();
+
+ } else if( BPy_SShape_Check(obj) ) {
+ self->vs = new ViewShape( ((BPy_SShape *) obj)->ss );
+
+ } else if( BPy_ViewShape_Check(obj) ) {
+ self->vs = new ViewShape(*( ((BPy_ViewShape *) obj)->vs ));
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument");
+ return -1;
+ }
+ self->borrowed = 0;
+
+ return 0;
+}
+
+static void ViewShape___dealloc__(BPy_ViewShape *self)
+{
+ if( self->vs && !self->borrowed )
+ delete self->vs;
+ Py_TYPE(self)->tp_free((PyObject*)self);
+}
+
+static PyObject * ViewShape___repr__(BPy_ViewShape *self)
+{
+ return PyUnicode_FromFormat("ViewShape - address: %p", self->vs );
+}
+
+static char ViewShape_sshape___doc__[] =
+".. method:: sshape()\n"
+"\n"
+" Returns the SShape on top of which this ViewShape is built.\n"
+"\n"
+" :return: The SShape on top of which this ViewShape is built.\n"
+" :rtype: :class:`SShape`\n";
+
+static PyObject * ViewShape_sshape( BPy_ViewShape *self ) {
+ return BPy_SShape_from_SShape( *(self->vs->sshape()) );
+}
+
+static char ViewShape_vertices___doc__[] =
+".. method:: vertices()\n"
+"\n"
+" Returns the list of ViewVertex objects contained in this ViewShape.\n"
+"\n"
+" :return: The list of ViewVertex objects.\n"
+" :rtype: List of :class:`ViewVertex` objects\n";
+
+static PyObject * ViewShape_vertices( BPy_ViewShape *self ) {
+ PyObject *py_vertices = PyList_New(0);
+
+ vector< ViewVertex * > vertices = self->vs->vertices();
+ vector< ViewVertex * >::iterator it;
+
+ for( it = vertices.begin(); it != vertices.end(); it++ ) {
+ PyList_Append( py_vertices, Any_BPy_ViewVertex_from_ViewVertex(*( *it )) );
+ }
+
+ return py_vertices;
+}
+
+static char ViewShape_edges___doc__[] =
+".. method:: edges()\n"
+"\n"
+" Returns the list of ViewEdge objects contained in this ViewShape.\n"
+"\n"
+" :return: The list of ViewEdge objects.\n"
+" :rtype: List of :class:`ViewEdge` objects\n";
+
+static PyObject * ViewShape_edges( BPy_ViewShape *self ) {
+ PyObject *py_edges = PyList_New(0);
+
+ vector< ViewEdge * > edges = self->vs->edges();
+ vector< ViewEdge * >::iterator it;
+
+ for( it = edges.begin(); it != edges.end(); it++ ) {
+ PyList_Append( py_edges, BPy_ViewEdge_from_ViewEdge(*( *it )) );
+ }
+
+ return py_edges;
+}
+
+static char ViewShape_getId___doc__[] =
+".. method:: getId()\n"
+"\n"
+" Returns the ViewShape id.\n"
+"\n"
+" :return: An Id object.\n"
+" :rtype: :class:`Id`\n";
+
+static PyObject * ViewShape_getId( BPy_ViewShape *self ) {
+ Id id( self->vs->getId() );
+ return BPy_Id_from_Id( id );
+}
+
+static char ViewShape_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the ViewShape.\n"
+"\n"
+" :return: The name string.\n"
+" :rtype: str\n";
+
+static PyObject * ViewShape_getName( BPy_ViewShape *self ) {
+ return PyUnicode_FromString( self->vs->getName().c_str() );
+}
+
+static char ViewShape_setSShape___doc__[] =
+".. method:: setSShape(iSShape)\n"
+"\n"
+" Sets the SShape on top of which the ViewShape is built.\n"
+"\n"
+" :arg iSShape: An SShape object.\n"
+" :type iSShape: :class:`SShape`\n";
+
+static PyObject * ViewShape_setSShape( BPy_ViewShape *self , PyObject *args) {
+ PyObject *py_ss = 0;
+
+ if(!( PyArg_ParseTuple(args, "O!", &SShape_Type, &py_ss) ))
+ return NULL;
+
+ self->vs->setSShape( ((BPy_SShape *) py_ss)->ss );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewShape_setVertices___doc__[] =
+".. method:: setVertices(iVertices)\n"
+"\n"
+" Sets the list of ViewVertex objects contained in this ViewShape.\n"
+"\n"
+" :arg iVertices: The list of ViewVertex objects.\n"
+" :type iVertices: List of :class:`ViewVertex` objects\n";
+
+static PyObject * ViewShape_setVertices( BPy_ViewShape *self , PyObject *args) {
+ PyObject *list = 0;
+ PyObject *tmp;
+
+ if(!( PyArg_ParseTuple(args, "O!", &PyList_Type, &list) ))
+ return NULL;
+
+ vector< ViewVertex *> v;
+
+ for( int i=0; i < PyList_Size(list); i++ ) {
+ tmp = PyList_GetItem(list, i);
+ if( BPy_ViewVertex_Check(tmp) )
+ v.push_back( ((BPy_ViewVertex *) tmp)->vv );
+ else {
+ PyErr_SetString(PyExc_TypeError, "argument must be list of ViewVertex objects");
+ return NULL;
+ }
+ }
+
+ self->vs->setVertices( v );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewShape_setEdges___doc__[] =
+".. method:: setEdges(iEdges)\n"
+"\n"
+" Sets the list of ViewEdge objects contained in this ViewShape.\n"
+"\n"
+" :arg iEdges: The list of ViewEdge objects.\n"
+" :type iEdges: List of :class:`ViewEdge` objects.\n";
+
+static PyObject * ViewShape_setEdges( BPy_ViewShape *self , PyObject *args) {
+ PyObject *list = 0;
+ PyObject *tmp;
+
+ if(!( PyArg_ParseTuple(args, "O!", &PyList_Type, &list) ))
+ return NULL;
+
+ vector<ViewEdge *> v;
+
+ for( int i=0; i < PyList_Size(list); i++ ) {
+ tmp = PyList_GetItem(list, i);
+ if( BPy_ViewEdge_Check(tmp) )
+ v.push_back( ((BPy_ViewEdge *) tmp)->ve );
+ else {
+ PyErr_SetString(PyExc_TypeError, "argument must be list of ViewEdge objects");
+ return NULL;
+ }
+ }
+
+ self->vs->setEdges( v );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewShape_AddEdge___doc__[] =
+".. method:: AddEdge(iEdge)\n"
+"\n"
+" Adds a ViewEdge to the list of ViewEdge objects.\n"
+"\n"
+" :arg iEdge: A ViewEdge object.\n"
+" :type iEdge: :class:`ViewEdge`\n";
+
+static PyObject * ViewShape_AddEdge( BPy_ViewShape *self , PyObject *args) {
+ PyObject *py_ve = 0;
+
+ if(!( PyArg_ParseTuple(args, "O!", &ViewEdge_Type, &py_ve) ))
+ return NULL;
+
+ self->vs->AddEdge( ((BPy_ViewEdge *) py_ve)->ve );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewShape_AddVertex___doc__[] =
+".. method:: AddVertex(iVertex)\n"
+"\n"
+" Adds a ViewVertex to the list of the ViewVertex objects.\n"
+"\n"
+" :arg iVertex: A ViewVertex object.\n"
+" :type iVertex: :class:`ViewVertex`\n";
+
+static PyObject * ViewShape_AddVertex( BPy_ViewShape *self , PyObject *args) {
+ PyObject *py_vv = 0;
+
+ if(!( PyArg_ParseTuple(args, "O!", &ViewVertex_Type, &py_vv) ))
+ return NULL;
+
+ self->vs->AddVertex( ((BPy_ViewVertex *) py_vv)->vv );
+
+ Py_RETURN_NONE;
+}
+
+// virtual ViewShape * duplicate ()
+
+/*---------------------- BPy_ViewShape instance definitions ----------------------------*/
+static PyMethodDef BPy_ViewShape_methods[] = {
+ {"sshape", ( PyCFunction ) ViewShape_sshape, METH_NOARGS, ViewShape_sshape___doc__},
+ {"vertices", ( PyCFunction ) ViewShape_vertices, METH_NOARGS, ViewShape_vertices___doc__},
+ {"edges", ( PyCFunction ) ViewShape_edges, METH_NOARGS, ViewShape_edges___doc__},
+ {"getId", ( PyCFunction ) ViewShape_getId, METH_NOARGS, ViewShape_getId___doc__},
+ {"getName", ( PyCFunction ) ViewShape_getName, METH_NOARGS, ViewShape_getName___doc__},
+ {"setSShape", ( PyCFunction ) ViewShape_setSShape, METH_VARARGS, ViewShape_setSShape___doc__},
+ {"setVertices", ( PyCFunction ) ViewShape_setVertices, METH_VARARGS, ViewShape_setVertices___doc__},
+ {"setEdges", ( PyCFunction ) ViewShape_setEdges, METH_VARARGS, ViewShape_setEdges___doc__},
+ {"AddEdge", ( PyCFunction ) ViewShape_AddEdge, METH_VARARGS, ViewShape_AddEdge___doc__},
+ {"AddVertex", ( PyCFunction ) ViewShape_AddVertex, METH_VARARGS, ViewShape_AddVertex___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_ViewShape type definition ------------------------------*/
+
+PyTypeObject ViewShape_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ViewShape", /* tp_name */
+ sizeof(BPy_ViewShape), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)ViewShape___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)ViewShape___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ViewShape___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_ViewShape_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ViewShape___init__, /* tp_init */
+ 0, /* tp_alloc */
+ PyType_GenericNew, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BPy_ViewShape.h b/source/blender/freestyle/intern/python/BPy_ViewShape.h
new file mode 100644
index 00000000000..1850ec8f13a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BPy_ViewShape.h
@@ -0,0 +1,35 @@
+#ifndef FREESTYLE_PYTHON_VIEWSHAPE_H
+#define FREESTYLE_PYTHON_VIEWSHAPE_H
+
+#include <Python.h>
+
+#include "../view_map/ViewMap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+extern PyTypeObject ViewShape_Type;
+
+#define BPy_ViewShape_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ViewShape_Type) )
+
+/*---------------------------Python BPy_ViewShape structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ ViewShape *vs;
+ int borrowed; /* non-zero if *vs a borrowed object */
+} BPy_ViewShape;
+
+/*---------------------------Python BPy_ViewShape visible prototypes-----------*/
+
+int ViewShape_Init( PyObject *module );
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_VIEWSHAPE_H */
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_FalseBP1D.cpp b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_FalseBP1D.cpp
new file mode 100644
index 00000000000..ad2885fb95a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_FalseBP1D.cpp
@@ -0,0 +1,79 @@
+#include "BPy_FalseBP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char FalseBP1D___doc__[] =
+"Class hierarchy: :class:`BinaryPredicate1D` > :class:`FalseBP1D`\n"
+"\n"
+".. method:: __call__(inter1, inter2)\n"
+"\n"
+" Always returns false.\n"
+"\n"
+" :arg inter1: The first Interface1D object.\n"
+" :type inter1: :class:`Interface1D`\n"
+" :arg inter2: The second Interface1D object.\n"
+" :type inter2: :class:`Interface1D`\n"
+" :return: False.\n"
+" :rtype: bool\n";
+
+static int FalseBP1D___init__( BPy_FalseBP1D* self, PyObject *args )
+{
+ if(!( PyArg_ParseTuple(args, "") ))
+ return -1;
+ self->py_bp1D.bp1D = new Predicates1D::FalseBP1D();
+ return 0;
+}
+
+/*-----------------------BPy_FalseBP1D type definition ------------------------------*/
+PyTypeObject FalseBP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "FalseBP1D", /* tp_name */
+ sizeof(BPy_FalseBP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ FalseBP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &BinaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)FalseBP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_FalseBP1D.h b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_FalseBP1D.h
new file mode 100644
index 00000000000..a8d4aad88aa
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_FalseBP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_FALSEBP1D_H
+#define FREESTYLE_PYTHON_FALSEBP1D_H
+
+#include "../BPy_BinaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject FalseBP1D_Type;
+
+#define BPy_FalseBP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &FalseBP1D_Type) )
+
+/*---------------------------Python BPy_FalseBP1D structure definition----------*/
+typedef struct {
+ BPy_BinaryPredicate1D py_bp1D;
+} BPy_FalseBP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_FALSEBP1D_H */
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_Length2DBP1D.cpp b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_Length2DBP1D.cpp
new file mode 100644
index 00000000000..1a59091c453
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_Length2DBP1D.cpp
@@ -0,0 +1,81 @@
+#include "BPy_Length2DBP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Length2DBP1D___doc__[] =
+"Class hierarchy: :class:`BinaryPredicate1D` > :class:`Length2DBP1D`\n"
+"\n"
+".. method:: __call__(inter1, inter2)\n"
+"\n"
+" Returns true if the 2D length of inter1 is less than the 2D length\n"
+" of inter2.\n"
+"\n"
+" :arg inter1: The first Interface1D object.\n"
+" :type inter1: :class:`Interface1D`\n"
+" :arg inter2: The second Interface1D object.\n"
+" :type inter2: :class:`Interface1D`\n"
+" :return: True or false.\n"
+" :rtype: bool\n";
+
+static int Length2DBP1D___init__( BPy_Length2DBP1D* self, PyObject *args )
+{
+ if(!( PyArg_ParseTuple(args, "") ))
+ return -1;
+ self->py_bp1D.bp1D = new Predicates1D::Length2DBP1D();
+ return 0;
+}
+
+/*-----------------------BPy_Length2DBP1D type definition ------------------------------*/
+
+PyTypeObject Length2DBP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Length2DBP1D", /* tp_name */
+ sizeof(BPy_Length2DBP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Length2DBP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &BinaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Length2DBP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_Length2DBP1D.h b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_Length2DBP1D.h
new file mode 100644
index 00000000000..d5bce5b150d
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_Length2DBP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_LENGTH2DBP1D_H
+#define FREESTYLE_PYTHON_LENGTH2DBP1D_H
+
+#include "../BPy_BinaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject Length2DBP1D_Type;
+
+#define BPy_Length2DBP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Length2DBP1D_Type) )
+
+/*---------------------------Python BPy_Length2DBP1D structure definition----------*/
+typedef struct {
+ BPy_BinaryPredicate1D py_bp1D;
+} BPy_Length2DBP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_LENGTH2DBP1D_H */
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.cpp b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.cpp
new file mode 100644
index 00000000000..2b479a49fc0
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.cpp
@@ -0,0 +1,80 @@
+#include "BPy_SameShapeIdBP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char SameShapeIdBP1D___doc__[] =
+"Class hierarchy: :class:`BinaryPredicate1D` > :class:`SameShapeIdBP1D`\n"
+"\n"
+".. method:: __call__(inter1, inter2)\n"
+"\n"
+" Returns true if inter1 and inter2 belong to the same shape.\n"
+"\n"
+" :arg inter1: The first Interface1D object.\n"
+" :type inter1: :class:`Interface1D`\n"
+" :arg inter2: The second Interface1D object.\n"
+" :type inter2: :class:`Interface1D`\n"
+" :return: True or false.\n"
+" :rtype: bool\n";
+
+static int SameShapeIdBP1D___init__( BPy_SameShapeIdBP1D* self, PyObject *args )
+{
+ if(!( PyArg_ParseTuple(args, "") ))
+ return -1;
+ self->py_bp1D.bp1D = new Predicates1D::SameShapeIdBP1D();
+ return 0;
+}
+
+/*-----------------------BPy_SameShapeIdBP1D type definition ------------------------------*/
+
+PyTypeObject SameShapeIdBP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "SameShapeIdBP1D", /* tp_name */
+ sizeof(BPy_SameShapeIdBP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ SameShapeIdBP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &BinaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)SameShapeIdBP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.h b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.h
new file mode 100644
index 00000000000..71065d4ceeb
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_SAMESHAPEIDBP1D_H
+#define FREESTYLE_PYTHON_SAMESHAPEIDBP1D_H
+
+#include "../BPy_BinaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject SameShapeIdBP1D_Type;
+
+#define BPy_SameShapeIdBP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &SameShapeIdBP1D_Type) )
+
+/*---------------------------Python BPy_SameShapeIdBP1D structure definition----------*/
+typedef struct {
+ BPy_BinaryPredicate1D py_bp1D;
+} BPy_SameShapeIdBP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_SAMESHAPEIDBP1D_H */
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_TrueBP1D.cpp b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_TrueBP1D.cpp
new file mode 100644
index 00000000000..090a8232794
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_TrueBP1D.cpp
@@ -0,0 +1,80 @@
+#include "BPy_TrueBP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char TrueBP1D___doc__[] =
+"Class hierarchy: :class:`BinaryPredicate1D` > :class:`TrueBP1D`\n"
+"\n"
+".. method:: __call__(inter1, inter2)\n"
+"\n"
+" Always returns true.\n"
+"\n"
+" :arg inter1: The first Interface1D object.\n"
+" :type inter1: :class:`Interface1D`\n"
+" :arg inter2: The second Interface1D object.\n"
+" :type inter2: :class:`Interface1D`\n"
+" :return: True.\n"
+" :rtype: bool\n";
+
+static int TrueBP1D___init__( BPy_TrueBP1D* self, PyObject *args )
+{
+ if(!( PyArg_ParseTuple(args, "") ))
+ return -1;
+ self->py_bp1D.bp1D = new Predicates1D::TrueBP1D();
+ return 0;
+}
+
+/*-----------------------BPy_TrueBP1D type definition ------------------------------*/
+
+PyTypeObject TrueBP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "TrueBP1D", /* tp_name */
+ sizeof(BPy_TrueBP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ TrueBP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &BinaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)TrueBP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_TrueBP1D.h b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_TrueBP1D.h
new file mode 100644
index 00000000000..7d809e1fe65
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_TrueBP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_TRUEBP1D_H
+#define FREESTYLE_PYTHON_TRUEBP1D_H
+
+#include "../BPy_BinaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject TrueBP1D_Type;
+
+#define BPy_TrueBP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &TrueBP1D_Type) )
+
+/*---------------------------Python BPy_TrueBP1D structure definition----------*/
+typedef struct {
+ BPy_BinaryPredicate1D py_bp1D;
+} BPy_TrueBP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_TRUEBP1D_H */
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.cpp b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.cpp
new file mode 100644
index 00000000000..f5ba9d58d72
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.cpp
@@ -0,0 +1,92 @@
+#include "BPy_ViewMapGradientNormBP1D.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+//ViewMapGradientNormBP1D(int level, IntegrationType iType=MEAN, float sampling=2.0)
+
+static char ViewMapGradientNormBP1D___doc__[] =
+"Class hierarchy: :class:`BinaryPredicate1D` > :class:`ViewMapGradientNormBP1D`\n"
+"\n"
+".. method:: __call__(inter1, inter2)\n"
+"\n"
+" Returns true if the evaluation of the Gradient norm Function is\n"
+" higher for inter1 than for inter2.\n"
+"\n"
+" :arg inter1: The first Interface1D object.\n"
+" :type inter1: :class:`Interface1D`\n"
+" :arg inter2: The second Interface1D object.\n"
+" :type inter2: :class:`Interface1D`\n"
+" :return: True or false.\n"
+" :rtype: bool\n";
+
+static int ViewMapGradientNormBP1D___init__( BPy_ViewMapGradientNormBP1D* self, PyObject *args )
+{
+ int i;
+ PyObject *obj;
+ float f = 2.0;
+
+ if(!( PyArg_ParseTuple(args, "i|O!f", &i, &IntegrationType_Type, &obj, &f) ))
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_bp1D.bp1D = new Predicates1D::ViewMapGradientNormBP1D(i,t,f);
+ return 0;
+}
+
+/*-----------------------BPy_ViewMapGradientNormBP1D type definition ------------------------------*/
+
+PyTypeObject ViewMapGradientNormBP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ViewMapGradientNormBP1D", /* tp_name */
+ sizeof(BPy_ViewMapGradientNormBP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ViewMapGradientNormBP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &BinaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ViewMapGradientNormBP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.h b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.h
new file mode 100644
index 00000000000..23d27e118a9
--- /dev/null
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_VIEWMAPGRADIENTNORMBP1D_H
+#define FREESTYLE_PYTHON_VIEWMAPGRADIENTNORMBP1D_H
+
+#include "../BPy_BinaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ViewMapGradientNormBP1D_Type;
+
+#define BPy_ViewMapGradientNormBP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ViewMapGradientNormBP1D_Type) )
+
+/*---------------------------Python BPy_ViewMapGradientNormBP1D structure definition----------*/
+typedef struct {
+ BPy_BinaryPredicate1D py_bp1D;
+} BPy_ViewMapGradientNormBP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_VIEWMAPGRADIENTNORMBP1D_H */
diff --git a/source/blender/freestyle/intern/python/Director.cpp b/source/blender/freestyle/intern/python/Director.cpp
new file mode 100644
index 00000000000..7471edea07c
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Director.cpp
@@ -0,0 +1,304 @@
+#include "Director.h"
+
+#include "BPy_Convert.h"
+
+#include "BPy_BinaryPredicate0D.h"
+#include "BPy_BinaryPredicate1D.h"
+#include "BPy_FrsMaterial.h"
+#include "BPy_Id.h"
+#include "BPy_UnaryFunction0D.h"
+#include "BPy_UnaryFunction1D.h"
+#include "BPy_UnaryPredicate0D.h"
+#include "BPy_UnaryPredicate1D.h"
+#include "BPy_StrokeShader.h"
+#include "Iterator/BPy_ChainingIterator.h"
+#include "Iterator/BPy_Interface0DIterator.h"
+#include "Interface1D/BPy_Stroke.h"
+#include "Interface1D/BPy_ViewEdge.h"
+#include "BPy_ViewShape.h"
+
+#include "UnaryFunction0D/BPy_UnaryFunction0DDouble.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DEdgeNature.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DFloat.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DId.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DMaterial.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DUnsigned.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DVec2f.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DVec3f.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.h"
+#include "UnaryFunction0D/BPy_UnaryFunction0DViewShape.h"
+
+#include "UnaryFunction1D/BPy_UnaryFunction1DDouble.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DFloat.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DUnsigned.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DVec2f.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DVec3f.h"
+#include "UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.h"
+
+
+// BinaryPredicate0D: __call__
+int Director_BPy_BinaryPredicate0D___call__( BinaryPredicate0D *bp0D, Interface0D& i1, Interface0D& i2 ) {
+ if (!bp0D->py_bp0D) { // internal error
+ PyErr_SetString(PyExc_RuntimeError, "Reference to Python object (py_bp0D) not initialized");
+ return -1;
+ }
+ PyObject *arg1 = Any_BPy_Interface0D_from_Interface0D(i1);
+ PyObject *arg2 = Any_BPy_Interface0D_from_Interface0D(i2);
+ if (!arg1 || !arg2) {
+ Py_XDECREF(arg1);
+ Py_XDECREF(arg2);
+ return -1;
+ }
+ PyObject *result = PyObject_CallMethod( bp0D->py_bp0D, (char*)"__call__", (char*)"OO", arg1, arg2 );
+ Py_DECREF(arg1);
+ Py_DECREF(arg2);
+ if (!result)
+ return -1;
+ int ret = PyObject_IsTrue(result);
+ Py_DECREF(result);
+ if (ret < 0)
+ return -1;
+ bp0D->result = ret;
+ return 0;
+}
+
+
+// BinaryPredicate1D: __call__
+int Director_BPy_BinaryPredicate1D___call__( BinaryPredicate1D *bp1D, Interface1D& i1, Interface1D& i2 ) {
+ if (!bp1D->py_bp1D) { // internal error
+ PyErr_SetString(PyExc_RuntimeError, "Reference to Python object (py_bp1D) not initialized");
+ return -1;
+ }
+ PyObject *arg1 = Any_BPy_Interface1D_from_Interface1D(i1);
+ PyObject *arg2 = Any_BPy_Interface1D_from_Interface1D(i2);
+ if (!arg1 || !arg2) {
+ Py_XDECREF(arg1);
+ Py_XDECREF(arg2);
+ return -1;
+ }
+ PyObject *result = PyObject_CallMethod( bp1D->py_bp1D, (char*)"__call__", (char*)"OO", arg1, arg2 );
+ Py_DECREF(arg1);
+ Py_DECREF(arg2);
+ if (!result)
+ return -1;
+ int ret = PyObject_IsTrue(result);
+ Py_DECREF(result);
+ if (ret < 0)
+ return -1;
+ bp1D->result = ret;
+ return 0;
+}
+
+
+// UnaryPredicate0D: __call__
+int Director_BPy_UnaryPredicate0D___call__( UnaryPredicate0D *up0D, Interface0DIterator& if0D_it ) {
+ if (!up0D->py_up0D) { // internal error
+ PyErr_SetString(PyExc_RuntimeError, "Reference to Python object (py_up0D) not initialized");
+ return -1;
+ }
+ PyObject *arg = BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, 0);
+ if (!arg)
+ return -1;
+ PyObject *result = PyObject_CallMethod( up0D->py_up0D, (char*)"__call__", (char*)"O", arg );
+ Py_DECREF(arg);
+ if (!result)
+ return -1;
+ int ret = PyObject_IsTrue(result);
+ Py_DECREF(result);
+ if (ret < 0)
+ return -1;
+ up0D->result = ret;
+ return 0;
+}
+
+
+// UnaryPredicate1D: __call__
+int Director_BPy_UnaryPredicate1D___call__( UnaryPredicate1D *up1D, Interface1D& if1D ) {
+ if (!up1D->py_up1D) { // internal error
+ PyErr_SetString(PyExc_RuntimeError, "Reference to Python object (py_up1D) not initialized");
+ return -1;
+ }
+ PyObject *arg = Any_BPy_Interface1D_from_Interface1D(if1D);
+ if (!arg)
+ return -1;
+ PyObject *result = PyObject_CallMethod( up1D->py_up1D, (char*)"__call__", (char*)"O", arg );
+ Py_DECREF(arg);
+ if (!result)
+ return -1;
+ int ret = PyObject_IsTrue(result);
+ Py_DECREF(result);
+ if (ret < 0)
+ return -1;
+ up1D->result = ret;
+ return 0;
+}
+
+
+// StrokeShader: shade
+int Director_BPy_StrokeShader_shade( StrokeShader *ss, Stroke& s ) {
+ if (!ss->py_ss) { // internal error
+ PyErr_SetString(PyExc_RuntimeError, "Reference to Python object (py_ss) not initialized");
+ return -1;
+ }
+ PyObject *arg = BPy_Stroke_from_Stroke(s);
+ if (!arg)
+ return -1;
+ PyObject *result = PyObject_CallMethod( ss->py_ss, (char*)"shade", (char*)"O", arg );
+ Py_DECREF(arg);
+ if (!result)
+ return -1;
+ Py_DECREF(result);
+ return 0;
+}
+
+// ChainingIterator: init, traverse
+int Director_BPy_ChainingIterator_init( ChainingIterator *c_it ) {
+ if (!c_it->py_c_it) { // internal error
+ PyErr_SetString(PyExc_RuntimeError, "Reference to Python object (py_c_it) not initialized");
+ return -1;
+ }
+ PyObject *result = PyObject_CallMethod( c_it->py_c_it, (char*)"init", NULL);
+ if (!result)
+ return -1;
+ Py_DECREF(result);
+ return 0;
+}
+
+int Director_BPy_ChainingIterator_traverse( ChainingIterator *c_it, AdjacencyIterator& a_it ) {
+ if (!c_it->py_c_it) { // internal error
+ PyErr_SetString(PyExc_RuntimeError, "Reference to Python object (py_c_it) not initialized");
+ return -1;
+ }
+ PyObject *arg = BPy_AdjacencyIterator_from_AdjacencyIterator(a_it);
+ if (!arg)
+ return -1;
+ PyObject *result = PyObject_CallMethod( c_it->py_c_it, (char*)"traverse", (char*)"O", arg );
+ Py_DECREF(arg);
+ if (!result)
+ return -1;
+ if (BPy_ViewEdge_Check(result)) {
+ c_it->result = ((BPy_ViewEdge *) result)->ve;
+ } else if (result == Py_None) {
+ c_it->result = NULL;
+ } else {
+ PyErr_SetString(PyExc_RuntimeError, "traverse method returned a wrong value");
+ Py_DECREF(result);
+ return -1;
+ }
+ Py_DECREF(result);
+ return 0;
+}
+
+
+// BPy_UnaryFunction{0D,1D}: __call__
+int Director_BPy_UnaryFunction0D___call__( void *uf0D, PyObject *obj, Interface0DIterator& if0D_it) {
+
+ if (!obj) { // internal error
+ PyErr_SetString(PyExc_RuntimeError, "Reference to Python object (py_uf0D) not initialized");
+ return -1;
+ }
+ PyObject *arg = BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, 0);
+ if (!arg)
+ return -1;
+ PyObject *result = PyObject_CallMethod( obj, (char*)"__call__", (char*)"O", arg );
+ Py_DECREF(arg);
+ if (!result)
+ return -1;
+
+ if( BPy_UnaryFunction0DDouble_Check(obj) ) {
+ ((UnaryFunction0D<double> *) uf0D)->result = PyFloat_AsDouble(result);
+
+ } else if ( BPy_UnaryFunction0DEdgeNature_Check(obj) ) {
+ ((UnaryFunction0D<Nature::EdgeNature> *) uf0D)->result = EdgeNature_from_BPy_Nature(result);
+
+ } else if ( BPy_UnaryFunction0DFloat_Check(obj) ) {
+ ((UnaryFunction0D<float> *) uf0D)->result = PyFloat_AsDouble(result);
+
+ } else if ( BPy_UnaryFunction0DId_Check(obj) ) {
+ ((UnaryFunction0D<Id> *) uf0D)->result = *( ((BPy_Id *) result)->id );
+
+ } else if ( BPy_UnaryFunction0DMaterial_Check(obj) ) {
+ ((UnaryFunction0D<FrsMaterial> *) uf0D)->result = *( ((BPy_FrsMaterial *) result)->m );
+
+ } else if ( BPy_UnaryFunction0DUnsigned_Check(obj) ) {
+ ((UnaryFunction0D<unsigned> *) uf0D)->result = PyLong_AsLong(result);
+
+ } else if ( BPy_UnaryFunction0DVec2f_Check(obj) ) {
+ Vec2f *v = Vec2f_ptr_from_Vector( result );
+ ((UnaryFunction0D<Vec2f> *) uf0D)->result = *v;
+ delete v;
+
+ } else if ( BPy_UnaryFunction0DVec3f_Check(obj) ) {
+ Vec3f *v = Vec3f_ptr_from_Vector( result );
+ ((UnaryFunction0D<Vec3f> *) uf0D)->result = *v;
+ delete v;
+
+ } else if ( BPy_UnaryFunction0DVectorViewShape_Check(obj) ) {
+ vector<ViewShape*> vec;
+ for( int i = 0; i < PyList_Size(result); i++) {
+ ViewShape *b = ( (BPy_ViewShape *) PyList_GetItem(result, i) )->vs;
+ vec.push_back( b );
+ }
+
+ ((UnaryFunction0D< vector<ViewShape*> > *) uf0D)->result = vec;
+
+ } else if ( BPy_UnaryFunction0DViewShape_Check(obj) ) {
+ ((UnaryFunction0D<ViewShape*> *) uf0D)->result = ((BPy_ViewShape *) result)->vs;
+
+ }
+
+ Py_DECREF(result);
+ return 0;
+}
+
+int Director_BPy_UnaryFunction1D___call__( void *uf1D, PyObject *obj, Interface1D& if1D) {
+
+ if (!obj) { // internal error
+ PyErr_SetString(PyExc_RuntimeError, "Reference to Python object (py_uf1D) not initialized");
+ return -1;
+ }
+ PyObject *arg = Any_BPy_Interface1D_from_Interface1D(if1D);
+ if (!arg)
+ return -1;
+ PyObject *result = PyObject_CallMethod( obj, (char*)"__call__", (char*)"O", arg );
+ Py_DECREF(arg);
+ if (!result)
+ return -1;
+
+ if( BPy_UnaryFunction1DDouble_Check(obj) ) {
+ ((UnaryFunction1D<double> *) uf1D)->result = PyFloat_AsDouble(result);
+
+ } else if ( BPy_UnaryFunction1DEdgeNature_Check(obj) ) {
+ ((UnaryFunction1D<Nature::EdgeNature> *) uf1D)->result = EdgeNature_from_BPy_Nature(result);
+
+ } else if ( BPy_UnaryFunction1DFloat_Check(obj) ) {
+ ((UnaryFunction1D<float> *) uf1D)->result = PyFloat_AsDouble(result);
+
+ } else if ( BPy_UnaryFunction1DUnsigned_Check(obj) ) {
+ ((UnaryFunction1D<unsigned> *) uf1D)->result = PyLong_AsLong(result);
+
+ } else if ( BPy_UnaryFunction1DVec2f_Check(obj) ) {
+ Vec2f *v = Vec2f_ptr_from_Vector( result );
+ ((UnaryFunction1D<Vec2f> *) uf1D)->result = *v;
+ delete v;
+
+ } else if ( BPy_UnaryFunction1DVec3f_Check(obj) ) {
+ Vec3f *v = Vec3f_ptr_from_Vector( result );
+ ((UnaryFunction1D<Vec3f> *) uf1D)->result = *v;
+ delete v;
+
+ } else if ( BPy_UnaryFunction1DVectorViewShape_Check(obj) ) {
+ vector<ViewShape*> vec;
+ for( int i = 1; i < PyList_Size(result); i++) {
+ ViewShape *b = ( (BPy_ViewShape *) PyList_GetItem(result, i) )->vs;
+ vec.push_back( b );
+ }
+
+ ((UnaryFunction1D< vector<ViewShape*> > *) uf1D)->result = vec;
+
+ }
+
+ Py_DECREF(result);
+ return 0;
+}
diff --git a/source/blender/freestyle/intern/python/Director.h b/source/blender/freestyle/intern/python/Director.h
new file mode 100644
index 00000000000..667d4a65942
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Director.h
@@ -0,0 +1,49 @@
+#ifndef FREESTYLE_PYTHON_DIRECTOR
+# define FREESTYLE_PYTHON_DIRECTOR
+
+class UnaryPredicate0D;
+class UnaryPredicate1D;
+class BinaryPredicate0D;
+class BinaryPredicate1D;
+class ChainingIterator;
+class AdjacencyIterator;
+class Interface0D;
+class Interface1D;
+class Interface0DIterator;
+class Stroke;
+class StrokeShader;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Python.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+// BinaryPredicate0D: __call__
+int Director_BPy_BinaryPredicate0D___call__( BinaryPredicate0D *bp0D, Interface0D& i1, Interface0D& i2 );
+
+// BinaryPredicate1D: __call__
+int Director_BPy_BinaryPredicate1D___call__( BinaryPredicate1D *bp1D, Interface1D& i1, Interface1D& i2 );
+
+// UnaryFunction{0D,1D}: __call__
+int Director_BPy_UnaryFunction0D___call__( void *uf0D, PyObject *obj, Interface0DIterator& if0D_it);
+int Director_BPy_UnaryFunction1D___call__( void *uf1D, PyObject *obj, Interface1D& if1D);
+
+// UnaryPredicate0D: __call__
+int Director_BPy_UnaryPredicate0D___call__( UnaryPredicate0D *up0D, Interface0DIterator& if0D_it );
+
+// UnaryPredicate1D: __call__
+int Director_BPy_UnaryPredicate1D___call__( UnaryPredicate1D *up1D, Interface1D& if1D );
+
+// StrokeShader: shade
+int Director_BPy_StrokeShader_shade( StrokeShader *ss, Stroke& s );
+
+// ChainingIterator: init, traverse
+int Director_BPy_ChainingIterator_init( ChainingIterator *c_it );
+int Director_BPy_ChainingIterator_traverse( ChainingIterator *c_it, AdjacencyIterator& a_it );
+
+#endif // FREESTYLE_PYTHON_DIRECTOR
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
new file mode 100644
index 00000000000..e213edd5c79
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
@@ -0,0 +1,278 @@
+#include "BPy_CurvePoint.h"
+
+#include "../BPy_Convert.h"
+#include "../Interface0D/BPy_SVertex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char CurvePoint___doc__[] =
+"Class hierarchy: :class:`Interface0D` > :class:`CurvePoint`\n"
+"\n"
+"Class to represent a point of a curve. A CurvePoint can be any point\n"
+"of a 1D curve (it doesn't have to be a vertex of the curve). Any\n"
+":class:`Interface1D` is built upon ViewEdges, themselves built upon\n"
+"FEdges. Therefore, a curve is basically a polyline made of a list of\n"
+":class:`SVertex` objects. Thus, a CurvePoint is built by linearly\n"
+"interpolating two :class:`SVertex` instances. CurvePoint can be used\n"
+"as virtual points while querying 0D information along a curve at a\n"
+"given resolution.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Defult constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: A CurvePoint object.\n"
+" :type iBrother: :class:`CurvePoint`\n"
+"\n"
+".. method:: __init__(iA, iB, t2d)\n"
+"\n"
+" Builds a CurvePoint from two SVertex and an interpolation parameter.\n"
+"\n"
+" :arg iA: The first SVertex.\n"
+" :type iA: :class:`SVertex`\n"
+" :arg iB: The second SVertex.\n"
+" :type iB: :class:`SVertex`\n"
+" :arg t2d: A 2D interpolation parameter used to linearly interpolate\n"
+" iA and iB.\n"
+" :type t2d: float\n"
+"\n"
+".. method:: __init__(iA, iB, t2d)\n"
+"\n"
+" Builds a CurvePoint from two CurvePoint and an interpolation\n"
+" parameter.\n"
+"\n"
+" :arg iA: The first CurvePoint.\n"
+" :type iA: :class:`CurvePoint`\n"
+" :arg iB: The second CurvePoint.\n"
+" :type iB: :class:`CurvePoint`\n"
+" :arg t2d: The 2D interpolation parameter used to linearly\n"
+" interpolate iA and iB.\n"
+" :type t2d: float\n";
+
+static int CurvePoint___init__(BPy_CurvePoint *self, PyObject *args, PyObject *kwds)
+{
+
+ PyObject *obj1 = 0, *obj2 = 0 , *obj3 = 0;
+
+ if (! PyArg_ParseTuple(args, "|OOO!", &obj1, &obj2, &PyFloat_Type, &obj3) )
+ return -1;
+
+ if( !obj1 ){
+ self->cp = new CurvePoint();
+
+ } else if( !obj2 && BPy_CurvePoint_Check(obj1) ) {
+ self->cp = new CurvePoint( *(((BPy_CurvePoint *) obj1)->cp) );
+
+ } else if( obj3 && BPy_SVertex_Check(obj1) && BPy_SVertex_Check(obj2) ) {
+ self->cp = new CurvePoint( ((BPy_SVertex *) obj1)->sv,
+ ((BPy_SVertex *) obj2)->sv,
+ PyFloat_AsDouble( obj3 ) );
+
+ } else if( obj3 && BPy_CurvePoint_Check(obj1) && BPy_CurvePoint_Check(obj2) ) {
+ CurvePoint *cp1 = ((BPy_CurvePoint *) obj1)->cp;
+ CurvePoint *cp2 = ((BPy_CurvePoint *) obj2)->cp;
+ if( !cp1 || cp1->A() == 0 || cp1->B() == 0 ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 is an invalid CurvePoint object");
+ return -1;
+ }
+ if( !cp2 || cp2->A() == 0 || cp2->B() == 0 ) {
+ PyErr_SetString(PyExc_TypeError, "argument 2 is an invalid CurvePoint object");
+ return -1;
+ }
+ self->cp = new CurvePoint( cp1, cp2, PyFloat_AsDouble( obj3 ) );
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
+ return -1;
+ }
+
+ self->py_if0D.if0D = self->cp;
+ self->py_if0D.borrowed = 0;
+
+ return 0;
+}
+
+static char CurvePoint_A___doc__[] =
+".. method:: A()\n"
+"\n"
+" Returns the first SVertex upon which the CurvePoint is built.\n"
+"\n"
+" :return: The first SVertex.\n"
+" :rtype: :class:`SVertex`\n";
+
+static PyObject * CurvePoint_A( BPy_CurvePoint *self ) {
+ SVertex *A = self->cp->A();
+ if( A )
+ return BPy_SVertex_from_SVertex( *A );
+
+ Py_RETURN_NONE;
+}
+
+static char CurvePoint_B___doc__[] =
+".. method:: B()\n"
+"\n"
+" Returns the second SVertex upon which the CurvePoint is built.\n"
+"\n"
+" :return: The second SVertex.\n"
+" :rtype: :class:`SVertex`\n";
+
+static PyObject * CurvePoint_B( BPy_CurvePoint *self ) {
+ SVertex *B = self->cp->B();
+ if( B )
+ return BPy_SVertex_from_SVertex( *B );
+
+ Py_RETURN_NONE;
+}
+
+static char CurvePoint_t2d___doc__[] =
+".. method:: t2d()\n"
+"\n"
+" Returns the 2D interpolation parameter.\n"
+"\n"
+" :return: The 2D interpolation parameter.\n"
+" :rtype: float\n";
+
+static PyObject * CurvePoint_t2d( BPy_CurvePoint *self ) {
+ return PyFloat_FromDouble( self->cp->t2d() );
+}
+
+static char CurvePoint_setA___doc__[] =
+".. method:: setA(iA)\n"
+"\n"
+" Sets the first SVertex upon which to build the CurvePoint.\n"
+"\n"
+" :arg iA: The first SVertex.\n"
+" :type iA: :class:`SVertex`\n";
+
+static PyObject *CurvePoint_setA( BPy_CurvePoint *self , PyObject *args) {
+ PyObject *py_sv;
+
+ if(!( PyArg_ParseTuple(args, "O!", &SVertex_Type, &py_sv) ))
+ return NULL;
+
+ self->cp->setA( ((BPy_SVertex *) py_sv)->sv );
+
+ Py_RETURN_NONE;
+}
+
+static char CurvePoint_setB___doc__[] =
+".. method:: setB(iB)\n"
+"\n"
+" Sets the first SVertex upon which to build the CurvePoint.\n"
+"\n"
+" :arg iB: The second SVertex.\n"
+" :type iB: :class:`SVertex`\n";
+
+static PyObject *CurvePoint_setB( BPy_CurvePoint *self , PyObject *args) {
+ PyObject *py_sv;
+
+ if(!( PyArg_ParseTuple(args, "O!", &SVertex_Type, &py_sv) ))
+ return NULL;
+
+ self->cp->setB( ((BPy_SVertex *) py_sv)->sv );
+
+ Py_RETURN_NONE;
+}
+
+static char CurvePoint_setT2d___doc__[] =
+".. method:: setT2d(t)\n"
+"\n"
+" Sets the 2D interpolation parameter to use.\n"
+"\n"
+" :arg t: The 2D interpolation parameter.\n"
+" :type t: float\n";
+
+static PyObject *CurvePoint_setT2d( BPy_CurvePoint *self , PyObject *args) {
+ float t;
+
+ if(!( PyArg_ParseTuple(args, "f", &t) ))
+ return NULL;
+
+ self->cp->setT2d( t );
+
+ Py_RETURN_NONE;
+}
+
+static char CurvePoint_curvatureFredo___doc__[] =
+".. method:: curvatureFredo()\n"
+"\n"
+" Returns the angle in radians.\n"
+"\n"
+" :return: The angle in radians.\n"
+" :rtype: float\n";
+
+static PyObject *CurvePoint_curvatureFredo( BPy_CurvePoint *self , PyObject *args) {
+ return PyFloat_FromDouble( self->cp->curvatureFredo() );
+}
+
+///bool operator== (const CurvePoint &b)
+
+/*----------------------CurvePoint instance definitions ----------------------------*/
+static PyMethodDef BPy_CurvePoint_methods[] = {
+ {"A", ( PyCFunction ) CurvePoint_A, METH_NOARGS, CurvePoint_A___doc__},
+ {"B", ( PyCFunction ) CurvePoint_B, METH_NOARGS, CurvePoint_B___doc__},
+ {"t2d", ( PyCFunction ) CurvePoint_t2d, METH_NOARGS, CurvePoint_t2d___doc__},
+ {"setA", ( PyCFunction ) CurvePoint_setA, METH_VARARGS, CurvePoint_setA___doc__},
+ {"setB", ( PyCFunction ) CurvePoint_setB, METH_VARARGS, CurvePoint_setB___doc__},
+ {"setT2d", ( PyCFunction ) CurvePoint_setT2d, METH_VARARGS, CurvePoint_setT2d___doc__},
+ {"curvatureFredo", ( PyCFunction ) CurvePoint_curvatureFredo, METH_NOARGS, CurvePoint_curvatureFredo___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_CurvePoint type definition ------------------------------*/
+PyTypeObject CurvePoint_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "CurvePoint", /* tp_name */
+ sizeof(BPy_CurvePoint), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ CurvePoint___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_CurvePoint_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Interface0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)CurvePoint___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.h b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.h
new file mode 100644
index 00000000000..b4c22645503
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_CURVEPOINT_H
+#define FREESTYLE_PYTHON_CURVEPOINT_H
+
+#include "../BPy_Interface0D.h"
+#include "../../stroke/Curve.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject CurvePoint_Type;
+
+#define BPy_CurvePoint_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &CurvePoint_Type) )
+
+/*---------------------------Python BPy_CurvePoint structure definition----------*/
+typedef struct {
+ BPy_Interface0D py_if0D;
+ CurvePoint *cp;
+} BPy_CurvePoint;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CURVEPOINT_H */
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp
new file mode 100644
index 00000000000..cd0131ad570
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp
@@ -0,0 +1,338 @@
+#include "BPy_SVertex.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_Id.h"
+#include "../Interface1D/BPy_FEdge.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+static char SVertex___doc__[] =
+"Class hierarchy: :class:`Interface0D` > :class:`SVertex`\n"
+"\n"
+"Class to define a vertex of the embedding.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: A SVertex object.\n"
+" :type iBrother: :class:`SVertex`\n"
+"\n"
+".. method:: __init__(iPoint3D, id)\n"
+"\n"
+" Builds a SVertex from 3D coordinates and an Id.\n"
+"\n"
+" :arg iPoint3D: A three-dimensional vector.\n"
+" :type iPoint3D: :class:`mathutils.Vector`\n"
+" :arg id: An Id object.\n"
+" :type id: :class:`Id`\n";
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static int SVertex___init__(BPy_SVertex *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *py_point = 0;
+ BPy_Id *py_id = 0;
+
+
+ if (! PyArg_ParseTuple(args, "|OO!", &py_point, &Id_Type, &py_id) )
+ return -1;
+
+ if( !py_point ) {
+ self->sv = new SVertex();
+
+ } else if( !py_id && BPy_SVertex_Check(py_point) ) {
+ self->sv = new SVertex( *(((BPy_SVertex *)py_point)->sv) );
+
+ } else if( py_point && py_id ) {
+ Vec3r *v = Vec3r_ptr_from_PyObject(py_point);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 3D vector (either a list of 3 elements or Vector)");
+ return -1;
+ }
+ self->sv = new SVertex( *v, *(py_id->id) );
+ delete v;
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
+ return -1;
+ }
+
+ self->py_if0D.if0D = self->sv;
+ self->py_if0D.borrowed = 0;
+
+ return 0;
+}
+
+static char SVertex_normals___doc__[] =
+".. method:: normals()\n"
+"\n"
+" Returns the normals for this Vertex as a list. In a smooth surface,\n"
+" a vertex has exactly one normal. In a sharp surface, a vertex can\n"
+" have any number of normals.\n"
+"\n"
+" :return: A list of normals.\n"
+" :rtype: List of :class:`mathutils.Vector` objects\n";
+
+static PyObject * SVertex_normals( BPy_SVertex *self ) {
+ PyObject *py_normals;
+ set< Vec3r > normals;
+
+ py_normals = PyList_New(0);
+ normals = self->sv->normals();
+
+ for( set< Vec3r >::iterator set_iterator = normals.begin(); set_iterator != normals.end(); set_iterator++ ) {
+ Vec3r v( *set_iterator );
+ PyList_Append( py_normals, Vector_from_Vec3r(v) );
+ }
+
+ return py_normals;
+}
+
+static char SVertex_normalsSize___doc__[] =
+".. method:: normalsSize()\n"
+"\n"
+" Returns the number of different normals for this vertex.\n"
+"\n"
+" :return: The number of normals.\n"
+" :rtype: int\n";
+
+static PyObject * SVertex_normalsSize( BPy_SVertex *self ) {
+ return PyLong_FromLong( self->sv->normalsSize() );
+}
+
+static char SVertex_viewvertex___doc__[] =
+".. method:: viewvertex()\n"
+"\n"
+" If this SVertex is also a ViewVertex, this method returns the\n"
+" ViewVertex. None is returned otherwise.\n"
+"\n"
+" :return: The ViewVertex object.\n"
+" :rtype: :class:`ViewVertex`\n";
+
+static PyObject * SVertex_viewvertex( BPy_SVertex *self ) {
+ ViewVertex *vv = self->sv->viewvertex();
+ if( vv )
+ return Any_BPy_ViewVertex_from_ViewVertex( *vv );
+
+ Py_RETURN_NONE;
+}
+
+static char SVertex_setPoint3D___doc__[] =
+".. method:: setPoint3D(p)\n"
+"\n"
+" Sets the 3D coordinates of the SVertex.\n"
+"\n"
+" :arg p: A three-dimensional vector.\n"
+" :type p: :class:`mathutils.Vector`, list or tuple of 3 real numbers\n";
+
+static PyObject *SVertex_setPoint3D( BPy_SVertex *self , PyObject *args) {
+ PyObject *py_point;
+
+ if(!( PyArg_ParseTuple(args, "O", &py_point) ))
+ return NULL;
+ Vec3r *v = Vec3r_ptr_from_PyObject(py_point);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 3D vector (either a list of 3 elements or Vector)");
+ return NULL;
+ }
+ self->sv->setPoint3D( *v );
+ delete v;
+
+ Py_RETURN_NONE;
+}
+
+static char SVertex_setPoint2D___doc__[] =
+".. method:: setPoint2D(p)\n"
+"\n"
+" Sets the 2D projected coordinates of the SVertex.\n"
+"\n"
+" :arg p: A three-dimensional vector.\n"
+" :type p: :class:`mathutils.Vector`, list or tuple of 3 real numbers\n";
+
+static PyObject *SVertex_setPoint2D( BPy_SVertex *self , PyObject *args) {
+ PyObject *py_point;
+
+ if(!( PyArg_ParseTuple(args, "O", &py_point) ))
+ return NULL;
+ Vec3r *v = Vec3r_ptr_from_PyObject(py_point);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 3D vector (either a list of 3 elements or Vector)");
+ return NULL;
+ }
+ self->sv->setPoint2D( *v );
+ delete v;
+
+ Py_RETURN_NONE;
+}
+
+static char SVertex_AddNormal___doc__[] =
+".. method:: AddNormal(n)\n"
+"\n"
+" Adds a normal to the SVertex's set of normals. If the same normal\n"
+" is already in the set, nothing changes.\n"
+"\n"
+" :arg n: A three-dimensional vector.\n"
+" :type n: :class:`mathutils.Vector`, list or tuple of 3 real numbers\n";
+
+static PyObject *SVertex_AddNormal( BPy_SVertex *self , PyObject *args) {
+ PyObject *py_normal;
+
+ if(!( PyArg_ParseTuple(args, "O", &py_normal) ))
+ return NULL;
+ Vec3r *n = Vec3r_ptr_from_PyObject(py_normal);
+ if( !n ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 3D vector (either a list of 3 elements or Vector)");
+ return NULL;
+ }
+ self->sv->AddNormal( *n );
+ delete n;
+
+ Py_RETURN_NONE;
+}
+
+static char SVertex_setId___doc__[] =
+".. method:: setId(id)\n"
+"\n"
+" Sets the identifier of the SVertex.\n"
+"\n"
+" :arg id: The identifier.\n"
+" :type id: :class:`Id`\n";
+
+static PyObject *SVertex_setId( BPy_SVertex *self , PyObject *args) {
+ BPy_Id *py_id;
+
+ if( !PyArg_ParseTuple(args, "O!", &Id_Type, &py_id) )
+ return NULL;
+
+ self->sv->setId( *(py_id->id) );
+
+ Py_RETURN_NONE;
+}
+
+static char SVertex_AddFEdge___doc__[] =
+".. method:: AddFEdge(fe)\n"
+"\n"
+" Add an FEdge to the list of edges emanating from this SVertex.\n"
+"\n"
+" :arg fe: An FEdge.\n"
+" :type fe: :class:`FEdge`\n";
+
+static PyObject *SVertex_AddFEdge( BPy_SVertex *self , PyObject *args) {
+ PyObject *py_fe;
+
+ if(!( PyArg_ParseTuple(args, "O!", &FEdge_Type, &py_fe) ))
+ return NULL;
+
+ self->sv->AddFEdge( ((BPy_FEdge *) py_fe)->fe );
+
+ Py_RETURN_NONE;
+}
+
+static char SVertex_curvatures___doc__[] =
+".. method:: curvatures()\n"
+"\n"
+" Returns curvature information in the form of a seven-element tuple\n"
+" (K1, e1, K2, e2, Kr, er, dKr), where K1 and K2 are scalar values\n"
+" representing the first (maximum) and second (minimum) principal\n"
+" curvatures at this SVertex, respectively; e1 and e2 are\n"
+" three-dimensional vectors representing the first and second principal\n"
+" directions, i.e. the directions of the normal plane where the\n"
+" curvature takes its maximum and minimum values, respectively; and Kr,\n"
+" er and dKr are the radial curvature, radial direction, and the\n"
+" derivative of the radial curvature at this SVertex, repectively.\n"
+" :return: curvature information expressed by a seven-element tuple\n"
+" (K1, e1, K2, e2, Kr, er, dKr).\n"
+" :rtype: tuple\n";
+
+static PyObject *SVertex_curvatures( BPy_SVertex *self , PyObject *args) {
+ const CurvatureInfo *info = self->sv->getCurvatureInfo();
+ if (!info)
+ Py_RETURN_NONE;
+ Vec3r e1(info->e1.x(), info->e1.y(), info->e1.z());
+ Vec3r e2(info->e2.x(), info->e2.y(), info->e2.z());
+ Vec3r er(info->er.x(), info->er.y(), info->er.z());
+ PyObject *retval = PyTuple_New(7);
+ PyTuple_SetItem( retval, 0, PyFloat_FromDouble(info->K1));
+ PyTuple_SetItem( retval, 2, Vector_from_Vec3r(e1));
+ PyTuple_SetItem( retval, 1, PyFloat_FromDouble(info->K2));
+ PyTuple_SetItem( retval, 3, Vector_from_Vec3r(e2));
+ PyTuple_SetItem( retval, 4, PyFloat_FromDouble(info->Kr));
+ PyTuple_SetItem( retval, 5, Vector_from_Vec3r(er));
+ PyTuple_SetItem( retval, 6, PyFloat_FromDouble(info->dKr));
+ return retval;
+}
+
+// virtual bool operator== (const SVertex &iBrother)
+// ViewVertex * viewvertex ()
+
+/*----------------------SVertex instance definitions ----------------------------*/
+static PyMethodDef BPy_SVertex_methods[] = {
+ {"normals", ( PyCFunction ) SVertex_normals, METH_NOARGS, SVertex_normals___doc__},
+ {"normalsSize", ( PyCFunction ) SVertex_normalsSize, METH_NOARGS, SVertex_normalsSize___doc__},
+ {"viewvertex", ( PyCFunction ) SVertex_viewvertex, METH_NOARGS, SVertex_viewvertex___doc__},
+ {"setPoint3D", ( PyCFunction ) SVertex_setPoint3D, METH_VARARGS, SVertex_setPoint3D___doc__},
+ {"setPoint2D", ( PyCFunction ) SVertex_setPoint2D, METH_VARARGS, SVertex_setPoint2D___doc__},
+ {"AddNormal", ( PyCFunction ) SVertex_AddNormal, METH_VARARGS, SVertex_AddNormal___doc__},
+ {"setId", ( PyCFunction ) SVertex_setId, METH_VARARGS, SVertex_setId___doc__},
+ {"AddFEdge", ( PyCFunction ) SVertex_AddFEdge, METH_VARARGS, SVertex_AddFEdge___doc__},
+ {"curvatures", ( PyCFunction ) SVertex_curvatures, METH_NOARGS, SVertex_curvatures___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_SVertex type definition ------------------------------*/
+PyTypeObject SVertex_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "SVertex", /* tp_name */
+ sizeof(BPy_SVertex), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ SVertex___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_SVertex_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Interface0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)SVertex___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.h b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.h
new file mode 100644
index 00000000000..7d310f2b7dc
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.h
@@ -0,0 +1,32 @@
+#ifndef FREESTYLE_PYTHON_SVERTEX_H
+#define FREESTYLE_PYTHON_SVERTEX_H
+
+#include "../../view_map/Silhouette.h"
+#include "../BPy_Interface0D.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject SVertex_Type;
+
+#define BPy_SVertex_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &SVertex_Type) )
+
+/*---------------------------Python BPy_SVertex structure definition----------*/
+typedef struct {
+ BPy_Interface0D py_if0D;
+ SVertex *sv;
+} BPy_SVertex;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_SVERTEX_H */
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
new file mode 100644
index 00000000000..c1fe6875ea7
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
@@ -0,0 +1,195 @@
+#include "BPy_ViewVertex.h"
+
+#include "../BPy_Convert.h"
+#include "../Interface1D/BPy_ViewEdge.h"
+#include "../BPy_Nature.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ViewVertex___doc__[] =
+"Class hierarchy: :class:`Interface0D` > :class:`ViewVertex`\n"
+"\n"
+"Class to define a view vertex. A view vertex is a feature vertex\n"
+"corresponding to a point of the image graph, where the characteristics\n"
+"of an edge (e.g., nature and visibility) might change. A\n"
+":class:`ViewVertex` can be of two kinds: A :class:`TVertex` when it\n"
+"corresponds to the intersection between two ViewEdges or a\n"
+":class:`NonTVertex` when it corresponds to a vertex of the initial\n"
+"input mesh (it is the case for vertices such as corners for example).\n"
+"Thus, this class can be specialized into two classes, the\n"
+":class:`TVertex` class and the :class:`NonTVertex` class.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: A ViewVertex object.\n"
+" :type iBrother: :class:`ViewVertex`\n";
+
+static int ViewVertex___init__( BPy_ViewVertex *self, PyObject *args, PyObject *kwds )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->vv = 0; // ViewVertex is abstract
+ self->py_if0D.if0D = self->vv;
+ self->py_if0D.borrowed = 0;
+ return 0;
+}
+
+static char ViewVertex_setNature___doc__[] =
+".. method:: setNature(iNature)\n"
+"\n"
+" Sets the nature of the vertex.\n"
+"\n"
+" :arg iNature: A Nature object.\n"
+" :type iNature: :class:`Nature`\n";
+
+static PyObject * ViewVertex_setNature( BPy_ViewVertex *self, PyObject *args ) {
+ PyObject *py_n;
+
+ if( !self->vv )
+ Py_RETURN_NONE;
+
+ if(!( PyArg_ParseTuple(args, "O!", &Nature_Type, &py_n) ))
+ return NULL;
+
+ PyObject *i = (PyObject *) &( ((BPy_Nature *) py_n)->i );
+ ((ViewVertex *) self->py_if0D.if0D)->setNature( PyLong_AsLong(i) );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewVertex_edgesBegin___doc__[] =
+".. method:: edgesBegin()\n"
+"\n"
+" Returns an iterator over the ViewEdges that goes to or comes from\n"
+" this ViewVertex pointing to the first ViewEdge of the list. The\n"
+" orientedViewEdgeIterator allows to iterate in CCW order over these\n"
+" ViewEdges and to get the orientation for each ViewEdge\n"
+" (incoming/outgoing).\n"
+"\n"
+" :return: An orientedViewEdgeIterator pointing to the first ViewEdge.\n"
+" :rtype: :class:`orientedViewEdgeIterator`\n";
+
+static PyObject * ViewVertex_edgesBegin( BPy_ViewVertex *self ) {
+ if( !self->vv )
+ Py_RETURN_NONE;
+
+ ViewVertexInternal::orientedViewEdgeIterator ove_it( self->vv->edgesBegin() );
+ return BPy_orientedViewEdgeIterator_from_orientedViewEdgeIterator( ove_it, 0 );
+}
+
+static char ViewVertex_edgesEnd___doc__[] =
+".. method:: edgesEnd()\n"
+"\n"
+" Returns an orientedViewEdgeIterator over the ViewEdges around this\n"
+" ViewVertex, pointing after the last ViewEdge.\n"
+"\n"
+" :return: An orientedViewEdgeIterator pointing after the last ViewEdge.\n"
+" :rtype: :class:`orientedViewEdgeIterator`\n";
+
+static PyObject * ViewVertex_edgesEnd( BPy_ViewVertex *self ) {
+#if 0
+ if( !self->vv )
+ Py_RETURN_NONE;
+
+ ViewVertexInternal::orientedViewEdgeIterator ove_it( self->vv->edgesEnd() );
+ return BPy_orientedViewEdgeIterator_from_orientedViewEdgeIterator( ove_it, 1 );
+#else
+ PyErr_SetString(PyExc_NotImplementedError, "edgesEnd method currently disabled");
+ return NULL;
+#endif
+}
+
+static char ViewVertex_edgesIterator___doc__[] =
+".. method:: edgesIterator(iEdge)\n"
+"\n"
+" Returns an orientedViewEdgeIterator pointing to the ViewEdge given\n"
+" as argument.\n"
+"\n"
+" :arg iEdge: A ViewEdge object.\n"
+" :type iEdge: :class:`ViewEdge`\n"
+" :return: An orientedViewEdgeIterator pointing to the given ViewEdge.\n"
+" :rtype: :class:`orientedViewEdgeIterator`\n";
+
+static PyObject * ViewVertex_edgesIterator( BPy_ViewVertex *self, PyObject *args ) {
+ PyObject *py_ve;
+
+ if( !self->vv )
+ Py_RETURN_NONE;
+
+ if(!( PyArg_ParseTuple(args, "O!", &ViewEdge_Type, &py_ve) ))
+ return NULL;
+
+ ViewEdge *ve = ((BPy_ViewEdge *) py_ve)->ve;
+ ViewVertexInternal::orientedViewEdgeIterator ove_it( self->vv->edgesIterator( ve ) );
+ return BPy_orientedViewEdgeIterator_from_orientedViewEdgeIterator( ove_it, 0 );
+}
+
+/*----------------------ViewVertex instance definitions ----------------------------*/
+static PyMethodDef BPy_ViewVertex_methods[] = {
+ {"setNature", ( PyCFunction ) ViewVertex_setNature, METH_VARARGS, ViewVertex_setNature___doc__},
+ {"edgesBegin", ( PyCFunction ) ViewVertex_edgesBegin, METH_NOARGS, ViewVertex_edgesBegin___doc__},
+ {"edgesEnd", ( PyCFunction ) ViewVertex_edgesEnd, METH_NOARGS, ViewVertex_edgesEnd___doc__},
+ {"edgesIterator", ( PyCFunction ) ViewVertex_edgesIterator, METH_VARARGS, ViewVertex_edgesIterator___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_ViewVertex type definition ------------------------------*/
+PyTypeObject ViewVertex_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ViewVertex", /* tp_name */
+ sizeof(BPy_ViewVertex), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ViewVertex___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_ViewVertex_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Interface0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ViewVertex___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.h b/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.h
new file mode 100644
index 00000000000..26c06b50d71
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_VIEWVERTEX_H
+#define FREESTYLE_PYTHON_VIEWVERTEX_H
+
+#include "../../view_map/ViewMap.h"
+#include "../BPy_Interface0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ViewVertex_Type;
+
+#define BPy_ViewVertex_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ViewVertex_Type) )
+
+/*---------------------------Python BPy_ViewVertex structure definition----------*/
+typedef struct {
+ BPy_Interface0D py_if0D;
+ ViewVertex *vv;
+} BPy_ViewVertex;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_VIEWVERTEX_H */
diff --git a/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
new file mode 100644
index 00000000000..80b9defd95e
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
@@ -0,0 +1,400 @@
+#include "BPy_StrokeVertex.h"
+
+#include "../../BPy_Convert.h"
+#include "../../BPy_StrokeAttribute.h"
+#include "../../Interface0D/BPy_SVertex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char StrokeVertex___doc__[] =
+"Class hierarchy: :class:`Interface0D` > :class:`CurvePoint` > :class:`StrokeVertex`\n"
+"\n"
+"Class to define a stroke vertex.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: A StrokeVertex object.\n"
+" :type iBrother: :class:`StrokeVertex`\n"
+"\n"
+".. method:: __init__(iA, iB, t3)\n"
+"\n"
+" Builds a stroke vertex from 2 stroke vertices and an interpolation\n"
+" parameter.\n"
+"\n"
+" :arg iA: The first StrokeVertex.\n"
+" :type iA: :class:`StrokeVertex`\n"
+" :arg iB: The second StrokeVertex.\n"
+" :type iB: :class:`StrokeVertex`\n"
+" :arg t3: An interpolation parameter.\n"
+" :type t3: float\n"
+"\n"
+".. method:: __init__(iPoint)\n"
+"\n"
+" Builds a stroke vertex from a CurvePoint\n"
+"\n"
+" :arg iPoint: A CurvePoint object.\n"
+" :type iPoint: :class:`CurvePoint`\n"
+"\n"
+".. method:: __init__(iSVertex)\n"
+"\n"
+" Builds a stroke vertex from a SVertex\n"
+"\n"
+" :arg iSVertex: An SVertex object.\n"
+" :type iSVertex: :class:`SVertex`\n"
+"\n"
+".. method:: __init__(iSVertex, iAttribute)\n"
+"\n"
+" Builds a stroke vertex from an SVertex and a StrokeAttribute object.\n"
+"\n"
+" :arg iSVertex: An SVertex object.\n"
+" :type iSVertex: :class:`SVertex`\n"
+" :arg iAttribute: A StrokeAttribute object.\n"
+" :type iAttribute: :class:`StrokeAttribute`\n";
+
+static int StrokeVertex___init__(BPy_StrokeVertex *self, PyObject *args, PyObject *kwds)
+{
+
+ PyObject *obj1 = 0, *obj2 = 0 , *obj3 = 0;
+
+ if (! PyArg_ParseTuple(args, "|OOO!", &obj1, &obj2, &PyFloat_Type, &obj3) )
+ return -1;
+
+ if( !obj1 ){
+ self->sv = new StrokeVertex();
+
+ } else if( !obj2 && BPy_StrokeVertex_Check(obj1) && ((BPy_StrokeVertex *) obj1)->sv ) {
+ self->sv = new StrokeVertex( *(((BPy_StrokeVertex *) obj1)->sv) );
+
+ } else if( !obj2 && BPy_CurvePoint_Check(obj1) && ((BPy_CurvePoint *) obj1)->cp ) {
+ self->sv = new StrokeVertex( ((BPy_CurvePoint *) obj1)->cp );
+
+ } else if( !obj2 && BPy_SVertex_Check(obj1) && ((BPy_SVertex *) obj1)->sv ) {
+ self->sv = new StrokeVertex( ((BPy_SVertex *) obj1)->sv );
+
+ } else if( obj3 && BPy_StrokeVertex_Check(obj1) && BPy_StrokeVertex_Check(obj2) ) {
+ StrokeVertex *sv1 = ((BPy_StrokeVertex *) obj1)->sv;
+ StrokeVertex *sv2 = ((BPy_StrokeVertex *) obj2)->sv;
+ if( !sv1 || ( sv1->A() == 0 && sv1->B() == 0 ) ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 is an invalid StrokeVertex object");
+ return -1;
+ }
+ if( !sv2 || ( sv2->A() == 0 && sv2->B() == 0 ) ) {
+ PyErr_SetString(PyExc_TypeError, "argument 2 is an invalid StrokeVertex object");
+ return -1;
+ }
+ self->sv = new StrokeVertex( sv1, sv2, PyFloat_AsDouble( obj3 ) );
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
+ return -1;
+ }
+
+ self->py_cp.cp = self->sv;
+ self->py_cp.py_if0D.if0D = self->sv;
+ self->py_cp.py_if0D.borrowed = 0;
+
+ return 0;
+}
+
+static char StrokeVertex_x___doc__[] =
+".. method:: x()\n"
+"\n"
+" Returns the 2D point X coordinate.\n"
+"\n"
+" :return: The X coordinate.\n"
+" :rtype: float\n";
+
+static PyObject * StrokeVertex_x( BPy_StrokeVertex *self ) {
+ return PyFloat_FromDouble( self->sv->x() );
+}
+
+static char StrokeVertex_y___doc__[] =
+".. method:: y()\n"
+"\n"
+" Returns the 2D point Y coordinate.\n"
+"\n"
+" :return: The Y coordinate.\n"
+" :rtype: float\n";
+
+static PyObject * StrokeVertex_y( BPy_StrokeVertex *self ) {
+ return PyFloat_FromDouble( self->sv->y() );
+}
+
+static char StrokeVertex_getPoint___doc__[] =
+".. method:: getPoint()\n"
+"\n"
+" Returns the 2D point coordinates as a two-dimensional vector.\n"
+"\n"
+" :return: The 2D coordinates.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static PyObject * StrokeVertex_getPoint( BPy_StrokeVertex *self ) {
+ Vec2f v( self->sv->getPoint() );
+ return Vector_from_Vec2f( v );
+}
+
+static char StrokeVertex_attribute___doc__[] =
+".. method:: attribute()\n"
+"\n"
+" Returns the StrokeAttribute for this StrokeVertex.\n"
+"\n"
+" :return: The StrokeAttribute object.\n"
+" :rtype: :class:`StrokeAttribute`\n";
+
+static PyObject * StrokeVertex_attribute( BPy_StrokeVertex *self ) {
+ return BPy_StrokeAttribute_from_StrokeAttribute( self->sv->attribute() );
+}
+
+static char StrokeVertex_curvilinearAbscissa___doc__[] =
+".. method:: curvilinearAbscissa()\n"
+"\n"
+" Returns the curvilinear abscissa.\n"
+"\n"
+" :return: The curvilinear abscissa.\n"
+" :rtype: float\n";
+
+static PyObject * StrokeVertex_curvilinearAbscissa( BPy_StrokeVertex *self ) {
+ return PyFloat_FromDouble( self->sv->curvilinearAbscissa() );
+}
+
+static char StrokeVertex_strokeLength___doc__[] =
+".. method:: strokeLength()\n"
+"\n"
+" Returns the length of the Stroke to which this StrokeVertex belongs\n"
+"\n"
+" :return: The stroke length.\n"
+" :rtype: float\n";
+
+static PyObject * StrokeVertex_strokeLength( BPy_StrokeVertex *self ) {
+ return PyFloat_FromDouble( self->sv->strokeLength() );
+}
+
+static char StrokeVertex_u___doc__[] =
+".. method:: u()\n"
+"\n"
+" Returns the curvilinear abscissa of this StrokeVertex in the Stroke\n"
+"\n"
+" :return: The curvilinear abscissa.\n"
+" :rtype: float\n";
+
+static PyObject * StrokeVertex_u( BPy_StrokeVertex *self ) {
+ return PyFloat_FromDouble( self->sv->u() );
+}
+
+static char StrokeVertex_setX___doc__[] =
+".. method:: setX(x)\n"
+"\n"
+" Sets the 2D point X coordinate.\n"
+"\n"
+" :arg x: The X coordinate.\n"
+" :type x: float\n";
+
+static PyObject *StrokeVertex_setX( BPy_StrokeVertex *self , PyObject *args) {
+ double r;
+
+ if(!( PyArg_ParseTuple(args, "d", &r) ))
+ return NULL;
+
+ self->sv->setX( r );
+
+ Py_RETURN_NONE;
+}
+
+static char StrokeVertex_setY___doc__[] =
+".. method:: setY(y)\n"
+"\n"
+" Sets the 2D point Y coordinate.\n"
+"\n"
+" :arg y: The Y coordinate.\n"
+" :type y: float\n";
+
+static PyObject *StrokeVertex_setY( BPy_StrokeVertex *self , PyObject *args) {
+ double r;
+
+ if(!( PyArg_ParseTuple(args, "d", &r) ))
+ return NULL;
+
+ self->sv->setY( r );
+
+ Py_RETURN_NONE;
+}
+
+static char StrokeVertex_setPoint___doc__[] =
+".. method:: setPoint(x, y)\n"
+"\n"
+" Sets the 2D point X and Y coordinates.\n"
+"\n"
+" :arg x: The X coordinate.\n"
+" :type x: float\n"
+" :arg y: The Y coordinate.\n"
+" :type y: float\n"
+"\n"
+".. method:: setPoint(p)\n"
+"\n"
+" Sets the 2D point X and Y coordinates.\n"
+"\n"
+" :arg p: A two-dimensional vector.\n"
+" :type p: :class:`mathutils.Vector`, list or tuple of 2 real numbers\n";
+
+static PyObject *StrokeVertex_setPoint( BPy_StrokeVertex *self , PyObject *args) {
+ PyObject *obj1 = 0, *obj2 = 0;
+
+ if(!( PyArg_ParseTuple(args, "O|O", &obj1, &obj2) ))
+ return NULL;
+
+ if( obj1 && !obj2 ){
+ Vec2f *v = Vec2f_ptr_from_PyObject(obj1);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 2D vector (either a list of 2 elements or Vector)");
+ return NULL;
+ }
+ self->sv->setPoint( *v );
+ delete v;
+ } else if( PyFloat_Check(obj1) && obj2 && PyFloat_Check(obj2) ){
+ self->sv->setPoint( PyFloat_AsDouble(obj1), PyFloat_AsDouble(obj2) );
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid arguments");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char StrokeVertex_setAttribute___doc__[] =
+".. method:: setAttribute(iAttribute)\n"
+"\n"
+" Sets the attribute.\n"
+"\n"
+" :arg iAttribute: A StrokeAttribute object.\n"
+" :type iAttribute: :class:`StrokeAttribute`\n";
+
+static PyObject *StrokeVertex_setAttribute( BPy_StrokeVertex *self , PyObject *args) {
+ PyObject *py_sa;
+
+ if(!( PyArg_ParseTuple(args, "O!", &StrokeAttribute_Type, &py_sa) ))
+ return NULL;
+
+ self->sv->setAttribute(*( ((BPy_StrokeAttribute *) py_sa)->sa ));
+
+ Py_RETURN_NONE;
+}
+
+static char StrokeVertex_setCurvilinearAbscissa___doc__[] =
+".. method:: setCurvilinearAbscissa(iAbscissa)\n"
+"\n"
+" Sets the curvilinear abscissa of this StrokeVertex in the Stroke\n"
+"\n"
+" :arg iAbscissa: The curvilinear abscissa.\n"
+" :type iAbscissa: float\n";
+
+static PyObject *StrokeVertex_setCurvilinearAbscissa( BPy_StrokeVertex *self , PyObject *args) {
+ double r;
+
+ if(!( PyArg_ParseTuple(args, "d", &r) ))
+ return NULL;
+
+ self->sv->setCurvilinearAbscissa( r );
+
+ Py_RETURN_NONE;
+}
+
+static char StrokeVertex_setStrokeLength___doc__[] =
+".. method:: setStrokeLength(iLength)\n"
+"\n"
+" Sets the stroke length (it is only a value retained by the\n"
+" StrokeVertex, and it won't change the real stroke length).\n"
+"\n"
+" :arg iLength: The stroke length.\n"
+" :type iLength: float\n";
+
+static PyObject *StrokeVertex_setStrokeLength( BPy_StrokeVertex *self , PyObject *args) {
+ double r;
+
+ if(!( PyArg_ParseTuple(args, "d", &r) ))
+ return NULL;
+
+ self->sv->setStrokeLength( r );
+
+ Py_RETURN_NONE;
+}
+
+// real operator[] (const int i) const
+// real & operator[] (const int i)
+
+/*----------------------StrokeVertex instance definitions ----------------------------*/
+static PyMethodDef BPy_StrokeVertex_methods[] = {
+ {"x", ( PyCFunction ) StrokeVertex_x, METH_NOARGS, StrokeVertex_x___doc__},
+ {"y", ( PyCFunction ) StrokeVertex_y, METH_NOARGS, StrokeVertex_y___doc__},
+ {"getPoint", ( PyCFunction ) StrokeVertex_getPoint, METH_NOARGS, StrokeVertex_getPoint___doc__},
+ {"attribute", ( PyCFunction ) StrokeVertex_attribute, METH_NOARGS, StrokeVertex_attribute___doc__},
+ {"curvilinearAbscissa", ( PyCFunction ) StrokeVertex_curvilinearAbscissa, METH_NOARGS, StrokeVertex_curvilinearAbscissa___doc__},
+ {"strokeLength", ( PyCFunction ) StrokeVertex_strokeLength, METH_NOARGS, StrokeVertex_strokeLength___doc__},
+ {"u", ( PyCFunction ) StrokeVertex_u, METH_NOARGS, StrokeVertex_u___doc__},
+ {"setX", ( PyCFunction ) StrokeVertex_setX, METH_VARARGS, StrokeVertex_setX___doc__},
+ {"setY", ( PyCFunction ) StrokeVertex_setY, METH_VARARGS, StrokeVertex_setY___doc__},
+ {"setPoint", ( PyCFunction ) StrokeVertex_setPoint, METH_VARARGS, StrokeVertex_setPoint___doc__},
+ {"setAttribute", ( PyCFunction ) StrokeVertex_setAttribute, METH_VARARGS, StrokeVertex_setAttribute___doc__},
+ {"setCurvilinearAbscissa", ( PyCFunction ) StrokeVertex_setCurvilinearAbscissa, METH_VARARGS, StrokeVertex_setCurvilinearAbscissa___doc__},
+ {"setStrokeLength", ( PyCFunction ) StrokeVertex_setStrokeLength, METH_VARARGS, StrokeVertex_setStrokeLength___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_StrokeVertex type definition ------------------------------*/
+PyTypeObject StrokeVertex_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "StrokeVertex", /* tp_name */
+ sizeof(BPy_StrokeVertex), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ StrokeVertex___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_StrokeVertex_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &CurvePoint_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)StrokeVertex___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.h b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.h
new file mode 100644
index 00000000000..2a84e2480f0
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_STROKEVERTEX_H
+#define FREESTYLE_PYTHON_STROKEVERTEX_H
+
+#include "../BPy_CurvePoint.h"
+#include "../../../stroke/Stroke.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject StrokeVertex_Type;
+
+#define BPy_StrokeVertex_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &StrokeVertex_Type) )
+
+/*---------------------------Python BPy_StrokeVertex structure definition----------*/
+typedef struct {
+ BPy_CurvePoint py_cp;
+ StrokeVertex *sv;
+} BPy_StrokeVertex;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_STROKEVERTEX_H */
diff --git a/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp
new file mode 100644
index 00000000000..ebb2920353d
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp
@@ -0,0 +1,153 @@
+#include "BPy_NonTVertex.h"
+
+#include "../../BPy_Convert.h"
+#include "../BPy_SVertex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char NonTVertex___doc__[] =
+"Class hierarchy: :class:`Interface0D` > :class:`ViewVertex` > :class:`NonTVertex`\n"
+"\n"
+"View vertex for corners, cusps, etc. associated to a single SVertex.\n"
+"Can be associated to 2 or more view edges.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: A NonTVertex object.\n"
+" :type iBrother: :class:`NonTVertex`\n"
+"\n"
+".. method:: __init__(iSVertex)\n"
+"\n"
+" Builds a NonTVertex from a SVertex.\n"
+"\n"
+" :arg iSVertex: An SVertex object.\n"
+" :type iSVertex: :class:`SVertex`\n";
+
+static int NonTVertex___init__(BPy_NonTVertex *self, PyObject *args, PyObject *kwds)
+{
+
+ PyObject *obj = 0;
+
+ if (! PyArg_ParseTuple(args, "|O!", &SVertex_Type, &obj) )
+ return -1;
+
+ if( !obj ){
+ self->ntv = new NonTVertex();
+
+ } else if( ((BPy_SVertex *) obj)->sv ) {
+ self->ntv = new NonTVertex( ((BPy_SVertex *) obj)->sv );
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument");
+ return -1;
+ }
+
+ self->py_vv.vv = self->ntv;
+ self->py_vv.py_if0D.if0D = self->ntv;
+ self->py_vv.py_if0D.borrowed = 0;
+
+ return 0;
+}
+
+static char NonTVertex_svertex___doc__[] =
+".. method:: svertex()\n"
+"\n"
+" Returns the SVertex on top of which this NonTVertex is built.\n"
+"\n"
+" :return: The SVertex on top of which this NonTVertex is built.\n"
+" :rtype: :class:`SVertex`\n";
+
+static PyObject * NonTVertex_svertex( BPy_NonTVertex *self ) {
+ SVertex *v = self->ntv->svertex();
+ if( v ){
+ return BPy_SVertex_from_SVertex( *v );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char NonTVertex_setSVertex___doc__[] =
+".. method:: setSVertex(iSVertex)\n"
+"\n"
+" Sets the SVertex on top of which this NonTVertex is built.\n"
+"\n"
+" :arg iSVertex: The SVertex on top of which this NonTVertex is built.\n"
+" :type iSVertex: :class:`SVertex`\n";
+
+static PyObject * NonTVertex_setSVertex( BPy_NonTVertex *self, PyObject *args) {
+ PyObject *py_sv;
+
+ if(!( PyArg_ParseTuple(args, "O!", &SVertex_Type, &py_sv) ))
+ return NULL;
+
+ self->ntv->setSVertex( ((BPy_SVertex *) py_sv)->sv );
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------NonTVertex instance definitions ----------------------------*/
+static PyMethodDef BPy_NonTVertex_methods[] = {
+ {"svertex", ( PyCFunction ) NonTVertex_svertex, METH_NOARGS, NonTVertex_svertex___doc__},
+ {"setSVertex", ( PyCFunction ) NonTVertex_setSVertex, METH_VARARGS, NonTVertex_setSVertex___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_NonTVertex type definition ------------------------------*/
+PyTypeObject NonTVertex_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "NonTVertex", /* tp_name */
+ sizeof(BPy_NonTVertex), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ NonTVertex___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_NonTVertex_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &ViewVertex_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)NonTVertex___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.h b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.h
new file mode 100644
index 00000000000..071194d2d42
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_NONTVERTEX_H
+#define FREESTYLE_PYTHON_NONTVERTEX_H
+
+#include "../BPy_ViewVertex.h"
+#include "../../../view_map/ViewMap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject NonTVertex_Type;
+
+#define BPy_NonTVertex_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &NonTVertex_Type) )
+
+/*---------------------------Python BPy_NonTVertex structure definition----------*/
+typedef struct {
+ BPy_ViewVertex py_vv;
+ NonTVertex *ntv;
+} BPy_NonTVertex;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_NONTVERTEX_H */
diff --git a/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp
new file mode 100644
index 00000000000..14add743a37
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp
@@ -0,0 +1,249 @@
+#include "BPy_TVertex.h"
+
+#include "../../BPy_Convert.h"
+#include "../BPy_SVertex.h"
+#include "../../BPy_Id.h"
+#include "../../Interface1D/BPy_FEdge.h"
+#include "../../Interface1D/BPy_ViewEdge.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char TVertex___doc__[] =
+"Class hierarchy: :class:`Interface0D` > :class:`ViewVertex` > :class:`TVertex`\n"
+"\n"
+"Class to define a T vertex, i.e. an intersection between two edges.\n"
+"It points towards two SVertex and four ViewEdges. Among the\n"
+"ViewEdges, two are front and the other two are back. Basically a\n"
+"front edge hides part of a back edge. So, among the back edges, one\n"
+"is of invisibility N and the other of invisibility N+1.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: A TVertex object.\n"
+" :type iBrother: :class:`TVertex`\n";
+
+static int TVertex___init__(BPy_TVertex *self, PyObject *args, PyObject *kwds)
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->tv = new TVertex();
+ self->py_vv.vv = self->tv;
+ self->py_vv.py_if0D.if0D = self->tv;
+ self->py_vv.py_if0D.borrowed = 0;
+
+ return 0;
+}
+
+static char TVertex_frontSVertex___doc__[] =
+".. method:: frontSVertex()\n"
+"\n"
+" Returns the SVertex that is closer to the viewpoint.\n"
+"\n"
+" :return: The SVertex that is closer to the viewpoint.\n"
+" :rtype: :class:`SVertex`\n";
+
+static PyObject * TVertex_frontSVertex( BPy_TVertex *self ) {
+ SVertex *v = self->tv->frontSVertex();
+ if( v ){
+ return BPy_SVertex_from_SVertex( *v );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char TVertex_backSVertex___doc__[] =
+".. method:: backSVertex()\n"
+"\n"
+" Returns the SVertex that is further away from the viewpoint.\n"
+"\n"
+" :return: The SVertex that is further away from the viewpoint.\n"
+" :rtype: :class:`SVertex`\n";
+
+static PyObject * TVertex_backSVertex( BPy_TVertex *self ) {
+ SVertex *v = self->tv->backSVertex();
+ if( v ){
+ return BPy_SVertex_from_SVertex( *v );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char TVertex_setFrontSVertex___doc__[] =
+".. method:: setFrontSVertex(iFrontSVertex)\n"
+"\n"
+" Sets the SVertex that is closer to the viewpoint.\n"
+"\n"
+" :arg iFrontSVertex: An SVertex object.\n"
+" :type iFrontSVertex: :class:`SVertex`\n";
+
+static PyObject * TVertex_setFrontSVertex( BPy_TVertex *self, PyObject *args) {
+ PyObject *py_sv;
+
+ if(!( PyArg_ParseTuple(args, "O!", &SVertex_Type, &py_sv) ))
+ return NULL;
+
+ self->tv->setFrontSVertex( ((BPy_SVertex *) py_sv)->sv );
+
+ Py_RETURN_NONE;
+}
+
+static char TVertex_setBackSVertex___doc__[] =
+".. method:: setBackSVertex(iBackSVertex)\n"
+"\n"
+" Sets the SVertex that is further away from the viewpoint.\n"
+"\n"
+" :arg iBackSVertex: An SVertex object.\n"
+" :type iBackSVertex: :class:`SVertex`\n";
+
+static PyObject * TVertex_setBackSVertex( BPy_TVertex *self, PyObject *args) {
+ PyObject *py_sv;
+
+ if(!( PyArg_ParseTuple(args, "O", &SVertex_Type, &py_sv) ))
+ return NULL;
+
+ self->tv->setBackSVertex( ((BPy_SVertex *) py_sv)->sv );
+
+ Py_RETURN_NONE;
+}
+
+static char TVertex_setId___doc__[] =
+".. method:: setId(iId)\n"
+"\n"
+" Sets the Id.\n"
+"\n"
+" :arg iId: An Id object.\n"
+" :type iId: :class:`Id`\n";
+
+static PyObject * TVertex_setId( BPy_TVertex *self, PyObject *args) {
+ PyObject *py_id;
+
+ if(!( PyArg_ParseTuple(args, "O!", &Id_Type, &py_id) ))
+ return NULL;
+
+ if( ((BPy_Id *) py_id)->id )
+ self->tv->setId(*( ((BPy_Id *) py_id)->id ));
+
+ Py_RETURN_NONE;
+}
+
+static char TVertex_getSVertex___doc__[] =
+".. method:: getSVertex(iFEdge)\n"
+"\n"
+" Returns the SVertex (among the 2) belonging to the given FEdge.\n"
+"\n"
+" :arg iFEdge: An FEdge object.\n"
+" :type iFEdge: :class:`FEdge`\n"
+" :return: The SVertex belonging to the given FEdge.\n"
+" :rtype: :class:`SVertex`\n";
+
+static PyObject * TVertex_getSVertex( BPy_TVertex *self, PyObject *args) {
+ PyObject *py_fe;
+
+ if(!( PyArg_ParseTuple(args, "O!", &FEdge_Type, &py_fe) ))
+ return NULL;
+
+ SVertex *sv = self->tv->getSVertex( ((BPy_FEdge *) py_fe)->fe );
+ if( sv ){
+ return BPy_SVertex_from_SVertex( *sv );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char TVertex_mate___doc__[] =
+".. method:: mate(iEdgeA)\n"
+"\n"
+" Returns the mate edge of the ViewEdge given as argument. If the\n"
+" ViewEdge is frontEdgeA, frontEdgeB is returned. If the ViewEdge is\n"
+" frontEdgeB, frontEdgeA is returned. Same for back edges.\n"
+"\n"
+" :arg iEdgeA: A ViewEdge object.\n"
+" :type iEdgeA: :class:`ViewEdge`\n"
+" :return: The mate edge of the given ViewEdge.\n"
+" :rtype: :class:`ViewEdge`\n";
+
+static PyObject * TVertex_mate( BPy_TVertex *self, PyObject *args) {
+ PyObject *py_ve;
+
+ if(!( PyArg_ParseTuple(args, "O!", &ViewEdge_Type, &py_ve) ))
+ return NULL;
+
+ ViewEdge *ve = self->tv->mate( ((BPy_ViewEdge *) py_ve)->ve );
+ if( ve ){
+ return BPy_ViewEdge_from_ViewEdge( *ve );
+ }
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------TVertex instance definitions ----------------------------*/
+static PyMethodDef BPy_TVertex_methods[] = {
+ {"frontSVertex", ( PyCFunction ) TVertex_frontSVertex, METH_NOARGS, TVertex_frontSVertex___doc__},
+ {"backSVertex", ( PyCFunction ) TVertex_backSVertex, METH_NOARGS, TVertex_backSVertex___doc__},
+ {"setFrontSVertex", ( PyCFunction ) TVertex_setFrontSVertex, METH_VARARGS, TVertex_setFrontSVertex___doc__},
+ {"setBackSVertex", ( PyCFunction ) TVertex_setBackSVertex, METH_VARARGS, TVertex_setBackSVertex___doc__},
+ {"setId", ( PyCFunction ) TVertex_setId, METH_VARARGS, TVertex_setId___doc__},
+ {"getSVertex", ( PyCFunction ) TVertex_getSVertex, METH_VARARGS, TVertex_getSVertex___doc__},
+ {"mate", ( PyCFunction ) TVertex_mate, METH_VARARGS, TVertex_mate___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_TVertex type definition ------------------------------*/
+PyTypeObject TVertex_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "TVertex", /* tp_name */
+ sizeof(BPy_TVertex), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ TVertex___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_TVertex_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &ViewVertex_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)TVertex___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.h b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.h
new file mode 100644
index 00000000000..12fe5c0cb43
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_TVERTEX_H
+#define FREESTYLE_PYTHON_TVERTEX_H
+
+#include "../BPy_ViewVertex.h"
+#include "../../../view_map/ViewMap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject TVertex_Type;
+
+#define BPy_TVertex_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &TVertex_Type) )
+
+/*---------------------------Python BPy_TVertex structure definition----------*/
+typedef struct {
+ BPy_ViewVertex py_vv;
+ TVertex *tv;
+} BPy_TVertex;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_TVERTEX_H */
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
new file mode 100644
index 00000000000..a7b710f796b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
@@ -0,0 +1,416 @@
+#include "BPy_FEdge.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_Id.h"
+#include "../Interface0D/BPy_SVertex.h"
+#include "../Interface1D/BPy_ViewEdge.h"
+#include "../BPy_Nature.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char FEdge___doc__[] =
+"Class hierarchy: :class:`Interface1D` > :class:`FEdge`\n"
+"\n"
+"Base Class for feature edges. This FEdge can represent a silhouette,\n"
+"a crease, a ridge/valley, a border or a suggestive contour. For\n"
+"silhouettes, the FEdge is oriented so that the visible face lies on\n"
+"the left of the edge. For borders, the FEdge is oriented so that the\n"
+"face lies on the left of the edge. An FEdge can represent an initial\n"
+"edge of the mesh or runs accross a face of the initial mesh depending\n"
+"on the smoothness or sharpness of the mesh. This class is specialized\n"
+"into a smooth and a sharp version since their properties slightly vary\n"
+"from one to the other.\n"
+"\n"
+".. method:: FEdge()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: FEdge(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: An FEdge object.\n"
+" :type iBrother: :class:`FEdge`\n"
+"\n"
+".. method:: FEdge(vA, vB)\n"
+"\n"
+" Builds an FEdge going from vA to vB.\n"
+"\n"
+" :arg vA: The first SVertex.\n"
+" :type vA: :class:`SVertex`\n"
+" :arg vB: The second SVertex.\n"
+" :type vB: :class:`SVertex`\n";
+
+static int FEdge___init__(BPy_FEdge *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj1 = 0, *obj2 = 0;
+
+ if (! PyArg_ParseTuple(args, "|OO", &obj1, &obj2) )
+ return -1;
+
+ if( !obj1 ){
+ self->fe = new FEdge();
+
+ } else if( !obj2 && BPy_FEdge_Check(obj1) ) {
+ self->fe = new FEdge(*( ((BPy_FEdge *) obj1)->fe ));
+
+ } else if( obj2 && BPy_SVertex_Check(obj1) && BPy_SVertex_Check(obj2) ) {
+ self->fe = new FEdge( ((BPy_SVertex *) obj1)->sv, ((BPy_SVertex *) obj2)->sv );
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
+ return -1;
+ }
+
+ self->py_if1D.if1D = self->fe;
+ self->py_if1D.borrowed = 0;
+
+ return 0;
+}
+
+static char FEdge_vertexA___doc__[] =
+".. method:: vertexA()\n"
+"\n"
+" Returns the first SVertex.\n"
+"\n"
+" :return: The first SVertex.\n"
+" :rtype: :class:`SVertex`\n";
+
+static PyObject * FEdge_vertexA( BPy_FEdge *self ) {
+ SVertex *A = self->fe->vertexA();
+ if( A ){
+ return BPy_SVertex_from_SVertex( *A );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char FEdge_vertexB___doc__[] =
+".. method:: vertexB()\n"
+"\n"
+" Returns the second SVertex.\n"
+"\n"
+" :return: The second SVertex.\n"
+" :rtype: :class:`SVertex`\n";
+
+static PyObject * FEdge_vertexB( BPy_FEdge *self ) {
+ SVertex *B = self->fe->vertexB();
+ if( B ){
+ return BPy_SVertex_from_SVertex( *B );
+ }
+
+ Py_RETURN_NONE;
+}
+
+
+static PyObject * FEdge___getitem__( BPy_FEdge *self, PyObject *args ) {
+ int i;
+
+ if(!( PyArg_ParseTuple(args, "i", &i) ))
+ return NULL;
+ if(!(i == 0 || i == 1)) {
+ PyErr_SetString(PyExc_IndexError, "index must be either 0 or 1");
+ return NULL;
+ }
+
+ SVertex *v = self->fe->operator[](i);
+ if( v )
+ return BPy_SVertex_from_SVertex( *v );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdge_nextEdge___doc__[] =
+".. method:: nextEdge()\n"
+"\n"
+" Returns the FEdge following this one in the ViewEdge. If this FEdge\n"
+" is the last of the ViewEdge, None is returned.\n"
+"\n"
+" :return: The edge following this one in the ViewEdge.\n"
+" :rtype: :class:`FEdge`\n";
+
+static PyObject * FEdge_nextEdge( BPy_FEdge *self ) {
+ FEdge *fe = self->fe->nextEdge();
+ if( fe )
+ return Any_BPy_FEdge_from_FEdge( *fe );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdge_previousEdge___doc__[] =
+".. method:: previousEdge()\n"
+"\n"
+" Returns the FEdge preceding this one in the ViewEdge. If this FEdge\n"
+" is the first one of the ViewEdge, None is returned.\n"
+"\n"
+" :return: The edge preceding this one in the ViewEdge.\n"
+" :rtype: :class:`FEdge`\n";
+
+static PyObject * FEdge_previousEdge( BPy_FEdge *self ) {
+ FEdge *fe = self->fe->previousEdge();
+ if( fe )
+ return Any_BPy_FEdge_from_FEdge( *fe );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdge_viewedge___doc__[] =
+".. method:: viewedge()\n"
+"\n"
+" Returns the ViewEdge to which this FEdge belongs to.\n"
+"\n"
+" :return: The ViewEdge to which this FEdge belongs to.\n"
+" :rtype: :class:`ViewEdge`\n";
+
+static PyObject * FEdge_viewedge( BPy_FEdge *self ) {
+ ViewEdge *ve = self->fe->viewedge();
+ if( ve )
+ return BPy_ViewEdge_from_ViewEdge( *ve );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdge_isSmooth___doc__[] =
+".. method:: isSmooth()\n"
+"\n"
+" Returns true if this FEdge is a smooth FEdge.\n"
+"\n"
+" :return: True if this FEdge is a smooth FEdge.\n"
+" :rtype: bool\n";
+
+static PyObject * FEdge_isSmooth( BPy_FEdge *self ) {
+ return PyBool_from_bool( self->fe->isSmooth() );
+}
+
+static char FEdge_setVertexA___doc__[] =
+".. method:: setVertexA(vA)\n"
+"\n"
+" Sets the first SVertex.\n"
+"\n"
+" :arg vA: An SVertex object.\n"
+" :type vA: :class:`SVertex`\n";
+
+static PyObject *FEdge_setVertexA( BPy_FEdge *self , PyObject *args) {
+ PyObject *py_sv;
+
+ if(!( PyArg_ParseTuple(args, "O!", &SVertex_Type, &py_sv) ))
+ return NULL;
+
+ self->fe->setVertexA( ((BPy_SVertex *) py_sv)->sv );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdge_setVertexB___doc__[] =
+".. method:: setVertexB(vB)\n"
+"\n"
+" Sets the second SVertex.\n"
+"\n"
+" :arg vB: An SVertex object.\n"
+" :type vB: :class:`SVertex`\n";
+
+static PyObject *FEdge_setVertexB( BPy_FEdge *self , PyObject *args) {
+ PyObject *py_sv;
+
+ if(!( PyArg_ParseTuple(args, "O", &py_sv) && BPy_SVertex_Check(py_sv) )) {
+ cout << "ERROR: FEdge_setVertexB" << endl;
+ Py_RETURN_NONE;
+ }
+
+ self->fe->setVertexB( ((BPy_SVertex *) py_sv)->sv );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdge_setId___doc__[] =
+".. method:: setId(id)\n"
+"\n"
+" Sets the Id of this FEdge.\n"
+"\n"
+" :arg id: An Id object.\n"
+" :type id: :class:`Id`\n";
+
+static PyObject *FEdge_setId( BPy_FEdge *self , PyObject *args) {
+ PyObject *py_id;
+
+ if(!( PyArg_ParseTuple(args, "O!", &Id_Type, &py_id) ))
+ return NULL;
+
+ self->fe->setId(*( ((BPy_Id *) py_id)->id ));
+
+ Py_RETURN_NONE;
+}
+
+static char FEdge_setNextEdge___doc__[] =
+".. method:: setNextEdge(iEdge)\n"
+"\n"
+" Sets the pointer to the next FEdge.\n"
+"\n"
+" :arg iEdge: An FEdge object.\n"
+" :type iEdge: :class:`FEdge`\n";
+
+static PyObject *FEdge_setNextEdge( BPy_FEdge *self , PyObject *args) {
+ PyObject *py_fe;
+
+ if(!( PyArg_ParseTuple(args, "O!", &FEdge_Type, &py_fe) ))
+ return NULL;
+
+ self->fe->setNextEdge( ((BPy_FEdge *) py_fe)->fe );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdge_setPreviousEdge___doc__[] =
+".. method:: setPreviousEdge(iEdge)\n"
+"\n"
+" Sets the pointer to the previous FEdge.\n"
+"\n"
+" :arg iEdge: An FEdge object.\n"
+" :type iEdge: :class:`FEdge`\n";
+
+static PyObject *FEdge_setPreviousEdge( BPy_FEdge *self , PyObject *args) {
+ PyObject *py_fe;
+
+ if(!( PyArg_ParseTuple(args, "O!", &FEdge_Type, &py_fe) ))
+ return NULL;
+
+ self->fe->setPreviousEdge( ((BPy_FEdge *) py_fe)->fe );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdge_setNature___doc__[] =
+".. method:: setNature(iNature)\n"
+"\n"
+" Sets the nature of this FEdge.\n"
+"\n"
+" :arg iNature: A Nature object.\n"
+" :type iNature: :class:`Nature`\n";
+
+static PyObject * FEdge_setNature( BPy_FEdge *self, PyObject *args ) {
+ PyObject *py_n;
+
+ if(!( PyArg_ParseTuple(args, "O!", &Nature_Type, &py_n) ))
+ return NULL;
+
+ PyObject *i = (PyObject *) &( ((BPy_Nature *) py_n)->i );
+ self->fe->setNature( PyLong_AsLong(i) );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdge_setViewEdge___doc__[] =
+".. method:: setViewEdge(iViewEdge)\n"
+"\n"
+" Sets the ViewEdge to which this FEdge belongs to.\n"
+"\n"
+" :arg iViewEdge: A ViewEdge object.\n"
+" :type iViewEdge: :class:`ViewEdge`\n";
+
+static PyObject * FEdge_setViewEdge( BPy_FEdge *self, PyObject *args ) {
+ PyObject *py_ve;
+
+ if(!( PyArg_ParseTuple(args, "O!", &ViewEdge_Type, &py_ve) ))
+ return NULL;
+
+ ViewEdge *ve = ((BPy_ViewEdge *) py_ve)->ve;
+ self->fe->setViewEdge( ve );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdge_setSmooth___doc__[] =
+".. method:: setSmooth(iFlag)\n"
+"\n"
+" Sets the flag telling whether this FEdge is smooth or sharp. True\n"
+" for Smooth, false for Sharp.\n"
+"\n"
+" :arg iFlag: True for Smooth, false for Sharp.\n"
+" :type iFlag: bool\n";
+
+static PyObject *FEdge_setSmooth( BPy_FEdge *self , PyObject *args) {
+ PyObject *py_b;
+
+ if(!( PyArg_ParseTuple(args, "O", &py_b) ))
+ return NULL;
+
+ self->fe->setSmooth( bool_from_PyBool(py_b) );
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------FEdge instance definitions ----------------------------*/
+
+static PyMethodDef BPy_FEdge_methods[] = {
+ {"vertexA", ( PyCFunction ) FEdge_vertexA, METH_NOARGS, FEdge_vertexA___doc__},
+ {"vertexB", ( PyCFunction ) FEdge_vertexB, METH_NOARGS, FEdge_vertexB___doc__},
+ {"__getitem__", ( PyCFunction ) FEdge___getitem__, METH_VARARGS, "(int i) Returns the first SVertex if i=0, the seccond SVertex if i=1."},
+ {"nextEdge", ( PyCFunction ) FEdge_nextEdge, METH_NOARGS, FEdge_nextEdge___doc__},
+ {"previousEdge", ( PyCFunction ) FEdge_previousEdge, METH_NOARGS, FEdge_previousEdge___doc__},
+ {"viewedge", ( PyCFunction ) FEdge_viewedge, METH_NOARGS, FEdge_viewedge___doc__},
+ {"isSmooth", ( PyCFunction ) FEdge_isSmooth, METH_NOARGS, FEdge_isSmooth___doc__},
+ {"setVertexA", ( PyCFunction ) FEdge_setVertexA, METH_VARARGS, FEdge_setVertexA___doc__},
+ {"setVertexB", ( PyCFunction ) FEdge_setVertexB, METH_VARARGS, FEdge_setVertexB___doc__},
+ {"setId", ( PyCFunction ) FEdge_setId, METH_VARARGS, FEdge_setId___doc__},
+ {"setNextEdge", ( PyCFunction ) FEdge_setNextEdge, METH_VARARGS, FEdge_setNextEdge___doc__},
+ {"setPreviousEdge", ( PyCFunction ) FEdge_setPreviousEdge, METH_VARARGS, FEdge_setPreviousEdge___doc__},
+ {"setSmooth", ( PyCFunction ) FEdge_setSmooth, METH_VARARGS, FEdge_setSmooth___doc__},
+ {"setViewEdge", ( PyCFunction ) FEdge_setViewEdge, METH_VARARGS, FEdge_setViewEdge___doc__},
+ {"setNature", ( PyCFunction ) FEdge_setNature, METH_VARARGS, FEdge_setNature___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_FEdge type definition ------------------------------*/
+
+PyTypeObject FEdge_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "FEdge", /* tp_name */
+ sizeof(BPy_FEdge), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ FEdge___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_FEdge_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Interface1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)FEdge___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.h b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.h
new file mode 100644
index 00000000000..9d13145aaf2
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_FEDGE_H
+#define FREESTYLE_PYTHON_FEDGE_H
+
+#include "../BPy_Interface1D.h"
+#include "../../view_map/Silhouette.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject FEdge_Type;
+
+#define BPy_FEdge_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &FEdge_Type) )
+
+/*---------------------------Python BPy_FEdge structure definition----------*/
+typedef struct {
+ BPy_Interface1D py_if1D;
+ FEdge *fe;
+} BPy_FEdge;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_FEDGE_H */
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp
new file mode 100644
index 00000000000..5b20db3a267
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp
@@ -0,0 +1,202 @@
+#include "BPy_FrsCurve.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_Id.h"
+#include "../Interface0D/BPy_CurvePoint.h"
+#include "../Interface0D/BPy_SVertex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char FrsCurve___doc__[] =
+"Class hierarchy: :class:`Interface1D` > :class:`Curve`\n"
+"\n"
+"Base class for curves made of CurvePoints. :class:`SVertex` is the\n"
+"type of the initial curve vertices. A :class:`Chain` is a\n"
+"specialization of a Curve.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default Constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy Constructor.\n"
+"\n"
+" :arg iBrother: A Curve object.\n"
+" :type iBrother: :class:`Curve`\n"
+"\n"
+".. method:: __init__(iId)\n"
+"\n"
+" Builds a Curve from its Id.\n"
+"\n"
+" :arg iId: An Id object.\n"
+" :type iId: :class:`Id`\n";
+
+static int FrsCurve___init__(BPy_FrsCurve *self, PyObject *args, PyObject *kwds)
+{
+
+ PyObject *obj = 0;
+
+ if (! PyArg_ParseTuple(args, "|O", &obj) )
+ return -1;
+
+ if( !obj ){
+ self->c = new Curve();
+
+ } else if( BPy_FrsCurve_Check(obj) ) {
+ self->c = new Curve(*( ((BPy_FrsCurve *) obj)->c ));
+
+ } else if( BPy_Id_Check(obj) ) {
+ self->c = new Curve(*( ((BPy_Id *) obj)->id ));
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument");
+ return -1;
+ }
+
+ self->py_if1D.if1D = self->c;
+ self->py_if1D.borrowed = 0;
+
+ return 0;
+}
+
+static char FrsCurve_push_vertex_back___doc__[] =
+".. method:: push_vertex_back(iVertex)\n"
+"\n"
+" Adds a single vertex at the end of the Curve.\n"
+"\n"
+" :arg iVertex: A vertex object.\n"
+" :type iVertex: :class:`SVertex` or :class:`CurvePoint`\n";
+
+static PyObject * FrsCurve_push_vertex_back( BPy_FrsCurve *self, PyObject *args ) {
+ PyObject *obj;
+
+ if(!( PyArg_ParseTuple(args, "O", &obj) ))
+ return NULL;
+
+ if( BPy_CurvePoint_Check(obj) ) {
+ self->c->push_vertex_back( ((BPy_CurvePoint *) obj)->cp );
+ } else if( BPy_SVertex_Check(obj) ) {
+ self->c->push_vertex_back( ((BPy_SVertex *) obj)->sv );
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char FrsCurve_push_vertex_front___doc__[] =
+".. method:: push_vertex_front(iVertex)\n"
+"\n"
+" Adds a single vertex at the front of the Curve.\n"
+"\n"
+" :arg iVertex: A vertex object.\n"
+" :type iVertex: :class:`SVertex` or :class:`CurvePoint`\n";
+
+static PyObject * FrsCurve_push_vertex_front( BPy_FrsCurve *self, PyObject *args ) {
+ PyObject *obj;
+
+ if(!( PyArg_ParseTuple(args, "O", &obj) ))
+ return NULL;
+
+ if( BPy_CurvePoint_Check(obj) ) {
+ self->c->push_vertex_front( ((BPy_CurvePoint *) obj)->cp );
+ } else if( BPy_SVertex_Check(obj) ) {
+ self->c->push_vertex_front( ((BPy_SVertex *) obj)->sv );
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char FrsCurve_empty___doc__[] =
+".. method:: empty()\n"
+"\n"
+" Returns true if the Curve doesn't have any Vertex yet.\n"
+"\n"
+" :return: True if the Curve has no vertices.\n"
+" :rtype: bool\n";
+
+static PyObject * FrsCurve_empty( BPy_FrsCurve *self ) {
+ return PyBool_from_bool( self->c->empty() );
+}
+
+static char FrsCurve_nSegments___doc__[] =
+".. method:: nSegments()\n"
+"\n"
+" Returns the number of segments in the polyline constituing the\n"
+" Curve.\n"
+"\n"
+" :return: The number of segments.\n"
+" :rtype: int\n";
+
+static PyObject * FrsCurve_nSegments( BPy_FrsCurve *self ) {
+ return PyLong_FromLong( self->c->nSegments() );
+}
+
+/*----------------------FrsCurve instance definitions ----------------------------*/
+static PyMethodDef BPy_FrsCurve_methods[] = {
+ {"push_vertex_back", ( PyCFunction ) FrsCurve_push_vertex_back, METH_VARARGS, FrsCurve_push_vertex_back___doc__},
+ {"push_vertex_front", ( PyCFunction ) FrsCurve_push_vertex_front, METH_VARARGS, FrsCurve_push_vertex_front___doc__},
+ {"empty", ( PyCFunction ) FrsCurve_empty, METH_NOARGS, FrsCurve_empty___doc__},
+ {"nSegments", ( PyCFunction ) FrsCurve_nSegments, METH_NOARGS, FrsCurve_nSegments___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_FrsCurve type definition ------------------------------*/
+
+PyTypeObject FrsCurve_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Curve", /* tp_name */
+ sizeof(BPy_FrsCurve), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ FrsCurve___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_FrsCurve_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Interface1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)FrsCurve___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.h b/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.h
new file mode 100644
index 00000000000..0829cf0ebf5
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_FRSCURVE_H
+#define FREESTYLE_PYTHON_FRSCURVE_H
+
+#include "../BPy_Interface1D.h"
+#include "../../stroke/Curve.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject FrsCurve_Type;
+
+#define BPy_FrsCurve_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &FrsCurve_Type) )
+
+/*---------------------------Python BPy_FrsCurve structure definition----------*/
+typedef struct {
+ BPy_Interface1D py_if1D;
+ Curve *c;
+} BPy_FrsCurve;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_FRSCURVE_H */
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
new file mode 100644
index 00000000000..fe215588275
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
@@ -0,0 +1,517 @@
+#include "BPy_Stroke.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_Id.h"
+#include "../Interface0D/BPy_SVertex.h"
+#include "../Interface0D/CurvePoint/BPy_StrokeVertex.h"
+#include "../Iterator/BPy_StrokeVertexIterator.h"
+#include "../BPy_MediumType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+// Stroke ()
+// template<class InputVertexIterator> Stroke (InputVertexIterator iBegin, InputVertexIterator iEnd)
+//
+// pb: - need to be able to switch representation: InputVertexIterator <=> position
+// - is it even used ? not even in SWIG version
+
+static char Stroke___doc__[] =
+"Class hierarchy: :class:`Interface1D` > :class:`Stroke`\n"
+"\n"
+"Class to define a stroke. A stroke is made of a set of 2D vertices\n"
+"(:class:`StrokeVertex`), regularly spaced out. This set of vertices\n"
+"defines the stroke's backbone geometry. Each of these stroke vertices\n"
+"defines the stroke's shape and appearance at this vertex position.\n"
+"\n"
+".. method:: Stroke()\n"
+"\n"
+" Default constructor\n"
+"\n"
+".. method:: Stroke(iBrother)\n"
+"\n"
+" Copy constructor\n"
+"\n"
+" :arg iBrother: \n"
+" :type iBrother: :class:`Stroke`\n"
+"\n"
+".. method:: Stroke(iBegin, iEnd)\n"
+"\n"
+" Builds a stroke from a set of StrokeVertex. This constructor is\n"
+" templated by an iterator type. This iterator type must allow the\n"
+" vertices parsing using the ++ operator.\n"
+"\n"
+" :arg iBegin: The iterator pointing to the first vertex.\n"
+" :type iBegin: InputVertexIterator\n"
+" :arg iEnd: The iterator pointing to the end of the vertex list.\n"
+" :type iEnd: InputVertexIterator\n";
+
+static int Stroke___init__(BPy_Stroke *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj1 = NULL, *obj2 = NULL;
+
+ if (! PyArg_ParseTuple(args, "|OO", &obj1, &obj2) )
+ return -1;
+
+ if( !obj1 ){
+ self->s = new Stroke();
+
+ } else if ( !obj2 && BPy_Stroke_Check(obj1) ) {
+ self->s = new Stroke(*( ((BPy_Stroke *)obj1)->s ));
+
+ } else if ( obj2 ) {
+ PyErr_SetString(PyExc_TypeError,
+ "Stroke(InputVertexIterator iBegin, InputVertexIterator iEnd) not implemented");
+ return -1;
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
+ return -1;
+ }
+
+ self->py_if1D.if1D = self->s;
+ self->py_if1D.borrowed = 0;
+
+ return 0;
+}
+
+static PyObject * Stroke___iter__( PyObject *self ) {
+ StrokeInternal::StrokeVertexIterator sv_it( ((BPy_Stroke *)self)->s->strokeVerticesBegin() );
+ return BPy_StrokeVertexIterator_from_StrokeVertexIterator( sv_it, 0 );
+}
+
+static Py_ssize_t Stroke_length( BPy_Stroke *self ) {
+ return self->s->strokeVerticesSize();
+}
+
+static PyObject * Stroke_item( BPy_Stroke *self, Py_ssize_t i ) {
+ if (i < 0 || i >= (Py_ssize_t)self->s->strokeVerticesSize()) {
+ PyErr_SetString(PyExc_IndexError, "subscript index out of range");
+ return NULL;
+ }
+ return BPy_StrokeVertex_from_StrokeVertex( self->s->strokeVerticeAt(i) );
+}
+
+static PyObject * Stroke___getitem__( BPy_Stroke *self, PyObject *item ) {
+ long i;
+
+ if (!PyLong_Check(item)) {
+ PyErr_SetString(PyExc_TypeError, "subscript indices must be integers");
+ return NULL;
+ }
+ i = PyLong_AsLong(item);
+ if (i == -1 && PyErr_Occurred())
+ return NULL;
+ if (i < 0) {
+ i += self->s->strokeVerticesSize();
+ }
+ return Stroke_item(self, i);
+}
+
+static char Stroke_ComputeSampling___doc__[] =
+".. method:: ComputeSampling(iNVertices)\n"
+"\n"
+" Compute the sampling needed to get iNVertices vertices. If the\n"
+" specified number of vertices is less than the actual number of\n"
+" vertices, the actual sampling value is returned. (To remove Vertices,\n"
+" use the RemoveVertex() method of this class.)\n"
+"\n"
+" :arg iNVertices: The number of stroke vertices we eventually want\n"
+" in our Stroke.\n"
+" :type iNVertices: int\n"
+" :return: The sampling that must be used in the Resample(float)\n"
+" method.\n"
+" :rtype: float\n";
+
+static PyObject * Stroke_ComputeSampling( BPy_Stroke *self, PyObject *args ) {
+ int i;
+
+ if(!( PyArg_ParseTuple(args, "i", &i) ))
+ return NULL;
+
+ return PyFloat_FromDouble( self->s->ComputeSampling( i ) );
+}
+
+static char Stroke_Resample___doc__[] =
+".. method:: Resample(iNPoints)\n"
+"\n"
+" Resamples the stroke so that it eventually has iNPoints. That means\n"
+" it is going to add iNPoints-vertices_size, if vertices_size is the\n"
+" number of points we already have. If vertices_size >= iNPoints, no\n"
+" resampling is done.\n"
+"\n"
+" :arg iNPoints: The number of vertices we eventually want in our stroke.\n"
+" :type iNPoints: int\n"
+"\n"
+".. method:: Resample(iSampling)\n"
+"\n"
+" Resamples the stroke with a given sampling. If the sampling is\n"
+" smaller than the actual sampling value, no resampling is done.\n"
+"\n"
+" :arg iSampling: The new sampling value.\n"
+" :type iSampling: float\n";
+
+static PyObject * Stroke_Resample( BPy_Stroke *self, PyObject *args ) {
+ PyObject *obj;
+
+ if(!( PyArg_ParseTuple(args, "O", &obj) ))
+ return NULL;
+
+ if( PyLong_Check(obj) )
+ self->s->Resample( (int) PyLong_AsLong(obj) );
+ else if( PyFloat_Check(obj) )
+ self->s->Resample( (float) PyFloat_AsDouble(obj) );
+ else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char Stroke_InsertVertex___doc__[] =
+".. method:: InsertVertex(iVertex, next)\n"
+"\n"
+" Inserts the stroke vertex iVertex in the stroke before next. The\n"
+" length, curvilinear abscissa are updated consequently.\n"
+"\n"
+" :arg iVertex: The StrokeVertex to insert in the Stroke.\n"
+" :type iVertex: :class:`StrokeVertex`\n"
+" :arg next: A StrokeVertexIterator pointing to the StrokeVertex\n"
+" before which iVertex must be inserted.\n"
+" :type next: :class:`StrokeVertexIterator`\n";
+
+static PyObject * Stroke_InsertVertex( BPy_Stroke *self, PyObject *args ) {
+ PyObject *py_sv = 0, *py_sv_it = 0;
+
+ if(!( PyArg_ParseTuple(args, "O!O!", &StrokeVertex_Type, &py_sv, &StrokeVertexIterator_Type, &py_sv_it) ))
+ return NULL;
+
+ StrokeVertex *sv = ((BPy_StrokeVertex *) py_sv)->sv;
+ StrokeInternal::StrokeVertexIterator sv_it(*( ((BPy_StrokeVertexIterator *) py_sv_it)->sv_it ));
+ self->s->InsertVertex( sv, sv_it );
+
+ Py_RETURN_NONE;
+}
+
+static char Stroke_RemoveVertex___doc__[] =
+".. method:: RemoveVertex(iVertex)\n"
+"\n"
+" Removes the stroke vertex iVertex from the stroke. The length and\n"
+" curvilinear abscissa are updated consequently.\n"
+"\n"
+" :arg iVertex: \n"
+" :type iVertex: :class:`StrokeVertex`\n";
+
+static PyObject * Stroke_RemoveVertex( BPy_Stroke *self, PyObject *args ) {
+ PyObject *py_sv;
+
+ if(!( PyArg_ParseTuple(args, "O!", &StrokeVertex_Type, &py_sv) ))
+ return NULL;
+
+ if( ((BPy_StrokeVertex *) py_sv)->sv )
+ self->s->RemoveVertex( ((BPy_StrokeVertex *) py_sv)->sv );
+ else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument");
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char Stroke_UpdateLength___doc__[] =
+".. method:: UpdateLength()\n"
+"\n"
+" Updates the 2D length of the Stroke.\n";
+
+static PyObject * Stroke_UpdateLength( BPy_Stroke *self ) {
+ self->s->UpdateLength();
+
+ Py_RETURN_NONE;
+}
+
+static char Stroke_getLength2D___doc__[] =
+".. method:: getLength2D()\n"
+"\n"
+" Returns the 2D length of the Stroke.\n"
+"\n"
+" :return: the 2D length of the Stroke.\n"
+" :rtype: float\n";
+
+static PyObject * Stroke_getLength2D( BPy_Stroke *self ) {
+ return PyFloat_FromDouble( self->s->getLength2D() );
+}
+
+static char Stroke_getMediumType___doc__[] =
+".. method:: getMediumType()\n"
+"\n"
+" Returns the MediumType used for this Stroke.\n"
+"\n"
+" :return: the MediumType used for this Stroke.\n"
+" :rtype: :class:`MediumType`\n";
+
+static PyObject * Stroke_getMediumType( BPy_Stroke *self ) {
+ return BPy_MediumType_from_MediumType( self->s->getMediumType() );
+}
+
+static char Stroke_getTextureId___doc__[] =
+".. method:: getTextureId()\n"
+"\n"
+" Returns the ID of the texture used to simulate th marks system for\n"
+" this Stroke\n"
+"\n"
+" :return: The texture ID.\n"
+" :rtype: int\n";
+
+static PyObject * Stroke_getTextureId( BPy_Stroke *self ) {
+ return PyLong_FromLong( self->s->getTextureId() );
+}
+
+static char Stroke_hasTips___doc__[] =
+".. method:: hasTips()\n"
+"\n"
+" Returns true if this Stroke uses a texture with tips, false\n"
+" otherwise.\n"
+"\n"
+" :return: True if this Stroke uses a texture with tips.\n"
+" :rtype: bool\n";
+
+static PyObject * Stroke_hasTips( BPy_Stroke *self ) {
+ return PyBool_from_bool( self->s->hasTips() );
+}
+
+static char Stroke_setId___doc__[] =
+".. method:: setId(id)\n"
+"\n"
+" Sets the Id of the Stroke.\n"
+"\n"
+" :arg id: the Id of the Stroke.\n"
+" :type id: :class:`Id`\n";
+
+static PyObject *Stroke_setId( BPy_Stroke *self , PyObject *args) {
+ PyObject *py_id;
+
+ if(!( PyArg_ParseTuple(args, "O!", &Id_Type, &py_id) ))
+ return NULL;
+
+ self->s->setId(*( ((BPy_Id *) py_id)->id ));
+
+ Py_RETURN_NONE;
+}
+
+static char Stroke_setLength___doc__[] =
+".. method:: setLength(iLength)\n"
+"\n"
+" Sets the 2D length of the Stroke.\n"
+"\n"
+" :arg iLength: The 2D length of the Stroke.\n"
+" :type iLength: float\n";
+
+static PyObject *Stroke_setLength( BPy_Stroke *self , PyObject *args) {
+ float f;
+
+ if(!( PyArg_ParseTuple(args, "f", &f) ))
+ return NULL;
+
+ self->s->setLength( f );
+
+ Py_RETURN_NONE;
+}
+
+static char Stroke_setMediumType___doc__[] =
+".. method:: setMediumType(iType)\n"
+"\n"
+" Sets the medium type that must be used for this Stroke.\n"
+"\n"
+" :arg iType: A MediumType object.\n"
+" :type iType: :class:`MediumType`\n";
+
+static PyObject *Stroke_setMediumType( BPy_Stroke *self , PyObject *args) {
+ PyObject *py_mt;
+
+ if(!( PyArg_ParseTuple(args, "O!", &MediumType_Type, &py_mt) ))
+ return NULL;
+
+ self->s->setMediumType( MediumType_from_BPy_MediumType(py_mt) );
+
+ Py_RETURN_NONE;
+}
+
+static char Stroke_setTextureId___doc__[] =
+".. method:: setTextureId(iId)\n"
+"\n"
+" Sets the texture ID to be used to simulate the marks system for this\n"
+" Stroke.\n"
+"\n"
+" :arg iId: A texture ID.\n"
+" :type iId: int\n";
+
+static PyObject *Stroke_setTextureId( BPy_Stroke *self , PyObject *args) {
+ unsigned int i;
+
+ if(!( PyArg_ParseTuple(args, "I", &i) ))
+ return NULL;
+
+ self->s->setTextureId( i );
+
+ Py_RETURN_NONE;
+}
+
+static char Stroke_setTips___doc__[] =
+".. method:: setTips(iTips)\n"
+"\n"
+" Sets the flag telling whether this stroke is using a texture with\n"
+" tips or not.\n"
+"\n"
+" :arg iTips: True if this stroke uses a texture with tips.\n"
+" :type iTips: bool\n";
+
+static PyObject *Stroke_setTips( BPy_Stroke *self , PyObject *args) {
+ PyObject *py_b;
+
+ if(!( PyArg_ParseTuple(args, "O", &py_b) ))
+ return NULL;
+
+ self->s->setTips( bool_from_PyBool(py_b) );
+
+ Py_RETURN_NONE;
+}
+
+static char Stroke_strokeVerticesBegin___doc__[] =
+".. method:: strokeVerticesBegin(t=0.0)\n"
+"\n"
+" Returns a StrokeVertexIterator pointing on the first StrokeVertex of\n"
+" the Stroke. O ne can specify a sampling value to resample the Stroke\n"
+" on the fly if needed.\n"
+"\n"
+" :arg t: The resampling value with which we want our Stroke to be\n"
+" resampled. If 0 is specified, no resampling is done.\n"
+" :type t: float\n"
+" :return: A StrokeVertexIterator pointing on the first StrokeVertex.\n"
+" :rtype: :class:`StrokeVertexIterator`\n";
+
+static PyObject * Stroke_strokeVerticesBegin( BPy_Stroke *self , PyObject *args) {
+ float f = 0;
+
+ if(!( PyArg_ParseTuple(args, "|f", &f) ))
+ return NULL;
+
+ StrokeInternal::StrokeVertexIterator sv_it( self->s->strokeVerticesBegin(f) );
+ return BPy_StrokeVertexIterator_from_StrokeVertexIterator( sv_it, 0 );
+}
+
+static char Stroke_strokeVerticesEnd___doc__[] =
+".. method:: strokeVerticesEnd()\n"
+"\n"
+" Returns a StrokeVertexIterator pointing after the last StrokeVertex\n"
+" of the Stroke.\n"
+"\n"
+" :return: A StrokeVertexIterator pointing after the last StrokeVertex.\n"
+" :rtype: :class:`StrokeVertexIterator`\n";
+
+static PyObject * Stroke_strokeVerticesEnd( BPy_Stroke *self ) {
+ StrokeInternal::StrokeVertexIterator sv_it( self->s->strokeVerticesEnd() );
+ return BPy_StrokeVertexIterator_from_StrokeVertexIterator( sv_it, 1 );
+}
+
+static char Stroke_strokeVerticesSize___doc__[] =
+".. method:: strokeVerticesSize()\n"
+"\n"
+" Returns the number of StrokeVertex constituing the Stroke.\n"
+"\n"
+" :return: The number of stroke vertices.\n"
+" :rtype: int\n";
+
+static PyObject * Stroke_strokeVerticesSize( BPy_Stroke *self ) {
+ return PyLong_FromLong( self->s->strokeVerticesSize() );
+}
+
+/*----------------------Stroke instance definitions ----------------------------*/
+
+static PyMethodDef BPy_Stroke_methods[] = {
+ {"__getitem__", ( PyCFunction ) Stroke___getitem__, METH_O, "(int i) Returns the i-th StrokeVertex constituting the Stroke."},
+ {"ComputeSampling", ( PyCFunction ) Stroke_ComputeSampling, METH_VARARGS, Stroke_ComputeSampling___doc__},
+ {"Resample", ( PyCFunction ) Stroke_Resample, METH_VARARGS, Stroke_Resample___doc__},
+ {"RemoveVertex", ( PyCFunction ) Stroke_RemoveVertex, METH_VARARGS, Stroke_RemoveVertex___doc__},
+ {"InsertVertex", ( PyCFunction ) Stroke_InsertVertex, METH_VARARGS, Stroke_InsertVertex___doc__},
+ {"UpdateLength", ( PyCFunction ) Stroke_UpdateLength, METH_NOARGS, Stroke_UpdateLength___doc__},
+ {"getLength2D", ( PyCFunction ) Stroke_getLength2D, METH_NOARGS, Stroke_getLength2D___doc__},
+ {"getMediumType", ( PyCFunction ) Stroke_getMediumType, METH_NOARGS, Stroke_getMediumType___doc__},
+ {"getTextureId", ( PyCFunction ) Stroke_getTextureId, METH_NOARGS, Stroke_getTextureId___doc__},
+ {"hasTips", ( PyCFunction ) Stroke_hasTips, METH_NOARGS, Stroke_hasTips___doc__},
+ {"setId", ( PyCFunction ) Stroke_setId, METH_VARARGS, Stroke_setId___doc__},
+ {"setLength", ( PyCFunction ) Stroke_setLength, METH_VARARGS, Stroke_setLength___doc__},
+ {"setMediumType", ( PyCFunction ) Stroke_setMediumType, METH_VARARGS, Stroke_setMediumType___doc__},
+ {"setTextureId", ( PyCFunction ) Stroke_setTextureId, METH_VARARGS, Stroke_setTextureId___doc__},
+ {"setTips", ( PyCFunction ) Stroke_setTips, METH_VARARGS, Stroke_setTips___doc__},
+ {"strokeVerticesBegin", ( PyCFunction ) Stroke_strokeVerticesBegin, METH_VARARGS, Stroke_strokeVerticesBegin___doc__},
+ {"strokeVerticesEnd", ( PyCFunction ) Stroke_strokeVerticesEnd, METH_NOARGS, Stroke_strokeVerticesEnd___doc__},
+ {"strokeVerticesSize", ( PyCFunction ) Stroke_strokeVerticesSize, METH_NOARGS, Stroke_strokeVerticesSize___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_Stroke type definition ------------------------------*/
+
+static PySequenceMethods Stroke_as_sequence = {
+ (lenfunc)Stroke_length, /* sq_length */
+ NULL, /* sq_concat */
+ NULL, /* sq_repeat */
+ (ssizeargfunc)Stroke_item, /* sq_item */
+ NULL, /* sq_slice */
+ NULL, /* sq_ass_item */
+ NULL, /* sq_ass_slice */
+ NULL, /* sq_contains */
+ NULL, /* sq_inplace_concat */
+ NULL, /* sq_inplace_repeat */
+};
+
+PyTypeObject Stroke_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Stroke", /* tp_name */
+ sizeof(BPy_Stroke), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ &Stroke_as_sequence, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Stroke___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)Stroke___iter__, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_Stroke_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Interface1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Stroke___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.h b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.h
new file mode 100644
index 00000000000..52c6d214b85
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_STROKE_H
+#define FREESTYLE_PYTHON_STROKE_H
+
+#include "../BPy_Interface1D.h"
+#include "../../stroke/Stroke.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject Stroke_Type;
+
+#define BPy_Stroke_Check(v) (( (PyObject *) v)->ob_type == &Stroke_Type)
+
+/*---------------------------Python BPy_Stroke structure definition----------*/
+typedef struct {
+ BPy_Interface1D py_if1D;
+ Stroke *s;
+} BPy_Stroke;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_STROKE_H */
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp
new file mode 100644
index 00000000000..e35ea82ace2
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp
@@ -0,0 +1,463 @@
+#include "BPy_ViewEdge.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_Id.h"
+#include "../Interface0D/BPy_ViewVertex.h"
+#include "../Interface1D/BPy_FEdge.h"
+#include "../Interface1D/BPy_ViewEdge.h"
+#include "../BPy_Nature.h"
+#include "../BPy_ViewShape.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ViewEdge___doc__[] =
+"Class hierarchy: :class:`Interface1D` > :class:`ViewEdge`\n"
+"\n"
+"Class defining a ViewEdge. A ViewEdge in an edge of the image graph.\n"
+"it connnects two :class:`ViewVertex` objects. It is made by connecting\n"
+"a set of FEdges.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: A ViewEdge object.\n"
+" :type iBrother: :class:`ViewEdge`\n";
+
+static int ViewEdge___init__(BPy_ViewEdge *self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->ve = new ViewEdge();
+ self->py_if1D.if1D = self->ve;
+ self->py_if1D.borrowed = 0;
+
+ return 0;
+}
+
+static char ViewEdge_A___doc__[] =
+".. method:: A()\n"
+"\n"
+" Returns the first ViewVertex.\n"
+"\n"
+" :return: The first ViewVertex.\n"
+" :rtype: :class:`ViewVertex`\n";
+
+static PyObject * ViewEdge_A( BPy_ViewEdge *self ) {
+ ViewVertex *v = self->ve->A();
+ if( v ){
+ return Any_BPy_ViewVertex_from_ViewVertex( *v );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_B___doc__[] =
+".. method:: B()\n"
+"\n"
+" Returns the second ViewVertex.\n"
+"\n"
+" :return: The second ViewVertex.\n"
+" :rtype: :class:`ViewVertex`\n";
+
+static PyObject * ViewEdge_B( BPy_ViewEdge *self ) {
+ ViewVertex *v = self->ve->B();
+ if( v ){
+ return Any_BPy_ViewVertex_from_ViewVertex( *v );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_fedgeA___doc__[] =
+".. method:: fedgeA()\n"
+"\n"
+" Returns the first FEdge that constitutes this ViewEdge.\n"
+"\n"
+" :return: The first FEdge constituting this ViewEdge.\n"
+" :rtype: :class:`FEdge`\n";
+
+static PyObject * ViewEdge_fedgeA( BPy_ViewEdge *self ) {
+ FEdge *A = self->ve->fedgeA();
+ if( A ){
+ return Any_BPy_FEdge_from_FEdge( *A );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_fedgeB___doc__[] =
+".. method:: fedgeB()\n"
+"\n"
+" Returns the last FEdge that constitutes this ViewEdge.\n"
+"\n"
+" :return: The last FEdge constituting this ViewEdge.\n"
+" :rtype: :class:`FEdge`\n";
+
+static PyObject * ViewEdge_fedgeB( BPy_ViewEdge *self ) {
+ FEdge *B = self->ve->fedgeB();
+ if( B ){
+ return Any_BPy_FEdge_from_FEdge( *B );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_viewShape___doc__[] =
+".. method:: viewShape()\n"
+"\n"
+" Returns the ViewShape to which this ViewEdge belongs to.\n"
+"\n"
+" :return: The ViewShape to which this ViewEdge belongs to.\n"
+" :rtype: :class:`ViewShape`\n";
+
+static PyObject * ViewEdge_viewShape( BPy_ViewEdge *self ) {
+ ViewShape *vs = self->ve->viewShape();
+ if( vs ){
+ return BPy_ViewShape_from_ViewShape( *vs );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_aShape___doc__[] =
+".. method:: aShape()\n"
+"\n"
+" Returns the shape that is occluded by the ViewShape to which this\n"
+" ViewEdge belongs to. If no object is occluded, None is returned.\n"
+"\n"
+" :return: The occluded ViewShape.\n"
+" :rtype: :class:`ViewShape`\n";
+
+static PyObject * ViewEdge_aShape( BPy_ViewEdge *self ) {
+ ViewShape *vs = self->ve->aShape();
+ if( vs ){
+ return BPy_ViewShape_from_ViewShape( *vs );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_isClosed___doc__[] =
+".. method:: isClosed()\n"
+"\n"
+" Tells whether this ViewEdge forms a closed loop or not.\n"
+"\n"
+" :return: True if this ViewEdge forms a closed loop.\n"
+" :rtype: bool\n";
+
+static PyObject * ViewEdge_isClosed( BPy_ViewEdge *self ) {
+ return PyBool_from_bool( self->ve->isClosed() );
+}
+
+static char ViewEdge_getChainingTimeStamp___doc__[] =
+".. method:: getChainingTimeStamp()\n"
+"\n"
+" Returns the time stamp of this ViewEdge.\n"
+"\n"
+" :return: The time stamp.\n"
+" :rtype: int\n";
+
+static PyObject * ViewEdge_getChainingTimeStamp( BPy_ViewEdge *self ) {
+ return PyLong_FromLong( self->ve->getChainingTimeStamp() );
+}
+
+static char ViewEdge_setChainingTimeStamp___doc__[] =
+".. method:: setChainingTimeStamp(ts)\n"
+"\n"
+" Sets the time stamp value.\n"
+"\n"
+" :arg ts: The time stamp.\n"
+" :type ts: int\n";
+
+static PyObject * ViewEdge_setChainingTimeStamp( BPy_ViewEdge *self, PyObject *args) {
+ int timestamp = 0 ;
+
+ if( !PyArg_ParseTuple(args, "i", &timestamp) )
+ return NULL;
+
+ self->ve->setChainingTimeStamp( timestamp );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_setA___doc__[] =
+".. method:: setA(iA)\n"
+"\n"
+" Sets the first ViewVertex of the ViewEdge.\n"
+"\n"
+" :arg iA: The first ViewVertex of the ViewEdge.\n"
+" :type iA: :class:`ViewVertex`\n";
+
+static PyObject *ViewEdge_setA( BPy_ViewEdge *self , PyObject *args) {
+ PyObject *py_vv;
+
+ if(!( PyArg_ParseTuple(args, "O!", &ViewVertex_Type, &py_vv) ))
+ return NULL;
+
+ self->ve->setA( ((BPy_ViewVertex *) py_vv)->vv );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_setB___doc__[] =
+".. method:: setB(iB)\n"
+"\n"
+" Sets the last ViewVertex of the ViewEdge.\n"
+"\n"
+" :arg iB: The last ViewVertex of the ViewEdge.\n"
+" :type iB: :class:`ViewVertex`\n";
+
+static PyObject *ViewEdge_setB( BPy_ViewEdge *self , PyObject *args) {
+ PyObject *py_vv;
+
+ if(!( PyArg_ParseTuple(args, "O!", &ViewVertex_Type, &py_vv) ))
+ return NULL;
+
+ self->ve->setB( ((BPy_ViewVertex *) py_vv)->vv );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_setNature___doc__[] =
+".. method:: setNature(iNature)\n"
+"\n"
+" Sets the nature of the ViewEdge.\n"
+"\n"
+" :arg iNature: The nature of the ViewEdge.\n"
+" :type iNature: :class:`Nature`\n";
+
+static PyObject * ViewEdge_setNature( BPy_ViewEdge *self, PyObject *args ) {
+ PyObject *py_n;
+
+ if(!( PyArg_ParseTuple(args, "O!", &Nature_Type, &py_n) ))
+ return NULL;
+
+ PyObject *i = (PyObject *) &( ((BPy_Nature *) py_n)->i );
+ self->ve->setNature( PyLong_AsLong(i) );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_setFEdgeA___doc__[] =
+".. method:: setFEdgeA(iFEdge)\n"
+"\n"
+" Sets the first FEdge of the ViewEdge.\n"
+"\n"
+" :arg iFEdge: The first FEdge of the ViewEdge.\n"
+" :type iFEdge: :class:`FEdge`\n";
+
+static PyObject * ViewEdge_setFEdgeA( BPy_ViewEdge *self, PyObject *args ) {
+ PyObject *py_fe;
+
+ if(!( PyArg_ParseTuple(args, "O!", &FEdge_Type, &py_fe) ))
+ return NULL;
+
+ self->ve->setFEdgeA( ((BPy_FEdge *) py_fe)->fe );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_setFEdgeB___doc__[] =
+".. method:: setFEdgeB(iFEdge)\n"
+"\n"
+" Sets the last FEdge of the ViewEdge.\n"
+"\n"
+" :arg iFEdge: The last FEdge of the ViewEdge.\n"
+" :type iFEdge: :class:`FEdge`\n";
+
+static PyObject * ViewEdge_setFEdgeB( BPy_ViewEdge *self, PyObject *args ) {
+ PyObject *py_fe;
+
+ if(!( PyArg_ParseTuple(args, "O!", &FEdge_Type, &py_fe) ))
+ return NULL;
+
+ self->ve->setFEdgeB( ((BPy_FEdge *) py_fe)->fe );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_setShape___doc__[] =
+".. method:: setShape(iVShape)\n"
+"\n"
+" Sets the ViewShape to which this ViewEdge belongs to.\n"
+"\n"
+" :arg iVShape: The ViewShape to which this ViewEdge belongs to.\n"
+" :type iVShape: :class:`ViewShape`\n";
+
+static PyObject * ViewEdge_setShape( BPy_ViewEdge *self, PyObject *args ) {
+ PyObject *py_vs;
+
+ if(!( PyArg_ParseTuple(args, "O", &ViewShape_Type, &py_vs) ))
+ return NULL;
+
+ self->ve->setShape( ((BPy_ViewShape *) py_vs)->vs );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_setId___doc__[] =
+".. method:: setId(id)\n"
+"\n"
+" Sets the ViewEdge id.\n"
+"\n"
+" :arg id: An Id object.\n"
+" :type id: :class:`Id`\n";
+
+static PyObject * ViewEdge_setId( BPy_ViewEdge *self, PyObject *args ) {
+ PyObject *py_id;
+
+ if(!( PyArg_ParseTuple(args, "O!", &Id_Type, &py_id) ))
+ return NULL;
+
+ Id id(*( ((BPy_Id *) py_id)->id ));
+ self->ve->setId( id );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_UpdateFEdges___doc__[] =
+".. method:: UpdateFEdges()\n"
+"\n"
+" Sets Viewedge to this for all embedded fedges.\n";
+
+static PyObject * ViewEdge_UpdateFEdges( BPy_ViewEdge *self ) {
+ self->ve->UpdateFEdges();
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_setaShape___doc__[] =
+".. method:: setaShape(iShape)\n"
+"\n"
+" Sets the occluded ViewShape.\n"
+"\n"
+" :arg iShape: A ViewShape object.\n"
+" :type iShape: :class:`ViewShape`\n";
+
+static PyObject * ViewEdge_setaShape( BPy_ViewEdge *self, PyObject *args ) {
+ PyObject *py_vs;
+
+ if(!( PyArg_ParseTuple(args, "O!", &ViewShape_Type, &py_vs) ))
+ return NULL;
+
+ ViewShape *vs = ((BPy_ViewShape *) py_vs)->vs;
+ self->ve->setaShape( vs );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_setQI___doc__[] =
+".. method:: setQI(qi)\n"
+"\n"
+" Sets the quantitative invisibility value of the ViewEdge.\n"
+"\n"
+" :arg qi: The quantitative invisibility.\n"
+" :type qi: int\n";
+
+static PyObject * ViewEdge_setQI( BPy_ViewEdge *self, PyObject *args ) {
+ int qi;
+
+ if(!( PyArg_ParseTuple(args, "i", &qi) ))
+ return NULL;
+
+ self->ve->setQI( qi );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdge_qi___doc__[] =
+".. method:: getChainingTimeStamp()\n"
+"\n"
+" Returns the quantitative invisibility value of the ViewEdge.\n"
+"\n"
+" :return: The quantitative invisibility.\n"
+" :rtype: int\n";
+
+static PyObject * ViewEdge_qi( BPy_ViewEdge *self ) {
+ return PyLong_FromLong( self->ve->qi() );
+}
+
+/*----------------------ViewEdge instance definitions ----------------------------*/
+static PyMethodDef BPy_ViewEdge_methods[] = {
+ {"A", ( PyCFunction ) ViewEdge_A, METH_NOARGS, ViewEdge_A___doc__},
+ {"B", ( PyCFunction ) ViewEdge_B, METH_NOARGS, ViewEdge_B___doc__},
+ {"fedgeA", ( PyCFunction ) ViewEdge_fedgeA, METH_NOARGS, ViewEdge_fedgeA___doc__},
+ {"fedgeB", ( PyCFunction ) ViewEdge_fedgeB, METH_NOARGS, ViewEdge_fedgeB___doc__},
+ {"viewShape", ( PyCFunction ) ViewEdge_viewShape, METH_NOARGS, ViewEdge_viewShape___doc__},
+ {"aShape", ( PyCFunction ) ViewEdge_aShape, METH_NOARGS, ViewEdge_aShape___doc__},
+ {"isClosed", ( PyCFunction ) ViewEdge_isClosed, METH_NOARGS, ViewEdge_isClosed___doc__},
+ {"getChainingTimeStamp", ( PyCFunction ) ViewEdge_getChainingTimeStamp, METH_NOARGS, ViewEdge_getChainingTimeStamp___doc__},
+ {"setChainingTimeStamp", ( PyCFunction ) ViewEdge_setChainingTimeStamp, METH_VARARGS, ViewEdge_setChainingTimeStamp___doc__},
+ {"setA", ( PyCFunction ) ViewEdge_setA, METH_VARARGS, ViewEdge_setA___doc__},
+ {"setB", ( PyCFunction ) ViewEdge_setB, METH_VARARGS, ViewEdge_setB___doc__},
+ {"setNature", ( PyCFunction ) ViewEdge_setNature, METH_VARARGS, ViewEdge_setNature___doc__},
+ {"setFEdgeA", ( PyCFunction ) ViewEdge_setFEdgeA, METH_VARARGS, ViewEdge_setFEdgeA___doc__},
+ {"setFEdgeB", ( PyCFunction ) ViewEdge_setFEdgeB, METH_VARARGS, ViewEdge_setFEdgeB___doc__},
+ {"setShape", ( PyCFunction ) ViewEdge_setShape, METH_VARARGS, ViewEdge_setShape___doc__},
+ {"setId", ( PyCFunction ) ViewEdge_setId, METH_VARARGS, ViewEdge_setId___doc__},
+ {"UpdateFEdges", ( PyCFunction ) ViewEdge_UpdateFEdges, METH_NOARGS, ViewEdge_UpdateFEdges___doc__},
+ {"setaShape", ( PyCFunction ) ViewEdge_setaShape, METH_VARARGS, ViewEdge_setaShape___doc__},
+ {"setQI", ( PyCFunction ) ViewEdge_setQI, METH_VARARGS, ViewEdge_setQI___doc__},
+ {"qi", ( PyCFunction ) ViewEdge_qi, METH_NOARGS, ViewEdge_qi___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_ViewEdge type definition ------------------------------*/
+
+PyTypeObject ViewEdge_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ViewEdge", /* tp_name */
+ sizeof(BPy_ViewEdge), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ViewEdge___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_ViewEdge_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Interface1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ViewEdge___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.h b/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.h
new file mode 100644
index 00000000000..ead377377e8
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.h
@@ -0,0 +1,32 @@
+#ifndef FREESTYLE_PYTHON_VIEWEDGE_H
+#define FREESTYLE_PYTHON_VIEWEDGE_H
+
+#include "../../view_map/ViewMap.h"
+
+#include "../BPy_Interface1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ViewEdge_Type;
+
+#define BPy_ViewEdge_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ViewEdge_Type) )
+
+/*---------------------------Python BPy_ViewEdge structure definition----------*/
+typedef struct {
+ BPy_Interface1D py_if1D;
+ ViewEdge *ve;
+} BPy_ViewEdge;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_VIEWEDGE_H */
diff --git a/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp b/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp
new file mode 100644
index 00000000000..343e65e9fe6
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp
@@ -0,0 +1,171 @@
+#include "BPy_Chain.h"
+
+#include "../../BPy_Convert.h"
+#include "../../BPy_Id.h"
+#include "../BPy_ViewEdge.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Chain___doc__[] =
+"Class hierarchy: :class:`Interface1D` > :class:`Curve` > :class:`Chain`\n"
+"\n"
+"Class to represent a 1D elements issued from the chaining process. A\n"
+"Chain is the last step before the :class:`Stroke` and is used in the\n"
+"Splitting and Creation processes.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Defult constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: A Chain object.\n"
+" :type iBrother: :class:`Chain`\n"
+"\n"
+".. method:: __init__(id)\n"
+"\n"
+" Builds a chain from its Id.\n"
+"\n"
+" :arg id: An Id object.\n"
+" :type id: :class:`Id`\n";
+
+static int Chain___init__(BPy_Chain *self, PyObject *args, PyObject *kwds)
+{
+
+ PyObject *obj = 0;
+
+ if (! PyArg_ParseTuple(args, "|O", &obj) )
+ return -1;
+
+ if( !obj ){
+ self->c = new Chain();
+
+ } else if( BPy_Chain_Check(obj) ) {
+ self->c = new Chain(*( ((BPy_Chain *) obj)->c ));
+
+ } else if( BPy_Id_Check(obj) ) {
+ self->c = new Chain(*( ((BPy_Id *) obj)->id ));
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument");
+ return -1;
+ }
+
+ self->py_c.c = self->c;
+ self->py_c.py_if1D.if1D = self->c;
+ self->py_c.py_if1D.borrowed = 0;
+
+ return 0;
+}
+
+static char Chain_push_viewedge_back___doc__[] =
+".. method:: push_viewedge_back(iViewEdge, orientation)\n"
+"\n"
+" Adds a ViewEdge at the end of the Chain.\n"
+"\n"
+" :arg iViewEdge: The ViewEdge that must be added.\n"
+" :type iViewEdge: :class:`ViewEdge`\n"
+" :arg orientation: The orientation with which the ViewEdge must be\n"
+" processed.\n"
+" :type orientation: bool\n";
+
+static PyObject * Chain_push_viewedge_back( BPy_Chain *self, PyObject *args ) {
+ PyObject *obj1 = 0, *obj2 = 0;
+
+ if(!( PyArg_ParseTuple(args, "O!O", &ViewEdge_Type, &obj1, &obj2) ))
+ return NULL;
+
+ ViewEdge *ve = ((BPy_ViewEdge *) obj1)->ve;
+ bool orientation = bool_from_PyBool( obj2 );
+ self->c->push_viewedge_back( ve, orientation);
+
+ Py_RETURN_NONE;
+}
+
+static char Chain_push_viewedge_front___doc__[] =
+".. method:: push_viewedge_front(iViewEdge, orientation)\n"
+"\n"
+" Adds a ViewEdge at the beginning of the Chain.\n"
+"\n"
+" :arg iViewEdge: The ViewEdge that must be added.\n"
+" :type iViewEdge: :class:`ViewEdge`\n"
+" :arg orientation: The orientation with which the ViewEdge must be\n"
+" processed.\n"
+" :type orientation: bool\n";
+
+static PyObject * Chain_push_viewedge_front( BPy_Chain *self, PyObject *args ) {
+ PyObject *obj1 = 0, *obj2 = 0;
+
+ if(!( PyArg_ParseTuple(args, "O!O", &ViewEdge_Type, &obj1, &obj2) ))
+ return NULL;
+
+ ViewEdge *ve = ((BPy_ViewEdge *) obj1)->ve;
+ bool orientation = bool_from_PyBool( obj2 );
+ self->c->push_viewedge_front(ve, orientation);
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------Chain instance definitions ----------------------------*/
+static PyMethodDef BPy_Chain_methods[] = {
+ {"push_viewedge_back", ( PyCFunction ) Chain_push_viewedge_back, METH_VARARGS, Chain_push_viewedge_back___doc__},
+ {"push_viewedge_front", ( PyCFunction ) Chain_push_viewedge_front, METH_VARARGS, Chain_push_viewedge_front___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_Chain type definition ------------------------------*/
+
+PyTypeObject Chain_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Chain", /* tp_name */
+ sizeof(BPy_Chain), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Chain___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_Chain_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &FrsCurve_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Chain___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.h b/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.h
new file mode 100644
index 00000000000..19f325ef513
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_CHAIN_H
+#define FREESTYLE_PYTHON_CHAIN_H
+
+#include "../BPy_FrsCurve.h"
+#include "../../../stroke/Chain.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject Chain_Type;
+
+#define BPy_Chain_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Chain_Type) )
+
+/*---------------------------Python BPy_Chain structure definition----------*/
+typedef struct {
+ BPy_FrsCurve py_c;
+ Chain *c;
+} BPy_Chain;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CHAIN_H */
diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
new file mode 100644
index 00000000000..39d644b7714
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
@@ -0,0 +1,373 @@
+#include "BPy_FEdgeSharp.h"
+
+#include "../../BPy_Convert.h"
+#include "../../Interface0D/BPy_SVertex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char FEdgeSharp___doc__[] =
+"Class hierarchy: :class:`Interface1D` > :class:`FEdge` > :class:`FEdgeSharp`\n"
+"\n"
+"Class defining a sharp FEdge. A Sharp FEdge corresponds to an initial\n"
+"edge of the input mesh. It can be a silhouette, a crease or a border.\n"
+"If it is a crease edge, then it is borded by two faces of the mesh.\n"
+"Face a lies on its right whereas Face b lies on its left. If it is a\n"
+"border edge, then it doesn't have any face on its right, and thus Face\n"
+"a is None.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: An FEdgeSharp object.\n"
+" :type iBrother: :class:`FEdgeSharp`\n"
+"\n"
+".. method:: __init__(vA, vB)\n"
+"\n"
+" Builds an FEdgeSharp going from vA to vB.\n"
+"\n"
+" :arg vA: The first SVertex object.\n"
+" :type vA: :class:`SVertex`\n"
+" :arg vB: The second SVertex object.\n"
+" :type vB: :class:`SVertex`\n";
+
+static int FEdgeSharp___init__(BPy_FEdgeSharp *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj1 = 0, *obj2 = 0;
+
+ if (! PyArg_ParseTuple(args, "|OO", &obj1, &obj2) )
+ return -1;
+
+ if( !obj1 ){
+ self->fes = new FEdgeSharp();
+
+ } else if( !obj2 && BPy_FEdgeSharp_Check(obj1) ) {
+ self->fes = new FEdgeSharp(*( ((BPy_FEdgeSharp *) obj1)->fes ));
+
+ } else if( obj2 && BPy_SVertex_Check(obj1) && BPy_SVertex_Check(obj2) ) {
+ self->fes = new FEdgeSharp( ((BPy_SVertex *) obj1)->sv, ((BPy_SVertex *) obj2)->sv );
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
+ return -1;
+ }
+
+ self->py_fe.fe = self->fes;
+ self->py_fe.py_if1D.if1D = self->fes;
+ self->py_fe.py_if1D.borrowed = 0;
+
+ return 0;
+}
+
+static char FEdgeSharp_normalA___doc__[] =
+".. method:: normalA()\n"
+"\n"
+" Returns the normal to the face lying on the right of the FEdge. If\n"
+" this FEdge is a border, it has no Face on its right and therefore, no\n"
+" normal.\n"
+"\n"
+" :return: The normal to the face lying on the right of the FEdge.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static PyObject * FEdgeSharp_normalA( BPy_FEdgeSharp *self ) {
+ Vec3r v( self->fes->normalA() );
+ return Vector_from_Vec3r( v );
+}
+
+static char FEdgeSharp_normalB___doc__[] =
+".. method:: normalB()\n"
+"\n"
+" Returns the normal to the face lying on the left of the FEdge.\n"
+"\n"
+" :return: The normal to the face lying on the left of the FEdge.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static PyObject * FEdgeSharp_normalB( BPy_FEdgeSharp *self ) {
+ Vec3r v( self->fes->normalB() );
+ return Vector_from_Vec3r( v );
+}
+
+static char FEdgeSharp_aMaterialIndex___doc__[] =
+".. method:: aMaterialIndex()\n"
+"\n"
+" Returns the index of the material of the face lying on the right of\n"
+" the FEdge. If this FEdge is a border, it has no Face on its right and\n"
+" therefore, no material.\n"
+"\n"
+" :return: The index of the material of the face lying on the right of\n"
+" the FEdge.\n"
+" :rtype: int\n";
+
+static PyObject * FEdgeSharp_aMaterialIndex( BPy_FEdgeSharp *self ) {
+ return PyLong_FromLong( self->fes->aFrsMaterialIndex() );
+}
+
+static char FEdgeSharp_bMaterialIndex___doc__[] =
+".. method:: bMaterialIndex()\n"
+"\n"
+" Returns the index of the material of the face lying on the left of\n"
+" the FEdge.\n"
+"\n"
+" :return: The index of the material of the face lying on the left of\n"
+" the FEdge.\n"
+" :rtype: int\n";
+
+static PyObject * FEdgeSharp_bMaterialIndex( BPy_FEdgeSharp *self ) {
+ return PyLong_FromLong( self->fes->bFrsMaterialIndex() );
+}
+
+static char FEdgeSharp_aMaterial___doc__[] =
+".. method:: aMaterial()\n"
+"\n"
+" Returns the material of the face lying on the right of the FEdge. If\n"
+" this FEdge is a border, it has no Face on its right and therefore, no\n"
+" material.\n"
+"\n"
+" :return: The material of the face lying on the right of the FEdge.\n"
+" :rtype: :class:`Material`\n";
+
+static PyObject * FEdgeSharp_aMaterial( BPy_FEdgeSharp *self ) {
+ FrsMaterial m( self->fes->aFrsMaterial() );
+ return BPy_FrsMaterial_from_FrsMaterial(m);
+}
+
+static char FEdgeSharp_bMaterial___doc__[] =
+".. method:: bMaterial()\n"
+"\n"
+" Returns the material of the face lying on the left of the FEdge.\n"
+"\n"
+" :return: The material of the face lying on the left of the FEdge.\n"
+" :rtype: :class:`Material`\n";
+
+static PyObject * FEdgeSharp_bMaterial( BPy_FEdgeSharp *self ) {
+ FrsMaterial m( self->fes->aFrsMaterial() );
+ return BPy_FrsMaterial_from_FrsMaterial(m);
+}
+
+static char FEdgeSharp_aFaceMark___doc__[] =
+".. method:: aFaceMark()\n"
+"\n"
+" Returns the face mark of the face lying on the right of the FEdge.\n"
+" If this FEdge is a border, it has no face on the right, and thus\n"
+" false is returned.\n"
+"\n"
+" :return: The face mark of the face lying on the right of the FEdge.\n"
+" :rtype: bool\n";
+
+static PyObject * FEdgeSharp_aFaceMark( BPy_FEdgeSharp *self ) {
+ return PyBool_from_bool( self->fes->aFaceMark() );
+}
+
+static char FEdgeSharp_bFaceMark___doc__[] =
+".. method:: bFaceMark()\n"
+"\n"
+" Returns the face mark of the face lying on the left of the FEdge.\n"
+"\n"
+" :return: The face mark of the face lying on the left of the FEdge.\n"
+" :rtype: bool\n";
+
+static PyObject * FEdgeSharp_bFaceMark( BPy_FEdgeSharp *self ) {
+ return PyBool_from_bool( self->fes->bFaceMark() );
+}
+
+static char FEdgeSharp_setNormalA___doc__[] =
+".. method:: setNormalA(iNormal)\n"
+"\n"
+" Sets the normal to the face lying on the right of the FEdge.\n"
+"\n"
+" :arg iNormal: A three-dimensional vector.\n"
+" :type iNormal: :class:`mathutils.Vector`, list or tuple of 3 real numbers\n";
+
+static PyObject * FEdgeSharp_setNormalA( BPy_FEdgeSharp *self, PyObject *args ) {
+ PyObject *obj = 0;
+
+ if(!( PyArg_ParseTuple(args, "O", &obj) ))
+ return NULL;
+ Vec3r *v = Vec3r_ptr_from_PyObject(obj);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 3D vector (either a list of 3 elements or Vector)");
+ return NULL;
+ }
+ self->fes->setNormalA( *v );
+ delete v;
+
+ Py_RETURN_NONE;
+}
+
+static char FEdgeSharp_setNormalB___doc__[] =
+".. method:: setNormalB(iNormal)\n"
+"\n"
+" Sets the normal to the face lying on the left of the FEdge.\n"
+"\n"
+" :arg iNormal: A three-dimensional vector.\n"
+" :type iNormal: :class:`mathutils.Vector`, list or tuple of 3 real numbers\n";
+
+static PyObject * FEdgeSharp_setNormalB( BPy_FEdgeSharp *self, PyObject *args ) {
+ PyObject *obj = 0;
+
+ if(!( PyArg_ParseTuple(args, "O", &obj) ))
+ return NULL;
+ Vec3r *v = Vec3r_ptr_from_PyObject(obj);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 3D vector (either a list of 3 elements or Vector)");
+ return NULL;
+ }
+ self->fes->setNormalB( *v );
+ delete v;
+
+ Py_RETURN_NONE;
+}
+
+static char FEdgeSharp_setaMaterialIndex___doc__[] =
+".. method:: setaMaterialIndex(i)\n"
+"\n"
+" Sets the index of the material lying on the right of the FEdge.\n"
+"\n"
+" :arg i: A material index.\n"
+" :type i: int\n";
+
+static PyObject * FEdgeSharp_setaMaterialIndex( BPy_FEdgeSharp *self, PyObject *args ) {
+ unsigned int i;
+
+ if(!( PyArg_ParseTuple(args, "I", &i) ))
+ return NULL;
+
+ self->fes->setaFrsMaterialIndex( i );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdgeSharp_setbMaterialIndex___doc__[] =
+".. method:: setbMaterialIndex(i)\n"
+"\n"
+" Sets the index of the material lying on the left of the FEdge.\n"
+"\n"
+" :arg i: A material index.\n"
+" :type i: int\n";
+
+static PyObject * FEdgeSharp_setbMaterialIndex( BPy_FEdgeSharp *self, PyObject *args ) {
+ unsigned int i;
+
+ if(!( PyArg_ParseTuple(args, "I", &i) ))
+ return NULL;
+
+ self->fes->setbFrsMaterialIndex( i );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdgeSharp_setaFaceMark___doc__[] =
+".. method:: setaFaceMark(i)\n"
+"\n"
+" Sets the face mark of the face lying on the right of the FEdge.\n"
+"\n"
+" :arg i: A face mark.\n"
+" :type i: bool\n";
+
+static PyObject * FEdgeSharp_setaFaceMark( BPy_FEdgeSharp *self, PyObject *args ) {
+ PyObject *obj;
+
+ if(!( PyArg_ParseTuple(args, "O", &obj) ))
+ return NULL;
+
+ self->fes->setaFaceMark( bool_from_PyBool(obj) );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdgeSharp_setbFaceMark___doc__[] =
+".. method:: setbFaceMark(i)\n"
+"\n"
+" Sets the face mark of the face lying on the left of the FEdge.\n"
+"\n"
+" :arg i: A face mark.\n"
+" :type i: bool\n";
+
+static PyObject * FEdgeSharp_setbFaceMark( BPy_FEdgeSharp *self, PyObject *args ) {
+ PyObject *obj;
+
+ if(!( PyArg_ParseTuple(args, "O", &obj) ))
+ return NULL;
+
+ self->fes->setbFaceMark( bool_from_PyBool(obj) );
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------FEdgeSharp instance definitions ----------------------------*/
+static PyMethodDef BPy_FEdgeSharp_methods[] = {
+ {"normalA", ( PyCFunction ) FEdgeSharp_normalA, METH_NOARGS, FEdgeSharp_normalA___doc__},
+ {"normalB", ( PyCFunction ) FEdgeSharp_normalB, METH_NOARGS, FEdgeSharp_normalB___doc__},
+ {"aMaterialIndex", ( PyCFunction ) FEdgeSharp_aMaterialIndex, METH_NOARGS, FEdgeSharp_aMaterialIndex___doc__},
+ {"bMaterialIndex", ( PyCFunction ) FEdgeSharp_bMaterialIndex, METH_NOARGS, FEdgeSharp_bMaterialIndex___doc__},
+ {"aMaterial", ( PyCFunction ) FEdgeSharp_aMaterial, METH_NOARGS, FEdgeSharp_aMaterial___doc__},
+ {"bMaterial", ( PyCFunction ) FEdgeSharp_bMaterial, METH_NOARGS, FEdgeSharp_bMaterial___doc__},
+ {"aFaceMark", ( PyCFunction ) FEdgeSharp_aFaceMark, METH_NOARGS, FEdgeSharp_aFaceMark___doc__},
+ {"bFaceMark", ( PyCFunction ) FEdgeSharp_bFaceMark, METH_NOARGS, FEdgeSharp_bFaceMark___doc__},
+ {"setNormalA", ( PyCFunction ) FEdgeSharp_setNormalA, METH_VARARGS, FEdgeSharp_setNormalA___doc__},
+ {"setNormalB", ( PyCFunction ) FEdgeSharp_setNormalB, METH_VARARGS, FEdgeSharp_setNormalB___doc__},
+ {"setaMaterialIndex", ( PyCFunction ) FEdgeSharp_setaMaterialIndex, METH_VARARGS, FEdgeSharp_setaMaterialIndex___doc__},
+ {"setbMaterialIndex", ( PyCFunction ) FEdgeSharp_setbMaterialIndex, METH_VARARGS, FEdgeSharp_setbMaterialIndex___doc__},
+ {"setaFaceMark", ( PyCFunction ) FEdgeSharp_setaFaceMark, METH_NOARGS, FEdgeSharp_setaFaceMark___doc__},
+ {"setbFaceMark", ( PyCFunction ) FEdgeSharp_setbFaceMark, METH_NOARGS, FEdgeSharp_setbFaceMark___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_FEdgeSharp type definition ------------------------------*/
+
+PyTypeObject FEdgeSharp_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "FEdgeSharp", /* tp_name */
+ sizeof(BPy_FEdgeSharp), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ FEdgeSharp___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_FEdgeSharp_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &FEdge_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)FEdgeSharp___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.h b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.h
new file mode 100644
index 00000000000..84b01e27c21
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_FEDGESHARP_H
+#define FREESTYLE_PYTHON_FEDGESHARP_H
+
+#include "../BPy_FEdge.h"
+#include "../../../view_map/Silhouette.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject FEdgeSharp_Type;
+
+#define BPy_FEdgeSharp_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &FEdgeSharp_Type) )
+
+/*---------------------------Python BPy_FEdgeSharp structure definition----------*/
+typedef struct {
+ BPy_FEdge py_fe;
+ FEdgeSharp *fes;
+} BPy_FEdgeSharp;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_FEDGESHARP_H */
diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
new file mode 100644
index 00000000000..3ddb4d060de
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
@@ -0,0 +1,240 @@
+#include "BPy_FEdgeSmooth.h"
+
+#include "../../BPy_Convert.h"
+#include "../../Interface0D/BPy_SVertex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char FEdgeSmooth___doc__[] =
+"Class hierarchy: :class:`Interface1D` > :class:`FEdge` > :class:`FEdgeSmooth`\n"
+"\n"
+"Class defining a smooth edge. This kind of edge typically runs across\n"
+"a face of the input mesh. It can be a silhouette, a ridge or valley,\n"
+"a suggestive contour.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: An FEdgeSmooth object.\n"
+" :type iBrother: :class:`FEdgeSmooth`\n"
+"\n"
+".. method:: __init__(vA, vB)\n"
+"\n"
+" Builds an FEdgeSmooth going from vA to vB.\n"
+"\n"
+" :arg vA: The first SVertex object.\n"
+" :type vA: :class:`SVertex`\n"
+" :arg vB: The second SVertex object.\n"
+" :type vB: :class:`SVertex`\n";
+
+static int FEdgeSmooth___init__(BPy_FEdgeSmooth *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj1 = 0, *obj2 = 0;
+
+ if (! PyArg_ParseTuple(args, "|OO", &obj1, &obj2) )
+ return -1;
+
+ if( !obj1 ){
+ self->fes = new FEdgeSmooth();
+
+ } else if( !obj2 && BPy_FEdgeSmooth_Check(obj1) ) {
+ self->fes = new FEdgeSmooth(*( ((BPy_FEdgeSmooth *) obj1)->fes ));
+
+ } else if( obj2 && BPy_SVertex_Check(obj1) && BPy_SVertex_Check(obj2) ) {
+ self->fes = new FEdgeSmooth( ((BPy_SVertex *) obj1)->sv, ((BPy_SVertex *) obj2)->sv );
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
+ return -1;
+ }
+
+ self->py_fe.fe = self->fes;
+ self->py_fe.py_if1D.if1D = self->fes;
+ self->py_fe.py_if1D.borrowed = 0;
+
+ return 0;
+}
+
+static char FEdgeSmooth_normal___doc__[] =
+".. method:: normal()\n"
+"\n"
+" Returns the normal to the Face it is running accross.\n"
+"\n"
+" :return: The normal to the Face it is running accross.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static PyObject * FEdgeSmooth_normal( BPy_FEdgeSmooth *self ) {
+ Vec3r v( self->fes->normal() );
+ return Vector_from_Vec3r( v );
+}
+
+static char FEdgeSmooth_materialIndex___doc__[] =
+".. method:: materialIndex()\n"
+"\n"
+" Returns the index of the material of the face it is running accross.\n"
+"\n"
+" :return: The index of the material of the face it is running accross.\n"
+" :rtype: int\n";
+
+static PyObject * FEdgeSmooth_materialIndex( BPy_FEdgeSmooth *self ) {
+ return PyLong_FromLong( self->fes->frs_materialIndex() );
+}
+
+static char FEdgeSmooth_material___doc__[] =
+".. method:: material()\n"
+"\n"
+" Returns the material of the face it is running accross.\n"
+"\n"
+" :return: The material of the face it is running accross.\n"
+" :rtype: :class:`Material`\n";
+
+static PyObject * FEdgeSmooth_material( BPy_FEdgeSmooth *self ) {
+ FrsMaterial m( self->fes->frs_material() );
+ return BPy_FrsMaterial_from_FrsMaterial(m);
+}
+
+static char FEdgeSmooth_faceMark___doc__[] =
+".. method:: faceMark()\n"
+"\n"
+" Returns the face mark of the face it is running across.\n"
+"\n"
+" :return: The face mark of the face it is running across.\n"
+" :rtype: bool\n";
+
+static PyObject * FEdgeSmooth_faceMark( BPy_FEdgeSmooth *self ) {
+ return PyBool_from_bool( self->fes->faceMark() );
+}
+
+static char FEdgeSmooth_setNormal___doc__[] =
+".. method:: setNormal(iNormal)\n"
+"\n"
+" Sets the normal to the Face it is running accross.\n"
+"\n"
+" :arg iNormal: A three-dimensional vector.\n"
+" :type iNormal: :class:`mathutils.Vector`, list or tuple of 3 real numbers\n";
+
+static PyObject * FEdgeSmooth_setNormal( BPy_FEdgeSmooth *self, PyObject *args ) {
+ PyObject *obj = 0;
+
+ if(!( PyArg_ParseTuple(args, "O", &obj) ))
+ return NULL;
+ Vec3r *v = Vec3r_ptr_from_PyObject(obj);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be a 3D vector (either a list of 3 elements or Vector)");
+ return NULL;
+ }
+ self->fes->setNormal( *v );
+ delete v;
+
+ Py_RETURN_NONE;
+}
+
+static char FEdgeSmooth_setMaterialIndex___doc__[] =
+".. method:: setMaterialIndex(i)\n"
+"\n"
+" Sets the index of the material of the face it is running accross.\n"
+"\n"
+" :arg i: The index of the material of the face it is running accross.\n"
+" :type i: int\n";
+
+static PyObject * FEdgeSmooth_setMaterialIndex( BPy_FEdgeSmooth *self, PyObject *args ) {
+ unsigned int i;
+
+ if(!( PyArg_ParseTuple(args, "I", &i) ))
+ return NULL;
+
+ self->fes->setFrsMaterialIndex( i );
+
+ Py_RETURN_NONE;
+}
+
+static char FEdgeSmooth_setFaceMark___doc__[] =
+".. method:: setFaceMark(i)\n"
+"\n"
+" Sets the face mark of the face it is running across.\n"
+"\n"
+" :arg i: A face mark.\n"
+" :type i: bool\n";
+
+static PyObject * FEdgeSmooth_setFaceMark( BPy_FEdgeSmooth *self, PyObject *args ) {
+ PyObject *obj;
+
+ if(!( PyArg_ParseTuple(args, "O", &obj) ))
+ return NULL;
+
+ self->fes->setFaceMark( bool_from_PyBool(obj) );
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------FEdgeSmooth instance definitions ----------------------------*/
+static PyMethodDef BPy_FEdgeSmooth_methods[] = {
+ {"normal", ( PyCFunction ) FEdgeSmooth_normal, METH_NOARGS, FEdgeSmooth_normal___doc__},
+ {"materialIndex", ( PyCFunction ) FEdgeSmooth_materialIndex, METH_NOARGS, FEdgeSmooth_materialIndex___doc__},
+ {"material", ( PyCFunction ) FEdgeSmooth_material, METH_NOARGS, FEdgeSmooth_material___doc__},
+ {"faceMark", ( PyCFunction ) FEdgeSmooth_faceMark, METH_NOARGS, FEdgeSmooth_faceMark___doc__},
+ {"setNormal", ( PyCFunction ) FEdgeSmooth_setNormal, METH_VARARGS, FEdgeSmooth_setNormal___doc__},
+ {"setMaterialIndex", ( PyCFunction ) FEdgeSmooth_setMaterialIndex, METH_VARARGS, FEdgeSmooth_setMaterialIndex___doc__},
+ {"setFaceMark", ( PyCFunction ) FEdgeSmooth_setFaceMark, METH_VARARGS, FEdgeSmooth_setFaceMark___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_FEdgeSmooth type definition ------------------------------*/
+
+PyTypeObject FEdgeSmooth_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "FEdgeSmooth", /* tp_name */
+ sizeof(BPy_FEdgeSmooth), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ FEdgeSmooth___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_FEdgeSmooth_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &FEdge_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)FEdgeSmooth___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.h b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.h
new file mode 100644
index 00000000000..d7b44bb1da7
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_FEDGESMOOTH_H
+#define FREESTYLE_PYTHON_FEDGESMOOTH_H
+
+#include "../BPy_FEdge.h"
+#include "../../../view_map/Silhouette.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject FEdgeSmooth_Type;
+
+#define BPy_FEdgeSmooth_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &FEdgeSmooth_Type) )
+
+/*---------------------------Python BPy_FEdgeSmooth structure definition----------*/
+typedef struct {
+ BPy_FEdge py_fe;
+ FEdgeSmooth *fes;
+} BPy_FEdgeSmooth;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_FEDGESMOOTH_H */
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp
new file mode 100644
index 00000000000..1f4b041cce8
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp
@@ -0,0 +1,167 @@
+#include "BPy_AdjacencyIterator.h"
+
+#include "../BPy_Convert.h"
+#include "../Interface0D/BPy_ViewVertex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char AdjacencyIterator___doc__[] =
+"Class hierarchy: :class:`Iterator` > :class:`AdjacencyIterator`\n"
+"\n"
+"Class for representing adjacency iterators used in the chaining\n"
+"process. An AdjacencyIterator is created in the increment() and\n"
+"decrement() methods of a :class:`ChainingIterator` and passed to the\n"
+"traverse() method of the ChainingIterator.\n"
+"\n"
+".. method:: __init__(iVertex, iRestrictToSelection=True, iRestrictToUnvisited=True)\n"
+"\n"
+" Builds a AdjacencyIterator object.\n"
+"\n"
+" :arg iVertex: The vertex which is the next crossing.\n"
+" :type iVertex: :class:`ViewVertex`\n"
+" :arg iRestrictToSelection: Indicates whether to force the chaining\n"
+" to stay within the set of selected ViewEdges or not.\n"
+" :type iRestrictToSelection: bool\n"
+" :arg iRestrictToUnvisited: Indicates whether a ViewEdge that has\n"
+" already been chained must be ignored ot not.\n"
+" :type iRestrictToUnvisited: bool\n"
+"\n"
+".. method:: __init__(it)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg it: An AdjacencyIterator object.\n"
+" :type it: :class:`AdjacencyIterator`\n";
+
+static int AdjacencyIterator___init__(BPy_AdjacencyIterator *self, PyObject *args )
+{
+ PyObject *obj1 = 0, *obj2 = 0 , *obj3 = 0;
+
+ if (! PyArg_ParseTuple(args, "|OOO", &obj1, &obj2, &obj3) )
+ return -1;
+
+ if( !obj1 && !obj2 && !obj3 ){
+ self->a_it = new AdjacencyIterator();
+
+ } else if( BPy_AdjacencyIterator_Check(obj1) ) {
+ self->a_it = new AdjacencyIterator(*( ((BPy_AdjacencyIterator *) obj1)->a_it ));
+
+ } else if( BPy_ViewVertex_Check(obj1) ) {
+ bool restrictToSelection = ( obj2 ) ? bool_from_PyBool(obj2) : true;
+ bool restrictToUnvisited = ( obj3 ) ? bool_from_PyBool(obj3) : true;
+
+ self->a_it = new AdjacencyIterator( ((BPy_ViewVertex *) obj1)->vv, restrictToSelection, restrictToUnvisited );
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
+ return -1;
+ }
+
+ self->py_it.it = self->a_it;
+
+ return 0;
+
+}
+
+static PyObject * AdjacencyIterator_iternext(BPy_AdjacencyIterator *self) {
+ if (self->a_it->isEnd()) {
+ PyErr_SetNone(PyExc_StopIteration);
+ return NULL;
+ }
+ ViewEdge *ve = self->a_it->operator*();
+ self->a_it->increment();
+ return BPy_ViewEdge_from_ViewEdge( *ve );
+}
+
+static char AdjacencyIterator_isIncoming___doc__[] =
+".. method:: isIncoming()\n"
+"\n"
+" Returns true if the current ViewEdge is coming towards the\n"
+" iteration vertex. False otherwise.\n"
+"\n"
+" :return: True if the current ViewEdge is coming towards the\n"
+" iteration vertex\n"
+" :rtype: bool\n";
+
+static PyObject * AdjacencyIterator_isIncoming(BPy_AdjacencyIterator *self) {
+ return PyBool_from_bool(self->a_it->isIncoming());
+}
+
+static char AdjacencyIterator_getObject___doc__[] =
+".. method:: getObject()\n"
+"\n"
+" Returns the pointed ViewEdge.\n"
+"\n"
+" :return: The pointed ViewEdge.\n"
+" :rtype: :class:`ViewEdge`\n";
+
+static PyObject * AdjacencyIterator_getObject(BPy_AdjacencyIterator *self) {
+
+ ViewEdge *ve = self->a_it->operator*();
+ if( ve )
+ return BPy_ViewEdge_from_ViewEdge( *ve );
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------AdjacencyIterator instance definitions ----------------------------*/
+static PyMethodDef BPy_AdjacencyIterator_methods[] = {
+ {"isIncoming", ( PyCFunction ) AdjacencyIterator_isIncoming, METH_NOARGS, AdjacencyIterator_isIncoming___doc__},
+ {"getObject", ( PyCFunction ) AdjacencyIterator_getObject, METH_NOARGS, AdjacencyIterator_getObject___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_AdjacencyIterator type definition ------------------------------*/
+
+PyTypeObject AdjacencyIterator_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "AdjacencyIterator", /* tp_name */
+ sizeof(BPy_AdjacencyIterator), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ AdjacencyIterator___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ PyObject_SelfIter, /* tp_iter */
+ (iternextfunc)AdjacencyIterator_iternext, /* tp_iternext */
+ BPy_AdjacencyIterator_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Iterator_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)AdjacencyIterator___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.h b/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.h
new file mode 100644
index 00000000000..733a9f2fcab
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.h
@@ -0,0 +1,32 @@
+#ifndef FREESTYLE_PYTHON_ADJACENCYITERATOR_H
+#define FREESTYLE_PYTHON_ADJACENCYITERATOR_H
+
+#include "../../stroke/ChainingIterators.h"
+#include "../BPy_Iterator.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject AdjacencyIterator_Type;
+
+#define BPy_AdjacencyIterator_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &AdjacencyIterator_Type) )
+
+/*---------------------------Python BPy_AdjacencyIterator structure definition----------*/
+typedef struct {
+ BPy_Iterator py_it;
+ AdjacencyIterator *a_it;
+} BPy_AdjacencyIterator;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_ADJACENCYITERATOR_H */
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
new file mode 100644
index 00000000000..aa6d10ddb5f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
@@ -0,0 +1,205 @@
+#include "BPy_ChainPredicateIterator.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_BinaryPredicate1D.h"
+#include "../Interface1D/BPy_ViewEdge.h"
+#include "../BPy_UnaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ChainPredicateIterator___doc__[] =
+"Class hierarchy: :class:`Iterator` > :class:`ViewEdgeIterator` > :class:`ChainingIterator` > :class:`ChainPredicateIterator`\n"
+"\n"
+"A \"generic\" user-controlled ViewEdge iterator. This iterator is in\n"
+"particular built from a unary predicate and a binary predicate.\n"
+"First, the unary predicate is evaluated for all potential next\n"
+"ViewEdges in order to only keep the ones respecting a certain\n"
+"constraint. Then, the binary predicate is evaluated on the current\n"
+"ViewEdge together with each ViewEdge of the previous selection. The\n"
+"first ViewEdge respecting both the unary predicate and the binary\n"
+"predicate is kept as the next one. If none of the potential next\n"
+"ViewEdge respects these two predicates, None is returned.\n"
+"\n"
+".. method:: __init__(iRestrictToSelection=True, iRestrictToUnvisited=True, begin=None, orientation=True)\n"
+"\n"
+" Builds a ChainPredicateIterator from a starting ViewEdge and its\n"
+" orientation.\n"
+"\n"
+" :arg iRestrictToSelection: Indicates whether to force the chaining\n"
+" to stay within the set of selected ViewEdges or not.\n"
+" :type iRestrictToSelection: bool\n"
+" :arg iRestrictToUnvisited: Indicates whether a ViewEdge that has\n"
+" already been chained must be ignored ot not.\n"
+" :type iRestrictToUnvisited: bool\n"
+" :arg begin: The ViewEdge from where to start the iteration.\n"
+" :type begin: :class:`ViewEdge` or None\n"
+" :arg orientation: If true, we'll look for the next ViewEdge among\n"
+" the ViewEdges that surround the ending ViewVertex of begin. If\n"
+" false, we'll search over the ViewEdges surrounding the ending\n"
+" ViewVertex of begin. \n"
+" :type orientation: bool\n"
+"\n"
+".. method:: __init__(upred, bpred, iRestrictToSelection=True, iRestrictToUnvisited=True, begin=None, orientation=True)\n"
+"\n"
+" Builds a ChainPredicateIterator from a unary predicate, a binary\n"
+" predicate, a starting ViewEdge and its orientation.\n"
+"\n"
+" :arg upred: The unary predicate that the next ViewEdge must satisfy.\n"
+" :type upred: :class:`UnaryPredicate1D`\n"
+" :arg bpred: The binary predicate that the next ViewEdge must\n"
+" satisfy together with the actual pointed ViewEdge.\n"
+" :type bpred: :class:`BinaryPredicate1D`\n"
+" :arg iRestrictToSelection: Indicates whether to force the chaining\n"
+" to stay within the set of selected ViewEdges or not.\n"
+" :type iRestrictToSelection: bool\n"
+" :arg iRestrictToUnvisited: Indicates whether a ViewEdge that has\n"
+" already been chained must be ignored ot not.\n"
+" :type iRestrictToUnvisited: bool\n"
+" :arg begin: The ViewEdge from where to start the iteration.\n"
+" :type begin: :class:`ViewEdge` or None\n"
+" :arg orientation: If true, we'll look for the next ViewEdge among\n"
+" the ViewEdges that surround the ending ViewVertex of begin. If\n"
+" false, we'll search over the ViewEdges surrounding the ending\n"
+" ViewVertex of begin.\n"
+" :type orientation: bool\n"
+"\n"
+".. method:: __init__(brother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg brother: A ChainPredicateIterator object.\n"
+" :type brother: :class:`ChainPredicateIterator`\n";
+
+static int ChainPredicateIterator___init__(BPy_ChainPredicateIterator *self, PyObject *args )
+{
+ PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0, *obj4 = 0, *obj5 = 0, *obj6 = 0;
+
+ if (!( PyArg_ParseTuple(args, "|OOOOOO", &obj1, &obj2, &obj3, &obj4, &obj5, &obj6) ))
+ return -1;
+
+ if( obj1 && BPy_ChainPredicateIterator_Check(obj1) ) {
+ self->cp_it = new ChainPredicateIterator(*( ((BPy_ChainPredicateIterator *) obj1)->cp_it ));
+ self->upred = NULL;
+ self->bpred = NULL;
+
+ } else if( obj1 && BPy_UnaryPredicate1D_Check(obj1) &&
+ obj2 && BPy_BinaryPredicate1D_Check(obj2) ) {
+
+ if (!((BPy_UnaryPredicate1D *) obj1)->up1D) {
+ PyErr_SetString(PyExc_TypeError, "1st argument: invalid UnaryPredicate1D object");
+ return -1;
+ }
+ if (!((BPy_BinaryPredicate1D *) obj2)->bp1D) {
+ PyErr_SetString(PyExc_TypeError, "2nd argument: invalid BinaryPredicate1D object");
+ return -1;
+ }
+ UnaryPredicate1D *up1D = ((BPy_UnaryPredicate1D *) obj1)->up1D;
+ BinaryPredicate1D *bp1D = ((BPy_BinaryPredicate1D *) obj2)->bp1D;
+ bool restrictToSelection = ( obj3 ) ? bool_from_PyBool(obj3) : true;
+ bool restrictToUnvisited = ( obj4 ) ? bool_from_PyBool(obj4) : true;
+ ViewEdge *begin;
+ if ( !obj5 || obj5 == Py_None )
+ begin = NULL;
+ else if ( BPy_ViewEdge_Check(obj5) )
+ begin = ((BPy_ViewEdge *) obj5)->ve;
+ else {
+ PyErr_SetString(PyExc_TypeError, "5th argument must be either a ViewEdge object or None");
+ return -1;
+ }
+ bool orientation = ( obj6 ) ? bool_from_PyBool(obj6) : true;
+
+ self->cp_it = new ChainPredicateIterator( *up1D, *bp1D, restrictToSelection, restrictToUnvisited, begin, orientation);
+ self->upred = obj1;
+ self->bpred = obj2;
+ Py_INCREF( self->upred );
+ Py_INCREF( self->bpred );
+
+ } else {
+ bool restrictToSelection = ( obj1 ) ? bool_from_PyBool(obj1) : true;
+ bool restrictToUnvisited = ( obj2 ) ? bool_from_PyBool(obj2) : true;
+ ViewEdge *begin;
+ if ( !obj3 || obj3 == Py_None )
+ begin = NULL;
+ else if ( BPy_ViewEdge_Check(obj3) )
+ begin = ((BPy_ViewEdge *) obj3)->ve;
+ else {
+ PyErr_SetString(PyExc_TypeError, "3rd argument must be either a ViewEdge object or None");
+ return -1;
+ }
+ bool orientation = ( obj4 ) ? bool_from_PyBool(obj4) : true;
+
+ self->cp_it = new ChainPredicateIterator( restrictToSelection, restrictToUnvisited, begin, orientation);
+ self->upred = NULL;
+ self->bpred = NULL;
+ }
+
+ self->py_c_it.c_it = self->cp_it;
+ self->py_c_it.py_ve_it.ve_it = self->cp_it;
+ self->py_c_it.py_ve_it.py_it.it = self->cp_it;
+
+
+ return 0;
+
+}
+
+static void ChainPredicateIterator___dealloc__(BPy_ChainPredicateIterator *self)
+{
+ Py_XDECREF( self->upred );
+ Py_XDECREF( self->bpred );
+ ChainingIterator_Type.tp_dealloc((PyObject *)self);
+}
+
+/*-----------------------BPy_ChainPredicateIterator type definition ------------------------------*/
+
+PyTypeObject ChainPredicateIterator_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ChainPredicateIterator", /* tp_name */
+ sizeof(BPy_ChainPredicateIterator), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)ChainPredicateIterator___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ChainPredicateIterator___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &ChainingIterator_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ChainPredicateIterator___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.h b/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.h
new file mode 100644
index 00000000000..5a31ac407d5
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.h
@@ -0,0 +1,35 @@
+#ifndef FREESTYLE_PYTHON_CHAINPREDICATEITERATOR_H
+#define FREESTYLE_PYTHON_CHAINPREDICATEITERATOR_H
+
+
+#include "../../stroke/ChainingIterators.h"
+
+#include "BPy_ChainingIterator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ChainPredicateIterator_Type;
+
+#define BPy_ChainPredicateIterator_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ChainPredicateIterator_Type) )
+
+/*---------------------------Python BPy_ChainPredicateIterator structure definition----------*/
+typedef struct {
+ BPy_ChainingIterator py_c_it;
+ ChainPredicateIterator *cp_it;
+ PyObject *upred;
+ PyObject *bpred;
+} BPy_ChainPredicateIterator;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CHAINPREDICATEITERATOR_H */
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp
new file mode 100644
index 00000000000..caf43a800c5
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp
@@ -0,0 +1,131 @@
+#include "BPy_ChainSilhouetteIterator.h"
+
+#include "../BPy_Convert.h"
+#include "../Interface1D/BPy_ViewEdge.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+// ChainSilhouetteIterator (bool iRestrictToSelection=true, ViewEdge *begin=NULL, bool orientation=true)
+// ChainSilhouetteIterator (const ChainSilhouetteIterator &brother)
+
+static char ChainSilhouetteIterator___doc__[] =
+"Class hierarchy: :class:`Iterator` > :class:`ViewEdgeIterator` > :class:`ChainingIterator` > :class:`ChainSilhouetteIterator`\n"
+"\n"
+"A ViewEdge Iterator used to follow ViewEdges the most naturally. For\n"
+"example, it will follow visible ViewEdges of same nature. As soon, as\n"
+"the nature or the visibility changes, the iteration stops (by setting\n"
+"the pointed ViewEdge to 0). In the case of an iteration over a set of\n"
+"ViewEdge that are both Silhouette and Crease, there will be a\n"
+"precedence of the silhouette over the crease criterion.\n"
+"\n"
+".. method:: __init__(iRestrictToSelection=True, begin=None, orientation=True)\n"
+"\n"
+" Builds a ChainSilhouetteIterator from the first ViewEdge used for\n"
+" iteration and its orientation.\n"
+"\n"
+" :arg iRestrictToSelection: Indicates whether to force the chaining\n"
+" to stay within the set of selected ViewEdges or not.\n"
+" :type iRestrictToSelection: bool\n"
+" :arg begin: The ViewEdge from where to start the iteration.\n"
+" :type begin: :class:`ViewEdge` or None\n"
+" :arg orientation: If true, we'll look for the next ViewEdge among\n"
+" the ViewEdges that surround the ending ViewVertex of begin. If\n"
+" false, we'll search over the ViewEdges surrounding the ending\n"
+" ViewVertex of begin.\n"
+" :type orientation: bool\n"
+"\n"
+".. method:: __init__(brother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg brother: A ChainSilhouetteIterator object.\n"
+" :type brother: :class:`ChainSilhouetteIterator`\n";
+
+static int ChainSilhouetteIterator___init__(BPy_ChainSilhouetteIterator *self, PyObject *args )
+{
+ PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0;
+
+ if (!( PyArg_ParseTuple(args, "|OOO", &obj1, &obj2, &obj3) ))
+ return -1;
+
+ if( obj1 && BPy_ChainSilhouetteIterator_Check(obj1) ) {
+ self->cs_it = new ChainSilhouetteIterator(*( ((BPy_ChainSilhouetteIterator *) obj1)->cs_it ));
+
+ } else {
+ bool restrictToSelection = ( obj1 ) ? bool_from_PyBool(obj1) : true;
+ ViewEdge *begin;
+ if ( !obj2 || obj2 == Py_None )
+ begin = NULL;
+ else if ( BPy_ViewEdge_Check(obj2) )
+ begin = ((BPy_ViewEdge *) obj2)->ve;
+ else {
+ PyErr_SetString(PyExc_TypeError, "2nd argument must be either a ViewEdge object or None");
+ return -1;
+ }
+ bool orientation = ( obj3 ) ? bool_from_PyBool(obj3) : true;
+
+ self->cs_it = new ChainSilhouetteIterator( restrictToSelection, begin, orientation);
+ }
+
+ self->py_c_it.c_it = self->cs_it;
+ self->py_c_it.py_ve_it.ve_it = self->cs_it;
+ self->py_c_it.py_ve_it.py_it.it = self->cs_it;
+
+ return 0;
+
+}
+
+/*-----------------------BPy_ChainSilhouetteIterator type definition ------------------------------*/
+
+PyTypeObject ChainSilhouetteIterator_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ChainSilhouetteIterator", /* tp_name */
+ sizeof(BPy_ChainSilhouetteIterator), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ChainSilhouetteIterator___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &ChainingIterator_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ChainSilhouetteIterator___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.h b/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.h
new file mode 100644
index 00000000000..912d397d279
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.h
@@ -0,0 +1,33 @@
+#ifndef FREESTYLE_PYTHON_CHAINSILHOUETTEITERATOR_H
+#define FREESTYLE_PYTHON_CHAINSILHOUETTEITERATOR_H
+
+
+#include "../../stroke/ChainingIterators.h"
+
+#include "BPy_ChainingIterator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ChainSilhouetteIterator_Type;
+
+#define BPy_ChainSilhouetteIterator_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ChainSilhouetteIterator_Type) )
+
+/*---------------------------Python BPy_ChainSilhouetteIterator structure definition----------*/
+typedef struct {
+ BPy_ChainingIterator py_c_it;
+ ChainSilhouetteIterator *cs_it;
+} BPy_ChainSilhouetteIterator;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CHAINSILHOUETTEITERATOR_H */
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp
new file mode 100644
index 00000000000..ddb957c900e
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.cpp
@@ -0,0 +1,236 @@
+#include "BPy_ChainingIterator.h"
+
+#include "../BPy_Convert.h"
+#include "../Interface0D/BPy_ViewVertex.h"
+#include "../Interface1D/BPy_ViewEdge.h"
+#include "BPy_AdjacencyIterator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ChainingIterator___doc__[] =
+"Class hierarchy: :class:`Iterator` > :class:`ViewEdgeIterator` > :class:`ChainingIterator`\n"
+"\n"
+"Base class for chaining iterators. This class is designed to be\n"
+"overloaded in order to describe chaining rules. It makes the\n"
+"description of chaining rules easier. The two main methods that need\n"
+"to overloaded are traverse() and init(). traverse() tells which\n"
+":class:`ViewEdge` to follow, among the adjacent ones. If you specify\n"
+"restriction rules (such as \"Chain only ViewEdges of the selection\"),\n"
+"they will be included in the adjacency iterator (i.e, the adjacent\n"
+"iterator will only stop on \"valid\" edges).\n"
+"\n"
+".. method:: __init__(iRestrictToSelection=True, iRestrictToUnvisited=True, begin=None, orientation=True)\n"
+"\n"
+" Builds a Chaining Iterator from the first ViewEdge used for\n"
+" iteration and its orientation.\n"
+"\n"
+" :arg iRestrictToSelection: Indicates whether to force the chaining\n"
+" to stay within the set of selected ViewEdges or not.\n"
+" :type iRestrictToSelection: bool\n"
+" :arg iRestrictToUnvisited: Indicates whether a ViewEdge that has\n"
+" already been chained must be ignored ot not.\n"
+" :type iRestrictToUnvisited: bool\n"
+" :arg begin: The ViewEdge from which to start the chain.\n"
+" :type begin: :class:`ViewEdge` or None\n"
+" :arg orientation: The direction to follow to explore the graph. If\n"
+" true, the direction indicated by the first ViewEdge is used.\n"
+" :type orientation: bool\n"
+"\n"
+".. method:: __init__(brother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg brother: \n"
+" :type brother: ChainingIterator\n";
+
+static int ChainingIterator___init__(BPy_ChainingIterator *self, PyObject *args )
+{
+ PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0, *obj4 = 0;
+
+ if (!( PyArg_ParseTuple(args, "|OOOO", &obj1, &obj2, &obj3, &obj4) ))
+ return -1;
+
+ if( obj1 && BPy_ChainingIterator_Check(obj1) ) {
+ self->c_it = new ChainingIterator(*( ((BPy_ChainingIterator *) obj1)->c_it ));
+
+ } else {
+ bool restrictToSelection = ( obj1 ) ? bool_from_PyBool(obj1) : true;
+ bool restrictToUnvisited = ( obj2 ) ? bool_from_PyBool(obj2) : true;
+ ViewEdge *begin;
+ if ( !obj3 || obj3 == Py_None )
+ begin = NULL;
+ else if ( BPy_ViewEdge_Check(obj3) )
+ begin = ((BPy_ViewEdge *) obj3)->ve;
+ else {
+ PyErr_SetString(PyExc_TypeError, "3rd argument must be either a ViewEdge object or None");
+ return -1;
+ }
+ bool orientation = ( obj4 ) ? bool_from_PyBool(obj4) : true;
+
+ self->c_it = new ChainingIterator( restrictToSelection, restrictToUnvisited, begin, orientation);
+ }
+
+ self->py_ve_it.ve_it = self->c_it;
+ self->py_ve_it.py_it.it = self->c_it;
+
+ self->c_it->py_c_it = (PyObject *) self;
+
+ return 0;
+}
+
+static char ChainingIterator_init___doc__[] =
+".. method:: init()\n"
+"\n"
+" Initializes the iterator context. This method is called each\n"
+" time a new chain is started. It can be used to reset some\n"
+" history information that you might want to keep.\n";
+
+static PyObject *ChainingIterator_init( BPy_ChainingIterator *self ) {
+ if( typeid(*(self->c_it)) == typeid(ChainingIterator) ) {
+ PyErr_SetString(PyExc_TypeError, "init() method not properly overridden");
+ return NULL;
+ }
+ self->c_it->init();
+
+ Py_RETURN_NONE;
+}
+
+static char ChainingIterator_traverse___doc__[] =
+".. method:: traverse(it)\n"
+"\n"
+" This method iterates over the potential next ViewEdges and returns\n"
+" the one that will be followed next. Returns the next ViewEdge to\n"
+" follow or None when the end of the chain is reached.\n"
+"\n"
+" :arg it: The iterator over the ViewEdges adjacent to the end vertex\n"
+" of the current ViewEdge. The adjacency iterator reflects the\n"
+" restriction rules by only iterating over the valid ViewEdges.\n"
+" :type it: :class:`AdjacencyIterator`\n"
+" :return: Returns the next ViewEdge to follow, or None if chaining ends.\n"
+" :rtype: :class:`ViewEdge` or None\n";
+
+static PyObject *ChainingIterator_traverse( BPy_ChainingIterator *self, PyObject *args ) {
+ PyObject *py_a_it;
+
+ if(!( PyArg_ParseTuple(args, "O!", &AdjacencyIterator_Type, &py_a_it) ))
+ return NULL;
+
+ if( typeid(*(self->c_it)) == typeid(ChainingIterator) ) {
+ PyErr_SetString(PyExc_TypeError, "traverse() method not properly overridden");
+ return NULL;
+ }
+ if( ((BPy_AdjacencyIterator *) py_a_it)->a_it )
+ self->c_it->traverse(*( ((BPy_AdjacencyIterator *) py_a_it)->a_it ));
+
+ Py_RETURN_NONE;
+}
+
+static char ChainingIterator_getVertex___doc__[] =
+".. method:: getVertex()\n"
+"\n"
+" Returns the vertex which is the next crossing.\n"
+"\n"
+" :return: The vertex which is the next crossing.\n"
+" :rtype: :class:`ViewVertex`\n";
+
+static PyObject *ChainingIterator_getVertex( BPy_ChainingIterator *self ) {
+ ViewVertex *v = self->c_it->getVertex();
+ if( v )
+ return Any_BPy_ViewVertex_from_ViewVertex( *v );
+
+ Py_RETURN_NONE;
+}
+
+static char ChainingIterator_isIncrementing___doc__[] =
+".. method:: isIncrementing()\n"
+"\n"
+" Returns true if the current iteration is an incrementation.\n"
+"\n"
+" :return: True if the current iteration is an incrementation.\n"
+" :rtype: bool\n";
+
+static PyObject *ChainingIterator_isIncrementing( BPy_ChainingIterator *self ) {
+ return PyBool_from_bool( self->c_it->isIncrementing() );
+}
+
+static char ChainingIterator_getObject___doc__[] =
+".. method:: getObject()\n"
+"\n"
+" Returns the pointed ViewEdge.\n"
+"\n"
+" :return: The pointed ViewEdge.\n"
+" :rtype: :class:`ViewEdge`\n";
+
+static PyObject * ChainingIterator_getObject( BPy_ChainingIterator *self) {
+
+ ViewEdge *ve = self->c_it->operator*();
+ if( ve )
+ return BPy_ViewEdge_from_ViewEdge( *ve );
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------ChainingIterator instance definitions ----------------------------*/
+static PyMethodDef BPy_ChainingIterator_methods[] = {
+ {"init", ( PyCFunction ) ChainingIterator_init, METH_NOARGS, ChainingIterator_init___doc__},
+ {"traverse", ( PyCFunction ) ChainingIterator_traverse, METH_VARARGS, ChainingIterator_traverse___doc__},
+ {"getVertex", ( PyCFunction ) ChainingIterator_getVertex, METH_NOARGS, ChainingIterator_getVertex___doc__},
+ {"isIncrementing", ( PyCFunction ) ChainingIterator_isIncrementing, METH_NOARGS, ChainingIterator_isIncrementing___doc__},
+ {"getObject", ( PyCFunction ) ChainingIterator_getObject, METH_NOARGS, ChainingIterator_getObject___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_ChainingIterator type definition ------------------------------*/
+
+PyTypeObject ChainingIterator_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ChainingIterator", /* tp_name */
+ sizeof(BPy_ChainingIterator), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ChainingIterator___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_ChainingIterator_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &ViewEdgeIterator_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ChainingIterator___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.h b/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.h
new file mode 100644
index 00000000000..2a00aa8072f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainingIterator.h
@@ -0,0 +1,33 @@
+#ifndef FREESTYLE_PYTHON_CHAININGITERATOR_H
+#define FREESTYLE_PYTHON_CHAININGITERATOR_H
+
+
+#include "../../stroke/ChainingIterators.h"
+
+#include "BPy_ViewEdgeIterator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ChainingIterator_Type;
+
+#define BPy_ChainingIterator_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ChainingIterator_Type) )
+
+/*---------------------------Python BPy_ChainingIterator structure definition----------*/
+typedef struct {
+ BPy_ViewEdgeIterator py_ve_it;
+ ChainingIterator *c_it;
+} BPy_ChainingIterator;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CHAININGITERATOR_H */
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp
new file mode 100644
index 00000000000..f66d95b3a39
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.cpp
@@ -0,0 +1,171 @@
+#include "BPy_CurvePointIterator.h"
+
+#include "../BPy_Convert.h"
+#include "BPy_Interface0DIterator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char CurvePointIterator___doc__[] =
+"Class hierarchy: :class:`Iterator` > :class:`CurvePointIterator`\n"
+"\n"
+"Class representing an iterator on a curve. Allows an iterating\n"
+"outside initial vertices. A CurvePoint is instanciated and returned\n"
+"by getObject().\n"
+"\n"
+".. method:: __init__(step=0.0)\n"
+"\n"
+" Builds a CurvePointIterator object.\n"
+"\n"
+" :arg step: A resampling resolution with which the curve is resampled.\n"
+" If zero, no resampling is done (i.e., the iterator iterates over\n"
+" initial vertices).\n"
+" :type step: float\n"
+"\n"
+".. method:: __init__(brother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg brother: A CurvePointIterator object.\n"
+" :type brother: :class:`CurvePointIterator`\n";
+
+static int CurvePointIterator___init__(BPy_CurvePointIterator *self, PyObject *args )
+{
+ PyObject *obj = 0;
+
+ if (! PyArg_ParseTuple(args, "|O", &obj) )
+ return -1;
+
+ if( !obj ){
+ self->cp_it = new CurveInternal::CurvePointIterator();
+
+ } else if( BPy_CurvePointIterator_Check(obj) ) {
+ self->cp_it = new CurveInternal::CurvePointIterator(*( ((BPy_CurvePointIterator *) obj)->cp_it ));
+
+ } else if( PyFloat_Check(obj) ) {
+ self->cp_it = new CurveInternal::CurvePointIterator( PyFloat_AsDouble(obj) );
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument");
+ return -1;
+ }
+
+ self->py_it.it = self->cp_it;
+
+ return 0;
+}
+
+static char CurvePointIterator_t___doc__[] =
+".. method:: t()\n"
+"\n"
+" Returns the curvilinear abscissa.\n"
+"\n"
+" :return: The curvilinear abscissa.\n"
+" :rtype: float\n";
+
+static PyObject * CurvePointIterator_t( BPy_CurvePointIterator *self ) {
+ return PyFloat_FromDouble( self->cp_it->t() );
+}
+
+static char CurvePointIterator_u___doc__[] =
+".. method:: u()\n"
+"\n"
+" Returns the point parameter in the curve (0<=u<=1).\n"
+"\n"
+" :return: The point parameter.\n"
+" :rtype: float\n";
+
+static PyObject * CurvePointIterator_u( BPy_CurvePointIterator *self ) {
+ return PyFloat_FromDouble( self->cp_it->u() );
+}
+
+static char CurvePointIterator_castToInterface0DIterator___doc__[] =
+".. method:: castToInterface0DIterator()\n"
+"\n"
+" Returns an Interface0DIterator converted from this\n"
+" CurvePointIterator. Useful for any call to a function of the\n"
+" UnaryFunction0D type.\n"
+"\n"
+" :return: An Interface0DIterator object converted from the\n"
+" iterator.\n"
+" :rtype: :class:`Interface0DIterator`\n";
+
+static PyObject * CurvePointIterator_castToInterface0DIterator( BPy_CurvePointIterator *self ) {
+ Interface0DIterator it( self->cp_it->castToInterface0DIterator() );
+ return BPy_Interface0DIterator_from_Interface0DIterator( it, 0 );
+}
+
+static char CurvePointIterator_getObject___doc__[] =
+".. method:: getObject()\n"
+"\n"
+" Returns a CurvePoint pointed by the iterator.\n"
+"\n"
+" :return: \n"
+" :rtype: :class:`CurvePoint`\n";
+
+static PyObject * CurvePointIterator_getObject(BPy_CurvePointIterator *self) {
+ return BPy_CurvePoint_from_CurvePoint( self->cp_it->operator*() );
+}
+
+/*----------------------CurvePointIterator instance definitions ----------------------------*/
+static PyMethodDef BPy_CurvePointIterator_methods[] = {
+ {"t", ( PyCFunction ) CurvePointIterator_t, METH_NOARGS, CurvePointIterator_t___doc__},
+ {"u", ( PyCFunction ) CurvePointIterator_u, METH_NOARGS, CurvePointIterator_u___doc__},
+ {"castToInterface0DIterator", ( PyCFunction ) CurvePointIterator_castToInterface0DIterator, METH_NOARGS, CurvePointIterator_castToInterface0DIterator___doc__},
+ {"getObject", ( PyCFunction ) CurvePointIterator_getObject, METH_NOARGS, CurvePointIterator_getObject___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_CurvePointIterator type definition ------------------------------*/
+
+PyTypeObject CurvePointIterator_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "CurvePointIterator", /* tp_name */
+ sizeof(BPy_CurvePointIterator), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ CurvePointIterator___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_CurvePointIterator_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Iterator_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)CurvePointIterator___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.h b/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.h
new file mode 100644
index 00000000000..ad04c7208bb
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_CurvePointIterator.h
@@ -0,0 +1,32 @@
+#ifndef FREESTYLE_PYTHON_CURVEPOINTITERATOR_H
+#define FREESTYLE_PYTHON_CURVEPOINTITERATOR_H
+
+#include "../../stroke/CurveIterators.h"
+
+#include "../BPy_Iterator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject CurvePointIterator_Type;
+
+#define BPy_CurvePointIterator_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &CurvePointIterator_Type) )
+
+/*---------------------------Python BPy_CurvePointIterator structure definition----------*/
+typedef struct {
+ BPy_Iterator py_it;
+ CurveInternal::CurvePointIterator *cp_it;
+} BPy_CurvePointIterator;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CURVEPOINTITERATOR_H */
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp
new file mode 100644
index 00000000000..6643913c32a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp
@@ -0,0 +1,151 @@
+#include "BPy_Interface0DIterator.h"
+
+#include "../BPy_Convert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Interface0DIterator___doc__[] =
+"Class hierarchy: :class:`Iterator` > :class:`Interface0DIterator`\n"
+"\n"
+"Class defining an iterator over Interface0D elements. An instance of\n"
+"this iterator is always obtained from a 1D element.\n"
+"\n"
+".. method:: __init__(it)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n";
+
+static int Interface0DIterator___init__(BPy_Interface0DIterator *self, PyObject *args )
+{
+ PyObject *obj = 0;
+
+ if (!( PyArg_ParseTuple(args, "O!", &Interface0DIterator_Type, &obj) ))
+ return -1;
+
+ self->if0D_it = new Interface0DIterator(*( ((BPy_Interface0DIterator *) obj)->if0D_it ));
+ self->py_it.it = self->if0D_it;
+ self->reversed = 0;
+
+ return 0;
+}
+
+static PyObject * Interface0DIterator_iternext( BPy_Interface0DIterator *self ) {
+ Interface0D *if0D;
+ if (self->reversed) {
+ if (self->if0D_it->isBegin()) {
+ PyErr_SetNone(PyExc_StopIteration);
+ return NULL;
+ }
+ self->if0D_it->decrement();
+ if0D = self->if0D_it->operator->();
+ } else {
+ if (self->if0D_it->isEnd()) {
+ PyErr_SetNone(PyExc_StopIteration);
+ return NULL;
+ }
+ if0D = self->if0D_it->operator->();
+ self->if0D_it->increment();
+ }
+ return Any_BPy_Interface0D_from_Interface0D( *if0D );
+}
+
+static char Interface0DIterator_t___doc__[] =
+".. method:: t()\n"
+"\n"
+" Returns the curvilinear abscissa.\n"
+"\n"
+" :return: The curvilinear abscissa.\n"
+" :rtype: float\n";
+
+static PyObject * Interface0DIterator_t( BPy_Interface0DIterator *self ) {
+ return PyFloat_FromDouble( self->if0D_it->t() );
+}
+
+static char Interface0DIterator_u___doc__[] =
+".. method:: u()\n"
+"\n"
+" Returns the point parameter in the curve 0<=u<=1.\n"
+"\n"
+" :return: The point parameter.\n"
+" :rtype: float\n";
+
+static PyObject * Interface0DIterator_u( BPy_Interface0DIterator *self ) {
+ return PyFloat_FromDouble( self->if0D_it->u() );
+}
+
+static char Interface0DIterator_getObject___doc__[] =
+".. method:: getObject()\n"
+"\n"
+" Returns the pointed Interface0D.\n"
+"\n"
+" :return: The pointed Interface0D.\n"
+" :rtype: :class:`Interface0D`\n";
+
+static PyObject * Interface0DIterator_getObject(BPy_Interface0DIterator *self) {
+ return Any_BPy_Interface0D_from_Interface0D( self->if0D_it->operator*() );
+}
+
+/*----------------------Interface0DIterator instance definitions ----------------------------*/
+static PyMethodDef BPy_Interface0DIterator_methods[] = {
+ {"t", ( PyCFunction ) Interface0DIterator_t, METH_NOARGS, Interface0DIterator_t___doc__},
+ {"u", ( PyCFunction ) Interface0DIterator_u, METH_NOARGS, Interface0DIterator_u___doc__},
+ {"getObject", ( PyCFunction ) Interface0DIterator_getObject, METH_NOARGS, Interface0DIterator_getObject___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_Interface0DIterator type definition ------------------------------*/
+
+PyTypeObject Interface0DIterator_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Interface0DIterator", /* tp_name */
+ sizeof(BPy_Interface0DIterator), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Interface0DIterator___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ PyObject_SelfIter, /* tp_iter */
+ (iternextfunc)Interface0DIterator_iternext, /* tp_iternext */
+ BPy_Interface0DIterator_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Iterator_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Interface0DIterator___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.h b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.h
new file mode 100644
index 00000000000..1972763b2eb
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.h
@@ -0,0 +1,33 @@
+#ifndef FREESTYLE_PYTHON_INTERFACE0DITERATOR_H
+#define FREESTYLE_PYTHON_INTERFACE0DITERATOR_H
+
+#include "../../view_map/Interface0D.h"
+#include "../BPy_Iterator.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject Interface0DIterator_Type;
+
+#define BPy_Interface0DIterator_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Interface0DIterator_Type) )
+
+/*---------------------------Python BPy_Interface0DIterator structure definition----------*/
+typedef struct {
+ BPy_Iterator py_it;
+ Interface0DIterator *if0D_it;
+ int reversed;
+} BPy_Interface0DIterator;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_INTERFACE0DITERATOR_H */
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp
new file mode 100644
index 00000000000..ef40d994e27
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.cpp
@@ -0,0 +1,181 @@
+#include "BPy_SVertexIterator.h"
+
+#include "../BPy_Convert.h"
+#include "../Interface0D/BPy_SVertex.h"
+#include "../Interface1D/BPy_FEdge.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char SVertexIterator___doc__[] =
+"Class hierarchy: :class:`Iterator` > :class:`SVertexIterator`\n"
+"\n"
+"Class representing an iterator over :class:`SVertex` of a\n"
+":class:`ViewEdge`. An instance of an SVertexIterator can be obtained\n"
+"from a ViewEdge by calling verticesBegin() or verticesEnd().\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(it)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg it: An SVertexIterator object.\n"
+" :type it: :class:`SVertexIterator`\n"
+"\n"
+".. method:: __init__(v, begin, prev, next, t)\n"
+"\n"
+" Builds an SVertexIterator that starts iteration from an SVertex\n"
+" object v.\n"
+"\n"
+" :arg v: The SVertex from which the iterator starts iteration.\n"
+" :type v: :class:`SVertex`\n"
+" :arg begin: The first vertex of a view edge.\n"
+" :type begin: :class:`SVertex`\n"
+" :arg prev: The previous FEdge coming to v.\n"
+" :type prev: :class:`FEdge`\n"
+" :arg next: The next FEdge going out from v.\n"
+" :type next: :class:`FEdge`\n"
+" :arg t: The curvilinear abscissa at v.\n"
+" :type t: float\n";
+
+static int SVertexIterator___init__(BPy_SVertexIterator *self, PyObject *args )
+{
+ PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0, *obj4 = 0;
+ float f = 0;
+
+ if (! PyArg_ParseTuple(args, "|OOOOf", &obj1, &obj2, &obj3, &obj4, f) )
+ return -1;
+
+ if( !obj1 ){
+ self->sv_it = new ViewEdgeInternal::SVertexIterator();
+
+ } else if( BPy_SVertexIterator_Check(obj1) ) {
+ self->sv_it = new ViewEdgeInternal::SVertexIterator(*( ((BPy_SVertexIterator *) obj1)->sv_it ));
+
+ } else if( obj1 && BPy_SVertex_Check(obj1) &&
+ obj2 && BPy_SVertex_Check(obj2) &&
+ obj3 && BPy_FEdge_Check(obj3) &&
+ obj4 && BPy_FEdge_Check(obj4) ) {
+
+ self->sv_it = new ViewEdgeInternal::SVertexIterator(
+ ((BPy_SVertex *) obj1)->sv,
+ ((BPy_SVertex *) obj2)->sv,
+ ((BPy_FEdge *) obj3)->fe,
+ ((BPy_FEdge *) obj4)->fe,
+ f );
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
+ return -1;
+ }
+
+ self->py_it.it = self->sv_it;
+
+ return 0;
+}
+
+static char SVertexIterator_t___doc__[] =
+".. method:: t()\n"
+"\n"
+" Returns the curvilinear abscissa.\n"
+"\n"
+" :return: The curvilinear abscissa.\n"
+" :rtype: float\n";
+
+static PyObject * SVertexIterator_t( BPy_SVertexIterator *self ) {
+ return PyFloat_FromDouble( self->sv_it->t() );
+}
+
+static char SVertexIterator_u___doc__[] =
+".. method:: u()\n"
+"\n"
+" Returns the point parameter (0<=u<=1).\n"
+"\n"
+" :return: The point parameter.\n"
+" :rtype: float\n";
+
+static PyObject * SVertexIterator_u( BPy_SVertexIterator *self ) {
+ return PyFloat_FromDouble( self->sv_it->u() );
+}
+
+static char SVertexIterator_getObject___doc__[] =
+".. method:: getObject()\n"
+"\n"
+" Returns the pointed SVertex.\n"
+"\n"
+" :return: the pointed SVertex.\n"
+" :rtype: :class:`SVertex`\n";
+
+static PyObject * SVertexIterator_getObject( BPy_SVertexIterator *self) {
+ SVertex *sv = self->sv_it->operator->();
+
+ if( sv )
+ return BPy_SVertex_from_SVertex( *sv );
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------SVertexIterator instance definitions ----------------------------*/
+static PyMethodDef BPy_SVertexIterator_methods[] = {
+ {"t", ( PyCFunction ) SVertexIterator_t, METH_NOARGS, SVertexIterator_t___doc__},
+ {"u", ( PyCFunction ) SVertexIterator_u, METH_NOARGS, SVertexIterator_u___doc__},
+ {"getObject", ( PyCFunction ) SVertexIterator_getObject, METH_NOARGS, SVertexIterator_getObject___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_SVertexIterator type definition ------------------------------*/
+
+PyTypeObject SVertexIterator_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "SVertexIterator", /* tp_name */
+ sizeof(BPy_SVertexIterator), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ SVertexIterator___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_SVertexIterator_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Iterator_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)SVertexIterator___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.h b/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.h
new file mode 100644
index 00000000000..b40f4d36420
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_SVertexIterator.h
@@ -0,0 +1,33 @@
+#ifndef FREESTYLE_PYTHON_SVERTEXITERATOR_H
+#define FREESTYLE_PYTHON_SVERTEXITERATOR_H
+
+#include "../../view_map/ViewMapIterators.h"
+
+#include "../BPy_Iterator.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject SVertexIterator_Type;
+
+#define BPy_SVertexIterator_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &SVertexIterator_Type) )
+
+/*---------------------------Python BPy_SVertexIterator structure definition----------*/
+typedef struct {
+ BPy_Iterator py_it;
+ ViewEdgeInternal::SVertexIterator *sv_it;
+} BPy_SVertexIterator;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_SVERTEXITERATOR_H */
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
new file mode 100644
index 00000000000..a9b2c4d774a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
@@ -0,0 +1,197 @@
+#include "BPy_StrokeVertexIterator.h"
+
+#include "../BPy_Convert.h"
+#include "BPy_Interface0DIterator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char StrokeVertexIterator___doc__[] =
+"Class hierarchy: :class:`Iterator` > :class:`StrokeVertexIterator`\n"
+"\n"
+"Class defining an iterator designed to iterate over the\n"
+":class:`StrokeVertex` of a :class:`Stroke`. An instance of a\n"
+"StrokeVertexIterator can only be obtained from a Stroke by calling\n"
+"strokeVerticesBegin() or strokeVerticesEnd(). It is iterating over\n"
+"the same vertices as an :class:`Interface0DIterator`. The difference\n"
+"resides in the object access. Indeed, an Interface0DIterator allows\n"
+"only an access to an Interface0D whereas we could need to access the\n"
+"specialized StrokeVertex type. In this case, one should use a\n"
+"StrokeVertexIterator. The castToInterface0DIterator() method is\n"
+"useful to get an Interface0DIterator from a StrokeVertexIterator in\n"
+"order to call any functions of the UnaryFunction0D type.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(it)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg it: A StrokeVertexIterator object.\n"
+" :type it: :class:`StrokeVertexIterator`\n";
+
+static int StrokeVertexIterator___init__(BPy_StrokeVertexIterator *self, PyObject *args )
+{
+ PyObject *obj = 0;
+
+ if (! PyArg_ParseTuple(args, "|O", &obj) )
+ return -1;
+
+ if( !obj ){
+ self->sv_it = new StrokeInternal::StrokeVertexIterator();
+
+ } else if( BPy_StrokeVertexIterator_Check(obj) ) {
+ self->sv_it = new StrokeInternal::StrokeVertexIterator(*( ((BPy_StrokeVertexIterator *) obj)->sv_it ));
+
+ } else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument");
+ return -1;
+ }
+
+ self->py_it.it = self->sv_it;
+ self->reversed = 0;
+
+ return 0;
+}
+
+static PyObject * StrokeVertexIterator_iternext( BPy_StrokeVertexIterator *self ) {
+ StrokeVertex *sv;
+ if (self->reversed) {
+ if (self->sv_it->isBegin()) {
+ PyErr_SetNone(PyExc_StopIteration);
+ return NULL;
+ }
+ self->sv_it->decrement();
+ sv = self->sv_it->operator->();
+ } else {
+ if (self->sv_it->isEnd()) {
+ PyErr_SetNone(PyExc_StopIteration);
+ return NULL;
+ }
+ sv = self->sv_it->operator->();
+ self->sv_it->increment();
+ }
+ return BPy_StrokeVertex_from_StrokeVertex( *sv );
+}
+
+static char StrokeVertexIterator_t___doc__[] =
+".. method:: t()\n"
+"\n"
+" Returns the curvilinear abscissa of the current point.\n"
+"\n"
+" :return: The curvilinear abscissa of the current point.\n"
+" :rtype: float\n";
+
+static PyObject * StrokeVertexIterator_t( BPy_StrokeVertexIterator *self ) {
+ return PyFloat_FromDouble( self->sv_it->t() );
+}
+
+static char StrokeVertexIterator_u___doc__[] =
+".. method:: u()\n"
+"\n"
+" Returns the point parameter in the stroke (0<=u<=1).\n"
+"\n"
+" :return: The point parameter in the stroke\n"
+" :rtype: float\n";
+
+static PyObject * StrokeVertexIterator_u( BPy_StrokeVertexIterator *self ) {
+ return PyFloat_FromDouble( self->sv_it->u() );
+}
+
+static char StrokeVertexIterator_castToInterface0DIterator___doc__[] =
+".. method:: castToInterface0DIterator()\n"
+"\n"
+" Returns an Interface0DIterator converted from this\n"
+" StrokeVertexIterator. Useful for any call to a function of the\n"
+" UnaryFunction0D type.\n"
+"\n"
+" :return: An Interface0DIterator converted from the StrokeVertexIterator.\n"
+" :rtype: :class:`Interface0DIterator`\n";
+
+static PyObject * StrokeVertexIterator_castToInterface0DIterator( BPy_StrokeVertexIterator *self ) {
+ Interface0DIterator it( self->sv_it->castToInterface0DIterator() );
+ return BPy_Interface0DIterator_from_Interface0DIterator( it, 0 );
+}
+
+static char StrokeVertexIterator_getObject___doc__[] =
+".. method:: getObject()\n"
+"\n"
+" Returns the pointed StrokeVertex.\n"
+"\n"
+" :return: The pointed StrokeVertex.\n"
+" :rtype: :class:`StrokeVertex`\n";
+
+static PyObject * StrokeVertexIterator_getObject( BPy_StrokeVertexIterator *self) {
+ if (!self->reversed && self->sv_it->isEnd())
+ Py_RETURN_NONE;
+ StrokeVertex *sv = self->sv_it->operator->();
+ if( sv )
+ return BPy_StrokeVertex_from_StrokeVertex( *sv );
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------StrokeVertexIterator instance definitions ----------------------------*/
+static PyMethodDef BPy_StrokeVertexIterator_methods[] = {
+ {"t", ( PyCFunction ) StrokeVertexIterator_t, METH_NOARGS, StrokeVertexIterator_t___doc__},
+ {"u", ( PyCFunction ) StrokeVertexIterator_u, METH_NOARGS, StrokeVertexIterator_u___doc__},
+ {"castToInterface0DIterator", ( PyCFunction ) StrokeVertexIterator_castToInterface0DIterator, METH_NOARGS, StrokeVertexIterator_castToInterface0DIterator___doc__},
+ {"getObject", ( PyCFunction ) StrokeVertexIterator_getObject, METH_NOARGS, StrokeVertexIterator_getObject___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_StrokeVertexIterator type definition ------------------------------*/
+
+PyTypeObject StrokeVertexIterator_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "StrokeVertexIterator", /* tp_name */
+ sizeof(BPy_StrokeVertexIterator), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ StrokeVertexIterator___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ PyObject_SelfIter, /* tp_iter */
+ (iternextfunc)StrokeVertexIterator_iternext, /* tp_iternext */
+ BPy_StrokeVertexIterator_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Iterator_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)StrokeVertexIterator___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.h b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.h
new file mode 100644
index 00000000000..0c4b6e4bb6c
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.h
@@ -0,0 +1,33 @@
+#ifndef FREESTYLE_PYTHON_STROKEVERTEXITERATOR_H
+#define FREESTYLE_PYTHON_STROKEVERTEXITERATOR_H
+
+#include "../../stroke/StrokeIterators.h"
+
+#include "../BPy_Iterator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject StrokeVertexIterator_Type;
+
+#define BPy_StrokeVertexIterator_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &StrokeVertexIterator_Type) )
+
+/*---------------------------Python BPy_StrokeVertexIterator structure definition----------*/
+typedef struct {
+ BPy_Iterator py_it;
+ StrokeInternal::StrokeVertexIterator *sv_it;
+ int reversed;
+} BPy_StrokeVertexIterator;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_STROKEVERTEXITERATOR_H */
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp
new file mode 100644
index 00000000000..660e00b7089
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.cpp
@@ -0,0 +1,266 @@
+#include "BPy_ViewEdgeIterator.h"
+
+#include "../BPy_Convert.h"
+#include "../Interface1D/BPy_ViewEdge.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ViewEdgeIterator___doc__[] =
+"Class hierarchy: :class:`Iterator` > :class:`ViewEdgeIterator`\n"
+"\n"
+"Base class for iterators over ViewEdges of the :class:`ViewMap` Graph.\n"
+"Basically the increment() operator of this class should be able to\n"
+"take the decision of \"where\" (on which ViewEdge) to go when pointing\n"
+"on a given ViewEdge.\n"
+"\n"
+".. method:: __init__(begin=None, orientation=True)\n"
+"\n"
+" Builds a ViewEdgeIterator from a starting ViewEdge and its\n"
+" orientation.\n"
+"\n"
+" :arg begin: The ViewEdge from where to start the iteration.\n"
+" :type begin: :class:`ViewEdge` or None\n"
+" :arg orientation: If true, we'll look for the next ViewEdge among\n"
+" the ViewEdges that surround the ending ViewVertex of begin. If\n"
+" false, we'll search over the ViewEdges surrounding the ending\n"
+" ViewVertex of begin.\n"
+" :type orientation: bool\n"
+"\n"
+".. method:: __init__(it)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg it: A ViewEdgeIterator object.\n"
+" :type it: :class:`ViewEdgeIterator`\n";
+
+static int ViewEdgeIterator___init__(BPy_ViewEdgeIterator *self, PyObject *args )
+{
+ PyObject *obj1 = 0, *obj2 = 0;
+
+ if (!( PyArg_ParseTuple(args, "O|O", &obj1, &obj2) ))
+ return -1;
+
+ if( obj1 && BPy_ViewEdgeIterator_Check(obj1) ) {
+ self->ve_it = new ViewEdgeInternal::ViewEdgeIterator(*( ((BPy_ViewEdgeIterator *) obj1)->ve_it ));
+
+ } else {
+ ViewEdge *begin;
+ if ( !obj1 || obj1 == Py_None )
+ begin = NULL;
+ else if ( BPy_ViewEdge_Check(obj1) )
+ begin = ((BPy_ViewEdge *) obj1)->ve;
+ else {
+ PyErr_SetString(PyExc_TypeError, "1st argument must be either a ViewEdge object or None");
+ return -1;
+ }
+ bool orientation = ( obj2 ) ? bool_from_PyBool(obj2) : true;
+
+ self->ve_it = new ViewEdgeInternal::ViewEdgeIterator( begin, orientation);
+
+ }
+
+ self->py_it.it = self->ve_it;
+
+ return 0;
+}
+
+static char ViewEdgeIterator_getCurrentEdge___doc__[] =
+".. method:: getCurrentEdge()\n"
+"\n"
+" Returns the current pointed ViewEdge.\n"
+"\n"
+" :return: The current pointed ViewEdge.\n"
+" :rtype: :class:`ViewEdge`\n";
+
+static PyObject *ViewEdgeIterator_getCurrentEdge( BPy_ViewEdgeIterator *self ) {
+ ViewEdge *ve = self->ve_it->getCurrentEdge();
+ if( ve )
+ return BPy_ViewEdge_from_ViewEdge( *ve );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdgeIterator_setCurrentEdge___doc__[] =
+".. method:: setCurrentEdge(edge)\n"
+"\n"
+" Sets the current pointed ViewEdge.\n"
+"\n"
+" :arg edge: The current pointed ViewEdge.\n"
+" :type edge: :class:`ViewEdge`\n";
+
+static PyObject *ViewEdgeIterator_setCurrentEdge( BPy_ViewEdgeIterator *self, PyObject *args ) {
+ PyObject *py_ve;
+
+ if(!( PyArg_ParseTuple(args, "O!", &ViewEdge_Type, &py_ve) ))
+ return NULL;
+
+ self->ve_it->setCurrentEdge( ((BPy_ViewEdge *) py_ve)->ve );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdgeIterator_getBegin___doc__[] =
+".. method:: getBegin()\n"
+"\n"
+" Returns the first ViewEdge used for the iteration.\n"
+"\n"
+" :return: The first ViewEdge used for the iteration.\n"
+" :rtype: :class:`ViewEdge`\n";
+
+static PyObject *ViewEdgeIterator_getBegin( BPy_ViewEdgeIterator *self ) {
+ ViewEdge *ve = self->ve_it->getBegin();
+ if( ve )
+ return BPy_ViewEdge_from_ViewEdge( *ve );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdgeIterator_setBegin___doc__[] =
+".. method:: setBegin(begin)\n"
+"\n"
+" Sets the first ViewEdge used for the iteration.\n"
+"\n"
+" :arg begin: The first ViewEdge used for the iteration.\n"
+" :type begin: :class:`ViewEdge`\n";
+
+static PyObject *ViewEdgeIterator_setBegin( BPy_ViewEdgeIterator *self, PyObject *args ) {
+ PyObject *py_ve;
+
+ if(!( PyArg_ParseTuple(args, "O!", &ViewEdge_Type, &py_ve) ))
+ return NULL;
+
+ self->ve_it->setBegin( ((BPy_ViewEdge *) py_ve)->ve );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdgeIterator_getOrientation___doc__[] =
+".. method:: getOrientation()\n"
+"\n"
+" Returns the orientation of the pointed ViewEdge in the iteration.\n"
+"\n"
+" :return: The orientation of the pointed ViewEdge in the iteration.\n"
+" :rtype: bool\n";
+
+static PyObject *ViewEdgeIterator_getOrientation( BPy_ViewEdgeIterator *self ) {
+ return PyBool_from_bool( self->ve_it->getOrientation() );
+}
+
+static char ViewEdgeIterator_setOrientation___doc__[] =
+".. method:: setOrientation(orientation)\n"
+"\n"
+" Sets the orientation of the pointed ViewEdge in the iteration.\n"
+"\n"
+" :arg orientation: If true, we'll look for the next ViewEdge among\n"
+" the ViewEdges that surround the ending ViewVertex of begin. If\n"
+" false, we'll search over the ViewEdges surrounding the ending\n"
+" ViewVertex of begin.\n"
+" :type orientation: bool\n";
+
+static PyObject *ViewEdgeIterator_setOrientation( BPy_ViewEdgeIterator *self, PyObject *args ) {
+ PyObject *py_b;
+
+ if(!( PyArg_ParseTuple(args, "O", &py_b) ))
+ return NULL;
+
+ self->ve_it->setOrientation( bool_from_PyBool(py_b) );
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdgeIterator_changeOrientation___doc__[] =
+".. method:: changeOrientation()\n"
+"\n"
+" Changes the current orientation.\n";
+
+static PyObject *ViewEdgeIterator_changeOrientation( BPy_ViewEdgeIterator *self ) {
+ self->ve_it->changeOrientation();
+
+ Py_RETURN_NONE;
+}
+
+static char ViewEdgeIterator_getObject___doc__[] =
+".. method:: getObject()\n"
+"\n"
+" Returns the pointed ViewEdge.\n"
+"\n"
+" :return: The pointed ViewEdge.\n"
+" :rtype: :class:`ViewEdge`\n";
+
+static PyObject * ViewEdgeIterator_getObject( BPy_ViewEdgeIterator *self) {
+
+ ViewEdge *ve = self->ve_it->operator*();
+ if( ve )
+ return BPy_ViewEdge_from_ViewEdge( *ve );
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------ViewEdgeIterator instance definitions ----------------------------*/
+static PyMethodDef BPy_ViewEdgeIterator_methods[] = {
+ {"getCurrentEdge", ( PyCFunction ) ViewEdgeIterator_getCurrentEdge, METH_NOARGS, ViewEdgeIterator_getCurrentEdge___doc__},
+ {"setCurrentEdge", ( PyCFunction ) ViewEdgeIterator_setCurrentEdge, METH_VARARGS, ViewEdgeIterator_setCurrentEdge___doc__},
+ {"getBegin", ( PyCFunction ) ViewEdgeIterator_getBegin, METH_NOARGS, ViewEdgeIterator_getBegin___doc__},
+ {"setBegin", ( PyCFunction ) ViewEdgeIterator_setBegin, METH_VARARGS, ViewEdgeIterator_setBegin___doc__},
+ {"getOrientation", ( PyCFunction ) ViewEdgeIterator_getOrientation, METH_NOARGS, ViewEdgeIterator_getOrientation___doc__},
+ {"setOrientation", ( PyCFunction ) ViewEdgeIterator_setOrientation, METH_VARARGS, ViewEdgeIterator_setOrientation___doc__},
+ {"changeOrientation", ( PyCFunction ) ViewEdgeIterator_changeOrientation, METH_NOARGS, ViewEdgeIterator_changeOrientation___doc__},
+ {"getObject", ( PyCFunction ) ViewEdgeIterator_getObject, METH_NOARGS, ViewEdgeIterator_getObject___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_ViewEdgeIterator type definition ------------------------------*/
+
+PyTypeObject ViewEdgeIterator_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ViewEdgeIterator", /* tp_name */
+ sizeof(BPy_ViewEdgeIterator), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ViewEdgeIterator___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_ViewEdgeIterator_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Iterator_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ViewEdgeIterator___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.h b/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.h
new file mode 100644
index 00000000000..dce90efc8cf
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ViewEdgeIterator.h
@@ -0,0 +1,33 @@
+#ifndef FREESTYLE_PYTHON_VIEWEDGEITERATOR_H
+#define FREESTYLE_PYTHON_VIEWEDGEITERATOR_H
+
+
+#include "../../view_map/ViewMapIterators.h"
+
+#include "../BPy_Iterator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ViewEdgeIterator_Type;
+
+#define BPy_ViewEdgeIterator_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ViewEdgeIterator_Type) )
+
+/*---------------------------Python BPy_ViewEdgeIterator structure definition----------*/
+typedef struct {
+ BPy_Iterator py_it;
+ ViewEdgeInternal::ViewEdgeIterator *ve_it;
+} BPy_ViewEdgeIterator;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_VIEWEDGEITERATOR_H */
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp
new file mode 100644
index 00000000000..46eb7055217
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp
@@ -0,0 +1,140 @@
+#include "BPy_orientedViewEdgeIterator.h"
+
+#include "../BPy_Convert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char orientedViewEdgeIterator___doc__[] =
+"Class hierarchy: :class:`Iterator` > :class:`orientedViewEdgeIterator`\n"
+"\n"
+"Class representing an iterator over oriented ViewEdges around a\n"
+":class:`ViewVertex`. This iterator allows a CCW iteration (in the image\n"
+"plane). An instance of an orientedViewEdgeIterator can only be\n"
+"obtained from a ViewVertex by calling edgesBegin() or edgesEnd().\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(iBrother)\n"
+"\n"
+" Copy constructor.\n"
+"\n"
+" :arg iBrother: An orientedViewEdgeIterator object.\n"
+" :type iBrother: :class:`orientedViewEdgeIterator`\n";
+
+static int orientedViewEdgeIterator___init__(BPy_orientedViewEdgeIterator *self, PyObject *args )
+{
+ PyObject *obj = 0;
+
+ if (!( PyArg_ParseTuple(args, "|O", &obj) ))
+ return -1;
+
+ if( !obj )
+ self->ove_it = new ViewVertexInternal::orientedViewEdgeIterator();
+ else if( BPy_orientedViewEdgeIterator_Check(obj) )
+ self->ove_it = new ViewVertexInternal::orientedViewEdgeIterator(*( ((BPy_orientedViewEdgeIterator *) obj)->ove_it ));
+ else {
+ PyErr_SetString(PyExc_TypeError, "invalid argument");
+ return -1;
+ }
+
+ self->py_it.it = self->ove_it;
+ self->reversed = 0;
+
+ return 0;
+}
+
+static PyObject * orientedViewEdgeIterator_iternext( BPy_orientedViewEdgeIterator *self ) {
+ ViewVertex::directedViewEdge *dve;
+ if (self->reversed) {
+ if (self->ove_it->isBegin()) {
+ PyErr_SetNone(PyExc_StopIteration);
+ return NULL;
+ }
+ self->ove_it->decrement();
+ dve = self->ove_it->operator->();
+ } else {
+ if (self->ove_it->isEnd()) {
+ PyErr_SetNone(PyExc_StopIteration);
+ return NULL;
+ }
+ dve = self->ove_it->operator->();
+ self->ove_it->increment();
+ }
+ return BPy_directedViewEdge_from_directedViewEdge( *dve );
+}
+
+static char orientedViewEdgeIterator_getObject___doc__[] =
+".. method:: getObject()\n"
+"\n"
+" Returns the pointed oriented ViewEdge.\n"
+"\n"
+" :return: A tuple of the pointed ViewEdge and a boolean value. If\n"
+" the boolean value is true, the ViewEdge is incoming.\n"
+" :rtype: (:class:`directedViewEdge`, bool)\n";
+
+static PyObject * orientedViewEdgeIterator_getObject( BPy_orientedViewEdgeIterator *self) {
+ return BPy_directedViewEdge_from_directedViewEdge( self->ove_it->operator*() );
+}
+
+/*----------------------orientedViewEdgeIterator instance definitions ----------------------------*/
+static PyMethodDef BPy_orientedViewEdgeIterator_methods[] = {
+ {"getObject", ( PyCFunction ) orientedViewEdgeIterator_getObject, METH_NOARGS, orientedViewEdgeIterator_getObject___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_orientedViewEdgeIterator type definition ------------------------------*/
+
+PyTypeObject orientedViewEdgeIterator_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "orientedViewEdgeIterator", /* tp_name */
+ sizeof(BPy_orientedViewEdgeIterator), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ orientedViewEdgeIterator___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ PyObject_SelfIter, /* tp_iter */
+ (iternextfunc)orientedViewEdgeIterator_iternext, /* tp_iternext */
+ BPy_orientedViewEdgeIterator_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &Iterator_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)orientedViewEdgeIterator___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.h b/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.h
new file mode 100644
index 00000000000..cd9edf1e224
--- /dev/null
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_ORIENTEDVIEWEDGEITERATOR_H
+#define FREESTYLE_PYTHON_ORIENTEDVIEWEDGEITERATOR_H
+
+#include "../../stroke/Stroke.h"
+#include "../../view_map/ViewMapIterators.h"
+
+#include "../BPy_Iterator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject orientedViewEdgeIterator_Type;
+
+#define BPy_orientedViewEdgeIterator_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &orientedViewEdgeIterator_Type) )
+
+/*---------------------------Python BPy_orientedViewEdgeIterator structure definition----------*/
+typedef struct {
+ BPy_Iterator py_it;
+ ViewVertexInternal::orientedViewEdgeIterator *ove_it;
+ int reversed;
+} BPy_orientedViewEdgeIterator;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_ORIENTEDVIEWEDGEITERATOR_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_BackboneStretcherShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_BackboneStretcherShader.cpp
new file mode 100644
index 00000000000..cdab4b38b95
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_BackboneStretcherShader.cpp
@@ -0,0 +1,91 @@
+#include "BPy_BackboneStretcherShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char BackboneStretcherShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`BackboneStretcherShader`\n"
+"\n"
+"[Geometry shader]\n"
+"\n"
+".. method:: __init__(iAmount=2.0)\n"
+"\n"
+" Builds a BackboneStretcherShader object.\n"
+"\n"
+" :arg iAmount: The stretching amount value.\n"
+" :type iAmount: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Stretches the stroke at its two extremities and following the\n"
+" respective directions: v(1)v(0) and v(n-1)v(n).\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int BackboneStretcherShader___init__( BPy_BackboneStretcherShader* self, PyObject *args)
+{
+ float f = 2.0;
+
+ if(!( PyArg_ParseTuple(args, "|f", &f) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::BackboneStretcherShader(f);
+ return 0;
+}
+
+/*-----------------------BPy_BackboneStretcherShader type definition ------------------------------*/
+
+PyTypeObject BackboneStretcherShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BackboneStretcherShader", /* tp_name */
+ sizeof(BPy_BackboneStretcherShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ BackboneStretcherShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)BackboneStretcherShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_BackboneStretcherShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_BackboneStretcherShader.h
new file mode 100644
index 00000000000..35a74c0bda2
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_BackboneStretcherShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_BACKBONESTRETCHERSHADER_H
+#define FREESTYLE_PYTHON_BACKBONESTRETCHERSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject BackboneStretcherShader_Type;
+
+#define BPy_BackboneStretcherShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &BackboneStretcherShader_Type) )
+
+/*---------------------------Python BPy_BackboneStretcherShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_BackboneStretcherShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_BACKBONESTRETCHERSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_BezierCurveShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_BezierCurveShader.cpp
new file mode 100644
index 00000000000..f3d3bfafd08
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_BezierCurveShader.cpp
@@ -0,0 +1,93 @@
+#include "BPy_BezierCurveShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char BezierCurveShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`BezierCurveShader`\n"
+"\n"
+"[Geometry shader]\n"
+"\n"
+".. method:: __init__(error=4.0)\n"
+"\n"
+" Builds a BezierCurveShader object.\n"
+"\n"
+" :arg error: The error we're allowing for the approximation. This\n"
+" error is the max distance allowed between the new curve and the\n"
+" original geometry.\n"
+" :type error: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Transforms the stroke backbone geometry so that it corresponds to a\n"
+" Bezier Curve approximation of the original backbone geometry.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int BezierCurveShader___init__( BPy_BezierCurveShader* self, PyObject *args)
+{
+ float f = 4.0;
+
+ if(!( PyArg_ParseTuple(args, "|f", &f) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::BezierCurveShader(f);
+ return 0;
+}
+
+/*-----------------------BPy_BezierCurveShader type definition ------------------------------*/
+
+PyTypeObject BezierCurveShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "BezierCurveShader", /* tp_name */
+ sizeof(BPy_BezierCurveShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ BezierCurveShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)BezierCurveShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_BezierCurveShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_BezierCurveShader.h
new file mode 100644
index 00000000000..b94ef88acea
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_BezierCurveShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_BEZIERCURVESHADER_H
+#define FREESTYLE_PYTHON_BEZIERCURVESHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject BezierCurveShader_Type;
+
+#define BPy_BezierCurveShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &BezierCurveShader_Type) )
+
+/*---------------------------Python BPy_BezierCurveShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_BezierCurveShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_BEZIERCURVESHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_CalligraphicShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_CalligraphicShader.cpp
new file mode 100644
index 00000000000..bb77d0ba5be
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_CalligraphicShader.cpp
@@ -0,0 +1,113 @@
+#include "BPy_CalligraphicShader.h"
+
+#include "../../stroke/AdvancedStrokeShaders.h"
+#include "../BPy_Convert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char CalligraphicShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`CalligraphicShader`\n"
+"\n"
+"[Thickness Shader]\n"
+"\n"
+".. method:: __init__(iMinThickness, iMaxThickness, iOrientation, iClamp)\n"
+"\n"
+" Builds a CalligraphicShader object.\n"
+"\n"
+" :arg iMinThickness: The minimum thickness in the direction\n"
+" perpendicular to the main direction.\n"
+" :type iMinThickness: float\n"
+" :arg iMaxThickness: The maximum thickness in the main direction.\n"
+" :type iMaxThickness: float\n"
+" :arg iOrientation: The 2D vector giving the main direction.\n"
+" :type iOrientation: :class:`mathutils.Vector`\n"
+" :arg iClamp: If true, the strokes are drawn in black when the stroke\n"
+" direction is between -90 and 90 degrees with respect to the main\n"
+" direction and drawn in white otherwise. If false, the strokes\n"
+" are always drawn in black.\n"
+" :type iClamp: bool\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Assigns thicknesses to the stroke vertices so that the stroke looks\n"
+" like made with a calligraphic tool, i.e. the stroke will be the\n"
+" thickest in a main direction, and the thinest in the direction\n"
+" perpendicular to this one, and an interpolation inbetween.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int CalligraphicShader___init__( BPy_CalligraphicShader* self, PyObject *args)
+{
+ double d1, d2;
+ PyObject *obj3 = 0, *obj4 = 0;
+
+
+ if(!( PyArg_ParseTuple(args, "ddOO", &d1, &d2, &obj3, &obj4) ))
+ return -1;
+ Vec2f *v = Vec2f_ptr_from_PyObject(obj3);
+ if( !v ) {
+ PyErr_SetString(PyExc_TypeError, "argument 3 must be a 2D vector (either a list of 2 elements or Vector)");
+ return -1;
+ }
+ self->py_ss.ss = new CalligraphicShader(d1, d2, *v, bool_from_PyBool(obj4) );
+ delete v;
+
+ return 0;
+
+}
+
+/*-----------------------BPy_CalligraphicShader type definition ------------------------------*/
+
+PyTypeObject CalligraphicShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "CalligraphicShader", /* tp_name */
+ sizeof(BPy_CalligraphicShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ CalligraphicShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)CalligraphicShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_CalligraphicShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_CalligraphicShader.h
new file mode 100644
index 00000000000..c573b0184ad
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_CalligraphicShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_CALLIGRAPHICSHADER_H
+#define FREESTYLE_PYTHON_CALLIGRAPHICSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject CalligraphicShader_Type;
+
+#define BPy_CalligraphicShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &CalligraphicShader_Type)
+
+/*---------------------------Python BPy_CalligraphicShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_CalligraphicShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_CALLIGRAPHICSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorNoiseShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorNoiseShader.cpp
new file mode 100644
index 00000000000..d005e8ccfe8
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorNoiseShader.cpp
@@ -0,0 +1,92 @@
+#include "BPy_ColorNoiseShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ColorNoiseShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`ColorNoiseShader`\n"
+"\n"
+"[Color shader]\n"
+"\n"
+".. method:: __init__(iAmplitude, iPeriod)\n"
+"\n"
+" Builds a ColorNoiseShader object.\n"
+"\n"
+" :arg iAmplitude: The amplitude of the noise signal.\n"
+" :type iAmplitude: float\n"
+" :arg iPeriod: The period of the noise signal.\n"
+" :type iPeriod: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Shader to add noise to the stroke colors.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int ColorNoiseShader___init__( BPy_ColorNoiseShader* self, PyObject *args)
+{
+ float f1, f2;
+
+ if(!( PyArg_ParseTuple(args, "ff", &f1, &f2) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::ColorNoiseShader(f1, f2);
+ return 0;
+}
+
+/*-----------------------BPy_ColorNoiseShader type definition ------------------------------*/
+
+PyTypeObject ColorNoiseShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ColorNoiseShader", /* tp_name */
+ sizeof(BPy_ColorNoiseShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ColorNoiseShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ColorNoiseShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorNoiseShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorNoiseShader.h
new file mode 100644
index 00000000000..694b847565e
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorNoiseShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_COLORNOISESHADER_H
+#define FREESTYLE_PYTHON_COLORNOISESHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ColorNoiseShader_Type;
+
+#define BPy_ColorNoiseShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ColorNoiseShader_Type) )
+
+/*---------------------------Python BPy_ColorNoiseShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_ColorNoiseShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_COLORNOISESHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.cpp
new file mode 100644
index 00000000000..2d48df78da1
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.cpp
@@ -0,0 +1,98 @@
+#include "BPy_ColorVariationPatternShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+#include "../BPy_Convert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ColorVariationPatternShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`ColorVariationPatternShader`\n"
+"\n"
+"[Color shader]\n"
+"\n"
+".. method:: __init__(pattern_name, stretch=True)\n"
+"\n"
+" Builds a ColorVariationPatternShader object.\n"
+"\n"
+" :arg pattern_name: The file name of the texture file to use as\n"
+" pattern.\n"
+" :type pattern_name: str\n"
+" :arg stretch: Tells whether the texture must be strecthed or\n"
+" repeted to fit the stroke.\n"
+" :type stretch: bool\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Applies a pattern to vary the original color. The new color is the\n"
+" result of the multiplication of the pattern and the original color.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int ColorVariationPatternShader___init__( BPy_ColorVariationPatternShader* self, PyObject *args)
+{
+ const char *s;
+ PyObject *obj = 0;
+
+ if(!( PyArg_ParseTuple(args, "s|O", &s, &obj) ))
+ return -1;
+
+ bool b = (obj) ? bool_from_PyBool(obj) : true;
+ self->py_ss.ss = new StrokeShaders::ColorVariationPatternShader(s,b);
+ return 0;
+}
+
+/*-----------------------BPy_ColorVariationPatternShader type definition ------------------------------*/
+
+PyTypeObject ColorVariationPatternShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ColorVariationPatternShader", /* tp_name */
+ sizeof(BPy_ColorVariationPatternShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ColorVariationPatternShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ColorVariationPatternShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.h
new file mode 100644
index 00000000000..b1898ebfecf
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_COLORVARIATIONPATTERNSHADER_H
+#define FREESTYLE_PYTHON_COLORVARIATIONPATTERNSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ColorVariationPatternShader_Type;
+
+#define BPy_ColorVariationPatternShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ColorVariationPatternShader_Type) )
+
+/*---------------------------Python BPy_ColorVariationPatternShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_ColorVariationPatternShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_COLORVARIATIONPATTERNSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantColorShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantColorShader.cpp
new file mode 100644
index 00000000000..d0f4c365a80
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantColorShader.cpp
@@ -0,0 +1,96 @@
+#include "BPy_ConstantColorShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ConstantColorShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`ConstantColorShader`\n"
+"\n"
+"[Color shader]\n"
+"\n"
+".. method:: __init__(iR, iG, iB, iAlpha=1.0)\n"
+"\n"
+" Builds a ConstantColorShader object.\n"
+"\n"
+" :arg iR: The red component.\n"
+" :type iR: float\n"
+" :arg iG: The green component.\n"
+" :type iG: float\n"
+" :arg iB: The blue component.\n"
+" :type iB: float\n"
+" :arg iAlpha: The alpha value.\n"
+" :type iAlpha: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Assigns a constant color to every vertex of the Stroke.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int ConstantColorShader___init__( BPy_ConstantColorShader* self, PyObject *args)
+{
+ float f1, f2, f3, f4 = 1.0;
+
+ if(!( PyArg_ParseTuple(args, "fff|f", &f1, &f2, &f3, &f4) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::ConstantColorShader(f1, f2, f3, f4);
+ return 0;
+}
+
+/*-----------------------BPy_ConstantColorShader type definition ------------------------------*/
+
+PyTypeObject ConstantColorShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ConstantColorShader", /* tp_name */
+ sizeof(BPy_ConstantColorShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ConstantColorShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ConstantColorShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantColorShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantColorShader.h
new file mode 100644
index 00000000000..30a09d852fd
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantColorShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_CONSTANTCOLORSHADER_H
+#define FREESTYLE_PYTHON_CONSTANTCOLORSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ConstantColorShader_Type;
+
+#define BPy_ConstantColorShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ConstantColorShader_Type) )
+
+/*---------------------------Python BPy_ConstantColorShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_ConstantColorShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_CONSTANTCOLORSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantThicknessShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantThicknessShader.cpp
new file mode 100644
index 00000000000..60d3e696675
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantThicknessShader.cpp
@@ -0,0 +1,90 @@
+#include "BPy_ConstantThicknessShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ConstantThicknessShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`ConstantThicknessShader`\n"
+"\n"
+"[Thickness shader]\n"
+"\n"
+".. method:: __init__(thickness)\n"
+"\n"
+" Builds a ConstantThicknessShader object.\n"
+"\n"
+" :arg thickness: The thickness that must be assigned to the stroke.\n"
+" :type thickness: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Assigns an absolute constant thickness to every vertex of the Stroke.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int ConstantThicknessShader___init__( BPy_ConstantThicknessShader* self, PyObject *args)
+{
+ float f;
+
+ if(!( PyArg_ParseTuple(args, "f", &f) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::ConstantThicknessShader(f);
+ return 0;
+}
+
+/*-----------------------BPy_ConstantThicknessShader type definition ------------------------------*/
+
+PyTypeObject ConstantThicknessShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ConstantThicknessShader", /* tp_name */
+ sizeof(BPy_ConstantThicknessShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ConstantThicknessShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ConstantThicknessShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantThicknessShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantThicknessShader.h
new file mode 100644
index 00000000000..bb7f3c0f622
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantThicknessShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_CONSTANTTHICKNESSSHADER_H
+#define FREESTYLE_PYTHON_CONSTANTTHICKNESSSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ConstantThicknessShader_Type;
+
+#define BPy_ConstantThicknessShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ConstantThicknessShader_Type) )
+
+/*---------------------------Python BPy_ConstantThicknessShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_ConstantThicknessShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_CONSTANTTHICKNESSSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.cpp
new file mode 100644
index 00000000000..3892ccca37b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.cpp
@@ -0,0 +1,96 @@
+#include "BPy_ConstrainedIncreasingThicknessShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ConstrainedIncreasingThicknessShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`ConstrainedIncreasingThicknessShader`\n"
+"\n"
+"[Thickness shader]\n"
+"\n"
+".. method:: __init__(iThicknessMin, iThicknessMax, iRatio)\n"
+"\n"
+" Builds a ConstrainedIncreasingThicknessShader object.\n"
+"\n"
+" :arg iThicknessMin: The minimum thickness.\n"
+" :type iThicknessMin: float\n"
+" :arg iThicknessMax: The maximum thickness.\n"
+" :type iThicknessMax: float\n"
+" :arg iRatio: The thickness/length ratio that we don't want to exceed. \n"
+" :type iRatio: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Same as the :class:`IncreasingThicknessShader`, but here we allow\n"
+" the user to control the thickness/length ratio so that we don't get\n"
+" fat short lines.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int ConstrainedIncreasingThicknessShader___init__( BPy_ConstrainedIncreasingThicknessShader* self, PyObject *args)
+{
+ float f1, f2, f3;
+
+ if(!( PyArg_ParseTuple(args, "fff", &f1, &f2, &f3) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::ConstrainedIncreasingThicknessShader(f1, f2, f3);
+ return 0;
+}
+
+/*-----------------------BPy_ConstrainedIncreasingThicknessShader type definition ------------------------------*/
+
+PyTypeObject ConstrainedIncreasingThicknessShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ConstrainedIncreasingThicknessShader", /* tp_name */
+ sizeof(BPy_ConstrainedIncreasingThicknessShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ConstrainedIncreasingThicknessShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ConstrainedIncreasingThicknessShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.h
new file mode 100644
index 00000000000..38a8aa2bfe0
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_CONSTRAINEDINCREASINGTHICKNESSSHADER_H
+#define FREESTYLE_PYTHON_CONSTRAINEDINCREASINGTHICKNESSSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ConstrainedIncreasingThicknessShader_Type;
+
+#define BPy_ConstrainedIncreasingThicknessShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ConstrainedIncreasingThicknessShader_Type) )
+
+/*---------------------------Python BPy_ConstrainedIncreasingThicknessShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_ConstrainedIncreasingThicknessShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_CONSTRAINEDINCREASINGTHICKNESSSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_GuidingLinesShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_GuidingLinesShader.cpp
new file mode 100644
index 00000000000..79af155b728
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_GuidingLinesShader.cpp
@@ -0,0 +1,98 @@
+#include "BPy_GuidingLinesShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GuidingLinesShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`GuidingLinesShader`\n"
+"\n"
+"[Geometry shader]\n"
+"\n"
+".. method:: __init__(iOffset)\n"
+"\n"
+" Builds a GuidingLinesShader object.\n"
+"\n"
+" :arg iOffset: The line that replaces the stroke is initially in the\n"
+" middle of the initial stroke bounding box. iOffset is the value\n"
+" of the displacement which is applied to this line along its\n"
+" normal.\n"
+" :type iOffset: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Shader to modify the Stroke geometry so that it corresponds to its\n"
+" main direction line. This shader must be used together with the\n"
+" splitting operator using the curvature criterion. Indeed, the\n"
+" precision of the approximation will depend on the size of the\n"
+" stroke's pieces. The bigger the pieces are, the rougher the\n"
+" approximation is.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int GuidingLinesShader___init__( BPy_GuidingLinesShader* self, PyObject *args)
+{
+ float f;
+
+ if(!( PyArg_ParseTuple(args, "f", &f) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::GuidingLinesShader(f);
+ return 0;
+}
+
+/*-----------------------BPy_GuidingLinesShader type definition ------------------------------*/
+
+PyTypeObject GuidingLinesShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GuidingLinesShader", /* tp_name */
+ sizeof(BPy_GuidingLinesShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GuidingLinesShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GuidingLinesShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_GuidingLinesShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_GuidingLinesShader.h
new file mode 100644
index 00000000000..e25704c33ba
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_GuidingLinesShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_GUIDINGLINESSHADER_H
+#define FREESTYLE_PYTHON_GUIDINGLINESSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GuidingLinesShader_Type;
+
+#define BPy_GuidingLinesShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GuidingLinesShader_Type) )
+
+/*---------------------------Python BPy_GuidingLinesShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_GuidingLinesShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_GUIDINGLINESSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingColorShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingColorShader.cpp
new file mode 100644
index 00000000000..063e5cd587d
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingColorShader.cpp
@@ -0,0 +1,106 @@
+#include "BPy_IncreasingColorShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char IncreasingColorShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`IncreasingColorShader`\n"
+"\n"
+"[Color shader]\n"
+"\n"
+".. method:: __init__(iRm, iGm, iBm, iAlpham, iRM, iGM, iBM, iAlphaM)\n"
+"\n"
+" Builds an IncreasingColorShader object.\n"
+"\n"
+" :arg iRm: The first color red component.\n"
+" :type iRm: float\n"
+" :arg iGm: The first color green component.\n"
+" :type iGm: float\n"
+" :arg iBm: The first color blue component.\n"
+" :type iBm: float\n"
+" :arg iAlpham: The first color alpha value.\n"
+" :type iAlpham: float\n"
+" :arg iRM: The second color red component.\n"
+" :type iRM: float\n"
+" :arg iGM: The second color green component.\n"
+" :type iGM: float\n"
+" :arg iBM: The second color blue component.\n"
+" :type iBM: float\n"
+" :arg iAlphaM: The second color alpha value.\n"
+" :type iAlphaM: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Assigns a varying color to the stroke. The user specifies two\n"
+" colors A and B. The stroke color will change linearly from A to B\n"
+" between the first and the last vertex.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int IncreasingColorShader___init__( BPy_IncreasingColorShader* self, PyObject *args)
+{
+ float f1, f2, f3, f4, f5, f6, f7, f8;
+
+ if(!( PyArg_ParseTuple(args, "ffffffff", &f1, &f2, &f3, &f4, &f5, &f6, &f7, &f8) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::IncreasingColorShader(f1, f2, f3, f4, f5, f6, f7, f8);
+ return 0;
+}
+
+/*-----------------------BPy_IncreasingColorShader type definition ------------------------------*/
+
+PyTypeObject IncreasingColorShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "IncreasingColorShader", /* tp_name */
+ sizeof(BPy_IncreasingColorShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ IncreasingColorShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)IncreasingColorShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingColorShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingColorShader.h
new file mode 100644
index 00000000000..9bc82e98098
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingColorShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_INCREASINGCOLORSHADER_H
+#define FREESTYLE_PYTHON_INCREASINGCOLORSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject IncreasingColorShader_Type;
+
+#define BPy_IncreasingColorShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &IncreasingColorShader_Type) )
+
+/*---------------------------Python BPy_IncreasingColorShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_IncreasingColorShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_INCREASINGCOLORSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingThicknessShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingThicknessShader.cpp
new file mode 100644
index 00000000000..398587df23e
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingThicknessShader.cpp
@@ -0,0 +1,96 @@
+#include "BPy_IncreasingThicknessShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char IncreasingThicknessShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`IncreasingThicknessShader`\n"
+"\n"
+"[Thickness shader]\n"
+"\n"
+".. method:: __init__(iThicknessA, iThicknessB)\n"
+"\n"
+" Builds an IncreasingThicknessShader object.\n"
+"\n"
+" :arg iThicknessA: The first thickness value.\n"
+" :type iThicknessA: float\n"
+" :arg iThicknessB: The second thickness value.\n"
+" :type iThicknessB: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Assigns thicknesses values such as the thickness increases from a\n"
+" thickness value A to a thickness value B between the first vertex\n"
+" to the midpoint vertex and then decreases from B to a A between\n"
+" this midpoint vertex and the last vertex. The thickness is\n"
+" linearly interpolated from A to B.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int IncreasingThicknessShader___init__( BPy_IncreasingThicknessShader* self, PyObject *args)
+{
+ float f1, f2;
+
+ if(!( PyArg_ParseTuple(args, "ff", &f1, &f2) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::IncreasingThicknessShader(f1, f2);
+ return 0;
+}
+
+/*-----------------------BPy_IncreasingThicknessShader type definition ------------------------------*/
+
+PyTypeObject IncreasingThicknessShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "IncreasingThicknessShader", /* tp_name */
+ sizeof(BPy_IncreasingThicknessShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ IncreasingThicknessShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)IncreasingThicknessShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingThicknessShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingThicknessShader.h
new file mode 100644
index 00000000000..33d883b1860
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingThicknessShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_INCREASINGTHICKNESSSHADER_H
+#define FREESTYLE_PYTHON_INCREASINGTHICKNESSSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject IncreasingThicknessShader_Type;
+
+#define BPy_IncreasingThicknessShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &IncreasingThicknessShader_Type) )
+
+/*---------------------------Python BPy_IncreasingThicknessShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_IncreasingThicknessShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_INCREASINGTHICKNESSSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_PolygonalizationShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_PolygonalizationShader.cpp
new file mode 100644
index 00000000000..2ea4bf14941
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_PolygonalizationShader.cpp
@@ -0,0 +1,97 @@
+#include "BPy_PolygonalizationShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char PolygonalizationShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`PolygonalizationShader`\n"
+"\n"
+"[Geometry shader]\n"
+"\n"
+".. method:: __init__(iError)\n"
+"\n"
+" Builds a PolygonalizationShader object.\n"
+"\n"
+" :arg iError: The error we want our polygonal approximation to have\n"
+" with respect to the original geometry. The smaller, the closer\n"
+" the new stroke is to the orinal one. This error corresponds to\n"
+" the maximum distance between the new stroke and the old one.\n"
+" :type iError: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Modifies the Stroke geometry so that it looks more \"polygonal\".\n"
+" The basic idea is to start from the minimal stroke approximation\n"
+" consisting in a line joining the first vertex to the last one and\n"
+" to subdivide using the original stroke vertices until a certain\n"
+" error is reached.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int PolygonalizationShader___init__( BPy_PolygonalizationShader* self, PyObject *args)
+{
+ float f;
+
+ if(!( PyArg_ParseTuple(args, "f", &f) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::PolygonalizationShader(f);
+ return 0;
+}
+
+/*-----------------------BPy_PolygonalizationShader type definition ------------------------------*/
+
+PyTypeObject PolygonalizationShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "PolygonalizationShader", /* tp_name */
+ sizeof(BPy_PolygonalizationShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ PolygonalizationShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)PolygonalizationShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_PolygonalizationShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_PolygonalizationShader.h
new file mode 100644
index 00000000000..85bcc00e869
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_PolygonalizationShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_POLYGONALIZATIONSHADER_H
+#define FREESTYLE_PYTHON_POLYGONALIZATIONSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject PolygonalizationShader_Type;
+
+#define BPy_PolygonalizationShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &PolygonalizationShader_Type) )
+
+/*---------------------------Python BPy_PolygonalizationShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_PolygonalizationShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_POLYGONALIZATIONSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_SamplingShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_SamplingShader.cpp
new file mode 100644
index 00000000000..08b1e64f7a5
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_SamplingShader.cpp
@@ -0,0 +1,90 @@
+#include "BPy_SamplingShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char SamplingShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`SamplingShader`\n"
+"\n"
+"[Geometry shader]\n"
+"\n"
+".. method:: __init__(sampling)\n"
+"\n"
+" Builds a SamplingShader object.\n"
+"\n"
+" :arg sampling: The sampling to use for the stroke resampling.\n"
+" :type sampling: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Resamples the stroke.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int SamplingShader___init__( BPy_SamplingShader* self, PyObject *args)
+{
+ float f;
+
+ if(!( PyArg_ParseTuple(args, "f", &f) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::SamplingShader(f);
+ return 0;
+}
+
+/*-----------------------BPy_SamplingShader type definition ------------------------------*/
+
+PyTypeObject SamplingShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "SamplingShader", /* tp_name */
+ sizeof(BPy_SamplingShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ SamplingShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)SamplingShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_SamplingShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_SamplingShader.h
new file mode 100644
index 00000000000..dfc6efb3319
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_SamplingShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_SAMPLINGSHADER_H
+#define FREESTYLE_PYTHON_SAMPLINGSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject SamplingShader_Type;
+
+#define BPy_SamplingShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &SamplingShader_Type) )
+
+/*---------------------------Python BPy_SamplingShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_SamplingShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_SAMPLINGSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp
new file mode 100644
index 00000000000..6f62865f99a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp
@@ -0,0 +1,108 @@
+#include "BPy_SmoothingShader.h"
+
+#include "../../stroke/AdvancedStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char SmoothingShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`SmoothingShader`\n"
+"\n"
+"[Geometry shader]\n"
+"\n"
+".. method:: __init__(iNbIteration, iFactorPoint, ifactorCurvature, iFactorCurvatureDifference, iAnisoPoint, iAnisNormal, iAnisoCurvature, icarricatureFactor)\n"
+"\n"
+" Builds a SmoothingShader object.\n"
+"\n"
+" :arg iNbIteration: The number of iterations (400).\n"
+" :type iNbIteration: int\n"
+" :arg iFactorPoint: 0.0\n"
+" :type iFactorPoint: float\n"
+" :arg ifactorCurvature: 0.0\n"
+" :type ifactorCurvature: float\n"
+" :arg iFactorCurvatureDifference: 0.2\n"
+" :type iFactorCurvatureDifference: float\n"
+" :arg iAnisoPoint: \n"
+" :type iAnisoPoint: float\n"
+" :arg iAnisNormal: 0.0\n"
+" :type iAnisNormal: float\n"
+" :arg iAnisoCurvature: 0.0\n"
+" :type iAnisoCurvature: float\n"
+" :arg icarricatureFactor: 1.0\n"
+" :type icarricatureFactor: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Smoothes the stroke by moving the vertices to make the stroke\n"
+" smoother. Uses curvature flow to converge towards a curve of\n"
+" constant curvature. The diffusion method we use is anisotropic to\n"
+" prevent the diffusion accross corners.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int SmoothingShader___init__( BPy_SmoothingShader* self, PyObject *args)
+{
+ int i1;
+ double d2, d3, d4, d5, d6, d7, d8;
+
+ if(!( PyArg_ParseTuple(args, "iddddddd", &i1, &d2, &d3, &d4, &d5, &d6, &d7, &d8) ))
+ return -1;
+
+ self->py_ss.ss = new SmoothingShader(i1, d2, d3, d4, d5, d6, d7, d8);
+ return 0;
+}
+
+/*-----------------------BPy_SmoothingShader type definition ------------------------------*/
+
+PyTypeObject SmoothingShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "SmoothingShader", /* tp_name */
+ sizeof(BPy_SmoothingShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ SmoothingShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)SmoothingShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.h
new file mode 100644
index 00000000000..18d6ca3cc30
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHONSMOOTHINGSHADER_H
+#define FREESTYLE_PYTHONSMOOTHINGSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject SmoothingShader_Type;
+
+#define BPy_SmoothingShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &SmoothingShader_Type) )
+
+/*---------------------------Python BPy_SmoothingShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_SmoothingShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHONSMOOTHINGSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_SpatialNoiseShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_SpatialNoiseShader.cpp
new file mode 100644
index 00000000000..245212c3950
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_SpatialNoiseShader.cpp
@@ -0,0 +1,102 @@
+#include "BPy_SpatialNoiseShader.h"
+
+#include "../../stroke/AdvancedStrokeShaders.h"
+#include "../BPy_Convert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char SpatialNoiseShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`SpatialNoiseShader`\n"
+"\n"
+"[Geometry shader]\n"
+"\n"
+".. method:: __init__(iAmount, ixScale, nbOctave, smooth, pureRandom)\n"
+"\n"
+" Builds a SpatialNoiseShader object.\n"
+"\n"
+" :arg iAmount: The amplitude of the noise.\n"
+" :type iAmount: float\n"
+" :arg ixScale: The noise frequency.\n"
+" :type ixScale: float\n"
+" :arg nbOctave: The number of octaves\n"
+" :type nbOctave: int\n"
+" :arg smooth: True if you want the noise to be smooth.\n"
+" :type smooth: bool\n"
+" :arg pureRandom: True if you don't want any coherence.\n"
+" :type pureRandom: bool\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Spatial Noise stroke shader. Moves the vertices to make the stroke\n"
+" more noisy.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int SpatialNoiseShader___init__( BPy_SpatialNoiseShader* self, PyObject *args)
+{
+ float f1, f2;
+ int i3;
+ PyObject *obj4 = 0, *obj5 = 0;
+
+ if(!( PyArg_ParseTuple(args, "ffiOO", &f1, &f2, &i3, &obj4, &obj5) ))
+ return -1;
+
+ self->py_ss.ss = new SpatialNoiseShader(f1, f2, i3, bool_from_PyBool(obj4), bool_from_PyBool(obj5) );
+ return 0;
+}
+
+/*-----------------------BPy_SpatialNoiseShader type definition ------------------------------*/
+
+PyTypeObject SpatialNoiseShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "SpatialNoiseShader", /* tp_name */
+ sizeof(BPy_SpatialNoiseShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ SpatialNoiseShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)SpatialNoiseShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_SpatialNoiseShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_SpatialNoiseShader.h
new file mode 100644
index 00000000000..46e1c12385d
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_SpatialNoiseShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_SPATIALNOISESHADER_H
+#define FREESTYLE_PYTHON_SPATIALNOISESHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject SpatialNoiseShader_Type;
+
+#define BPy_SpatialNoiseShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &SpatialNoiseShader_Type) )
+
+/*---------------------------Python BPy_SpatialNoiseShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_SpatialNoiseShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_SPATIALNOISESHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.cpp
new file mode 100644
index 00000000000..a6e2d9f71e0
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.cpp
@@ -0,0 +1,117 @@
+#include "BPy_StrokeTextureShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+#include "../BPy_Convert.h"
+#include "../BPy_MediumType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char StrokeTextureShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`StrokeTextureShader`\n"
+"\n"
+"[Texture shader]\n"
+"\n"
+".. method:: __init__(textureFile, mediumType=MediumType.OPAQUE_MEDIUM, iTips=False)\n"
+"\n"
+" Builds a StrokeTextureShader object.\n"
+"\n"
+" :arg textureFile: \n"
+" :type textureFile: str\n"
+" :arg mediumType: The medium type and therefore, the blending mode\n"
+" that must be used for the rendering of this stroke.\n"
+" :type mediumType: :class:`MediumType`\n"
+" :arg iTips: Tells whether the texture includes tips or not. If it\n"
+" is the case, the texture image must respect the following format.\n"
+" :type iTips: bool\n"
+"\n"
+" The format of a texture image including tips::\n"
+"\n"
+" ___________\n"
+" | |\n"
+" | A |\n"
+" |___________|\n"
+" | | |\n"
+" | B | C |\n"
+" |_____|_____|\n"
+"\n"
+" * A : The stroke's corpus texture.\n"
+" * B : The stroke's left extremity texture.\n"
+" * C : The stroke's right extremity texture.\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Assigns a texture and a blending mode to the stroke in order to\n"
+" simulate its marks system.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int StrokeTextureShader___init__( BPy_StrokeTextureShader* self, PyObject *args)
+{
+ const char *s1;
+ PyObject *obj2 = 0, *obj3 = 0;
+
+ if(!( PyArg_ParseTuple(args, "s|O!O", &s1, &MediumType_Type, &obj2, &obj3) ))
+ return -1;
+
+ Stroke::MediumType mt = (obj2) ? MediumType_from_BPy_MediumType(obj2) : Stroke::OPAQUE_MEDIUM;
+ bool b = (obj3) ? bool_from_PyBool(obj3) : true;
+
+ self->py_ss.ss = new StrokeShaders::StrokeTextureShader(s1,mt,b);
+ return 0;
+}
+
+/*-----------------------BPy_StrokeTextureShader type definition ------------------------------*/
+
+PyTypeObject StrokeTextureShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "StrokeTextureShader", /* tp_name */
+ sizeof(BPy_StrokeTextureShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ StrokeTextureShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)StrokeTextureShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.h
new file mode 100644
index 00000000000..c65506f2f14
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_STROKETEXTURESHADER_H
+#define FREESTYLE_PYTHON_STROKETEXTURESHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject StrokeTextureShader_Type;
+
+#define BPy_StrokeTextureShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &StrokeTextureShader_Type) )
+
+/*---------------------------Python BPy_StrokeTextureShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_StrokeTextureShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_STROKETEXTURESHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.cpp
new file mode 100644
index 00000000000..7fbb3462fb4
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.cpp
@@ -0,0 +1,106 @@
+#include "BPy_TextureAssignerShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char TextureAssignerShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`TextureAssignerShader`\n"
+"\n"
+"[Texture shader]\n"
+"\n"
+".. method:: __init__(id)\n"
+"\n"
+" Builds a TextureAssignerShader object.\n"
+"\n"
+" :arg id: The preset number to use.\n"
+" :type id: int\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Assigns a texture to the stroke in order to simulate its marks\n"
+" system. This shader takes as input an integer value telling which\n"
+" texture and blending mode to use among a set of predefined\n"
+" textures. Here are the different presets:\n"
+"\n"
+" * 0: `/brushes/charcoalAlpha.bmp`, `MediumType.HUMID_MEDIUM`\n"
+" * 1: `/brushes/washbrushAlpha.bmp`, `MediumType.HUMID_MEDIUM`\n"
+" * 2: `/brushes/oil.bmp`, `MediumType.HUMID_MEDIUM`\n"
+" * 3: `/brushes/oilnoblend.bmp`, `MediumType.HUMID_MEDIUM`\n"
+" * 4: `/brushes/charcoalAlpha.bmp`, `MediumType.DRY_MEDIUM`\n"
+" * 5: `/brushes/washbrushAlpha.bmp`, `MediumType.DRY_MEDIUM`\n"
+" * 6: `/brushes/opaqueDryBrushAlpha.bmp`, `MediumType.OPAQUE_MEDIUM`\n"
+" * 7: `/brushes/opaqueBrushAlpha.bmp`, `MediumType.OPAQUE_MEDIUM`\n"
+"\n"
+" Any other value will lead to the following preset:\n"
+"\n"
+" * Default: `/brushes/smoothAlpha.bmp`, `MediumType.OPAQUE_MEDIUM`\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int TextureAssignerShader___init__( BPy_TextureAssignerShader* self, PyObject *args)
+{
+ int i;
+
+ if(!( PyArg_ParseTuple(args, "i", &i) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::TextureAssignerShader(i);
+ return 0;
+}
+
+/*-----------------------BPy_TextureAssignerShader type definition ------------------------------*/
+
+PyTypeObject TextureAssignerShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "TextureAssignerShader", /* tp_name */
+ sizeof(BPy_TextureAssignerShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ TextureAssignerShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)TextureAssignerShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.h
new file mode 100644
index 00000000000..9cffc1c1662
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_TEXTUREASSIGNERSHADER_H
+#define FREESTYLE_PYTHON_TEXTUREASSIGNERSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject TextureAssignerShader_Type;
+
+#define BPy_TextureAssignerShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &TextureAssignerShader_Type) )
+
+/*---------------------------Python BPy_TextureAssignerShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_TextureAssignerShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_TEXTUREASSIGNERSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessNoiseShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessNoiseShader.cpp
new file mode 100644
index 00000000000..c0cf2176b52
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessNoiseShader.cpp
@@ -0,0 +1,92 @@
+#include "BPy_ThicknessNoiseShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ThicknessNoiseShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`ThicknessNoiseShader`\n"
+"\n"
+"[Thickness shader]\n"
+"\n"
+".. method:: __init__(iAmplitude, iPeriod)\n"
+"\n"
+" Builds a ThicknessNoiseShader object.\n"
+"\n"
+" :arg iAmplitude: The amplitude of the noise signal.\n"
+" :type iAmplitude: float\n"
+" :arg iPeriod: The period of the noise signal.\n"
+" :type iPeriod: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Adds some noise to the stroke thickness.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int ThicknessNoiseShader___init__( BPy_ThicknessNoiseShader* self, PyObject *args)
+{
+ float f1, f2;
+
+ if(!( PyArg_ParseTuple(args, "ff", &f1, &f2) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::ThicknessNoiseShader(f1, f2);
+ return 0;
+}
+
+/*-----------------------BPy_ThicknessNoiseShader type definition ------------------------------*/
+
+PyTypeObject ThicknessNoiseShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ThicknessNoiseShader", /* tp_name */
+ sizeof(BPy_ThicknessNoiseShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ThicknessNoiseShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ThicknessNoiseShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessNoiseShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessNoiseShader.h
new file mode 100644
index 00000000000..c3ef101683e
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessNoiseShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_THICKNESSNOISESHADER_H
+#define FREESTYLE_PYTHON_THICKNESSNOISESHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ThicknessNoiseShader_Type;
+
+#define BPy_ThicknessNoiseShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ThicknessNoiseShader_Type) )
+
+/*---------------------------Python BPy_ThicknessNoiseShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_ThicknessNoiseShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_THICKNESSNOISESHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.cpp
new file mode 100644
index 00000000000..afcfd68fcec
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.cpp
@@ -0,0 +1,103 @@
+#include "BPy_ThicknessVariationPatternShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+#include "../BPy_Convert.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ThicknessVariationPatternShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`ThicknessVariationPatternShader`\n"
+"\n"
+"[Thickness shader]\n"
+"\n"
+".. method:: __init__(pattern_name, iMinThickness, iMaxThickness, stretch)\n"
+"\n"
+" Builds a ThicknessVariationPatternShader object.\n"
+"\n"
+" :arg pattern_name: The texture file name.\n"
+" :type pattern_name: str\n"
+" :arg iMinThickness: The minimum thickness we don't want to exceed.\n"
+" :type iMinThickness: float\n"
+" :arg iMaxThickness: The maximum thickness we don't want to exceed.\n"
+" :type iMaxThickness: float\n"
+" :arg stretch: Tells whether the pattern texture must be stretched\n"
+" or repeted to fit the stroke.\n"
+" :type stretch: bool\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Applies a pattern (texture) to vary thickness. The new thicknesses\n"
+" are the result of the multiplication of the pattern and the\n"
+" original thickness.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int ThicknessVariationPatternShader___init__( BPy_ThicknessVariationPatternShader* self, PyObject *args)
+{
+ const char *s1;
+ float f2 = 1.0, f3 = 5.0;
+ PyObject *obj4 = 0;
+
+ if(!( PyArg_ParseTuple(args, "s|ffO", &s1, &f2, &f3, &obj4) ))
+ return -1;
+
+ bool b = (obj4) ? bool_from_PyBool(obj4) : true;
+ self->py_ss.ss = new StrokeShaders::ThicknessVariationPatternShader(s1, f2, f3, b);
+ return 0;
+}
+
+/*-----------------------BPy_ThicknessVariationPatternShader type definition ------------------------------*/
+
+PyTypeObject ThicknessVariationPatternShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ThicknessVariationPatternShader", /* tp_name */
+ sizeof(BPy_ThicknessVariationPatternShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ThicknessVariationPatternShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ThicknessVariationPatternShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.h
new file mode 100644
index 00000000000..302c9e005ae
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_THICKNESSVARIATIONPATTERNSHADER_H
+#define FREESTYLE_PYTHON_THICKNESSVARIATIONPATTERNSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ThicknessVariationPatternShader_Type;
+
+#define BPy_ThicknessVariationPatternShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ThicknessVariationPatternShader_Type) )
+
+/*---------------------------Python BPy_ThicknessVariationPatternShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_ThicknessVariationPatternShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_THICKNESSVARIATIONPATTERNSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_TipRemoverShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_TipRemoverShader.cpp
new file mode 100644
index 00000000000..8241a03892c
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_TipRemoverShader.cpp
@@ -0,0 +1,91 @@
+#include "BPy_TipRemoverShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char TipRemoverShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`TipRemoverShader`\n"
+"\n"
+"[Geometry shader]\n"
+"\n"
+".. method:: __init__(tipLength)\n"
+"\n"
+" Builds a TipRemoverShader object.\n"
+"\n"
+" :arg tipLength: The length of the piece of stroke we want to remove\n"
+" at each extremity.\n"
+" :type tipLength: float\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Removes the stroke's extremities.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int TipRemoverShader___init__( BPy_TipRemoverShader* self, PyObject *args)
+{
+ double d;
+
+ if(!( PyArg_ParseTuple(args, "d", &d) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::TipRemoverShader(d);
+ return 0;
+}
+
+/*-----------------------BPy_TipRemoverShader type definition ------------------------------*/
+
+PyTypeObject TipRemoverShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "TipRemoverShader", /* tp_name */
+ sizeof(BPy_TipRemoverShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ TipRemoverShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)TipRemoverShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_TipRemoverShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_TipRemoverShader.h
new file mode 100644
index 00000000000..a1b2e3988bc
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_TipRemoverShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_TIPREMOVERSHADER_H
+#define FREESTYLE_PYTHON_TIPREMOVERSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject TipRemoverShader_Type;
+
+#define BPy_TipRemoverShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &TipRemoverShader_Type) )
+
+/*---------------------------Python BPy_TipRemoverShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_TipRemoverShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_TIPREMOVERSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.cpp
new file mode 100644
index 00000000000..2d9828c232c
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.cpp
@@ -0,0 +1,90 @@
+#include "BPy_fstreamShader.h"
+
+#include "../../stroke/AdvancedStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char fstreamShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`fstreamShader`\n"
+"\n"
+"[Output shader]\n"
+"\n"
+".. method:: __init__(iFileName)\n"
+"\n"
+" Builds a fstreamShader object.\n"
+"\n"
+" :arg iFileName: The output file name.\n"
+" :type iFileName: str\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Streams the Stroke in a file.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int fstreamShader___init__( BPy_fstreamShader* self, PyObject *args)
+{
+ const char *s;
+
+ if(!( PyArg_ParseTuple(args, "s", &s) ))
+ return -1;
+
+ self->py_ss.ss = new StrokeShaders::fstreamShader(s);
+ return 0;
+}
+
+/*-----------------------BPy_fstreamShader type definition ------------------------------*/
+
+PyTypeObject fstreamShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "fstreamShader", /* tp_name */
+ sizeof(BPy_fstreamShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ fstreamShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)fstreamShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.h
new file mode 100644
index 00000000000..843d50505db
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_FSTREAMSHADER_H
+#define FREESTYLE_PYTHON_FSTREAMSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject fstreamShader_Type;
+
+#define BPy_fstreamShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &fstreamShader_Type) )
+
+/*---------------------------Python BPy_fstreamShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_fstreamShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_FSTREAMSHADER_H */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.cpp
new file mode 100644
index 00000000000..722c51c440e
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.cpp
@@ -0,0 +1,84 @@
+#include "BPy_streamShader.h"
+
+#include "../../stroke/BasicStrokeShaders.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char streamShader___doc__[] =
+"Class hierarchy: :class:`StrokeShader` > :class:`streamShader`\n"
+"\n"
+"[Output shader]\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a streamShader object.\n"
+"\n"
+".. method:: shade(s)\n"
+"\n"
+" Streams the Stroke into stdout.\n"
+"\n"
+" :arg s: A Stroke object.\n"
+" :type s: :class:`Stroke`\n";
+
+static int streamShader___init__( BPy_streamShader* self, PyObject *args)
+{
+ if(!( PyArg_ParseTuple(args, "") ))
+ return -1;
+ self->py_ss.ss = new StrokeShaders::streamShader();
+ return 0;
+}
+
+/*-----------------------BPy_streamShader type definition ------------------------------*/
+
+PyTypeObject streamShader_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "streamShader", /* tp_name */
+ sizeof(BPy_streamShader), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ streamShader___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &StrokeShader_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)streamShader___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.h
new file mode 100644
index 00000000000..38056d5fa59
--- /dev/null
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.h
@@ -0,0 +1,31 @@
+#ifndef FREESTYLE_PYTHON_STREAMSHADER_H
+#define FREESTYLE_PYTHON_STREAMSHADER_H
+
+#include "../BPy_StrokeShader.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject streamShader_Type;
+
+#define BPy_streamShader_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &streamShader_Type) )
+
+/*---------------------------Python BPy_streamShader structure definition----------*/
+typedef struct {
+ BPy_StrokeShader py_ss;
+} BPy_streamShader;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* FREESTYLE_PYTHON_STREAMSHADER_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DDouble.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DDouble.cpp
new file mode 100644
index 00000000000..b61b9baf033
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DDouble.cpp
@@ -0,0 +1,215 @@
+#include "BPy_UnaryFunction0DDouble.h"
+
+#include "../BPy_Convert.h"
+#include "../Iterator/BPy_Interface0DIterator.h"
+
+#include "UnaryFunction0D_double/BPy_Curvature2DAngleF0D.h"
+#include "UnaryFunction0D_double/BPy_DensityF0D.h"
+#include "UnaryFunction0D_double/BPy_GetProjectedXF0D.h"
+#include "UnaryFunction0D_double/BPy_GetProjectedYF0D.h"
+#include "UnaryFunction0D_double/BPy_GetProjectedZF0D.h"
+#include "UnaryFunction0D_double/BPy_GetXF0D.h"
+#include "UnaryFunction0D_double/BPy_GetYF0D.h"
+#include "UnaryFunction0D_double/BPy_GetZF0D.h"
+#include "UnaryFunction0D_double/BPy_LocalAverageDepthF0D.h"
+#include "UnaryFunction0D_double/BPy_ZDiscontinuityF0D.h"
+
+#include "../Director.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction0DDouble_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction0DDouble_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction0DDouble_Type );
+ PyModule_AddObject(module, "UnaryFunction0DDouble", (PyObject *)&UnaryFunction0DDouble_Type);
+
+ if( PyType_Ready( &DensityF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &DensityF0D_Type );
+ PyModule_AddObject(module, "DensityF0D", (PyObject *)&DensityF0D_Type);
+
+ if( PyType_Ready( &LocalAverageDepthF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &LocalAverageDepthF0D_Type );
+ PyModule_AddObject(module, "LocalAverageDepthF0D", (PyObject *)&LocalAverageDepthF0D_Type);
+
+ if( PyType_Ready( &Curvature2DAngleF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Curvature2DAngleF0D_Type );
+ PyModule_AddObject(module, "Curvature2DAngleF0D", (PyObject *)&Curvature2DAngleF0D_Type);
+
+ if( PyType_Ready( &GetProjectedXF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetProjectedXF0D_Type );
+ PyModule_AddObject(module, "GetProjectedXF0D", (PyObject *)&GetProjectedXF0D_Type);
+
+ if( PyType_Ready( &GetProjectedYF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetProjectedYF0D_Type );
+ PyModule_AddObject(module, "GetProjectedYF0D", (PyObject *)&GetProjectedYF0D_Type);
+
+ if( PyType_Ready( &GetProjectedZF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetProjectedZF0D_Type );
+ PyModule_AddObject(module, "GetProjectedZF0D", (PyObject *)&GetProjectedZF0D_Type);
+
+ if( PyType_Ready( &GetXF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetXF0D_Type );
+ PyModule_AddObject(module, "GetXF0D", (PyObject *)&GetXF0D_Type);
+
+ if( PyType_Ready( &GetYF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetYF0D_Type );
+ PyModule_AddObject(module, "GetYF0D", (PyObject *)&GetYF0D_Type);
+
+ if( PyType_Ready( &GetZF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetZF0D_Type );
+ PyModule_AddObject(module, "GetZF0D", (PyObject *)&GetZF0D_Type);
+
+ if( PyType_Ready( &ZDiscontinuityF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ZDiscontinuityF0D_Type );
+ PyModule_AddObject(module, "ZDiscontinuityF0D", (PyObject *)&ZDiscontinuityF0D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction0DDouble___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface0DIterator` and return a float value.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n";
+
+static int UnaryFunction0DDouble___init__(BPy_UnaryFunction0DDouble* self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->uf0D_double = new UnaryFunction0D<double>();
+ self->uf0D_double->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+static void UnaryFunction0DDouble___dealloc__(BPy_UnaryFunction0DDouble* self)
+{
+ if (self->uf0D_double)
+ delete self->uf0D_double;
+ UnaryFunction0D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction0DDouble___repr__(BPy_UnaryFunction0DDouble* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf0D_double->getName().c_str(), self->uf0D_double );
+}
+
+static char UnaryFunction0DDouble_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 0D predicate.\n"
+"\n"
+" :return: The name of the unary 0D predicate.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction0DDouble_getName( BPy_UnaryFunction0DDouble *self )
+{
+ return PyUnicode_FromString( self->uf0D_double->getName().c_str() );
+}
+
+static PyObject * UnaryFunction0DDouble___call__( BPy_UnaryFunction0DDouble *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if(!PyArg_ParseTuple(args, "O!", &Interface0DIterator_Type, &obj))
+ return NULL;
+
+ if( typeid(*(self->uf0D_double)) == typeid(UnaryFunction0D<double>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf0D_double->operator()(*( ((BPy_Interface0DIterator *) obj)->if0D_it)) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf0D_double->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return PyFloat_FromDouble( self->uf0D_double->result );
+
+}
+
+/*----------------------UnaryFunction0DDouble instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction0DDouble_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction0DDouble_getName, METH_NOARGS, UnaryFunction0DDouble_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction0DDouble type definition ------------------------------*/
+
+PyTypeObject UnaryFunction0DDouble_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction0DDouble", /* tp_name */
+ sizeof(BPy_UnaryFunction0DDouble), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction0DDouble___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction0DDouble___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction0DDouble___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction0DDouble___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction0DDouble_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction0DDouble___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DDouble.h b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DDouble.h
new file mode 100644
index 00000000000..dbeb70cc082
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DDouble.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION0DDOUBLE_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION0DDOUBLE_H
+
+#include "../BPy_UnaryFunction0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction0DDouble_Type;
+
+#define BPy_UnaryFunction0DDouble_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction0DDouble_Type) )
+
+/*---------------------------Python BPy_UnaryFunction0DDouble structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0D py_uf0D;
+ UnaryFunction0D<double> *uf0D_double;
+} BPy_UnaryFunction0DDouble;
+
+/*---------------------------Python BPy_UnaryFunction0DDouble visible prototypes-----------*/
+int UnaryFunction0DDouble_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION0DDOUBLE_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DEdgeNature.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DEdgeNature.cpp
new file mode 100644
index 00000000000..a5ecd46b3bd
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DEdgeNature.cpp
@@ -0,0 +1,159 @@
+#include "BPy_UnaryFunction0DEdgeNature.h"
+
+#include "../BPy_Convert.h"
+#include "../Iterator/BPy_Interface0DIterator.h"
+
+#include "UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction0DEdgeNature_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction0DEdgeNature_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction0DEdgeNature_Type );
+ PyModule_AddObject(module, "UnaryFunction0DEdgeNature", (PyObject *)&UnaryFunction0DEdgeNature_Type);
+
+ if( PyType_Ready( &CurveNatureF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &CurveNatureF0D_Type );
+ PyModule_AddObject(module, "CurveNatureF0D", (PyObject *)&CurveNatureF0D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction0DEdgeNature___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DEdgeNature`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface0DIterator` and return a :class:`Nature` object.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n";
+
+static int UnaryFunction0DEdgeNature___init__(BPy_UnaryFunction0DEdgeNature* self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->uf0D_edgenature = new UnaryFunction0D<Nature::EdgeNature>();
+ self->uf0D_edgenature->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+static void UnaryFunction0DEdgeNature___dealloc__(BPy_UnaryFunction0DEdgeNature* self)
+{
+ if (self->uf0D_edgenature)
+ delete self->uf0D_edgenature;
+ UnaryFunction0D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction0DEdgeNature___repr__(BPy_UnaryFunction0DEdgeNature* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf0D_edgenature->getName().c_str(), self->uf0D_edgenature );
+}
+
+static char UnaryFunction0DEdgeNature_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 0D predicate.\n"
+"\n"
+" :return: The name of the unary 0D predicate.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction0DEdgeNature_getName( BPy_UnaryFunction0DEdgeNature *self )
+{
+ return PyUnicode_FromString( self->uf0D_edgenature->getName().c_str() );
+}
+
+static PyObject * UnaryFunction0DEdgeNature___call__( BPy_UnaryFunction0DEdgeNature *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if(!PyArg_ParseTuple(args, "O!", &Interface0DIterator_Type, &obj))
+ return NULL;
+
+ if( typeid(*(self->uf0D_edgenature)) == typeid(UnaryFunction0D<Nature::EdgeNature>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf0D_edgenature->operator()(*( ((BPy_Interface0DIterator *) obj)->if0D_it )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf0D_edgenature->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return BPy_Nature_from_Nature( self->uf0D_edgenature->result );
+
+}
+
+/*----------------------UnaryFunction0DEdgeNature instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction0DEdgeNature_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction0DEdgeNature_getName, METH_NOARGS, UnaryFunction0DEdgeNature_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction0DEdgeNature type definition ------------------------------*/
+
+PyTypeObject UnaryFunction0DEdgeNature_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction0DEdgeNature", /* tp_name */
+ sizeof(BPy_UnaryFunction0DEdgeNature), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction0DEdgeNature___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction0DEdgeNature___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction0DEdgeNature___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction0DEdgeNature___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction0DEdgeNature_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction0DEdgeNature___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DEdgeNature.h b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DEdgeNature.h
new file mode 100644
index 00000000000..d6959cae57f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DEdgeNature.h
@@ -0,0 +1,36 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION0DEDGENATURE_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION0DEDGENATURE_H
+
+#include "../BPy_UnaryFunction0D.h"
+
+#include "../../winged_edge/Nature.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction0DEdgeNature_Type;
+
+#define BPy_UnaryFunction0DEdgeNature_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction0DEdgeNature_Type) )
+
+/*---------------------------Python BPy_UnaryFunction0DEdgeNature structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0D py_uf0D;
+ UnaryFunction0D<Nature::EdgeNature> *uf0D_edgenature;
+} BPy_UnaryFunction0DEdgeNature;
+
+/*---------------------------Python BPy_UnaryFunction0DEdgeNature visible prototypes-----------*/
+int UnaryFunction0DEdgeNature_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION0DEDGENATURE_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DFloat.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DFloat.cpp
new file mode 100644
index 00000000000..72ca2acf3b7
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DFloat.cpp
@@ -0,0 +1,189 @@
+#include "BPy_UnaryFunction0DFloat.h"
+
+#include "../BPy_Convert.h"
+#include "../Iterator/BPy_Interface0DIterator.h"
+
+#include "UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.h"
+#include "UnaryFunction0D_float/BPy_GetParameterF0D.h"
+#include "UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.h"
+#include "UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.h"
+#include "UnaryFunction0D_float/BPy_ReadMapPixelF0D.h"
+#include "UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction0DFloat_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction0DFloat_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction0DFloat_Type );
+ PyModule_AddObject(module, "UnaryFunction0DFloat", (PyObject *)&UnaryFunction0DFloat_Type);
+
+ if( PyType_Ready( &GetCurvilinearAbscissaF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetCurvilinearAbscissaF0D_Type );
+ PyModule_AddObject(module, "GetCurvilinearAbscissaF0D", (PyObject *)&GetCurvilinearAbscissaF0D_Type);
+
+ if( PyType_Ready( &GetParameterF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetParameterF0D_Type );
+ PyModule_AddObject(module, "GetParameterF0D", (PyObject *)&GetParameterF0D_Type);
+
+ if( PyType_Ready( &GetViewMapGradientNormF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetViewMapGradientNormF0D_Type );
+ PyModule_AddObject(module, "GetViewMapGradientNormF0D", (PyObject *)&GetViewMapGradientNormF0D_Type);
+
+ if( PyType_Ready( &ReadCompleteViewMapPixelF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ReadCompleteViewMapPixelF0D_Type );
+ PyModule_AddObject(module, "ReadCompleteViewMapPixelF0D", (PyObject *)&ReadCompleteViewMapPixelF0D_Type);
+
+ if( PyType_Ready( &ReadMapPixelF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ReadMapPixelF0D_Type );
+ PyModule_AddObject(module, "ReadMapPixelF0D", (PyObject *)&ReadMapPixelF0D_Type);
+
+ if( PyType_Ready( &ReadSteerableViewMapPixelF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ReadSteerableViewMapPixelF0D_Type );
+ PyModule_AddObject(module, "ReadSteerableViewMapPixelF0D", (PyObject *)&ReadSteerableViewMapPixelF0D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction0DFloat___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DFloat`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface0DIterator` and return a float value.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n";
+
+static int UnaryFunction0DFloat___init__(BPy_UnaryFunction0DFloat* self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->uf0D_float = new UnaryFunction0D<float>();
+ self->uf0D_float->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+static void UnaryFunction0DFloat___dealloc__(BPy_UnaryFunction0DFloat* self)
+{
+ if (self->uf0D_float)
+ delete self->uf0D_float;
+ UnaryFunction0D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction0DFloat___repr__(BPy_UnaryFunction0DFloat* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf0D_float->getName().c_str(), self->uf0D_float );
+}
+
+static char UnaryFunction0DFloat_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 0D predicate.\n"
+"\n"
+" :return: The name of the unary 0D predicate.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction0DFloat_getName( BPy_UnaryFunction0DFloat *self )
+{
+ return PyUnicode_FromString( self->uf0D_float->getName().c_str() );
+}
+
+static PyObject * UnaryFunction0DFloat___call__( BPy_UnaryFunction0DFloat *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if(!PyArg_ParseTuple(args, "O!", &Interface0DIterator_Type, &obj))
+ return NULL;
+
+ if( typeid(*(self->uf0D_float)) == typeid(UnaryFunction0D<float>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf0D_float->operator()(*( ((BPy_Interface0DIterator *) obj)->if0D_it )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf0D_float->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return PyFloat_FromDouble( self->uf0D_float->result );
+
+}
+
+/*----------------------UnaryFunction0DFloat instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction0DFloat_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction0DFloat_getName, METH_NOARGS, UnaryFunction0DFloat_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction0DFloat type definition ------------------------------*/
+
+PyTypeObject UnaryFunction0DFloat_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction0DFloat", /* tp_name */
+ sizeof(BPy_UnaryFunction0DFloat), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction0DFloat___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction0DFloat___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction0DFloat___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction0DFloat___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction0DFloat_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction0DFloat___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DFloat.h b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DFloat.h
new file mode 100644
index 00000000000..fbf207d48c7
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DFloat.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION0DFLOAT_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION0DFLOAT_H
+
+#include "../BPy_UnaryFunction0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction0DFloat_Type;
+
+#define BPy_UnaryFunction0DFloat_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction0DFloat_Type) )
+
+/*---------------------------Python BPy_UnaryFunction0DFloat structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0D py_uf0D;
+ UnaryFunction0D<float> *uf0D_float;
+} BPy_UnaryFunction0DFloat;
+
+/*---------------------------Python BPy_UnaryFunction0DFloat visible prototypes-----------*/
+int UnaryFunction0DFloat_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION0DFLOAT_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DId.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DId.cpp
new file mode 100644
index 00000000000..3c4ccdbcbf1
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DId.cpp
@@ -0,0 +1,158 @@
+#include "BPy_UnaryFunction0DId.h"
+
+#include "../BPy_Convert.h"
+#include "../Iterator/BPy_Interface0DIterator.h"
+
+#include "UnaryFunction0D_Id/BPy_ShapeIdF0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction0DId_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction0DId_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction0DId_Type );
+ PyModule_AddObject(module, "UnaryFunction0DId", (PyObject *)&UnaryFunction0DId_Type);
+
+ if( PyType_Ready( &ShapeIdF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ShapeIdF0D_Type );
+ PyModule_AddObject(module, "ShapeIdF0D", (PyObject *)&ShapeIdF0D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction0DId___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DId`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface0DIterator` and return an :class:`Id` object.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n";
+
+static int UnaryFunction0DId___init__(BPy_UnaryFunction0DId* self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->uf0D_id = new UnaryFunction0D<Id>();
+ self->uf0D_id->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+static void UnaryFunction0DId___dealloc__(BPy_UnaryFunction0DId* self)
+{
+ if (self->uf0D_id)
+ delete self->uf0D_id;
+ UnaryFunction0D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction0DId___repr__(BPy_UnaryFunction0DId* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf0D_id->getName().c_str(), self->uf0D_id );
+}
+
+static char UnaryFunction0DId_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 0D predicate.\n"
+"\n"
+" :return: The name of the unary 0D predicate.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction0DId_getName( BPy_UnaryFunction0DId *self )
+{
+ return PyUnicode_FromString( self->uf0D_id->getName().c_str() );
+}
+
+static PyObject * UnaryFunction0DId___call__( BPy_UnaryFunction0DId *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if(!PyArg_ParseTuple(args, "O!", &Interface0DIterator_Type, &obj))
+ return NULL;
+
+ if( typeid(*(self->uf0D_id)) == typeid(UnaryFunction0D<Id>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf0D_id->operator()(*( ((BPy_Interface0DIterator *) obj)->if0D_it )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf0D_id->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return BPy_Id_from_Id( self->uf0D_id->result );
+}
+
+/*----------------------UnaryFunction0DId instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction0DId_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction0DId_getName, METH_NOARGS, UnaryFunction0DId_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction0DId type definition ------------------------------*/
+
+PyTypeObject UnaryFunction0DId_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction0DId", /* tp_name */
+ sizeof(BPy_UnaryFunction0DId), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction0DId___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction0DId___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction0DId___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction0DId___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction0DId_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction0DId___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DId.h b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DId.h
new file mode 100644
index 00000000000..159e24e2674
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DId.h
@@ -0,0 +1,36 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION0DID_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION0DID_H
+
+#include "../BPy_UnaryFunction0D.h"
+
+#include "../../system/Id.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction0DId_Type;
+
+#define BPy_UnaryFunction0DId_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction0DId_Type) )
+
+/*---------------------------Python BPy_UnaryFunction0DId structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0D py_uf0D;
+ UnaryFunction0D<Id> *uf0D_id;
+} BPy_UnaryFunction0DId;
+
+/*---------------------------Python BPy_UnaryFunction0DId visible prototypes-----------*/
+int UnaryFunction0DId_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION0DID_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DMaterial.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DMaterial.cpp
new file mode 100644
index 00000000000..d61453172b9
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DMaterial.cpp
@@ -0,0 +1,160 @@
+#include "BPy_UnaryFunction0DMaterial.h"
+
+#include "../BPy_Convert.h"
+#include "../Iterator/BPy_Interface0DIterator.h"
+
+#include "UnaryFunction0D_Material/BPy_MaterialF0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction0DMaterial_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction0DMaterial_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction0DMaterial_Type );
+ PyModule_AddObject(module, "UnaryFunction0DMaterial", (PyObject *)&UnaryFunction0DMaterial_Type);
+
+ if( PyType_Ready( &MaterialF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &MaterialF0D_Type );
+ PyModule_AddObject(module, "MaterialF0D", (PyObject *)&MaterialF0D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction0DMaterial___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DMaterial`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface0DIterator` and return a :class:`Material` object.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n";
+
+static int UnaryFunction0DMaterial___init__(BPy_UnaryFunction0DMaterial* self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->uf0D_material = new UnaryFunction0D<FrsMaterial>();
+ self->uf0D_material->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+static void UnaryFunction0DMaterial___dealloc__(BPy_UnaryFunction0DMaterial* self)
+{
+ if (self->uf0D_material)
+ delete self->uf0D_material;
+ UnaryFunction0D_Type.tp_dealloc((PyObject*)self);
+}
+
+
+static PyObject * UnaryFunction0DMaterial___repr__(BPy_UnaryFunction0DMaterial* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf0D_material->getName().c_str(), self->uf0D_material );
+}
+
+static char UnaryFunction0DMaterial_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 0D predicate.\n"
+"\n"
+" :return: The name of the unary 0D predicate.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction0DMaterial_getName( BPy_UnaryFunction0DMaterial *self )
+{
+ return PyUnicode_FromString( self->uf0D_material->getName().c_str() );
+}
+
+static PyObject * UnaryFunction0DMaterial___call__( BPy_UnaryFunction0DMaterial *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if(!PyArg_ParseTuple(args, "O!", &Interface0DIterator_Type, &obj))
+ return NULL;
+
+ if( typeid(*(self->uf0D_material)) == typeid(UnaryFunction0D<FrsMaterial>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf0D_material->operator()(*( ((BPy_Interface0DIterator *) obj)->if0D_it )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf0D_material->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return BPy_FrsMaterial_from_FrsMaterial( self->uf0D_material->result );
+
+}
+
+/*----------------------UnaryFunction0DMaterial instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction0DMaterial_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction0DMaterial_getName, METH_NOARGS, UnaryFunction0DMaterial_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction0DMaterial type definition ------------------------------*/
+
+PyTypeObject UnaryFunction0DMaterial_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction0DMaterial", /* tp_name */
+ sizeof(BPy_UnaryFunction0DMaterial), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction0DMaterial___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction0DMaterial___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction0DMaterial___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction0DMaterial___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction0DMaterial_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction0DMaterial___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DMaterial.h b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DMaterial.h
new file mode 100644
index 00000000000..02fb2b99ccd
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DMaterial.h
@@ -0,0 +1,36 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION0DMATERIAL_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION0DMATERIAL_H
+
+#include "../BPy_UnaryFunction0D.h"
+
+#include "../../scene_graph/FrsMaterial.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction0DMaterial_Type;
+
+#define BPy_UnaryFunction0DMaterial_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction0DMaterial_Type) )
+
+/*---------------------------Python BPy_UnaryFunction0DMaterial structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0D py_uf0D;
+ UnaryFunction0D<FrsMaterial> *uf0D_material;
+} BPy_UnaryFunction0DMaterial;
+
+/*---------------------------Python BPy_UnaryFunction0DMaterial visible prototypes-----------*/
+int UnaryFunction0DMaterial_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION0DMATERIAL_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.cpp
new file mode 100644
index 00000000000..37f6a2ab342
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.cpp
@@ -0,0 +1,159 @@
+#include "BPy_UnaryFunction0DUnsigned.h"
+
+#include "../BPy_Convert.h"
+#include "../Iterator/BPy_Interface0DIterator.h"
+
+#include "UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction0DUnsigned_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction0DUnsigned_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction0DUnsigned_Type );
+ PyModule_AddObject(module, "UnaryFunction0DUnsigned", (PyObject *)&UnaryFunction0DUnsigned_Type);
+
+ if( PyType_Ready( &QuantitativeInvisibilityF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &QuantitativeInvisibilityF0D_Type );
+ PyModule_AddObject(module, "QuantitativeInvisibilityF0D", (PyObject *)&QuantitativeInvisibilityF0D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction0DUnsigned___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DUnsigned`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface0DIterator` and return an int value.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+ " Default constructor.\n";
+
+static int UnaryFunction0DUnsigned___init__(BPy_UnaryFunction0DUnsigned* self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->uf0D_unsigned = new UnaryFunction0D<unsigned int>();
+ self->uf0D_unsigned->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+static void UnaryFunction0DUnsigned___dealloc__(BPy_UnaryFunction0DUnsigned* self)
+{
+ if (self->uf0D_unsigned)
+ delete self->uf0D_unsigned;
+ UnaryFunction0D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction0DUnsigned___repr__(BPy_UnaryFunction0DUnsigned* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf0D_unsigned->getName().c_str(), self->uf0D_unsigned );
+}
+
+static char UnaryFunction0DUnsigned_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 0D predicate.\n"
+"\n"
+" :return: The name of the unary 0D predicate.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction0DUnsigned_getName( BPy_UnaryFunction0DUnsigned *self )
+{
+ return PyUnicode_FromString( self->uf0D_unsigned->getName().c_str() );
+}
+
+static PyObject * UnaryFunction0DUnsigned___call__( BPy_UnaryFunction0DUnsigned *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if(!PyArg_ParseTuple(args, "O!", &Interface0DIterator_Type, &obj))
+ return NULL;
+
+ if( typeid(*(self->uf0D_unsigned)) == typeid(UnaryFunction0D<unsigned int>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf0D_unsigned->operator()(*( ((BPy_Interface0DIterator *) obj)->if0D_it )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf0D_unsigned->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return PyLong_FromLong( self->uf0D_unsigned->result );
+
+}
+
+/*----------------------UnaryFunction0DUnsigned instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction0DUnsigned_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction0DUnsigned_getName, METH_NOARGS, UnaryFunction0DUnsigned_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction0DUnsigned type definition ------------------------------*/
+
+PyTypeObject UnaryFunction0DUnsigned_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction0DUnsigned", /* tp_name */
+ sizeof(BPy_UnaryFunction0DUnsigned), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction0DUnsigned___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction0DUnsigned___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction0DUnsigned___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction0DUnsigned___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction0DUnsigned_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction0DUnsigned___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.h b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.h
new file mode 100644
index 00000000000..4776ce30918
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION0DUNSIGNED_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION0DUNSIGNED_H
+
+#include "../BPy_UnaryFunction0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction0DUnsigned_Type;
+
+#define BPy_UnaryFunction0DUnsigned_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction0DUnsigned_Type) )
+
+/*---------------------------Python BPy_UnaryFunction0DUnsigned structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0D py_uf0D;
+ UnaryFunction0D<unsigned int> *uf0D_unsigned;
+} BPy_UnaryFunction0DUnsigned;
+
+/*---------------------------Python BPy_UnaryFunction0DUnsigned visible prototypes-----------*/
+int UnaryFunction0DUnsigned_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION0DUNSIGNED_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec2f.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec2f.cpp
new file mode 100644
index 00000000000..9c9e2e85568
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec2f.cpp
@@ -0,0 +1,165 @@
+#include "BPy_UnaryFunction0DVec2f.h"
+
+#include "../BPy_Convert.h"
+#include "../Iterator/BPy_Interface0DIterator.h"
+
+#include "UnaryFunction0D_Vec2f/BPy_Normal2DF0D.h"
+#include "UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction0DVec2f_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction0DVec2f_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction0DVec2f_Type );
+ PyModule_AddObject(module, "UnaryFunction0DVec2f", (PyObject *)&UnaryFunction0DVec2f_Type);
+
+ if( PyType_Ready( &Normal2DF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Normal2DF0D_Type );
+ PyModule_AddObject(module, "Normal2DF0D", (PyObject *)&Normal2DF0D_Type);
+
+ if( PyType_Ready( &VertexOrientation2DF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &VertexOrientation2DF0D_Type );
+ PyModule_AddObject(module, "VertexOrientation2DF0D", (PyObject *)&VertexOrientation2DF0D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction0DVec2f___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DVec2f`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface0DIterator` and return a 2D vector.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n";
+
+static int UnaryFunction0DVec2f___init__(BPy_UnaryFunction0DVec2f* self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->uf0D_vec2f = new UnaryFunction0D<Vec2f>();
+ self->uf0D_vec2f->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+static void UnaryFunction0DVec2f___dealloc__(BPy_UnaryFunction0DVec2f* self)
+{
+ if (self->uf0D_vec2f)
+ delete self->uf0D_vec2f;
+ UnaryFunction0D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction0DVec2f___repr__(BPy_UnaryFunction0DVec2f* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf0D_vec2f->getName().c_str(), self->uf0D_vec2f );
+}
+
+static char UnaryFunction0DVec2f_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 0D predicate.\n"
+"\n"
+" :return: The name of the unary 0D predicate.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction0DVec2f_getName( BPy_UnaryFunction0DVec2f *self )
+{
+ return PyUnicode_FromString( self->uf0D_vec2f->getName().c_str() );
+}
+
+static PyObject * UnaryFunction0DVec2f___call__( BPy_UnaryFunction0DVec2f *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if(!PyArg_ParseTuple(args, "O!", &Interface0DIterator_Type, &obj))
+ return NULL;
+
+ if( typeid(*(self->uf0D_vec2f)) == typeid(UnaryFunction0D<Vec2f>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf0D_vec2f->operator()(*( ((BPy_Interface0DIterator *) obj)->if0D_it )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf0D_vec2f->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return Vector_from_Vec2f( self->uf0D_vec2f->result );
+
+}
+
+/*----------------------UnaryFunction0DVec2f instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction0DVec2f_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction0DVec2f_getName, METH_NOARGS, UnaryFunction0DVec2f_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction0DVec2f type definition ------------------------------*/
+
+PyTypeObject UnaryFunction0DVec2f_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction0DVec2f", /* tp_name */
+ sizeof(BPy_UnaryFunction0DVec2f), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction0DVec2f___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction0DVec2f___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction0DVec2f___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction0DVec2f___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction0DVec2f_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction0DVec2f___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec2f.h b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec2f.h
new file mode 100644
index 00000000000..6628d629a41
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec2f.h
@@ -0,0 +1,37 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION0DVEC2F_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION0DVEC2F_H
+
+#include "../BPy_UnaryFunction0D.h"
+
+#include "../../geometry/Geom.h"
+using namespace Geometry;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction0DVec2f_Type;
+
+#define BPy_UnaryFunction0DVec2f_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction0DVec2f_Type) )
+
+/*---------------------------Python BPy_UnaryFunction0DVec2f structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0D py_uf0D;
+ UnaryFunction0D<Vec2f> *uf0D_vec2f;
+} BPy_UnaryFunction0DVec2f;
+
+/*---------------------------Python BPy_UnaryFunction0DVec2f visible prototypes-----------*/
+int UnaryFunction0DVec2f_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION0DVEC2F_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec3f.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec3f.cpp
new file mode 100644
index 00000000000..13f8dd69fa1
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec3f.cpp
@@ -0,0 +1,159 @@
+#include "BPy_UnaryFunction0DVec3f.h"
+
+#include "../BPy_Convert.h"
+#include "../Iterator/BPy_Interface0DIterator.h"
+
+#include "UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction0DVec3f_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction0DVec3f_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction0DVec3f_Type );
+ PyModule_AddObject(module, "UnaryFunction0DVec3f", (PyObject *)&UnaryFunction0DVec3f_Type);
+
+ if( PyType_Ready( &VertexOrientation3DF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &VertexOrientation3DF0D_Type );
+ PyModule_AddObject(module, "VertexOrientation3DF0D", (PyObject *)&VertexOrientation3DF0D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction0DVec3f___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DVec3f`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface0DIterator` and return a 3D vector.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n";
+
+static int UnaryFunction0DVec3f___init__(BPy_UnaryFunction0DVec3f* self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->uf0D_vec3f = new UnaryFunction0D<Vec3f>();
+ self->uf0D_vec3f->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+static void UnaryFunction0DVec3f___dealloc__(BPy_UnaryFunction0DVec3f* self)
+{
+ if (self->uf0D_vec3f)
+ delete self->uf0D_vec3f;
+ UnaryFunction0D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction0DVec3f___repr__(BPy_UnaryFunction0DVec3f* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf0D_vec3f->getName().c_str(), self->uf0D_vec3f );
+}
+
+static char UnaryFunction0DVec3f_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 0D predicate.\n"
+"\n"
+" :return: The name of the unary 0D predicate.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction0DVec3f_getName( BPy_UnaryFunction0DVec3f *self )
+{
+ return PyUnicode_FromString( self->uf0D_vec3f->getName().c_str() );
+}
+
+static PyObject * UnaryFunction0DVec3f___call__( BPy_UnaryFunction0DVec3f *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if(!PyArg_ParseTuple(args, "O!", &Interface0DIterator_Type, &obj))
+ return NULL;
+
+ if( typeid(*(self->uf0D_vec3f)) == typeid(UnaryFunction0D<Vec3f>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf0D_vec3f->operator()(*( ((BPy_Interface0DIterator *) obj)->if0D_it )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf0D_vec3f->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return Vector_from_Vec3f( self->uf0D_vec3f->result );
+
+}
+
+/*----------------------UnaryFunction0DVec3f instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction0DVec3f_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction0DVec3f_getName, METH_NOARGS, UnaryFunction0DVec3f_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction0DVec3f type definition ------------------------------*/
+
+PyTypeObject UnaryFunction0DVec3f_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction0DVec3f", /* tp_name */
+ sizeof(BPy_UnaryFunction0DVec3f), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction0DVec3f___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction0DVec3f___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction0DVec3f___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction0DVec3f___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction0DVec3f_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction0DVec3f___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec3f.h b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec3f.h
new file mode 100644
index 00000000000..47ec89fb179
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec3f.h
@@ -0,0 +1,37 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION0DVEC3F_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION0DVEC3F_H
+
+#include "../BPy_UnaryFunction0D.h"
+
+#include "../../geometry/Geom.h"
+using namespace Geometry;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction0DVec3f_Type;
+
+#define BPy_UnaryFunction0DVec3f_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction0DVec3f_Type) )
+
+/*---------------------------Python BPy_UnaryFunction0DVec3f structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0D py_uf0D;
+ UnaryFunction0D<Vec3f> *uf0D_vec3f;
+} BPy_UnaryFunction0DVec3f;
+
+/*---------------------------Python BPy_UnaryFunction0DVec3f visible prototypes-----------*/
+int UnaryFunction0DVec3f_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION0DVEC3F_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp
new file mode 100644
index 00000000000..40564b018d6
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp
@@ -0,0 +1,172 @@
+#include "BPy_UnaryFunction0DVectorViewShape.h"
+
+#include "../BPy_Convert.h"
+#include "../Iterator/BPy_Interface0DIterator.h"
+
+#include "UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction0DVectorViewShape_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction0DVectorViewShape_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction0DVectorViewShape_Type );
+ PyModule_AddObject(module, "UnaryFunction0DVectorViewShape", (PyObject *)&UnaryFunction0DVectorViewShape_Type);
+
+ if( PyType_Ready( &GetOccludersF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetOccludersF0D_Type );
+ PyModule_AddObject(module, "GetOccludersF0D", (PyObject *)&GetOccludersF0D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction0DVectorViewShape___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DVectorViewShape`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface0DIterator` and return a list of :class:`ViewShape`\n"
+"objects.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n";
+
+static int UnaryFunction0DVectorViewShape___init__(BPy_UnaryFunction0DVectorViewShape* self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->uf0D_vectorviewshape = new UnaryFunction0D< std::vector<ViewShape*> >();
+ self->uf0D_vectorviewshape->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+static void UnaryFunction0DVectorViewShape___dealloc__(BPy_UnaryFunction0DVectorViewShape* self)
+{
+ if (self->uf0D_vectorviewshape)
+ delete self->uf0D_vectorviewshape;
+ UnaryFunction0D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction0DVectorViewShape___repr__(BPy_UnaryFunction0DVectorViewShape* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf0D_vectorviewshape->getName().c_str(), self->uf0D_vectorviewshape );
+}
+
+static char UnaryFunction0DVectorViewShape_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 0D predicate.\n"
+"\n"
+" :return: The name of the unary 0D predicate.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction0DVectorViewShape_getName( BPy_UnaryFunction0DVectorViewShape *self )
+{
+ return PyUnicode_FromString( self->uf0D_vectorviewshape->getName().c_str() );
+}
+
+static PyObject * UnaryFunction0DVectorViewShape___call__( BPy_UnaryFunction0DVectorViewShape *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if(!PyArg_ParseTuple(args, "O!", &Interface0DIterator_Type, &obj))
+ return NULL;
+
+ if( typeid(*(self->uf0D_vectorviewshape)) == typeid(UnaryFunction0D< std::vector<ViewShape*> >) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf0D_vectorviewshape->operator()(*( ((BPy_Interface0DIterator *) obj)->if0D_it )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf0D_vectorviewshape->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ PyObject *list = PyList_New(0);
+ PyObject *item;
+ for( unsigned int i = 0; i < self->uf0D_vectorviewshape->result.size(); i++) {
+ ViewShape *v = self->uf0D_vectorviewshape->result[i];
+ if (v) {
+ item = BPy_ViewShape_from_ViewShape(*v);
+ } else {
+ item = Py_None;
+ Py_INCREF(item);
+ }
+ PyList_Append(list, item);
+ }
+
+ return list;
+}
+
+/*----------------------UnaryFunction0DVectorViewShape instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction0DVectorViewShape_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction0DVectorViewShape_getName, METH_NOARGS, UnaryFunction0DVectorViewShape_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction0DVectorViewShape type definition ------------------------------*/
+
+PyTypeObject UnaryFunction0DVectorViewShape_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction0DVectorViewShape", /* tp_name */
+ sizeof(BPy_UnaryFunction0DVectorViewShape), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction0DVectorViewShape___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction0DVectorViewShape___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction0DVectorViewShape___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction0DVectorViewShape___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction0DVectorViewShape_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction0DVectorViewShape___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.h b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.h
new file mode 100644
index 00000000000..77f96e96f20
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.h
@@ -0,0 +1,37 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION0DVECTORVIEWSHAPE_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION0DVECTORVIEWSHAPE_H
+
+#include "../BPy_UnaryFunction0D.h"
+
+#include <vector>
+#include "../../view_map/ViewMap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction0DVectorViewShape_Type;
+
+#define BPy_UnaryFunction0DVectorViewShape_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction0DVectorViewShape_Type) )
+
+/*---------------------------Python BPy_UnaryFunction0DVectorViewShape structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0D py_uf0D;
+ UnaryFunction0D< std::vector<ViewShape*> > *uf0D_vectorviewshape;
+} BPy_UnaryFunction0DVectorViewShape;
+
+/*---------------------------Python BPy_UnaryFunction0DVectorViewShape visible prototypes-----------*/
+int UnaryFunction0DVectorViewShape_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION0DVECTORVIEWSHAPE_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DViewShape.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DViewShape.cpp
new file mode 100644
index 00000000000..5f3f18453ba
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DViewShape.cpp
@@ -0,0 +1,165 @@
+#include "BPy_UnaryFunction0DViewShape.h"
+
+#include "../BPy_Convert.h"
+#include "../Iterator/BPy_Interface0DIterator.h"
+
+#include "UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.h"
+#include "UnaryFunction0D_ViewShape/BPy_GetShapeF0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction0DViewShape_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction0DViewShape_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction0DViewShape_Type );
+ PyModule_AddObject(module, "UnaryFunction0DViewShape", (PyObject *)&UnaryFunction0DViewShape_Type);
+
+ if( PyType_Ready( &GetOccludeeF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetOccludeeF0D_Type );
+ PyModule_AddObject(module, "GetOccludeeF0D", (PyObject *)&GetOccludeeF0D_Type);
+
+ if( PyType_Ready( &GetShapeF0D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetShapeF0D_Type );
+ PyModule_AddObject(module, "GetShapeF0D", (PyObject *)&GetShapeF0D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction0DViewShape___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DViewShape`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface0DIterator` and return a :class:`ViewShape` object.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n";
+
+static int UnaryFunction0DViewShape___init__(BPy_UnaryFunction0DViewShape* self, PyObject *args, PyObject *kwds)
+{
+ if ( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->uf0D_viewshape = new UnaryFunction0D<ViewShape*>();
+ self->uf0D_viewshape->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+static void UnaryFunction0DViewShape___dealloc__(BPy_UnaryFunction0DViewShape* self)
+{
+ if (self->uf0D_viewshape)
+ delete self->uf0D_viewshape;
+ UnaryFunction0D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction0DViewShape___repr__(BPy_UnaryFunction0DViewShape* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf0D_viewshape->getName().c_str(), self->uf0D_viewshape );
+}
+
+static char UnaryFunction0DViewShape_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 0D predicate.\n"
+"\n"
+" :return: The name of the unary 0D predicate.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction0DViewShape_getName( BPy_UnaryFunction0DViewShape *self )
+{
+ return PyUnicode_FromString( self->uf0D_viewshape->getName().c_str() );
+}
+
+static PyObject * UnaryFunction0DViewShape___call__( BPy_UnaryFunction0DViewShape *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if(!PyArg_ParseTuple(args, "O!", &Interface0DIterator_Type, &obj))
+ return NULL;
+
+ if( typeid(*(self->uf0D_viewshape)) == typeid(UnaryFunction0D<ViewShape*>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf0D_viewshape->operator()(*( ((BPy_Interface0DIterator *) obj)->if0D_it )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf0D_viewshape->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return BPy_ViewShape_from_ViewShape( *(self->uf0D_viewshape->result) );
+
+}
+
+/*----------------------UnaryFunction0DViewShape instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction0DViewShape_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction0DViewShape_getName, METH_NOARGS, UnaryFunction0DViewShape_getName___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction0DViewShape type definition ------------------------------*/
+
+PyTypeObject UnaryFunction0DViewShape_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction0DViewShape", /* tp_name */
+ sizeof(BPy_UnaryFunction0DViewShape), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction0DViewShape___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction0DViewShape___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction0DViewShape___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction0DViewShape___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction0DViewShape_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction0DViewShape___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DViewShape.h b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DViewShape.h
new file mode 100644
index 00000000000..68c888eb36b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/BPy_UnaryFunction0DViewShape.h
@@ -0,0 +1,36 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION0DVIEWSHAPE_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION0DVIEWSHAPE_H
+
+#include "../BPy_UnaryFunction0D.h"
+
+#include "../../view_map/ViewMap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction0DViewShape_Type;
+
+#define BPy_UnaryFunction0DViewShape_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction0DViewShape_Type) )
+
+/*---------------------------Python BPy_UnaryFunction0DViewShape structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0D py_uf0D;
+ UnaryFunction0D<ViewShape*> *uf0D_viewshape;
+} BPy_UnaryFunction0DViewShape;
+
+/*---------------------------Python BPy_UnaryFunction0DViewShape visible prototypes-----------*/
+int UnaryFunction0DViewShape_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION0DVIEWSHAPE_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.cpp
new file mode 100644
index 00000000000..49e8310380a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.cpp
@@ -0,0 +1,92 @@
+#include "BPy_ShapeIdF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ShapeIdF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DId` > :class:`ShapeIdF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a ShapeIdF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the :class:`Id` of the Shape the :class:`Interface0D`\n"
+" pointed by the Interface0DIterator belongs to. This evaluation can\n"
+" be ambiguous (in the case of a :class:`TVertex` for example). This\n"
+" functor tries to remove this ambiguity using the context offered by\n"
+" the 1D element to which the Interface0DIterator belongs to.\n"
+" However, there still can be problematic cases, and the user willing\n"
+" to deal with this cases in a specific way should implement its own\n"
+" getShapeIdF0D functor.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The Id of the Shape the pointed Interface0D belongs to.\n"
+" :rtype: :class:`Id`\n";
+
+static int ShapeIdF0D___init__( BPy_ShapeIdF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_id.uf0D_id = new Functions0D::ShapeIdF0D();
+ self->py_uf0D_id.uf0D_id->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_ShapeIdF0D type definition ------------------------------*/
+
+PyTypeObject ShapeIdF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ShapeIdF0D", /* tp_name */
+ sizeof(BPy_ShapeIdF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ShapeIdF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DId_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ShapeIdF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.h
new file mode 100644
index 00000000000..11995bb4e88
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_SHAPEIDF0D_H
+#define FREESTYLE_PYTHON_SHAPEIDF0D_H
+
+#include "../BPy_UnaryFunction0DId.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ShapeIdF0D_Type;
+
+#define BPy_ShapeIdF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ShapeIdF0D_Type) )
+
+/*---------------------------Python BPy_ShapeIdF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DId py_uf0D_id;
+} BPy_ShapeIdF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_SHAPEIDF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp
new file mode 100644
index 00000000000..85ea137134a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp
@@ -0,0 +1,96 @@
+#include "BPy_MaterialF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char MaterialF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DMaterial` > :class:`MaterialF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a MaterialF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the material of the object evaluated at the\n"
+" :class:`Interface0D` pointed by the Interface0DIterator. This\n"
+" evaluation can be ambiguous (in the case of a :class:`TVertex` for\n"
+" example. This functor tries to remove this ambiguity using the\n"
+" context offered by the 1D element to which the Interface0DIterator\n"
+" belongs to and by arbitrary chosing the material of the face that\n"
+" lies on its left when following the 1D element if there are two\n"
+" different materials on each side of the point. However, there\n"
+" still can be problematic cases, and the user willing to deal with\n"
+" this cases in a specific way should implement its own getMaterial\n"
+" functor.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The material of the object evaluated at the pointed\n"
+" Interface0D.\n"
+" :rtype: :class:`Material`\n";
+
+static int MaterialF0D___init__( BPy_MaterialF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_material.uf0D_material = new Functions0D::MaterialF0D();
+ self->py_uf0D_material.uf0D_material->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_MaterialF0D type definition ------------------------------*/
+
+PyTypeObject MaterialF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "MaterialF0D", /* tp_name */
+ sizeof(BPy_MaterialF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ MaterialF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DMaterial_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)MaterialF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.h
new file mode 100644
index 00000000000..1ae30484ba5
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_MATERIALF0D_H
+#define FREESTYLE_PYTHON_MATERIALF0D_H
+
+#include "../BPy_UnaryFunction0DMaterial.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject MaterialF0D_Type;
+
+#define BPy_MaterialF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &MaterialF0D_Type) )
+
+/*---------------------------Python BPy_MaterialF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DMaterial py_uf0D_material;
+} BPy_MaterialF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_MATERIALF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.cpp
new file mode 100644
index 00000000000..0d2023313ca
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.cpp
@@ -0,0 +1,87 @@
+#include "BPy_CurveNatureF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char CurveNatureF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DEdgeNature` > :class:`CurveNatureF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a CurveNatureF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the :class:`Nature` of the 1D element the Interface0D pointed\n"
+" by the Interface0DIterator belongs to.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The nature of the 1D element to which the pointed Interface0D\n"
+" belongs.\n"
+" :rtype: :class:`Nature`\n";
+
+static int CurveNatureF0D___init__( BPy_CurveNatureF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_edgenature.uf0D_edgenature = new Functions0D::CurveNatureF0D();
+ self->py_uf0D_edgenature.uf0D_edgenature->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_CurveNatureF0D type definition ------------------------------*/
+
+PyTypeObject CurveNatureF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "CurveNatureF0D", /* tp_name */
+ sizeof(BPy_CurveNatureF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ CurveNatureF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DEdgeNature_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)CurveNatureF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.h
new file mode 100644
index 00000000000..63b3050c474
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_CURVENATUREF0D_H
+#define FREESTYLE_PYTHON_CURVENATUREF0D_H
+
+#include "../BPy_UnaryFunction0DEdgeNature.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject CurveNatureF0D_Type;
+
+#define BPy_CurveNatureF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &CurveNatureF0D_Type) )
+
+/*---------------------------Python BPy_CurveNatureF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DEdgeNature py_uf0D_edgenature;
+} BPy_CurveNatureF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CURVENATUREF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.cpp
new file mode 100644
index 00000000000..fdec2c324c6
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.cpp
@@ -0,0 +1,89 @@
+#include "BPy_Normal2DF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Normal2DF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DVec2f` > :class:`Normal2DF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a Normal2DF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns a two-dimensional vector giving the normalized 2D normal to\n"
+" the 1D element to which the :class:`Interface0D` pointed by the\n"
+" Interface0DIterator belongs. The normal is evaluated at the pointed\n"
+" Interface0D.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The 2D normal of the 1D element evaluated at the pointed\n"
+" Interface0D.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static int Normal2DF0D___init__( BPy_Normal2DF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_vec2f.uf0D_vec2f = new Functions0D::Normal2DF0D();
+ self->py_uf0D_vec2f.uf0D_vec2f->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_Normal2DF0D type definition ------------------------------*/
+
+PyTypeObject Normal2DF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Normal2DF0D", /* tp_name */
+ sizeof(BPy_Normal2DF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Normal2DF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DVec2f_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Normal2DF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.h
new file mode 100644
index 00000000000..0b3be2df428
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_NORMAL2DF0D_H
+#define FREESTYLE_PYTHON_NORMAL2DF0D_H
+
+#include "../BPy_UnaryFunction0DVec2f.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject Normal2DF0D_Type;
+
+#define BPy_Normal2DF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Normal2DF0D_Type) )
+
+/*---------------------------Python BPy_Normal2DF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DVec2f py_uf0D_vec2f;
+} BPy_Normal2DF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_NORMAL2DF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.cpp
new file mode 100644
index 00000000000..f362293e179
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.cpp
@@ -0,0 +1,89 @@
+#include "BPy_VertexOrientation2DF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char VertexOrientation2DF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DVec2f` > :class:`VertexOrientation2DF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a VertexOrientation2DF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns a two-dimensional vector giving the 2D oriented tangent to\n"
+" the 1D element to which the :class:`Interface0D` pointed by the\n"
+" Interface0DIterator belongs. The 2D oriented tangent is evaluated\n"
+" at the pointed Interface0D.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The 2D oriented tangent to the 1D element evaluated at the\n"
+" pointed Interface0D.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static int VertexOrientation2DF0D___init__( BPy_VertexOrientation2DF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_vec2f.uf0D_vec2f = new Functions0D::VertexOrientation2DF0D();
+ self->py_uf0D_vec2f.uf0D_vec2f->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_VertexOrientation2DF0D type definition ------------------------------*/
+
+PyTypeObject VertexOrientation2DF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "VertexOrientation2DF0D", /* tp_name */
+ sizeof(BPy_VertexOrientation2DF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ VertexOrientation2DF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DVec2f_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)VertexOrientation2DF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.h
new file mode 100644
index 00000000000..1cce9b592ba
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_VERTEXORIENTATION2DF0D_H
+#define FREESTYLE_PYTHON_VERTEXORIENTATION2DF0D_H
+
+#include "../BPy_UnaryFunction0DVec2f.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject VertexOrientation2DF0D_Type;
+
+#define BPy_VertexOrientation2DF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &VertexOrientation2DF0D_Type) )
+
+/*---------------------------Python BPy_VertexOrientation2DF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DVec2f py_uf0D_vec2f;
+} BPy_VertexOrientation2DF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_VERTEXORIENTATION2DF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.cpp
new file mode 100644
index 00000000000..8cb3e88efe3
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.cpp
@@ -0,0 +1,89 @@
+#include "BPy_VertexOrientation3DF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char VertexOrientation3DF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DVec3f` > :class:`VertexOrientation3DF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a VertexOrientation3DF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns a three-dimensional vector giving the 3D oriented tangent\n"
+" to the 1D element to which the :class:`Interface0D` pointed by the\n"
+" Interface0DIterator belongs. The 3D oriented tangent is evaluated\n"
+" at the pointed Interface0D.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The 3D oriented tangent to the 1D element evaluated at the\n"
+" pointed Interface0D.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static int VertexOrientation3DF0D___init__( BPy_VertexOrientation3DF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_vec3f.uf0D_vec3f = new Functions0D::VertexOrientation3DF0D();
+ self->py_uf0D_vec3f.uf0D_vec3f->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_VertexOrientation3DF0D type definition ------------------------------*/
+
+PyTypeObject VertexOrientation3DF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "VertexOrientation3DF0D", /* tp_name */
+ sizeof(BPy_VertexOrientation3DF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ VertexOrientation3DF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DVec3f_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)VertexOrientation3DF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.h
new file mode 100644
index 00000000000..80cac529f0b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_VERTEXORIENTATION3DF0D_H
+#define FREESTYLE_PYTHON_VERTEXORIENTATION3DF0D_H
+
+#include "../BPy_UnaryFunction0DVec3f.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject VertexOrientation3DF0D_Type;
+
+#define BPy_VertexOrientation3DF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &VertexOrientation3DF0D_Type) )
+
+/*---------------------------Python BPy_VertexOrientation3DF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DVec3f py_uf0D_vec3f;
+} BPy_VertexOrientation3DF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_VERTEXORIENTATION3DF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.cpp
new file mode 100644
index 00000000000..8bfd2bb2638
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.cpp
@@ -0,0 +1,86 @@
+#include "BPy_GetOccludeeF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetOccludeeF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DViewShape` > :class:`GetOccludeeF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetOccludeeF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the :class:`ViewShape` that the Interface0D pointed by the\n"
+" Interface0DIterator occludes.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The ViewShape occluded by the pointed Interface0D.\n"
+" :rtype: :class:`ViewShape`\n";
+
+static int GetOccludeeF0D___init__( BPy_GetOccludeeF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_viewshape.uf0D_viewshape = new Functions0D::GetOccludeeF0D();
+ self->py_uf0D_viewshape.uf0D_viewshape->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_GetOccludeeF0D type definition ------------------------------*/
+
+PyTypeObject GetOccludeeF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetOccludeeF0D", /* tp_name */
+ sizeof(BPy_GetOccludeeF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetOccludeeF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DViewShape_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetOccludeeF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.h
new file mode 100644
index 00000000000..fd4f7d92bbb
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETOCCLUDEEF0D_H
+#define FREESTYLE_PYTHON_GETOCCLUDEEF0D_H
+
+#include "../BPy_UnaryFunction0DViewShape.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetOccludeeF0D_Type;
+
+#define BPy_GetOccludeeF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetOccludeeF0D_Type) )
+
+/*---------------------------Python BPy_GetOccludeeF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DViewShape py_uf0D_viewshape;
+} BPy_GetOccludeeF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETOCCLUDEEF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.cpp
new file mode 100644
index 00000000000..3cc931edec5
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.cpp
@@ -0,0 +1,86 @@
+#include "BPy_GetShapeF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetShapeF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DViewShape` > :class:`GetShapeF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetShapeF0D.cpp object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the :class:`ViewShape` containing the Interface0D pointed\n"
+" by the Interface0DIterator.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The ViewShape containing the pointed Interface0D.\n"
+" :rtype: :class:`ViewShape`\n";
+
+static int GetShapeF0D___init__( BPy_GetShapeF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_viewshape.uf0D_viewshape = new Functions0D::GetShapeF0D();
+ self->py_uf0D_viewshape.uf0D_viewshape->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_GetShapeF0D type definition ------------------------------*/
+
+PyTypeObject GetShapeF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetShapeF0D", /* tp_name */
+ sizeof(BPy_GetShapeF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetShapeF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DViewShape_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetShapeF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.h
new file mode 100644
index 00000000000..040c753968d
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETSHAPEF0D_H
+#define FREESTYLE_PYTHON_GETSHAPEF0D_H
+
+#include "../BPy_UnaryFunction0DViewShape.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetShapeF0D_Type;
+
+#define BPy_GetShapeF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetShapeF0D_Type) )
+
+/*---------------------------Python BPy_GetShapeF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DViewShape py_uf0D_viewshape;
+} BPy_GetShapeF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETSHAPEF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.cpp
new file mode 100644
index 00000000000..e28b1ca138a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.cpp
@@ -0,0 +1,89 @@
+#include "BPy_Curvature2DAngleF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Curvature2DAngleF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`Curvature2DAngleF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a Curvature2DAngleF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns a real value giving the 2D curvature (as an angle) of the\n"
+" 1D element to which the :class:`Interface0D` pointed by the\n"
+" Interface0DIterator belongs. The 2D curvature is evaluated at the\n"
+" Interface0D.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The 2D curvature of the 1D element evaluated at the\n"
+" pointed Interface0D.\n"
+" :rtype: float\n";
+
+static int Curvature2DAngleF0D___init__( BPy_Curvature2DAngleF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_double.uf0D_double = new Functions0D::Curvature2DAngleF0D();
+ self->py_uf0D_double.uf0D_double->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_Curvature2DAngleF0D type definition ------------------------------*/
+
+PyTypeObject Curvature2DAngleF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Curvature2DAngleF0D", /* tp_name */
+ sizeof(BPy_Curvature2DAngleF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Curvature2DAngleF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Curvature2DAngleF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.h
new file mode 100644
index 00000000000..810ba04db8a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_CURVATURE2DANGLEF0D_H
+#define FREESTYLE_PYTHON_CURVATURE2DANGLEF0D_H
+
+#include "../BPy_UnaryFunction0DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject Curvature2DAngleF0D_Type;
+
+#define BPy_Curvature2DAngleF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Curvature2DAngleF0D_Type) )
+
+/*---------------------------Python BPy_Curvature2DAngleF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DDouble py_uf0D_double;
+} BPy_Curvature2DAngleF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CURVATURE2DANGLEF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.cpp
new file mode 100644
index 00000000000..64c2d453552
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.cpp
@@ -0,0 +1,96 @@
+#include "BPy_DensityF0D.h"
+
+#include "../../../stroke/AdvancedFunctions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char DensityF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`DensityF0D`\n"
+"\n"
+".. method:: __init__(sigma=2.0)\n"
+"\n"
+" Builds a DensityF0D object.\n"
+"\n"
+" :arg sigma: The gaussian sigma value ndicating the X value for\n"
+" which the gaussian function is 0.5. It leads to the window size\n"
+" value (the larger, the smoother).\n"
+" :type sigma: float\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the density of the (result) image evaluated at the\n"
+" :class:`Interface0D` pointed by the Interface0DIterator. This\n"
+" density is evaluated using a pixels square window around the\n"
+" evaluation point and integrating these values using a gaussian.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The density of the image evaluated at the pointed\n"
+" Interface0D.\n"
+" :rtype: float\n";
+
+static int DensityF0D___init__( BPy_DensityF0D* self, PyObject *args)
+{
+ double d = 2;
+
+ if( !PyArg_ParseTuple(args, "|d", &d) )
+ return -1;
+ self->py_uf0D_double.uf0D_double = new Functions0D::DensityF0D(d);
+ self->py_uf0D_double.uf0D_double->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_DensityF0D type definition ------------------------------*/
+
+PyTypeObject DensityF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "DensityF0D", /* tp_name */
+ sizeof(BPy_DensityF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ DensityF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)DensityF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.h
new file mode 100644
index 00000000000..17ea95a771c
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_DENSITYF0D_H
+#define FREESTYLE_PYTHON_DENSITYF0D_H
+
+#include "../BPy_UnaryFunction0DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject DensityF0D_Type;
+
+#define BPy_DensityF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &DensityF0D_Type) )
+
+/*---------------------------Python BPy_DensityF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DDouble py_uf0D_double;
+} BPy_DensityF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_DENSITYF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.cpp
new file mode 100644
index 00000000000..e539ca10dc8
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.cpp
@@ -0,0 +1,86 @@
+#include "BPy_GetProjectedXF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetProjectedXF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`GetProjectedXF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetProjectedXF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the X 3D projected coordinate of the :class:`Interface0D`\n"
+" pointed by the Interface0DIterator.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The X 3D projected coordinate of the pointed Interface0D.\n"
+" :rtype: float\n";
+
+static int GetProjectedXF0D___init__( BPy_GetProjectedXF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_double.uf0D_double = new Functions0D::GetProjectedXF0D();
+ self->py_uf0D_double.uf0D_double->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_GetProjectedXF0D type definition ------------------------------*/
+
+PyTypeObject GetProjectedXF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetProjectedXF0D", /* tp_name */
+ sizeof(BPy_GetProjectedXF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetProjectedXF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetProjectedXF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.h
new file mode 100644
index 00000000000..da73623cbf0
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETPROJECTEDXF0D_H
+#define FREESTYLE_PYTHON_GETPROJECTEDXF0D_H
+
+#include "../BPy_UnaryFunction0DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetProjectedXF0D_Type;
+
+#define BPy_GetProjectedXF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetProjectedXF0D_Type) )
+
+/*---------------------------Python BPy_GetProjectedXF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DDouble py_uf0D_double;
+} BPy_GetProjectedXF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETPROJECTEDXF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.cpp
new file mode 100644
index 00000000000..4e1fbbd699c
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.cpp
@@ -0,0 +1,86 @@
+#include "BPy_GetProjectedYF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetProjectedYF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`GetProjectedYF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetProjectedYF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the Y 3D projected coordinate of the :class:`Interface0D`\n"
+" pointed by the Interface0DIterator.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The Y 3D projected coordinate of the pointed Interface0D.\n"
+" :rtype: float\n";
+
+static int GetProjectedYF0D___init__( BPy_GetProjectedYF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_double.uf0D_double = new Functions0D::GetProjectedYF0D();
+ self->py_uf0D_double.uf0D_double->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_GetProjectedYF0D type definition ------------------------------*/
+
+PyTypeObject GetProjectedYF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetProjectedYF0D", /* tp_name */
+ sizeof(BPy_GetProjectedYF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetProjectedYF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetProjectedYF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.h
new file mode 100644
index 00000000000..3a26e093747
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETPROJECTEDYF0D_H
+#define FREESTYLE_PYTHON_GETPROJECTEDYF0D_H
+
+#include "../BPy_UnaryFunction0DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetProjectedYF0D_Type;
+
+#define BPy_GetProjectedYF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetProjectedYF0D_Type) )
+
+/*---------------------------Python BPy_GetProjectedYF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DDouble py_uf0D_double;
+} BPy_GetProjectedYF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETPROJECTEDYF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.cpp
new file mode 100644
index 00000000000..73a68b8f6a8
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.cpp
@@ -0,0 +1,86 @@
+#include "BPy_GetProjectedZF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetProjectedZF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`GetProjectedZF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetProjectedZF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the Z 3D projected coordinate of the :class:`Interface0D`\n"
+" pointed by the Interface0DIterator.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The Z 3D projected coordinate of the pointed Interface0D.\n"
+" :rtype: float\n";
+
+static int GetProjectedZF0D___init__( BPy_GetProjectedZF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_double.uf0D_double = new Functions0D::GetProjectedZF0D();
+ self->py_uf0D_double.uf0D_double->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_GetProjectedZF0D type definition ------------------------------*/
+
+PyTypeObject GetProjectedZF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetProjectedZF0D", /* tp_name */
+ sizeof(BPy_GetProjectedZF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetProjectedZF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetProjectedZF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.h
new file mode 100644
index 00000000000..aa41b70c660
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETPROJECTEDZF0D_H
+#define FREESTYLE_PYTHON_GETPROJECTEDZF0D_H
+
+#include "../BPy_UnaryFunction0DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetProjectedZF0D_Type;
+
+#define BPy_GetProjectedZF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetProjectedZF0D_Type) )
+
+/*---------------------------Python BPy_GetProjectedZF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DDouble py_uf0D_double;
+} BPy_GetProjectedZF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETPROJECTEDZF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.cpp
new file mode 100644
index 00000000000..099977e35eb
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.cpp
@@ -0,0 +1,86 @@
+#include "BPy_GetXF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetXF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`GetXF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetXF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the X 3D coordinate of the :class:`Interface0D` pointed by\n"
+" the Interface0DIterator.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The X 3D coordinate of the pointed Interface0D.\n"
+" :rtype: float\n";
+
+static int GetXF0D___init__( BPy_GetXF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_double.uf0D_double = new Functions0D::GetXF0D();
+ self->py_uf0D_double.uf0D_double->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_GetXF0D type definition ------------------------------*/
+
+PyTypeObject GetXF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetXF0D", /* tp_name */
+ sizeof(BPy_GetXF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetXF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetXF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.h
new file mode 100644
index 00000000000..69e9a892f4a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETXF0D_H
+#define FREESTYLE_PYTHON_GETXF0D_H
+
+#include "../BPy_UnaryFunction0DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetXF0D_Type;
+
+#define BPy_GetXF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetXF0D_Type) )
+
+/*---------------------------Python BPy_GetXF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DDouble py_uf0D_double;
+} BPy_GetXF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETXF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.cpp
new file mode 100644
index 00000000000..7640dafef6f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.cpp
@@ -0,0 +1,86 @@
+#include "BPy_GetYF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetYF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`GetYF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetYF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the Y 3D coordinate of the :class:`Interface0D` pointed by\n"
+" the Interface0DIterator.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The Y 3D coordinate of the pointed Interface0D.\n"
+" :rtype: float\n";
+
+static int GetYF0D___init__( BPy_GetYF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_double.uf0D_double = new Functions0D::GetYF0D();
+ self->py_uf0D_double.uf0D_double->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_GetYF0D type definition ------------------------------*/
+
+PyTypeObject GetYF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetYF0D", /* tp_name */
+ sizeof(BPy_GetYF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetYF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetYF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.h
new file mode 100644
index 00000000000..0601f38585f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETYF0D_H
+#define FREESTYLE_PYTHON_GETYF0D_H
+
+#include "../BPy_UnaryFunction0DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetYF0D_Type;
+
+#define BPy_GetYF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetYF0D_Type) )
+
+/*---------------------------Python BPy_GetYF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DDouble py_uf0D_double;
+} BPy_GetYF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETYF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.cpp
new file mode 100644
index 00000000000..01932c2b4ed
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.cpp
@@ -0,0 +1,86 @@
+#include "BPy_GetZF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetZF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`GetZF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetZF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the Z 3D coordinate of the :class:`Interface0D` pointed by\n"
+" the Interface0DIterator.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The Z 3D coordinate of the pointed Interface0D.\n"
+" :rtype: float\n";
+
+static int GetZF0D___init__( BPy_GetZF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_double.uf0D_double = new Functions0D::GetZF0D();
+ self->py_uf0D_double.uf0D_double->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_GetZF0D type definition ------------------------------*/
+
+PyTypeObject GetZF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetZF0D", /* tp_name */
+ sizeof(BPy_GetZF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetZF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetZF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.h
new file mode 100644
index 00000000000..eac52426600
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETZF0D_H
+#define FREESTYLE_PYTHON_GETZF0D_H
+
+#include "../BPy_UnaryFunction0DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetZF0D_Type;
+
+#define BPy_GetZF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetZF0D_Type) )
+
+/*---------------------------Python BPy_GetZF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DDouble py_uf0D_double;
+} BPy_GetZF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETZF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.cpp
new file mode 100644
index 00000000000..f268fdf7003
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.cpp
@@ -0,0 +1,92 @@
+#include "BPy_LocalAverageDepthF0D.h"
+
+#include "../../../stroke/AdvancedFunctions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char LocalAverageDepthF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`LocalAverageDepthF0D`\n"
+"\n"
+".. method:: __init__(maskSize=5.0)\n"
+"\n"
+" Builds a LocalAverageDepthF0D object.\n"
+"\n"
+" :arg maskSize: The size of the mask.\n"
+" :type maskSize: float\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the average depth around the :class:`Interface0D` pointed\n"
+" by the Interface0DIterator. The result is obtained by querying the\n"
+" depth buffer on a window around that point.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The average depth around the pointed Interface0D.\n"
+" :rtype: float\n";
+
+static int LocalAverageDepthF0D___init__( BPy_LocalAverageDepthF0D* self, PyObject *args)
+{
+ double d = 5.0;
+
+ if( !PyArg_ParseTuple(args, "|d", &d) )
+ return -1;
+ self->py_uf0D_double.uf0D_double = new Functions0D::LocalAverageDepthF0D(d);
+ self->py_uf0D_double.uf0D_double->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_LocalAverageDepthF0D type definition ------------------------------*/
+
+PyTypeObject LocalAverageDepthF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "LocalAverageDepthF0D", /* tp_name */
+ sizeof(BPy_LocalAverageDepthF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ LocalAverageDepthF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)LocalAverageDepthF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.h
new file mode 100644
index 00000000000..7385e1d24c1
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_LOCALAVERAGEDEPTHF0D_H
+#define FREESTYLE_PYTHON_LOCALAVERAGEDEPTHF0D_H
+
+#include "../BPy_UnaryFunction0DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject LocalAverageDepthF0D_Type;
+
+#define BPy_LocalAverageDepthF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &LocalAverageDepthF0D_Type) )
+
+/*---------------------------Python BPy_LocalAverageDepthF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DDouble py_uf0D_double;
+} BPy_LocalAverageDepthF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_LOCALAVERAGEDEPTHF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp
new file mode 100644
index 00000000000..20e2ab31bda
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp
@@ -0,0 +1,91 @@
+#include "BPy_ZDiscontinuityF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ZDiscontinuityF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`ZDiscontinuityF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a ZDiscontinuityF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns a real value giving the distance between the\n"
+" :class:`Interface0D` pointed by the Interface0DIterator and the\n"
+" shape that lies behind (occludee). This distance is evaluated in\n"
+" the camera space and normalized between 0 and 1. Therefore, if no\n"
+" oject is occluded by the shape to which the Interface0D belongs to,\n"
+" 1 is returned.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The normalized distance between the pointed Interface0D\n"
+" and the occludee.\n"
+" :rtype: float\n";
+
+static int ZDiscontinuityF0D___init__( BPy_ZDiscontinuityF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_double.uf0D_double = new Functions0D::ZDiscontinuityF0D();
+ self->py_uf0D_double.uf0D_double->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_ZDiscontinuityF0D type definition ------------------------------*/
+
+PyTypeObject ZDiscontinuityF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ZDiscontinuityF0D", /* tp_name */
+ sizeof(BPy_ZDiscontinuityF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ZDiscontinuityF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ZDiscontinuityF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.h
new file mode 100644
index 00000000000..a26ba4fdbd6
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_ZDISCONTINUITYF0D_H
+#define FREESTYLE_PYTHON_ZDISCONTINUITYF0D_H
+
+#include "../BPy_UnaryFunction0DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ZDiscontinuityF0D_Type;
+
+#define BPy_ZDiscontinuityF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ZDiscontinuityF0D_Type) )
+
+/*---------------------------Python BPy_ZDiscontinuityF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DDouble py_uf0D_double;
+} BPy_ZDiscontinuityF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_ZDISCONTINUITYF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.cpp
new file mode 100644
index 00000000000..4aaceb3559a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.cpp
@@ -0,0 +1,87 @@
+#include "BPy_GetCurvilinearAbscissaF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetCurvilinearAbscissaF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DFloat` > :class:`GetCurvilinearAbscissaF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetCurvilinearAbscissaF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the curvilinear abscissa of the :class:`Interface0D`\n"
+" pointed by the Interface0DIterator in the context of its 1D\n"
+" element.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The curvilinear abscissa of the pointed Interface0D.\n"
+" :rtype: float\n";
+
+static int GetCurvilinearAbscissaF0D___init__( BPy_GetCurvilinearAbscissaF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_float.uf0D_float = new Functions0D::GetCurvilinearAbscissaF0D();
+ self->py_uf0D_float.uf0D_float->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_GetCurvilinearAbscissaF0D type definition ------------------------------*/
+
+PyTypeObject GetCurvilinearAbscissaF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetCurvilinearAbscissaF0D", /* tp_name */
+ sizeof(BPy_GetCurvilinearAbscissaF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetCurvilinearAbscissaF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DFloat_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetCurvilinearAbscissaF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.h
new file mode 100644
index 00000000000..0cb56fcec70
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETCURVILINEARABSCISSAF0D_H
+#define FREESTYLE_PYTHON_GETCURVILINEARABSCISSAF0D_H
+
+#include "../BPy_UnaryFunction0DFloat.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetCurvilinearAbscissaF0D_Type;
+
+#define BPy_GetCurvilinearAbscissaF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetCurvilinearAbscissaF0D_Type) )
+
+/*---------------------------Python BPy_GetCurvilinearAbscissaF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DFloat py_uf0D_float;
+} BPy_GetCurvilinearAbscissaF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETCURVILINEARABSCISSAF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.cpp
new file mode 100644
index 00000000000..aeea47deffc
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.cpp
@@ -0,0 +1,86 @@
+#include "BPy_GetParameterF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetParameterF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DFloat` > :class:`GetParameterF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetParameterF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the parameter of the :class:`Interface0D` pointed by the\n"
+" Interface0DIterator in the context of its 1D element.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The parameter of an Interface0D.\n"
+" :rtype: float\n";
+
+static int GetParameterF0D___init__( BPy_GetParameterF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_float.uf0D_float = new Functions0D::GetParameterF0D();
+ self->py_uf0D_float.uf0D_float->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_GetParameterF0D type definition ------------------------------*/
+
+PyTypeObject GetParameterF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetParameterF0D", /* tp_name */
+ sizeof(BPy_GetParameterF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetParameterF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DFloat_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetParameterF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.h
new file mode 100644
index 00000000000..4817e5cec86
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETPARAMETERF0D_H
+#define FREESTYLE_PYTHON_GETPARAMETERF0D_H
+
+#include "../BPy_UnaryFunction0DFloat.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetParameterF0D_Type;
+
+#define BPy_GetParameterF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetParameterF0D_Type) )
+
+/*---------------------------Python BPy_GetParameterF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DFloat py_uf0D_float;
+} BPy_GetParameterF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETPARAMETERF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.cpp
new file mode 100644
index 00000000000..bac65716ba9
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.cpp
@@ -0,0 +1,93 @@
+#include "BPy_GetViewMapGradientNormF0D.h"
+
+#include "../../../stroke/AdvancedFunctions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetViewMapGradientNormF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DFloat` > :class:`GetViewMapGradientNormF0D`\n"
+"\n"
+".. method:: __init__(level)\n"
+"\n"
+" Builds a GetViewMapGradientNormF0D object.\n"
+"\n"
+" :arg level: The level of the pyramid from which the pixel must be\n"
+" read.\n"
+" :type level: int\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the norm of the gradient of the global viewmap density\n"
+" image.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The norm of the gradient of the global viewmap density\n"
+" image.\n"
+" :rtype: float\n";
+
+static int GetViewMapGradientNormF0D___init__( BPy_GetViewMapGradientNormF0D* self, PyObject *args)
+{
+ int i;
+
+ if( !PyArg_ParseTuple(args, "i", &i) )
+ return -1;
+ self->py_uf0D_float.uf0D_float = new Functions0D::GetViewMapGradientNormF0D(i);
+ self->py_uf0D_float.uf0D_float->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_GetViewMapGradientNormF0D type definition ------------------------------*/
+
+PyTypeObject GetViewMapGradientNormF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetViewMapGradientNormF0D", /* tp_name */
+ sizeof(BPy_GetViewMapGradientNormF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetViewMapGradientNormF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DFloat_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetViewMapGradientNormF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.h
new file mode 100644
index 00000000000..c072ba7f408
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETVIEWMAPGRADIENTNORMF0D_H
+#define FREESTYLE_PYTHON_GETVIEWMAPGRADIENTNORMF0D_H
+
+#include "../BPy_UnaryFunction0DFloat.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetViewMapGradientNormF0D_Type;
+
+#define BPy_GetViewMapGradientNormF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetViewMapGradientNormF0D_Type) )
+
+/*---------------------------Python BPy_GetViewMapGradientNormF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DFloat py_uf0D_float;
+} BPy_GetViewMapGradientNormF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETVIEWMAPGRADIENTNORMF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.cpp
new file mode 100644
index 00000000000..6a40266cf7b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.cpp
@@ -0,0 +1,91 @@
+#include "BPy_ReadCompleteViewMapPixelF0D.h"
+
+#include "../../../stroke/AdvancedFunctions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ReadCompleteViewMapPixelF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DFloat` > :class:`ReadCompleteViewMapPixelF0D`\n"
+"\n"
+".. method:: __init__(level)\n"
+"\n"
+" Builds a ReadCompleteViewMapPixelF0D object.\n"
+"\n"
+" :arg level: The level of the pyramid from which the pixel must be\n"
+" read.\n"
+" :type level: int\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Reads a pixel in one of the level of the complete viewmap.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: A pixel in one of the level of the complete viewmap.\n"
+" :rtype: float\n";
+
+static int ReadCompleteViewMapPixelF0D___init__( BPy_ReadCompleteViewMapPixelF0D* self, PyObject *args)
+{
+ int i;
+
+ if( !PyArg_ParseTuple(args, "i", &i) )
+ return -1;
+ self->py_uf0D_float.uf0D_float = new Functions0D::ReadCompleteViewMapPixelF0D(i);
+ self->py_uf0D_float.uf0D_float->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_ReadCompleteViewMapPixelF0D type definition ------------------------------*/
+
+PyTypeObject ReadCompleteViewMapPixelF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ReadCompleteViewMapPixelF0D", /* tp_name */
+ sizeof(BPy_ReadCompleteViewMapPixelF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ReadCompleteViewMapPixelF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DFloat_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ReadCompleteViewMapPixelF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.h
new file mode 100644
index 00000000000..6a10e6c06a4
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_READCOMPLETEVIEWMAPPIXELF0D_H
+#define FREESTYLE_PYTHON_READCOMPLETEVIEWMAPPIXELF0D_H
+
+#include "../BPy_UnaryFunction0DFloat.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ReadCompleteViewMapPixelF0D_Type;
+
+#define BPy_ReadCompleteViewMapPixelF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ReadCompleteViewMapPixelF0D_Type) )
+
+/*---------------------------Python BPy_ReadCompleteViewMapPixelF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DFloat py_uf0D_float;
+} BPy_ReadCompleteViewMapPixelF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_READCOMPLETEVIEWMAPPIXELF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.cpp
new file mode 100644
index 00000000000..74cf688507e
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.cpp
@@ -0,0 +1,94 @@
+#include "BPy_ReadMapPixelF0D.h"
+
+#include "../../../stroke/AdvancedFunctions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ReadMapPixelF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DFloat` > :class:`ReadMapPixelF0D`\n"
+"\n"
+".. method:: __init__(iMapName, level)\n"
+"\n"
+" Builds a ReadMapPixelF0D object.\n"
+"\n"
+" :arg iMapName: The name of the map to be read.\n"
+" :type iMapName: str\n"
+" :arg level: The level of the pyramid from which the pixel must be\n"
+" read.\n"
+" :type level: int\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Reads a pixel in a map.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: A pixel in a map.\n"
+" :rtype: float\n";
+
+static int ReadMapPixelF0D___init__( BPy_ReadMapPixelF0D* self, PyObject *args)
+{
+ const char *s;
+ int i;
+
+ if( !PyArg_ParseTuple(args, "si", &s, &i) )
+ return -1;
+ self->py_uf0D_float.uf0D_float = new Functions0D::ReadMapPixelF0D(s,i);
+ self->py_uf0D_float.uf0D_float->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_ReadMapPixelF0D type definition ------------------------------*/
+
+PyTypeObject ReadMapPixelF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ReadMapPixelF0D", /* tp_name */
+ sizeof(BPy_ReadMapPixelF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ReadMapPixelF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DFloat_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ReadMapPixelF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.h
new file mode 100644
index 00000000000..9aed0cd82bf
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_READMAPPIXELF0D_H
+#define FREESTYLE_PYTHON_READMAPPIXELF0D_H
+
+#include "../BPy_UnaryFunction0DFloat.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ReadMapPixelF0D_Type;
+
+#define BPy_ReadMapPixelF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ReadMapPixelF0D_Type) )
+
+/*---------------------------Python BPy_ReadMapPixelF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DFloat py_uf0D_float;
+} BPy_ReadMapPixelF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_READMAPPIXELF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp
new file mode 100644
index 00000000000..db0145e3e2a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp
@@ -0,0 +1,95 @@
+#include "BPy_ReadSteerableViewMapPixelF0D.h"
+
+#include "../../../stroke/AdvancedFunctions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ReadSteerableViewMapPixelF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DFloat` > :class:`ReadSteerableViewMapPixelF0D`\n"
+"\n"
+".. method:: __init__(nOrientation, level)\n"
+"\n"
+" Builds a ReadSteerableViewMapPixelF0D object.\n"
+"\n"
+" :arg nOrientation: The integer belonging to [0, 4] indicating the\n"
+" orientation (E, NE, N, NW) we are interested in.\n"
+" :type nOrientation: int\n"
+" :arg level: The level of the pyramid from which the pixel must be\n"
+" read.\n"
+" :type level: int\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Reads a pixel in one of the level of one of the steerable viewmaps.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: A pixel in one of the level of one of the steerable viewmaps.\n"
+" :rtype: float\n";
+
+static int ReadSteerableViewMapPixelF0D___init__( BPy_ReadSteerableViewMapPixelF0D* self, PyObject *args)
+{
+ unsigned int u;
+ int i;
+
+ if( !PyArg_ParseTuple(args, "Ii", &u, &i) )
+ return -1;
+ self->py_uf0D_float.uf0D_float = new Functions0D::ReadSteerableViewMapPixelF0D(u,i);
+ self->py_uf0D_float.uf0D_float->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_ReadSteerableViewMapPixelF0D type definition ------------------------------*/
+
+PyTypeObject ReadSteerableViewMapPixelF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ReadSteerableViewMapPixelF0D", /* tp_name */
+ sizeof(BPy_ReadSteerableViewMapPixelF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ReadSteerableViewMapPixelF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DFloat_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ReadSteerableViewMapPixelF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.h
new file mode 100644
index 00000000000..a881a10f72d
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_READSTEERABLEVIEWMAPPIXELF0D_H
+#define FREESTYLE_PYTHON_READSTEERABLEVIEWMAPPIXELF0D_H
+
+#include "../BPy_UnaryFunction0DFloat.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ReadSteerableViewMapPixelF0D_Type;
+
+#define BPy_ReadSteerableViewMapPixelF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ReadSteerableViewMapPixelF0D_Type) )
+
+/*---------------------------Python BPy_ReadSteerableViewMapPixelF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DFloat py_uf0D_float;
+} BPy_ReadSteerableViewMapPixelF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_READSTEERABLEVIEWMAPPIXELF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.cpp
new file mode 100644
index 00000000000..e993a99c1d8
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.cpp
@@ -0,0 +1,92 @@
+#include "BPy_QuantitativeInvisibilityF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char QuantitativeInvisibilityF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DUnsigned` > :class:`QuantitativeInvisibilityF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a QuantitativeInvisibilityF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns the quantitative invisibility of the :class:`Interface0D`\n"
+" pointed by the Interface0DIterator. This evaluation can be\n"
+" ambiguous (in the case of a :class:`TVertex` for example). This\n"
+" functor tries to remove this ambiguity using the context offered by\n"
+" the 1D element to which the Interface0D belongs to. However, there\n"
+" still can be problematic cases, and the user willing to deal with\n"
+" this cases in a specific way should implement its own getQIF0D\n"
+" functor.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: The quantitative invisibility of the pointed Interface0D.\n"
+" :rtype: int\n";
+
+static int QuantitativeInvisibilityF0D___init__( BPy_QuantitativeInvisibilityF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_unsigned.uf0D_unsigned = new Functions0D::QuantitativeInvisibilityF0D();
+ self->py_uf0D_unsigned.uf0D_unsigned->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_QuantitativeInvisibilityF0D type definition ------------------------------*/
+
+PyTypeObject QuantitativeInvisibilityF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "QuantitativeInvisibilityF0D", /* tp_name */
+ sizeof(BPy_QuantitativeInvisibilityF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ QuantitativeInvisibilityF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DUnsigned_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)QuantitativeInvisibilityF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.h
new file mode 100644
index 00000000000..39b73343608
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_QUANTITATIVEINVISIBILITYF0D_H
+#define FREESTYLE_PYTHON_QUANTITATIVEINVISIBILITYF0D_H
+
+#include "../BPy_UnaryFunction0DUnsigned.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject QuantitativeInvisibilityF0D_Type;
+
+#define BPy_QuantitativeInvisibilityF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &QuantitativeInvisibilityF0D_Type) )
+
+/*---------------------------Python BPy_QuantitativeInvisibilityF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DUnsigned py_uf0D_unsigned;
+} BPy_QuantitativeInvisibilityF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_QUANTITATIVEINVISIBILITYF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.cpp
new file mode 100644
index 00000000000..50686ce92f9
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.cpp
@@ -0,0 +1,87 @@
+#include "BPy_GetOccludersF0D.h"
+
+#include "../../../view_map/Functions0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetOccludersF0D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DVectorViewShape` > :class:`GetOccludersF0D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetOccludersF0D object.\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Returns a list of :class:`ViewShape` objects occluding the\n"
+" :class:`Interface0D` pointed by the Interface0DIterator.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: A list of ViewShape objects occluding the pointed\n"
+" Interface0D.\n"
+" :rtype: list of :class:`ViewShape` objects\n";
+
+static int GetOccludersF0D___init__( BPy_GetOccludersF0D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf0D_vectorviewshape.uf0D_vectorviewshape = new Functions0D::GetOccludersF0D();
+ self->py_uf0D_vectorviewshape.uf0D_vectorviewshape->py_uf0D = (PyObject *)self;
+ return 0;
+}
+
+/*-----------------------BPy_GetOccludersF0D type definition ------------------------------*/
+
+PyTypeObject GetOccludersF0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetOccludersF0D", /* tp_name */
+ sizeof(BPy_GetOccludersF0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetOccludersF0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction0DVectorViewShape_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetOccludersF0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.h b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.h
new file mode 100644
index 00000000000..0e92158a2e7
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETOCCLUDERSF0D_H
+#define FREESTYLE_PYTHON_GETOCCLUDERSF0D_H
+
+#include "../BPy_UnaryFunction0DVectorViewShape.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetOccludersF0D_Type;
+
+#define BPy_GetOccludersF0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetOccludersF0D_Type) )
+
+/*---------------------------Python BPy_GetOccludersF0D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction0DVectorViewShape py_uf0D_vectorviewshape;
+} BPy_GetOccludersF0D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETOCCLUDERSF0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.cpp
new file mode 100644
index 00000000000..07fb48dd9a8
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.cpp
@@ -0,0 +1,289 @@
+#include "BPy_UnaryFunction1DDouble.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_Interface1D.h"
+#include "../BPy_IntegrationType.h"
+
+#include "UnaryFunction1D_double/BPy_Curvature2DAngleF1D.h"
+#include "UnaryFunction1D_double/BPy_DensityF1D.h"
+#include "UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.h"
+#include "UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.h"
+#include "UnaryFunction1D_double/BPy_GetProjectedXF1D.h"
+#include "UnaryFunction1D_double/BPy_GetProjectedYF1D.h"
+#include "UnaryFunction1D_double/BPy_GetProjectedZF1D.h"
+#include "UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.h"
+#include "UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.h"
+#include "UnaryFunction1D_double/BPy_GetXF1D.h"
+#include "UnaryFunction1D_double/BPy_GetYF1D.h"
+#include "UnaryFunction1D_double/BPy_GetZF1D.h"
+#include "UnaryFunction1D_double/BPy_LocalAverageDepthF1D.h"
+#include "UnaryFunction1D_double/BPy_ZDiscontinuityF1D.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction1DDouble_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction1DDouble_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction1DDouble_Type );
+ PyModule_AddObject(module, "UnaryFunction1DDouble", (PyObject *)&UnaryFunction1DDouble_Type);
+
+ if( PyType_Ready( &DensityF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &DensityF1D_Type );
+ PyModule_AddObject(module, "DensityF1D", (PyObject *)&DensityF1D_Type);
+
+ if( PyType_Ready( &Curvature2DAngleF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Curvature2DAngleF1D_Type );
+ PyModule_AddObject(module, "Curvature2DAngleF1D", (PyObject *)&Curvature2DAngleF1D_Type);
+
+ if( PyType_Ready( &GetCompleteViewMapDensityF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetCompleteViewMapDensityF1D_Type );
+ PyModule_AddObject(module, "GetCompleteViewMapDensityF1D", (PyObject *)&GetCompleteViewMapDensityF1D_Type);
+
+ if( PyType_Ready( &GetDirectionalViewMapDensityF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetDirectionalViewMapDensityF1D_Type );
+ PyModule_AddObject(module, "GetDirectionalViewMapDensityF1D", (PyObject *)&GetDirectionalViewMapDensityF1D_Type);
+
+ if( PyType_Ready( &GetProjectedXF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetProjectedXF1D_Type );
+ PyModule_AddObject(module, "GetProjectedXF1D", (PyObject *)&GetProjectedXF1D_Type);
+
+ if( PyType_Ready( &GetProjectedYF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetProjectedYF1D_Type );
+ PyModule_AddObject(module, "GetProjectedYF1D", (PyObject *)&GetProjectedYF1D_Type);
+
+ if( PyType_Ready( &GetProjectedZF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetProjectedZF1D_Type );
+ PyModule_AddObject(module, "GetProjectedZF1D", (PyObject *)&GetProjectedZF1D_Type);
+
+ if( PyType_Ready( &GetSteerableViewMapDensityF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetSteerableViewMapDensityF1D_Type );
+ PyModule_AddObject(module, "GetSteerableViewMapDensityF1D", (PyObject *)&GetSteerableViewMapDensityF1D_Type);
+
+ if( PyType_Ready( &GetViewMapGradientNormF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetViewMapGradientNormF1D_Type );
+ PyModule_AddObject(module, "GetViewMapGradientNormF1D", (PyObject *)&GetViewMapGradientNormF1D_Type);
+
+ if( PyType_Ready( &GetXF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetXF1D_Type );
+ PyModule_AddObject(module, "GetXF1D", (PyObject *)&GetXF1D_Type);
+
+ if( PyType_Ready( &GetYF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetYF1D_Type );
+ PyModule_AddObject(module, "GetYF1D", (PyObject *)&GetYF1D_Type);
+
+ if( PyType_Ready( &GetZF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetZF1D_Type );
+ PyModule_AddObject(module, "GetZF1D", (PyObject *)&GetZF1D_Type);
+
+ if( PyType_Ready( &LocalAverageDepthF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &LocalAverageDepthF1D_Type );
+ PyModule_AddObject(module, "LocalAverageDepthF1D", (PyObject *)&LocalAverageDepthF1D_Type);
+
+ if( PyType_Ready( &ZDiscontinuityF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ZDiscontinuityF1D_Type );
+ PyModule_AddObject(module, "ZDiscontinuityF1D", (PyObject *)&ZDiscontinuityF1D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction1DDouble___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface1D` and return a float value.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(integration)\n"
+"\n"
+" Builds a unary 1D function using the integration method given as\n"
+" argument.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static int UnaryFunction1DDouble___init__(BPy_UnaryFunction1DDouble* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ if( !obj )
+ self->uf1D_double = new UnaryFunction1D<double>();
+ else {
+ self->uf1D_double = new UnaryFunction1D<double>( IntegrationType_from_BPy_IntegrationType(obj) );
+ }
+
+ self->uf1D_double->py_uf1D = (PyObject *)self;
+
+ return 0;
+}
+
+static void UnaryFunction1DDouble___dealloc__(BPy_UnaryFunction1DDouble* self)
+{
+ if (self->uf1D_double)
+ delete self->uf1D_double;
+ UnaryFunction1D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction1DDouble___repr__(BPy_UnaryFunction1DDouble* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf1D_double->getName().c_str(), self->uf1D_double );
+}
+
+static char UnaryFunction1DDouble_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 1D function.\n"
+"\n"
+" :return: The name of the unary 1D function.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction1DDouble_getName( BPy_UnaryFunction1DDouble *self )
+{
+ return PyUnicode_FromString( self->uf1D_double->getName().c_str() );
+}
+
+static PyObject * UnaryFunction1DDouble___call__( BPy_UnaryFunction1DDouble *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if( !PyArg_ParseTuple(args, "O!", &Interface1D_Type, &obj) )
+ return NULL;
+
+ if( typeid(*(self->uf1D_double)) == typeid(UnaryFunction1D<double>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf1D_double->operator()(*( ((BPy_Interface1D *) obj)->if1D )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf1D_double->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return PyFloat_FromDouble( self->uf1D_double->result );
+
+}
+
+static char UnaryFunction1DDouble_setIntegrationType___doc__[] =
+".. method:: setIntegrationType(integration)\n"
+"\n"
+" Sets the integration method.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DDouble_setIntegrationType(BPy_UnaryFunction1DDouble* self, PyObject *args)
+{
+ PyObject *obj;
+
+ if( !PyArg_ParseTuple(args, "O!", &IntegrationType_Type, &obj) )
+ return NULL;
+
+ self->uf1D_double->setIntegrationType( IntegrationType_from_BPy_IntegrationType(obj) );
+ Py_RETURN_NONE;
+}
+
+static char UnaryFunction1DDouble_getIntegrationType___doc__[] =
+".. method:: getIntegrationType(integration)\n"
+"\n"
+" Returns the integration method.\n"
+"\n"
+" :return: The integration method.\n"
+" :rtype: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DDouble_getIntegrationType(BPy_UnaryFunction1DDouble* self) {
+ return BPy_IntegrationType_from_IntegrationType( self->uf1D_double->getIntegrationType() );
+}
+
+/*----------------------UnaryFunction1DDouble instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction1DDouble_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction1DDouble_getName, METH_NOARGS, UnaryFunction1DDouble_getName___doc__},
+ {"setIntegrationType", ( PyCFunction ) UnaryFunction1DDouble_setIntegrationType, METH_VARARGS, UnaryFunction1DDouble_setIntegrationType___doc__},
+ {"getIntegrationType", ( PyCFunction ) UnaryFunction1DDouble_getIntegrationType, METH_NOARGS, UnaryFunction1DDouble_getIntegrationType___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction1DDouble type definition ------------------------------*/
+
+PyTypeObject UnaryFunction1DDouble_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction1DDouble", /* tp_name */
+ sizeof(BPy_UnaryFunction1DDouble), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction1DDouble___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction1DDouble___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction1DDouble___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction1DDouble___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction1DDouble_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction1DDouble___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.h b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.h
new file mode 100644
index 00000000000..9a9170cfe17
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION1DDOUBLE_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION1DDOUBLE_H
+
+#include "../BPy_UnaryFunction1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction1DDouble_Type;
+
+#define BPy_UnaryFunction1DDouble_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction1DDouble_Type) )
+
+/*---------------------------Python BPy_UnaryFunction1DDouble structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1D py_uf1D;
+ UnaryFunction1D<double> *uf1D_double;
+} BPy_UnaryFunction1DDouble;
+
+/*---------------------------Python BPy_UnaryFunction1DDouble visible prototypes-----------*/
+int UnaryFunction1DDouble_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION1DDOUBLE_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.cpp
new file mode 100644
index 00000000000..4f6a672857a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.cpp
@@ -0,0 +1,210 @@
+#include "BPy_UnaryFunction1DEdgeNature.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_Interface1D.h"
+#include "../BPy_IntegrationType.h"
+
+#include "UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction1DEdgeNature_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction1DEdgeNature_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction1DEdgeNature_Type );
+ PyModule_AddObject(module, "UnaryFunction1DEdgeNature", (PyObject *)&UnaryFunction1DEdgeNature_Type);
+
+ if( PyType_Ready( &CurveNatureF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &CurveNatureF1D_Type );
+ PyModule_AddObject(module, "CurveNatureF1D", (PyObject *)&CurveNatureF1D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction1DEdgeNature___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DEdgeNature`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface1D` and return a :class:`Nature` object.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(integration)\n"
+"\n"
+" Builds a unary 1D function using the integration method given as\n"
+" argument.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static int UnaryFunction1DEdgeNature___init__(BPy_UnaryFunction1DEdgeNature* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ if( !obj )
+ self->uf1D_edgenature = new UnaryFunction1D<Nature::EdgeNature>();
+ else {
+ self->uf1D_edgenature = new UnaryFunction1D<Nature::EdgeNature>( IntegrationType_from_BPy_IntegrationType(obj) );
+ }
+
+ self->uf1D_edgenature->py_uf1D = (PyObject *)self;
+
+ return 0;
+}
+
+static void UnaryFunction1DEdgeNature___dealloc__(BPy_UnaryFunction1DEdgeNature* self)
+{
+ if (self->uf1D_edgenature)
+ delete self->uf1D_edgenature;
+ UnaryFunction1D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction1DEdgeNature___repr__(BPy_UnaryFunction1DEdgeNature* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf1D_edgenature->getName().c_str(), self->uf1D_edgenature );
+}
+
+static char UnaryFunction1DEdgeNature_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 1D function.\n"
+"\n"
+" :return: The name of the unary 1D function.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction1DEdgeNature_getName( BPy_UnaryFunction1DEdgeNature *self )
+{
+ return PyUnicode_FromString( self->uf1D_edgenature->getName().c_str() );
+}
+
+static PyObject * UnaryFunction1DEdgeNature___call__( BPy_UnaryFunction1DEdgeNature *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if( !PyArg_ParseTuple(args, "O!", &Interface1D_Type, &obj) )
+ return NULL;
+
+ if( typeid(*(self->uf1D_edgenature)) == typeid(UnaryFunction1D<Nature::EdgeNature>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf1D_edgenature->operator()(*( ((BPy_Interface1D *) obj)->if1D )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf1D_edgenature->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return BPy_Nature_from_Nature( self->uf1D_edgenature->result );
+
+}
+
+static char UnaryFunction1DEdgeNature_setIntegrationType___doc__[] =
+".. method:: setIntegrationType(integration)\n"
+"\n"
+" Sets the integration method.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DEdgeNature_setIntegrationType(BPy_UnaryFunction1DEdgeNature* self, PyObject *args)
+{
+ PyObject *obj;
+
+ if( !PyArg_ParseTuple(args, "O!", &IntegrationType_Type, &obj) )
+ return NULL;
+
+ self->uf1D_edgenature->setIntegrationType( IntegrationType_from_BPy_IntegrationType(obj) );
+ Py_RETURN_NONE;
+}
+
+static char UnaryFunction1DEdgeNature_getIntegrationType___doc__[] =
+".. method:: getIntegrationType(integration)\n"
+"\n"
+" Returns the integration method.\n"
+"\n"
+" :return: The integration method.\n"
+" :rtype: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DEdgeNature_getIntegrationType(BPy_UnaryFunction1DEdgeNature* self) {
+ return BPy_IntegrationType_from_IntegrationType( self->uf1D_edgenature->getIntegrationType() );
+}
+
+/*----------------------UnaryFunction1DEdgeNature instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction1DEdgeNature_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction1DEdgeNature_getName, METH_NOARGS, UnaryFunction1DEdgeNature_getName___doc__},
+ {"setIntegrationType", ( PyCFunction ) UnaryFunction1DEdgeNature_setIntegrationType, METH_VARARGS, UnaryFunction1DEdgeNature_setIntegrationType___doc__},
+ {"getIntegrationType", ( PyCFunction ) UnaryFunction1DEdgeNature_getIntegrationType, METH_NOARGS, UnaryFunction1DEdgeNature_getIntegrationType___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction1DEdgeNature type definition ------------------------------*/
+
+PyTypeObject UnaryFunction1DEdgeNature_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction1DEdgeNature", /* tp_name */
+ sizeof(BPy_UnaryFunction1DEdgeNature), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction1DEdgeNature___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction1DEdgeNature___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction1DEdgeNature___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction1DEdgeNature___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction1DEdgeNature_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction1DEdgeNature___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.h b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.h
new file mode 100644
index 00000000000..05e3e522c4b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.h
@@ -0,0 +1,36 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION1DEDGENATURE_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION1DEDGENATURE_H
+
+#include "../BPy_UnaryFunction1D.h"
+
+#include "../../winged_edge/Nature.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction1DEdgeNature_Type;
+
+#define BPy_UnaryFunction1DEdgeNature_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction1DEdgeNature_Type) )
+
+/*---------------------------Python BPy_UnaryFunction1DEdgeNature structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1D py_uf1D;
+ UnaryFunction1D<Nature::EdgeNature> *uf1D_edgenature;
+} BPy_UnaryFunction1DEdgeNature;
+
+/*---------------------------Python BPy_UnaryFunction1DEdgeNature visible prototypes-----------*/
+int UnaryFunction1DEdgeNature_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION1DEDGENATURE_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.cpp
new file mode 100644
index 00000000000..9f16ed9ce36
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.cpp
@@ -0,0 +1,203 @@
+#include "BPy_UnaryFunction1DFloat.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_Interface1D.h"
+#include "../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction1DFloat_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction1DFloat_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction1DFloat_Type );
+ PyModule_AddObject(module, "UnaryFunction1DFloat", (PyObject *)&UnaryFunction1DFloat_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction1DFloat___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DFloat`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface1D` and return a float value.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(integration)\n"
+"\n"
+" Builds a unary 1D function using the integration method given as\n"
+" argument.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static int UnaryFunction1DFloat___init__(BPy_UnaryFunction1DFloat* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ if( !obj )
+ self->uf1D_float = new UnaryFunction1D<float>();
+ else {
+ self->uf1D_float = new UnaryFunction1D<float>( IntegrationType_from_BPy_IntegrationType(obj) );
+ }
+
+ self->uf1D_float->py_uf1D = (PyObject *)self;
+
+ return 0;
+}
+
+static void UnaryFunction1DFloat___dealloc__(BPy_UnaryFunction1DFloat* self)
+{
+ if (self->uf1D_float)
+ delete self->uf1D_float;
+ UnaryFunction1D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction1DFloat___repr__(BPy_UnaryFunction1DFloat* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf1D_float->getName().c_str(), self->uf1D_float );
+}
+
+static char UnaryFunction1DFloat_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 1D function.\n"
+"\n"
+" :return: The name of the unary 1D function.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction1DFloat_getName( BPy_UnaryFunction1DFloat *self )
+{
+ return PyUnicode_FromString( self->uf1D_float->getName().c_str() );
+}
+
+static PyObject * UnaryFunction1DFloat___call__( BPy_UnaryFunction1DFloat *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if( !PyArg_ParseTuple(args, "O!", &Interface1D_Type, &obj) )
+ return NULL;
+
+ if( typeid(*(self->uf1D_float)) == typeid(UnaryFunction1D<float>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf1D_float->operator()(*( ((BPy_Interface1D *) obj)->if1D )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf1D_float->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return PyFloat_FromDouble( self->uf1D_float->result );
+
+}
+
+static char UnaryFunction1DFloat_setIntegrationType___doc__[] =
+".. method:: setIntegrationType(integration)\n"
+"\n"
+" Sets the integration method.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DFloat_setIntegrationType(BPy_UnaryFunction1DFloat* self, PyObject *args)
+{
+ PyObject *obj;
+
+ if( !PyArg_ParseTuple(args, "O!", &IntegrationType_Type, &obj) )
+ return NULL;
+
+ self->uf1D_float->setIntegrationType( IntegrationType_from_BPy_IntegrationType(obj) );
+ Py_RETURN_NONE;
+}
+
+static char UnaryFunction1DFloat_getIntegrationType___doc__[] =
+".. method:: getIntegrationType(integration)\n"
+"\n"
+" Returns the integration method.\n"
+"\n"
+" :return: The integration method.\n"
+" :rtype: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DFloat_getIntegrationType(BPy_UnaryFunction1DFloat* self) {
+ return BPy_IntegrationType_from_IntegrationType( self->uf1D_float->getIntegrationType() );
+}
+
+/*----------------------UnaryFunction1DFloat instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction1DFloat_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction1DFloat_getName, METH_NOARGS, UnaryFunction1DFloat_getName___doc__},
+ {"setIntegrationType", ( PyCFunction ) UnaryFunction1DFloat_setIntegrationType, METH_VARARGS, UnaryFunction1DFloat_setIntegrationType___doc__},
+ {"getIntegrationType", ( PyCFunction ) UnaryFunction1DFloat_getIntegrationType, METH_NOARGS, UnaryFunction1DFloat_getIntegrationType___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction1DFloat type definition ------------------------------*/
+
+PyTypeObject UnaryFunction1DFloat_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction1DFloat", /* tp_name */
+ sizeof(BPy_UnaryFunction1DFloat), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction1DFloat___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction1DFloat___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction1DFloat___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction1DFloat___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction1DFloat_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction1DFloat___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.h b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.h
new file mode 100644
index 00000000000..529b382372e
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION1DFLOAT_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION1DFLOAT_H
+
+#include "../BPy_UnaryFunction1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction1DFloat_Type;
+
+#define BPy_UnaryFunction1DFloat_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction1DFloat_Type) )
+
+/*---------------------------Python BPy_UnaryFunction1DFloat structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1D py_uf1D;
+ UnaryFunction1D<float> *uf1D_float;
+} BPy_UnaryFunction1DFloat;
+
+/*---------------------------Python BPy_UnaryFunction1DFloat visible prototypes-----------*/
+int UnaryFunction1DFloat_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION1DFLOAT_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp
new file mode 100644
index 00000000000..98615728c63
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp
@@ -0,0 +1,210 @@
+#include "BPy_UnaryFunction1DUnsigned.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_Interface1D.h"
+#include "../BPy_IntegrationType.h"
+
+#include "UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction1DUnsigned_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction1DUnsigned_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction1DUnsigned_Type );
+ PyModule_AddObject(module, "UnaryFunction1DUnsigned", (PyObject *)&UnaryFunction1DUnsigned_Type);
+
+ if( PyType_Ready( &QuantitativeInvisibilityF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &QuantitativeInvisibilityF1D_Type );
+ PyModule_AddObject(module, "QuantitativeInvisibilityF1D", (PyObject *)&QuantitativeInvisibilityF1D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction1DUnsigned___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DUnsigned`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface1D` and return an int value.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(integration)\n"
+"\n"
+" Builds a unary 1D function using the integration method given as\n"
+" argument.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static int UnaryFunction1DUnsigned___init__(BPy_UnaryFunction1DUnsigned* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ if( !obj )
+ self->uf1D_unsigned = new UnaryFunction1D<unsigned int>();
+ else {
+ self->uf1D_unsigned = new UnaryFunction1D<unsigned int>( IntegrationType_from_BPy_IntegrationType(obj) );
+ }
+
+ self->uf1D_unsigned->py_uf1D = (PyObject *)self;
+
+ return 0;
+}
+
+static void UnaryFunction1DUnsigned___dealloc__(BPy_UnaryFunction1DUnsigned* self)
+{
+ if (self->uf1D_unsigned)
+ delete self->uf1D_unsigned;
+ UnaryFunction1D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction1DUnsigned___repr__(BPy_UnaryFunction1DUnsigned* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf1D_unsigned->getName().c_str(), self->uf1D_unsigned );
+}
+
+static char UnaryFunction1DUnsigned_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 1D function.\n"
+"\n"
+" :return: The name of the unary 1D function.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction1DUnsigned_getName( BPy_UnaryFunction1DUnsigned *self )
+{
+ return PyUnicode_FromString( self->uf1D_unsigned->getName().c_str() );
+}
+
+static PyObject * UnaryFunction1DUnsigned___call__( BPy_UnaryFunction1DUnsigned *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if( !PyArg_ParseTuple(args, "O!", &Interface1D_Type, &obj) )
+ return NULL;
+
+ if( typeid(*(self->uf1D_unsigned)) == typeid(UnaryFunction1D<unsigned int>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf1D_unsigned->operator()(*( ((BPy_Interface1D *) obj)->if1D )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf1D_unsigned->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return PyLong_FromLong( self->uf1D_unsigned->result );
+
+}
+
+static char UnaryFunction1DUnsigned_setIntegrationType___doc__[] =
+".. method:: setIntegrationType(integration)\n"
+"\n"
+" Sets the integration method.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DUnsigned_setIntegrationType(BPy_UnaryFunction1DUnsigned* self, PyObject *args)
+{
+ PyObject *obj;
+
+ if( !PyArg_ParseTuple(args, "O!", &IntegrationType_Type, &obj) )
+ return NULL;
+
+ self->uf1D_unsigned->setIntegrationType( IntegrationType_from_BPy_IntegrationType(obj) );
+ Py_RETURN_NONE;
+}
+
+static char UnaryFunction1DUnsigned_getIntegrationType___doc__[] =
+".. method:: getIntegrationType(integration)\n"
+"\n"
+" Returns the integration method.\n"
+"\n"
+" :return: The integration method.\n"
+" :rtype: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DUnsigned_getIntegrationType(BPy_UnaryFunction1DUnsigned* self) {
+ return BPy_IntegrationType_from_IntegrationType( self->uf1D_unsigned->getIntegrationType() );
+}
+
+/*----------------------UnaryFunction1DUnsigned instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction1DUnsigned_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction1DUnsigned_getName, METH_NOARGS, UnaryFunction1DUnsigned_getName___doc__},
+ {"setIntegrationType", ( PyCFunction ) UnaryFunction1DUnsigned_setIntegrationType, METH_VARARGS, UnaryFunction1DUnsigned_setIntegrationType___doc__},
+ {"getIntegrationType", ( PyCFunction ) UnaryFunction1DUnsigned_getIntegrationType, METH_NOARGS, UnaryFunction1DUnsigned_getIntegrationType___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction1DUnsigned type definition ------------------------------*/
+
+PyTypeObject UnaryFunction1DUnsigned_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction1DUnsigned", /* tp_name */
+ sizeof(BPy_UnaryFunction1DUnsigned), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction1DUnsigned___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction1DUnsigned___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction1DUnsigned___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction1DUnsigned___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction1DUnsigned_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction1DUnsigned___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.h b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.h
new file mode 100644
index 00000000000..c70cc6257a7
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION1DUNSIGNED_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION1DUNSIGNED_H
+
+#include "../BPy_UnaryFunction1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction1DUnsigned_Type;
+
+#define BPy_UnaryFunction1DUnsigned_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction1DUnsigned_Type) )
+
+/*---------------------------Python BPy_UnaryFunction1DUnsigned structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1D py_uf1D;
+ UnaryFunction1D<unsigned int> *uf1D_unsigned;
+} BPy_UnaryFunction1DUnsigned;
+
+/*---------------------------Python BPy_UnaryFunction1DUnsigned visible prototypes-----------*/
+int UnaryFunction1DUnsigned_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION1DUNSIGNED_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.cpp
new file mode 100644
index 00000000000..9f2c52c6f44
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.cpp
@@ -0,0 +1,216 @@
+#include "BPy_UnaryFunction1DVec2f.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_Interface1D.h"
+#include "../BPy_IntegrationType.h"
+
+#include "UnaryFunction1D_Vec2f/BPy_Normal2DF1D.h"
+#include "UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction1DVec2f_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction1DVec2f_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction1DVec2f_Type );
+ PyModule_AddObject(module, "UnaryFunction1DVec2f", (PyObject *)&UnaryFunction1DVec2f_Type);
+
+ if( PyType_Ready( &Normal2DF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Normal2DF1D_Type );
+ PyModule_AddObject(module, "Normal2DF1D", (PyObject *)&Normal2DF1D_Type);
+
+ if( PyType_Ready( &Orientation2DF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Orientation2DF1D_Type );
+ PyModule_AddObject(module, "Orientation2DF1D", (PyObject *)&Orientation2DF1D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction1DVec2f___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVec2f`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface1D` and return a 2D vector.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(integration)\n"
+"\n"
+" Builds a unary 1D function using the integration method given as\n"
+" argument.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static int UnaryFunction1DVec2f___init__(BPy_UnaryFunction1DVec2f* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ if( !obj )
+ self->uf1D_vec2f = new UnaryFunction1D<Vec2f>();
+ else {
+ self->uf1D_vec2f = new UnaryFunction1D<Vec2f>( IntegrationType_from_BPy_IntegrationType(obj) );
+ }
+
+ self->uf1D_vec2f->py_uf1D = (PyObject *)self;
+
+ return 0;
+}
+
+static void UnaryFunction1DVec2f___dealloc__(BPy_UnaryFunction1DVec2f* self)
+{
+ if (self->uf1D_vec2f)
+ delete self->uf1D_vec2f;
+ UnaryFunction1D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction1DVec2f___repr__(BPy_UnaryFunction1DVec2f* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf1D_vec2f->getName().c_str(), self->uf1D_vec2f );
+}
+
+static char UnaryFunction1DVec2f_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 1D function.\n"
+"\n"
+" :return: The name of the unary 1D function.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction1DVec2f_getName( BPy_UnaryFunction1DVec2f *self )
+{
+ return PyUnicode_FromString( self->uf1D_vec2f->getName().c_str() );
+}
+
+static PyObject * UnaryFunction1DVec2f___call__( BPy_UnaryFunction1DVec2f *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if( !PyArg_ParseTuple(args, "O!", &Interface1D_Type, &obj) )
+ return NULL;
+
+ if( typeid(*(self->uf1D_vec2f)) == typeid(UnaryFunction1D<Vec2f>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf1D_vec2f->operator()(*( ((BPy_Interface1D *) obj)->if1D )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf1D_vec2f->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return Vector_from_Vec2f( self->uf1D_vec2f->result );
+
+}
+
+static char UnaryFunction1DVec2f_setIntegrationType___doc__[] =
+".. method:: setIntegrationType(integration)\n"
+"\n"
+" Sets the integration method.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DVec2f_setIntegrationType(BPy_UnaryFunction1DVec2f* self, PyObject *args)
+{
+ PyObject *obj;
+
+ if( !PyArg_ParseTuple(args, "O!", &IntegrationType_Type, &obj) )
+ return NULL;
+
+ self->uf1D_vec2f->setIntegrationType( IntegrationType_from_BPy_IntegrationType(obj) );
+ Py_RETURN_NONE;
+}
+
+static char UnaryFunction1DVec2f_getIntegrationType___doc__[] =
+".. method:: getIntegrationType(integration)\n"
+"\n"
+" Returns the integration method.\n"
+"\n"
+" :return: The integration method.\n"
+" :rtype: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DVec2f_getIntegrationType(BPy_UnaryFunction1DVec2f* self) {
+ return BPy_IntegrationType_from_IntegrationType( self->uf1D_vec2f->getIntegrationType() );
+}
+
+/*----------------------UnaryFunction1DVec2f instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction1DVec2f_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction1DVec2f_getName, METH_NOARGS, UnaryFunction1DVec2f_getName___doc__},
+ {"setIntegrationType", ( PyCFunction ) UnaryFunction1DVec2f_setIntegrationType, METH_VARARGS, UnaryFunction1DVec2f_setIntegrationType___doc__},
+ {"getIntegrationType", ( PyCFunction ) UnaryFunction1DVec2f_getIntegrationType, METH_NOARGS, UnaryFunction1DVec2f_getIntegrationType___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction1DVec2f type definition ------------------------------*/
+
+PyTypeObject UnaryFunction1DVec2f_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction1DVec2f", /* tp_name */
+ sizeof(BPy_UnaryFunction1DVec2f), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction1DVec2f___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction1DVec2f___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction1DVec2f___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction1DVec2f___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction1DVec2f_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction1DVec2f___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.h b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.h
new file mode 100644
index 00000000000..64a616e211a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.h
@@ -0,0 +1,37 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION1DVEC2F_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION1DVEC2F_H
+
+#include "../BPy_UnaryFunction1D.h"
+
+#include "../../geometry/Geom.h"
+using namespace Geometry;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction1DVec2f_Type;
+
+#define BPy_UnaryFunction1DVec2f_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction1DVec2f_Type) )
+
+/*---------------------------Python BPy_UnaryFunction1DVec2f structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1D py_uf1D;
+ UnaryFunction1D<Vec2f> *uf1D_vec2f;
+} BPy_UnaryFunction1DVec2f;
+
+/*---------------------------Python BPy_UnaryFunction1DVec2f visible prototypes-----------*/
+int UnaryFunction1DVec2f_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION1DVEC2F_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.cpp
new file mode 100644
index 00000000000..6d50a1ed437
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.cpp
@@ -0,0 +1,210 @@
+#include "BPy_UnaryFunction1DVec3f.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_Interface1D.h"
+#include "../BPy_IntegrationType.h"
+
+#include "UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction1DVec3f_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction1DVec3f_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction1DVec3f_Type );
+ PyModule_AddObject(module, "UnaryFunction1DVec3f", (PyObject *)&UnaryFunction1DVec3f_Type);
+
+ if( PyType_Ready( &Orientation3DF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &Orientation3DF1D_Type );
+ PyModule_AddObject(module, "Orientation3DF1D", (PyObject *)&Orientation3DF1D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction1DVec3f___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVec3f`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface1D` and return a 3D vector.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(integration)\n"
+"\n"
+" Builds a unary 1D function using the integration method given as\n"
+" argument.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static int UnaryFunction1DVec3f___init__(BPy_UnaryFunction1DVec3f* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ if( !obj )
+ self->uf1D_vec3f = new UnaryFunction1D<Vec3f>();
+ else {
+ self->uf1D_vec3f = new UnaryFunction1D<Vec3f>( IntegrationType_from_BPy_IntegrationType(obj) );
+ }
+
+ self->uf1D_vec3f->py_uf1D = (PyObject *)self;
+
+ return 0;
+}
+static void UnaryFunction1DVec3f___dealloc__(BPy_UnaryFunction1DVec3f* self)
+{
+ if (self->uf1D_vec3f)
+ delete self->uf1D_vec3f;
+ UnaryFunction1D_Type.tp_dealloc((PyObject*)self);
+}
+
+
+static PyObject * UnaryFunction1DVec3f___repr__(BPy_UnaryFunction1DVec3f* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf1D_vec3f->getName().c_str(), self->uf1D_vec3f );
+}
+
+static char UnaryFunction1DVec3f_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 1D function.\n"
+"\n"
+" :return: The name of the unary 1D function.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction1DVec3f_getName( BPy_UnaryFunction1DVec3f *self )
+{
+ return PyUnicode_FromString( self->uf1D_vec3f->getName().c_str() );
+}
+
+static PyObject * UnaryFunction1DVec3f___call__( BPy_UnaryFunction1DVec3f *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if( !PyArg_ParseTuple(args, "O!", &Interface1D_Type, &obj) )
+ return NULL;
+
+ if( typeid(*(self->uf1D_vec3f)) == typeid(UnaryFunction1D<Vec3f>) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf1D_vec3f->operator()(*( ((BPy_Interface1D *) obj)->if1D )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf1D_vec3f->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ return Vector_from_Vec3f( self->uf1D_vec3f->result );
+
+}
+
+static char UnaryFunction1DVec3f_setIntegrationType___doc__[] =
+".. method:: setIntegrationType(integration)\n"
+"\n"
+" Sets the integration method.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DVec3f_setIntegrationType(BPy_UnaryFunction1DVec3f* self, PyObject *args)
+{
+ PyObject *obj;
+
+ if( !PyArg_ParseTuple(args, "O!", &IntegrationType_Type, &obj) )
+ return NULL;
+
+ self->uf1D_vec3f->setIntegrationType( IntegrationType_from_BPy_IntegrationType(obj) );
+ Py_RETURN_NONE;
+}
+
+static char UnaryFunction1DVec3f_getIntegrationType___doc__[] =
+".. method:: getIntegrationType(integration)\n"
+"\n"
+" Returns the integration method.\n"
+"\n"
+" :return: The integration method.\n"
+" :rtype: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DVec3f_getIntegrationType(BPy_UnaryFunction1DVec3f* self) {
+ return BPy_IntegrationType_from_IntegrationType( self->uf1D_vec3f->getIntegrationType() );
+}
+
+/*----------------------UnaryFunction1DVec3f instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction1DVec3f_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction1DVec3f_getName, METH_NOARGS, UnaryFunction1DVec3f_getName___doc__},
+ {"setIntegrationType", ( PyCFunction ) UnaryFunction1DVec3f_setIntegrationType, METH_VARARGS, UnaryFunction1DVec3f_setIntegrationType___doc__},
+ {"getIntegrationType", ( PyCFunction ) UnaryFunction1DVec3f_getIntegrationType, METH_NOARGS, UnaryFunction1DVec3f_getIntegrationType___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction1DVec3f type definition ------------------------------*/
+
+PyTypeObject UnaryFunction1DVec3f_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction1DVec3f", /* tp_name */
+ sizeof(BPy_UnaryFunction1DVec3f), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction1DVec3f___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction1DVec3f___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction1DVec3f___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction1DVec3f___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction1DVec3f_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction1DVec3f___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.h b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.h
new file mode 100644
index 00000000000..7730271fc09
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.h
@@ -0,0 +1,37 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION1DVEC3F_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION1DVEC3F_H
+
+#include "../BPy_UnaryFunction1D.h"
+
+#include "../../geometry/Geom.h"
+using namespace Geometry;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction1DVec3f_Type;
+
+#define BPy_UnaryFunction1DVec3f_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction1DVec3f_Type) )
+
+/*---------------------------Python BPy_UnaryFunction1DVec3f structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1D py_uf1D;
+ UnaryFunction1D<Vec3f> *uf1D_vec3f;
+} BPy_UnaryFunction1DVec3f;
+
+/*---------------------------Python BPy_UnaryFunction1DVec3f visible prototypes-----------*/
+int UnaryFunction1DVec3f_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION1DVEC3F_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp
new file mode 100644
index 00000000000..5555f401cbf
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp
@@ -0,0 +1,235 @@
+#include "BPy_UnaryFunction1DVectorViewShape.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_Interface1D.h"
+#include "../BPy_IntegrationType.h"
+
+#include "UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.h"
+#include "UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.h"
+#include "UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction1DVectorViewShape_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction1DVectorViewShape_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction1DVectorViewShape_Type );
+ PyModule_AddObject(module, "UnaryFunction1DVectorViewShape", (PyObject *)&UnaryFunction1DVectorViewShape_Type);
+
+ if( PyType_Ready( &GetOccludeeF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetOccludeeF1D_Type );
+ PyModule_AddObject(module, "GetOccludeeF1D", (PyObject *)&GetOccludeeF1D_Type);
+
+ if( PyType_Ready( &GetOccludersF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetOccludersF1D_Type );
+ PyModule_AddObject(module, "GetOccludersF1D", (PyObject *)&GetOccludersF1D_Type);
+
+ if( PyType_Ready( &GetShapeF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &GetShapeF1D_Type );
+ PyModule_AddObject(module, "GetShapeF1D", (PyObject *)&GetShapeF1D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction1DVectorViewShape___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVectorViewShape`\n"
+"\n"
+"Base class for unary functions (functors) that work on\n"
+":class:`Interface1D` and return a list of :class:`ViewShape`\n"
+"objects.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(integration)\n"
+"\n"
+" Builds a unary 1D function using the integration method given as\n"
+" argument.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static int UnaryFunction1DVectorViewShape___init__(BPy_UnaryFunction1DVectorViewShape* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ if( !obj )
+ self->uf1D_vectorviewshape = new UnaryFunction1D< std::vector<ViewShape*> >();
+ else {
+ self->uf1D_vectorviewshape = new UnaryFunction1D< std::vector<ViewShape*> >( IntegrationType_from_BPy_IntegrationType(obj) );
+ }
+
+ self->uf1D_vectorviewshape->py_uf1D = (PyObject *)self;
+
+ return 0;
+}
+
+static void UnaryFunction1DVectorViewShape___dealloc__(BPy_UnaryFunction1DVectorViewShape* self)
+{
+ if (self->uf1D_vectorviewshape)
+ delete self->uf1D_vectorviewshape;
+ UnaryFunction1D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction1DVectorViewShape___repr__(BPy_UnaryFunction1DVectorViewShape* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf1D_vectorviewshape->getName().c_str(), self->uf1D_vectorviewshape );
+}
+
+static char UnaryFunction1DVectorViewShape_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 1D function.\n"
+"\n"
+" :return: The name of the unary 1D function.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction1DVectorViewShape_getName( BPy_UnaryFunction1DVectorViewShape *self )
+{
+ return PyUnicode_FromString( self->uf1D_vectorviewshape->getName().c_str() );
+}
+
+static PyObject * UnaryFunction1DVectorViewShape___call__( BPy_UnaryFunction1DVectorViewShape *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if( !PyArg_ParseTuple(args, "O!", &Interface1D_Type, &obj) )
+ return NULL;
+
+ if( typeid(*(self->uf1D_vectorviewshape)) == typeid(UnaryFunction1D< std::vector<ViewShape*> >) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf1D_vectorviewshape->operator()(*( ((BPy_Interface1D *) obj)->if1D )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf1D_vectorviewshape->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ PyObject *list = PyList_New(0);
+ PyObject *item;
+ for( unsigned int i = 0; i < self->uf1D_vectorviewshape->result.size(); i++) {
+ ViewShape *v = self->uf1D_vectorviewshape->result[i];
+ if (v) {
+ item = BPy_ViewShape_from_ViewShape(*v);
+ } else {
+ item = Py_None;
+ Py_INCREF(item);
+ }
+ PyList_Append(list, item);
+ }
+
+ return list;
+}
+
+static char UnaryFunction1DVectorViewShape_setIntegrationType___doc__[] =
+".. method:: setIntegrationType(integration)\n"
+"\n"
+" Sets the integration method.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DVectorViewShape_setIntegrationType(BPy_UnaryFunction1DVectorViewShape* self, PyObject *args)
+{
+ PyObject *obj;
+
+ if( !PyArg_ParseTuple(args, "O!", &IntegrationType_Type, &obj) )
+ return NULL;
+
+ self->uf1D_vectorviewshape->setIntegrationType( IntegrationType_from_BPy_IntegrationType(obj) );
+ Py_RETURN_NONE;
+}
+
+static char UnaryFunction1DVectorViewShape_getIntegrationType___doc__[] =
+".. method:: getIntegrationType(integration)\n"
+"\n"
+" Returns the integration method.\n"
+"\n"
+" :return: The integration method.\n"
+" :rtype: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DVectorViewShape_getIntegrationType(BPy_UnaryFunction1DVectorViewShape* self) {
+ return BPy_IntegrationType_from_IntegrationType( self->uf1D_vectorviewshape->getIntegrationType() );
+}
+
+/*----------------------UnaryFunction1DVectorViewShape instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction1DVectorViewShape_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction1DVectorViewShape_getName, METH_NOARGS, UnaryFunction1DVectorViewShape_getName___doc__},
+ {"setIntegrationType", ( PyCFunction ) UnaryFunction1DVectorViewShape_setIntegrationType, METH_VARARGS, UnaryFunction1DVectorViewShape_setIntegrationType___doc__},
+ {"getIntegrationType", ( PyCFunction ) UnaryFunction1DVectorViewShape_getIntegrationType, METH_NOARGS, UnaryFunction1DVectorViewShape_getIntegrationType___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction1DVectorViewShape type definition ------------------------------*/
+
+PyTypeObject UnaryFunction1DVectorViewShape_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction1DVectorViewShape", /* tp_name */
+ sizeof(BPy_UnaryFunction1DVectorViewShape), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction1DVectorViewShape___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction1DVectorViewShape___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction1DVectorViewShape___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction1DVectorViewShape___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction1DVectorViewShape_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction1DVectorViewShape___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.h b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.h
new file mode 100644
index 00000000000..e2321a6107f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.h
@@ -0,0 +1,37 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION1DVECTORVIEWSHAPE_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION1DVECTORVIEWSHAPE_H
+
+#include "../BPy_UnaryFunction1D.h"
+
+#include <vector>
+#include "../../view_map/ViewMap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction1DVectorViewShape_Type;
+
+#define BPy_UnaryFunction1DVectorViewShape_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction1DVectorViewShape_Type) )
+
+/*---------------------------Python BPy_UnaryFunction1DVectorViewShape structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1D py_uf1D;
+ UnaryFunction1D< std::vector<ViewShape*> > *uf1D_vectorviewshape;
+} BPy_UnaryFunction1DVectorViewShape;
+
+/*---------------------------Python BPy_UnaryFunction1DVectorViewShape visible prototypes-----------*/
+int UnaryFunction1DVectorViewShape_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION1DVECTORVIEWSHAPE_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.cpp
new file mode 100644
index 00000000000..f18421d8754
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.cpp
@@ -0,0 +1,222 @@
+#include "BPy_UnaryFunction1DVoid.h"
+
+#include "../BPy_Convert.h"
+#include "../BPy_Interface1D.h"
+#include "../BPy_IntegrationType.h"
+
+#include "UnaryFunction1D_void/BPy_ChainingTimeStampF1D.h"
+#include "UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.h"
+#include "UnaryFunction1D_void/BPy_TimeStampF1D.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//-------------------MODULE INITIALIZATION--------------------------------
+
+int UnaryFunction1DVoid_Init( PyObject *module ) {
+
+ if( module == NULL )
+ return -1;
+
+ if( PyType_Ready( &UnaryFunction1DVoid_Type ) < 0 )
+ return -1;
+ Py_INCREF( &UnaryFunction1DVoid_Type );
+ PyModule_AddObject(module, "UnaryFunction1DVoid", (PyObject *)&UnaryFunction1DVoid_Type);
+
+ if( PyType_Ready( &ChainingTimeStampF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &ChainingTimeStampF1D_Type );
+ PyModule_AddObject(module, "ChainingTimeStampF1D", (PyObject *)&ChainingTimeStampF1D_Type);
+
+ if( PyType_Ready( &IncrementChainingTimeStampF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &IncrementChainingTimeStampF1D_Type );
+ PyModule_AddObject(module, "IncrementChainingTimeStampF1D", (PyObject *)&IncrementChainingTimeStampF1D_Type);
+
+ if( PyType_Ready( &TimeStampF1D_Type ) < 0 )
+ return -1;
+ Py_INCREF( &TimeStampF1D_Type );
+ PyModule_AddObject(module, "TimeStampF1D", (PyObject *)&TimeStampF1D_Type);
+
+ return 0;
+}
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char UnaryFunction1DVoid___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVoid`\n"
+"\n"
+"Base class for unary functions (functors) working on\n"
+":class:`Interface1D`.\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Default constructor.\n"
+"\n"
+".. method:: __init__(integration)\n"
+"\n"
+" Builds a unary 1D function using the integration method given as\n"
+" argument.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static int UnaryFunction1DVoid___init__(BPy_UnaryFunction1DVoid* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ if( !obj )
+ self->uf1D_void = new UnaryFunction1D_void();
+ else {
+ self->uf1D_void = new UnaryFunction1D_void( IntegrationType_from_BPy_IntegrationType(obj) );
+ }
+
+ self->uf1D_void->py_uf1D = (PyObject *)self;
+
+ return 0;
+}
+
+static void UnaryFunction1DVoid___dealloc__(BPy_UnaryFunction1DVoid* self)
+{
+ if (self->uf1D_void)
+ delete self->uf1D_void;
+ UnaryFunction1D_Type.tp_dealloc((PyObject*)self);
+}
+
+static PyObject * UnaryFunction1DVoid___repr__(BPy_UnaryFunction1DVoid* self)
+{
+ return PyUnicode_FromFormat("type: %s - address: %p", self->uf1D_void->getName().c_str(), self->uf1D_void );
+}
+
+static char UnaryFunction1DVoid_getName___doc__[] =
+".. method:: getName()\n"
+"\n"
+" Returns the name of the unary 1D function.\n"
+"\n"
+" :return: The name of the unary 1D function.\n"
+" :rtype: str\n";
+
+static PyObject * UnaryFunction1DVoid_getName( BPy_UnaryFunction1DVoid *self )
+{
+ return PyUnicode_FromString( self->uf1D_void->getName().c_str() );
+}
+
+static PyObject * UnaryFunction1DVoid___call__( BPy_UnaryFunction1DVoid *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *obj;
+
+ if( kwds != NULL ) {
+ PyErr_SetString(PyExc_TypeError, "keyword argument(s) not supported");
+ return NULL;
+ }
+ if( !PyArg_ParseTuple(args, "O!", &Interface1D_Type, &obj) )
+ return NULL;
+
+ if( typeid(*(self->uf1D_void)) == typeid(UnaryFunction1D_void) ) {
+ PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
+ return NULL;
+ }
+ if (self->uf1D_void->operator()(*( ((BPy_Interface1D *) obj)->if1D )) < 0) {
+ if (!PyErr_Occurred()) {
+ string msg(self->uf1D_void->getName() + " __call__ method failed");
+ PyErr_SetString(PyExc_RuntimeError, msg.c_str());
+ }
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static char UnaryFunction1DVoid_setIntegrationType___doc__[] =
+".. method:: setIntegrationType(integration)\n"
+"\n"
+" Sets the integration method.\n"
+"\n"
+" :arg integration: An integration method.\n"
+" :type integration: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DVoid_setIntegrationType(BPy_UnaryFunction1DVoid* self, PyObject *args)
+{
+ PyObject *obj;
+
+ if( !PyArg_ParseTuple(args, "O!", &IntegrationType_Type, &obj) )
+ return NULL;
+
+ self->uf1D_void->setIntegrationType( IntegrationType_from_BPy_IntegrationType(obj) );
+ Py_RETURN_NONE;
+}
+
+static char UnaryFunction1DVoid_getIntegrationType___doc__[] =
+".. method:: getIntegrationType(integration)\n"
+"\n"
+" Returns the integration method.\n"
+"\n"
+" :return: The integration method.\n"
+" :rtype: :class:`IntegrationType`\n";
+
+static PyObject * UnaryFunction1DVoid_getIntegrationType(BPy_UnaryFunction1DVoid* self) {
+ return BPy_IntegrationType_from_IntegrationType( self->uf1D_void->getIntegrationType() );
+}
+
+/*----------------------UnaryFunction1DVoid instance definitions ----------------------------*/
+static PyMethodDef BPy_UnaryFunction1DVoid_methods[] = {
+ {"getName", ( PyCFunction ) UnaryFunction1DVoid_getName, METH_NOARGS, UnaryFunction1DVoid_getName___doc__},
+ {"setIntegrationType", ( PyCFunction ) UnaryFunction1DVoid_setIntegrationType, METH_VARARGS, UnaryFunction1DVoid_setIntegrationType___doc__},
+ {"getIntegrationType", ( PyCFunction ) UnaryFunction1DVoid_getIntegrationType, METH_NOARGS, UnaryFunction1DVoid_getIntegrationType___doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------BPy_UnaryFunction1DVoid type definition ------------------------------*/
+
+PyTypeObject UnaryFunction1DVoid_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "UnaryFunction1DVoid", /* tp_name */
+ sizeof(BPy_UnaryFunction1DVoid), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)UnaryFunction1DVoid___dealloc__, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ (reprfunc)UnaryFunction1DVoid___repr__, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ (ternaryfunc)UnaryFunction1DVoid___call__, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ UnaryFunction1DVoid___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_UnaryFunction1DVoid_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)UnaryFunction1DVoid___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.h b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.h
new file mode 100644
index 00000000000..af907aeec84
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.h
@@ -0,0 +1,34 @@
+#ifndef FREESTYLE_PYTHON_UNARYFUNCTION1DVOID_H
+#define FREESTYLE_PYTHON_UNARYFUNCTION1DVOID_H
+
+#include "../BPy_UnaryFunction1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject UnaryFunction1DVoid_Type;
+
+#define BPy_UnaryFunction1DVoid_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &UnaryFunction1DVoid_Type) )
+
+/*---------------------------Python BPy_UnaryFunction1DVoid structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1D py_uf1D;
+ UnaryFunction1D_void *uf1D_void;
+} BPy_UnaryFunction1DVoid;
+
+/*---------------------------Python BPy_UnaryFunction1DVoid visible prototypes-----------*/
+int UnaryFunction1DVoid_Init( PyObject *module );
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_UNARYFUNCTION1DVOID_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.cpp
new file mode 100644
index 00000000000..a31d96ad1a4
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.cpp
@@ -0,0 +1,99 @@
+#include "BPy_CurveNatureF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char CurveNatureF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DEdgeNature` > :class:`CurveNatureF1D`\n"
+"\n"
+".. method:: __init__(iType=IntegrationType.MEAN)\n"
+"\n"
+" Builds a CurveNatureF1D object.\n"
+"\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the nature of the Interface1D (silhouette, ridge, crease,\n"
+" and so on). Except if the Interface1D is a :class:`ViewEdge`, this\n"
+" result might be ambiguous. Indeed, the Interface1D might result\n"
+" from the gathering of several 1D elements, each one being of a\n"
+" different nature. An integration method, such as the MEAN, might\n"
+" give, in this case, irrelevant results.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The nature of the Interface1D.\n"
+" :rtype: :class:`Nature`\n";
+
+static int CurveNatureF1D___init__( BPy_CurveNatureF1D* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_edgenature.uf1D_edgenature = new Functions1D::CurveNatureF1D(t);
+ return 0;
+}
+
+/*-----------------------BPy_CurveNatureF1D type definition ------------------------------*/
+
+PyTypeObject CurveNatureF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "CurveNatureF1D", /* tp_name */
+ sizeof(BPy_CurveNatureF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ CurveNatureF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DEdgeNature_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)CurveNatureF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.h
new file mode 100644
index 00000000000..852f8937954
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_CURVENATUREF1D_H
+#define FREESTYLE_PYTHON_CURVENATUREF1D_H
+
+#include "../BPy_UnaryFunction1DEdgeNature.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject CurveNatureF1D_Type;
+
+#define BPy_CurveNatureF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &CurveNatureF1D_Type) )
+
+/*---------------------------Python BPy_CurveNatureF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DEdgeNature py_uf1D_edgenature;
+} BPy_CurveNatureF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CURVENATUREF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.cpp
new file mode 100644
index 00000000000..92ba5b05e75
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.cpp
@@ -0,0 +1,94 @@
+#include "BPy_Normal2DF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Normal2DF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVec2f` > :class:`Normal2DF1D`\n"
+"\n"
+".. method:: __init__(iType=IntegrationType.MEAN)\n"
+"\n"
+" Builds a Normal2DF1D object.\n"
+"\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the 2D normal for the Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The 2D normal for the Interface1D.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static int Normal2DF1D___init__( BPy_Normal2DF1D* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_vec2f.uf1D_vec2f = new Functions1D::Normal2DF1D(t);
+ return 0;
+}
+
+/*-----------------------BPy_Normal2DF1D type definition ------------------------------*/
+
+PyTypeObject Normal2DF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Normal2DF1D", /* tp_name */
+ sizeof(BPy_Normal2DF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Normal2DF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DVec2f_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Normal2DF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.h
new file mode 100644
index 00000000000..32078558d0c
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_NORMAL2DF1D_H
+#define FREESTYLE_PYTHON_NORMAL2DF1D_H
+
+#include "../BPy_UnaryFunction1DVec2f.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject Normal2DF1D_Type;
+
+#define BPy_Normal2DF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Normal2DF1D_Type) )
+
+/*---------------------------Python BPy_Normal2DF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DVec2f py_uf1D_vec2f;
+} BPy_Normal2DF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_NORMAL2DF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.cpp
new file mode 100644
index 00000000000..a1b87b9cf17
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.cpp
@@ -0,0 +1,96 @@
+#include "BPy_Orientation2DF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Orientation2DF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVec2f` > :class:`Orientation2DF1D`\n"
+"\n"
+".. method:: __init__(iType=IntegrationType.MEAN)\n"
+"\n"
+" Builds an Orientation2DF1D object.\n"
+"\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the 2D orientation of the Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The 2D orientation of the Interface1D.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static int Orientation2DF1D___init__( BPy_Orientation2DF1D* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_vec2f.uf1D_vec2f = new Functions1D::Orientation2DF1D(t);
+ return 0;
+
+}
+
+
+/*-----------------------BPy_Orientation2DF1D type definition ------------------------------*/
+
+PyTypeObject Orientation2DF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Orientation2DF1D", /* tp_name */
+ sizeof(BPy_Orientation2DF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Orientation2DF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DVec2f_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Orientation2DF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.h
new file mode 100644
index 00000000000..189ab04db4f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_ORIENTATION2DF1D_H
+#define FREESTYLE_PYTHON_ORIENTATION2DF1D_H
+
+#include "../BPy_UnaryFunction1DVec2f.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject Orientation2DF1D_Type;
+
+#define BPy_Orientation2DF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Orientation2DF1D_Type) )
+
+/*---------------------------Python BPy_Orientation2DF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DVec2f py_uf1D_vec2f;
+} BPy_Orientation2DF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_ORIENTATION2DF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.cpp
new file mode 100644
index 00000000000..a55c1f7a542
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.cpp
@@ -0,0 +1,94 @@
+#include "BPy_Orientation3DF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Orientation3DF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVec3f` > :class:`Orientation3DF1D`\n"
+"\n"
+".. method:: __init__(iType=IntegrationType.MEAN)\n"
+"\n"
+" Builds an Orientation3DF1D object.\n"
+"\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the 3D orientation of the Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The 3D orientation of the Interface1D.\n"
+" :rtype: :class:`mathutils.Vector`\n";
+
+static int Orientation3DF1D___init__( BPy_Orientation3DF1D* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_vec3f.uf1D_vec3f = new Functions1D::Orientation3DF1D(t);
+ return 0;
+}
+
+/*-----------------------BPy_Orientation3DF1D type definition ------------------------------*/
+
+PyTypeObject Orientation3DF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Orientation3DF1D", /* tp_name */
+ sizeof(BPy_Orientation3DF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Orientation3DF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DVec3f_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Orientation3DF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.h
new file mode 100644
index 00000000000..b69baf106f4
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_ORIENTATION3DF1D_H
+#define FREESTYLE_PYTHON_ORIENTATION3DF1D_H
+
+#include "../BPy_UnaryFunction1DVec3f.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject Orientation3DF1D_Type;
+
+#define BPy_Orientation3DF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Orientation3DF1D_Type) )
+
+/*---------------------------Python BPy_Orientation3DF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DVec3f py_uf1D_vec3f;
+} BPy_Orientation3DF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_ORIENTATION3DF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.cpp
new file mode 100644
index 00000000000..aec76c2888c
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.cpp
@@ -0,0 +1,94 @@
+#include "BPy_Curvature2DAngleF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char Curvature2DAngleF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`Curvature2DAngleF1D`\n"
+"\n"
+".. method:: __init__(iType=IntegrationType.MEAN)\n"
+"\n"
+" Builds a Curvature2DAngleF1D object.\n"
+"\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the 2D curvature as an angle for an Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The 2D curvature as an angle.\n"
+" :rtype: float\n";
+
+static int Curvature2DAngleF1D___init__( BPy_Curvature2DAngleF1D* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::Curvature2DAngleF1D(t);
+ return 0;
+
+}
+/*-----------------------BPy_Curvature2DAngleF1D type definition ------------------------------*/
+
+PyTypeObject Curvature2DAngleF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "Curvature2DAngleF1D", /* tp_name */
+ sizeof(BPy_Curvature2DAngleF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ Curvature2DAngleF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Curvature2DAngleF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.h
new file mode 100644
index 00000000000..1603a7dc4ea
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_CURVATURE2DANGLEF1D_H
+#define FREESTYLE_PYTHON_CURVATURE2DANGLEF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject Curvature2DAngleF1D_Type;
+
+#define BPy_Curvature2DAngleF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &Curvature2DAngleF1D_Type) )
+
+/*---------------------------Python BPy_Curvature2DAngleF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_Curvature2DAngleF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CURVATURE2DANGLEF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.cpp
new file mode 100644
index 00000000000..360f98fa361
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.cpp
@@ -0,0 +1,109 @@
+#include "BPy_DensityF1D.h"
+
+#include "../../../stroke/AdvancedFunctions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char DensityF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`DensityF1D`\n"
+"\n"
+".. method:: __init__(sigma=2.0, iType=IntegrationType.MEAN, sampling=2.0)\n"
+"\n"
+" Builds a DensityF1D object.\n"
+"\n"
+" :arg sigma: The sigma used in DensityF0D and determining the window size\n"
+" used in each density query.\n"
+" :type sigma: float\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+" :arg sampling: The resolution used to sample the chain: the\n"
+" corresponding 0D function is evaluated at each sample point and\n"
+" the result is obtained by combining the resulting values into a\n"
+" single one, following the method specified by iType.\n"
+" :type sampling: float\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the density evaluated for an Interface1D. The density is\n"
+" evaluated for a set of points along the Interface1D (using the\n"
+" :class:`DensityF0D` functor) with a user-defined sampling and then\n"
+" integrated into a single value using a user-defined integration\n"
+" method.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The density evaluated for an Interface1D.\n"
+" :rtype: float\n";
+
+static int DensityF1D___init__( BPy_DensityF1D* self, PyObject *args)
+{
+ PyObject *obj = 0;
+ double d = 2.0;
+ float f = 2.0;
+
+ if( !PyArg_ParseTuple(args, "|dO!f", &d, &IntegrationType_Type, &obj, &f) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::DensityF1D(d,t,f);
+ return 0;
+
+}
+
+/*-----------------------BPy_DensityF1D type definition ------------------------------*/
+
+PyTypeObject DensityF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "DensityF1D", /* tp_name */
+ sizeof(BPy_DensityF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ DensityF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)DensityF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.h
new file mode 100644
index 00000000000..36426536b36
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_DENSITYF1D_H
+#define FREESTYLE_PYTHON_DENSITYF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject DensityF1D_Type;
+
+#define BPy_DensityF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &DensityF1D_Type) )
+
+/*---------------------------Python BPy_DensityF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_DensityF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_DENSITYF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.cpp
new file mode 100644
index 00000000000..b30d26c8516
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.cpp
@@ -0,0 +1,110 @@
+#include "BPy_GetCompleteViewMapDensityF1D.h"
+
+#include "../../../stroke/AdvancedFunctions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetCompleteViewMapDensityF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetCompleteViewMapDensityF1D`\n"
+"\n"
+".. method:: __init__(level, iType=IntegrationType.MEAN, sampling=2.0)\n"
+"\n"
+" Builds a GetCompleteViewMapDensityF1D object.\n"
+"\n"
+" :arg level: The level of the pyramid from which the pixel must be\n"
+" read.\n"
+" :type level: int\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+" :arg sampling: The resolution used to sample the chain: the\n"
+" corresponding 0D function is evaluated at each sample point and\n"
+" the result is obtained by combining the resulting values into a\n"
+" single one, following the method specified by iType.\n"
+" :type sampling: float\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the density evaluated for an Interface1D in the complete\n"
+" viewmap image. The density is evaluated for a set of points along\n"
+" the Interface1D (using the :class:`ReadCompleteViewMapPixelF0D`\n"
+" functor) and then integrated into a single value using a\n"
+" user-defined integration method.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The density evaluated for the Interface1D in the complete\n"
+" viewmap image.\n"
+" :rtype: float\n";
+
+static int GetCompleteViewMapDensityF1D___init__( BPy_GetCompleteViewMapDensityF1D* self, PyObject *args)
+{
+ PyObject *obj = 0;
+ unsigned i;
+ float f = 2.0;
+
+ if( !PyArg_ParseTuple(args, "i|O!f", &i, &IntegrationType_Type, &obj, &f) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::GetCompleteViewMapDensityF1D(i,t,f);
+ return 0;
+
+}
+
+/*-----------------------BPy_GetCompleteViewMapDensityF1D type definition ------------------------------*/
+
+PyTypeObject GetCompleteViewMapDensityF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetCompleteViewMapDensityF1D", /* tp_name */
+ sizeof(BPy_GetCompleteViewMapDensityF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetCompleteViewMapDensityF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetCompleteViewMapDensityF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.h
new file mode 100644
index 00000000000..5963b820348
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETCOMPLETEVIEWMAPDENSITYF1D_H
+#define FREESTYLE_PYTHON_GETCOMPLETEVIEWMAPDENSITYF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetCompleteViewMapDensityF1D_Type;
+
+#define BPy_GetCompleteViewMapDensityF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetCompleteViewMapDensityF1D_Type) )
+
+/*---------------------------Python BPy_GetCompleteViewMapDensityF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_GetCompleteViewMapDensityF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETCOMPLETEVIEWMAPDENSITYF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp
new file mode 100644
index 00000000000..494297d3a3b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp
@@ -0,0 +1,114 @@
+#include "BPy_GetDirectionalViewMapDensityF1D.h"
+
+#include "../../../stroke/AdvancedFunctions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetDirectionalViewMapDensityF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetDirectionalViewMapDensityF1D`\n"
+"\n"
+".. method:: __init__(iOrientation, level, iType=IntegrationType.MEAN, sampling=2.0)\n"
+"\n"
+" Builds a GetDirectionalViewMapDensityF1D object.\n"
+"\n"
+" :arg iOrientation: The number of the directional map we must work\n"
+" with.\n"
+" :type iOrientation: int\n"
+" :arg level: The level of the pyramid from which the pixel must be\n"
+" read.\n"
+" :type level: int\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+" :arg sampling: The resolution used to sample the chain: the\n"
+" corresponding 0D function is evaluated at each sample point and\n"
+" the result is obtained by combining the resulting values into a\n"
+" single one, following the method specified by iType.\n"
+" :type sampling: float\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the density evaluated for an Interface1D in of the\n"
+" steerable viewmaps image. The direction telling which Directional\n"
+" map to choose is explicitely specified by the user. The density is\n"
+" evaluated for a set of points along the Interface1D (using the\n"
+" :class:`ReadSteerableViewMapPixelF0D` functor) and then integrated\n"
+" into a single value using a user-defined integration method.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: the density evaluated for an Interface1D in of the\n"
+" steerable viewmaps image.\n"
+" :rtype: float\n";
+
+static int GetDirectionalViewMapDensityF1D___init__( BPy_GetDirectionalViewMapDensityF1D* self, PyObject *args)
+{
+ PyObject *obj = 0;
+ unsigned int u1, u2;
+ float f = 2.0;
+
+ if( !PyArg_ParseTuple(args, "II|O!f", &u1, &u2, &IntegrationType_Type, &obj, &f) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::GetDirectionalViewMapDensityF1D(u1, u2, t, f);
+ return 0;
+
+}
+
+/*-----------------------BPy_GetDirectionalViewMapDensityF1D type definition ------------------------------*/
+
+PyTypeObject GetDirectionalViewMapDensityF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetDirectionalViewMapDensityF1D", /* tp_name */
+ sizeof(BPy_GetDirectionalViewMapDensityF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetDirectionalViewMapDensityF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetDirectionalViewMapDensityF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.h
new file mode 100644
index 00000000000..0e2d7ec2718
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETDIRECTIONALVIEWMAPDENSITYF1D_H
+#define FREESTYLE_PYTHON_GETDIRECTIONALVIEWMAPDENSITYF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetDirectionalViewMapDensityF1D_Type;
+
+#define BPy_GetDirectionalViewMapDensityF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetDirectionalViewMapDensityF1D_Type) )
+
+/*---------------------------Python BPy_GetDirectionalViewMapDensityF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_GetDirectionalViewMapDensityF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETDIRECTIONALVIEWMAPDENSITYF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.cpp
new file mode 100644
index 00000000000..7b1e7193b85
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.cpp
@@ -0,0 +1,95 @@
+#include "BPy_GetProjectedXF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetProjectedXF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetProjectedXF1D`\n"
+"\n"
+".. method:: __init__(iType=IntegrationType.MEAN)\n"
+"\n"
+" Builds a GetProjectedXF1D object.\n"
+"\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values. \n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the projected X 3D coordinate of an Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The projected X 3D coordinate of an Interface1D.\n"
+" :rtype: float\n";
+
+static int GetProjectedXF1D___init__( BPy_GetProjectedXF1D* self, PyObject *args )
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::GetProjectedXF1D(t);
+ return 0;
+}
+
+
+/*-----------------------BPy_GetProjectedXF1D type definition ------------------------------*/
+
+PyTypeObject GetProjectedXF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetProjectedXF1D", /* tp_name */
+ sizeof(BPy_GetProjectedXF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetProjectedXF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetProjectedXF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.h
new file mode 100644
index 00000000000..d799fb7b334
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETPROJECTEDXF1D_H
+#define FREESTYLE_PYTHON_GETPROJECTEDXF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetProjectedXF1D_Type;
+
+#define BPy_GetProjectedXF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetProjectedXF1D_Type) )
+
+/*---------------------------Python BPy_GetProjectedXF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_GetProjectedXF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETPROJECTEDXF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.cpp
new file mode 100644
index 00000000000..df09b32b5b9
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.cpp
@@ -0,0 +1,94 @@
+#include "BPy_GetProjectedYF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetProjectedYF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetProjectedYF1D`\n"
+"\n"
+".. method:: __init__(iType=IntegrationType.MEAN)\n"
+"\n"
+" Builds a GetProjectedYF1D object.\n"
+"\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values. \n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the projected Y 3D coordinate of an Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The projected Y 3D coordinate of an Interface1D.\n"
+" :rtype: float\n";
+
+static int GetProjectedYF1D___init__( BPy_GetProjectedYF1D* self, PyObject *args )
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::GetProjectedYF1D(t);
+ return 0;
+}
+
+/*-----------------------BPy_GetProjectedYF1D type definition ------------------------------*/
+
+PyTypeObject GetProjectedYF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetProjectedYF1D", /* tp_name */
+ sizeof(BPy_GetProjectedYF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetProjectedYF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetProjectedYF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.h
new file mode 100644
index 00000000000..1b7fe6c6b5f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETPROJECTEDYF1D_H
+#define FREESTYLE_PYTHON_GETPROJECTEDYF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetProjectedYF1D_Type;
+
+#define BPy_GetProjectedYF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetProjectedYF1D_Type) )
+
+/*---------------------------Python BPy_GetProjectedYF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_GetProjectedYF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETPROJECTEDYF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.cpp
new file mode 100644
index 00000000000..acd03856b2c
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.cpp
@@ -0,0 +1,94 @@
+#include "BPy_GetProjectedZF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetProjectedZF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetProjectedZF1D`\n"
+"\n"
+".. method:: __init__(iType=IntegrationType.MEAN)\n"
+"\n"
+" Builds a GetProjectedZF1D object.\n"
+"\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values. \n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the projected Z 3D coordinate of an Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The projected Z 3D coordinate of an Interface1D.\n"
+" :rtype: float\n";
+
+static int GetProjectedZF1D___init__( BPy_GetProjectedZF1D* self, PyObject *args )
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::GetProjectedZF1D(t);
+ return 0;
+}
+
+/*-----------------------BPy_GetProjectedZF1D type definition ------------------------------*/
+
+PyTypeObject GetProjectedZF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetProjectedZF1D", /* tp_name */
+ sizeof(BPy_GetProjectedZF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetProjectedZF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetProjectedZF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.h
new file mode 100644
index 00000000000..a87ac6f8c5e
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETPROJECTEDZF1D_H
+#define FREESTYLE_PYTHON_GETPROJECTEDZF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetProjectedZF1D_Type;
+
+#define BPy_GetProjectedZF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetProjectedZF1D_Type) )
+
+/*---------------------------Python BPy_GetProjectedZF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_GetProjectedZF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETPROJECTEDZF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.cpp
new file mode 100644
index 00000000000..cc3813030ac
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.cpp
@@ -0,0 +1,107 @@
+#include "BPy_GetSteerableViewMapDensityF1D.h"
+
+#include "../../../stroke/AdvancedFunctions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetSteerableViewMapDensityF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetSteerableViewMapDensityF1D`\n"
+"\n"
+".. method:: __init__(level, iType=IntegrationType.MEAN, sampling=2.0)\n"
+"\n"
+" Builds a GetSteerableViewMapDensityF1D object.\n"
+"\n"
+" :arg level: The level of the pyramid from which the pixel must be\n"
+" read.\n"
+" :type level: int\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+" :arg sampling: The resolution used to sample the chain: the\n"
+" corresponding 0D function is evaluated at each sample point and\n"
+" the result is obtained by combining the resulting values into a\n"
+" single one, following the method specified by iType.\n"
+" :type sampling: float\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the density of the ViewMap for a given Interface1D. The\n"
+" density of each :class:`FEdge` is evaluated in the proper steerable\n"
+" :class:`ViewMap` depending on its orientation.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The density of the ViewMap for a given Interface1D.\n"
+" :rtype: float\n";
+
+static int GetSteerableViewMapDensityF1D___init__( BPy_GetSteerableViewMapDensityF1D* self, PyObject *args)
+{
+ PyObject *obj = 0;
+ int i;
+ float f = 2.0;
+
+ if( !PyArg_ParseTuple(args, "i|O!f", &i, &IntegrationType_Type, &obj, &f) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::GetSteerableViewMapDensityF1D(i,t,f);
+ return 0;
+
+}
+
+/*-----------------------BPy_GetSteerableViewMapDensityF1D type definition ------------------------------*/
+
+PyTypeObject GetSteerableViewMapDensityF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetSteerableViewMapDensityF1D", /* tp_name */
+ sizeof(BPy_GetSteerableViewMapDensityF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetSteerableViewMapDensityF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetSteerableViewMapDensityF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.h
new file mode 100644
index 00000000000..29880c7e9a7
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_GETSTEERABLEVIEWMAPDENSITYF1D_H
+#define FREESTYLE_PYTHON_GETSTEERABLEVIEWMAPDENSITYF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetSteerableViewMapDensityF1D_Type;
+
+#define BPy_GetSteerableViewMapDensityF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetSteerableViewMapDensityF1D_Type) )
+/*---------------------------Python BPy_GetSteerableViewMapDensityF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_GetSteerableViewMapDensityF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETSTEERABLEVIEWMAPDENSITYF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.cpp
new file mode 100644
index 00000000000..c3e12fd7792
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.cpp
@@ -0,0 +1,107 @@
+#include "BPy_GetViewMapGradientNormF1D.h"
+
+#include "../../../stroke/AdvancedFunctions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetViewMapGradientNormF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetViewMapGradientNormF1D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetViewMapGradientNormF1D object.\n"
+"\n"
+" :arg level: The level of the pyramid from which the pixel must be\n"
+" read.\n"
+" :type level: int\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+" :arg sampling: The resolution used to sample the chain: the\n"
+" corresponding 0D function is evaluated at each sample point and\n"
+" the result is obtained by combining the resulting values into a\n"
+" single one, following the method specified by iType.\n"
+" :type sampling: float\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the density of the ViewMap for a given Interface1D. The\n"
+" density of each :class:`FEdge` is evaluated in the proper steerable\n"
+" :class:`ViewMap` depending on its orientation.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The density of the ViewMap for a given Interface1D.\n"
+" :rtype: float\n";
+
+static int GetViewMapGradientNormF1D___init__( BPy_GetViewMapGradientNormF1D* self, PyObject *args)
+{
+ PyObject *obj = 0;
+ int i;
+ float f = 2.0;
+
+ if( !PyArg_ParseTuple(args, "i|O!f", &i, &IntegrationType_Type, &obj, &f) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::GetViewMapGradientNormF1D(i,t,f);
+ return 0;
+
+}
+
+/*-----------------------BPy_GetViewMapGradientNormF1D type definition ------------------------------*/
+
+PyTypeObject GetViewMapGradientNormF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetViewMapGradientNormF1D", /* tp_name */
+ sizeof(BPy_GetViewMapGradientNormF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetViewMapGradientNormF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetViewMapGradientNormF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.h
new file mode 100644
index 00000000000..4f07629870f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETVIEWMAPGRADIENTNORMF1D_H
+#define FREESTYLE_PYTHON_GETVIEWMAPGRADIENTNORMF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetViewMapGradientNormF1D_Type;
+
+#define BPy_GetViewMapGradientNormF1D_Check(v) ( ((PyObject *) v)->ob_type == PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetViewMapGradientNormF1D_Type) )
+
+/*---------------------------Python BPy_GetViewMapGradientNormF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_GetViewMapGradientNormF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETVIEWMAPGRADIENTNORMF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.cpp
new file mode 100644
index 00000000000..a15c6f59a3b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.cpp
@@ -0,0 +1,95 @@
+#include "BPy_GetXF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetXF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetXF1D`\n"
+"\n"
+".. method:: __init__(iType)\n"
+"\n"
+" Builds a GetXF1D object.\n"
+"\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the X 3D coordinate of an Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The X 3D coordinate of the Interface1D.\n"
+" :rtype: float\n";
+
+static int GetXF1D___init__( BPy_GetXF1D* self, PyObject *args )
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::GetXF1D(t);
+ return 0;
+}
+
+
+/*-----------------------BPy_GetXF1D type definition ------------------------------*/
+
+PyTypeObject GetXF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetXF1D", /* tp_name */
+ sizeof(BPy_GetXF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetXF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetXF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.h
new file mode 100644
index 00000000000..5eae107daae
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETXF1D_H
+#define FREESTYLE_PYTHON_GETXF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetXF1D_Type;
+
+#define BPy_GetXF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetXF1D_Type) )
+
+/*---------------------------Python BPy_GetXF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_GetXF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETXF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.cpp
new file mode 100644
index 00000000000..b8ee3d8be27
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.cpp
@@ -0,0 +1,93 @@
+#include "BPy_GetYF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetYF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetYF1D`\n"
+"\n"
+".. method:: __init__(iType)\n"
+"\n"
+" Builds a GetYF1D object.\n"
+"\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the Y 3D coordinate of an Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The Y 3D coordinate of the Interface1D.\n"
+" :rtype: float\n";
+
+static int GetYF1D___init__( BPy_GetYF1D* self, PyObject *args )
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::GetYF1D(t);
+ return 0;
+}
+/*-----------------------BPy_GetYF1D type definition ------------------------------*/
+
+PyTypeObject GetYF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetYF1D", /* tp_name */
+ sizeof(BPy_GetYF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetYF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetYF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.h
new file mode 100644
index 00000000000..5864c245776
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETYF1D_H
+#define FREESTYLE_PYTHON_GETYF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetYF1D_Type;
+
+#define BPy_GetYF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetYF1D_Type) )
+
+/*---------------------------Python BPy_GetYF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_GetYF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETYF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.cpp
new file mode 100644
index 00000000000..af275c906c4
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.cpp
@@ -0,0 +1,94 @@
+#include "BPy_GetZF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetZF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetZF1D`\n"
+"\n"
+".. method:: __init__(iType)\n"
+"\n"
+" Builds a GetZF1D object.\n"
+"\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the Z 3D coordinate of an Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The Z 3D coordinate of the Interface1D.\n"
+" :rtype: float\n";
+
+static int GetZF1D___init__( BPy_GetZF1D* self, PyObject *args )
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::GetZF1D(t);
+ return 0;
+}
+
+/*-----------------------BPy_GetZF1D type definition ------------------------------*/
+
+PyTypeObject GetZF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetZF1D", /* tp_name */
+ sizeof(BPy_GetZF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetZF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetZF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.h
new file mode 100644
index 00000000000..4b91a567eef
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETZF1D_H
+#define FREESTYLE_PYTHON_GETZF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetZF1D_Type;
+
+#define BPy_GetZF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetZF1D_Type) )
+
+/*---------------------------Python BPy_GetZF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_GetZF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETZF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.cpp
new file mode 100644
index 00000000000..a3b15e6b5f7
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.cpp
@@ -0,0 +1,101 @@
+#include "BPy_LocalAverageDepthF1D.h"
+
+#include "../../../stroke/AdvancedFunctions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char LocalAverageDepthF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`LocalAverageDepthF1D`\n"
+"\n"
+".. method:: __init__(sigma, iType=IntegrationType.MEAN)\n"
+"\n"
+" Builds a LocalAverageDepthF1D object.\n"
+"\n"
+" :arg sigma: The sigma used in DensityF0D and determining the window\n"
+" size used in each density query.\n"
+" :type sigma: float\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the average depth evaluated for an Interface1D. The\n"
+" average depth is evaluated for a set of points along the\n"
+" Interface1D (using the :class:`LocalAverageDepthF0D` functor) with\n"
+" a user-defined sampling and then integrated into a single value\n"
+" using a user-defined integration method.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The average depth evaluated for the Interface1D.\n"
+" :rtype: float\n";
+
+static int LocalAverageDepthF1D___init__( BPy_LocalAverageDepthF1D* self, PyObject *args)
+{
+ PyObject *obj = 0;
+ double d;
+
+ if( !PyArg_ParseTuple(args, "d|O!", &d, &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::LocalAverageDepthF1D(d,t);
+ return 0;
+}
+/*-----------------------BPy_LocalAverageDepthF1D type definition ------------------------------*/
+
+PyTypeObject LocalAverageDepthF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "LocalAverageDepthF1D", /* tp_name */
+ sizeof(BPy_LocalAverageDepthF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ LocalAverageDepthF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)LocalAverageDepthF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.h
new file mode 100644
index 00000000000..627d10b6414
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_LOCALAVERAGEDEPTHF1D_H
+#define FREESTYLE_PYTHON_LOCALAVERAGEDEPTHF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject LocalAverageDepthF1D_Type;
+
+#define BPy_LocalAverageDepthF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &LocalAverageDepthF1D_Type) )
+
+/*---------------------------Python BPy_LocalAverageDepthF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_LocalAverageDepthF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_LOCALAVERAGEDEPTHF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp
new file mode 100644
index 00000000000..32a5106b380
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp
@@ -0,0 +1,99 @@
+#include "BPy_ZDiscontinuityF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ZDiscontinuityF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`ZDiscontinuityF1D`\n"
+"\n"
+".. method:: __init__(iType=IntegrationType.MEAN)\n"
+"\n"
+" Builds a ZDiscontinuityF1D object.\n"
+"\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns a real value giving the distance between an Interface1D\n"
+" and the shape that lies behind (occludee). This distance is\n"
+" evaluated in the camera space and normalized between 0 and 1.\n"
+" Therefore, if no oject is occluded by the shape to which the\n"
+" Interface1D belongs to, 1 is returned.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The normalized distance between the Interface1D and the occludee.\n"
+" :rtype: float\n";
+
+static int ZDiscontinuityF1D___init__( BPy_ZDiscontinuityF1D* self, PyObject *args )
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_double.uf1D_double = new Functions1D::ZDiscontinuityF1D(t);
+ return 0;
+}
+
+
+/*-----------------------BPy_ZDiscontinuityF1D type definition ------------------------------*/
+
+PyTypeObject ZDiscontinuityF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ZDiscontinuityF1D", /* tp_name */
+ sizeof(BPy_ZDiscontinuityF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ZDiscontinuityF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DDouble_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ZDiscontinuityF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.h
new file mode 100644
index 00000000000..e6b4be556d7
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_ZDISCONTINUITYF1D_H
+#define FREESTYLE_PYTHON_ZDISCONTINUITYF1D_H
+
+#include "../BPy_UnaryFunction1DDouble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ZDiscontinuityF1D_Type;
+
+#define BPy_ZDiscontinuityF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ZDiscontinuityF1D_Type) )
+
+/*---------------------------Python BPy_ZDiscontinuityF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DDouble py_uf1D_double;
+} BPy_ZDiscontinuityF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_ZDISCONTINUITYF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.cpp
new file mode 100644
index 00000000000..a7379c4f769
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.cpp
@@ -0,0 +1,99 @@
+#include "BPy_QuantitativeInvisibilityF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char QuantitativeInvisibilityF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DUnsigned` > :class:`QuantitativeInvisibilityF1D`\n"
+"\n"
+".. method:: __init__(iType=IntegrationType.MEAN)\n"
+"\n"
+" Builds a QuantitativeInvisibilityF1D object.\n"
+"\n"
+" :arg iType: The integration method used to compute a single value\n"
+" from a set of values.\n"
+" :type iType: :class:`IntegrationType`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the Quantitative Invisibility of an Interface1D element.\n"
+" If the Interface1D is a :class:`ViewEdge`, then there is no\n"
+" ambiguity concerning the result. But, if the Interface1D results\n"
+" of a chaining (chain, stroke), then it might be made of several 1D\n"
+" elements of different Quantitative Invisibilities.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: The Quantitative Invisibility of the Interface1D.\n"
+" :rtype: int\n";
+
+static int QuantitativeInvisibilityF1D___init__( BPy_QuantitativeInvisibilityF1D* self, PyObject *args)
+{
+ PyObject *obj = 0;
+
+ if( !PyArg_ParseTuple(args, "|O!", &IntegrationType_Type, &obj) )
+ return -1;
+
+ IntegrationType t = ( obj ) ? IntegrationType_from_BPy_IntegrationType(obj) : MEAN;
+ self->py_uf1D_unsigned.uf1D_unsigned = new Functions1D::QuantitativeInvisibilityF1D(t);
+ return 0;
+
+}
+
+/*-----------------------BPy_QuantitativeInvisibilityF1D type definition ------------------------------*/
+
+PyTypeObject QuantitativeInvisibilityF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "QuantitativeInvisibilityF1D", /* tp_name */
+ sizeof(BPy_QuantitativeInvisibilityF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ QuantitativeInvisibilityF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DUnsigned_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)QuantitativeInvisibilityF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.h
new file mode 100644
index 00000000000..5bcf5fcc0a2
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_QUANTITATIVEINVISIBILITYF1D_H
+#define FREESTYLE_PYTHON_QUANTITATIVEINVISIBILITYF1D_H
+
+#include "../BPy_UnaryFunction1DUnsigned.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject QuantitativeInvisibilityF1D_Type;
+
+#define BPy_QuantitativeInvisibilityF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &QuantitativeInvisibilityF1D_Type) )
+
+/*---------------------------Python BPy_QuantitativeInvisibilityF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DUnsigned py_uf1D_unsigned;
+} BPy_QuantitativeInvisibilityF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_QUANTITATIVEINVISIBILITYF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.cpp
new file mode 100644
index 00000000000..4bd03f8fe75
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.cpp
@@ -0,0 +1,86 @@
+#include "BPy_GetOccludeeF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetOccludeeF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVectorViewShape` > :class:`GetOccludeeF1D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetOccludeeF1D object.\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns a list of occluded shapes covered by this Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: A list of occluded shapes covered by the Interface1D.\n"
+" :rtype: list of :class:`ViewShape` objects\n";
+
+static int GetOccludeeF1D___init__( BPy_GetOccludeeF1D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf1D_vectorviewshape.uf1D_vectorviewshape = new Functions1D::GetOccludeeF1D();
+ return 0;
+}
+
+/*-----------------------BPy_GetOccludeeF1D type definition ------------------------------*/
+
+PyTypeObject GetOccludeeF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetOccludeeF1D", /* tp_name */
+ sizeof(BPy_GetOccludeeF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetOccludeeF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DVectorViewShape_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetOccludeeF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.h
new file mode 100644
index 00000000000..c8d5e99a6a7
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETOCCLUDEEF1D_H
+#define FREESTYLE_PYTHON_GETOCCLUDEEF1D_H
+
+#include "../BPy_UnaryFunction1DVectorViewShape.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetOccludeeF1D_Type;
+
+#define BPy_GetOccludeeF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetOccludeeF1D_Type) )
+
+/*---------------------------Python BPy_GetOccludeeF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DVectorViewShape py_uf1D_vectorviewshape;
+} BPy_GetOccludeeF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETOCCLUDEEF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.cpp
new file mode 100644
index 00000000000..d37102a8447
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.cpp
@@ -0,0 +1,86 @@
+#include "BPy_GetOccludersF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetOccludersF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVectorViewShape` > :class:`GetOccludersF1D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetOccludersF1D object.\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns a list of occluding shapes that cover this Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: A list of occluding shapes that cover the Interface1D.\n"
+" :rtype: list of :class:`ViewShape` objects\n";
+
+static int GetOccludersF1D___init__( BPy_GetOccludersF1D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf1D_vectorviewshape.uf1D_vectorviewshape = new Functions1D::GetOccludersF1D();
+ return 0;
+}
+
+/*-----------------------BPy_GetOccludersF1D type definition ------------------------------*/
+
+PyTypeObject GetOccludersF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetOccludersF1D", /* tp_name */
+ sizeof(BPy_GetOccludersF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetOccludersF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DVectorViewShape_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetOccludersF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.h
new file mode 100644
index 00000000000..ad39ad25c3d
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETOCCLUDERSF1D_H
+#define FREESTYLE_PYTHON_GETOCCLUDERSF1D_H
+
+#include "../BPy_UnaryFunction1DVectorViewShape.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetOccludersF1D_Type;
+
+#define BPy_GetOccludersF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetOccludersF1D_Type) )
+
+/*---------------------------Python BPy_GetOccludersF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DVectorViewShape py_uf1D_vectorviewshape;
+} BPy_GetOccludersF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETOCCLUDERSF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.cpp
new file mode 100644
index 00000000000..9b2007296f9
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.cpp
@@ -0,0 +1,86 @@
+#include "BPy_GetShapeF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char GetShapeF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVectorViewShape` > :class:`GetShapeF1D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a GetShapeF1D object.\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns a list of shapes covered by this Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: A list of shapes covered by the Interface1D.\n"
+" :rtype: list of :class:`ViewShape` objects\n";
+
+static int GetShapeF1D___init__( BPy_GetShapeF1D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf1D_vectorviewshape.uf1D_vectorviewshape = new Functions1D::GetShapeF1D();
+ return 0;
+}
+
+/*-----------------------BPy_GetShapeF1D type definition ------------------------------*/
+
+PyTypeObject GetShapeF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "GetShapeF1D", /* tp_name */
+ sizeof(BPy_GetShapeF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ GetShapeF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DVectorViewShape_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)GetShapeF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.h
new file mode 100644
index 00000000000..39d1268c03f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_GETSHAPEF1D_H
+#define FREESTYLE_PYTHON_GETSHAPEF1D_H
+
+#include "../BPy_UnaryFunction1DVectorViewShape.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject GetShapeF1D_Type;
+
+#define BPy_GetShapeF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &GetShapeF1D_Type) )
+
+/*---------------------------Python BPy_GetShapeF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DVectorViewShape py_uf1D_vectorviewshape;
+} BPy_GetShapeF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_GETSHAPEF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.cpp
new file mode 100644
index 00000000000..be774a09d99
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.cpp
@@ -0,0 +1,84 @@
+#include "BPy_ChainingTimeStampF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ChainingTimeStampF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVoid` > :class:`ChainingTimeStampF1D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a ChainingTimeStampF1D object.\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Sets the chaining time stamp of the Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n";
+
+static int ChainingTimeStampF1D___init__( BPy_ChainingTimeStampF1D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf1D_void.uf1D_void = new Functions1D::ChainingTimeStampF1D();
+ return 0;
+}
+
+/*-----------------------BPy_ChainingTimeStampF1D type definition ------------------------------*/
+
+PyTypeObject ChainingTimeStampF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ChainingTimeStampF1D", /* tp_name */
+ sizeof(BPy_ChainingTimeStampF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ChainingTimeStampF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DVoid_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ChainingTimeStampF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.h
new file mode 100644
index 00000000000..6855ddaf14b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_CHAININGTIMESTAMPF1D_H
+#define FREESTYLE_PYTHON_CHAININGTIMESTAMPF1D_H
+
+#include "../BPy_UnaryFunction1DVoid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ChainingTimeStampF1D_Type;
+
+#define BPy_ChainingTimeStampF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ChainingTimeStampF1D_Type) )
+
+/*---------------------------Python BPy_ChainingTimeStampF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DVoid py_uf1D_void;
+} BPy_ChainingTimeStampF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CHAININGTIMESTAMPF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.cpp
new file mode 100644
index 00000000000..2d1a1344c4b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.cpp
@@ -0,0 +1,84 @@
+#include "BPy_IncrementChainingTimeStampF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char IncrementChainingTimeStampF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVoid` > :class:`IncrementChainingTimeStampF1D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds an IncrementChainingTimeStampF1D object.\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Increments the chaining time stamp of the Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n";
+
+static int IncrementChainingTimeStampF1D___init__( BPy_IncrementChainingTimeStampF1D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf1D_void.uf1D_void = new Functions1D::IncrementChainingTimeStampF1D();
+ return 0;
+}
+
+/*-----------------------BPy_IncrementChainingTimeStampF1D type definition ------------------------------*/
+
+PyTypeObject IncrementChainingTimeStampF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "IncrementChainingTimeStampF1D", /* tp_name */
+ sizeof(BPy_IncrementChainingTimeStampF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ IncrementChainingTimeStampF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DVoid_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)IncrementChainingTimeStampF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.h
new file mode 100644
index 00000000000..a1d5714ab63
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_INCREMENTCHAININGTIMESTAMPF1D_H
+#define FREESTYLE_PYTHON_INCREMENTCHAININGTIMESTAMPF1D_H
+
+#include "../BPy_UnaryFunction1DVoid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject IncrementChainingTimeStampF1D_Type;
+
+#define BPy_IncrementChainingTimeStampF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &IncrementChainingTimeStampF1D_Type) )
+
+/*---------------------------Python BPy_IncrementChainingTimeStampF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DVoid py_uf1D_void;
+} BPy_IncrementChainingTimeStampF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_INCREMENTCHAININGTIMESTAMPF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.cpp
new file mode 100644
index 00000000000..c5311501098
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.cpp
@@ -0,0 +1,84 @@
+#include "BPy_TimeStampF1D.h"
+
+#include "../../../view_map/Functions1D.h"
+#include "../../BPy_Convert.h"
+#include "../../BPy_IntegrationType.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char TimeStampF1D___doc__[] =
+"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVoid` > :class:`TimeStampF1D`\n"
+"\n"
+".. method:: __init__()\n"
+"\n"
+" Builds a TimeStampF1D object.\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns the time stamp of the Interface1D.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n";
+
+static int TimeStampF1D___init__( BPy_TimeStampF1D* self, PyObject *args )
+{
+ if( !PyArg_ParseTuple(args, "") )
+ return -1;
+ self->py_uf1D_void.uf1D_void = new Functions1D::TimeStampF1D();
+ return 0;
+}
+
+/*-----------------------BPy_TimeStampF1D type definition ------------------------------*/
+
+PyTypeObject TimeStampF1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "TimeStampF1D", /* tp_name */
+ sizeof(BPy_TimeStampF1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ TimeStampF1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryFunction1DVoid_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)TimeStampF1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.h b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.h
new file mode 100644
index 00000000000..d9bee247c09
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.h
@@ -0,0 +1,30 @@
+#ifndef FREESTYLE_PYTHON_TIMESTAMPF1D_H
+#define FREESTYLE_PYTHON_TIMESTAMPF1D_H
+
+#include "../BPy_UnaryFunction1DVoid.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject TimeStampF1D_Type;
+
+#define BPy_TimeStampF1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &TimeStampF1D_Type) )
+
+/*---------------------------Python BPy_TimeStampF1D structure definition----------*/
+typedef struct {
+ BPy_UnaryFunction1DVoid py_uf1D_void;
+} BPy_TimeStampF1D;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CHAININGTIMESTAMPF1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_FalseUP0D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_FalseUP0D.cpp
new file mode 100644
index 00000000000..afefa703d14
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_FalseUP0D.cpp
@@ -0,0 +1,78 @@
+#include "BPy_FalseUP0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char FalseUP0D___doc__[] =
+"Class hierarchy: :class:`UnaryPredicate0D` > :class:`FalseUP0D`\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Always returns false.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: False.\n"
+" :rtype: bool\n";
+
+static int FalseUP0D___init__( BPy_FalseUP0D* self, PyObject *args)
+{
+ if(!( PyArg_ParseTuple(args, "") ))
+ return -1;
+ self->py_up0D.up0D = new Predicates0D::FalseUP0D();
+ return 0;
+}
+
+/*-----------------------BPy_FalseUP0D type definition ------------------------------*/
+
+PyTypeObject FalseUP0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "FalseUP0D", /* tp_name */
+ sizeof(BPy_FalseUP0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ FalseUP0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryPredicate0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)FalseUP0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_FalseUP0D.h b/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_FalseUP0D.h
new file mode 100644
index 00000000000..399941d442d
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_FalseUP0D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_FALSEUP0D_H
+#define FREESTYLE_PYTHON_FALSEUP0D_H
+
+#include "../BPy_UnaryPredicate0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject FalseUP0D_Type;
+
+#define BPy_FalseUP0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &FalseUP0D_Type) )
+
+/*---------------------------Python BPy_FalseUP0D structure definition----------*/
+typedef struct {
+ BPy_UnaryPredicate0D py_up0D;
+} BPy_FalseUP0D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_FALSEUP0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_TrueUP0D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_TrueUP0D.cpp
new file mode 100644
index 00000000000..2efc9ed6f74
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_TrueUP0D.cpp
@@ -0,0 +1,78 @@
+#include "BPy_TrueUP0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char TrueUP0D___doc__[] =
+"Class hierarchy: :class:`UnaryPredicate0D` > :class:`TrueUP0D`\n"
+"\n"
+".. method:: __call__(it)\n"
+"\n"
+" Always returns true.\n"
+"\n"
+" :arg it: An Interface0DIterator object.\n"
+" :type it: :class:`Interface0DIterator`\n"
+" :return: True.\n"
+" :rtype: bool\n";
+
+static int TrueUP0D___init__( BPy_TrueUP0D* self, PyObject *args )
+{
+ if(!( PyArg_ParseTuple(args, "") ))
+ return -1;
+ self->py_up0D.up0D = new Predicates0D::TrueUP0D();
+ return 0;
+}
+
+/*-----------------------BPy_TrueUP0D type definition ------------------------------*/
+
+PyTypeObject TrueUP0D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "TrueUP0D", /* tp_name */
+ sizeof(BPy_TrueUP0D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ TrueUP0D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryPredicate0D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)TrueUP0D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_TrueUP0D.h b/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_TrueUP0D.h
new file mode 100644
index 00000000000..24976aaa5c9
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_TrueUP0D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_TRUEUP0D_H
+#define FREESTYLE_PYTHON_TRUEUP0D_H
+
+#include "../BPy_UnaryPredicate0D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject TrueUP0D_Type;
+
+#define BPy_TrueUP0D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &TrueUP0D_Type) )
+
+/*---------------------------Python BPy_TrueUP0D structure definition----------*/
+typedef struct {
+ BPy_UnaryPredicate0D py_up0D;
+} BPy_TrueUP0D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_TRUEUP0D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp
new file mode 100644
index 00000000000..dbbcc4255cf
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp
@@ -0,0 +1,79 @@
+#include "BPy_ContourUP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ContourUP1D___doc__[] =
+"Class hierarchy: :class:`UnaryPredicate1D` > :class:`ContourUP1D`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns true if the Interface1D is a contour. An Interface1D is a\n"
+" contour if it is borded by a different shape on each of its sides.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: True if the Interface1D is a contour, false otherwise.\n"
+" :rtype: bool\n";
+
+static int ContourUP1D___init__( BPy_ContourUP1D* self, PyObject *args )
+{
+ if(!( PyArg_ParseTuple(args, "") ))
+ return -1;
+ self->py_up1D.up1D = new Predicates1D::ContourUP1D();
+ return 0;
+}
+
+/*-----------------------BPy_ContourUP1D type definition ------------------------------*/
+
+PyTypeObject ContourUP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ContourUP1D", /* tp_name */
+ sizeof(BPy_ContourUP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ContourUP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ContourUP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.h b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.h
new file mode 100644
index 00000000000..a24261a60de
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_CONTOURUP1D_H
+#define FREESTYLE_PYTHON_CONTOURUP1D_H
+
+#include "../BPy_UnaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ContourUP1D_Type;
+
+#define BPy_ContourUP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ContourUP1D_Type) )
+
+/*---------------------------Python BPy_ContourUP1D structure definition----------*/
+typedef struct {
+ BPy_UnaryPredicate1D py_up1D;
+} BPy_ContourUP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_CONTOURUP1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.cpp
new file mode 100644
index 00000000000..c88f077c23b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.cpp
@@ -0,0 +1,95 @@
+#include "BPy_DensityLowerThanUP1D.h"
+
+#include "../../stroke/AdvancedPredicates1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char DensityLowerThanUP1D___doc__[] =
+"Class hierarchy: :class:`UnaryPredicate1D` > :class:`DensityLowerThanUP1D`\n"
+"\n"
+".. method:: __init__(threshold, sigma=2.0)\n"
+"\n"
+" Builds a DensityLowerThanUP1D object.\n"
+"\n"
+" :arg threshold: The value of the threshold density. Any Interface1D\n"
+" having a density lower than this threshold will match.\n"
+" :type threshold: float\n"
+" :arg sigma: The sigma value defining the density evaluation window\n"
+" size used in the :class:`DensityF0D` functor.\n"
+" :type sigma: float\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns true if the density evaluated for the Interface1D is less\n"
+" than a user-defined density value.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: True if the density is lower than a threshold.\n"
+" :rtype: bool\n";
+
+static int DensityLowerThanUP1D___init__( BPy_DensityLowerThanUP1D* self, PyObject *args )
+{
+ double d1, d2 = 2.0;
+
+ if( !PyArg_ParseTuple(args, "d|d", &d1, &d2) )
+ return -1;
+
+ self->py_up1D.up1D = new Predicates1D::DensityLowerThanUP1D(d1,d2);
+ return 0;
+}
+
+/*-----------------------BPy_DensityLowerThanUP1D type definition ------------------------------*/
+
+PyTypeObject DensityLowerThanUP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "DensityLowerThanUP1D", /* tp_name */
+ sizeof(BPy_DensityLowerThanUP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ DensityLowerThanUP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)DensityLowerThanUP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.h b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.h
new file mode 100644
index 00000000000..2862b060a0a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_DENSITYLOWERTHANUP1D_H
+#define FREESTYLE_PYTHON_DENSITYLOWERTHANUP1D_H
+
+#include "../BPy_UnaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject DensityLowerThanUP1D_Type;
+
+#define BPy_DensityLowerThanUP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &DensityLowerThanUP1D_Type) )
+
+/*---------------------------Python BPy_DensityLowerThanUP1D structure definition----------*/
+typedef struct {
+ BPy_UnaryPredicate1D py_up1D;
+} BPy_DensityLowerThanUP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_DENSITYLOWERTHANUP1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp
new file mode 100644
index 00000000000..2310f5792c5
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp
@@ -0,0 +1,89 @@
+#include "BPy_EqualToChainingTimeStampUP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char EqualToChainingTimeStampUP1D___doc__[] =
+"Class hierarchy: :class:`UnaryPredicate1D` > :class:`EqualToChainingTimeStampUP1D`\n"
+"\n"
+".. method:: __init__(ts)\n"
+"\n"
+" Builds a EqualToChainingTimeStampUP1D object.\n"
+"\n"
+" :arg ts: A time stamp value.\n"
+" :type ts: int\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns true if the Interface1D's time stamp is equal to a certain\n"
+" user-defined value.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: True if the time stamp is equal to a user-defined value.\n"
+" :rtype: bool\n";
+
+static int EqualToChainingTimeStampUP1D___init__( BPy_EqualToChainingTimeStampUP1D* self, PyObject *args )
+{
+ unsigned u;
+
+ if( !PyArg_ParseTuple(args, "I", &u) )
+ return -1;
+
+ self->py_up1D.up1D = new Predicates1D::EqualToChainingTimeStampUP1D(u);
+ return 0;
+}
+
+/*-----------------------BPy_EqualToChainingTimeStampUP1D type definition ------------------------------*/
+
+PyTypeObject EqualToChainingTimeStampUP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "EqualToChainingTimeStampUP1D", /* tp_name */
+ sizeof(BPy_EqualToChainingTimeStampUP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ EqualToChainingTimeStampUP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)EqualToChainingTimeStampUP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.h b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.h
new file mode 100644
index 00000000000..39423423b8e
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_EQUALTOCHAININGTIMESTAMPUP1D_H
+#define FREESTYLE_PYTHON_EQUALTOCHAININGTIMESTAMPUP1D_H
+
+#include "../BPy_UnaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject EqualToChainingTimeStampUP1D_Type;
+
+#define BPy_EqualToChainingTimeStampUP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &EqualToChainingTimeStampUP1D_Type) )
+
+/*---------------------------Python BPy_EqualToChainingTimeStampUP1D structure definition----------*/
+typedef struct {
+ BPy_UnaryPredicate1D py_up1D;
+} BPy_EqualToChainingTimeStampUP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_EQUALTOCHAININGTIMESTAMPUP1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp
new file mode 100644
index 00000000000..97415b2b28f
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp
@@ -0,0 +1,89 @@
+#include "BPy_EqualToTimeStampUP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char EqualToTimeStampUP1D___doc__[] =
+"Class hierarchy: :class:`UnaryPredicate1D` > :class:`EqualToTimeStampUP1D`\n"
+"\n"
+".. method:: __init__(ts)\n"
+"\n"
+" Builds a EqualToTimeStampUP1D object.\n"
+"\n"
+" :arg ts: A time stamp value.\n"
+" :type ts: int\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns true if the Interface1D's time stamp is equal to a certain\n"
+" user-defined value.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: True if the time stamp is equal to a user-defined value.\n"
+" :rtype: bool\n";
+
+static int EqualToTimeStampUP1D___init__( BPy_EqualToTimeStampUP1D* self, PyObject *args )
+{
+ unsigned u;
+
+ if( !PyArg_ParseTuple(args, "I", &u) )
+ return -1;
+
+ self->py_up1D.up1D = new Predicates1D::EqualToTimeStampUP1D(u);
+ return 0;
+}
+
+/*-----------------------BPy_EqualToTimeStampUP1D type definition ------------------------------*/
+
+PyTypeObject EqualToTimeStampUP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "EqualToTimeStampUP1D", /* tp_name */
+ sizeof(BPy_EqualToTimeStampUP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ EqualToTimeStampUP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)EqualToTimeStampUP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.h b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.h
new file mode 100644
index 00000000000..538dc400dc2
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_EQUALTOTIMESTAMPUP1D_H
+#define FREESTYLE_PYTHON_EQUALTOTIMESTAMPUP1D_H
+
+#include "../BPy_UnaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject EqualToTimeStampUP1D_Type;
+
+#define BPy_EqualToTimeStampUP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &EqualToTimeStampUP1D_Type) )
+
+/*---------------------------Python BPy_EqualToTimeStampUP1D structure definition----------*/
+typedef struct {
+ BPy_UnaryPredicate1D py_up1D;
+} BPy_EqualToTimeStampUP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_EQUALTOTIMESTAMPUP1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp
new file mode 100644
index 00000000000..3c9156f3a89
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp
@@ -0,0 +1,81 @@
+#include "BPy_ExternalContourUP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ExternalContourUP1D___doc__[] =
+"Class hierarchy: :class:`UnaryPredicate1D` > :class:`ExternalContourUP1D`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns true if the Interface1D is an external contour. An\n"
+" Interface1D is an external contour if it is borded by no shape on\n"
+" one of its sides.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: True if the Interface1D is an external contour, false\n"
+" otherwise.\n"
+" :rtype: bool\n";
+
+static int ExternalContourUP1D___init__( BPy_ExternalContourUP1D* self, PyObject *args )
+{
+ if(!( PyArg_ParseTuple(args, "") ))
+ return -1;
+ self->py_up1D.up1D = new Predicates1D::ExternalContourUP1D();
+ return 0;
+}
+
+/*-----------------------BPy_ExternalContourUP1D type definition ------------------------------*/
+
+PyTypeObject ExternalContourUP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ExternalContourUP1D", /* tp_name */
+ sizeof(BPy_ExternalContourUP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ExternalContourUP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ExternalContourUP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.h b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.h
new file mode 100644
index 00000000000..31300f04dfe
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_EXTERNALCONTOURUP1D_H
+#define FREESTYLE_PYTHON_EXTERNALCONTOURUP1D_H
+
+#include "../BPy_UnaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ExternalContourUP1D_Type;
+
+#define BPy_ExternalContourUP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ExternalContourUP1D_Type) )
+
+/*---------------------------Python BPy_ExternalContourUP1D structure definition----------*/
+typedef struct {
+ BPy_UnaryPredicate1D py_up1D;
+} BPy_ExternalContourUP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_EXTERNALCONTOURUP1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_FalseUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_FalseUP1D.cpp
new file mode 100644
index 00000000000..ac878a7770b
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_FalseUP1D.cpp
@@ -0,0 +1,78 @@
+#include "BPy_FalseUP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char FalseUP1D___doc__[] =
+"Class hierarchy: :class:`UnaryPredicate1D` > :class:`FalseUP1D`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Always returns false.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: False.\n"
+" :rtype: bool\n";
+
+static int FalseUP1D___init__( BPy_FalseUP1D* self, PyObject *args )
+{
+ if(!( PyArg_ParseTuple(args, "") ))
+ return -1;
+ self->py_up1D.up1D = new Predicates1D::FalseUP1D();
+ return 0;
+}
+
+/*-----------------------BPy_FalseUP1D type definition ------------------------------*/
+
+PyTypeObject FalseUP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "FalseUP1D", /* tp_name */
+ sizeof(BPy_FalseUP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ FalseUP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)FalseUP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_FalseUP1D.h b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_FalseUP1D.h
new file mode 100644
index 00000000000..273e4962db9
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_FalseUP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_FALSEUP1D_H
+#define FREESTYLE_PYTHON_FALSEUP1D_H
+
+#include "../BPy_UnaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject FalseUP1D_Type;
+
+#define BPy_FalseUP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &FalseUP1D_Type) )
+
+/*---------------------------Python BPy_FalseUP1D structure definition----------*/
+typedef struct {
+ BPy_UnaryPredicate1D py_up1D;
+} BPy_FalseUP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_FALSEUP1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.cpp
new file mode 100644
index 00000000000..cabc4689a03
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.cpp
@@ -0,0 +1,92 @@
+#include "BPy_QuantitativeInvisibilityUP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char QuantitativeInvisibilityUP1D___doc__[] =
+"Class hierarchy: :class:`UnaryPredicate1D` > :class:`QuantitativeInvisibilityUP1D`\n"
+"\n"
+".. method:: __init__(qi=0)\n"
+"\n"
+" Builds a QuantitativeInvisibilityUP1D object.\n"
+"\n"
+" :arg qi: The Quantitative Invisibility you want the Interface1D to\n"
+" have.\n"
+" :type qi: int\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns true if the Quantitative Invisibility evaluated at an\n"
+" Interface1D, using the :class:`QuantitativeInvisibilityF1D`\n"
+" functor, equals a certain user-defined value.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: True if Quantitative Invisibility equals a user-defined\n"
+" value.\n"
+" :rtype: bool\n";
+
+static int QuantitativeInvisibilityUP1D___init__( BPy_QuantitativeInvisibilityUP1D* self, PyObject *args )
+{
+ int i = 0;
+
+ if( !PyArg_ParseTuple(args, "|i", &i) )
+ return -1;
+
+ self->py_up1D.up1D = new Predicates1D::QuantitativeInvisibilityUP1D(i);
+ return 0;
+}
+
+/*-----------------------BPy_QuantitativeInvisibilityUP1D type definition ------------------------------*/
+
+PyTypeObject QuantitativeInvisibilityUP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "QuantitativeInvisibilityUP1D", /* tp_name */
+ sizeof(BPy_QuantitativeInvisibilityUP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ QuantitativeInvisibilityUP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)QuantitativeInvisibilityUP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.h b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.h
new file mode 100644
index 00000000000..f120ecb9778
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_QUANTITATIVEINVISIBILITYUP1D_H
+#define FREESTYLE_PYTHON_QUANTITATIVEINVISIBILITYUP1D_H
+
+#include "../BPy_UnaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject QuantitativeInvisibilityUP1D_Type;
+
+#define BPy_QuantitativeInvisibilityUP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &QuantitativeInvisibilityUP1D_Type) )
+
+/*---------------------------Python BPy_QuantitativeInvisibilityUP1D structure definition----------*/
+typedef struct {
+ BPy_UnaryPredicate1D py_up1D;
+} BPy_QuantitativeInvisibilityUP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_QUANTITATIVEINVISIBILITYUP1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp
new file mode 100644
index 00000000000..9e6e57c8d94
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp
@@ -0,0 +1,92 @@
+#include "BPy_ShapeUP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char ShapeUP1D___doc__[] =
+"Class hierarchy: :class:`UnaryPredicate1D` > :class:`ShapeUP1D`\n"
+"\n"
+".. method:: __init__(idFirst, idSecond=0)\n"
+"\n"
+" Builds a ShapeUP1D object.\n"
+"\n"
+" :arg idFirst: The first Id component.\n"
+" :type idFirst: int\n"
+" :arg idSecond: The second Id component.\n"
+" :type idSecond: int\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns true if the shape to which the Interface1D belongs to has\n"
+" the same :class:`Id` as the one specified by the user.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: True if Interface1D belongs to the shape of the\n"
+" user-specified Id.\n"
+" :rtype: bool\n";
+
+static int ShapeUP1D___init__( BPy_ShapeUP1D* self, PyObject *args )
+{
+ unsigned u1, u2 = 0;
+
+ if( !PyArg_ParseTuple(args, "I|I", &u1, &u2) )
+ return -1;
+
+ self->py_up1D.up1D = new Predicates1D::ShapeUP1D(u1,u2);
+ return 0;
+}
+
+/*-----------------------BPy_ShapeUP1D type definition ------------------------------*/
+
+PyTypeObject ShapeUP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "ShapeUP1D", /* tp_name */
+ sizeof(BPy_ShapeUP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ ShapeUP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)ShapeUP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.h b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.h
new file mode 100644
index 00000000000..ce6d0276edd
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_SHAPEUP1D_H
+#define FREESTYLE_PYTHON_SHAPEUP1D_H
+
+#include "../BPy_UnaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject ShapeUP1D_Type;
+
+#define BPy_ShapeUP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &ShapeUP1D_Type) )
+
+/*---------------------------Python BPy_ShapeUP1D structure definition----------*/
+typedef struct {
+ BPy_UnaryPredicate1D py_up1D;
+} BPy_ShapeUP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_SHAPEUP1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_TrueUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_TrueUP1D.cpp
new file mode 100644
index 00000000000..01da1a44453
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_TrueUP1D.cpp
@@ -0,0 +1,78 @@
+#include "BPy_TrueUP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char TrueUP1D___doc__[] =
+"Class hierarchy: :class:`UnaryPredicate1D` > :class:`TrueUP1D`\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Always returns true.\n"
+"\n"
+" :arg inter: An Interface1D object.\n"
+" :type inter: :class:`Interface1D`\n"
+" :return: True.\n"
+" :rtype: bool\n";
+
+static int TrueUP1D___init__( BPy_TrueUP1D* self, PyObject *args )
+{
+ if(!( PyArg_ParseTuple(args, "") ))
+ return -1;
+ self->py_up1D.up1D = new Predicates1D::TrueUP1D();
+ return 0;
+}
+
+/*-----------------------BPy_TrueUP1D type definition ------------------------------*/
+
+PyTypeObject TrueUP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "TrueUP1D", /* tp_name */
+ sizeof(BPy_TrueUP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ TrueUP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)TrueUP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_TrueUP1D.h b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_TrueUP1D.h
new file mode 100644
index 00000000000..5a01ad42d2a
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_TrueUP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_TRUEUP1D_H
+#define FREESTYLE_PYTHON_TRUEUP1D_H
+
+#include "../BPy_UnaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject TrueUP1D_Type;
+
+#define BPy_TrueUP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &TrueUP1D_Type) )
+
+/*---------------------------Python BPy_TrueUP1D structure definition----------*/
+typedef struct {
+ BPy_UnaryPredicate1D py_up1D;
+} BPy_TrueUP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_TRUEUP1D_H */
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.cpp
new file mode 100644
index 00000000000..9beae103113
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.cpp
@@ -0,0 +1,88 @@
+#include "BPy_WithinImageBoundaryUP1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+//------------------------INSTANCE METHODS ----------------------------------
+
+static char WithinImageBoundaryUP1D___doc__[] =
+"Class hierarchy: :class:`UnaryPredicate1D` > :class:`WithinImageBoundaryUP1D`\n"
+"\n"
+".. method:: __init__(xmin, ymin, xmax, ymax)\n"
+"\n"
+" Builds an WithinImageBoundaryUP1D object.\n"
+"\n"
+" :arg xmin: X lower bound of the image boundary.\n"
+" :type xmin: float\n"
+" :arg ymin: Y lower bound of the image boundary.\n"
+" :type ymin: float\n"
+" :arg xmax: X upper bound of the image boundary.\n"
+" :type xmax: float\n"
+" :arg ymax: Y upper bound of the image boundary.\n"
+" :type ymax: float\n"
+"\n"
+".. method:: __call__(inter)\n"
+"\n"
+" Returns true if the Interface1D intersects with image boundary.\n";
+
+static int WithinImageBoundaryUP1D___init__( BPy_WithinImageBoundaryUP1D* self, PyObject *args )
+{
+ double xmin, ymin, xmax, ymax;
+
+ if(!( PyArg_ParseTuple(args, "dddd", &xmin, &ymin, &xmax, &ymax) ))
+ return -1;
+ self->py_up1D.up1D = new Predicates1D::WithinImageBoundaryUP1D(xmin, ymin, xmax, ymax);
+ return 0;
+}
+
+/*-----------------------BPy_TrueUP1D type definition ------------------------------*/
+
+PyTypeObject WithinImageBoundaryUP1D_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "WithinImageBoundaryUP1D", /* tp_name */
+ sizeof(BPy_WithinImageBoundaryUP1D), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ WithinImageBoundaryUP1D___doc__, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &UnaryPredicate1D_Type, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)WithinImageBoundaryUP1D___init__, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.h b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.h
new file mode 100644
index 00000000000..2bd3e698a21
--- /dev/null
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.h
@@ -0,0 +1,29 @@
+#ifndef FREESTYLE_PYTHON_WITHINIMAGEBOUNDARYUP1D_H
+#define FREESTYLE_PYTHON_WITHINIMAGEBOUNDARYUP1D_H
+
+#include "../BPy_UnaryPredicate1D.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#include <Python.h>
+
+extern PyTypeObject WithinImageBoundaryUP1D_Type;
+
+#define BPy_WithinImageBoundaryUP1D_Check(v) ( PyObject_IsInstance( (PyObject *) v, (PyObject *) &WithinImageBoundaryUP1D_Type) )
+
+/*---------------------------Python BPy_WithinImageBoundaryUP1D structure definition----------*/
+typedef struct {
+ BPy_UnaryPredicate1D py_up1D;
+} BPy_WithinImageBoundaryUP1D;
+
+///////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* FREESTYLE_PYTHON_WITHINIMAGEBOUNDARYUP1D_H */
diff --git a/source/blender/freestyle/intern/scene_graph/DrawingStyle.h b/source/blender/freestyle/intern/scene_graph/DrawingStyle.h
new file mode 100644
index 00000000000..000b6c8575d
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/DrawingStyle.h
@@ -0,0 +1,128 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_DRAWING_STYLE_H__
+#define __FREESTYLE_DRAWING_STYLE_H__
+
+/** \file blender/freestyle/intern/scene_graph/DrawingStyle.h
+ * \ingroup freestyle
+ * \brief Class to define the drawing style of a node
+ * \author Stephane Grabli
+ * \date 10/10/2002
+ */
+
+class DrawingStyle
+{
+public:
+ enum STYLE {
+ FILLED,
+ LINES,
+ POINTS,
+ INVISIBLE,
+ };
+
+ inline DrawingStyle()
+ {
+ Style = FILLED;
+ LineWidth = 2.0f;
+ PointSize = 2.0f;
+ LightingEnabled = true;
+ }
+
+ inline explicit DrawingStyle(const DrawingStyle& iBrother);
+
+ virtual ~DrawingStyle() {}
+
+ /*! operators */
+ inline DrawingStyle& operator=(const DrawingStyle& ds);
+
+ inline void setStyle(const STYLE iStyle)
+ {
+ Style = iStyle;
+ }
+
+ inline void setLineWidth(const float iLineWidth)
+ {
+ LineWidth = iLineWidth;
+ }
+
+ inline void setPointSize(const float iPointSize)
+ {
+ PointSize = iPointSize;
+ }
+
+ inline void setLightingEnabled(const bool on)
+ {
+ LightingEnabled = on;
+ }
+
+ inline STYLE style() const
+ {
+ return Style;
+ }
+
+ inline float lineWidth() const
+ {
+ return LineWidth;
+ }
+
+ inline float pointSize() const
+ {
+ return PointSize;
+ }
+
+ inline bool lightingEnabled() const
+ {
+ return LightingEnabled;
+ }
+
+private:
+ STYLE Style;
+ float LineWidth;
+ float PointSize;
+ bool LightingEnabled;
+};
+
+DrawingStyle::DrawingStyle(const DrawingStyle& iBrother)
+{
+ Style = iBrother.Style;
+ LineWidth = iBrother.LineWidth;
+ PointSize = iBrother.PointSize;
+ LightingEnabled = iBrother.LightingEnabled;
+}
+
+DrawingStyle& DrawingStyle::operator=(const DrawingStyle& ds)
+{
+ Style = ds.Style;
+ LineWidth = ds.LineWidth;
+ PointSize = ds.PointSize;
+ LightingEnabled = ds.LightingEnabled;
+
+ return *this;
+}
+
+#endif // __FREESTYLE_DRAWING_STYLE_H__
diff --git a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
new file mode 100644
index 00000000000..831c384d472
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
@@ -0,0 +1,379 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_MATERIAL_H__
+#define __FREESTYLE_MATERIAL_H__
+
+/** \file blender/freestyle/intern/scene_graph/FrsMaterial.h
+ * \ingroup freestyle
+ * \brief Class used to handle materials.
+ * \author Stephane Grabli
+ * \date 10/10/2002
+ */
+
+#include "../system/FreestyleConfig.h"
+
+/*! Class defining a material */
+class FrsMaterial
+{
+public:
+ /*! Default constructor */
+ inline FrsMaterial();
+
+ /*! Builds a Material from its diffuse, ambiant, specular, emissive colors and a shininess coefficient.
+ * \param iDiffuse
+ * A 4 element float-array containing the diffuse color.
+ * \param iAmbiant
+ * A 4 element float-array containing the ambiant color.
+ * \param iSpecular
+ * A 4 element float-array containing the specular color.
+ * \param iEmission
+ * A 4 element float-array containing the emissive color.
+ * \param iShininess
+ * The shininess coefficient.
+ */
+ inline FrsMaterial(const float *iDiffuse, const float *iAmbiant, const float *iSpecular, const float *iEmission,
+ const float iShininess);
+
+ /*! Copy constructor */
+ inline FrsMaterial(const FrsMaterial& m);
+
+ /*! Destructor */
+ virtual ~FrsMaterial() {}
+
+
+ /*! Returns the diffuse color as a 4 float array */
+ inline const float *diffuse() const
+ {
+ return Diffuse;
+ }
+
+ /*! Returns the red component of the diffuse color */
+ inline const float diffuseR() const
+ {
+ return Diffuse[0];
+ }
+
+ /*! Returns the green component of the diffuse color */
+ inline const float diffuseG() const
+ {
+ return Diffuse[1];
+ }
+
+ /*! Returns the blue component of the diffuse color */
+ inline const float diffuseB() const
+ {
+ return Diffuse[2];
+ }
+
+ /*! Returns the alpha component of the diffuse color */
+ inline const float diffuseA() const
+ {
+ return Diffuse[3];
+ }
+
+ /*! Returns the specular color as a 4 float array */
+ inline const float *specular() const
+ {
+ return Specular;
+ }
+
+ /*! Returns the red component of the specular color */
+ inline const float specularR() const
+ {
+ return Specular[0];
+ }
+
+ /*! Returns the green component of the specular color */
+ inline const float specularG() const
+ {
+ return Specular[1];
+ }
+
+ /*! Returns the blue component of the specular color */
+ inline const float specularB() const
+ {
+ return Specular[2];
+ }
+
+ /*! Returns the alpha component of the specular color */
+ inline const float specularA() const
+ {
+ return Specular[3];
+ }
+
+ /*! Returns the ambiant color as a 4 float array */
+ inline const float *ambient() const
+ {
+ return Ambient;
+ }
+
+ /*! Returns the red component of the ambiant color */
+ inline const float ambientR() const
+ {
+ return Ambient[0];
+ }
+
+ /*! Returns the green component of the ambiant color */
+ inline const float ambientG() const
+ {
+ return Ambient[1];
+ }
+
+ /*! Returns the blue component of the ambiant color */
+ inline const float ambientB() const
+ {
+ return Ambient[2];
+ }
+
+ /*! Returns the alpha component of the ambiant color */
+ inline const float ambientA() const
+ {
+ return Ambient[3];
+ }
+
+ /*! Returns the emissive color as a 4 float array */
+ inline const float *emission() const
+ {
+ return Emission;
+ }
+
+ /*! Returns the red component of the emissive color */
+ inline const float emissionR() const
+ {
+ return Emission[0];
+ }
+
+ /*! Returns the green component of the emissive color */
+ inline const float emissionG() const
+ {
+ return Emission[1];
+ }
+
+ /*! Returns the blue component of the emissive color */
+ inline const float emissionB() const
+ {
+ return Emission[2];
+ }
+
+ /*! Returns the alpha component of the emissive color */
+ inline const float emissionA() const
+ {
+ return Emission[3];
+ }
+
+ /*! Returns the shininess coefficient */
+ inline const float shininess() const
+ {
+ return Shininess;
+ }
+
+ /*! Sets the diffuse color.
+ * \param r
+ * Red component
+ * \param g
+ * Green component
+ * \param b
+ * Blue component
+ * \param a
+ * Alpha component
+ */
+ inline void setDiffuse(const float r, const float g, const float b, const float a);
+
+ /*! Sets the specular color.
+ * \param r
+ * Red component
+ * \param g
+ * Green component
+ * \param b
+ * Blue component
+ * \param a
+ * Alpha component
+ */
+ inline void setSpecular(const float r, const float g, const float b, const float a);
+
+ /*! Sets the ambiant color.
+ * \param r
+ * Red component
+ * \param g
+ * Green component
+ * \param b
+ * Blue component
+ * \param a
+ * Alpha component
+ */
+ inline void setAmbient(const float r, const float g, const float b, const float a);
+
+ /*! Sets the emissive color.
+ * \param r
+ * Red component
+ * \param g
+ * Green component
+ * \param b
+ * Blue component
+ * \param a
+ * Alpha component
+ */
+ inline void setEmission(const float r, const float g, const float b, const float a);
+
+ /*! Sets the shininess.
+ * \param s
+ * Shininess
+ */
+ inline void setShininess(const float s);
+
+ /* operators */
+ inline FrsMaterial& operator=(const FrsMaterial& m);
+ inline bool operator!=(const FrsMaterial& m) const;
+ inline bool operator==(const FrsMaterial& m) const;
+
+private:
+ /*! Material properties */
+ float Diffuse[4];
+ float Specular[4];
+ float Ambient[4];
+ float Emission[4];
+ float Shininess;
+};
+
+FrsMaterial::FrsMaterial()
+{
+ Ambient[0] = Ambient[1] = Ambient[2] = 0.2f;
+ Ambient[3] = 1.0f;
+
+ Diffuse[0] = Diffuse[1] = Diffuse[2] = 0.8f;
+ Diffuse[3] = 1.0f;
+
+ Emission[0] = Emission[1] = Emission[2] = 0.0f;
+ Emission[3] = 1.0f;
+
+ Specular[0] = Specular[1] = Specular[2] = 0.0f;
+ Specular[3] = 1.0f;
+
+ Shininess = 0.0f;
+}
+
+FrsMaterial::FrsMaterial(const float *iDiffuse, const float *iAmbiant, const float *iSpecular, const float *iEmission,
+ const float iShininess)
+{
+ for (int i = 0; i < 4; i++) {
+ Diffuse[i] = iDiffuse[i];
+ Specular[i] = iSpecular[i];
+ Ambient[i] = iAmbiant[i];
+ Emission[i] = iEmission[i];
+ }
+
+ Shininess = iShininess;
+}
+
+FrsMaterial::FrsMaterial(const FrsMaterial& m)
+{
+ for (int i = 0; i < 4; i++) {
+ Diffuse[i] = m.diffuse()[i];
+ Specular[i] = m.specular()[i];
+ Ambient[i] = m.ambient()[i];
+ Emission[i] = m.emission()[i];
+ }
+
+ Shininess = m.shininess();
+}
+
+void FrsMaterial::setDiffuse(const float r, const float g, const float b, const float a)
+{
+ Diffuse[0] = r;
+ Diffuse[1] = g;
+ Diffuse[2] = b;
+ Diffuse[3] = a;
+}
+
+void FrsMaterial::setSpecular(const float r, const float g, const float b, const float a)
+{
+ Specular[0] = r;
+ Specular[1] = g;
+ Specular[2] = b;
+ Specular[3] = a;
+}
+
+void FrsMaterial::setAmbient(const float r, const float g, const float b, const float a)
+{
+ Ambient[0] = r;
+ Ambient[1] = g;
+ Ambient[2] = b;
+ Ambient[3] = a;
+}
+
+void FrsMaterial::setEmission(const float r, const float g, const float b, const float a)
+{
+ Emission[0] = r;
+ Emission[1] = g;
+ Emission[2] = b;
+ Emission[3] = a;
+}
+
+void FrsMaterial::setShininess(const float s)
+{
+ Shininess = s;
+}
+
+FrsMaterial& FrsMaterial::operator=(const FrsMaterial& m)
+{
+ for (int i = 0; i < 4; i++) {
+ Diffuse[i] = m.diffuse()[i];
+ Specular[i] = m.specular()[i];
+ Ambient[i] = m.ambient()[i];
+ Emission[i] = m.emission()[i];
+ }
+
+ Shininess = m.shininess();
+ return *this;
+}
+
+bool FrsMaterial::operator!=(const FrsMaterial& m) const
+{
+ if (Shininess != m.shininess())
+ return true;
+
+ for (int i = 0; i < 4; i++) {
+ if (Diffuse[i] != m.diffuse()[i])
+ return true;
+ if (Specular[i] != m.specular()[i])
+ return true;
+ if (Ambient[i] != m.ambient()[i])
+ return true;
+ if (Emission[i] != m.emission()[i])
+ return true;
+ }
+
+ return false;
+}
+
+bool FrsMaterial::operator==(const FrsMaterial& m) const
+{
+ return (!((*this) != m));
+}
+
+#endif // __FREESTYLE_MATERIAL_H__
diff --git a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp
new file mode 100644
index 00000000000..f373b730d0f
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp
@@ -0,0 +1,331 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/IndexedFaceSet.cpp
+ * \ingroup freestyle
+ * \brief A Set of indexed faces to represent a surfacic object
+ * \author Stephane Grabli
+ * \date 22/01/2002
+ */
+
+#include "IndexedFaceSet.h"
+
+IndexedFaceSet::IndexedFaceSet() : Rep()
+{
+ _Vertices = NULL;
+ _Normals = NULL;
+ _FrsMaterials = 0;
+ _TexCoords = 0;
+ _FaceEdgeMarks = 0;
+ _VSize = 0;
+ _NSize = 0;
+ _MSize = 0;
+ _TSize = 0;
+ _NumFaces = 0;
+ _NumVertexPerFace = NULL;
+ _FaceStyle = NULL;
+ _VIndices = NULL;
+ _VISize = 0;
+ _NIndices = NULL;
+ _NISize = 0;
+ _MIndices = NULL;
+ _MISize = 0;
+ _TIndices = NULL;
+ _TISize = 0;
+ _displayList = 0;
+}
+
+IndexedFaceSet::IndexedFaceSet(real *iVertices, unsigned iVSize, real *iNormals, unsigned iNSize,
+ FrsMaterial **iMaterials, unsigned iMSize, real *iTexCoords, unsigned iTSize,
+ unsigned iNumFaces, unsigned *iNumVertexPerFace, TRIANGLES_STYLE *iFaceStyle,
+ FaceEdgeMark *iFaceEdgeMarks, unsigned *iVIndices, unsigned iVISize,
+ unsigned *iNIndices, unsigned iNISize, unsigned *iMIndices, unsigned iMISize,
+ unsigned *iTIndices, unsigned iTISize, unsigned iCopy)
+: Rep()
+{
+ if (1 == iCopy) {
+ _VSize = iVSize;
+ _Vertices = new real[_VSize];
+ memcpy(_Vertices, iVertices, iVSize * sizeof(real));
+
+ _NSize = iNSize;
+ _Normals = new real[_NSize];
+ memcpy(_Normals, iNormals, iNSize * sizeof(real));
+
+ _MSize = iMSize;
+ _FrsMaterials = 0;
+ if (iMaterials) {
+ _FrsMaterials = new FrsMaterial * [_MSize];
+ for (unsigned int i = 0; i < _MSize; ++i)
+ _FrsMaterials[i] = new FrsMaterial(*(iMaterials[i]));
+ }
+ _TSize = iTSize;
+ _TexCoords = 0;
+ if (_TSize) {
+ _TexCoords = new real[_TSize];
+ memcpy(_TexCoords, iTexCoords, iTSize * sizeof(real));
+ }
+
+ _NumFaces = iNumFaces;
+ _NumVertexPerFace = new unsigned[_NumFaces];
+ memcpy(_NumVertexPerFace, iNumVertexPerFace, _NumFaces * sizeof(unsigned));
+
+ _FaceStyle = new TRIANGLES_STYLE[_NumFaces];
+ memcpy(_FaceStyle, iFaceStyle, _NumFaces * sizeof(TRIANGLES_STYLE));
+
+ _FaceEdgeMarks = new FaceEdgeMark[_NumFaces];
+ memcpy(_FaceEdgeMarks, iFaceEdgeMarks, _NumFaces * sizeof(FaceEdgeMark));
+
+ _VISize = iVISize;
+ _VIndices = new unsigned[_VISize];
+ memcpy(_VIndices, iVIndices, _VISize * sizeof(unsigned));
+
+ _NISize = iNISize;
+ _NIndices = new unsigned[_NISize];
+ memcpy(_NIndices, iNIndices, _NISize * sizeof(unsigned));
+
+ _MISize = iMISize;
+ _MIndices = 0;
+ if (iMIndices) {
+ _MIndices = new unsigned[_MISize];
+ memcpy(_MIndices, iMIndices, _MISize * sizeof(unsigned));
+ }
+ _TISize = iTISize;
+ _TIndices = 0;
+ if (_TISize) {
+ _TIndices = new unsigned[_TISize];
+ memcpy(_TIndices, iTIndices, _TISize * sizeof(unsigned));
+ }
+ }
+ else {
+ _VSize = iVSize;
+ _Vertices = iVertices;
+
+ _NSize = iNSize;
+ _Normals = iNormals;
+
+ _MSize = iMSize;
+ _FrsMaterials = 0;
+ if (iMaterials)
+ _FrsMaterials = iMaterials;
+
+ _TSize = iTSize;
+ _TexCoords = iTexCoords;
+
+ _NumFaces = iNumFaces;
+ _NumVertexPerFace = iNumVertexPerFace;
+ _FaceStyle = iFaceStyle;
+ _FaceEdgeMarks = iFaceEdgeMarks;
+
+ _VISize = iVISize;
+ _VIndices = iVIndices;
+
+ _NISize = iNISize;
+ _NIndices = iNIndices;
+
+ _MISize = iMISize;
+ _MIndices = 0;
+ if (iMISize)
+ _MIndices = iMIndices;
+
+ _TISize = iTISize;
+ _TIndices = iTIndices;
+ }
+
+ _displayList = 0;
+}
+
+IndexedFaceSet::IndexedFaceSet(const IndexedFaceSet& iBrother) : Rep(iBrother)
+{
+ _VSize = iBrother.vsize();
+ _Vertices = new real[_VSize];
+ memcpy(_Vertices, iBrother.vertices(), _VSize * sizeof(real));
+
+ _NSize = iBrother.nsize();
+ _Normals = new real[_NSize];
+ memcpy(_Normals, iBrother.normals(), _NSize * sizeof(real));
+
+ _MSize = iBrother.msize();
+ if (_MSize) {
+ _FrsMaterials = new FrsMaterial * [_MSize];
+ for (unsigned int i = 0; i < _MSize; ++i) {
+ _FrsMaterials[i] = new FrsMaterial(*(iBrother._FrsMaterials[i]));
+ }
+ }
+ else {
+ _FrsMaterials = 0;
+ }
+
+ _TSize = iBrother.tsize();
+ _TexCoords = 0;
+ if (_TSize) {
+ _TexCoords = new real[_TSize];
+ memcpy(_TexCoords, iBrother.texCoords(), _TSize * sizeof(real));
+ }
+
+ _NumFaces = iBrother.numFaces();
+ _NumVertexPerFace = new unsigned[_NumFaces];
+ memcpy(_NumVertexPerFace, iBrother.numVertexPerFaces(), _NumFaces * sizeof(unsigned));
+
+ _FaceStyle = new TRIANGLES_STYLE[_NumFaces];
+ memcpy(_FaceStyle, iBrother.trianglesStyle(), _NumFaces * sizeof(TRIANGLES_STYLE));
+
+ _FaceEdgeMarks = new FaceEdgeMark[_NumFaces];
+ memcpy(_FaceEdgeMarks, iBrother.faceEdgeMarks(), _NumFaces * sizeof(FaceEdgeMark));
+
+ _VISize = iBrother.visize();
+ _VIndices = new unsigned[_VISize];
+ memcpy(_VIndices, iBrother.vindices(), _VISize * sizeof(unsigned));
+
+ _NISize = iBrother.nisize();
+ _NIndices = new unsigned[_NISize];
+ memcpy(_NIndices, iBrother.nindices(), _NISize * sizeof(unsigned));
+
+ _MISize = iBrother.misize();
+ if (_MISize) {
+ _MIndices = new unsigned[_MISize];
+ memcpy(_MIndices, iBrother.mindices(), _MISize * sizeof(unsigned));
+ }
+ else {
+ _MIndices = 0;
+ }
+
+ _TISize = iBrother.tisize();
+ _TIndices = 0;
+ if (_TISize) {
+ _TIndices = new unsigned[_TISize];
+ memcpy(_TIndices, iBrother.tindices(), _TISize * sizeof(unsigned));
+ }
+
+ _displayList = 0;
+}
+
+IndexedFaceSet::~IndexedFaceSet()
+{
+ if (NULL != _Vertices) {
+ delete[] _Vertices;
+ _Vertices = NULL;
+ }
+
+ if (NULL != _Normals)
+ {
+ delete[] _Normals;
+ _Normals = NULL;
+ }
+
+ if (NULL != _FrsMaterials) {
+ for (unsigned int i = 0; i < _MSize; ++i)
+ delete _FrsMaterials[i];
+ delete[] _FrsMaterials;
+ _FrsMaterials = NULL;
+ }
+
+ if (NULL != _TexCoords) {
+ delete[] _TexCoords;
+ _TexCoords = NULL;
+ }
+
+ if (NULL != _NumVertexPerFace) {
+ delete[] _NumVertexPerFace;
+ _NumVertexPerFace = NULL;
+ }
+
+ if (NULL != _FaceStyle) {
+ delete[] _FaceStyle;
+ _FaceStyle = NULL;
+ }
+
+ if (NULL != _FaceEdgeMarks) {
+ delete[] _FaceEdgeMarks;
+ _FaceEdgeMarks = NULL;
+ }
+
+ if (NULL != _VIndices) {
+ delete[] _VIndices;
+ _VIndices = NULL;
+ }
+
+ if (NULL != _NIndices) {
+ delete[] _NIndices;
+ _NIndices = NULL;
+ }
+
+ if (NULL != _MIndices) {
+ delete[] _MIndices;
+ _MIndices = NULL;
+ }
+ if (NULL != _TIndices) {
+ delete[] _TIndices;
+ _TIndices = NULL;
+ }
+
+ // should find a way to deallocates the displayList
+ // glDeleteLists(GLuint list, GLSizei range)
+ _displayList = 0;
+}
+
+void IndexedFaceSet::accept(SceneVisitor& v)
+{
+ Rep::accept(v);
+ v.visitIndexedFaceSet(*this);
+}
+
+void IndexedFaceSet::ComputeBBox()
+{
+ real XMax = _Vertices[0];
+ real YMax = _Vertices[1];
+ real ZMax = _Vertices[2];
+
+ real XMin = _Vertices[0];
+ real YMin = _Vertices[1];
+ real ZMin = _Vertices[2];
+
+ // parse all the coordinates to find the Xmax, YMax, ZMax
+ real *v = _Vertices;
+
+ for (unsigned int i = 0; i < (_VSize / 3); ++i) {
+ if (*v > XMax)
+ XMax = *v;
+ if (*v < XMin)
+ XMin = *v;
+ ++v;
+
+ if (*v > YMax)
+ YMax = *v;
+ if (*v < YMin)
+ YMin = *v;
+ ++v;
+
+ if (*v > ZMax)
+ ZMax = *v;
+ if (*v < ZMin)
+ ZMin = *v;
+ ++v;
+ }
+
+ setBBox(BBox<Vec3r>(Vec3r(XMin, YMin, ZMin), Vec3r(XMax, YMax, ZMax)));
+}
diff --git a/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h
new file mode 100644
index 00000000000..6ec769f4caf
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/IndexedFaceSet.h
@@ -0,0 +1,322 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_INDEXED_FACE_SET_H__
+#define __FREESTYLE_INDEXED_FACE_SET_H__
+
+/** \file blender/freestyle/intern/scene_graph/IndexedFaceSet.h
+ * \ingroup freestyle
+ * \brief A Set of indexed faces to represent a surfacic object
+ * \author Stephane Grabli
+ * \date 22/01/2002
+ */
+
+#include <memory.h>
+#include <stdio.h>
+
+//! inherits from class Rep
+#include "Rep.h"
+
+#include "../system/FreestyleConfig.h"
+
+class LIB_SCENE_GRAPH_EXPORT IndexedFaceSet : public Rep
+{
+public:
+ /*! Triangles description style:*/
+ enum TRIANGLES_STYLE {
+ TRIANGLE_STRIP,
+ TRIANGLE_FAN,
+ TRIANGLES,
+ };
+
+ /*! User-specified face and edge marks for feature edge detection */
+ /* XXX Why in hel not use an enum here too? */
+ typedef unsigned char FaceEdgeMark;
+ static const FaceEdgeMark FACE_MARK = 1 << 0;
+ static const FaceEdgeMark EDGE_MARK_V1V2 = 1 << 1;
+ static const FaceEdgeMark EDGE_MARK_V2V3 = 1 << 2;
+ static const FaceEdgeMark EDGE_MARK_V3V1 = 1 << 3;
+
+ /*! Builds an empty indexed face set */
+ IndexedFaceSet();
+
+ /*! Builds an indexed face set
+ * iVertices
+ * The array of object vertices 3D coordinates (for all faces).
+ * If iCopy != 0, the array is copied; you must desallocate iVertices. Else you must not.
+ * iVSize
+ * The size of iVertices (must be a multiple of 3)
+ * iNormals
+ * The array of object normals 3D coordinates.
+ * If iCopy != 0, the array is copied; you must desallocate iNormals. Else you must not.
+ * iNSize
+ * The size of iNormals
+ * iMaterials
+ * The array of materials
+ * iMSize
+ * The size of iMaterials
+ * iTexCoords
+ * The array of texture coordinates.
+ * iTSize
+ * The size of iTexCoords (must be multiple of 2)
+ * iNumFaces
+ * The number of faces
+ * iNumVertexPerFace
+ * Array containing the number of vertices per face.
+ * iFaceStyle
+ * Array containing the description style of each faces.
+ * The style belongs to:
+ * - TRIANGLE_STRIP: the face indices describe a triangle strip
+ * - TRIANGLE_FAN : the face indices describe a triangle fan
+ * - TRIANGLES : the face indices describe single triangles
+ * If iCopy != 0, the array is copied; you must desallocate iFaceStyle. Else you must not.
+ * iVIndices,
+ * Array of vertices indices.
+ * The integers contained in this array must be multiple of 3.
+ * If iCopy != 0, the array is copied; you must desallocate iVIndices. Else you must not.
+ * iVISize
+ * The size of iVIndices.
+ * iNIndices
+ * Array of normals indices.
+ * The integers contained in this array must be multiple of 3.
+ * If iCopy != 0, the array is copied; you must desallocate iNIndices. Else you must not.
+ * iNISize
+ * The size of iNIndices
+ * iMIndices
+ * The Material indices (per vertex)
+ * iMISize
+ * The size of iMIndices
+ * iTIndices
+ * The Texture coordinates indices (per vertex). The integers contained in this array must be multiple of 2.
+ * iTISize
+ * The size of iMIndices
+ * iCopy
+ * 0 : the arrays are not copied. The pointers passed as arguments are used. IndexedFaceSet takes these
+ * arrays desallocation in charge.
+ * 1 : the arrays are copied. The caller is in charge of the arrays, passed as arguments desallocation.
+ */
+ IndexedFaceSet(real *iVertices, unsigned iVSize, real *iNormals, unsigned iNSize, FrsMaterial **iMaterials,
+ unsigned iMSize, real *iTexCoords, unsigned iTSize, unsigned iNumFaces, unsigned *iNumVertexPerFace,
+ TRIANGLES_STYLE *iFaceStyle, FaceEdgeMark *iFaceEdgeMarks, unsigned *iVIndices, unsigned iVISize,
+ unsigned *iNIndices, unsigned iNISize, unsigned *iMIndices, unsigned iMISize, unsigned *iTIndices,
+ unsigned iTISize, unsigned iCopy = 1);
+
+ /*! Builds an indexed face set from an other indexed face set */
+ IndexedFaceSet(const IndexedFaceSet& iBrother);
+
+ void swap(IndexedFaceSet& ioOther)
+ {
+ std::swap(_Vertices, ioOther._Vertices);
+ std::swap(_Normals, ioOther._Normals);
+ std::swap(_FrsMaterials, ioOther._FrsMaterials);
+ std::swap(_TexCoords, ioOther._TexCoords);
+ std::swap(_FaceEdgeMarks, ioOther._FaceEdgeMarks);
+
+ std::swap(_VSize, ioOther._VSize);
+ std::swap(_NSize, ioOther._NSize);
+ std::swap(_MSize, ioOther._MSize);
+ std::swap(_TSize, ioOther._TSize);
+
+ std::swap(_NumFaces, ioOther._NumFaces);
+ std::swap(_NumVertexPerFace, ioOther._NumVertexPerFace);
+ std::swap(_FaceStyle, ioOther._FaceStyle);
+
+ std::swap(_VIndices, ioOther._VIndices);
+ std::swap(_NIndices, ioOther._NIndices);
+ std::swap(_MIndices, ioOther._MIndices); // Material Indices
+ std::swap(_TIndices, ioOther._TIndices);
+
+ std::swap(_VISize, ioOther._VISize);
+ std::swap(_NISize, ioOther._NISize);
+ std::swap(_MISize, ioOther._MISize);
+ std::swap(_TISize, ioOther._TISize);
+
+ std::swap(_displayList, ioOther._displayList);
+
+ Rep::swap(ioOther);
+ }
+
+ IndexedFaceSet& operator=(const IndexedFaceSet& iBrother)
+ {
+ IndexedFaceSet tmp(iBrother);
+ swap(tmp);
+ return *this;
+ }
+
+ /*! Desctructor
+ * desallocates all the ressources
+ */
+ virtual ~IndexedFaceSet();
+
+ /*! Accept the corresponding visitor */
+ virtual void accept(SceneVisitor& v);
+
+ /*! Compute the Bounding Box */
+ virtual void ComputeBBox();
+
+ /*! modifiers */
+ inline void setDisplayList(unsigned int index)
+ {
+ _displayList = index;
+ }
+
+ /*! Accessors */
+ virtual const real * vertices() const
+ {
+ return _Vertices;
+ }
+
+ virtual const real * normals() const
+ {
+ return _Normals;
+ }
+
+ virtual const FrsMaterial*const* frs_materials() const
+ {
+ return _FrsMaterials;
+ }
+
+ virtual const real* texCoords() const
+ {
+ return _TexCoords;
+ }
+
+ virtual const unsigned vsize() const
+ {
+ return _VSize;
+ }
+
+ virtual const unsigned nsize() const
+ {
+ return _NSize;
+ }
+
+ virtual const unsigned msize() const
+ {
+ return _MSize;
+ }
+
+ virtual const unsigned tsize() const
+ {
+ return _TSize;
+ }
+
+ virtual const unsigned numFaces() const
+ {
+ return _NumFaces;
+ }
+
+ virtual const unsigned * numVertexPerFaces() const
+ {
+ return _NumVertexPerFace;
+ }
+
+ virtual const TRIANGLES_STYLE * trianglesStyle() const
+ {
+ return _FaceStyle;
+ }
+
+ virtual const unsigned char * faceEdgeMarks() const
+ {
+ return _FaceEdgeMarks;
+ }
+
+ virtual const unsigned* vindices() const
+ {
+ return _VIndices;
+ }
+
+ virtual const unsigned* nindices() const
+ {
+ return _NIndices;
+ }
+
+ virtual const unsigned* mindices() const
+ {
+ return _MIndices;
+ }
+
+ virtual const unsigned* tindices() const
+ {
+ return _TIndices;
+ }
+
+ virtual const unsigned visize() const
+ {
+ return _VISize;
+ }
+
+ virtual const unsigned nisize() const
+ {
+ return _NISize;
+ }
+
+ virtual const unsigned misize() const
+ {
+ return _MISize;
+ }
+
+ virtual const unsigned tisize() const
+ {
+ return _TISize;
+ }
+
+ inline unsigned int displayList() const
+ {
+ return _displayList;
+ }
+
+protected:
+ real *_Vertices;
+ real *_Normals;
+ FrsMaterial **_FrsMaterials;
+ real *_TexCoords;
+
+ unsigned _VSize;
+ unsigned _NSize;
+ unsigned _MSize;
+ unsigned _TSize;
+
+ unsigned _NumFaces;
+ unsigned *_NumVertexPerFace;
+ TRIANGLES_STYLE *_FaceStyle;
+ FaceEdgeMark *_FaceEdgeMarks;
+
+ unsigned *_VIndices;
+ unsigned *_NIndices;
+ unsigned *_MIndices; // Material Indices
+ unsigned *_TIndices; // Texture coordinates Indices
+
+ unsigned _VISize;
+ unsigned _NISize;
+ unsigned _MISize;
+ unsigned _TISize;
+
+ unsigned int _displayList;
+};
+
+#endif // __FREESTYLE_INDEXED_FACE_SET_H__
diff --git a/source/blender/freestyle/intern/scene_graph/LineRep.cpp b/source/blender/freestyle/intern/scene_graph/LineRep.cpp
new file mode 100644
index 00000000000..bf442bccbc1
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/LineRep.cpp
@@ -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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/LineRep.cpp
+ * \ingroup freestyle
+ * \brief Class to define the representation of 3D Line.
+ * \author Stephane Grabli
+ * \date 26/03/2002
+ */
+
+#include "LineRep.h"
+
+void LineRep::ComputeBBox()
+{
+ real XMax = _vertices.front()[0];
+ real YMax = _vertices.front()[1];
+ real ZMax = _vertices.front()[2];
+
+ real XMin = _vertices.front()[0];
+ real YMin = _vertices.front()[1];
+ real ZMin = _vertices.front()[2];
+
+ // parse all the coordinates to find
+ // the XMax, YMax, ZMax
+ vector<Vec3r>::iterator v;
+ for (v = _vertices.begin(); v != _vertices.end(); ++v) {
+ // X
+ if ((*v)[0] > XMax)
+ XMax = (*v)[0];
+ if ((*v)[0] < XMin)
+ XMin = (*v)[0];
+
+ // Y
+ if ((*v)[1] > YMax)
+ YMax = (*v)[1];
+ if ((*v)[1] < YMin)
+ YMin = (*v)[1];
+
+ // Z
+ if ((*v)[2] > ZMax)
+ ZMax = (*v)[2];
+ if ((*v)[2] < ZMin)
+ ZMin = (*v)[2];
+ }
+
+ setBBox(BBox<Vec3r>(Vec3r(XMin, YMin, ZMin), Vec3r(XMax, YMax, ZMax)));
+}
diff --git a/source/blender/freestyle/intern/scene_graph/LineRep.h b/source/blender/freestyle/intern/scene_graph/LineRep.h
new file mode 100644
index 00000000000..3d93db4835d
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/LineRep.h
@@ -0,0 +1,158 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_LINE_REP_H__
+#define __FREESTYLE_LINE_REP_H__
+
+/** \file blender/freestyle/intern/scene_graph/LineRep.h
+ * \ingroup freestyle
+ * \brief Class to define the representation of 3D Line.
+ * \author Stephane Grabli
+ * \date 26/03/2002
+ */
+
+#include <list>
+#include <vector>
+
+#include "Rep.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace std;
+
+/*! Base class for all lines objects */
+class LIB_SCENE_GRAPH_EXPORT LineRep : public Rep
+{
+public:
+ /*! Line description style */
+ enum LINES_STYLE {
+ LINES,
+ LINE_STRIP,
+ LINE_LOOP,
+ };
+
+ inline LineRep() : Rep()
+ {
+ _width = 0.0f;
+ }
+
+ /*! Builds a single line from 2 vertices
+ * v1
+ * first vertex
+ * v2
+ * second vertex
+ */
+ inline LineRep(const Vec3r& v1, const Vec3r& v2) : Rep()
+ {
+ setStyle(LINES);
+ AddVertex(v1);
+ AddVertex(v2);
+ _width = 0.0f;
+ }
+
+ /*! Builds a line rep from a vertex chain */
+ inline LineRep(const vector<Vec3r>& vertices) : Rep()
+ {
+ _vertices = vertices;
+ setStyle(LINE_STRIP);
+ _width = 0.0f;
+ }
+
+ /*! Builds a line rep from a vertex chain */
+ inline LineRep(const list<Vec3r>& vertices) : Rep()
+ {
+ for (list<Vec3r>::const_iterator v = vertices.begin(), end = vertices.end(); v != end; ++v) {
+ _vertices.push_back(*v);
+ }
+ setStyle(LINE_STRIP);
+ _width = 0.0f;
+ }
+
+ virtual ~LineRep()
+ {
+ _vertices.clear();
+ }
+
+ /*! accessors */
+ inline const LINES_STYLE style() const
+ {
+ return _Style;
+ }
+
+ inline const vector<Vec3r>& vertices() const
+ {
+ return _vertices;
+ }
+
+ inline float width() const
+ {
+ return _width;
+ }
+
+ /*! modifiers */
+ inline void setStyle(const LINES_STYLE iStyle)
+ {
+ _Style = iStyle;
+ }
+
+ inline void AddVertex(const Vec3r& iVertex)
+ {
+ _vertices.push_back(iVertex);
+ }
+
+ inline void setVertices(const vector<Vec3r>& iVertices)
+ {
+ if (0 != _vertices.size()) {
+ _vertices.clear();
+ }
+ for (vector<Vec3r>::const_iterator v = iVertices.begin(), end = iVertices.end(); v != end; ++v) {
+ _vertices.push_back(*v);
+ }
+ }
+
+ inline void setWidth(float iWidth)
+ {
+ _width = iWidth;
+ }
+
+ /*! Accept the corresponding visitor */
+ virtual void accept(SceneVisitor& v)
+ {
+ Rep::accept(v);
+ v.visitLineRep(*this);
+ }
+
+ /*! Computes the line bounding box.*/
+ virtual void ComputeBBox();
+
+private:
+ LINES_STYLE _Style;
+ vector<Vec3r> _vertices;
+ float _width;
+};
+
+#endif // __FREESTYLE_LINE_REP_H__
diff --git a/source/blender/freestyle/intern/scene_graph/Node.h b/source/blender/freestyle/intern/scene_graph/Node.h
new file mode 100644
index 00000000000..626a0913233
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/Node.h
@@ -0,0 +1,115 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_NODE_H__
+#define __FREESTYLE_NODE_H__
+
+/** \file blender/freestyle/intern/scene_graph/Node.h
+ * \ingroup freestyle
+ * \brief Abstract class for scene graph nodes. Inherits from BaseObject which defines the addRef release mechanism.
+ * \author Stephane Grabli
+ * \date 24/01/2002
+ */
+
+#include "SceneVisitor.h"
+
+#include "../system/BaseObject.h"
+#include "../system/FreestyleConfig.h"
+#include "../system/Precision.h"
+
+#include "../geometry/BBox.h"
+#include "../geometry/Geom.h"
+
+using namespace std;
+using namespace Geometry;
+
+class LIB_SCENE_GRAPH_EXPORT Node : public BaseObject
+{
+public:
+ inline Node() : BaseObject() {}
+
+ inline Node(const Node& iBrother) : BaseObject()
+ {
+ _BBox = iBrother.bbox();
+ }
+
+ virtual ~Node(){}
+
+ /*! Accept the corresponding visitor
+ * Each inherited node must overload this method
+ */
+ virtual void accept(SceneVisitor& v)
+ {
+ v.visitNode(*this);
+ }
+
+ /*! bounding box management */
+ /*! Returns the node bounding box
+ * If no bounding box exists, an empty bbox is returned
+ */
+ virtual const BBox<Vec3r>& bbox() const
+ {
+ return _BBox;
+ }
+
+ /*! Sets the Node bounding box */
+ virtual void setBBox(const BBox<Vec3r>& iBox)
+ {
+ _BBox = iBox;
+ }
+
+ /*! Makes the union of _BBox and iBox */
+ virtual void AddBBox(const BBox<Vec3r>& iBox)
+ {
+ if(iBox.empty())
+ return;
+
+ if(_BBox.empty())
+ _BBox = iBox;
+ else
+ _BBox += iBox;
+ }
+
+ /*! Updates the BBox */
+ virtual const BBox<Vec3r>& UpdateBBox()
+ {
+ return _BBox;
+ }
+
+ /*! Clears the bounding box */
+ virtual void clearBBox()
+ {
+ _BBox.clear();
+ }
+
+protected:
+
+private:
+ BBox<Vec3r> _BBox;
+};
+
+#endif // __FREESTYLE_NODE_H__
diff --git a/source/blender/freestyle/intern/scene_graph/NodeCamera.cpp b/source/blender/freestyle/intern/scene_graph/NodeCamera.cpp
new file mode 100644
index 00000000000..d8b01bf3f64
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/NodeCamera.cpp
@@ -0,0 +1,143 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/NodeCamera.cpp
+ * \ingroup freestyle
+ * \brief Class to represent a light node
+ * \author Stephane Grabli
+ * \date 25/01/2002
+ */
+
+#include <math.h>
+#include <string.h> // for memcpy
+
+#include "NodeCamera.h"
+
+static void loadIdentity(double * matrix)
+{
+ int i;
+
+ // Build Identity matrix
+ for (i = 0; i < 16; ++i) {
+ double value ;
+ if ((i % 5) == 0)
+ value = 1.0;
+ else
+ value = 0;
+ matrix[i] = value;
+ }
+}
+
+NodeCamera::NodeCamera(CameraType camera_type) : camera_type_(camera_type)
+{
+ loadIdentity(modelview_matrix_);
+ loadIdentity(projection_matrix_);
+}
+
+NodeCamera::NodeCamera(const NodeCamera& iBrother) : camera_type_(iBrother.camera_type_)
+{
+ memcpy(modelview_matrix_, iBrother.modelview_matrix_, 16 * sizeof(double));
+ memcpy(projection_matrix_, iBrother.projection_matrix_, 16 * sizeof(double));
+}
+
+void NodeCamera::accept(SceneVisitor& v)
+{
+ v.visitNodeCamera(*this);
+}
+
+void NodeCamera::setModelViewMatrix(double modelview_matrix[16])
+{
+ memcpy(modelview_matrix_, modelview_matrix, 16 * sizeof(double));
+}
+
+void NodeCamera::setProjectionMatrix(double projection_matrix[16])
+{
+ memcpy(projection_matrix_, projection_matrix, 16 * sizeof(double));
+}
+
+NodeOrthographicCamera::NodeOrthographicCamera()
+: NodeCamera(NodeCamera::ORTHOGRAPHIC), left_(0), right_(0), bottom_(0), top_(0), zNear_(0), zFar_(0)
+{
+ loadIdentity(projection_matrix_);
+ loadIdentity(modelview_matrix_);
+}
+
+NodeOrthographicCamera::NodeOrthographicCamera(double left, double right, double bottom, double top,
+ double zNear, double zFar)
+: NodeCamera(NodeCamera::ORTHOGRAPHIC), left_(left), right_(right), bottom_(bottom), top_(top),
+ zNear_(zNear), zFar_(zFar)
+{
+ loadIdentity(projection_matrix_);
+
+ projection_matrix_[0] = 2.0 / (right - left);
+ projection_matrix_[3] = -(right + left) / (right - left) ;
+ projection_matrix_[5] = 2.0 / (top - bottom);
+ projection_matrix_[7] = -(top + bottom) / (top - bottom) ;
+ projection_matrix_[10] = -2.0 / (zFar - zNear);
+ projection_matrix_[11] = -(zFar + zNear) / (zFar - zNear);
+}
+
+NodeOrthographicCamera::NodeOrthographicCamera(const NodeOrthographicCamera& iBrother)
+: NodeCamera(iBrother), left_(iBrother.left_), right_(iBrother.right_), bottom_(iBrother.bottom_), top_(iBrother.top_),
+ zNear_(iBrother.zNear_), zFar_(iBrother.zFar_)
+{
+}
+
+NodePerspectiveCamera::NodePerspectiveCamera() : NodeCamera(NodeCamera::PERSPECTIVE)
+{
+}
+
+NodePerspectiveCamera::NodePerspectiveCamera(double fovy, double aspect, double zNear, double zFar)
+: NodeCamera(NodeCamera::PERSPECTIVE)
+{
+ loadIdentity(projection_matrix_);
+
+ double f = cos(fovy / 2.0) / sin(fovy / 2.0); // cotangent
+
+ projection_matrix_[0] = f / aspect;
+ projection_matrix_[5] = f;
+ projection_matrix_[10] = (zNear + zFar) / (zNear - zFar);
+ projection_matrix_[11] = (2.0 * zNear * zFar) / (zNear - zFar);
+ projection_matrix_[14] = -1.0;
+ projection_matrix_[15] = 0;
+}
+
+NodePerspectiveCamera::NodePerspectiveCamera(double left, double right, double bottom, double top,
+ double zNear, double zFar)
+: NodeCamera(NodeCamera::PERSPECTIVE)
+{
+ loadIdentity(projection_matrix_);
+
+ projection_matrix_[0] = (2.0 * zNear) / (right - left);
+ projection_matrix_[2] = (right + left) / (right - left);
+ projection_matrix_[5] = (2.0 * zNear) / (top - bottom);
+ projection_matrix_[6] = (top + bottom) / (top - bottom);
+ projection_matrix_[10] = -(zFar + zNear) / (zFar - zNear);
+ projection_matrix_[11] = -(2.0 * zFar * zNear) / (zFar - zNear);
+ projection_matrix_[14] = -1.0;
+ projection_matrix_[15] = 0;
+}
diff --git a/source/blender/freestyle/intern/scene_graph/NodeCamera.h b/source/blender/freestyle/intern/scene_graph/NodeCamera.h
new file mode 100644
index 00000000000..f7141a72a51
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/NodeCamera.h
@@ -0,0 +1,216 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_NODE_CAMERA_H__
+#define __FREESTYLE_NODE_CAMERA_H__
+
+/** \file blender/freestyle/intern/scene_graph/NodeCamera.h
+ * \ingroup freestyle
+ * \brief Class to represent a light node
+ * \author Stephane Grabli
+ * \date 25/01/2002
+ */
+
+#include "Node.h"
+
+#include "../geometry/Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace Geometry;
+
+class NodeOrthographicCamera;
+
+class NodePerspectiveCamera;
+
+class LIB_SCENE_GRAPH_EXPORT NodeCamera : public Node
+{
+public:
+ typedef enum {
+ PERSPECTIVE,
+ ORTHOGRAPHIC,
+ GENERIC,
+ } CameraType;
+
+ /*! Default matrices: Identity for both projection and modelview. */
+ NodeCamera(CameraType camera_type = GENERIC);
+ NodeCamera(const NodeCamera& iBrother);
+
+ virtual ~NodeCamera() {}
+
+ /*! Accept the corresponding visitor */
+ virtual void accept(SceneVisitor& v);
+
+ /*! Matrix is copied */
+ void setModelViewMatrix(double modelview_matrix[16]);
+
+ /*! Matrix is copied */
+ void setProjectionMatrix(double projection_matrix[16]);
+
+ double * modelViewMatrix()
+ {
+ return modelview_matrix_;
+ }
+
+ double * projectionMatrix()
+ {
+ return projection_matrix_;
+ }
+
+protected:
+ // row major right handed matrix
+ double modelview_matrix_[16];
+ // row major right handed matrix
+ double projection_matrix_[16];
+
+ CameraType camera_type_;
+};
+
+class LIB_SCENE_GRAPH_EXPORT NodeOrthographicCamera : public NodeCamera
+{
+public:
+ NodeOrthographicCamera();
+
+ /*! Builds a parallel projection matrix a la glOrtho.
+ * A 0 0 tx
+ * 0 B 0 ty
+ * 0 0 C tz
+ * 0 0 0 1
+ *
+ * where
+ * A = 2 / (right - left)
+ * B = 2 / (top - bottom)
+ * C = -2 / (far - near)
+ * tx = -(right + left) / (right - left)
+ * ty = -(top + bottom) / (top - bottom)
+ * tz = -(zFar + zNear) / (zFar - zNear)
+ */
+ NodeOrthographicCamera(double left, double right, double bottom, double top, double zNear, double zFar);
+
+ double left() const
+ {
+ return left_;
+ }
+
+ double right() const
+ {
+ return right_;
+ }
+
+ double bottom() const
+ {
+ return bottom_;
+ }
+
+ double top() const
+ {
+ return top_;
+ }
+
+ double zNear() const
+ {
+ return zNear_;
+ }
+
+ double zFar() const
+ {
+ return zFar_;
+ }
+
+ NodeOrthographicCamera(const NodeOrthographicCamera& iBrother);
+
+private:
+ double left_;
+ double right_;
+ double bottom_;
+ double top_;
+ double zNear_;
+ double zFar_;
+};
+
+class LIB_SCENE_GRAPH_EXPORT NodePerspectiveCamera : public NodeCamera
+{
+public:
+ NodePerspectiveCamera();
+
+ /*! Builds a perspective projection matrix a la gluPerspective.
+ * Given f defined as follows:
+ * fovy
+ * f = cotangent(____)
+ * 2
+ * The generated matrix is
+ * ( f )
+ * | ______ 0 0 0 |
+ * | aspect |
+ * | |
+ * | 0 f 0 0 |
+ * | |
+ * | zNear+zFar 2*zNear*zFar |
+ * | 0 0 __________ ____________ |
+ * | zNear-zFar zNear-zFar |
+ * | |
+ * ( 0 0 -1 0 )
+ * \param fovy
+ * Field of View specified in radians.
+ */
+ NodePerspectiveCamera(double fovy, double aspect, double zNear, double zFar);
+
+ /*! Builds a perspective projection matrix a la glFrustum.
+ * ( 2*zNear )
+ * | __________ 0 A 0 |
+ * | right-left |
+ * | |
+ * | 2*zNear |
+ * | 0 __________ B 0 |
+ * | top-bottom |
+ * | |
+ * | 0 0 C D |
+ * | |
+ * | 0 0 -1 0 |
+ * ( )
+ *
+ * right+left
+ * A = __________
+ * right-left
+ *
+ * top+bottom
+ * B = __________
+ * top-bottom
+ *
+ * zFar+zNear
+ * C = - __________
+ * zFar-zNear
+ *
+ * 2*zFar*zNear
+ * D = - ____________
+ * zFar-zNear
+ */
+ NodePerspectiveCamera(double left, double right, double bottom, double top, double zNear, double zFar);
+};
+
+
+#endif // __FREESTYLE_NODE_CAMERA_H__
diff --git a/source/blender/freestyle/intern/scene_graph/NodeDrawingStyle.cpp b/source/blender/freestyle/intern/scene_graph/NodeDrawingStyle.cpp
new file mode 100644
index 00000000000..fed589b17c5
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/NodeDrawingStyle.cpp
@@ -0,0 +1,46 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/NodeDrawingStyle.cpp
+ * \ingroup freestyle
+ * \brief Class to define a Drawing Style to be applied to the underlying children. Inherits from NodeGroup.
+ * \author Stephane Grabli
+ * \date 06/02/2002
+ */
+
+#include "NodeDrawingStyle.h"
+
+void NodeDrawingStyle::accept(SceneVisitor& v)
+{
+ v.visitNodeDrawingStyle(*this);
+
+ v.visitNodeDrawingStyleBefore(*this);
+ v.visitDrawingStyle(_DrawingStyle);
+ for (vector<Node*>::iterator node = _Children.begin(), end = _Children.end(); node != end; ++node)
+ (*node)->accept(v);
+ v.visitNodeDrawingStyleAfter(*this);
+}
diff --git a/source/blender/freestyle/intern/scene_graph/NodeDrawingStyle.h b/source/blender/freestyle/intern/scene_graph/NodeDrawingStyle.h
new file mode 100644
index 00000000000..29a05290df1
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/NodeDrawingStyle.h
@@ -0,0 +1,111 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_NODE_DRAWING_STYLE_H__
+#define __FREESTYLE_NODE_DRAWING_STYLE_H__
+
+/** \file blender/freestyle/intern/scene_graph/NodeDrawingStyle.h
+ * \ingroup freestyle
+ * \brief Class to define a Drawing Style to be applied to the underlying children. Inherits from NodeGroup.
+ * \author Stephane Grabli
+ * \date 06/02/2002
+ */
+
+#include "DrawingStyle.h"
+#include "NodeGroup.h"
+
+#include "../system/FreestyleConfig.h"
+
+class LIB_SCENE_GRAPH_EXPORT NodeDrawingStyle : public NodeGroup
+{
+public:
+ inline NodeDrawingStyle() : NodeGroup() {}
+ virtual ~NodeDrawingStyle() {}
+
+ inline const DrawingStyle& drawingStyle() const
+ {
+ return _DrawingStyle;
+ }
+
+ inline void setDrawingStyle(const DrawingStyle& iDrawingStyle)
+ {
+ _DrawingStyle = iDrawingStyle;
+ }
+
+ /*! Sets the style. Must be one of FILLED, LINES, POINTS, INVISIBLE. */
+ inline void setStyle(const DrawingStyle::STYLE iStyle)
+ {
+ _DrawingStyle.setStyle(iStyle);
+ }
+
+ /*! Sets the line width in the LINES style case */
+ inline void setLineWidth(const float iLineWidth)
+ {
+ _DrawingStyle.setLineWidth(iLineWidth);
+ }
+
+ /*! Sets the Point size in the POINTS style case */
+ inline void setPointSize(const float iPointSize)
+ {
+ _DrawingStyle.setPointSize(iPointSize);
+ }
+
+ /*! Enables or disables the lighting. TRUE = enable */
+ inline void setLightingEnabled(const bool iEnableLighting)
+ {
+ _DrawingStyle.setLightingEnabled(iEnableLighting);
+ }
+
+ /*! Accept the corresponding visitor */
+ virtual void accept(SceneVisitor& v);
+
+ /*! accessors */
+ inline DrawingStyle::STYLE style() const
+ {
+ return _DrawingStyle.style();
+ }
+
+ inline float lineWidth() const
+ {
+ return _DrawingStyle.lineWidth();
+ }
+
+ inline float pointSize() const
+ {
+ return _DrawingStyle.pointSize();
+ }
+
+ inline bool lightingEnabled() const
+ {
+ return _DrawingStyle.lightingEnabled();
+ }
+
+private:
+ DrawingStyle _DrawingStyle;
+};
+
+#endif // __FREESTYLE_NODE_DRAWING_STYLE_H__
diff --git a/source/blender/freestyle/intern/scene_graph/NodeGroup.cpp b/source/blender/freestyle/intern/scene_graph/NodeGroup.cpp
new file mode 100644
index 00000000000..3ac9cbbcbdc
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/NodeGroup.cpp
@@ -0,0 +1,126 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/NodeGroup.cpp
+ * \ingroup freestyle
+ * \brief Class to represent a group node. This node can contains several children.
+ * \brief It also contains a transform matrix indicating the transform state of the underlying children.
+ * \author Stephane Grabli
+ * \date 24/01/2002
+ */
+
+#include "NodeGroup.h"
+
+void NodeGroup::AddChild(Node *iChild)
+{
+ if (NULL == iChild)
+ return;
+
+ _Children.push_back(iChild);
+ iChild->addRef();
+}
+
+int NodeGroup::destroy()
+{
+ /*! Node::destroy makes a release on the object and then returns the reference counter.
+ * If the reference counter is equal to 0, that means that nobody else is linking this node group and
+ * that we can destroy the whole underlying tree.
+ * Else, one or several Node link this node group, and we only returns the reference counter
+ * decremented by Node::destroy();
+ */
+ int refThis = Node::destroy();
+
+ // if refThis != 0, we can't destroy the tree
+ if (0 != refThis)
+ return refThis;
+
+ // If we are here, that means that nobody else needs our NodeGroup and we can destroy it.
+ int refCount = 0;
+ vector<Node *>::iterator node;
+
+ for (node = _Children.begin(); node != _Children.end(); ++node) {
+ refCount = (*node)->destroy();
+ if (0 == refCount)
+ delete (*node);
+ }
+
+ _Children.clear();
+
+ return refThis;
+}
+
+void NodeGroup::accept(SceneVisitor& v)
+{
+ v.visitNodeGroup(*this);
+
+ v.visitNodeGroupBefore(*this);
+ for (vector<Node *>::iterator node = _Children.begin(), end = _Children.end(); node != end; ++node)
+ (*node)->accept(v);
+ v.visitNodeGroupAfter(*this);
+}
+
+void NodeGroup::DetachChildren()
+{
+ vector<Node *>::iterator node;
+
+ for (node = _Children.begin(); node != _Children.end(); ++node) {
+ (*node)->release();
+ }
+
+ _Children.clear();
+}
+
+void NodeGroup::DetachChild(Node *iChild)
+{
+ /* int found = 0; */ /* UNUSED */
+ vector<Node*>::iterator node;
+
+ for (node = _Children.begin(); node != _Children.end(); ++node) {
+ if ((*node) == iChild) {
+ (*node)->release();
+ _Children.erase(node);
+ /* found = 1; */ /* UNUSED */
+ break;
+ }
+ }
+}
+
+void NodeGroup::RetrieveChildren(vector<Node*>& oNodes)
+{
+ oNodes = _Children;
+}
+
+const BBox<Vec3r>& NodeGroup::UpdateBBox()
+{
+ vector<Node *>::iterator node;
+ clearBBox();
+ for (node = _Children.begin(); node != _Children.end(); ++node) {
+ AddBBox((*node)->UpdateBBox());
+ }
+
+ return Node::UpdateBBox();
+}
diff --git a/source/blender/freestyle/intern/scene_graph/NodeGroup.h b/source/blender/freestyle/intern/scene_graph/NodeGroup.h
new file mode 100644
index 00000000000..1c5b106d5c6
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/NodeGroup.h
@@ -0,0 +1,89 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_NODE_GROUP_H__
+#define __FREESTYLE_NODE_GROUP_H__
+
+/** \file blender/freestyle/intern/scene_graph/NodeGroup.h
+ * \ingroup freestyle
+ * \brief Class to represent a group node. This node can contains several children.
+ * \brief It also contains a transform matrix indicating the transform state of the underlying children.
+ * \author Stephane Grabli
+ * \date 24/01/2002
+ */
+
+#include <vector>
+
+#include "Node.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace std;
+
+class LIB_SCENE_GRAPH_EXPORT NodeGroup : public Node
+{
+public:
+ inline NodeGroup(): Node() {}
+ virtual ~NodeGroup(){}
+
+ /*! Adds a child. Makes a addRef on the iChild reference counter */
+ virtual void AddChild(Node *iChild);
+
+ /*! destroys all the underlying nodes
+ * Returns the reference counter after having done a release()
+ */
+ virtual int destroy();
+
+ /*! Detaches all the children */
+ virtual void DetachChildren();
+
+ /*! Detached the sepcified child */
+ virtual void DetachChild(Node *iChild);
+
+ /*! Retrieve children */
+ virtual void RetrieveChildren(vector<Node*>& oNodes);
+
+ /*! Renders every children */
+// virtual void Render(Renderer *iRenderer);
+
+ /*! Accept the corresponding visitor */
+ virtual void accept(SceneVisitor& v);
+
+ /*! Updates the BBox */
+ virtual const BBox<Vec3r>& UpdateBBox();
+
+ /*! Returns the number of children */
+ virtual int numberOfChildren()
+ {
+ return _Children.size();
+ }
+
+protected:
+ vector<Node*> _Children;
+};
+
+#endif // __FREESTYLE_NODE_GROUP_H__
diff --git a/source/blender/freestyle/intern/scene_graph/NodeLight.cpp b/source/blender/freestyle/intern/scene_graph/NodeLight.cpp
new file mode 100644
index 00000000000..f410d2da18e
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/NodeLight.cpp
@@ -0,0 +1,86 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/NodeLight.cpp
+ * \ingroup freestyle
+ * \brief Class to represent a light node
+ * \author Stephane Grabli
+ * \date 25/01/2002
+ */
+
+#include "NodeLight.h"
+
+int NodeLight::numberOfLights = 0;
+
+NodeLight::NodeLight() : Node()
+{
+ if (numberOfLights > 7) {
+ _number = 7;
+ }
+ else {
+ _number = numberOfLights;
+ numberOfLights++;
+ }
+
+ Ambient[0] = Ambient[1] = Ambient[2] = 0.0f;
+ Ambient[3] = 1.0f;
+
+ for (int i = 0; i < 4; i++) {
+ Diffuse[i] = 1.0f;
+ Specular[i] = 1.0f;
+ }
+
+ Position[0] = Position[1] = Position[3] = 0.0f;
+ Position[2] = 1.0f;
+
+ on = true;
+}
+
+NodeLight::NodeLight(NodeLight& iBrother) : Node(iBrother)
+{
+ if (numberOfLights > 7) {
+ _number = 7;
+ }
+ else {
+ _number = numberOfLights;
+ numberOfLights++;
+ }
+
+ for (int i = 0; i < 4; i++) {
+ Ambient[i] = iBrother.ambient()[i];
+ Diffuse[i] = iBrother.diffuse()[i];
+ Specular[i] = iBrother.specular()[i];
+ Position[i] = iBrother.position()[i];
+ }
+
+ on = iBrother.isOn();
+}
+
+void NodeLight::accept(SceneVisitor& v)
+{
+ v.visitNodeLight(*this);
+}
diff --git a/source/blender/freestyle/intern/scene_graph/NodeLight.h b/source/blender/freestyle/intern/scene_graph/NodeLight.h
new file mode 100644
index 00000000000..49484d8b9b3
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/NodeLight.h
@@ -0,0 +1,113 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_NODE_LIGHT_H__
+#define __FREESTYLE_NODE_LIGHT_H__
+
+/** \file blender/freestyle/intern/scene_graph/NodeLight.h
+ * \ingroup freestyle
+ * \brief Class to represent a light node
+ * \author Stephane Grabli
+ * \date 25/01/2002
+ */
+
+#include "Node.h"
+
+#include "../geometry/Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace Geometry;
+
+class LIB_SCENE_GRAPH_EXPORT NodeLight : public Node
+{
+public:
+ NodeLight();
+ NodeLight(NodeLight& iBrother);
+
+ virtual ~NodeLight() {}
+
+ /*! Accept the corresponding visitor */
+ virtual void accept(SceneVisitor& v);
+
+ /*! Accessors for the light properties */
+ inline const float * ambient() const
+ {
+ return Ambient;
+ }
+
+ inline const float * diffuse() const
+ {
+ return Diffuse;
+ }
+
+ inline const float * specular() const
+ {
+ return Specular;
+ }
+
+ inline const float * position() const
+ {
+ return Position;
+ }
+
+ inline bool isOn() const
+ {
+ return on;
+ }
+
+ inline int number() const
+ {
+ return _number;
+ }
+
+private:
+ // Data members
+ // ============
+
+ /*! on=true, the light is on */
+ bool on;
+
+ /*! The color definition */
+ float Ambient[4];
+ float Diffuse[4];
+ float Specular[4];
+
+ /*! Light position. if w = 0, the light is placed at infinite. */
+ float Position[4];
+
+ /*! used to manage the number of lights */
+ /*! numberOfLights
+ * the number of lights in the scene.
+ * Initially, 0.
+ */
+ static int numberOfLights;
+ /*! The current lignt number */
+ int _number;
+};
+
+#endif // __FREESTYLE_NODE_LIGHT_H__
diff --git a/source/blender/freestyle/intern/scene_graph/NodeShape.cpp b/source/blender/freestyle/intern/scene_graph/NodeShape.cpp
new file mode 100644
index 00000000000..b1593c9f43b
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/NodeShape.cpp
@@ -0,0 +1,63 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/NodeShape.cpp
+ * \ingroup freestyle
+ * \brief Class to build a shape node. It contains a Rep, which is the shape geometry
+ * \author Stephane Grabli
+ * \date 25/01/2002
+ */
+
+#include "NodeShape.h"
+
+NodeShape::~NodeShape()
+{
+ vector<Rep *>::iterator rep;
+
+ if (0 != _Shapes.size()) {
+ for (rep = _Shapes.begin(); rep != _Shapes.end(); ++rep) {
+ int refCount = (*rep)->destroy();
+ if (0 == refCount)
+ delete (*rep);
+ }
+
+ _Shapes.clear();
+ }
+}
+
+void NodeShape::accept(SceneVisitor& v)
+{
+ v.visitNodeShape(*this);
+
+ v.visitFrsMaterial(_FrsMaterial);
+
+ v.visitNodeShapeBefore(*this);
+ vector<Rep *>::iterator rep;
+ for (rep = _Shapes.begin(); rep != _Shapes.end(); ++rep)
+ (*rep)->accept(v);
+ v.visitNodeShapeAfter(*this);
+}
diff --git a/source/blender/freestyle/intern/scene_graph/NodeShape.h b/source/blender/freestyle/intern/scene_graph/NodeShape.h
new file mode 100644
index 00000000000..046d8b0e392
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/NodeShape.h
@@ -0,0 +1,103 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_NODE_SHAPE_H__
+#define __FREESTYLE_NODE_SHAPE_H__
+
+/** \file blender/freestyle/intern/scene_graph/NodeShape.h
+ * \ingroup freestyle
+ * \brief Class to build a shape node. It contains a Rep, which is the shape geometry
+ * \author Stephane Grabli
+ * \date 25/01/2002
+ */
+
+#include <vector>
+
+#include "../geometry/BBox.h"
+#include "../geometry/Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+#include "FrsMaterial.h"
+#include "Node.h"
+#include "Rep.h"
+
+using namespace std;
+using namespace Geometry;
+
+class LIB_SCENE_GRAPH_EXPORT NodeShape : public Node
+{
+public:
+ inline NodeShape() : Node() {}
+
+ virtual ~NodeShape();
+
+ /*! Adds a Rep to the _Shapes list
+ * The delete of the rep is done when it is not used any more by the Scene Manager.
+ * So, it must not be deleted by the caller
+ */
+ virtual void AddRep(Rep *iRep)
+ {
+ if (NULL == iRep)
+ return;
+ _Shapes.push_back(iRep);
+ iRep->addRef();
+
+ // updates bbox:
+ AddBBox(iRep->bbox());
+ }
+
+ /*! Accept the corresponding visitor */
+ virtual void accept(SceneVisitor& v);
+
+ /*! Sets the shape material */
+ inline void setFrsMaterial(const FrsMaterial& iMaterial)
+ {
+ _FrsMaterial = iMaterial;
+ }
+
+ /*! accessors */
+ /*! returns the shape's material */
+ inline FrsMaterial& frs_material()
+ {
+ return _FrsMaterial;
+ }
+
+ inline const vector<Rep*>& shapes()
+ {
+ return _Shapes;
+ }
+
+private:
+ /*! list of shapes */
+ vector<Rep*> _Shapes;
+
+ /*! Shape Material */
+ FrsMaterial _FrsMaterial;
+};
+
+#endif // __FREESTYLE_NODE_SHAPE_H__
diff --git a/source/blender/freestyle/intern/scene_graph/NodeTransform.cpp b/source/blender/freestyle/intern/scene_graph/NodeTransform.cpp
new file mode 100644
index 00000000000..aa01200a4d2
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/NodeTransform.cpp
@@ -0,0 +1,178 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/NodeTransform.cpp
+ * \ingroup freestyle
+ * \brief Class to represent a transform node. A Transform node contains one or several children,
+ * \brief all affected by the transformation.
+ * \author Stephane Grabli
+ * \date 06/02/2002
+ */
+
+#include "NodeTransform.h"
+
+#include "../system/FreestyleConfig.h"
+
+void NodeTransform::Translate(real x, real y, real z)
+{
+ _Matrix(0, 3) += x;
+ _Matrix(1, 3) += y;
+ _Matrix(2, 3) += z;
+}
+
+void NodeTransform::Rotate(real iAngle, real x, real y, real z)
+{
+ //Normalize the x,y,z vector;
+ real norm = (real)sqrt(x * x + y * y + z * z);
+ if (0 == norm)
+ return;
+
+ x /= norm;
+ y /= norm;
+ z /= norm;
+
+ /* find the corresponding matrix with the Rodrigues formula:
+ * R = I + sin(iAngle)*Ntilda + (1-cos(iAngle))*Ntilda*Ntilda
+ */
+ Matrix33r Ntilda;
+ Ntilda(0, 0) = Ntilda(1, 1) = Ntilda(2, 2) = 0.0f;
+ Ntilda(0, 1) = -z;
+ Ntilda(0, 2) = y;
+ Ntilda(1, 0) = z;
+ Ntilda(1, 2) = -x;
+ Ntilda(2, 0) = -y;
+ Ntilda(2, 1) = x;
+
+ const Matrix33r Ntilda2(Ntilda * Ntilda);
+
+
+ const real sinAngle = (real)sin((iAngle / 180.0f) * M_PI);
+ const real cosAngle = (real)cos((iAngle / 180.0f) * M_PI);
+
+ Matrix33r NS(Ntilda * sinAngle);
+ Matrix33r NC(Ntilda2 * (1.0f - cosAngle));
+ Matrix33r R;
+ R = Matrix33r::identity();
+ R += NS + NC;
+
+ // R4 is the corresponding 4x4 matrix
+ Matrix44r R4;
+ R4 = Matrix44r::identity();
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++)
+ R4(i, j) = R(i, j);
+ }
+
+ // Finally, we multiply our current matrix by R4:
+ Matrix44r mat_tmp(_Matrix);
+ _Matrix = mat_tmp * R4;
+}
+
+void NodeTransform::Scale(real x, real y, real z)
+{
+ _Matrix(0, 0) *= x;
+ _Matrix(1, 1) *= y;
+ _Matrix(2, 2) *= z;
+
+ _Scaled = true;
+}
+
+void NodeTransform::MultiplyMatrix(const Matrix44r &iMatrix)
+{
+ Matrix44r mat_tmp(_Matrix);
+ _Matrix = mat_tmp * iMatrix;
+}
+
+void NodeTransform::setMatrix(const Matrix44r &iMatrix)
+{
+ _Matrix = iMatrix;
+ if (isScaled(iMatrix))
+ _Scaled = true;
+}
+
+void NodeTransform::accept(SceneVisitor& v)
+{
+ v.visitNodeTransform(*this);
+
+ v.visitNodeTransformBefore(*this);
+ for (vector<Node *>::iterator node = _Children.begin(), end = _Children.end(); node != end; ++node)
+ (*node)->accept(v);
+ v.visitNodeTransformAfter(*this);
+}
+
+void NodeTransform::AddBBox(const BBox<Vec3r>& iBBox)
+{
+ Vec3r oldMin(iBBox.getMin());
+ Vec3r oldMax(iBBox.getMax());
+
+ // compute the 8 corners of the bbox
+ HVec3r box[8];
+ box[0] = HVec3r(iBBox.getMin());
+ box[1] = HVec3r(oldMax[0], oldMin[1], oldMin[2]);
+ box[2] = HVec3r(oldMax[0], oldMax[1], oldMin[2]);
+ box[3] = HVec3r(oldMin[0], oldMax[1], oldMin[2]);
+ box[4] = HVec3r(oldMin[0], oldMin[1], oldMax[2]);
+ box[5] = HVec3r(oldMax[0], oldMin[1], oldMax[2]);
+ box[6] = HVec3r(oldMax[0], oldMax[1], oldMax[2]);
+ box[7] = HVec3r(oldMin[0], oldMax[1], oldMax[2]);
+
+ // Computes the transform iBBox
+ HVec3r tbox[8];
+ unsigned int i;
+ for (i = 0; i < 8; i++)
+ tbox[i] = _Matrix * box[i];
+
+ Vec3r newMin(tbox[0]);
+ Vec3r newMax(tbox[0]);
+ for (i = 0; i < 8; i++) {
+ for (unsigned int j = 0; j < 3; j++) {
+ if (newMin[j] > tbox[i][j])
+ newMin[j] = tbox[i][j];
+ if (newMax[j] < tbox[i][j])
+ newMax[j] = tbox[i][j];
+ }
+ }
+
+ BBox<Vec3r> transformBox(newMin, newMax);
+
+ Node::AddBBox(transformBox);
+}
+
+bool NodeTransform::isScaled(const Matrix44r &M)
+{
+ for (unsigned int j = 0; j < 3; j++) {
+ real norm = 0;
+ for (unsigned int i = 0; i < 3; i++) {
+ norm += M(i, j) * M(i, j);
+ }
+ if ((norm > 1.01) || (norm < 0.99))
+ return true;
+ }
+
+ return false;
+}
diff --git a/source/blender/freestyle/intern/scene_graph/NodeTransform.h b/source/blender/freestyle/intern/scene_graph/NodeTransform.h
new file mode 100644
index 00000000000..e98045989d3
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/NodeTransform.h
@@ -0,0 +1,110 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_NODE_TRANSFORM_H__
+#define __FREESTYLE_NODE_TRANSFORM_H__
+
+/** \file blender/freestyle/intern/scene_graph/NodeTransform.h
+ * \ingroup freestyle
+ * \brief Class to represent a transform node. A Transform node contains one or several children,
+ * \brief all affected by the transformation.
+ * \author Stephane Grabli
+ * \date 06/02/2002
+ */
+
+#include "NodeGroup.h"
+
+#include "../geometry/Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace Geometry;
+
+class LIB_SCENE_GRAPH_EXPORT NodeTransform : public NodeGroup
+{
+public:
+ inline NodeTransform() : NodeGroup()
+ {
+ _Matrix = Matrix44r::identity();
+ _Scaled = false;
+ }
+
+ virtual ~NodeTransform() {}
+
+ /*! multiplys the current matrix by the x, y, z translation matrix. */
+ void Translate(real x, real y, real z);
+
+ /*! multiplys the current matrix by a rotation matrix
+ * iAngle
+ * The rotation angle
+ * x, y, z
+ * The rotation axis
+ */
+ void Rotate(real iAngle, real x, real y, real z);
+
+ /*! multiplys the current matrix by a scaling matrix.
+ * x, y, z
+ * The scaling coefficients with respect to the x,y,z axis
+ */
+ void Scale(real x, real y, real z);
+
+ /*! Multiplys the current matrix by iMatrix */
+ void MultiplyMatrix(const Matrix44r &iMatrix);
+
+ /*! Sets the current matrix to iMatrix */
+ void setMatrix(const Matrix44r &iMatrix);
+
+ /*! Accept the corresponding visitor */
+ virtual void accept(SceneVisitor& v);
+
+ /*! Overloads the Node::AddBBox in order to take care about the transformation */
+ virtual void AddBBox(const BBox<Vec3r>& iBBox);
+
+ /*! Checks whether a matrix contains a scale factor or not.
+ * Returns true if yes.
+ * M
+ * The matrix to check
+ */
+ bool isScaled(const Matrix44r &M);
+
+ /*! accessors */
+ inline const Matrix44r& matrix() const
+ {
+ return _Matrix;
+ }
+
+ inline bool scaled() const
+ {
+ return _Scaled;
+ }
+
+private:
+ Matrix44r _Matrix;
+ bool _Scaled;
+};
+
+#endif // __FREESTYLE_NODE_TRANSFORM_H__
diff --git a/source/blender/freestyle/intern/scene_graph/OrientedLineRep.cpp b/source/blender/freestyle/intern/scene_graph/OrientedLineRep.cpp
new file mode 100644
index 00000000000..8b29c0256ff
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/OrientedLineRep.cpp
@@ -0,0 +1,46 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/OrientedLineRep.cpp
+ * \ingroup freestyle
+ * \brief Class to display an oriented line representation.
+ * \author Stephane Grabli
+ * \date 24/10/2002
+ */
+
+#include "OrientedLineRep.h"
+
+#include "../system/BaseObject.h"
+
+void OrientedLineRep::accept(SceneVisitor& v)
+{
+ Rep::accept(v);
+ if (!frs_material())
+ v.visitOrientedLineRep(*this);
+ else
+ v.visitLineRep(*this);
+}
diff --git a/source/blender/freestyle/intern/scene_graph/OrientedLineRep.h b/source/blender/freestyle/intern/scene_graph/OrientedLineRep.h
new file mode 100644
index 00000000000..45cda3610f2
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/OrientedLineRep.h
@@ -0,0 +1,66 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_ORIENTED_LINE_REP_H__
+#define __FREESTYLE_ORIENTED_LINE_REP_H__
+
+/** \file blender/freestyle/intern/scene_graph/OrientedLineRep.h
+ * \ingroup freestyle
+ * \brief Class to display an oriented line representation.
+ * \author Stephane Grabli
+ * \date 24/10/2002
+ */
+
+#include "LineRep.h"
+
+#include "../system/FreestyleConfig.h"
+
+class LIB_SCENE_GRAPH_EXPORT OrientedLineRep : public LineRep
+{
+public:
+ OrientedLineRep() : LineRep() {}
+ /*! Builds a single line from 2 vertices
+ * v1
+ * first vertex
+ * v2
+ * second vertex
+ */
+ inline OrientedLineRep(const Vec3r& v1, const Vec3r& v2) : LineRep(v1,v2) {}
+
+ /*! Builds a line rep from a vertex chain */
+ inline OrientedLineRep(const vector<Vec3r>& vertices) : LineRep(vertices) {}
+
+ /*! Builds a line rep from a vertex chain */
+ inline OrientedLineRep(const list<Vec3r>& vertices) : LineRep(vertices) {}
+
+ virtual ~OrientedLineRep() {}
+
+ /*! Accept the corresponding visitor */
+ virtual void accept(SceneVisitor& v);
+};
+
+#endif // __FREESTYLE_ORIENTED_LINE_REP_H__
diff --git a/source/blender/freestyle/intern/scene_graph/Rep.cpp b/source/blender/freestyle/intern/scene_graph/Rep.cpp
new file mode 100644
index 00000000000..0319a617a68
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/Rep.cpp
@@ -0,0 +1,35 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/Rep.cpp
+ * \ingroup freestyle
+ * \brief Base class for all shapes. Inherits from BasicObjects for references counter management (addRef, release).
+ * \author Stephane Grabli
+ * \date 25/01/2002
+ */
+
+#include "Rep.h"
diff --git a/source/blender/freestyle/intern/scene_graph/Rep.h b/source/blender/freestyle/intern/scene_graph/Rep.h
new file mode 100644
index 00000000000..c1b29d3fceb
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/Rep.h
@@ -0,0 +1,173 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_REP_H__
+#define __FREESTYLE_REP_H__
+
+/** \file blender/freestyle/intern/scene_graph/Rep.h
+ * \ingroup freestyle
+ * \brief Base class for all shapes. Inherits from BasicObjects for references counter management (addRef, release).
+ * \author Stephane Grabli
+ * \date 25/01/2002
+ */
+
+#include "FrsMaterial.h"
+#include "SceneVisitor.h"
+
+#include "../geometry/BBox.h"
+#include "../geometry/Geom.h"
+
+#include "../system/BaseObject.h"
+#include "../system/Id.h"
+#include "../system/Precision.h"
+
+using namespace Geometry;
+
+class LIB_SCENE_GRAPH_EXPORT Rep : public BaseObject
+{
+public:
+ inline Rep() : BaseObject()
+ {
+ _Id = 0;
+ _FrsMaterial = 0;
+ }
+
+ inline Rep(const Rep& iBrother) : BaseObject()
+ {
+ _Id = iBrother._Id;
+ _Name = iBrother._Name;
+ if (0 == iBrother._FrsMaterial)
+ _FrsMaterial = 0;
+ else
+ _FrsMaterial = new FrsMaterial(*(iBrother._FrsMaterial));
+
+ _BBox = iBrother.bbox();
+ }
+
+ inline void swap(Rep& ioOther)
+ {
+ std::swap(_BBox,ioOther._BBox);
+ std::swap(_Id, ioOther._Id);
+ std::swap(_Name, ioOther._Name);
+ std::swap(_FrsMaterial,ioOther._FrsMaterial);
+ }
+
+ Rep& operator=(const Rep& iBrother)
+ {
+ if (&iBrother != this) {
+ _Id = iBrother._Id;
+ _Name = iBrother._Name;
+ if (0 == iBrother._FrsMaterial) {
+ _FrsMaterial = 0;
+ }
+ else {
+ if (_FrsMaterial == 0) {
+ _FrsMaterial = new FrsMaterial(*iBrother._FrsMaterial);
+ }
+ else {
+ (*_FrsMaterial) = (*(iBrother._FrsMaterial));
+ }
+ _BBox = iBrother.bbox();
+ }
+ }
+ return *this;
+ }
+
+ virtual ~Rep()
+ {
+ if (0 != _FrsMaterial) {
+ delete _FrsMaterial;
+ _FrsMaterial = 0;
+ }
+ }
+
+ /*! Accept the corresponding visitor
+ * Must be overload by inherited classes
+ */
+ virtual void accept(SceneVisitor& v)
+ {
+ if (_FrsMaterial)
+ v.visitFrsMaterial(*_FrsMaterial);
+ v.visitRep(*this);
+ }
+
+ /*! Computes the rep bounding box.
+ * Each Inherited rep must compute its bbox depending on the way the data are stored. So, each inherited class
+ * must overload this method
+ */
+ virtual void ComputeBBox() = 0;
+
+ /*! Returns the rep bounding box */
+ virtual const BBox<Vec3r>& bbox() const
+ {
+ return _BBox;
+ }
+
+ inline Id getId() const
+ {
+ return _Id;
+ }
+
+ inline const string& getName() const
+ {
+ return _Name;
+ }
+
+ inline const FrsMaterial * frs_material() const
+ {
+ return _FrsMaterial;
+ }
+
+ /*! Sets the Rep bounding box */
+ virtual void setBBox(const BBox<Vec3r>& iBox)
+ {
+ _BBox = iBox;
+ }
+
+ inline void setId(const Id& id)
+ {
+ _Id = id;
+ }
+
+ inline void setName(const string& name)
+ {
+ _Name = name;
+ }
+
+ inline void setFrsMaterial(const FrsMaterial& iMaterial)
+ {
+ _FrsMaterial = new FrsMaterial(iMaterial);
+ }
+
+private:
+ BBox<Vec3r> _BBox;
+ Id _Id;
+ string _Name;
+ FrsMaterial *_FrsMaterial;
+};
+
+#endif // __FREESTYLE_REP_H__
diff --git a/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.cpp b/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.cpp
new file mode 100644
index 00000000000..8be3f2527b6
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.cpp
@@ -0,0 +1,110 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/ScenePrettyPrinter.cpp
+ * \ingroup freestyle
+ * \brief Class to display textual information about a scene graph.
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 26/04/2003
+ */
+
+#include <iomanip>
+
+#include "IndexedFaceSet.h"
+#include "ScenePrettyPrinter.h"
+
+#define VISIT(CLASS) \
+ void ScenePrettyPrinter::visit##CLASS(CLASS&) \
+ { \
+ _ofs << _space << #CLASS << endl; \
+ }
+
+VISIT(Node)
+VISIT(NodeShape)
+VISIT(NodeGroup)
+VISIT(NodeLight)
+VISIT(NodeDrawingStyle)
+VISIT(NodeTransform)
+
+void ScenePrettyPrinter::visitNodeShapeBefore(NodeShape&)
+{
+ increaseSpace();
+}
+
+void ScenePrettyPrinter::visitNodeShapeAfter(NodeShape&)
+{
+ decreaseSpace();
+}
+
+void ScenePrettyPrinter::visitNodeGroupBefore(NodeGroup&)
+{
+ increaseSpace();
+}
+
+void ScenePrettyPrinter::visitNodeGroupAfter(NodeGroup&)
+{
+ decreaseSpace();
+}
+
+void ScenePrettyPrinter::visitNodeDrawingStyleBefore(NodeDrawingStyle&)
+{
+ increaseSpace();
+}
+
+void ScenePrettyPrinter::visitNodeDrawingStyleAfter(NodeDrawingStyle&)
+{
+ decreaseSpace();
+}
+
+void ScenePrettyPrinter::visitNodeTransformBefore(NodeTransform&)
+{
+ increaseSpace();
+}
+
+void ScenePrettyPrinter::visitNodeTransformAfter(NodeTransform&)
+{
+ decreaseSpace();
+}
+
+VISIT(LineRep)
+VISIT(OrientedLineRep)
+VISIT(TriangleRep)
+VISIT(VertexRep)
+
+void ScenePrettyPrinter::visitIndexedFaceSet(IndexedFaceSet& ifs)
+{
+ const real *vertices = ifs.vertices();
+ unsigned vsize = ifs.vsize();
+
+ _ofs << _space << "IndexedFaceSet" << endl;
+ const real *p = vertices;
+ for (unsigned int i = 0; i < vsize / 3; i++) {
+ _ofs << _space << " " << setw(3) << setfill('0') << i << ": " << p[0] << ", " << p[1] << ", " << p[2] << endl;
+ p += 3;
+ }
+}
diff --git a/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.h b/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.h
new file mode 100644
index 00000000000..39fb9eceef8
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/ScenePrettyPrinter.h
@@ -0,0 +1,109 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_SCENE_PRETTY_PRINTER_H__
+#define __FREESTYLE_SCENE_PRETTY_PRINTER_H__
+
+/** \file blender/freestyle/intern/scene_graph/ScenePrettyPrinter.h
+ * \ingroup freestyle
+ * \brief Class to display textual information about a scene graph.
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 26/04/2003
+ */
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include "SceneVisitor.h"
+
+using namespace std;
+
+class ScenePrettyPrinter : public SceneVisitor
+{
+public:
+ ScenePrettyPrinter(const string filename = "SceneLog.txt") : SceneVisitor()
+ {
+ if (!filename.empty())
+ _ofs.open(filename.c_str());
+ if (!_ofs.is_open())
+ cerr << "Warning, unable to open file \"" << filename << "\"" << endl;
+ _space = "";
+ }
+
+ virtual ~ScenePrettyPrinter()
+ {
+ if (_ofs.is_open())
+ _ofs.close();
+ }
+
+
+ //
+ // visitClass methods
+ //
+ //////////////////////////////////////////////
+
+ VISIT_DECL(Node);
+ VISIT_DECL(NodeShape);
+ VISIT_DECL(NodeGroup);
+ VISIT_DECL(NodeLight);
+ VISIT_DECL(NodeDrawingStyle);
+ VISIT_DECL(NodeTransform);
+
+ VISIT_DECL(LineRep);
+ VISIT_DECL(OrientedLineRep);
+ VISIT_DECL(TriangleRep);
+ VISIT_DECL(VertexRep);
+ VISIT_DECL(IndexedFaceSet);
+
+ virtual void visitNodeShapeBefore(NodeShape&);
+ virtual void visitNodeShapeAfter(NodeShape&);
+ virtual void visitNodeGroupBefore(NodeGroup&);
+ virtual void visitNodeGroupAfter(NodeGroup&);
+ virtual void visitNodeDrawingStyleBefore(NodeDrawingStyle&);
+ virtual void visitNodeDrawingStyleAfter(NodeDrawingStyle&);
+ virtual void visitNodeTransformBefore(NodeTransform&);
+ virtual void visitNodeTransformAfter(NodeTransform&);
+
+protected:
+ void increaseSpace()
+ {
+ _space += " ";
+ }
+
+ void decreaseSpace()
+ {
+ _space.erase(0, 2);
+ }
+
+private:
+ ofstream _ofs;
+ string _space;
+};
+
+#endif // __FREESTYLE_SCENE_PRETTY_PRINTER_H__
diff --git a/source/blender/freestyle/intern/scene_graph/SceneVisitor.cpp b/source/blender/freestyle/intern/scene_graph/SceneVisitor.cpp
new file mode 100644
index 00000000000..32ba38ece80
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/SceneVisitor.cpp
@@ -0,0 +1,35 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/SceneVisitor.cpp
+ * \ingroup freestyle
+ * \brief Class to visit (without doing anything) a scene graph structure
+ * \author Emmanuel Turquin
+ * \date 26/04/2003
+ */
+
+#include "SceneVisitor.h"
diff --git a/source/blender/freestyle/intern/scene_graph/SceneVisitor.h b/source/blender/freestyle/intern/scene_graph/SceneVisitor.h
new file mode 100644
index 00000000000..57d3f9189ed
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/SceneVisitor.h
@@ -0,0 +1,102 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_SCENE_VISITOR_H__
+#define __FREESTYLE_SCENE_VISITOR_H__
+
+/** \file blender/freestyle/intern/scene_graph/SceneVisitor.h
+ * \ingroup freestyle
+ * \brief Class to visit (without doing anything) a scene graph structure
+ * \author Emmanuel Turquin
+ * \date 26/04/2003
+ */
+
+#include "../system/FreestyleConfig.h"
+
+#define VISIT_COMPLETE_DEF(type) \
+ virtual void visit##type(type&) {} \
+ virtual void visit##type##Before(type&) {} \
+ virtual void visit##type##After(type&) {}
+
+#define VISIT_DECL(type) \
+ virtual void visit##type(type&);
+
+#define VISIT_COMPLETE_DECL(type) \
+ virtual void visit##type##Before(type&); \
+ virtual void visit##type(type&); \
+ virtual void visit##type##After(type&);
+
+class Node;
+class NodeShape;
+class NodeGroup;
+class NodeLight;
+class NodeCamera;
+class NodeDrawingStyle;
+class NodeTransform;
+
+class Rep;
+class LineRep;
+class OrientedLineRep;
+class TriangleRep;
+class VertexRep;
+class IndexedFaceSet;
+class DrawingStyle;
+class FrsMaterial;
+
+class LIB_SCENE_GRAPH_EXPORT SceneVisitor
+{
+public:
+ SceneVisitor() {}
+ virtual ~SceneVisitor() {}
+
+ virtual void beginScene() {}
+ virtual void endScene() {}
+
+ //
+ // visitClass methods
+ //
+ //////////////////////////////////////////////
+
+ VISIT_COMPLETE_DEF(Node)
+ VISIT_COMPLETE_DEF(NodeShape)
+ VISIT_COMPLETE_DEF(NodeGroup)
+ VISIT_COMPLETE_DEF(NodeLight)
+ VISIT_COMPLETE_DEF(NodeCamera)
+ VISIT_COMPLETE_DEF(NodeDrawingStyle)
+ VISIT_COMPLETE_DEF(NodeTransform)
+
+ VISIT_COMPLETE_DEF(Rep)
+ VISIT_COMPLETE_DEF(LineRep)
+ VISIT_COMPLETE_DEF(OrientedLineRep)
+ VISIT_COMPLETE_DEF(TriangleRep)
+ VISIT_COMPLETE_DEF(VertexRep)
+ VISIT_COMPLETE_DEF(IndexedFaceSet)
+ VISIT_COMPLETE_DEF(DrawingStyle)
+ VISIT_COMPLETE_DEF(FrsMaterial)
+};
+
+#endif // __FREESTYLE_SCENE_VISITOR_H__
diff --git a/source/blender/freestyle/intern/scene_graph/TriangleRep.cpp b/source/blender/freestyle/intern/scene_graph/TriangleRep.cpp
new file mode 100644
index 00000000000..01053561aae
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/TriangleRep.cpp
@@ -0,0 +1,69 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/TriangleRep.cpp
+ * \ingroup freestyle
+ * \brief Class to define the represenation of a triangle
+ * \author Stephane Grabli
+ * \date 16/12/2002
+ */
+
+#include "TriangleRep.h"
+
+void TriangleRep::ComputeBBox()
+{
+ real XMax = _vertices[0][0];
+ real YMax = _vertices[0][1];
+ real ZMax = _vertices[0][2];
+
+ real XMin = _vertices[0][0];
+ real YMin = _vertices[0][1];
+ real ZMin = _vertices[0][2];
+
+ // parse all the coordinates to find the XMax, YMax, ZMax
+ for (int i = 0; i < 3; ++i) {
+ // X
+ if (_vertices[i][0] > XMax)
+ XMax = _vertices[i][0];
+ if (_vertices[i][0] < XMin)
+ XMin = _vertices[i][0];
+
+ // Y
+ if (_vertices[i][1] > YMax)
+ YMax = _vertices[i][1];
+ if (_vertices[i][1] < YMin)
+ YMin = _vertices[i][1];
+
+ // Z
+ if (_vertices[i][2] > ZMax)
+ ZMax = _vertices[i][2];
+ if (_vertices[i][2] < ZMin)
+ ZMin = _vertices[i][2];
+ }
+
+ setBBox(BBox<Vec3r>(Vec3r(XMin, YMin, ZMin), Vec3r(XMax, YMax, ZMax)));
+}
diff --git a/source/blender/freestyle/intern/scene_graph/TriangleRep.h b/source/blender/freestyle/intern/scene_graph/TriangleRep.h
new file mode 100644
index 00000000000..c65eee72e03
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/TriangleRep.h
@@ -0,0 +1,150 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_TRIANGLE_REP_H__
+#define __FREESTYLE_TRIANGLE_REP_H__
+
+/** \file blender/freestyle/intern/scene_graph/TriangleRep.h
+ * \ingroup freestyle
+ * \brief Class to define the represenation of a triangle
+ * \author Stephane Grabli
+ * \date 16/12/2002
+ */
+
+//! inherits from class Rep
+#include "Rep.h"
+
+/*! Base class for all lines objects */
+class LIB_SCENE_GRAPH_EXPORT TriangleRep : public Rep
+{
+public:
+ /*! Line description style */
+ enum TRIANGLE_STYLE {
+ FILL,
+ LINES,
+ };
+
+private:
+ TRIANGLE_STYLE _Style;
+ Vec3r _vertices[3];
+ Vec3r _colors[3];
+
+public:
+ inline TriangleRep() : Rep()
+ {
+ _Style = FILL;
+ }
+
+ /*! Builds a triangle from 3 vertices
+ * v0
+ * first vertex
+ * v1
+ * second vertex
+ * v2
+ * third vertex
+ */
+ inline TriangleRep(const Vec3r& v0, const Vec3r& v1, const Vec3r& v2) : Rep()
+ {
+ _vertices[0] = v0;
+ _vertices[1] = v1;
+ _vertices[2] = v2;
+ _Style = FILL;
+ }
+
+ inline TriangleRep(const Vec3r& v0, const Vec3r& c0, const Vec3r& v1, const Vec3r& c1,
+ const Vec3r& v2, const Vec3r& c2)
+ : Rep()
+ {
+ _vertices[0] = v0;
+ _vertices[1] = v1;
+ _vertices[2] = v2;
+ _colors[0] = c0;
+ _colors[1] = c1;
+ _colors[2] = c2;
+ _Style = FILL;
+ }
+
+ virtual ~TriangleRep() {}
+
+ /*! accessors */
+ inline const TRIANGLE_STYLE style() const
+ {
+ return _Style;
+ }
+
+ inline const Vec3r& vertex(int index) const
+ {
+ return _vertices[index];
+ }
+
+ inline const Vec3r& color(int index) const
+ {
+ return _colors[index];
+ }
+
+ /*! modifiers */
+ inline void setStyle(const TRIANGLE_STYLE iStyle)
+ {
+ _Style = iStyle;
+ }
+
+ inline void setVertex(int index, const Vec3r& iVertex)
+ {
+ _vertices[index] = iVertex;
+ }
+
+ inline void setColor(int index, const Vec3r& iColor)
+ {
+ _colors[index] = iColor;
+ }
+
+ inline void setVertices(const Vec3r& v0, const Vec3r& v1, const Vec3r& v2)
+ {
+ _vertices[0] = v0;
+ _vertices[1] = v1;
+ _vertices[2] = v2;
+ }
+
+ inline void setColors(const Vec3r& c0, const Vec3r& c1, const Vec3r& c2)
+ {
+ _colors[0] = c0;
+ _colors[1] = c1;
+ _colors[2] = c2;
+ }
+
+ /*! Accept the corresponding visitor */
+ virtual void accept(SceneVisitor& v)
+ {
+ Rep::accept(v);
+ v.visitTriangleRep(*this);
+ }
+
+ /*! Computes the triangle bounding box.*/
+ virtual void ComputeBBox();
+};
+
+#endif // __FREESTYLE_TRIANGLE_REP_H__
diff --git a/source/blender/freestyle/intern/scene_graph/VertexRep.cpp b/source/blender/freestyle/intern/scene_graph/VertexRep.cpp
new file mode 100644
index 00000000000..75b0d4b91b3
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/VertexRep.cpp
@@ -0,0 +1,41 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/scene_graph/VertexRep.cpp
+ * \ingroup freestyle
+ * \brief Class to define the representation of a vertex for displaying purpose.
+ * \author Stephane Grabli
+ * \date 03/04/2002
+ */
+
+#include "VertexRep.h"
+
+void VertexRep::ComputeBBox()
+{
+ setBBox(BBox<Vec3r>(Vec3r(_coordinates[0], _coordinates[1], _coordinates[2]),
+ Vec3r(_coordinates[0], _coordinates[1], _coordinates[2])));
+}
diff --git a/source/blender/freestyle/intern/scene_graph/VertexRep.h b/source/blender/freestyle/intern/scene_graph/VertexRep.h
new file mode 100644
index 00000000000..7483806f1fe
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/VertexRep.h
@@ -0,0 +1,141 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_VERTEX_REP_H__
+#define __FREESTYLE_VERTEX_REP_H__
+
+/** \file blender/freestyle/intern/scene_graph/VertexRep.h
+ * \ingroup freestyle
+ * \brief Class to define the representation of a vertex for displaying purpose.
+ * \author Stephane Grabli
+ * \date 03/04/2002
+ */
+
+#include "Rep.h"
+
+class LIB_SCENE_GRAPH_EXPORT VertexRep : public Rep
+{
+public:
+ inline VertexRep() : Rep()
+ {
+ _vid = 0;
+ _PointSize = 0.0f;
+ }
+
+ inline VertexRep(real x, real y, real z, int id = 0) : Rep()
+ {
+ _coordinates[0] = x;
+ _coordinates[1] = y;
+ _coordinates[2] = z;
+
+ _vid = id;
+ _PointSize = 0.0f;
+ }
+
+ inline ~VertexRep() {}
+
+ /*! Accept the corresponding visitor */
+ virtual void accept(SceneVisitor& v)
+ {
+ Rep::accept(v);
+ v.visitVertexRep(*this);
+ }
+
+ /*! Computes the rep bounding box. */
+ virtual void ComputeBBox();
+
+ /*! accessors */
+ inline const int vid() const
+ {
+ return _vid;
+ }
+
+ inline const real * coordinates() const
+ {
+ return _coordinates;
+ }
+
+ inline real x() const
+ {
+ return _coordinates[0];
+ }
+
+ inline real y() const
+ {
+ return _coordinates[1];
+ }
+
+ inline real z() const
+ {
+ return _coordinates[2];
+ }
+
+ inline float pointSize() const
+ {
+ return _PointSize;
+ }
+
+ /*! modifiers */
+ inline void setVid(int id)
+ {
+ _vid = id;
+ }
+
+ inline void setX(real x)
+ {
+ _coordinates[0] = x;
+ }
+
+ inline void setY(real y)
+ {
+ _coordinates[1] = y;
+ }
+
+ inline void setZ(real z)
+ {
+ _coordinates[2] = z;
+ }
+
+ inline void setCoordinates(real x, real y, real z)
+ {
+ _coordinates[0] = x;
+ _coordinates[1] = y;
+ _coordinates[2] = z;
+ }
+
+ inline void setPointSize(float iPointSize)
+ {
+ _PointSize = iPointSize;
+ }
+
+private:
+ int _vid; // vertex id
+ real _coordinates[3];
+ float _PointSize;
+};
+
+#endif // __FREESTYLE_VERTEX_REP_H__
diff --git a/source/blender/freestyle/intern/stroke/AdvancedFunctions0D.cpp b/source/blender/freestyle/intern/stroke/AdvancedFunctions0D.cpp
new file mode 100644
index 00000000000..9d955722ac7
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedFunctions0D.cpp
@@ -0,0 +1,117 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/AdvancedFunctions0D.cpp
+ * \ingroup freestyle
+ * \brief Functions taking 0D input
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include "AdvancedFunctions0D.h"
+#include "Canvas.h"
+
+#include "../view_map/Functions0D.h"
+#include "../view_map/SteerableViewMap.h"
+
+namespace Functions0D {
+
+int DensityF0D::operator()(Interface0DIterator& iter)
+{
+ Canvas* canvas = Canvas::getInstance();
+ int bound = _filter.getBound();
+
+ if ((iter->getProjectedX()-bound < 0) || (iter->getProjectedX()+bound>canvas->width()) ||
+ (iter->getProjectedY()-bound < 0) || (iter->getProjectedY()+bound>canvas->height())) {
+ result = 0.0;
+ return 0;
+ }
+
+ RGBImage image;
+ canvas->readColorPixels((int)iter->getProjectedX() - bound, (int)iter->getProjectedY() - bound,
+ _filter.maskSize(), _filter.maskSize(), image);
+ result = _filter.getSmoothedPixel<RGBImage>(&image, (int)iter->getProjectedX(), (int)iter->getProjectedY());
+
+ return 0;
+}
+
+
+int LocalAverageDepthF0D::operator()(Interface0DIterator& iter)
+{
+ Canvas * iViewer = Canvas::getInstance();
+ int bound = _filter.getBound();
+
+ if ((iter->getProjectedX()-bound < 0) || (iter->getProjectedX()+bound>iViewer->width()) ||
+ (iter->getProjectedY()-bound < 0) || (iter->getProjectedY()+bound>iViewer->height())) {
+ result = 0.0;
+ return 0;
+ }
+
+ GrayImage image;
+ iViewer->readDepthPixels((int)iter->getProjectedX() - bound, (int)iter->getProjectedY()-bound,
+ _filter.maskSize(), _filter.maskSize(), image);
+ result = _filter.getSmoothedPixel(&image, (int)iter->getProjectedX(), (int)iter->getProjectedY());
+
+ return 0;
+}
+
+int ReadMapPixelF0D::operator()(Interface0DIterator& iter)
+{
+ Canvas * canvas = Canvas::getInstance();
+ result = canvas->readMapPixel(_mapName, _level, (int)iter->getProjectedX(), (int)iter->getProjectedY());
+ return 0;
+}
+
+int ReadSteerableViewMapPixelF0D::operator()(Interface0DIterator& iter)
+{
+ SteerableViewMap *svm = Canvas::getInstance()->getSteerableViewMap();
+ result = svm->readSteerableViewMapPixel(_orientation, _level, (int)iter->getProjectedX(),
+ (int)iter->getProjectedY());
+ return 0;
+}
+
+int ReadCompleteViewMapPixelF0D::operator()(Interface0DIterator& iter)
+{
+ SteerableViewMap *svm = Canvas::getInstance()->getSteerableViewMap();
+ result = svm->readCompleteViewMapPixel(_level,(int)iter->getProjectedX(), (int)iter->getProjectedY());
+ return 0;
+}
+
+int GetViewMapGradientNormF0D::operator()(Interface0DIterator& iter)
+{
+ SteerableViewMap *svm = Canvas::getInstance()->getSteerableViewMap();
+ float pxy = svm->readCompleteViewMapPixel(_level, (int)iter->getProjectedX(), (int)iter->getProjectedY());
+ float gx = svm->readCompleteViewMapPixel(_level, (int)iter->getProjectedX() + _step, (int)iter->getProjectedY())
+ - pxy;
+ float gy = svm->readCompleteViewMapPixel(_level, (int)iter->getProjectedX(), (int)iter->getProjectedY() + _step)
+ - pxy;
+ result = Vec2f(gx, gy).norm();
+ return 0;
+}
+
+} // end of namespace Functions0D
diff --git a/source/blender/freestyle/intern/stroke/AdvancedFunctions0D.h b/source/blender/freestyle/intern/stroke/AdvancedFunctions0D.h
new file mode 100644
index 00000000000..2875402700b
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedFunctions0D.h
@@ -0,0 +1,229 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_ADVANCED_FUNCTIONS_0D_H__
+#define __FREESTYLE_ADVANCED_FUNCTIONS_0D_H__
+
+/** \file blender/freestyle/intern/stroke/AdvancedFunctions0D.h
+ * \ingroup freestyle
+ * \brief Functions taking 0D input
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include "../image/GaussianFilter.h"
+#include "../image/Image.h"
+
+#include "../view_map/Functions0D.h"
+
+//
+// Functions definitions
+//
+///////////////////////////////////////////////////////////
+
+namespace Functions0D {
+
+// DensityF0D
+/*! Returns the density of the (result) image evaluated at an Interface0D.
+ * This density is evaluated using a pixels square window around the evaluation point and integrating
+ * these values using a gaussian.
+ */
+class LIB_STROKE_EXPORT DensityF0D : public UnaryFunction0D<double>
+{
+public:
+ /*! Builds the functor from the gaussian sigma value.
+ * \param sigma
+ * sigma indicates the x value for which the gaussian function is 0.5. It leads to the window size value.
+ * (the larger, the smoother)
+ */
+ DensityF0D(double sigma = 2) : UnaryFunction0D<double>()
+ {
+ _filter.setSigma((float)sigma);
+ }
+
+ /*! Returns the string "DensityF0D" */
+ string getName() const
+ {
+ return "DensityF0D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface0DIterator& iter);
+
+private:
+ GaussianFilter _filter;
+};
+
+// LocalAverageDepthF0D
+/*! Returns the average depth around a point.
+ * The result is obtained by querying the depth buffer on a window around that point.
+ */
+class LIB_STROKE_EXPORT LocalAverageDepthF0D : public UnaryFunction0D<double>
+{
+private:
+ GaussianFilter _filter;
+
+public:
+ /*! Builds the functor from the size of the mask that will be used. */
+ LocalAverageDepthF0D(real maskSize = 5.0f) : UnaryFunction0D<double>()
+ {
+ _filter.setSigma((float)maskSize / 2.0f);
+ }
+
+ /*! Returns the string "LocalAverageDepthF0D" */
+ string getName() const
+ {
+ return "LocalAverageDepthF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// ReadMapPixel
+/*! Reads a pixel in a map. */
+class LIB_STROKE_EXPORT ReadMapPixelF0D : public UnaryFunction0D<float>
+{
+private:
+ const char * _mapName;
+ int _level;
+
+public:
+ /*! Builds the functor from name of the
+ * Map that must be read.
+ * \param iMapName
+ * The name of the map.
+ * \param level
+ * The level of the pyramid from which the pixel must be read.
+ */
+ ReadMapPixelF0D(const char *iMapName, int level) : UnaryFunction0D<float>()
+ {
+ _mapName = iMapName;
+ _level = level;
+ }
+
+ /*! Returns the string "ReadMapPixelF0D" */
+ string getName() const
+ {
+ return "ReadMapPixelF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// ReadSteerableViewMapPixel
+/*! Reads a pixel in one of the level of one of the steerable viewmaps. */
+class LIB_STROKE_EXPORT ReadSteerableViewMapPixelF0D : public UnaryFunction0D<float>
+{
+private:
+ unsigned _orientation;
+ int _level;
+
+public:
+ /*! Builds the functor
+ * \param nOrientation
+ * The integer belonging to [0,4] indicating the orientation (E,NE,N,NW) we are interested in.
+ * \param level
+ * The level of the pyramid from which the pixel must be read.
+ */
+ ReadSteerableViewMapPixelF0D(unsigned nOrientation, int level) : UnaryFunction0D<float>()
+ {
+ _orientation = nOrientation;
+ _level = level;
+ }
+
+ /*! Returns the string "ReadSteerableViewMapPixelF0D" */
+ string getName() const
+ {
+ return "ReadSteerableViewMapPixelF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// ReadCompleteViewMapPixel
+/*! Reads a pixel in one of the level of the complete viewmap. */
+class LIB_STROKE_EXPORT ReadCompleteViewMapPixelF0D : public UnaryFunction0D<float>
+{
+private:
+ int _level;
+
+public:
+ /*! Builds the functor
+ * \param level
+ * The level of the pyramid from which the pixel must be read.
+ */
+ ReadCompleteViewMapPixelF0D(int level) : UnaryFunction0D<float>()
+ {
+ _level = level;
+ }
+
+ /*! Returns the string "ReadCompleteViewMapPixelF0D" */
+ string getName() const
+ {
+ return "ReadCompleteViewMapPixelF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// GetViewMapGradientNormF0D
+/*! Returns the norm of the gradient of the global viewmap density image. */
+class LIB_STROKE_EXPORT GetViewMapGradientNormF0D: public UnaryFunction0D< float>
+{
+private:
+ int _level;
+ float _step;
+
+public:
+ /*! Builds the functor
+ * \param level
+ * The level of the pyramid from which the pixel must be read.
+ */
+ GetViewMapGradientNormF0D(int level) : UnaryFunction0D<float>()
+ {
+ _level = level;
+ _step = (float)pow(2.0, _level);
+ }
+
+ /*! Returns the string "GetOccludeeF0D" */
+ string getName() const
+ {
+ return "GetViewMapGradientNormF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+} // end of namespace Functions0D
+
+#endif // __FREESTYLE_ADVANCED_FUNCTIONS_0D_H__
diff --git a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp
new file mode 100644
index 00000000000..2df4d19195e
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp
@@ -0,0 +1,138 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/AdvancedFunctions1D.cpp
+ * \ingroup freestyle
+ * \brief Functions taking 1D input
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include "AdvancedFunctions1D.h"
+#include "Canvas.h"
+
+#include "../view_map/SteerableViewMap.h"
+
+// FIXME
+namespace Functions1D {
+
+int GetSteerableViewMapDensityF1D::operator()(Interface1D& inter)
+{
+ SteerableViewMap * svm = Canvas::getInstance()->getSteerableViewMap();
+ Interface0DIterator it = inter.pointsBegin(_sampling);
+ Interface0DIterator itnext = it;
+ ++itnext;
+ FEdge *fe;
+ unsigned nSVM;
+ vector<float> values;
+
+ while (!itnext.isEnd()) {
+ Interface0D& i0D = (*it);
+ Interface0D& i0Dnext = (*itnext);
+ fe = i0D.getFEdge(i0Dnext);
+ if (fe == 0) {
+ cerr << "GetSteerableViewMapDensityF1D warning: no FEdge between " << i0D.getId() << " and "
+ << i0Dnext.getId() << endl;
+ // compute the direction between these two ???
+ Vec2f dir = i0Dnext.getPoint2D() - i0D.getPoint2D();
+ nSVM = svm->getSVMNumber(dir);
+ }
+ else {
+ nSVM = svm->getSVMNumber(fe->getId().getFirst());
+ }
+ Vec2r m((i0D.getProjectedX() + i0Dnext.getProjectedX()) / 2.0,
+ (i0D.getProjectedY() + i0Dnext.getProjectedY()) / 2.0);
+ values.push_back(svm->readSteerableViewMapPixel(nSVM, _level, (int)m[0], (int)m[1]));
+ ++it;
+ ++itnext;
+ }
+
+ float res, res_tmp;
+ vector<float>::iterator v = values.begin(), vend = values.end();
+ unsigned size = 1;
+ switch (_integration) {
+ case MIN:
+ res = *v;
+ ++v;
+ for (; v != vend; ++v) {
+ res_tmp = *v;
+ if (res_tmp < res)
+ res = res_tmp;
+ }
+ break;
+ case MAX:
+ res = *v;
+ ++v;
+ for (; v != vend; ++v) {
+ res_tmp = *v;
+ if (res_tmp > res)
+ res = res_tmp;
+ }
+ break;
+ case FIRST:
+ res = *v;
+ break;
+ case LAST:
+ --vend;
+ res = *vend;
+ break;
+ case MEAN:
+ default:
+ res = *v;
+ ++v;
+ for (; v != vend; ++v, ++size)
+ res += *v;
+ res /= (size ? size : 1);
+ break;
+ }
+ result = res;
+ return 0;
+}
+
+int GetDirectionalViewMapDensityF1D::operator()(Interface1D& inter)
+{
+ //soc unsigned size;
+ result = integrate(_fun, inter.pointsBegin(_sampling), inter.pointsEnd(_sampling), _integration);
+ return 0;
+}
+
+int GetCompleteViewMapDensityF1D::operator()(Interface1D& inter)
+{
+ //soc unsigned size;
+ /* Id id = inter.getId(); */ /* UNUSED */
+ result = integrate(_fun, inter.pointsBegin(_sampling), inter.pointsEnd(_sampling), _integration);
+ return 0;
+}
+
+int GetViewMapGradientNormF1D::operator()(Interface1D& inter)
+{
+ result = integrate(_func, inter.pointsBegin(_sampling), inter.pointsEnd(_sampling), _integration);
+ return 0;
+}
+
+} // Functions1D namespace
diff --git a/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h
new file mode 100644
index 00000000000..35f516cd781
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedFunctions1D.h
@@ -0,0 +1,294 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_ADVANCED_FUNCTIONS_1D_H__
+#define __FREESTYLE_ADVANCED_FUNCTIONS_1D_H__
+
+/** \file blender/freestyle/intern/stroke/AdvancedFunctions1D.h
+ * \ingroup freestyle
+ * \brief Functions taking 1D input
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include "AdvancedFunctions0D.h"
+
+#include "../view_map/Functions1D.h"
+
+//
+// Functions definitions
+//
+///////////////////////////////////////////////////////////
+
+namespace Functions1D {
+
+// DensityF1D
+/*! Returns the density evaluated for an Interface1D.
+ * The density is evaluated for a set of points along the Interface1D (using the DensityF0D functor) with a
+ * user-defined sampling and then integrated into a single value using a user-defined integration method.
+ */
+class DensityF1D : public UnaryFunction1D<double>
+{
+private:
+ float _sampling;
+
+public:
+ /*! Builds the functor.
+ * \param sigma
+ * Thesigma used in DensityF0D and determining the window size used in each density query.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ * \param sampling
+ * The resolution used to sample the chain: the corresponding 0D function is evaluated at each sample point and the
+ * result is obtained by combining the resulting values into a single one, following the method specified by iType.
+ */
+ DensityF1D(double sigma = 2, IntegrationType iType = MEAN, float sampling = 2.0f)
+ : UnaryFunction1D<double>(iType), _fun(sigma)
+ {
+ _sampling = sampling;
+ }
+
+ /*! Destructor */
+ virtual ~DensityF1D() {}
+
+ /*! Returns the string "DensityF1D"*/
+ string getName() const
+ {
+ return "DensityF1D";
+ }
+
+ /*! the () operator.*/
+ int operator()(Interface1D& inter)
+ {
+ result = integrate(_fun, inter.pointsBegin(_sampling), inter.pointsEnd(_sampling), _integration);
+ return 0;
+ }
+
+private:
+ Functions0D::DensityF0D _fun;
+};
+
+// LocalAverageDepthF1D
+/*! Returns the average depth evaluated for an Interface1D.
+ * The average depth is evaluated for a set of points along the Interface1D (using the LocalAverageDepthF0D functor)
+ * with a user-defined sampling and then integrated into a single value using a user-defined integration method.
+ */
+class LocalAverageDepthF1D : public UnaryFunction1D<double>
+{
+public:
+ /*! Builds the functor.
+ * \param sigma
+ * The sigma used in DensityF0D and determining the window size used in each density query.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ LocalAverageDepthF1D(real sigma, IntegrationType iType = MEAN)
+ : UnaryFunction1D<double>(iType), _fun(sigma)
+ {
+ }
+
+ /*! Returns the string "LocalAverageDepthF1D" */
+ string getName() const
+ {
+ return "LocalAverageDepthF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter)
+ {
+ result = integrate(_fun, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ return 0;
+ }
+
+private:
+ Functions0D::LocalAverageDepthF0D _fun;
+};
+
+// GetCompleteViewMapDensity
+/*! Returns the density evaluated for an Interface1D in the complete viewmap image.
+ * The density is evaluated for a set of points along the Interface1D (using the ReadCompleteViewMapPixelF0D functor)
+ * and then integrated into a single value using a user-defined integration method.
+ */
+class LIB_STROKE_EXPORT GetCompleteViewMapDensityF1D : public UnaryFunction1D<double>
+{
+public:
+ /*! Builds the functor.
+ * \param level
+ * The level of the pyramid from which
+ * the pixel must be read.
+ * \param iType
+ * The integration method used to compute
+ * a single value from a set of values.
+ * \param sampling
+ * The resolution used to sample the chain: the corresponding 0D function
+ * is evaluated at each sample point and the result is obtained by
+ * combining the resulting values into a single one, following the
+ * method specified by iType.
+ */
+ GetCompleteViewMapDensityF1D(unsigned level, IntegrationType iType = MEAN, float sampling = 2.0f)
+ : UnaryFunction1D<double>(iType), _fun(level)
+ {
+ _sampling = sampling;
+ }
+
+ /*! Returns the string "GetCompleteViewMapDensityF1D" */
+ string getName() const
+ {
+ return "GetCompleteViewMapDensityF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+
+private:
+ Functions0D::ReadCompleteViewMapPixelF0D _fun;
+ float _sampling;
+};
+
+// GetDirectionalViewMapDensity
+/*! Returns the density evaluated for an Interface1D in of the steerable viewmaps image.
+ * The direction telling which Directional map to choose is explicitely specified by the user.
+ * The density is evaluated for a set of points along the Interface1D (using the ReadSteerableViewMapPixelF0D functor)
+ * and then integrated into a single value using a user-defined integration method.
+ */
+class LIB_STROKE_EXPORT GetDirectionalViewMapDensityF1D : public UnaryFunction1D<double>
+{
+public:
+ /*! Builds the functor.
+ * \param iOrientation
+ * The number of the directional map we must work with.
+ * \param level
+ * The level of the pyramid from which the pixel must be read.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ * \param sampling
+ * The resolution used to sample the chain: the corresponding 0D function is evaluated at each sample point and the
+ * result is obtained by combining the resulting values into a single one, following the method specified by iType.
+ */
+ GetDirectionalViewMapDensityF1D(unsigned iOrientation, unsigned level, IntegrationType iType = MEAN,
+ float sampling = 2.0f)
+ : UnaryFunction1D<double>(iType), _fun(iOrientation, level)
+ {
+ _sampling = sampling;
+ }
+
+ /*! Returns the string "GetDirectionalViewMapDensityF1D" */
+ string getName() const
+ {
+ return "GetDirectionalViewMapDensityF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+
+private:
+ Functions0D::ReadSteerableViewMapPixelF0D _fun;
+ float _sampling;
+};
+
+// GetSteerableViewMapDensityF1D
+/*! Returns the density of the viewmap for a given Interface1D. The density of each FEdge is evaluated
+ * in the proper steerable ViewMap depending on its oorientation.
+ */
+class LIB_STROKE_EXPORT GetSteerableViewMapDensityF1D : public UnaryFunction1D<real>
+{
+private:
+ int _level;
+ float _sampling;
+
+public:
+ /*! Builds the functor from the level of the pyramid from which the pixel must be read.
+ * \param level
+ * The level of the pyramid from which the pixel must be read.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ * \param sampling
+ * The resolution used to sample the chain: the corresponding 0D function is evaluated at each sample point and the
+ * result is obtained by combining the resulting values into a single one, following the method specified by iType.
+ */
+ GetSteerableViewMapDensityF1D(int level,IntegrationType iType = MEAN, float sampling = 2.0f)
+ : UnaryFunction1D<real>(iType)
+ {
+ _level = level;
+ _sampling = sampling;
+ }
+
+ /*! Destructor */
+ virtual ~GetSteerableViewMapDensityF1D() {}
+
+ /*! Returns the string "GetSteerableViewMapDensityF1D" */
+ string getName() const
+ {
+ return "GetSteerableViewMapDensityF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// GetViewMapGradientNormF1D
+/*! Returns the density of the viewmap for a given Interface1D. The density of each FEdge is evaluated in
+ * the proper steerable ViewMap depending on its oorientation.
+ */
+class LIB_STROKE_EXPORT GetViewMapGradientNormF1D : public UnaryFunction1D<real>
+{
+private:
+ int _level;
+ float _sampling;
+ Functions0D::GetViewMapGradientNormF0D _func;
+
+public:
+ /*! Builds the functor from the level of the pyramid from which the pixel must be read.
+ * \param level
+ * The level of the pyramid from which the pixel must be read.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ * \param sampling
+ * The resolution used to sample the chain: the corresponding 0D function is evaluated at each sample point and the
+ * result is obtained by combining the resulting values into a single one, following the method specified by iType.
+ */
+ GetViewMapGradientNormF1D(int level,IntegrationType iType = MEAN, float sampling = 2.0f)
+ : UnaryFunction1D<real>(iType), _func(level)
+ {
+ _level = level;
+ _sampling = sampling;
+ }
+
+ /*! Returns the string "GetSteerableViewMapDensityF1D" */
+ string getName() const
+ {
+ return "GetViewMapGradientNormF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+} // end of namespace Functions1D
+
+#endif // __FREESTYLE_ADVANCED_FUNCTIONS_1D_H__
diff --git a/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h b/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h
new file mode 100644
index 00000000000..9235598da78
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h
@@ -0,0 +1,95 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_ADVANCED_PREDICATES_1D_H__
+#define __FREESTYLE_ADVANCED_PREDICATES_1D_H__
+
+/** \file blender/freestyle/intern/stroke/AdvancedPredicates1D.h
+ * \ingroup freestyle
+ * \brief Class gathering stroke creation algorithms
+ * \author Stephane Grabli
+ * \date 01/07/2003
+ */
+
+#include <string>
+
+#include "AdvancedFunctions1D.h"
+#include "Predicates1D.h"
+
+#include "../view_map/Interface1D.h"
+
+//
+// Predicates definitions
+//
+///////////////////////////////////////////////////////////
+
+namespace Predicates1D {
+
+// DensityLowerThanUP1D
+/*! Returns true if the density evaluated for the
+* Interface1D is less than a user-defined density value.
+*/
+class DensityLowerThanUP1D : public UnaryPredicate1D
+{
+public:
+ /*! Builds the functor.
+ * \param threshold
+ * The value of the threshold density.
+ * Any Interface1D having a density lower than this threshold will match.
+ * \param sigma
+ * The sigma value defining the density evaluation window size used in the DensityF0D functor.
+ */
+ DensityLowerThanUP1D(double threshold, double sigma = 2)
+ {
+ _threshold = threshold;
+ _sigma = sigma;
+ }
+
+ /*! Returns the string "DensityLowerThanUP1D" */
+ string getName() const
+ {
+ return "DensityLowerThanUP1D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface1D& inter)
+ {
+ Functions1D::DensityF1D fun(_sigma);
+ if (fun(inter) < 0)
+ return -1;
+ result = (fun.result < _threshold);
+ return 0;
+ }
+
+private:
+ double _sigma;
+ double _threshold;
+};
+
+} // end of namespace Predicates1D
+
+#endif // __FREESTYLE_ADVANCED_PREDICATES_1D_H__
diff --git a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp
new file mode 100644
index 00000000000..e631b9f4471
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp
@@ -0,0 +1,404 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp
+ * \ingroup freestyle
+ * \brief Fredo's stroke shaders
+ * \author Fredo Durand
+ * \date 17/12/2002
+ */
+
+#include "AdvancedStrokeShaders.h"
+#include "StrokeIterators.h"
+
+#include "../system/PseudoNoise.h"
+#include "../system/RandGen.h"
+
+/////////////////////////////////////////
+//
+// CALLIGRAPHICS SHADER
+//
+/////////////////////////////////////////
+
+CalligraphicShader::CalligraphicShader(real iMinThickness, real iMaxThickness, const Vec2f &iOrientation, bool clamp)
+: StrokeShader()
+{
+ _minThickness = iMinThickness;
+ _maxThickness = iMaxThickness;
+ _orientation = iOrientation;
+ _orientation.normalize();
+ _clamp = clamp;
+}
+
+float ksinToto = 0.0f;
+
+int CalligraphicShader::shade(Stroke &ioStroke) const
+{
+ Interface0DIterator v;
+ Functions0D::VertexOrientation2DF0D fun;
+ StrokeVertex *sv;
+ for (v = ioStroke.verticesBegin(); !v.isEnd(); ++v) {
+ real thickness;
+ if (fun(v) < 0)
+ return -1;
+
+ Vec2f vertexOri(fun.result);
+ Vec2r ori2d(-vertexOri[1], vertexOri[0]);
+ ori2d.normalizeSafe();
+ real scal = ori2d * _orientation;
+ sv = dynamic_cast<StrokeVertex*>(&(*v));
+ if (_clamp && (scal<0)) {
+ scal = 0.0;
+ sv->attribute().setColor(1, 1, 1);
+ }
+ else {
+ scal = fabs(scal);
+ sv->attribute().setColor(0, 0, 0);
+ }
+ thickness = _minThickness + scal * (_maxThickness - _minThickness);
+ if (thickness < 0.0)
+ thickness = 0.0;
+ sv->attribute().setThickness(thickness / 2.0, thickness / 2.0);
+ }
+
+ return 0;
+}
+
+#if 0
+void TipRemoverShader::shade(Stroke &ioStroke) const
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ for (v = ioStroke.strokeVerticesBegin(), vend = ioStroke.strokeVerticesEnd(); v != vend; ++v) {
+ if (((*v)->curvilinearAbscissa() < _tipLength) ||
+ (((*v)->strokeLength() - (*v)->curvilinearAbscissa()) < _tipLength)) {
+ (*v)->attribute().setThickness(0.0, 0.0);
+ (*v)->attribute().setColor(1, 1, 1);
+ }
+ }
+}
+#endif
+
+/////////////////////////////////////////
+//
+// SPATIAL NOISE SHADER
+//
+/////////////////////////////////////////
+
+static const unsigned NB_VALUE_NOISE = 512;
+
+SpatialNoiseShader::SpatialNoiseShader(float ioamount, float ixScale, int nbOctave, bool smooth, bool pureRandom)
+: StrokeShader()
+{
+ _amount = ioamount;
+ if (ixScale == 0)
+ _xScale = 0;
+ else
+ _xScale = 1.0 / ixScale / real(NB_VALUE_NOISE);
+ _nbOctave = nbOctave;
+ _smooth = smooth;
+ _pureRandom = pureRandom;
+}
+
+int SpatialNoiseShader::shade(Stroke &ioStroke) const
+{
+ Interface0DIterator v, v2;
+ v = ioStroke.verticesBegin();
+ Vec2r p(v->getProjectedX(), v->getProjectedY());
+ v2 = v;
+ ++v2;
+ Vec2r p0(v2->getProjectedX(), v2->getProjectedY());
+ p0 = p + 2 * (p - p0);
+ StrokeVertex *sv;
+ sv = dynamic_cast<StrokeVertex*>(&(*v));
+ real initU = sv->strokeLength() * real(NB_VALUE_NOISE);
+ if (_pureRandom)
+ initU += RandGen::drand48() * real(NB_VALUE_NOISE);
+
+ Functions0D::VertexOrientation2DF0D fun;
+ while (!v.isEnd()) {
+ sv = dynamic_cast<StrokeVertex*>(&(*v));
+ Vec2r p(sv->getPoint());
+ if (fun(v) < 0)
+ return -1;
+ Vec2r vertexOri(fun.result);
+ Vec2r ori2d(vertexOri[0], vertexOri[1]);
+ ori2d = Vec2r(p - p0);
+ ori2d.normalizeSafe();
+
+ PseudoNoise mynoise;
+ real bruit;
+
+ if (_smooth)
+ bruit = mynoise.turbulenceSmooth(_xScale * sv->curvilinearAbscissa() + initU, _nbOctave);
+ else
+ bruit = mynoise.turbulenceLinear(_xScale * sv->curvilinearAbscissa() + initU, _nbOctave);
+
+ Vec2r noise(-ori2d[1] * _amount * bruit, ori2d[0] * _amount * bruit);
+
+ sv->setPoint(p[0] + noise[0], p[1] + noise[1]);
+ p0 = p;
+
+ ++v;
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////
+//
+// SMOOTHING SHADER
+//
+/////////////////////////////////////////
+
+SmoothingShader::SmoothingShader(int ionbIteration, real iFactorPoint, real ifactorCurvature,
+ real iFactorCurvatureDifference, real iAnisoPoint, real iAnisoNormal,
+ real iAnisoCurvature, real iCarricatureFactor)
+: StrokeShader()
+{
+ _nbIterations = ionbIteration;
+ _factorCurvature = ifactorCurvature;
+ _factorCurvatureDifference = iFactorCurvatureDifference;
+ _anisoNormal = iAnisoNormal;
+ _anisoCurvature = iAnisoCurvature;
+ _carricatureFactor = iCarricatureFactor;
+ _factorPoint = iFactorPoint;
+ _anisoPoint = iAnisoPoint;
+}
+
+int SmoothingShader::shade(Stroke &ioStroke) const
+{
+ // cerr << " Smoothing a stroke " << endl;
+
+ Smoother smoother(ioStroke);
+ smoother.smooth(_nbIterations, _factorPoint, _factorCurvature, _factorCurvatureDifference, _anisoPoint,
+ _anisoNormal, _anisoCurvature, _carricatureFactor);
+ return 0;
+}
+
+// SMOOTHER
+////////////////////////////
+
+Smoother::Smoother(Stroke &ioStroke)
+{
+ _stroke = &ioStroke;
+
+ _nbVertices = ioStroke.vertices_size();
+ _vertex = new Vec2r[_nbVertices];
+ _curvature = new real[_nbVertices];
+ _normal = new Vec2r[_nbVertices];
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int i = 0;
+ for (v = ioStroke.strokeVerticesBegin(), vend = ioStroke.strokeVerticesEnd(); v != vend; ++v, ++i) {
+ _vertex[i] = (v)->getPoint();
+ }
+ Vec2r vec_tmp(_vertex[0] - _vertex[_nbVertices - 1]);
+ _isClosedCurve = (vec_tmp.norm() < M_EPSILON);
+
+ _safeTest = (_nbVertices > 4);
+}
+
+void Smoother::smooth(int nbIteration, real iFactorPoint, real ifactorCurvature, real iFactorCurvatureDifference,
+ real iAnisoPoint, real iAnisoNormal, real iAnisoCurvature, real iCarricatureFactor)
+{
+ _factorCurvature = ifactorCurvature;
+ _factorCurvatureDifference = iFactorCurvatureDifference;
+ _anisoNormal = iAnisoNormal;
+ _anisoCurvature = iAnisoCurvature;
+ _carricatureFactor = iCarricatureFactor;
+ _factorPoint = iFactorPoint;
+ _anisoPoint = iAnisoPoint;
+
+ for (int i = 0; i < nbIteration; ++i)
+ iteration ();
+ copyVertices();
+}
+
+static real edgeStopping(real x, real sigma)
+{
+ if (sigma == 0.0)
+ return 1.0;
+ return exp(-x * x / (sigma * sigma));
+}
+
+void Smoother::iteration()
+{
+ computeCurvature();
+ for (int i = 1; i < (_nbVertices - 1); ++i) {
+ real motionNormal = _factorCurvature * _curvature[i] * edgeStopping(_curvature[i], _anisoNormal);
+
+ real diffC1 = _curvature[i] - _curvature[i - 1];
+ real diffC2 = _curvature[i] - _curvature[i + 1];
+ real motionCurvature = edgeStopping(diffC1, _anisoCurvature) * diffC1 +
+ edgeStopping(diffC2, _anisoCurvature) * diffC2; //_factorCurvatureDifference;
+ motionCurvature *= _factorCurvatureDifference;
+ //motionCurvature = _factorCurvatureDifference * (diffC1 + diffC2);
+ if (_safeTest)
+ _vertex[i] = Vec2r(_vertex[i] + (motionNormal + motionCurvature) * _normal[i]);
+ Vec2r v1(_vertex[i - 1] - _vertex[i]);
+ Vec2r v2(_vertex[i + 1] - _vertex[i]);
+ real d1 = v1.norm();
+ real d2 = v2.norm();
+ _vertex[i] = Vec2r(_vertex[i] +
+ _factorPoint * edgeStopping(d2, _anisoPoint) * (_vertex[i - 1] - _vertex[i]) +
+ _factorPoint * edgeStopping(d1, _anisoPoint) * (_vertex[i + 1] - _vertex[i]));
+ }
+
+ if (_isClosedCurve) {
+ real motionNormal = _factorCurvature * _curvature[0] * edgeStopping(_curvature[0], _anisoNormal);
+
+ real diffC1 = _curvature[0] - _curvature[_nbVertices - 2];
+ real diffC2 = _curvature[0] - _curvature[1];
+ real motionCurvature = edgeStopping(diffC1, _anisoCurvature) * diffC1 +
+ edgeStopping(diffC2, _anisoCurvature) * diffC2; //_factorCurvatureDifference;
+ motionCurvature *= _factorCurvatureDifference;
+ //motionCurvature = _factorCurvatureDifference * (diffC1 + diffC2);
+ _vertex[0] = Vec2r(_vertex[0] + (motionNormal + motionCurvature) * _normal[0]);
+ _vertex[_nbVertices - 1] = _vertex[0];
+ }
+}
+
+
+void Smoother::computeCurvature()
+{
+ int i;
+ Vec2r BA, BC, normalCurvature;
+ for (i = 1; i < (_nbVertices - 1); ++i) {
+ BA = _vertex[i - 1] - _vertex[i];
+ BC = _vertex[i + 1] - _vertex[i];
+ real lba = BA.norm(), lbc = BC.norm();
+ BA.normalizeSafe();
+ BC.normalizeSafe();
+ normalCurvature = BA + BC;
+
+ _normal[i] = Vec2r(-(BC - BA)[1], (BC - BA)[0]);
+ _normal[i].normalizeSafe();
+
+ _curvature[i] = normalCurvature * _normal[i];
+ if (lba + lbc > M_EPSILON)
+ _curvature[i] /= (0.5 * lba + lbc);
+ }
+ _curvature[0] = _curvature[1];
+ _curvature[_nbVertices - 1] = _curvature[_nbVertices - 2];
+ Vec2r di(_vertex[1] - _vertex[0]);
+ _normal[0] = Vec2r(-di[1], di[0]);
+ _normal[0].normalizeSafe();
+ di = _vertex[_nbVertices - 1] - _vertex[_nbVertices - 2];
+ _normal[_nbVertices - 1] = Vec2r(-di[1], di[0]);
+ _normal[_nbVertices - 1].normalizeSafe();
+
+ if (_isClosedCurve) {
+ BA = _vertex[_nbVertices - 2] - _vertex[0];
+ BC = _vertex[1] - _vertex[0];
+ real lba = BA.norm(), lbc = BC.norm();
+ BA.normalizeSafe();
+ BC.normalizeSafe();
+ normalCurvature = BA + BC;
+
+ _normal[i] = Vec2r(-(BC - BA)[1], (BC - BA)[0]);
+ _normal[i].normalizeSafe();
+
+ _curvature[i] = normalCurvature * _normal[i];
+ if (lba + lbc > M_EPSILON)
+ _curvature[i] /= (0.5 * lba + lbc);
+
+ _normal[_nbVertices - 1] = _normal[0];
+ _curvature[_nbVertices - 1] = _curvature[0];
+ }
+}
+
+void Smoother::copyVertices()
+{
+ int i = 0;
+ StrokeInternal::StrokeVertexIterator v, vend;
+ for (v = _stroke->strokeVerticesBegin(), vend = _stroke->strokeVerticesEnd(); v != vend; ++v) {
+ const Vec2r p0((v)->getPoint());
+ const Vec2r p1(_vertex[i]);
+ Vec2r p(p0 + _carricatureFactor * (p1 - p0));
+
+ (v)->setPoint(p[0], p[1]);
+ ++i;
+ }
+}
+
+#if 0 // FIXME
+
+/////////////////////////////////////////
+//
+// OMISSION SHADER
+//
+/////////////////////////////////////////
+
+OmissionShader::OmissionShader(real sizeWindow, real thrVari, real thrFlat, real lFlat)
+{
+ _sizeWindow = sizeWindow;
+ _thresholdVariation = thrVari;
+ _thresholdFlat = thrFlat;
+ _lengthFlat = lFlat;
+}
+
+int OmissionShader::shade(Stroke &ioStroke) const
+{
+ Omitter omi(ioStroke);
+ omi.omit(_sizeWindow, _thresholdVariation, _thresholdFlat, _lengthFlat);
+
+ return 0;
+}
+
+
+// OMITTER
+///////////////////////////
+
+Omitter::Omitter(Stroke &ioStroke) : Smoother(ioStroke)
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int i = 0;
+ for (v = ioStroke.strokeVerticesBegin(), vend = ioStroke.strokeVerticesEnd(); v != vend; ++v, ++i) {
+ _u[i] = (v)->curvilinearAbscissa();
+ }
+}
+
+void Omitter::omit(real sizeWindow, real thrVari, real thrFlat, real lFlat)
+{
+ _sizeWindow=sizeWindow;
+ _thresholdVariation=thrVari;
+ _thresholdFlat=thrFlat;
+ _lengthFlat=lFlat;
+
+ for (int i = 1; i < _nbVertices-1; ++i) {
+ if (_u[i] < _lengthFlat)
+ continue;
+ // is the previous segment flat?
+ int j = i - 1;
+ while ((j >= 0) && (_u[i] - _u[j] < _lengthFlat)) {
+ if ((_normal[j] * _normal[i]) < _thresholdFlat)
+ ; // FIXME
+ --j;
+ }
+ }
+}
+
+#endif
diff --git a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
new file mode 100644
index 00000000000..a957a3f7155
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
@@ -0,0 +1,226 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_ADVANCED_STROKE_SHADERS_H__
+#define __FREESTYLE_ADVANCED_STROKE_SHADERS_H__
+
+/** \file blender/freestyle/intern/stroke/AdvancedStrokeShaders.h
+ * \ingroup freestyle
+ * \brief Fredo's stroke shaders
+ * \author Fredo Durand
+ * \date 17/12/2002
+ */
+
+#include "BasicStrokeShaders.h"
+
+/*! [ Thickness Shader ].
+ * Assigns thicknesses to the stroke vertices so that the stroke looks like made with a calligraphic tool.
+ * i.e. The stroke will be the thickest in a main direction, the thinest in the direction perpendicular to this one,
+ * and an interpolation inbetween.
+ */
+class LIB_STROKE_EXPORT CalligraphicShader : public StrokeShader
+{
+public:
+ /*! Builds the shader.
+ * \param iMinThickness
+ * The minimum thickness in the direction perpandicular to the main direction.
+ * \param iMaxThickness
+ * The maximum thickness in the main direction.
+ * \param iOrientation
+ * The 2D vector giving the main direction.
+ * \param clamp
+ * Tells ???
+ */
+ CalligraphicShader(real iMinThickness, real iMaxThickness, const Vec2f &iOrientation, bool clamp);
+
+ /*! Destructor. */
+ virtual ~CalligraphicShader() {}
+
+ /*! The shading method */
+ virtual int shade(Stroke &ioStroke) const;
+
+protected:
+ real _maxThickness;
+ real _minThickness;
+ Vec2f _orientation;
+ bool _clamp;
+};
+
+/*! [ Geometry Shader ].
+ * Spatial Noise stroke shader.
+ * Moves the vertices to make the stroke more noisy.
+ * @see \htmlonly <a href=noise/noise.html>noise/noise.html</a> \endhtmlonly
+ */
+class LIB_STROKE_EXPORT SpatialNoiseShader : public StrokeShader
+{
+public:
+ /*! Builds the shader.
+ * \param iAmount
+ * The amplitude of the noise.
+ * \param ixScale
+ * The noise frequency
+ * \param nbOctave
+ * The number of octaves
+ * \param smooth
+ * If you want the noise to be smooth
+ * \param pureRandom
+ * If you don't want any coherence
+ */
+ SpatialNoiseShader(float iAmount, float ixScale, int nbOctave, bool smooth, bool pureRandom);
+
+ /*! Destructor. */
+ virtual ~SpatialNoiseShader() {}
+
+ /*! The shading method. */
+ virtual int shade(Stroke &ioStroke) const;
+
+protected:
+ float _amount;
+ float _xScale;
+ int _nbOctave;
+ bool _smooth;
+ bool _pureRandom;
+};
+
+/*! [ Geometry Shader ].
+ * Smoothes the stroke.
+ * (Moves the vertices to make the stroke smoother).
+ * Uses curvature flow to converge towards a curve of constant curvature. The diffusion method we use is anisotropic
+ * to prevent the diffusion accross corners.
+ * @see \htmlonly <a href=/smoothing/smoothing.html>smoothing/smoothing.html</a> endhtmlonly
+ */
+class LIB_STROKE_EXPORT SmoothingShader : public StrokeShader
+{
+public:
+ /*! Builds the shader.
+ * \param iNbIteration
+ * The number of iterations. (400)
+ * \param iFactorPoint
+ * 0
+ * \param ifactorCurvature
+ * 0
+ * \param iFactorCurvatureDifference
+ * 0.2
+ * \param iAnisoPoint
+ * 0
+ * \param iAnisNormal
+ * 0
+ * \param iAnisoCurvature
+ * 0
+ * \param icarricatureFactor
+ * 1
+ */
+ SmoothingShader(int iNbIteration, real iFactorPoint, real ifactorCurvature, real iFactorCurvatureDifference,
+ real iAnisoPoint, real iAnisoNormal, real iAnisoCurvature, real icarricatureFactor);
+
+ /*! Destructor. */
+ virtual ~SmoothingShader() {}
+
+ /*! The shading method. */
+ virtual int shade(Stroke &ioStroke) const;
+
+protected:
+ int _nbIterations;
+ real _factorPoint;
+ real _factorCurvature;
+ real _factorCurvatureDifference;
+ real _anisoPoint;
+ real _anisoNormal;
+ real _anisoCurvature;
+ real _carricatureFactor;
+};
+
+class LIB_STROKE_EXPORT Smoother
+{
+public:
+ Smoother(Stroke &ioStroke);
+
+ virtual ~Smoother() {}
+
+ void smooth(int nbIterations, real iFactorPoint, real ifactorCurvature, real iFactorCurvatureDifference,
+ real iAnisoPoint, real iAnisoNormal, real iAnisoCurvature, real icarricatureFactor);
+
+ void computeCurvature();
+
+protected:
+ real _factorPoint;
+ real _factorCurvature;
+ real _factorCurvatureDifference;
+ real _anisoPoint;
+ real _anisoNormal;
+ real _anisoCurvature;
+ real _carricatureFactor;
+
+ void iteration();
+ void copyVertices ();
+
+ Stroke *_stroke;
+ int _nbVertices;
+ Vec2r *_vertex;
+ Vec2r *_normal;
+ real *_curvature;
+ bool *_isFixedVertex;
+
+ bool _isClosedCurve;
+ bool _safeTest;
+};
+
+class LIB_STROKE_EXPORT Omitter : public Smoother
+{
+public:
+ Omitter(Stroke &ioStroke);
+
+ virtual ~Omitter() {}
+
+ void omit(real sizeWindow, real thrVari, real thrFlat, real lFlat);
+
+protected:
+ real *_u;
+
+ real _sizeWindow;
+ real _thresholdVariation;
+ real _thresholdFlat;
+ real _lengthFlat;
+};
+
+/*! Omission shader */
+class LIB_STROKE_EXPORT OmissionShader : public StrokeShader
+{
+public:
+ OmissionShader(real sizeWindow, real thrVari, real thrFlat, real lFlat);
+ virtual ~OmissionShader() {}
+
+ virtual int shade(Stroke &ioStroke) const;
+
+protected:
+ real _sizeWindow;
+ real _thresholdVariation;
+ real _thresholdFlat;
+ real _lengthFlat;
+};
+
+#endif // __FREESTYLE_ADVANCED_STROKE_SHADERS_H__
diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp
new file mode 100644
index 00000000000..dd6e6dc317e
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp
@@ -0,0 +1,1134 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/BasicStrokeShaders.cpp
+ * \ingroup freestyle
+ * \brief Class gathering basic stroke shaders
+ * \author Stephane Grabli
+ * \date 17/12/2002
+ */
+
+#include <fstream>
+
+#include "AdvancedFunctions0D.h"
+#include "AdvancedFunctions1D.h"
+#include "BasicStrokeShaders.h"
+#include "StrokeIO.h"
+#include "StrokeIterators.h"
+#include "StrokeRenderer.h"
+
+#include "../system/PseudoNoise.h"
+#include "../system/RandGen.h"
+#include "../system/StringUtils.h"
+
+#include "../view_map/Functions0D.h"
+#include "../view_map/Functions1D.h"
+
+#include "BKE_global.h"
+
+//soc #include <qimage.h>
+//soc #include <QString>
+
+extern "C" {
+# include "IMB_imbuf.h"
+# include "IMB_imbuf_types.h"
+}
+
+// Internal function
+
+#if 0 // soc
+void convert(const QImage& iImage, float **oArray, unsigned &oSize)
+{
+ oSize = iImage.width();
+ *oArray = new float[oSize];
+ for (unsigned int i = 0; i < oSize; ++i) {
+ QRgb rgb = iImage.pixel(i,0);
+ (*oArray)[i] = ((float)qBlue(rgb)) / 255.0f;
+ }
+}
+#endif
+
+static void convert(ImBuf *imBuf, float **oArray, unsigned &oSize)
+{
+ oSize = imBuf->x;
+ *oArray = new float[oSize];
+
+ char *pix;
+ for (unsigned int i = 0; i < oSize; ++i) {
+ pix = (char*) imBuf->rect + i * 4;
+ (*oArray)[i] = ((float) pix[2]) / 255.0f;
+ }
+}
+
+namespace StrokeShaders {
+
+//
+// Thickness modifiers
+//
+//////////////////////////////////////////////////////////
+
+int ConstantThicknessShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int i = 0;
+ int size = stroke.strokeVerticesSize();
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ // XXX What's the use of i here? And is not the thickness always overriden by the last line of the loop?
+ if ((1 == i) || (size - 2 == i))
+ v->attribute().setThickness(_thickness / 4.0, _thickness / 4.0);
+ if ((0 == i) || (size - 1 == i))
+ v->attribute().setThickness(0, 0);
+
+ v->attribute().setThickness(_thickness / 2.0, _thickness / 2.0);
+ }
+ return 0;
+}
+
+int ConstantExternThicknessShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int i = 0;
+ int size = stroke.strokeVerticesSize();
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ // XXX What's the use of i here? And is not the thickness always overriden by the last line of the loop?
+ if ((1 == i) || (size - 2 == i))
+ v->attribute().setThickness(_thickness / 2.0, 0);
+ if ((0 == i) || (size - 1 == i))
+ v->attribute().setThickness(0, 0);
+
+ v->attribute().setThickness(_thickness, 0);
+ }
+ return 0;
+}
+
+int IncreasingThicknessShader::shade(Stroke& stroke) const
+{
+ int n = stroke.strokeVerticesSize() - 1, i;
+ StrokeInternal::StrokeVertexIterator v, vend;
+ for (i = 0, v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd();
+ v != vend;
+ ++v, ++i)
+ {
+ float t;
+ if (i < (float)n / 2.0f)
+ t = (1.0 - (float)i / (float)n) * _ThicknessMin + (float)i / (float)n * _ThicknessMax;
+ else
+ t = (1.0 - (float)i / (float)n) * _ThicknessMax + (float)i / (float)n * _ThicknessMin;
+ v->attribute().setThickness(t / 2.0, t / 2.0);
+ }
+ return 0;
+}
+
+int ConstrainedIncreasingThicknessShader::shade(Stroke& stroke) const
+{
+ float slength = stroke.getLength2D();
+ float maxT = min(_ratio*slength,_ThicknessMax);
+ int n = stroke.strokeVerticesSize() - 1, i;
+ StrokeInternal::StrokeVertexIterator v, vend;
+ for (i = 0, v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd();
+ v != vend;
+ ++v, ++i)
+ {
+ // XXX Why not using an if/else here? Else, if last condition is true, everything else is computed for nothing!
+ float t;
+ if (i < (float)n / 2.0f)
+ t = (1.0 - (float)i / (float)n) * _ThicknessMin + (float)i / (float)n * maxT;
+ else
+ t = (1.0 - (float)i / (float)n) * maxT + (float)i / (float)n * _ThicknessMin;
+ v->attribute().setThickness(t / 2.0, t / 2.0);
+ if (i == n - 1)
+ v->attribute().setThickness(_ThicknessMin / 2.0, _ThicknessMin / 2.0);
+ }
+ return 0;
+}
+
+
+int LengthDependingThicknessShader::shade(Stroke& stroke) const
+{
+ float step = (_maxThickness - _minThickness) / 3.0f;
+ float l = stroke.getLength2D();
+ float thickness = 0.0f;
+ if (l > 300.0f)
+ thickness = _minThickness + 3.0f * step;
+ else if ((l < 300.0f) && (l > 100.0f))
+ thickness = _minThickness + 2.0f * step;
+ else if ((l < 100.0f) && (l > 50.0f))
+ thickness = _minThickness + 1.0f * step;
+ else // else if (l < 50.0f), tsst...
+ thickness = _minThickness;
+
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int i = 0;
+ int size = stroke.strokeVerticesSize();
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ // XXX What's the use of i here? And is not the thickness always overriden by the last line of the loop?
+ if ((1 == i) || (size - 2 == i))
+ v->attribute().setThickness(thickness / 4.0, thickness / 4.0);
+ if ((0 == i) || (size - 1 == i))
+ v->attribute().setThickness(0, 0);
+
+ v->attribute().setThickness(thickness / 2.0, thickness / 2.0);
+ }
+ return 0;
+}
+
+
+ThicknessVariationPatternShader::ThicknessVariationPatternShader(const string pattern_name, float iMinThickness,
+ float iMaxThickness, bool stretch)
+: StrokeShader()
+{
+ _stretch = stretch;
+ _minThickness = iMinThickness;
+ _maxThickness = iMaxThickness;
+ ImBuf *image = NULL; //soc
+ vector<string> pathnames;
+ StringUtils::getPathName(TextureManager::Options::getPatternsPath(), pattern_name, pathnames);
+ for (vector<string>::const_iterator j = pathnames.begin(); j != pathnames.end(); ++j) {
+ ifstream ifs(j->c_str());
+ if (ifs.is_open()) {
+ //soc image.load(j->c_str());
+ /* OCIO_TODO: support different input color space */
+ image = IMB_loadiffname(j->c_str(), 0, NULL);
+ break;
+ }
+ }
+ if (image == NULL) //soc
+ cerr << "Error: cannot find pattern \"" << pattern_name << "\" - check the path in the Options" << endl;
+ else
+ convert(image, &_aThickness, _size);
+}
+
+
+int ThicknessVariationPatternShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ float *array = NULL;
+ /* int size; */ /* UNUSED */
+ array = _aThickness;
+ /* size = _size; */ /* UNUSED */
+ int vert_size = stroke.strokeVerticesSize();
+ int sig = 0;
+ unsigned index;
+ const float* originalThickness;
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ originalThickness = v->attribute().getThickness();
+ if (_stretch) {
+ float tmp = v->u() * (_size - 1);
+ index = (unsigned)floor(tmp);
+ if ((tmp - index) > (index + 1 - tmp))
+ ++index;
+ }
+ else {
+ index = (unsigned)floor(v->curvilinearAbscissa());
+ }
+ index %= _size;
+ float thicknessR = array[index] * originalThickness[0];
+ float thicknessL = array[index] * originalThickness[1];
+ if (thicknessR+thicknessL < _minThickness) {
+ thicknessL = _minThickness/2.0f;
+ thicknessR = _minThickness/2.0f;
+ }
+ if (thicknessR+thicknessL > _maxThickness) {
+ thicknessL = _maxThickness/2.0f;
+ thicknessR = _maxThickness/2.0f;
+ }
+ if ((sig == 0) || (sig == vert_size - 1))
+ v->attribute().setThickness(1, 1);
+ else
+ v->attribute().setThickness(thicknessR, thicknessL);
+ ++sig;
+ }
+ return 0;
+}
+
+
+static const unsigned NB_VALUE_NOISE = 512;
+
+ThicknessNoiseShader::ThicknessNoiseShader() : StrokeShader()
+{
+ _amplitude = 1.0f;
+ _scale = 1.0f / 2.0f / (float)NB_VALUE_NOISE;
+}
+
+ThicknessNoiseShader::ThicknessNoiseShader(float iAmplitude, float iPeriod) : StrokeShader()
+{
+ _amplitude = iAmplitude;
+ _scale = 1.0f / iPeriod / (float)NB_VALUE_NOISE;
+}
+
+int ThicknessNoiseShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v = stroke.strokeVerticesBegin(), vend;
+ real initU1 = v->strokeLength() * real(NB_VALUE_NOISE) + RandGen::drand48() * real(NB_VALUE_NOISE);
+ real initU2 = v->strokeLength() * real(NB_VALUE_NOISE) + RandGen::drand48() * real(NB_VALUE_NOISE);
+
+ real bruit, bruit2;
+ PseudoNoise mynoise, mynoise2;
+ for (vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ bruit = mynoise.turbulenceSmooth(_scale * v->curvilinearAbscissa() + initU1, 2); // 2 : nbOctaves
+ bruit2 = mynoise2.turbulenceSmooth(_scale * v->curvilinearAbscissa() + initU2, 2); // 2 : nbOctaves
+ const float *originalThickness = v->attribute().getThickness();
+ float r = bruit * _amplitude + originalThickness[0];
+ float l = bruit2 * _amplitude + originalThickness[1];
+ v->attribute().setThickness(r, l);
+ }
+
+ return 0;
+}
+
+//
+// Color shaders
+//
+///////////////////////////////////////////////////////////////////////////////
+
+int ConstantColorShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ v->attribute().setColor(_color[0], _color[1], _color[2]);
+ v->attribute().setAlpha(_color[3]);
+ }
+ return 0;
+}
+
+int IncreasingColorShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ int n = stroke.strokeVerticesSize() - 1, yo;
+ float newcolor[4];
+ for (yo = 0, v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd();
+ v != vend;
+ ++v, ++yo)
+ {
+ for (int i = 0; i < 4; ++i) {
+ newcolor[i] = (1.0 - (float) yo / (float)n) * _colorMin[i] + (float)yo / (float)n * _colorMax[i];
+ }
+ v->attribute().setColor(newcolor[0], newcolor[1], newcolor[2]);
+ v->attribute().setAlpha(newcolor[3]);
+ }
+ return 0;
+}
+
+ColorVariationPatternShader::ColorVariationPatternShader(const string pattern_name, bool stretch) : StrokeShader()
+{
+ _stretch = stretch;
+ ImBuf *image = NULL; //soc
+ vector<string> pathnames;
+ StringUtils::getPathName(TextureManager::Options::getPatternsPath(), pattern_name, pathnames);
+ for (vector<string>::const_iterator j = pathnames.begin(); j != pathnames.end(); ++j) {
+ ifstream ifs(j->c_str());
+ if (ifs.is_open()) {
+ /* OCIO_TODO: support different input color space */
+ image = IMB_loadiffname(j->c_str(), 0, NULL); //soc
+ break;
+ }
+ }
+ if (image == NULL) //soc
+ cerr << "Error: cannot find pattern \"" << pattern_name << "\" - check the path in the Options" << endl;
+ else
+ convert(image, &_aVariation, _size);
+}
+
+int ColorVariationPatternShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v, vend;
+ unsigned index;
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ const float *originalColor = v->attribute().getColor();
+ if (_stretch) {
+ float tmp = v->u() * (_size - 1);
+ index = (unsigned)floor(tmp);
+ if ((tmp - index) > (index + 1 - tmp))
+ ++index;
+ }
+ else {
+ index = (unsigned)floor(v->curvilinearAbscissa());
+ }
+ index %= _size;
+ float r = _aVariation[index] * originalColor[0];
+ float g = _aVariation[index] * originalColor[1];
+ float b = _aVariation[index] * originalColor[2];
+ v->attribute().setColor(r, g, b);
+ }
+ return 0;
+}
+
+int MaterialColorShader::shade(Stroke& stroke) const
+{
+ Interface0DIterator v, vend;
+ Functions0D::MaterialF0D fun;
+ StrokeVertex *sv;
+ for (v = stroke.verticesBegin(), vend = stroke.verticesEnd(); v != vend; ++v) {
+ if (fun(v) < 0)
+ return -1;
+ const float *diffuse = fun.result.diffuse();
+ sv = dynamic_cast<StrokeVertex*>(&(*v));
+ sv->attribute().setColor(diffuse[0] * _coefficient, diffuse[1] * _coefficient, diffuse[2] * _coefficient);
+ sv->attribute().setAlpha(diffuse[3]);
+ }
+ return 0;
+}
+
+
+int CalligraphicColorShader::shade(Stroke& stroke) const
+{
+ Interface0DIterator v;
+ Functions0D::VertexOrientation2DF0D fun;
+ StrokeVertex *sv;
+ for (v = stroke.verticesBegin(); !v.isEnd(); ++v) {
+ if (fun(v) < 0)
+ return -1;
+ Vec2f vertexOri(fun.result);
+ Vec2d ori2d(-vertexOri[1], vertexOri[0]);
+ ori2d.normalizeSafe();
+ real scal = ori2d * _orientation;
+ sv = dynamic_cast<StrokeVertex*>(&(*v));
+ if ((scal < 0))
+ sv->attribute().setColor(0, 0, 0);
+ else
+ sv->attribute().setColor(1, 1, 1);
+ }
+ return 0;
+}
+
+
+ColorNoiseShader::ColorNoiseShader() : StrokeShader()
+{
+ _amplitude = 1.0f;
+ _scale = 1.0f / 2.0f / (float)NB_VALUE_NOISE;
+}
+
+ColorNoiseShader::ColorNoiseShader(float iAmplitude, float iPeriod) : StrokeShader()
+{
+ _amplitude = iAmplitude;
+ _scale = 1.0f / iPeriod / (float)NB_VALUE_NOISE;
+}
+
+int ColorNoiseShader::shade(Stroke& stroke) const
+{
+ StrokeInternal::StrokeVertexIterator v = stroke.strokeVerticesBegin(), vend;
+ real initU = v->strokeLength() * real(NB_VALUE_NOISE) + RandGen::drand48() * real(NB_VALUE_NOISE);
+
+ real bruit;
+ PseudoNoise mynoise;
+ for (vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ bruit = mynoise.turbulenceSmooth(_scale * v->curvilinearAbscissa() + initU, 2); // 2 : nbOctaves
+ const float *originalColor = v->attribute().getColor();
+ float r = bruit * _amplitude + originalColor[0];
+ float g = bruit * _amplitude + originalColor[1];
+ float b = bruit * _amplitude + originalColor[2];
+ v->attribute().setColor(r, g, b);
+ }
+
+ return 0;
+}
+
+
+//
+// Texture Shaders
+//
+///////////////////////////////////////////////////////////////////////////////
+
+int TextureAssignerShader::shade(Stroke& stroke) const
+{
+#if 0
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/charcoalAlpha.bmp", Stroke::HUMID_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/washbrushAlpha.bmp", Stroke::HUMID_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/oil.bmp", Stroke::HUMID_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/oilnoblend.bmp", Stroke::HUMID_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/charcoalAlpha.bmp", Stroke::DRY_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/washbrushAlpha.bmp", Stroke::DRY_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/opaqueDryBrushAlpha.bmp", Stroke::OPAQUE_MEDIUM);
+ getBrushTextureIndex(TEXTURES_DIR "/brushes/opaqueBrushAlpha.bmp", Stroke::OPAQUE_MEDIUM);
+#endif
+
+ TextureManager *instance = TextureManager::getInstance();
+ if (!instance)
+ return 0;
+ string pathname;
+ Stroke::MediumType mediumType;
+ bool hasTips = false;
+ switch (_textureId) {
+ case 0:
+ //pathname = TextureManager::Options::getBrushesPath() + "/charcoalAlpha.bmp";
+ pathname = "/charcoalAlpha.bmp";
+ mediumType = Stroke::HUMID_MEDIUM;
+ hasTips = false;
+ break;
+ case 1:
+ pathname = "/washbrushAlpha.bmp";
+ mediumType = Stroke::HUMID_MEDIUM;
+ hasTips = true;
+ break;
+ case 2:
+ pathname = "/oil.bmp";
+ mediumType = Stroke::HUMID_MEDIUM;
+ hasTips = true;
+ break;
+ case 3:
+ pathname = "/oilnoblend.bmp";
+ mediumType = Stroke::HUMID_MEDIUM;
+ hasTips = true;
+ break;
+ case 4:
+ pathname = "/charcoalAlpha.bmp";
+ mediumType = Stroke::DRY_MEDIUM;
+ hasTips = false;
+ break;
+ case 5:
+ mediumType = Stroke::DRY_MEDIUM;
+ hasTips = true;
+ break;
+ case 6:
+ pathname = "/opaqueDryBrushAlpha.bmp";
+ mediumType = Stroke::OPAQUE_MEDIUM;
+ hasTips = true;
+ break;
+ case 7:
+ pathname = "/opaqueBrushAlpha.bmp";
+ mediumType = Stroke::OPAQUE_MEDIUM;
+ hasTips = true;
+ break;
+ default:
+ pathname = "/smoothAlpha.bmp";
+ mediumType = Stroke::OPAQUE_MEDIUM;
+ hasTips = false;
+ break;
+ }
+ unsigned int texId = instance->getBrushTextureIndex(pathname, mediumType);
+ stroke.setMediumType(mediumType);
+ stroke.setTips(hasTips);
+ stroke.setTextureId(texId);
+ return 0;
+}
+
+// FIXME
+int StrokeTextureShader::shade(Stroke& stroke) const
+{
+ TextureManager *instance = TextureManager::getInstance();
+ if (!instance)
+ return 0;
+ string pathname = TextureManager::Options::getBrushesPath() + "/" + _texturePath;
+ unsigned int texId = instance->getBrushTextureIndex(pathname, _mediumType);
+ stroke.setMediumType(_mediumType);
+ stroke.setTips(_tips);
+ stroke.setTextureId(texId);
+ return 0;
+}
+
+//
+// Geometry Shaders
+//
+///////////////////////////////////////////////////////////////////////////////
+
+int BackboneStretcherShader::shade(Stroke& stroke) const
+{
+ float l = stroke.getLength2D();
+ if (l <= 1.0e-6)
+ return 0;
+
+ StrokeInternal::StrokeVertexIterator v0 = stroke.strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator v1 = v0;
+ ++v1;
+ StrokeInternal::StrokeVertexIterator vn = stroke.strokeVerticesEnd();
+ --vn;
+ StrokeInternal::StrokeVertexIterator vn_1 = vn;
+ --vn_1;
+
+
+ Vec2d first((v0)->x(), (v0)->y());
+ Vec2d last((vn)->x(), (vn)->y());
+
+ Vec2d d1(first-Vec2d((v1)->x(), (v1)->y()));
+ d1.normalize();
+ Vec2d dn(last-Vec2d((vn_1)->x(), (vn_1)->y()));
+ dn.normalize();
+
+ Vec2d newFirst(first + _amount * d1);
+ (v0)->setPoint(newFirst[0], newFirst[1]);
+ Vec2d newLast(last + _amount * dn);
+ (vn)->setPoint(newLast[0], newLast[1]);
+
+ stroke.UpdateLength();
+ return 0;
+}
+
+int SamplingShader::shade(Stroke& stroke) const
+{
+ stroke.Resample(_sampling);
+ stroke.UpdateLength();
+ return 0;
+}
+
+int ExternalContourStretcherShader::shade(Stroke& stroke) const
+{
+ //float l = stroke.getLength2D();
+ Interface0DIterator it;
+ Functions0D::Normal2DF0D fun;
+ StrokeVertex* sv;
+ for (it = stroke.verticesBegin(); !it.isEnd(); ++it) {
+ if (fun(it) < 0)
+ return -1;
+ Vec2f n(fun.result);
+ sv = dynamic_cast<StrokeVertex*>(&(*it));
+ Vec2d newPoint(sv->x() + _amount * n.x(), sv->y() + _amount * n.y());
+ sv->setPoint(newPoint[0], newPoint[1]);
+ }
+ stroke.UpdateLength();
+ return 0;
+}
+
+int BSplineShader::shade(Stroke& stroke) const
+{
+ if (stroke.strokeVerticesSize() < 4)
+ return 0;
+
+ // Find the new vertices
+ vector<Vec2d> newVertices;
+ double t = 0.0;
+ float _sampling = 5.0f;
+
+ StrokeInternal::StrokeVertexIterator p0, p1, p2, p3, end;
+ p0 = stroke.strokeVerticesBegin();
+ p1 = p0;
+ p2 = p1;
+ p3 = p2;
+ end = stroke.strokeVerticesEnd();
+ double a[4], b[4];
+ int n = 0;
+ while (p1 != end) {
+#if 0
+ if (p1 == end)
+ p1 = p0;
+#endif
+ if (p2 == end)
+ p2 = p1;
+ if (p3 == end)
+ p3 = p2;
+ // compute new matrix
+ a[0] = (-(p0)->x() + 3 * (p1)->x() - 3 * (p2)->x() + (p3)->x()) / 6.0;
+ a[1] = (3 * (p0)->x() - 6 * (p1)->x() + 3 * (p2)->x()) / 6.0;
+ a[2] = (-3 * (p0)->x() + 3 * (p2)->x()) / 6.0;
+ a[3] = ((p0)->x() + 4 * (p1)->x() + (p2)->x()) / 6.0;
+
+ b[0] = (-(p0)->y() + 3 * (p1)->y() - 3 * (p2)->y() + (p3)->y()) / 6.0;
+ b[1] = (3 * (p0)->y() - 6 * (p1)->y() + 3 * (p2)->y()) / 6.0;
+ b[2] = (-3 * (p0)->y() + 3 * (p2)->y()) / 6.0;
+ b[3] = ((p0)->y() + 4 * (p1)->y() + (p2)->y()) / 6.0;
+
+ // draw the spline depending on resolution:
+ Vec2d p1p2((p2)->x() - (p1)->x(), (p2)->y() - (p1)->y());
+ double norm = p1p2.norm();
+ //t = _sampling / norm;
+ t = 0;
+ while (t < 1) {
+ newVertices.push_back(Vec2d((a[3] + t * (a[2] + t * (a[1] + t * a[0]))),
+ (b[3] + t * (b[2] + t * (b[1] + t * b[0])))));
+ t = t + _sampling / norm;
+ }
+ if (n > 2) {
+ ++p0;
+ ++p1;
+ ++p2;
+ ++p3;
+ }
+ else {
+ if (n == 0)
+ ++p3;
+ if (n == 1) {
+ ++p2;
+ ++p3;
+ }
+ if (n == 2) {
+ ++p1;
+ ++p2;
+ ++p3;
+ }
+ ++n;
+ }
+ }
+ //last point:
+ newVertices.push_back(Vec2d((p0)->x(), (p0)->y()));
+
+ int originalSize = newVertices.size();
+ _sampling = stroke.ComputeSampling(originalSize);
+
+ // Resample and set x,y coordinates
+ stroke.Resample(_sampling);
+ int newsize = stroke.strokeVerticesSize();
+
+ int nExtraVertex = 0;
+ if (newsize < originalSize) {
+ cerr << "Warning: unsufficient resampling" << endl;
+ }
+ else {
+ nExtraVertex = newsize - originalSize;
+ }
+
+ // assigns the new coordinates:
+ vector<Vec2d>::iterator p = newVertices.begin(), pend = newVertices.end();
+ vector<Vec2d>::iterator last = p;
+ n = 0;
+ StrokeInternal::StrokeVertexIterator it, itend;
+ for (it = stroke.strokeVerticesBegin(), itend = stroke.strokeVerticesEnd();
+ (it != itend) && (p != pend);
+ ++it, ++p, ++n)
+ {
+ it->setX(p->x());
+ it->setY(p->y());
+ last = p;
+ }
+
+ // nExtraVertex should stay unassigned
+ for (int i = 0; i < nExtraVertex; ++i, ++it, ++n) {
+ it->setX(last->x());
+ it->setY(last->y());
+ if (it.isEnd()) {
+ // XXX Shouldn't we break in this case???
+ cerr << "Warning: Problem encountered while creating B-spline" << endl;
+ }
+ }
+ stroke.UpdateLength();
+ return 0;
+}
+
+//!! Bezier curve stroke shader
+int BezierCurveShader::shade(Stroke& stroke) const
+{
+ if (stroke.strokeVerticesSize() < 4)
+ return 0;
+
+ // Build the Bezier curve from this set of data points:
+ vector<Vec2d> data;
+ StrokeInternal::StrokeVertexIterator v = stroke.strokeVerticesBegin(), vend;
+ data.push_back(Vec2d(v->x(), v->y())); //first one
+ StrokeInternal::StrokeVertexIterator previous = v;
+ ++v;
+ for (vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ if (!((fabs(v->x() - (previous)->x()) < M_EPSILON) && ((fabs(v->y() - (previous)->y()) < M_EPSILON))))
+ data.push_back(Vec2d(v->x(), v->y()));
+ previous = v;
+ }
+
+#if 0
+ Vec2d tmp;
+ bool equal = false;
+ if (data.front() == data.back()) {
+ tmp = data.back();
+ data.pop_back();
+ equal = true;
+ }
+#endif
+ // here we build the bezier curve
+ BezierCurve bcurve(data, _error);
+
+ // bad performances are here !!! // FIXME
+ vector<Vec2d> CurveVertices;
+ vector<BezierCurveSegment*>& bsegments = bcurve.segments();
+ vector<BezierCurveSegment*>::iterator s = bsegments.begin(), send;
+ vector<Vec2d>& segmentsVertices = (*s)->vertices();
+ vector<Vec2d>::iterator p, pend;
+ // first point
+ CurveVertices.push_back(segmentsVertices[0]);
+ for (send = bsegments.end(); s != send; ++s) {
+ segmentsVertices = (*s)->vertices();
+ p = segmentsVertices.begin();
+ ++p;
+ for (pend = segmentsVertices.end(); p != pend; ++p) {
+ CurveVertices.push_back((*p));
+ }
+ }
+
+#if 0
+ if (equal) {
+ if (data.back() == data.front()) {
+ vector<Vec2d>::iterator d = data.begin(), dend;
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "ending point = starting point" << endl;
+ cout << "---------------DATA----------" << endl;
+ for (dend = data.end(); d != dend; ++d) {
+ cout << d->x() << "-" << d->y() << endl;
+ }
+ cout << "--------------BEZIER RESULT----------" << endl;
+ for (d = CurveVertices.begin(), dend = CurveVertices.end(); d != dend; ++d) {
+ cout << d->x() << "-" << d->y() << endl;
+ }
+ }
+ }
+ }
+#endif
+
+ // Resample the Stroke depending on the number of vertices of the bezier curve:
+ int originalSize = CurveVertices.size();
+#if 0
+ float sampling = stroke.ComputeSampling(originalSize);
+ stroke.Resample(sampling);
+#endif
+ stroke.Resample(originalSize);
+ int newsize = stroke.strokeVerticesSize();
+ int nExtraVertex = 0;
+ if (newsize < originalSize) {
+ cerr << "Warning: unsufficient resampling" << endl;
+ }
+ else {
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Oversampling" << endl;
+ }
+#endif
+ nExtraVertex = newsize - originalSize;
+ if (nExtraVertex != 0) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Bezier Shader : Stroke " << stroke.getId() << " have not been resampled" << endl;
+ }
+ }
+ }
+
+ // assigns the new coordinates:
+ p = CurveVertices.begin();
+ vector<Vec2d>::iterator last = p;
+ int n;
+ StrokeInternal::StrokeVertexIterator it, itend;
+#if 0
+ for (; p != pend; ++n, ++p);
+#endif
+ for (n = 0, it = stroke.strokeVerticesBegin(), itend = stroke.strokeVerticesEnd(), pend = CurveVertices.end();
+ (it != itend) && (p != pend);
+ ++it, ++p, ++n)
+ {
+ it->setX(p->x());
+ it->setY(p->y());
+#if 0
+ double x = p->x();
+ double y = p->y();
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "x = " << x << "-" << "y = " << y << endl;
+ }
+#endif
+ last = p;
+ }
+ stroke.UpdateLength();
+
+ // Deal with extra vertices:
+ if (nExtraVertex == 0)
+ return 0;
+
+ // nExtraVertex should stay unassigned
+ vector<StrokeAttribute> attributes;
+ vector<StrokeVertex*> verticesToRemove;
+ for (int i = 0; i < nExtraVertex; ++i, ++it, ++n) {
+ verticesToRemove.push_back(&(*it));
+ if (it.isEnd()) {
+ // XXX Shocking! :P Shouldn't we break in this case???
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "fucked up" << endl;
+ }
+ }
+ }
+ for (it = stroke.strokeVerticesBegin(); it != itend; ++it) {
+ attributes.push_back(it->attribute());
+ }
+
+ for (vector<StrokeVertex*>::iterator vr = verticesToRemove.begin(), vrend = verticesToRemove.end();
+ vr != vrend;
+ ++vr)
+ {
+ stroke.RemoveVertex(*vr);
+ }
+
+ vector<StrokeAttribute>::iterator a = attributes.begin(), aend = attributes.end();
+ int index = 0;
+ int index1 = (int)floor((float)originalSize / 2.0);
+ int index2 = index1 + nExtraVertex;
+ for (it = stroke.strokeVerticesBegin(), itend = stroke.strokeVerticesEnd();
+ (it != itend) && (a != aend);
+ ++it)
+ {
+ (it)->setAttribute(*a);
+ if ((index <= index1) || (index > index2))
+ ++a;
+ ++index;
+ }
+ return 0;
+}
+
+int InflateShader::shade(Stroke& stroke) const
+{
+ // we're computing the curvature variance of the stroke. (Combo 5)
+ // If it's too high, forget about it
+ Functions1D::Curvature2DAngleF1D fun;
+ if (fun(stroke) < 0)
+ return -1;
+ if (fun.result > _curvatureThreshold)
+ return 0;
+
+ Functions0D::VertexOrientation2DF0D ori_fun;
+ Functions0D::Curvature2DAngleF0D curv_fun;
+ Functions1D::Normal2DF1D norm_fun;
+ Interface0DIterator it;
+ StrokeVertex *sv;
+ for (it = stroke.verticesBegin(); !it.isEnd(); ++it) {
+ if (ori_fun(it) < 0)
+ return -1;
+ Vec2f ntmp(ori_fun.result);
+ Vec2f n(ntmp.y(), -ntmp.x());
+ if (norm_fun(stroke) < 0)
+ return -1;
+ Vec2f strokeN(norm_fun.result);
+ if (n*strokeN < 0) {
+ n[0] = -n[0];
+ n[1] = -n[1];
+ }
+ sv = dynamic_cast<StrokeVertex*>(&(*it));
+ float u = sv->u();
+ float t = 4.0f * (0.25f - (u - 0.5) * (u - 0.5));
+ if (curv_fun(it) < 0)
+ return -1;
+ float curvature_coeff = (M_PI - curv_fun.result) / M_PI;
+ Vec2d newPoint(sv->x() + curvature_coeff * t * _amount * n.x(),
+ sv->y() + curvature_coeff * t * _amount * n.y());
+ sv->setPoint(newPoint[0], newPoint[1]);
+ }
+ stroke.UpdateLength();
+ return 0;
+}
+
+class CurvePiece
+{
+public:
+ StrokeInternal::StrokeVertexIterator _begin;
+ StrokeInternal::StrokeVertexIterator _last;
+ Vec2d A;
+ Vec2d B;
+ int size;
+ float _error;
+
+ CurvePiece(StrokeInternal::StrokeVertexIterator b, StrokeInternal::StrokeVertexIterator l, int iSize)
+ {
+ _begin = b;
+ _last = l;
+ A = Vec2d((_begin)->x(), (_begin)->y());
+ B = Vec2d((_last)->x(), (_last)->y());
+ size = iSize;
+ }
+
+ float error()
+ {
+ float maxE = 0.0f;
+ for (StrokeInternal::StrokeVertexIterator it = _begin; it != _last; ++it) {
+ Vec2d P(it->x(), it->y());
+ float d = GeomUtils::distPointSegment(P, A, B);
+ if (d > maxE)
+ maxE = d;
+ }
+ _error = maxE;
+ return maxE;
+ }
+
+ //! Subdivides the curve into two pieces.
+ // The first piece is this same object (modified)
+ // The second piece is returned by the method
+ CurvePiece *subdivide()
+ {
+ StrokeInternal::StrokeVertexIterator it = _begin;
+ int actualSize = (size > 1) ? size / 2 : 1;
+ for (int i = 0; i <= actualSize; ++it, ++i);
+
+ CurvePiece *second = new CurvePiece(it, _last, size - actualSize + 1);
+ size = actualSize;
+ _last = it;
+ B = Vec2d((_last)->x(), (_last)->y());
+ return second;
+ }
+};
+
+int PolygonalizationShader::shade(Stroke& stroke) const
+{
+ vector<CurvePiece*> _pieces;
+ vector<CurvePiece*> _results;
+ vector<CurvePiece*>::iterator cp, cpend;
+
+ // Compute first approx:
+ StrokeInternal::StrokeVertexIterator a = stroke.strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator b = stroke.strokeVerticesEnd();
+ --b;
+ int size = stroke.strokeVerticesSize();
+
+ CurvePiece *piece = new CurvePiece(a, b, size);
+ _pieces.push_back(piece);
+
+ while (!_pieces.empty()) {
+ piece = _pieces.back();
+ _pieces.pop_back();
+ if (piece->error() > _error) {
+ CurvePiece *second = piece->subdivide();
+ _pieces.push_back(second);
+ _pieces.push_back(piece);
+ }
+ else {
+ _results.push_back(piece);
+ }
+ }
+
+ // actually modify the geometry for each piece:
+ for (cp = _results.begin(), cpend = _results.end(); cp != cpend; ++cp) {
+ a = (*cp)->_begin;
+ b = (*cp)->_last;
+ Vec2d u = (*cp)->B - (*cp)->A;
+ Vec2d n(u[1], -u[0]);
+ n.normalize();
+ //Vec2d n(0, 0);
+ float offset = ((*cp)->_error);
+ StrokeInternal::StrokeVertexIterator v;
+ for (v = a; v != b; ++v) {
+ v->setPoint((*cp)->A.x() + v->u() * u.x() + n.x() * offset,
+ (*cp)->A.y() + v->u() * u.y() + n.y() * offset);
+ }
+#if 0
+ u.normalize();
+ (*a)->setPoint((*a)->x() - u.x() * 10, (*a)->y() - u.y() * 10);
+#endif
+ }
+ stroke.UpdateLength();
+
+ // delete stuff
+ for (cp = _results.begin(), cpend = _results.end(); cp != cpend; ++cp) {
+ delete (*cp);
+ }
+ _results.clear();
+ return 0;
+}
+
+int GuidingLinesShader::shade(Stroke& stroke) const
+{
+ Functions1D::Normal2DF1D norm_fun;
+ StrokeInternal::StrokeVertexIterator a = stroke.strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator b = stroke.strokeVerticesEnd();
+ --b;
+ int size = stroke.strokeVerticesSize();
+ CurvePiece piece(a, b, size);
+
+ Vec2d u = piece.B - piece.A;
+ Vec2f n(u[1], -u[0]);
+ n.normalize();
+ if (norm_fun(stroke) < 0)
+ return -1;
+ Vec2f strokeN(norm_fun.result);
+ if (n * strokeN < 0) {
+ n[0] = -n[0];
+ n[1] = -n[1];
+ }
+ float offset = (piece.error()) / 2.0f * _offset;
+ StrokeInternal::StrokeVertexIterator v, vend;
+ for (v = a, vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ v->setPoint(piece.A.x() + v->u() * u.x() + n.x() * offset,
+ piece.A.y() + v->u() * u.y() + n.y() * offset);
+ }
+ stroke.UpdateLength();
+ return 0;
+}
+
+/////////////////////////////////////////
+//
+// Tip Remover
+//
+/////////////////////////////////////////
+
+
+TipRemoverShader::TipRemoverShader(real tipLength) : StrokeShader()
+{
+ _tipLength = tipLength;
+}
+
+int TipRemoverShader::shade(Stroke& stroke) const
+{
+ int originalSize = stroke.strokeVerticesSize();
+
+ if (originalSize < 4)
+ return 0;
+
+ StrokeInternal::StrokeVertexIterator v, vend;
+ vector<StrokeVertex*> verticesToRemove;
+ vector<StrokeAttribute> oldAttributes;
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
+ if ((v->curvilinearAbscissa() < _tipLength) || (v->strokeLength() - v->curvilinearAbscissa() < _tipLength)) {
+ verticesToRemove.push_back(&(*v));
+ }
+ oldAttributes.push_back(v->attribute());
+ }
+
+ if (originalSize - verticesToRemove.size() < 2)
+ return 0;
+
+ vector<StrokeVertex*>::iterator sv, svend;
+ for (sv = verticesToRemove.begin(), svend = verticesToRemove.end(); sv != svend; ++sv) {
+ stroke.RemoveVertex((*sv));
+ }
+
+ // Resample so that our new stroke have the same number of vertices than before
+ stroke.Resample(originalSize);
+
+ if ((int)stroke.strokeVerticesSize() != originalSize) //soc
+ cerr << "Warning: resampling problem" << endl;
+
+ // assign old attributes to new stroke vertices:
+ vector<StrokeAttribute>::iterator a = oldAttributes.begin(), aend = oldAttributes.end();
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "-----------------------------------------------" << endl;
+ }
+#endif
+ for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd();
+ (v != vend) && (a != aend);
+ ++v, ++a)
+ {
+ v->setAttribute(*a);
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "thickness = " << (*a).getThickness()[0] << "-" << (*a).getThickness()[1] << endl;
+ }
+#endif
+ }
+ // we're done!
+ return 0;
+}
+
+int streamShader::shade(Stroke& stroke) const
+{
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << stroke << endl;
+ }
+ return 0;
+}
+
+int fstreamShader::shade(Stroke& stroke) const
+{
+ _stream << stroke << endl;
+ return 0;
+}
+
+} // end of namespace StrokeShaders
diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h
new file mode 100644
index 00000000000..58647861390
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h
@@ -0,0 +1,902 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_BASIC_STROKE_SHADERS_H__
+#define __FREESTYLE_BASIC_STROKE_SHADERS_H__
+
+/** \file blender/freestyle/intern/stroke/BasicStrokeShaders.h
+ * \ingroup freestyle
+ * \brief Class gathering basic stroke shaders
+ * \author Stephane Grabli
+ * \date 17/12/2002
+ */
+
+#include <fstream>
+
+#include "Stroke.h"
+#include "StrokeShader.h"
+
+#include "../geometry/Bezier.h"
+#include "../geometry/Geom.h"
+
+using namespace std;
+using namespace Geometry;
+
+namespace StrokeShaders {
+
+//
+// Thickness modifiers
+//
+//////////////////////////////////////////////////////
+
+/*! [ Thickness Shader ].
+ * Assigns an absolute constant thickness to every vertices of the Stroke.
+ */
+class LIB_STROKE_EXPORT ConstantThicknessShader : public StrokeShader
+{
+public:
+ /*! Builds the shader.
+ * \param thickness
+ * The thickness that must be assigned to the stroke.
+ */
+ ConstantThicknessShader(float thickness) : StrokeShader()
+ {
+ _thickness = thickness;
+ }
+
+ /*! Destructor. */
+ virtual ~ConstantThicknessShader() {}
+
+ /*! Returns the string "ConstantThicknessShader".*/
+ virtual string getName() const
+ {
+ return "ConstantThicknessShader";
+ }
+
+ /*! The shading method. */
+ virtual int shade(Stroke& stroke) const;
+
+private:
+ float _thickness;
+};
+
+/* [ Thickness Shader ].
+ * Assigns an absolute constant external thickness to every vertices of the Stroke. The external thickness of a point
+ * is its thickness from the point to the strip border in the direction pointing outside the object the
+ * Stroke delimitates.
+ */
+class LIB_STROKE_EXPORT ConstantExternThicknessShader : public StrokeShader
+{
+public:
+ ConstantExternThicknessShader(float thickness) : StrokeShader()
+ {
+ _thickness = thickness;
+ }
+
+ virtual ~ConstantExternThicknessShader() {}
+
+ virtual string getName() const
+ {
+ return "ConstantExternThicknessShader";
+ }
+
+ virtual int shade(Stroke& stroke) const;
+
+private:
+ float _thickness;
+};
+
+/*! [ Thickness Shader ].
+ * Assigns thicknesses values such as the thickness increases from a thickness value A to a thickness value B between
+ * the first vertex to the midpoint vertex and then decreases from B to a A between this midpoint vertex
+ * and the last vertex.
+ * The thickness is linearly interpolated from A to B.
+ */
+class LIB_STROKE_EXPORT IncreasingThicknessShader : public StrokeShader
+{
+public:
+ /*! Builds the shader.
+ * \param iThicknessMin
+ * The first thickness value.
+ * \param iThicknessMax
+ * The second thickness value.
+ */
+ IncreasingThicknessShader(float iThicknessMin, float iThicknessMax) : StrokeShader()
+ {
+ _ThicknessMin = iThicknessMin;
+ _ThicknessMax = iThicknessMax;
+ }
+
+ /*! Destructor.*/
+ virtual ~IncreasingThicknessShader() {}
+
+ virtual string getName() const
+ {
+ return "IncreasingThicknessShader";
+ }
+
+ /*! The shading method. */
+ virtual int shade(Stroke& stroke) const;
+
+private:
+ float _ThicknessMin;
+ float _ThicknessMax;
+};
+
+/*! [ Thickness shader ].
+ * Same as previous but here we allow the user to control the ratio thickness/length so that we don't get
+ * fat short lines
+ */
+class LIB_STROKE_EXPORT ConstrainedIncreasingThicknessShader : public StrokeShader
+{
+private:
+ float _ThicknessMin;
+ float _ThicknessMax;
+ float _ratio;
+
+public:
+ /*! Builds the shader.
+ * \param iThicknessMin
+ * The first thickness value.
+ * \param iThicknessMax
+ * The second thickness value.
+ * \param iRatio
+ * The ration thickness/length we don't want to exceed.
+ */
+ ConstrainedIncreasingThicknessShader(float iThicknessMin, float iThicknessMax, float iRatio) : StrokeShader()
+ {
+ _ThicknessMin = iThicknessMin;
+ _ThicknessMax = iThicknessMax;
+ _ratio = iRatio;
+ }
+
+ /*! Destructor.*/
+ virtual ~ConstrainedIncreasingThicknessShader() {}
+
+ virtual string getName() const
+ {
+ return "ConstrainedIncreasingThicknessShader";
+ }
+
+ /*! The shading method. */
+ virtual int shade(Stroke& stroke) const;
+};
+
+/* [ Thickness Shader ].
+ * Modifys the thickness in a relative way depending on its length.
+ */
+class LIB_STROKE_EXPORT LengthDependingThicknessShader : public StrokeShader
+{
+private:
+ float _minThickness;
+ float _maxThickness;
+ // We divide the strokes in 4 categories:
+ // l > 300
+ // 100 < l < 300
+ // 50 < l < 100
+ // l < 50
+
+public:
+ LengthDependingThicknessShader(float iMinThickness, float iMaxThickness) : StrokeShader()
+ {
+ _minThickness = iMinThickness;
+ _maxThickness = iMaxThickness;
+ }
+
+ virtual ~LengthDependingThicknessShader() {}
+
+ virtual string getName() const
+ {
+ return "LengthDependingThicknessShader";
+ }
+
+ virtual int shade(Stroke& stroke) const;
+};
+
+/*! [ Thickness Shader ].
+* Applys a pattern (texture) to vary thickness.
+* The new thicknesses are the result of the multiplication
+* of the pattern and the original thickness
+*/
+class LIB_STROKE_EXPORT ThicknessVariationPatternShader : public StrokeShader
+{
+public:
+ /*! Builds the shader.
+ * \param pattern_name
+ * The texture file name.
+ * \param iMinThickness
+ * The minimum thickness we don't want to exceed.
+ * \param iMaxThickness
+ * The maximum thickness we don't want to exceed.
+ * \param stretch
+ * Tells whether the pattern texture must be stretched or repeted to fit the stroke.
+ */
+ ThicknessVariationPatternShader(const string pattern_name, float iMinThickness = 1.0f, float iMaxThickness = 5.0f,
+ bool stretch = true);
+
+ /*! Destructor.*/
+ virtual ~ThicknessVariationPatternShader()
+ {
+ if (0 != _aThickness) {
+ delete[] _aThickness;
+ _aThickness = 0;
+ }
+ }
+
+ virtual string getName() const
+ {
+ return "ThicknessVariationPatternShader";
+ }
+
+ /*! The shading method. */
+ virtual int shade(Stroke& stroke) const;
+
+private:
+ float *_aThickness; // array of thickness values, in % of the max (i.e comprised between 0 and 1)
+ unsigned _size;
+ float _minThickness;
+ float _maxThickness;
+ bool _stretch;
+};
+
+/*! [ Thickness Shader ].
+ * Adds some noise to the stroke thickness.
+ * \see \htmlonly <a href=noise/noise.html>noise/noise.html</a>\endhtmlonly
+ */
+class LIB_STROKE_EXPORT ThicknessNoiseShader : public StrokeShader
+{
+private:
+ float _amplitude;
+ float _scale;
+
+public:
+ ThicknessNoiseShader();
+
+ /*! Builds a Thickness Noise Shader
+ * \param iAmplitude
+ * The amplitude of the noise signal
+ * \param iPeriod
+ * The period of the noise signal
+ */
+ ThicknessNoiseShader(float iAmplitude, float iPeriod);
+
+ virtual string getName() const
+ {
+ return "ThicknessNoiseShader";
+ }
+
+ /*! The shading method. */
+ virtual int shade(Stroke& stroke) const;
+};
+
+
+//
+// Color shaders
+//
+/////////////////////////////////////////////////////////
+/*! [ Color Shader ].
+ * Assigns a constant color to every vertices of the Stroke.
+ */
+class LIB_STROKE_EXPORT ConstantColorShader : public StrokeShader
+{
+public:
+ /*! Builds the shader from a user-specified color.
+ * \param iR
+ * The red component
+ * \param iG
+ * The green component
+ * \param iB
+ * The blue component
+ * \param iAlpha
+ * The alpha value
+ */
+ ConstantColorShader(float iR, float iG, float iB, float iAlpha = 1.0f) : StrokeShader()
+ {
+ _color[0] = iR;
+ _color[1] = iG;
+ _color[2] = iB;
+ _color[3] = iAlpha;
+ }
+
+ virtual string getName() const
+ {
+ return "ConstantColorShader";
+ }
+
+ /*! The shading method. */
+ virtual int shade(Stroke& stroke) const;
+
+private:
+ float _color[4];
+};
+
+/*! [ Color Shader ].
+ * Assigns a varying color to the stroke.
+ * The user specifies 2 colors A and B. The stroke color will change linearly from A to B between the
+ * first and the last vertex.
+ */
+class LIB_STROKE_EXPORT IncreasingColorShader : public StrokeShader
+{
+private:
+ float _colorMin[4];
+ float _colorMax[4];
+
+public:
+ /*! Builds the shader from 2 user-specified colors.
+ * \param iRm
+ * The first color red component
+ * \param iGm
+ * The first color green component
+ * \param iBm
+ * The first color blue component
+ * \param iAlpham
+ * The first color alpha value
+ * \param iRM
+ * The second color red component
+ * \param iGM
+ * The second color green component
+ * \param iBM
+ * The second color blue component
+ * \param iAlphaM
+ * The second color alpha value
+ */
+ IncreasingColorShader(float iRm, float iGm, float iBm, float iAlpham,
+ float iRM, float iGM, float iBM, float iAlphaM)
+ : StrokeShader()
+ {
+ _colorMin[0] = iRm;
+ _colorMin[1] = iGm;
+ _colorMin[2] = iBm;
+ _colorMin[3] = iAlpham;
+
+ _colorMax[0] = iRM;
+ _colorMax[1] = iGM;
+ _colorMax[2] = iBM;
+ _colorMax[3] = iAlphaM;
+ }
+
+ virtual string getName() const
+ {
+ return "IncreasingColorShader";
+ }
+
+ /*! The shading method. */
+ virtual int shade(Stroke& stroke) const;
+};
+
+/*! [ Color Shader ].
+ * Applys a pattern to vary original color.
+ * The new color is the result of the multiplication of the pattern and the original color
+ */
+class LIB_STROKE_EXPORT ColorVariationPatternShader : public StrokeShader
+{
+public:
+ /*! Builds the shader from the pattern texture file name.
+ * \param pattern_name
+ * The file name of the texture file to use as pattern
+ * \param stretch
+ * Tells whether the texture must be strecthed or repeted to fit the stroke.
+ */
+ ColorVariationPatternShader(const string pattern_name, bool stretch = true);
+
+ /*! Destructor */
+ virtual ~ColorVariationPatternShader()
+ {
+ if (0 != _aVariation) {
+ delete[] _aVariation;
+ _aVariation = 0;
+ }
+ }
+
+ virtual string getName() const
+ {
+ return "ColorVariationPatternShader";
+ }
+
+ /*! The shading method. */
+ virtual int shade(Stroke& stroke) const;
+
+private:
+ float *_aVariation; // array of coef values, in % of the max (i.e comprised between 0 and 1)
+ unsigned _size;
+ bool _stretch;
+};
+
+/* [ Color Shader ].
+ * Assigns a color to the stroke depending on the material of the shape to which ot belongs to. (Disney shader)
+ */
+class LIB_STROKE_EXPORT MaterialColorShader : public StrokeShader
+{
+private:
+ float _coefficient;
+
+public:
+ MaterialColorShader(float coeff = 1.0f) : StrokeShader()
+ {
+ _coefficient = coeff;
+ }
+
+ virtual string getName() const
+ {
+ return "MaterialColorShader";
+ }
+
+ virtual int shade(Stroke& stroke) const;
+};
+
+class LIB_STROKE_EXPORT CalligraphicColorShader : public StrokeShader
+{
+private:
+ int _textureId;
+ Vec2d _orientation;
+
+public:
+ CalligraphicColorShader(const Vec2d &iOrientation) : StrokeShader()
+ {
+ _orientation = iOrientation;
+ _orientation.normalize();
+ }
+
+ virtual string getName() const
+ {
+ return "CalligraphicColorShader";
+ }
+
+ virtual int shade(Stroke& stroke) const;
+};
+
+/*! [ Color Shader ].
+ * Shader to add noise to the stroke colors.
+ */
+class LIB_STROKE_EXPORT ColorNoiseShader : public StrokeShader
+{
+private:
+ float _amplitude;
+ float _scale;
+
+public:
+ ColorNoiseShader();
+
+ /*! Builds a Color Noise Shader
+ * \param iAmplitude
+ * The amplitude of the noise signal
+ * \param iPeriod
+ * The period of the noise signal
+ */
+ ColorNoiseShader(float iAmplitude, float iPeriod);
+
+ virtual string getName() const
+ {
+ return "ColorNoiseShader";
+ }
+
+ /*! The shading method. */
+ virtual int shade(Stroke& stroke) const;
+};
+
+//
+// Texture Shaders
+//
+///////////////////////////////////////////////////////////////////////////////
+/*! [ Texture Shader ].
+* Assigns a texture to the stroke in order to simulate
+* its marks system. This shader takes as input an integer value
+* telling which texture and blending mode to use among a set of
+* predefined textures.
+* Here are the different presets:
+* 0) -> /brushes/charcoalAlpha.bmp, HUMID_MEDIUM
+* 1) -> /brushes/washbrushAlpha.bmp, HUMID_MEDIUM
+* 2) -> /brushes/oil.bmp, HUMID_MEDIUM
+* 3) -> /brushes/oilnoblend.bmp, HUMID_MEDIUM
+* 4) -> /brushes/charcoalAlpha.bmp, DRY_MEDIUM
+* 5) -> /brushes/washbrushAlpha.bmp, DRY_MEDIUM
+* 6) -> /brushes/opaqueDryBrushAlpha.bmp, OPAQUE_MEDIUM
+* 7) -> /brushes/opaqueBrushAlpha.bmp, Stroke::OPAQUE_MEDIUM
+* Any other value will lead to the following preset:
+* default) -> /brushes/smoothAlpha.bmp, OPAQUE_MEDIUM.
+*/
+class LIB_STROKE_EXPORT TextureAssignerShader : public StrokeShader // FIXME
+{
+private:
+ int _textureId;
+
+public:
+ /*! Builds the shader.
+ * \param id
+ * The number of the preset to use.
+ */
+ TextureAssignerShader(int id) : StrokeShader()
+ {
+ _textureId = id;
+ }
+
+ virtual string getName() const
+ {
+ return "TextureAssignerShader";
+ }
+
+ /*! The shading method */
+ virtual int shade(Stroke& stroke) const;
+};
+
+/*! [ Texture Shader ].
+* Assigns a texture and a blending mode to the stroke
+* in order to simulate its marks system.
+*/
+class LIB_STROKE_EXPORT StrokeTextureShader : public StrokeShader
+{
+private:
+ string _texturePath;
+ Stroke::MediumType _mediumType;
+ bool _tips; // 0 or 1
+
+public:
+ /*! Builds the shader from the texture file name and the blending mode to use.
+ * \param textureFile
+ * The the texture file name.
+ * \attention The textures must be placed in the $FREESTYLE_DIR/data/textures/brushes directory.
+ * \param mediumType
+ * The medium type and therefore, the blending mode that must be used for the rendering of this stroke.
+ * \param iTips
+ * Tells whether the texture includes tips or not.
+ * If it is the case, the texture image must respect the following format:
+ * \verbatim
+ * __________
+ * | |
+ * | A |
+ * |__________|
+ * | | |
+ * | B | C |
+ * |_____|____|
+ *
+ * \endverbatim
+ * - A : The stroke's corpus texture
+ * - B : The stroke's left extremity texture
+ * - C : The stroke's right extremity texture
+ */
+ StrokeTextureShader(const string textureFile, Stroke::MediumType mediumType = Stroke::OPAQUE_MEDIUM,
+ bool iTips = false)
+ : StrokeShader()
+ {
+ _texturePath = textureFile;
+ _mediumType = mediumType;
+ _tips = iTips;
+ }
+
+ virtual string getName() const
+ {
+ return "StrokeTextureShader";
+ }
+
+ /*! The shading method */
+ virtual int shade(Stroke& stroke) const;
+};
+
+
+//
+// Geometry Shaders
+//
+///////////////////////////////////////////////////////////////////////////////
+/*! [ Geometry Shader ].
+ * Stretches the stroke at its two extremities and following the respective directions: v(1)v(0) and v(n-1)v(n).
+ */
+class LIB_STROKE_EXPORT BackboneStretcherShader : public StrokeShader
+{
+private:
+ float _amount;
+
+public:
+ /*! Builds the shader.
+ * \param iAmount
+ * The stretching amount value.
+ */
+ BackboneStretcherShader(float iAmount = 2.0f) : StrokeShader()
+ {
+ _amount = iAmount;
+ }
+
+ virtual string getName() const
+ {
+ return "BackboneStretcherShader";
+ }
+
+ /*! The shading method */
+ virtual int shade(Stroke& stroke) const;
+};
+
+/*! [ Geometry Shader. ]
+ * Resamples the stroke.
+ * @see Stroke::Resample(float).
+ */
+class LIB_STROKE_EXPORT SamplingShader: public StrokeShader
+{
+private:
+ float _sampling;
+
+public:
+ /*! Builds the shader.
+ * \param sampling
+ * The sampling to use for the stroke resampling
+ */
+ SamplingShader(float sampling) : StrokeShader()
+ {
+ _sampling = sampling;
+ }
+
+ virtual string getName() const
+ {
+ return "SamplingShader";
+ }
+
+ /*! The shading method */
+ virtual int shade(Stroke& stroke) const;
+};
+
+
+class LIB_STROKE_EXPORT ExternalContourStretcherShader : public StrokeShader
+{
+private:
+ float _amount;
+
+public:
+ ExternalContourStretcherShader(float iAmount = 2.0f) : StrokeShader()
+ {
+ _amount = iAmount;
+ }
+
+ virtual string getName() const
+ {
+ return "ExternalContourStretcherShader";
+ }
+
+ virtual int shade(Stroke& stroke) const;
+};
+
+// B-Spline stroke shader
+class LIB_STROKE_EXPORT BSplineShader: public StrokeShader
+{
+public:
+ BSplineShader() : StrokeShader() {}
+
+ virtual string getName() const
+ {
+ return "BSplineShader";
+ }
+
+ virtual int shade(Stroke& stroke) const;
+};
+
+
+// Bezier curve stroke shader
+/*! [ Geometry Shader ].
+ * Transforms the stroke backbone geometry so that it corresponds to a Bezier Curve approximation of the
+ * original backbone geometry.
+ * @see \htmlonly <a href=bezier/bezier.html>bezier/bezier.html</a> \endhtmlonly
+ */
+class LIB_STROKE_EXPORT BezierCurveShader : public StrokeShader
+{
+private:
+ float _error;
+
+public:
+ /*! Builds the shader.
+ * \param error
+ * The error we're allowing for the approximation.
+ * This error is the max distance allowed between the new curve and the original geometry.
+ */
+ BezierCurveShader(float error = 4.0) : StrokeShader()
+ {
+ _error = error;
+ }
+
+ virtual string getName() const
+ {
+ return "BezierCurveShader";
+ }
+
+ /*! The shading method */
+ virtual int shade(Stroke& stroke) const;
+};
+
+/* Shader to inflate the curves. It keeps the extreme points positions and moves the other ones along the 2D normal.
+ * The displacement value is proportional to the 2d curvature at the considered point (the higher the curvature,
+ * the smaller the displacement) and to a value specified by the user.
+ */
+class LIB_STROKE_EXPORT InflateShader : public StrokeShader
+{
+private:
+ float _amount;
+ float _curvatureThreshold;
+
+public:
+ /*! Builds an inflate shader
+ * \param iAmount
+ * A multiplicative coefficient that acts on the amount and direction of displacement
+ * \param iThreshold
+ * The curves having a 2d curvature > iThreshold at one of their points is not inflated
+ */
+ InflateShader(float iAmount, float iThreshold) : StrokeShader()
+ {
+ _amount = iAmount;
+ _curvatureThreshold = iThreshold;
+ }
+
+ virtual string getName() const
+ {
+ return "InflateShader";
+ }
+
+ /*! The shading method */
+ virtual int shade(Stroke& stroke) const;
+};
+
+/*! [ Geometry Shader ].
+ * Shader to modify the Stroke geometry so that it looks more "polygonal".
+ * The basic idea is to start from the minimal stroke approximation consisting in a line joining the first vertex
+ * to the last one and to subdivide using the original stroke vertices until a certain error is reached.
+ */
+class LIB_STROKE_EXPORT PolygonalizationShader : public StrokeShader
+{
+private:
+ float _error;
+
+public:
+ /*! Builds the shader.
+ * \param iError
+ * The error we want our polygonal approximation to have with respect to the original geometry.
+ * The smaller, the closer the new stroke to the orinal one.
+ * This error corresponds to the maximum distance between the new stroke and the old one.
+ */
+ PolygonalizationShader(float iError) : StrokeShader()
+ {
+ _error = iError;
+ }
+
+ virtual string getName() const
+ {
+ return "PolygonalizationShader";
+ }
+
+ /*! The shading method */
+ virtual int shade(Stroke& stroke) const;
+};
+
+
+/*! [ Geometry Shader ].
+ * Shader to modify the Stroke geometry so that it corresponds to its main direction line.
+ * This shader must be used together with the splitting operator using the curvature criterion.
+ * Indeed, the precision of the approximation will depend on the size of the stroke's pieces.
+ * The bigger the pieces, the rougher the approximation.
+ */
+class LIB_STROKE_EXPORT GuidingLinesShader : public StrokeShader
+{
+private:
+ float _offset;
+
+public:
+ /*! Builds a Guiding Lines shader
+ * \param iOffset
+ * The line that replaces the stroke is initially in the middle of the initial stroke "bbox".
+ * iOffset is the value of the displacement which is applied to this line along its normal.
+ */
+ GuidingLinesShader(float iOffset) : StrokeShader()
+ {
+ _offset = iOffset;
+ }
+
+ virtual string getName() const
+ {
+ return "GuidingLinesShader";
+ }
+
+ /*! The shading method */
+ virtual int shade(Stroke& stroke) const;
+};
+
+/*! [ Geometry Shader ].
+ * Removes the stroke's extremities.
+ */
+class LIB_STROKE_EXPORT TipRemoverShader : public StrokeShader
+{
+public:
+ /*! Builds the shader.
+ * \param tipLength
+ * The length of the piece of stroke we want to remove at each extremity.
+ */
+ TipRemoverShader (real tipLength);
+
+ /*! Destructor. */
+ virtual ~TipRemoverShader () {}
+
+ /*! The shading method */
+ virtual string getName() const
+ {
+ return "TipRemoverShader";
+ }
+
+ virtual int shade(Stroke &stroke) const;
+
+protected:
+ real _tipLength;
+};
+
+/*! [ output Shader ].
+ * streams the Stroke
+ */
+class LIB_STROKE_EXPORT streamShader : public StrokeShader
+{
+public:
+ /*! Destructor. */
+ virtual ~streamShader() {}
+
+ /*! Returns the string "streamShader".*/
+ virtual string getName() const
+ {
+ return "streamShader";
+ }
+
+ /*! The shading method. */
+ virtual int shade(Stroke& stroke) const;
+};
+
+/*! [ output Shader ].
+ * streams the Stroke in a file
+ */
+class LIB_STROKE_EXPORT fstreamShader : public StrokeShader
+{
+protected:
+ mutable ofstream _stream;
+
+public:
+ /*! Builds the shader from the output file name */
+ fstreamShader(const char *iFileName) : StrokeShader()
+ {
+ _stream .open(iFileName);
+ if (!_stream.is_open()) {
+ cerr << "couldn't open file " << iFileName << endl;
+ }
+ }
+
+ /*! Destructor. */
+ virtual ~fstreamShader()
+ {
+ _stream.close();
+ }
+
+ /*! Returns the string "fstreamShader".*/
+ virtual string getName() const
+ {
+ return "fstreamShader";
+ }
+
+ /*! The shading method. */
+ virtual int shade(Stroke& stroke) const;
+};
+
+} // end of namespace StrokeShaders
+
+#endif // __FREESTYLE_BASIC_STROKE_SHADERS_H__
diff --git a/source/blender/freestyle/intern/stroke/Canvas.cpp b/source/blender/freestyle/intern/stroke/Canvas.cpp
new file mode 100644
index 00000000000..4427192a7b0
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Canvas.cpp
@@ -0,0 +1,477 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/Canvas.cpp
+ * \ingroup freestyle
+ * \brief Class to define a canvas designed to draw style modules
+ * \author Stephane Grabli
+ * \date 20/10/2002
+ */
+
+#include <sstream>
+#include <vector>
+
+#include "Canvas.h"
+#include "StrokeRenderer.h"
+#include "StyleModule.h"
+
+#include "../image/Image.h"
+#include "../image/GaussianFilter.h"
+#include "../image/ImagePyramid.h"
+
+#include "../system/FreestyleConfig.h"
+#include "../system/TimeStamp.h"
+#include "../system/PseudoNoise.h"
+
+#include "../view_map/SteerableViewMap.h"
+
+#include "BKE_global.h"
+
+//soc #include <qimage.h>
+//soc #include <QString>
+
+extern "C" {
+# include "IMB_imbuf.h"
+# include "IMB_imbuf_types.h"
+}
+
+using namespace std;
+
+LIB_STROKE_EXPORT
+Canvas *Canvas::_pInstance = 0;
+
+LIB_STROKE_EXPORT
+const char *Canvas::_MapsPath = 0;
+
+Canvas::Canvas()
+{
+ _SelectedFEdge = 0;
+ _pInstance = this;
+ PseudoNoise::init(42);
+ _Renderer = 0;
+ _current_sm = NULL;
+ _steerableViewMap = new SteerableViewMap(NB_STEERABLE_VIEWMAP - 1);
+ _basic = false;
+}
+
+Canvas::Canvas(const Canvas& iBrother)
+{
+ _SelectedFEdge = iBrother._SelectedFEdge;
+ _pInstance = this;
+ PseudoNoise::init(42);
+ _Renderer = iBrother._Renderer;
+ _current_sm = iBrother._current_sm;
+ _steerableViewMap = new SteerableViewMap(*(iBrother._steerableViewMap));
+ _basic = iBrother._basic;
+}
+
+Canvas::~Canvas()
+{
+ _pInstance = 0;
+
+ Clear();
+ if (_Renderer) {
+ delete _Renderer;
+ _Renderer = 0;
+ }
+ // FIXME: think about an easy control for the maps memory management...
+ if (!_maps.empty()) {
+ for (mapsMap::iterator m = _maps.begin(), mend = _maps.end(); m != mend; ++m) {
+ delete ((*m).second);
+ }
+ _maps.clear();
+ }
+ if (_steerableViewMap)
+ delete _steerableViewMap;
+}
+
+void Canvas::preDraw() {}
+
+void Canvas::Draw()
+{
+ if (_StyleModules.empty())
+ return;
+ preDraw();
+ TimeStamp *timestamp = TimeStamp::instance();
+
+ for (unsigned int i = 0; i < _StyleModules.size(); ++i) {
+ _current_sm = _StyleModules[i];
+
+ if (i < _Layers.size() && _Layers[i])
+ delete _Layers[i];
+
+ _Layers[i] = _StyleModules[i]->execute();
+ if (!_Layers[i])
+ continue;
+
+ stroke_count += _Layers[i]->strokes_size();
+
+ timestamp->increment();
+ }
+ postDraw();
+}
+
+void Canvas::postDraw()
+{
+ update();
+}
+
+
+void Canvas::Clear()
+{
+ if (!_Layers.empty()) {
+ for (deque<StrokeLayer*>::iterator sl = _Layers.begin(), slend = _Layers.end(); sl != slend; ++sl) {
+ if (*sl)
+ delete (*sl);
+ }
+ _Layers.clear();
+ }
+
+ if (!_StyleModules.empty()) {
+ for (deque<StyleModule*>::iterator s = _StyleModules.begin(), send = _StyleModules.end(); s != send; ++s) {
+ if (*s)
+ delete (*s);
+ }
+ _StyleModules.clear();
+ }
+ if (_steerableViewMap)
+ _steerableViewMap->Reset();
+
+ stroke_count = 0;
+}
+
+void Canvas::Erase()
+{
+ if (!_Layers.empty()) {
+ for (deque<StrokeLayer*>::iterator sl = _Layers.begin(), slend = _Layers.end(); sl != slend; ++sl) {
+ if (*sl)
+ (*sl)->clear();
+ }
+ }
+ if (_steerableViewMap)
+ _steerableViewMap->Reset();
+ update();
+
+ stroke_count = 0;
+}
+
+void Canvas::PushBackStyleModule(StyleModule *iStyleModule)
+{
+ StrokeLayer* layer = new StrokeLayer();
+ _StyleModules.push_back(iStyleModule);
+ _Layers.push_back(layer);
+}
+
+void Canvas::InsertStyleModule(unsigned index, StyleModule *iStyleModule)
+{
+ unsigned size = _StyleModules.size();
+ StrokeLayer *layer = new StrokeLayer();
+ if ((_StyleModules.empty()) || (index == size)) {
+ _StyleModules.push_back(iStyleModule);
+ _Layers.push_back(layer);
+ return;
+ }
+ _StyleModules.insert(_StyleModules.begin() + index, iStyleModule);
+ _Layers.insert(_Layers.begin() + index, layer);
+}
+
+void Canvas::RemoveStyleModule(unsigned index)
+{
+ unsigned int i = 0;
+ if (!_StyleModules.empty()) {
+ for (deque<StyleModule*>::iterator s = _StyleModules.begin(), send = _StyleModules.end();
+ s != send;
+ ++s, ++i)
+ {
+ if (i == index) {
+ // remove shader
+ if (*s)
+ delete *s;
+ _StyleModules.erase(s);
+ break;
+ }
+ }
+ }
+
+ if (!_Layers.empty()) {
+ i = 0;
+ for (deque<StrokeLayer*>::iterator sl = _Layers.begin(), slend = _Layers.end();
+ sl != slend;
+ ++sl, ++i)
+ {
+ if (i == index) {
+ // remove layer
+ if (*sl)
+ delete *sl;
+ _Layers.erase(sl);
+ break;
+ }
+ }
+ }
+}
+
+
+void Canvas::SwapStyleModules(unsigned i1, unsigned i2)
+{
+ StyleModule *tmp;
+ tmp = _StyleModules[i1];
+ _StyleModules[i1] = _StyleModules[i2];
+ _StyleModules[i2] = tmp;
+
+ StrokeLayer *tmp2;
+ tmp2 = _Layers[i1];
+ _Layers[i1] = _Layers[i2];
+ _Layers[i2] = tmp2;
+}
+
+void Canvas::ReplaceStyleModule(unsigned index, StyleModule *iStyleModule)
+{
+ unsigned i = 0;
+ for (deque<StyleModule*>::iterator s = _StyleModules.begin(), send = _StyleModules.end(); s != send; ++s, ++i) {
+ if (i == index) {
+ if (*s)
+ delete *s;
+ *s = iStyleModule;
+ break;
+ }
+ }
+}
+
+void Canvas::setVisible(unsigned index, bool iVisible)
+{
+ _StyleModules[index]->setDisplayed(iVisible);
+}
+
+void Canvas::setModified(unsigned index, bool iMod)
+{
+ _StyleModules[index]->setModified(iMod);
+}
+
+void Canvas::resetModified(bool iMod/* = false */)
+{
+ unsigned int size = _StyleModules.size();
+ for (unsigned int i = 0; i < size; ++i)
+ setModified(i, iMod);
+}
+
+void Canvas::causalStyleModules(vector<unsigned>& vec, unsigned index)
+{
+ unsigned int size = _StyleModules.size();
+
+ for (unsigned int i = index; i < size; ++i) {
+ if (_StyleModules[i]->getCausal())
+ vec.push_back(i);
+ }
+}
+
+void Canvas::Render(const StrokeRenderer *iRenderer)
+{
+ for (unsigned int i = 0; i < _StyleModules.size(); ++i) {
+ if (!_StyleModules[i]->getDisplayed() || !_Layers[i])
+ continue;
+ _Layers[i]->Render(iRenderer);
+ }
+}
+
+void Canvas::RenderBasic(const StrokeRenderer *iRenderer)
+{
+ for (unsigned int i = 0; i < _StyleModules.size(); ++i) {
+ if (!_StyleModules[i]->getDisplayed() || !_Layers[i])
+ continue;
+ _Layers[i]->RenderBasic(iRenderer);
+ }
+}
+
+void Canvas::loadMap(const char *iFileName, const char *iMapName, unsigned int iNbLevels, float iSigma)
+{
+ // check whether this map was already loaded:
+ if (!_maps.empty()) {
+ mapsMap::iterator m = _maps.find(iMapName);
+ if (m != _maps.end()) {
+ // lazy check for size changes
+ ImagePyramid * pyramid = (*m).second;
+ if ((pyramid->width() != width()) || (pyramid->height() != height())) {
+ delete pyramid;
+ }
+ else {
+ return;
+ }
+ }
+ }
+
+ string filePath;
+ if (_MapsPath) {
+ filePath = _MapsPath;
+ filePath += iFileName;
+ }
+ else {
+ filePath = iFileName;
+ }
+
+#if 0 //soc
+ QImage *qimg;
+ QImage newMap(filePath.c_str());
+ if (newMap.isNull()) {
+ cerr << "Could not load image file " << filePath << endl;
+ return;
+ }
+ qimg = &newMap;
+#endif
+ /* OCIO_TODO: support different input color space */
+ ImBuf *qimg = IMB_loadiffname(filePath.c_str(), 0, NULL);
+ if (qimg == 0) {
+ cerr << "Could not load image file " << filePath << endl;
+ return;
+ }
+
+#if 0 // soc
+ // resize
+ QImage scaledImg;
+ if ((newMap.width() != width()) || (newMap.height() != height())) {
+ scaledImg = newMap.scaled(width(), height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ qimg = &scaledImg;
+ }
+#endif
+ ImBuf *scaledImg;
+ if ((qimg->x != width()) || (qimg->y != height())) {
+ scaledImg = IMB_dupImBuf(qimg);
+ IMB_scaleImBuf(scaledImg, width(), height());
+ }
+
+
+ // deal with color image
+#if 0
+ if (newMap->depth() != 8) {
+ int w = newMap->width();
+ int h = newMap->height();
+ QImage *tmp = new QImage(w, h, 8);
+ for (unsigned int y = 0; y < h; ++y) {
+ for (unsigned int x = 0; x < w; ++x) {
+ int c = qGray(newMap->pixel(x, y));
+ tmp->setPixel(x, y, c);
+ }
+ }
+ delete newMap;
+ newMap = tmp;
+ }
+#endif
+
+ int x, y;
+ int w = qimg->x;
+ int h = qimg->y;
+ int rowbytes = w * 4;
+ GrayImage tmp(w, h);
+ char *pix;
+
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ pix = (char*)qimg->rect + y * rowbytes + x * 4;
+ float c = (pix[0] * 11 + pix[1] * 16 + pix[2] * 5) / 32;
+ tmp.setPixel(x, y, c);
+ }
+ }
+
+#if 0
+ GrayImage blur(w, h);
+ GaussianFilter gf(4.0f);
+ //int bound = gf.getBound();
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ int c = gf.getSmoothedPixel<GrayImage>(&tmp, x, y);
+ blur.setPixel(x, y, c);
+ }
+ }
+#endif
+
+ GaussianPyramid *pyramid = new GaussianPyramid(tmp, iNbLevels, iSigma);
+ int ow = pyramid->width(0);
+ int oh = pyramid->height(0);
+ string base(iMapName); //soc
+ for (int i = 0; i < pyramid->getNumberOfLevels(); ++i) {
+ // save each image:
+#if 0
+ w = pyramid.width(i);
+ h = pyramid.height(i);
+#endif
+
+ //soc QImage qtmp(ow, oh, QImage::Format_RGB32);
+ ImBuf *qtmp = IMB_allocImBuf(ow, oh, 32, IB_rect);
+
+ //int k = (1 << i);
+ for (y = 0; y < oh; ++y) {
+ for (x = 0; x < ow; ++x) {
+ int c = pyramid->pixel(x, y, i); // 255 * pyramid->pixel(x, y, i);
+ //soc qtmp.setPixel(x, y, qRgb(c, c, c));
+ pix = (char*)qtmp->rect + y * rowbytes + x * 4;
+ pix[0] = pix [1] = pix[2] = c;
+ }
+ }
+ //soc qtmp.save(base + QString::number(i) + ".bmp", "BMP");
+ stringstream filename;
+ filename << base;
+ filename << i << ".bmp";
+ qtmp->ftype = BMP;
+ IMB_saveiff(qtmp, const_cast<char *>(filename.str().c_str()), 0);
+ }
+
+#if 0
+ QImage *qtmp = new QImage(w, h, 32);
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ int c = (int)blur.pixel(x, y);
+ qtmp->setPixel(x, y, qRgb(c, c, c));
+ }
+ }
+ delete newMap;
+ newMap = qtmp;
+#endif
+
+ _maps[iMapName] = pyramid;
+ //newMap->save("toto.bmp", "BMP");
+}
+
+float Canvas::readMapPixel(const char *iMapName, int level, int x, int y)
+{
+ if (_maps.empty()) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "readMapPixel warning: no map was loaded "<< endl;
+ }
+ return -1;
+ }
+ mapsMap::iterator m = _maps.find(iMapName);
+ if (m == _maps.end()) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "readMapPixel warning: no map was loaded with the name " << iMapName << endl;
+ }
+ return -1;
+ }
+ ImagePyramid *pyramid = (*m).second;
+ if ((x < 0) || (x >= pyramid->width()) || (y < 0) || (y >= pyramid->height()))
+ return 0;
+
+ return pyramid->pixel(x, height() - 1 - y, level);
+}
diff --git a/source/blender/freestyle/intern/stroke/Canvas.h b/source/blender/freestyle/intern/stroke/Canvas.h
new file mode 100644
index 00000000000..9931bf3c97e
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Canvas.h
@@ -0,0 +1,249 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_CANVAS_H__
+#define __FREESTYLE_CANVAS_H__
+
+/** \file blender/freestyle/intern/stroke/Canvas.h
+ * \ingroup freestyle
+ * \brief Class to define a canvas designed to draw style modules
+ * \author Stephane Grabli
+ * \date 20/10/2002
+ */
+
+#include <cstring>
+#include <deque>
+#include <map>
+#include <vector>
+
+#include "StrokeLayer.h"
+
+#include "../geometry/BBox.h"
+#include "../geometry/Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace Geometry;
+
+struct ltstr
+{
+ bool operator()(const char* s1, const char* s2) const
+ {
+ return strcmp(s1, s2) < 0;
+ }
+};
+
+class InformationMap;
+class StrokeRenderer;
+class ViewMap;
+class ViewEdge;
+class FEdge;
+class RGBImage;
+class GrayImage;
+class QImage;
+class ImagePyramid;
+class SteerableViewMap;
+class StyleModule;
+
+/*! Class to define the canvas on which strokes are drawn.
+ * It's used to store state information about the drawing.
+ */
+class LIB_STROKE_EXPORT Canvas
+{
+public:
+ /*! Returns a pointer on the Canvas instance */
+ static Canvas *getInstance()
+ {
+ return _pInstance;
+ }
+
+ typedef std::map<const char*, ImagePyramid*, ltstr> mapsMap;
+ static const int NB_STEERABLE_VIEWMAP = 5;
+
+protected:
+ static Canvas *_pInstance;
+ std::deque<StrokeLayer*> _Layers;
+ std::deque<StyleModule*> _StyleModules;
+ FEdge *_SelectedFEdge;
+
+ StrokeRenderer *_Renderer;
+ StyleModule *_current_sm;
+ mapsMap _maps;
+ static const char *_MapsPath;
+ SteerableViewMap *_steerableViewMap;
+ bool _basic;
+
+public:
+ /* Builds the Canvas */
+ Canvas();
+ /* Copy constructor */
+ Canvas(const Canvas& iBrother);
+ /* Destructor */
+ virtual ~Canvas();
+
+ /* operations that need to be done before a draw */
+ virtual void preDraw();
+
+ /* Draw the canvas using the current shader */
+ virtual void Draw();
+
+ /* operations that need to be done after a draw */
+ virtual void postDraw();
+
+ /* Renders the created strokes */
+ virtual void Render(const StrokeRenderer *iRenderer);
+ /* Basic Renders the created strokes */
+ virtual void RenderBasic(const StrokeRenderer *iRenderer);
+ /* Renders a stroke */
+ virtual void RenderStroke(Stroke *iStroke) = 0;
+
+ /* init the canvas */
+ virtual void init() = 0;
+
+ /* Clears the Canvas (shaders stack, layers stack...) */
+ void Clear();
+
+ /* Erases the layers */
+ virtual void Erase();
+
+ /* Reads a pixel area from the canvas */
+ virtual void readColorPixels(int x, int y,int w, int h, RGBImage& oImage) const = 0;
+ /* Reads a depth pixel area from the canvas */
+ virtual void readDepthPixels(int x, int y,int w, int h, GrayImage& oImage) const = 0;
+
+ /* update the canvas (display) */
+ virtual void update() = 0;
+
+ /* checks whether the canvas is empty or not */
+ bool isEmpty() const
+ {
+ return (_Layers.empty());
+ }
+
+ /* Maps management */
+ /*! Loads an image map. The map will be scaled (without preserving the ratio in order to fit the actual
+ * canvas size.).
+ * The image must be a gray values image...
+ * \param iFileName
+ * The name of the image file
+ * \param iMapName
+ * The name that will be used to access this image
+ * \param iNbLevels
+ * The number of levels in the map pyramid. (default = 4).
+ * If iNbLevels == 0, the complete pyramid is built.
+ */
+ void loadMap(const char *iFileName, const char *iMapName, unsigned iNbLevels = 4, float iSigma = 1.0f);
+
+ /*! Reads a pixel value in a map.
+ * Returns a value between 0 and 1.
+ * \param iMapName
+ * The name of the map
+ * \param level
+ * The level of the pyramid from which the pixel must be read.
+ * \param x
+ * The abscissa of the desired pixel specified in level0 coordinate system. The origin is the lower left corner.
+ * \param y
+ * The ordinate of the desired pixel specified in level0 coordinate system. The origin is the lower left corner.
+ */
+ float readMapPixel(const char *iMapName, int level, int x, int y);
+
+ /*! Sets the steerable viewmap */
+ void loadSteerableViewMap(SteerableViewMap * iSVM)
+ {
+ _steerableViewMap = iSVM;
+ }
+
+ /*! Returns the steerable VM */
+ SteerableViewMap * getSteerableViewMap()
+ {
+ return _steerableViewMap;
+ }
+
+ /*! accessors */
+ inline const FEdge *selectedFEdge() const
+ {
+ return _SelectedFEdge;
+ }
+
+ inline FEdge *selectedFEdge()
+ {
+ return _SelectedFEdge;
+ }
+
+ virtual int width() const = 0;
+ virtual int height() const = 0;
+ virtual BBox<Vec3r> scene3DBBox() const = 0;
+
+ inline const StrokeRenderer *renderer() const
+ {
+ return _Renderer;
+ }
+
+ inline StyleModule *getCurrentStyleModule()
+ {
+ return _current_sm;
+ }
+
+ virtual bool getRecordFlag() const
+ {
+ return false;
+ }
+
+ int stroke_count;
+
+ /*! modifiers */
+ inline void setSelectedFEdge(FEdge *iFEdge)
+ {
+ _SelectedFEdge = iFEdge;
+ }
+
+ /*! inserts a shader at pos index+1 */
+ void PushBackStyleModule(StyleModule *iStyleModule);
+ void InsertStyleModule(unsigned index, StyleModule *iStyleModule);
+ void RemoveStyleModule(unsigned index);
+ void SwapStyleModules(unsigned i1, unsigned i2);
+ void ReplaceStyleModule(unsigned index, StyleModule *iStyleModule);
+ void setVisible(unsigned index, bool iVisible) ;
+
+#if 0
+ inline void setDensityMap(InformationMap<RGBImage> *iMap)
+ {
+ _DensityMap = iMap;
+ }
+#endif
+
+ inline void AddLayer(StrokeLayer *iLayer)
+ {
+ _Layers.push_back(iLayer);
+ }
+
+ void resetModified(bool iMod = false);
+ void causalStyleModules(std::vector<unsigned>& vec, unsigned index = 0);
+ void setModified(unsigned index, bool b);
+};
+
+#endif // __FREESTYLE_CANVAS_H__
diff --git a/source/blender/freestyle/intern/stroke/Chain.cpp b/source/blender/freestyle/intern/stroke/Chain.cpp
new file mode 100644
index 00000000000..59cebbd5da0
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Chain.cpp
@@ -0,0 +1,156 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/Chain.h
+ * \ingroup freestyle
+ * \brief Class to define a chain of viewedges.
+ * \author Stephane Grabli
+ * \date 09/01/2003
+ */
+
+#include "Chain.h"
+
+#include "../view_map/ViewMapAdvancedIterators.h"
+#include "../view_map/ViewMapIterators.h"
+
+void Chain::push_viewedge_back(ViewEdge *iViewEdge, bool orientation)
+{
+ ViewEdge::vertex_iterator v;
+ ViewEdge::vertex_iterator vend;
+ ViewEdge::vertex_iterator vfirst;
+ Vec3r previous, current;
+ if (true == orientation) {
+ v = iViewEdge->vertices_begin();
+ vfirst = v;
+ vend = iViewEdge->vertices_end();
+ }
+ else {
+ v = iViewEdge->vertices_last();
+ vfirst = v;
+ vend = iViewEdge->vertices_end();
+ }
+
+ if (!_Vertices.empty()) {
+ previous = _Vertices.back()->point2d();
+ if (orientation)
+ ++v;
+ else
+ --v;
+ // Ensure the continuity of underlying FEdges
+ CurvePoint *cp = _Vertices.back(); // assumed to be instantiated as new CurvePoint(iSVertex, 0, 0.f);
+ SVertex *sv_first = (*vfirst);
+ FEdge *fe = _fedgeB->duplicate();
+ fe->setVertexB(sv_first);
+ fe->vertexA()->shape()->AddEdge(fe);
+ fe->vertexA()->AddFEdge(fe);
+ fe->vertexB()->AddFEdge(fe);
+ cp->setA(sv_first);
+ }
+ else {
+ previous = (*v)->point2d();
+ }
+ do {
+ current = (*v)->point2d();
+ Curve::push_vertex_back(*v);
+ //_Length += (current - previous).norm();
+ previous = current;
+ if (orientation)
+ ++v;
+ else
+ --v;
+ } while ((v != vend) && (v != vfirst));
+
+ if (v == vfirst) {
+ //Add last one:
+ current = (*v)->point2d();
+ Curve::push_vertex_back(*v);
+ //_Length += (current - previous).norm();
+ }
+
+ _fedgeB = (orientation) ? iViewEdge->fedgeB() : iViewEdge->fedgeA();
+}
+
+void Chain::push_viewedge_front(ViewEdge *iViewEdge, bool orientation)
+{
+ orientation = !orientation;
+ ViewEdge::vertex_iterator v;
+ ViewEdge::vertex_iterator vend;
+ ViewEdge::vertex_iterator vfirst;
+ Vec3r previous, current;
+ if (true == orientation) {
+ v = iViewEdge->vertices_begin();
+ vfirst = v;
+ vend = iViewEdge->vertices_end();
+ }
+ else {
+ v = iViewEdge->vertices_last();
+ vfirst = v;
+ vend = iViewEdge->vertices_end();
+ }
+
+ if (!_Vertices.empty()) {
+ previous = _Vertices.front()->point2d();
+ if (orientation)
+ ++v;
+ else
+ --v;
+ // Ensure the continuity of underlying FEdges
+ CurvePoint *cp = _Vertices.front(); // assumed to be instantiated as new CurvePoint(iSVertex, 0, 0.f);
+ SVertex *sv_last = cp->A();
+ SVertex *sv_curr = (*v);
+ FEdge *fe = (orientation) ? iViewEdge->fedgeA() : iViewEdge->fedgeB();
+ FEdge *fe2 = fe->duplicate();
+ fe2->setVertexA(sv_curr);
+ fe2->setVertexB(sv_last);
+ sv_last->AddFEdge(fe2);
+ sv_curr->AddFEdge(fe2);
+ sv_curr->shape()->AddEdge(fe2);
+ }
+ else {
+ previous = (*v)->point2d();
+ }
+ do {
+ current = (*v)->point2d();
+ Curve::push_vertex_front((*v));
+ //_Length += (current - previous).norm();
+ previous = current;
+ if (orientation)
+ ++v;
+ else
+ --v;
+ } while ((v != vend) && (v != vfirst));
+
+ if (v == vfirst) {
+ //Add last one:
+ current = (*v)->point2d();
+ Curve::push_vertex_front(*v);
+ //_Length += (current - previous).norm();
+ }
+
+ if (!_fedgeB)
+ _fedgeB = (orientation) ? iViewEdge->fedgeB() : iViewEdge->fedgeA();
+}
diff --git a/source/blender/freestyle/intern/stroke/Chain.h b/source/blender/freestyle/intern/stroke/Chain.h
new file mode 100644
index 00000000000..425761d28ef
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Chain.h
@@ -0,0 +1,116 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_CHAIN_H__
+#define __FREESTYLE_CHAIN_H__
+
+/** \file blender/freestyle/intern/stroke/Chain.h
+ * \ingroup freestyle
+ * \brief Class to define a chain of viewedges.
+ * \author Stephane Grabli
+ * \date 09/01/2003
+ */
+
+#include "Curve.h"
+
+#include "../view_map/ViewMap.h"
+
+/*! Class to represent a 1D elements issued from the chaining process.
+ * A Chain is the last step before the Stroke and is used in the Splitting and Creation processes.
+ */
+class Chain : public Curve
+{
+protected:
+ // tmp
+ Id * _splittingId;
+ FEdge *_fedgeB; // the last FEdge of the ViewEdge passed to the last call for push_viewedge_back().
+
+public:
+ /*! Defult constructor. */
+ Chain() : Curve()
+ {
+ _splittingId = 0;
+ _fedgeB = 0;
+ }
+
+ /*! Builds a chain from its Id. */
+ Chain(const Id& id) : Curve(id)
+ {
+ _splittingId = 0;
+ _fedgeB = 0;
+ }
+
+ /*! Copy Constructor */
+ Chain(const Chain& iBrother) : Curve(iBrother)
+ {
+ _splittingId = iBrother._splittingId;
+ _fedgeB = iBrother._fedgeB;
+ }
+
+ /*! Destructor. */
+ virtual ~Chain() {
+ // only the last splitted deletes this id
+ if (_splittingId) {
+ if (*_splittingId == _Id)
+ delete _splittingId;
+ }
+ }
+
+ /*! Returns the string "Chain" */
+ virtual string getExactTypeName() const
+ {
+ return "Chain";
+ }
+
+ /*! Adds a ViewEdge at the end of the chain
+ * \param iViewEdge
+ * The ViewEdge that must be added.
+ * \param orientation
+ * The orientation with which this ViewEdge must be processed.
+ */
+ void push_viewedge_back(ViewEdge *iViewEdge, bool orientation);
+
+ /*! Adds a ViewEdge at the beginning of the chain
+ * \param iViewEdge
+ * The ViewEdge that must be added.
+ * \param orientation
+ * The orientation with which this ViewEdge must be processed.
+ */
+ void push_viewedge_front(ViewEdge *iViewEdge, bool orientation);
+
+ inline void setSplittingId(Id *sid)
+ {
+ _splittingId = sid;
+ }
+
+ inline Id* getSplittingId()
+ {
+ return _splittingId;
+ }
+};
+
+#endif // __FREESTYLE_CHAIN_H__
diff --git a/source/blender/freestyle/intern/stroke/ChainingIterators.cpp b/source/blender/freestyle/intern/stroke/ChainingIterators.cpp
new file mode 100644
index 00000000000..1883e494eab
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/ChainingIterators.cpp
@@ -0,0 +1,202 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/ChainingIterators.cpp
+ * \ingroup freestyle
+ * \brief Chaining iterators
+ * \author Stephane Grabli
+ * \date 01/07/2003
+ */
+
+#include "ChainingIterators.h"
+
+#include "../system/TimeStamp.h"
+
+ViewEdge* AdjacencyIterator::operator*()
+{
+ return (*_internalIterator).first;
+}
+
+bool AdjacencyIterator::isIncoming() const
+{
+ return (*_internalIterator).second;
+}
+
+int AdjacencyIterator::increment()
+{
+ ++_internalIterator;
+ while((!_internalIterator.isEnd()) && (!isValid((*_internalIterator).first)))
+ ++_internalIterator;
+ return 0;
+}
+
+bool AdjacencyIterator::isValid(ViewEdge* edge)
+{
+ if (_restrictToSelection) {
+ if (edge->getTimeStamp() != TimeStamp::instance()->getTimeStamp())
+ return false;
+ }
+ if (_restrictToUnvisited) {
+ if (edge->getChainingTimeStamp() > TimeStamp::instance()->getTimeStamp())
+ return false;
+ }
+ return true;
+}
+
+int ChainingIterator::increment()
+{
+ _increment = true;
+ ViewVertex * vertex = getVertex();
+ if (!vertex) {
+ _edge = 0;
+ return 0;
+ }
+ AdjacencyIterator it = AdjacencyIterator(vertex, _restrictToSelection, _restrictToUnvisited);
+ if (it.isEnd()) {
+ _edge = 0;
+ return 0;
+ }
+ if (traverse(it) < 0)
+ return -1;
+ _edge = result;
+ if(_edge == 0)
+ return 0;
+ if(_edge->A() == vertex)
+ _orientation = true;
+ else
+ _orientation = false;
+ return 0;
+}
+
+int ChainingIterator::decrement()
+{
+ _increment = false;
+ ViewVertex * vertex = getVertex();
+ if (!vertex) {
+ _edge = 0;
+ return 0;
+ }
+ AdjacencyIterator it = AdjacencyIterator(vertex, _restrictToSelection, _restrictToUnvisited);
+ if (it.isEnd()) {
+ _edge = 0;
+ return 0;
+ }
+ if (traverse(it) < 0)
+ return -1;
+ _edge = result;
+ if(_edge == 0)
+ return 0;
+ if(_edge->B() == vertex)
+ _orientation = true;
+ else
+ _orientation = false;
+ return 0;
+}
+
+//
+// ChainSilhouetteIterators
+//
+///////////////////////////////////////////////////////////
+
+int ChainSilhouetteIterator::traverse(const AdjacencyIterator& ait)
+{
+ AdjacencyIterator it(ait);
+ ViewVertex* nextVertex = getVertex();
+ // we can't get a NULL nextVertex here, it was intercepted before
+ if (nextVertex->getNature() & Nature::T_VERTEX) {
+ TVertex * tvertex = (TVertex*)nextVertex;
+ ViewEdge *mate = (tvertex)->mate(getCurrentEdge());
+ while (!it.isEnd()) {
+ ViewEdge *ve = *it;
+ if (ve == mate) {
+ result = ve;
+ return 0;
+ }
+ ++it;
+ }
+ result = 0;
+ return 0;
+ }
+ if (nextVertex->getNature() & Nature::NON_T_VERTEX) {
+ //soc NonTVertex * nontvertex = (NonTVertex*)nextVertex;
+ ViewEdge * newEdge(0);
+ // we'll try to chain the edges by keeping the same nature...
+ // the preseance order is : SILHOUETTE, BORDER, CREASE, SUGGESTIVE, VALLEY, RIDGE
+ Nature::EdgeNature natures[6] = {
+ Nature::SILHOUETTE,
+ Nature::BORDER,
+ Nature::CREASE,
+ Nature::SUGGESTIVE_CONTOUR,
+ Nature::VALLEY,
+ Nature::RIDGE
+ };
+ for (unsigned int i = 0; i < 6; ++i) {
+ if (getCurrentEdge()->getNature() & natures[i]) {
+ int n = 0;
+ while (!it.isEnd()) {
+ ViewEdge *ve = *it;
+ if(ve->getNature() & natures[i]) {
+ ++n;
+ newEdge = ve;
+ }
+ ++it;
+ }
+ if (n == 1) {
+ result = newEdge;
+ }
+ else {
+ result = 0;
+ }
+ return 0;
+ }
+ }
+ }
+ result = 0;
+ return 0;
+}
+
+int ChainPredicateIterator::traverse(const AdjacencyIterator& ait)
+{
+ AdjacencyIterator it(ait);
+ // Iterates over next edges to see if one of them respects the predicate:
+ while (!it.isEnd()) {
+ ViewEdge *ve = *it;
+ if (_unary_predicate->operator()(*ve) < 0)
+ return -1;
+ if (_unary_predicate->result) {
+ if (_binary_predicate->operator()(*(getCurrentEdge()), *(ve)) < 0)
+ return -1;
+ if (_binary_predicate->result) {
+ result = ve;
+ return 0;
+ }
+ }
+ ++it;
+ }
+ result = 0;
+ return 0;
+}
diff --git a/source/blender/freestyle/intern/stroke/ChainingIterators.h b/source/blender/freestyle/intern/stroke/ChainingIterators.h
new file mode 100644
index 00000000000..66a57061ec9
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/ChainingIterators.h
@@ -0,0 +1,407 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_CHAINING_ITERATORS_H__
+#define __FREESTYLE_CHAINING_ITERATORS_H__
+
+/** \file blender/freestyle/intern/stroke/ChainingIterators.h
+ * \ingroup freestyle
+ * \brief Chaining iterators
+ * \author Stephane Grabli
+ * \date 01/07/2003
+ */
+
+#include <iostream>
+
+#include "Predicates1D.h"
+
+#include "../python/Director.h"
+
+#include "../system/Iterator.h" //soc
+
+#include "../view_map/ViewMap.h"
+#include "../view_map/ViewMapIterators.h"
+#include "../view_map/ViewMapAdvancedIterators.h"
+
+//using namespace ViewEdgeInternal;
+
+//
+// Adjacency iterator used in the chaining process
+//
+///////////////////////////////////////////////////////////
+class LIB_STROKE_EXPORT AdjacencyIterator : public Iterator
+{
+protected:
+ ViewVertexInternal::orientedViewEdgeIterator _internalIterator;
+ bool _restrictToSelection;
+ bool _restrictToUnvisited;
+
+public:
+ AdjacencyIterator()
+ {
+ _restrictToSelection = true;
+ _restrictToUnvisited = true;
+ }
+
+ AdjacencyIterator(ViewVertex *iVertex, bool iRestrictToSelection = true, bool iRestrictToUnvisited = true)
+ {
+ _restrictToSelection = iRestrictToSelection;
+ _restrictToUnvisited = iRestrictToUnvisited;
+ _internalIterator = iVertex->edgesBegin();
+ while ((!_internalIterator.isEnd()) && (!isValid((*_internalIterator).first)))
+ ++_internalIterator;
+ }
+
+ AdjacencyIterator(const AdjacencyIterator& iBrother)
+ {
+ _internalIterator = iBrother._internalIterator;
+ _restrictToSelection = iBrother._restrictToSelection;
+ _restrictToUnvisited = iBrother._restrictToUnvisited;
+ }
+
+ AdjacencyIterator& operator=(const AdjacencyIterator& iBrother)
+ {
+ _internalIterator = iBrother._internalIterator;
+ _restrictToSelection = iBrother._restrictToSelection;
+ _restrictToUnvisited = iBrother._restrictToUnvisited;
+ return *this;
+ }
+
+ virtual ~AdjacencyIterator() {}
+
+ virtual string getExactTypeName() const
+ {
+ return "AdjacencyIterator";
+ }
+
+ virtual inline bool isEnd() const
+ {
+ return _internalIterator.isEnd();
+ }
+
+ virtual inline bool isBegin() const
+ {
+ return _internalIterator.isBegin();
+ }
+
+ /*! Returns true if the current ViewEdge is is coming towards the iteration vertex. False otherwise. */
+ bool isIncoming() const;
+
+ /*! Returns a *pointer* to the pointed ViewEdge. */
+ virtual ViewEdge* operator*();
+
+ virtual ViewEdge* operator->()
+ {
+ return operator*();
+ }
+
+ virtual AdjacencyIterator& operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ virtual AdjacencyIterator operator++(int)
+ {
+ AdjacencyIterator tmp(*this);
+ increment();
+ return tmp;
+ }
+
+ virtual int increment();
+
+ virtual int decrement()
+ {
+ cerr << "Warning: method decrement() not implemented" << endl;
+ return 0;
+ }
+
+protected:
+ bool isValid(ViewEdge* edge);
+};
+
+//
+// Base class for Chaining Iterators
+//
+///////////////////////////////////////////////////////////
+
+/*! Base class for chaining iterators.
+ * This class is designed to be overloaded in order to describe chaining rules.
+ * It makes the works of chaining rules description easier.
+ * The two main methods that need to overloaded are traverse() and init().
+ * traverse() tells which ViewEdge to follow, among the adjacent ones.
+ * If you specify restriction rules (such as "Chain only ViewEdges of the selection"), they will be included
+ * in the adjacency iterator. (i.e, the adjacent iterator will only stop on "valid" edges).
+ */
+class LIB_STROKE_EXPORT ChainingIterator : public ViewEdgeInternal::ViewEdgeIterator
+{
+protected:
+ bool _restrictToSelection;
+ bool _restrictToUnvisited;
+ bool _increment; //true if we're currently incrementing, false when decrementing
+
+public:
+ ViewEdge *result;
+ PyObject *py_c_it;
+
+ /*! Builds a Chaining Iterator from the first ViewEdge used for iteration and its orientation.
+ * \param iRestrictToSelection
+ * Indicates whether to force the chaining to stay within the set of selected ViewEdges or not.
+ * \param iRestrictToUnvisited
+ * Indicates whether a ViewEdge that has already been chained must be ignored ot not.
+ * \param begin
+ * The ViewEdge from which to start the chain.
+ * \param orientation
+ * The direction to follow to explore the graph. If true, the direction indicated by the first ViewEdge is used.
+ */
+ ChainingIterator(bool iRestrictToSelection = true, bool iRestrictToUnvisited = true, ViewEdge* begin = 0,
+ bool orientation = true)
+ : ViewEdgeIterator(begin, orientation)
+ {
+ _restrictToSelection = iRestrictToSelection;
+ _restrictToUnvisited = iRestrictToUnvisited;
+ _increment = true;
+ py_c_it = 0;
+ }
+
+ /*! Copy constructor */
+ ChainingIterator(const ChainingIterator& brother)
+ : ViewEdgeIterator(brother)
+ {
+ _restrictToSelection = brother._restrictToSelection;
+ _restrictToUnvisited = brother._restrictToUnvisited;
+ _increment = brother._increment;
+ py_c_it = brother.py_c_it;
+ }
+
+ /*! Returns the string "ChainingIterator" */
+ virtual string getExactTypeName() const
+ {
+ return "ChainingIterator";
+ }
+
+ /*! Inits the iterator context.
+ * This method is called each time a new chain is started.
+ * It can be used to reset some history information that you might want to keep.
+ */
+ virtual int init()
+ {
+ return Director_BPy_ChainingIterator_init(this);
+ }
+
+ /*! This method iterates over the potential next ViewEdges and returns the one that will be followed next.
+ * returns the next ViewEdge to follow or 0 when the end of the chain is reached.
+ * \param it
+ * The iterator over the ViewEdges adjacent to the end vertex of the current ViewEdge.
+ * The Adjacency iterator reflects the restriction rules by only iterating over the valid ViewEdges.
+ */
+ virtual int traverse(const AdjacencyIterator &it)
+ {
+ return Director_BPy_ChainingIterator_traverse(this, const_cast<AdjacencyIterator &>(it));
+ }
+
+ /* accessors */
+ /*! Returns true if the orientation of the current ViewEdge corresponds to its natural orientation */
+ //inline bool getOrientation() const {}
+
+ /*! Returns the vertex which is the next crossing */
+ inline ViewVertex * getVertex()
+ {
+ if (_increment) {
+ if (_orientation) {
+ return _edge->B();
+ }
+ else {
+ return _edge->A();
+ }
+ }
+ else {
+ if (_orientation) {
+ return _edge->A();
+ }
+ else {
+ return _edge->B();
+ }
+ }
+ }
+
+ /*! Returns true if the current iteration is an incrementation */
+ inline bool isIncrementing() const
+ {
+ return _increment;
+ }
+
+ /* increments.*/
+ virtual int increment();
+ virtual int decrement();
+};
+
+//
+// Chaining iterators definitions
+//
+///////////////////////////////////////////////////////////
+
+/*! A ViewEdge Iterator used to follow ViewEdges the most naturally.
+ * For example, it will follow visible ViewEdges of same nature.
+ * As soon, as the nature or the visibility changes, the iteration stops (by setting the pointed ViewEdge to 0).
+ * In the case of an iteration over a set of ViewEdge that are both Silhouette and Crease, there will be a precedence
+ * of the silhouette over the crease criterion.
+ */
+class LIB_STROKE_EXPORT ChainSilhouetteIterator : public ChainingIterator
+{
+public:
+ /*! Builds a ChainSilhouetteIterator from the first ViewEdge used for iteration and its orientation.
+ * \param iRestrictToSelection
+ * Indicates whether to force the chaining to stay within the set of selected ViewEdges or not.
+ * \param begin
+ * The ViewEdge from where to start the iteration.
+ * \param orientation
+ * If true, we'll look for the next ViewEdge among the ViewEdges that surround the ending ViewVertex of begin.
+ * If false, we'll search over the ViewEdges surrounding the ending ViewVertex of begin.
+ */
+ ChainSilhouetteIterator(bool iRestrictToSelection = true, ViewEdge* begin = NULL, bool orientation = true)
+ : ChainingIterator(iRestrictToSelection, true, begin, orientation)
+ {
+ }
+
+ /*! Copy constructor */
+ ChainSilhouetteIterator(const ChainSilhouetteIterator& brother) : ChainingIterator(brother) {}
+
+ /*! Returns the string "ChainSilhouetteIterator" */
+ virtual string getExactTypeName() const
+ {
+ return "ChainSilhouetteIterator";
+ }
+
+ /*! This method iterates over the potential next ViewEdges and returns the one that will be followed next.
+ * When reaching the end of a chain, 0 is returned.
+ */
+ virtual int traverse(const AdjacencyIterator& it);
+
+ /*! Inits the iterator context */
+ virtual int init()
+ {
+ return 0;
+ }
+};
+
+//
+// ChainPredicateIterator
+//
+///////////////////////////////////////////////////////////
+
+/*! A "generic" user-controlled ViewEdge iterator. This iterator is in particular built from a unary predicate and
+ * a binary predicate.
+ * First, the unary predicate is evaluated for all potential next ViewEdges in order to only keep the ones respecting
+ * a certain constraint.
+ * Then, the binary predicate is evaluated on the current ViewEdge together with each ViewEdge of the previous
+ * selection. The first ViewEdge respecting both the unary predicate and the binary predicate is kept as the next one.
+ * If none of the potential next ViewEdge respects these 2 predicates, 0 is returned.
+ */
+class LIB_STROKE_EXPORT ChainPredicateIterator : public ChainingIterator
+{
+protected:
+ BinaryPredicate1D *_binary_predicate; // the caller is responsible for the deletion of this object
+ UnaryPredicate1D *_unary_predicate; // the caller is responsible for the deletion of this object
+
+public:
+ /*! Builds a ChainPredicateIterator from a starting ViewEdge and its orientation.
+ * \param iRestrictToSelection
+ * Indicates whether to force the chaining to stay within the set of selected ViewEdges or not.
+ * \param iRestrictToUnvisited
+ * Indicates whether a ViewEdge that has already been chained must be ignored ot not.
+ * \param begin
+ * The ViewEdge from where to start the iteration.
+ * \param orientation
+ * If true, we'll look for the next ViewEdge among the ViewEdges that surround the ending ViewVertex of begin.
+ * If false, we'll search over the ViewEdges surrounding the ending ViewVertex of begin.
+ */
+ ChainPredicateIterator(bool iRestrictToSelection = true, bool iRestrictToUnvisited = true, ViewEdge* begin = NULL,
+ bool orientation = true)
+ : ChainingIterator(iRestrictToSelection, iRestrictToUnvisited, begin, orientation)
+ {
+ _binary_predicate = 0;
+ _unary_predicate = 0;
+ }
+
+ /*! Builds a ChainPredicateIterator from a unary predicate, a binary predicate, a starting ViewEdge and
+ * its orientation.
+ * \param iRestrictToSelection
+ * Indicates whether to force the chaining to stay within the set of selected ViewEdges or not.
+ * \param iRestrictToUnvisited
+ * Indicates whether a ViewEdge that has already been chained must be ignored ot not.
+ * \param upred
+ * The unary predicate that the next ViewEdge must satisfy.
+ * \param bpred
+ * The binary predicate that the next ViewEdge must satisfy together with the actual pointed ViewEdge.
+ * \param begin
+ * The ViewEdge from where to start the iteration.
+ * \param orientation
+ * If true, we'll look for the next ViewEdge among the ViewEdges that surround the ending ViewVertex of begin.
+ * If false, we'll search over the ViewEdges surrounding the ending ViewVertex of begin.
+ */
+ ChainPredicateIterator(UnaryPredicate1D& upred, BinaryPredicate1D& bpred, bool iRestrictToSelection = true,
+ bool iRestrictToUnvisited = true, ViewEdge* begin = NULL, bool orientation = true)
+ : ChainingIterator(iRestrictToSelection, iRestrictToUnvisited, begin, orientation)
+ {
+ _unary_predicate = &upred;
+ _binary_predicate = &bpred;
+ }
+
+ /*! Copy constructor */
+ ChainPredicateIterator(const ChainPredicateIterator& brother) : ChainingIterator(brother)
+ {
+ _unary_predicate = brother._unary_predicate;
+ _binary_predicate = brother._binary_predicate;
+ }
+
+ /*! Destructor. */
+ virtual ~ChainPredicateIterator()
+ {
+ _unary_predicate = 0;
+ _binary_predicate = 0;
+ }
+
+ /*! Returns the string "ChainPredicateIterator" */
+ virtual string getExactTypeName() const
+ {
+ return "ChainPredicateIterator";
+ }
+
+ /*! This method iterates over the potential next ViewEdges and returns the one that will be followed next.
+ * When reaching the end of a chain, 0 is returned.
+ */
+ virtual int traverse(const AdjacencyIterator &it);
+
+ /*! Inits the iterator context */
+ virtual int init()
+ {
+ return 0;
+ }
+};
+
+#endif // __FREESTYLE_CHAINING_ITERATORS_H__
diff --git a/source/blender/freestyle/intern/stroke/ContextFunctions.cpp b/source/blender/freestyle/intern/stroke/ContextFunctions.cpp
new file mode 100644
index 00000000000..7723c57921d
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/ContextFunctions.cpp
@@ -0,0 +1,87 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/ContextFunctions.cpp
+ * \ingroup freestyle
+ * \brief Functions related to context queries
+ * \brief Interface to access the context related information.
+ * \author Stephane Grabli
+ * \date 20/12/2003
+ */
+
+#include "ContextFunctions.h"
+
+#include "../view_map/SteerableViewMap.h"
+
+#include "../system/TimeStamp.h"
+
+namespace ContextFunctions {
+
+unsigned GetTimeStampCF()
+{
+ return TimeStamp::instance()->getTimeStamp();
+}
+
+unsigned GetCanvasWidthCF()
+{
+ return Canvas::getInstance()->width();
+}
+
+unsigned GetCanvasHeightCF()
+{
+ return Canvas::getInstance()->height();
+}
+
+void LoadMapCF(const char *iFileName, const char *iMapName, unsigned iNbLevels, float iSigma)
+{
+ return Canvas::getInstance()->loadMap(iFileName, iMapName, iNbLevels,iSigma);
+}
+
+float ReadMapPixelCF(const char *iMapName, int level, unsigned x, unsigned y)
+{
+ Canvas *canvas = Canvas::getInstance();
+ return canvas->readMapPixel(iMapName, level, x, y);
+}
+
+float ReadCompleteViewMapPixelCF(int level, unsigned x, unsigned y)
+{
+ SteerableViewMap *svm = Canvas::getInstance()->getSteerableViewMap();
+ return svm->readCompleteViewMapPixel(level, x, y);
+}
+
+float ReadDirectionalViewMapPixelCF(int iOrientation, int level, unsigned x, unsigned y)
+{
+ SteerableViewMap *svm = Canvas::getInstance()->getSteerableViewMap();
+ return svm->readSteerableViewMapPixel(iOrientation, level, x, y);
+}
+
+FEdge * GetSelectedFEdgeCF()
+{
+ return Canvas::getInstance()->selectedFEdge();
+}
+
+} // ContextFunctions namespace
diff --git a/source/blender/freestyle/intern/stroke/ContextFunctions.h b/source/blender/freestyle/intern/stroke/ContextFunctions.h
new file mode 100644
index 00000000000..0718ebb1d6a
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/ContextFunctions.h
@@ -0,0 +1,120 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_CONTEXT_FUNCTIONS_H__
+#define __FREESTYLE_CONTEXT_FUNCTIONS_H__
+
+/** \file blender/freestyle/intern/stroke/ContextFunctions.h
+ * \ingroup freestyle
+ * \brief Functions related to context queries
+ * \brief Interface to access the context related information.
+ * \author Stephane Grabli
+ * \date 20/12/2003
+ */
+
+#include "Canvas.h"
+
+#include "../image/GaussianFilter.h"
+#include "../image/Image.h"
+
+//
+// Context Functions definitions
+//
+///////////////////////////////////////////////////////////
+/*! namespace containing all the Context related functions */
+namespace ContextFunctions {
+
+// GetTimeStamp
+/*! Returns the system time stamp */
+LIB_STROKE_EXPORT
+unsigned GetTimeStampCF();
+
+// GetCanvasWidth
+/*! Returns the canvas width */
+LIB_STROKE_EXPORT
+unsigned GetCanvasWidthCF();
+
+// GetCanvasHeight
+/*! Returns the canvas width */
+LIB_STROKE_EXPORT
+unsigned GetCanvasHeightCF();
+
+// Load map
+/*! Loads an image map for further reading */
+LIB_STROKE_EXPORT
+void LoadMapCF(const char *iFileName, const char *iMapName, unsigned iNbLevels = 4, float iSigma = 1.0f);
+
+// ReadMapPixel
+/*! Reads a pixel in a user-defined map
+ * \return the floating value stored for that pixel
+ * \param iMapName
+ * The name of the map
+ * \param level
+ * The level of the pyramid in which we wish to read the pixel
+ * \param x
+ * The x-coordinate of the pixel we wish to read. The origin is in the lower-left corner.
+ * \param y
+ * The y-coordinate of the pixel we wish to read. The origin is in the lower-left corner.
+ */
+LIB_STROKE_EXPORT
+float ReadMapPixelCF(const char *iMapName, int level, unsigned x, unsigned y);
+
+// ReadCompleteViewMapPixel
+/*! Reads a pixel in the complete view map
+ * \return the floating value stored for that pixel
+ * \param level
+ * The level of the pyramid in which we wish to read the pixel
+ * \param x
+ * The x-coordinate of the pixel we wish to read. The origin is in the lower-left corner.
+ * \param y
+ * The y-coordinate of the pixel we wish to read. The origin is in the lower-left corner.
+ */
+LIB_STROKE_EXPORT
+float ReadCompleteViewMapPixelCF(int level, unsigned x, unsigned y);
+
+// ReadOrientedViewMapPixel
+/*! Reads a pixel in one of the oriented view map images
+ * \return the floating value stored for that pixel
+ * \param iOrientation
+ * The number telling which orientation we want to check
+ * \param level
+ * The level of the pyramid in which we wish to read the pixel
+ * \param x
+ * The x-coordinate of the pixel we wish to read. The origin is in the lower-left corner.
+ * \param y
+ * The y-coordinate of the pixel we wish to read. The origin is in the lower-left corner.
+ */
+LIB_STROKE_EXPORT
+float ReadDirectionalViewMapPixelCF(int iOrientation, int level, unsigned x, unsigned y);
+
+// DEBUG
+LIB_STROKE_EXPORT
+FEdge *GetSelectedFEdgeCF();
+
+} // end of namespace ContextFunctions
+
+#endif // __FREESTYLE_CONTEXT_FUNCTIONS_H__
diff --git a/source/blender/freestyle/intern/stroke/Curve.cpp b/source/blender/freestyle/intern/stroke/Curve.cpp
new file mode 100644
index 00000000000..30d651421a4
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Curve.cpp
@@ -0,0 +1,931 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/Curve.cpp
+ * \ingroup freestyle
+ * \brief Class to define a container for curves
+ * \author Stephane Grabli
+ * \date 11/01/2003
+ */
+
+#include "Curve.h"
+#include "CurveAdvancedIterators.h"
+#include "CurveIterators.h"
+
+#include "BKE_global.h"
+
+/**********************************/
+/* */
+/* */
+/* CurvePoint */
+/* */
+/* */
+/**********************************/
+
+CurvePoint::CurvePoint()
+{
+ __A = 0;
+ __B = 0;
+ _t2d = 0;
+}
+
+CurvePoint::CurvePoint(SVertex *iA, SVertex *iB, float t)
+{
+ __A = iA;
+ __B = iB;
+ _t2d = t;
+ if ((iA == 0) && (t == 1.0f)) {
+ _Point2d = __B->point2d();
+ _Point3d = __B->point3d();
+ }
+ else if ((iB == 0) && (t == 0.0f)) {
+ _Point2d = __A->point2d();
+ _Point3d = __A->point3d();
+ }
+ else {
+ _Point2d = __A->point2d() + _t2d * (__B->point2d() - __A->point2d());
+ _Point3d = __A->point3d() + _t2d * (__B->point3d() - __A->point3d());
+ }
+}
+
+CurvePoint::CurvePoint(CurvePoint *iA, CurvePoint *iB, float t3)
+{
+ __A = 0;
+ __B = 0;
+ float t1 = iA->t2d();
+ float t2 = iB->t2d();
+ if ((iA->A() == iB->A()) && (iA->B() == iB->B()) &&
+ (iA->A() != 0) && (iA->B() != 0) && (iB->A() != 0) && (iB->B() != 0))
+ {
+ __A = iA->A();
+ __B = iB->B();
+ _t2d = t1 + t2 * t3 - t1 * t3;
+ }
+ else if ((iA->B() == 0) && (iB->B() == 0)) {
+ __A = iA->A();
+ __B = iB->A();
+ _t2d = t3;
+ }
+ else if ((iA->t2d() == 0) && (iB->t2d() == 0)) {
+ __A = iA->A();
+ __B = iB->A();
+ _t2d = t3;
+ }
+ else if (iA->A() == iB->A()) {
+iA_A_eq_iB_A:
+ if (iA->t2d() == 0) {
+ __A = iB->A();
+ __B = iB->B();
+ _t2d = t3;
+ }
+ else if (iB->t2d() == 0) {
+ __A = iA->A();
+ __B = iA->B();
+ _t2d = t3;
+ }
+ }
+ else if (iA->B() == iB->B()) {
+iA_B_eq_iB_B:
+ if (iA->t2d() == 1) {
+ __A = iB->A();
+ __B = iB->B();
+ _t2d = t3;
+ }
+ else if (iB->t2d() == 1) {
+ __A = iA->A();
+ __B = iA->B();
+ _t2d = t3;
+ }
+ }
+ else if (iA->B() == iB->A()) {
+iA_B_eq_iB_A:
+ if ((iA->t2d() != 1.0f) && (iB->t2d() == 0.0f)) {
+ __A = iA->A();
+ __B = iA->B();
+ _t2d = t1 + t3 - t1 * t3;
+ //_t2d = t3;
+ }
+ else if ((iA->t2d() == 1.0f) && (iB->t2d() != 0.0f)) {
+ __A = iB->A();
+ __B = iB->B();
+ //_t2d = t3;
+ _t2d = t2 * t3;
+ }
+ else if ((iA->getPoint2D() - iA->getPoint2D()).norm() < 1.0e-6) {
+ __A = iB->A();
+ __B = iB->B();
+ //_t2d = t3;
+ _t2d = t2 * t3;
+ }
+ }
+ else if (iA->A() != 0 && iB->A() != 0 && (iA->A()->point3d() - iB->A()->point3d()).norm() < 1.0e-6) {
+ goto iA_A_eq_iB_A;
+ }
+ else if (iA->B() != 0 && iB->B() != 0 && (iA->B()->point3d() - iB->B()->point3d()).norm() < 1.0e-6) {
+ goto iA_B_eq_iB_B;
+ }
+ else if (iA->B() != 0 && iB->A() != 0 && (iA->B()->point3d() - iB->A()->point3d()).norm() < 1.0e-6) {
+ goto iA_B_eq_iB_A;
+ }
+
+ if (!__A || !__B) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("iA A 0x%p p (%f, %f)\n", iA->A(), iA->A()->getPoint2D().x(), iA->A()->getPoint2D().y());
+ printf("iA B 0x%p p (%f, %f)\n", iA->B(), iA->B()->getPoint2D().x(), iA->B()->getPoint2D().y());
+ printf("iB A 0x%p p (%f, %f)\n", iB->A(), iB->A()->getPoint2D().x(), iB->A()->getPoint2D().y());
+ printf("iB B 0x%p p (%f, %f)\n", iB->B(), iB->B()->getPoint2D().x(), iB->B()->getPoint2D().y());
+ printf("iA t2d %f p (%f, %f)\n", iA->t2d(), iA->getPoint2D().x(), iA->getPoint2D().y());
+ printf("iB t2d %f p (%f, %f)\n", iB->t2d(), iB->getPoint2D().x(), iB->getPoint2D().y());
+ }
+ cerr << "Fatal error in CurvePoint::CurvePoint(CurvePoint *iA, CurvePoint *iB, float t3)" << endl;
+ }
+ assert(__A != 0 && __B != 0);
+
+#if 0
+ _Point2d = __A->point2d() + _t2d * (__B->point2d() - __A->point2d());
+ _Point3d = __A->point3d() + _t2d * (__B->point3d() - __A->point3d());
+#endif
+
+ _Point2d = iA->point2d() + t3 * (iB->point2d() - iA->point2d());
+ _Point3d = __A->point3d() + _t2d * (__B->point3d() - __A->point3d());
+}
+
+CurvePoint::CurvePoint(const CurvePoint& iBrother)
+{
+ __A = iBrother.__A;
+ __B = iBrother.__B;
+ _t2d = iBrother._t2d;
+ _Point2d = iBrother._Point2d;
+ _Point3d = iBrother._Point3d;
+}
+
+CurvePoint& CurvePoint::operator=(const CurvePoint& iBrother)
+{
+ __A = iBrother.__A;
+ __B = iBrother.__B;
+ _t2d = iBrother._t2d;
+ _Point2d = iBrother._Point2d;
+ _Point3d = iBrother._Point3d;
+ return *this;
+}
+
+
+FEdge *CurvePoint::fedge()
+{
+ if (getNature() & Nature::T_VERTEX)
+ return 0;
+ return __A->fedge();
+}
+
+
+FEdge *CurvePoint::getFEdge(Interface0D& inter)
+{
+ CurvePoint* iVertexB = dynamic_cast<CurvePoint*>(&inter);
+ if (!iVertexB) {
+ cerr << "Warning: CurvePoint::getFEdge() failed to cast the given 0D element to CurvePoint." << endl;
+ return 0;
+ }
+ if (((__A == iVertexB->__A) && (__B == iVertexB->__B)) ||
+ ((__A == iVertexB->__B) && (__B == iVertexB->__A)))
+ {
+ return __A->getFEdge(*__B);
+ }
+ if (__B == 0) {
+ if (iVertexB->__B == 0)
+ return __A->getFEdge(*(iVertexB->__A));
+ else if (iVertexB->__A == __A)
+ return __A->getFEdge(*(iVertexB->__B));
+ else if (iVertexB->__B == __A)
+ return __A->getFEdge(*(iVertexB->__A));
+ }
+ if (iVertexB->__B == 0) {
+ if (iVertexB->__A == __A)
+ return __B->getFEdge(*(iVertexB->__A));
+ else if (iVertexB->__A == __B)
+ return __A->getFEdge(*(iVertexB->__A));
+ }
+ if (__B == iVertexB->__A) {
+ if ((_t2d != 1) && (iVertexB->_t2d == 0))
+ return __A->getFEdge(*__B);
+ if ((_t2d == 1) && (iVertexB->_t2d != 0))
+ return iVertexB->__A->getFEdge(*(iVertexB->__B));
+ }
+ if (__B == iVertexB->__B) {
+ if ((_t2d != 1) && (iVertexB->_t2d == 1))
+ return __A->getFEdge(*__B);
+ if ((_t2d == 1) && (iVertexB->_t2d != 1))
+ return iVertexB->__A->getFEdge(*(iVertexB->__B));
+ }
+ if (__A == iVertexB->__A) {
+ if ((_t2d == 0) && (iVertexB->_t2d != 0))
+ return iVertexB->__A->getFEdge(*(iVertexB->__B));
+ if ((_t2d != 0) && (iVertexB->_t2d == 0))
+ return __A->getFEdge(*__B);
+ }
+ if (__A == iVertexB->__B) {
+ if ((_t2d == 0) && (iVertexB->_t2d != 1))
+ return iVertexB->__A->getFEdge(*(iVertexB->__B));
+ if ((_t2d != 0) && (iVertexB->_t2d == 1))
+ return __A->getFEdge(*__B);
+ }
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("__A 0x%p p (%f, %f)\n", __A, __A->getPoint2D().x(), __A->getPoint2D().y());
+ printf("__B 0x%p p (%f, %f)\n", __B, __B->getPoint2D().x(), __B->getPoint2D().y());
+ printf("iVertexB->A() 0x%p p (%f, %f)\n", iVertexB->A(), iVertexB->A()->getPoint2D().x(),
+ iVertexB->A()->getPoint2D().y());
+ printf("iVertexB->B() 0x%p p (%f, %f)\n", iVertexB->B(), iVertexB->B()->getPoint2D().x(),
+ iVertexB->B()->getPoint2D().y());
+ printf("_t2d %f p (%f, %f)\n", _t2d, getPoint2D().x(), getPoint2D().y());
+ printf("iVertexB->t2d() %f p (%f, %f)\n", iVertexB->t2d(), iVertexB->getPoint2D().x(), iVertexB->getPoint2D().y());
+ }
+#endif
+ cerr << "Warning: CurvePoint::getFEdge() failed." << endl;
+
+ return NULL;
+}
+
+
+Vec3r CurvePoint::normal() const
+{
+ if (__B == 0)
+ return __A->normal();
+ if (__A == 0)
+ return __B->normal();
+ Vec3r Na = __A->normal();
+ if (Exception::getException())
+ Na = Vec3r(0, 0, 0);
+ Vec3r Nb = __B->normal();
+ if (Exception::getException())
+ Nb = Vec3r(0, 0, 0);
+ // compute t3d:
+ real t3d = SilhouetteGeomEngine::ImageToWorldParameter(__A->getFEdge(*__B), _t2d);
+ return ((1 - t3d) * Na + t3d * Nb);
+}
+
+
+#if 0
+Material CurvePoint::material() const
+{
+ if (__A == 0)
+ return __B->material();
+ return __A->material();
+}
+
+Id CurvePoint::shape_id() const
+{
+ if (__A == 0)
+ return __B->shape_id();
+ return __A->shape_id();
+}
+#endif
+
+
+const SShape *CurvePoint::shape() const
+{
+ if (__A == 0)
+ return __B->shape();
+ return __A->shape();
+}
+
+#if 0
+float CurvePoint::shape_importance() const
+{
+ if (__A == 0)
+ return __B->shape_importance();
+ return __A->shape_importance();
+}
+
+
+const unsigned CurvePoint::qi() const
+{
+ if (__A == 0)
+ return __B->qi();
+ if (__B == 0)
+ return __A->qi();
+ return __A->getFEdge(*__B)->qi();
+}
+#endif
+
+occluder_container::const_iterator CurvePoint::occluders_begin() const
+{
+ if (__A == 0)
+ return __B->occluders_begin();
+ if (__B == 0)
+ return __A->occluders_begin();
+ return __A->getFEdge(*__B)->occluders_begin();
+}
+
+occluder_container::const_iterator CurvePoint::occluders_end() const
+{
+ if (__A == 0)
+ return __B->occluders_end();
+ if (__B == 0)
+ return __A->occluders_end();
+ return __A->getFEdge(*__B)->occluders_end();
+}
+
+bool CurvePoint::occluders_empty() const
+{
+ if (__A == 0)
+ return __B->occluders_empty();
+ if (__B == 0)
+ return __A->occluders_empty();
+ return __A->getFEdge(*__B)->occluders_empty();
+}
+
+int CurvePoint::occluders_size() const
+{
+ if (__A == 0)
+ return __B->occluders_size();
+ if (__B == 0)
+ return __A->occluders_size();
+ return __A->getFEdge(*__B)->occluders_size();
+}
+
+const SShape *CurvePoint::occluded_shape() const
+{
+ if (__A == 0)
+ return __B->occluded_shape();
+ if (__B == 0)
+ return __A->occluded_shape();
+ return __A->getFEdge(*__B)->occluded_shape();
+}
+
+const Polygon3r& CurvePoint::occludee() const
+{
+ if (__A == 0)
+ return __B->occludee();
+ if (__B == 0)
+ return __A->occludee();
+ return __A->getFEdge(*__B)->occludee();
+}
+
+const bool CurvePoint::occludee_empty() const
+{
+ if (__A == 0)
+ return __B->occludee_empty();
+ if (__B == 0)
+ return __A->occludee_empty();
+ return __A->getFEdge(*__B)->occludee_empty();
+}
+
+real CurvePoint::z_discontinuity() const
+{
+ if (__A == 0)
+ return __B->z_discontinuity();
+ if (__B == 0)
+ return __A->z_discontinuity();
+ if (__A->getFEdge(*__B) == 0)
+ return 0.0;
+
+ return __A->getFEdge(*__B)->z_discontinuity();
+}
+
+#if 0
+float CurvePoint::local_average_depth() const
+{
+ return local_average_depth_function<CurvePoint >(this);
+}
+
+float CurvePoint::local_depth_variance() const
+{
+ return local_depth_variance_function<CurvePoint >(this);
+}
+
+real CurvePoint::local_average_density(float sigma) const
+{
+ //return local_average_density<CurvePoint >(this);
+ return density_function<CurvePoint >(this);
+}
+
+Vec3r shaded_color() const;
+
+Vec3r CurvePoint::orientation2d() const
+{
+ if (__A == 0)
+ return __B->orientation2d();
+ if (__B == 0)
+ return __A->orientation2d();
+ return __B->point2d() - __A->point2d();
+}
+
+Vec3r CurvePoint::orientation3d() const
+{
+ if (__A == 0)
+ return __B->orientation3d();
+ if (__B == 0)
+ return __A->orientation3d();
+ return __B->point3d() - __A->point3d();
+}
+
+real curvature2d() const
+{
+ return viewedge()->curvature2d((_VertexA->point2d() + _VertexB->point2d()) / 2.0);
+}
+
+Vec3r CurvePoint::curvature2d_as_vector() const
+{
+#if 0
+ Vec3r edgeA = (_FEdges[0])->orientation2d().normalize();
+ Vec3r edgeB = (_FEdges[1])->orientation2d().normalize();
+ return edgeA + edgeB;
+#endif
+ if (__A == 0)
+ return __B->curvature2d_as_vector();
+ if (__B == 0)
+ return __A->curvature2d_as_vector();
+ return ((1 - _t2d) * __A->curvature2d_as_vector() + _t2d * __B->curvature2d_as_vector());
+}
+
+real CurvePoint::curvature2d_as_angle() const
+{
+#if 0
+ Vec3r edgeA = (_FEdges[0])->orientation2d();
+ Vec3r edgeB = (_FEdges[1])->orientation2d();
+ Vec2d N1(-edgeA.y(), edgeA.x());
+ N1.normalize();
+ Vec2d N2(-edgeB.y(), edgeB.x());
+ N2.normalize();
+ return acos((N1 * N2));
+#endif
+ if (__A == 0)
+ return __B->curvature2d_as_angle();
+ if (__B == 0)
+ return __A->curvature2d_as_angle();
+ return ((1 - _t2d) * __A->curvature2d_as_angle() + _t2d * __B->curvature2d_as_angle());
+}
+#endif
+
+real CurvePoint::curvatureFredo() const
+{
+ if (__A == 0)
+ return __B->curvatureFredo();
+ if (__B == 0)
+ return __A->curvatureFredo();
+ return ((1 - _t2d) * __A->curvatureFredo() + _t2d * __B->curvatureFredo());
+}
+
+Vec2d CurvePoint::directionFredo () const
+{
+ if (__A == 0)
+ return __B->directionFredo();
+ if (__B == 0)
+ return __A->directionFredo();
+ return ((1 - _t2d) * __A->directionFredo() + _t2d * __B->directionFredo());
+}
+
+/**********************************/
+/* */
+/* */
+/* Curve */
+/* */
+/* */
+/**********************************/
+
+/* for functions */
+
+Curve::~Curve()
+{
+ if (!_Vertices.empty()) {
+ for (vertex_container::iterator it = _Vertices.begin(), itend = _Vertices.end(); it != itend; ++it) {
+ delete (*it);
+ }
+ _Vertices.clear();
+ }
+}
+
+/*! iterators access */
+Curve::point_iterator Curve::points_begin(float step)
+{
+ vertex_container::iterator second = _Vertices.begin();
+ ++second;
+ return point_iterator(_Vertices.begin(), second, _Vertices.begin(), _Vertices.end(), _nSegments, step, 0.0f, 0.0f);
+ //return point_iterator(_Vertices.begin(), second, _nSegments, step, 0.0f, 0.0f);
+}
+
+Curve::const_point_iterator Curve::points_begin(float step) const
+{
+ vertex_container::const_iterator second = _Vertices.begin();
+ ++second;
+ return const_point_iterator(_Vertices.begin(), second, _Vertices.begin(), _Vertices.end(),
+ _nSegments, step, 0.0f, 0.0f);
+ //return const_point_iterator(_Vertices.begin(), second, _nSegments, step, 0.0f, 0.0f);
+}
+
+Curve::point_iterator Curve::points_end(float step)
+{
+ return point_iterator(_Vertices.end(), _Vertices.end(), _Vertices.begin(), _Vertices.end(),
+ _nSegments, step, 1.0f, _Length);
+ //return point_iterator(_Vertices.end(), _Vertices.end(), _nSegments, step, 1.0f, _Length);
+}
+
+Curve::const_point_iterator Curve::points_end(float step) const
+{
+ return const_point_iterator(_Vertices.end(), _Vertices.end(), _Vertices.begin(), _Vertices.end(),
+ _nSegments, step, 1.0f, _Length);
+ //return const_point_iterator(_Vertices.end(), _Vertices.end(), _nSegments, step, 1.0f, _Length);
+}
+
+// Adavnced Iterators access
+Curve::point_iterator Curve::vertices_begin()
+{
+ return points_begin(0);
+}
+
+Curve::const_point_iterator Curve::vertices_begin() const
+{
+ return points_begin(0);
+}
+
+Curve::point_iterator Curve::vertices_end()
+{
+ return points_end(0);
+}
+
+Curve::const_point_iterator Curve::vertices_end() const
+{
+ return points_end(0);
+}
+
+// specialized iterators access
+CurveInternal::CurvePointIterator Curve::curvePointsBegin(float t)
+{
+ vertex_container::iterator second = _Vertices.begin();
+ ++second;
+ return CurveInternal::CurvePointIterator(_Vertices.begin(), second, _Vertices.begin(), _Vertices.end(),
+ 0, _nSegments, _Length, t, 0.0f, 0.0f);
+}
+
+CurveInternal::CurvePointIterator Curve::curvePointsEnd(float t)
+{
+ vertex_container::iterator last = _Vertices.end();
+ --last;
+ return CurveInternal::CurvePointIterator(last, _Vertices.end(), _Vertices.begin(), _Vertices.end(),
+ _nSegments, _nSegments, _Length, t, 0.0f, _Length);
+}
+
+CurveInternal::CurvePointIterator Curve::curveVerticesBegin()
+{
+ return curvePointsBegin(0);
+}
+
+CurveInternal::CurvePointIterator Curve::curveVerticesEnd()
+{
+ return curvePointsEnd(0);
+}
+
+Interface0DIterator Curve::pointsBegin(float t)
+{
+ vertex_container::iterator second = _Vertices.begin();
+ ++second;
+ Interface0DIterator ret(new CurveInternal::CurvePointIterator(_Vertices.begin(), second, _Vertices.begin(),
+ _Vertices.end(), 0, _nSegments, _Length,
+ t, 0.0f, 0.0f));
+ return ret;
+}
+
+Interface0DIterator Curve::pointsEnd(float t)
+{
+ vertex_container::iterator last = _Vertices.end();
+ --last;
+ Interface0DIterator ret(new CurveInternal::CurvePointIterator(last, _Vertices.end(), _Vertices.begin(),
+ _Vertices.end(), _nSegments, _nSegments,
+ _Length, t, 0.0f, _Length));
+ return ret;
+}
+
+Interface0DIterator Curve::verticesBegin()
+{
+ return pointsBegin(0);
+}
+
+Interface0DIterator Curve::verticesEnd()
+{
+ return pointsEnd(0);
+}
+
+#if 0
+Vec3r shaded_color(int iCombination = 0) const;
+
+Vec3r Curve::orientation2d(point_iterator it) const
+{
+ return (*it)->orientation2d();
+}
+
+template <class BaseVertex>
+Vec3r Curve::orientation2d(int iCombination) const
+{
+ return edge_orientation2d_function<Curve >(this, iCombination);
+}
+
+Vec3r Curve::orientation3d(point_iterator it) const
+{
+ return (*it)->orientation3d();
+}
+
+Vec3r Curve::orientation3d(int iCombination) const
+{
+ return edge_orientation3d_function<Curve >(this, iCombination);
+}
+
+real curvature2d(point_iterator it) const
+{
+ return (*it)->curvature2d();
+}
+
+real curvature2d(int iCombination = 0) const;
+
+Material Curve::material() const
+{
+ const_vertex_iterator v = vertices_begin(), vend = vertices_end();
+ const Material& mat = (*v)->material();
+ for (; v != vend; ++v) {
+ if ((*v)->material() != mat)
+ Exception::raiseException();
+ }
+ return mat;
+}
+
+int Curve::qi() const
+{
+ const_vertex_iterator v = vertices_begin(), vend = vertices_end();
+ int qi_ = (*v)->qi();
+ for (; v != vend; ++v) {
+ if ((*v)->qi() != qi_)
+ Exception::raiseException();
+ }
+ return qi_;
+}
+
+occluder_container::const_iterator occluders_begin() const
+{
+ return _FEdgeA->occluders().begin();
+}
+
+occluder_container::const_iterator occluders_end() const
+{
+ return _FEdgeA->occluders().end();
+}
+
+int Curve::occluders_size() const
+{
+ return qi();
+}
+
+bool Curve::occluders_empty() const
+{
+ const_vertex_iterator v = vertices_begin(), vend = vertices_end();
+ bool empty = (*v)->occluders_empty();
+ for (; v != vend; ++v) {
+ if ((*v)->occluders_empty() != empty)
+ Exception::raiseException();
+ }
+ return empty;
+}
+
+const Polygon3r& occludee() const
+{
+ return *(_FEdgeA->aFace());
+}
+
+const SShape *Curve::occluded_shape() const
+{
+ const_vertex_iterator v = vertices_begin(), vend = vertices_end();
+ const SShape *sshape = (*v)->occluded_shape();
+ for (; v != vend; ++v) {
+ if ((*v)->occluded_shape() != sshape)
+ Exception::raiseException();
+ }
+ return sshape;
+}
+
+const bool Curve::occludee_empty() const
+{
+ const_vertex_iterator v = vertices_begin(), vend = vertices_end();
+ bool empty = (*v)->occludee_empty();
+ for (; v != vend; ++v) {
+ if ((*v)->occludee_empty() != empty)
+ Exception::raiseException();
+ }
+ return empty;
+}
+real Curve::z_discontinuity(int iCombination) const
+{
+ return z_discontinuity_edge_function<Curve>(this, iCombination);
+}
+
+int Curve::shape_id() const
+{
+ const_vertex_iterator v = vertices_begin(), vend = vertices_end();
+ Id id = (*v)->shape_id();
+ for (; v != vend; ++v) {
+ if ((*v)->shape_id() != id)
+ Exception::raiseException();
+ }
+ return id.first;
+}
+
+
+const SShape *Curve::shape() const
+{
+ const_vertex_iterator v = vertices_begin(), vend = vertices_end();
+ const SShape *sshape = (*v)->shape();
+ for (; v != vend; ++v) {
+ if ((*v)->shape() != sshape)
+ Exception::raiseException();
+ }
+ return sshape;
+}
+
+
+occluder_container::const_iterator Curve::occluders_begin() const
+{
+ const_vertex_iterator v = vertices_begin();
+ return (*v)->occluders_begin();
+}
+
+
+occluder_container::const_iterator Curve::occluders_end() const
+{
+ const_vertex_iterator v = vertices_end();
+ return (*v)->occluders_end();
+}
+
+Vec3r Curve::curvature2d_as_vector(int iCombination) const
+{
+ return curvature2d_as_vector_edge_function<Curve>(this, iCombination);
+}
+
+real Curve::curvature2d_as_angle(int iCombination) const
+{
+ return curvature2d_as_angle_edge_function<Curve>(this, iCombination);
+}
+
+float Curve::shape_importance(int iCombination) const
+{
+ return shape_importance_edge_function<Curve>(this, iCombination);
+}
+
+float Curve::local_average_depth(int iCombination) const
+{
+ return local_average_depth_edge_function<Curve>(this, iCombination);
+}
+
+float Curve::local_depth_variance(int iCombination ) const
+{
+ return local_depth_variance_edge_function<Curve>(this, iCombination);
+#if 0
+ local_depth_variance_functor<Point> functor;
+ float result;
+ Evaluate<float, local_depth_variance_functor<Point> >(&functor, iCombination, result);
+ return result;
+#endif
+}
+
+real Curve::local_average_density(float sigma, int iCombination ) const
+{
+ return density_edge_function<Curve>(this, iCombination);
+#if 0
+ density_functor<Point> functor;
+ real result;
+ Evaluate<real, density_functor<Point> >(&functor, iCombination, result);
+ return result;
+#endif
+}
+#endif
+
+#define EPS_CURVA_DIR 0.01
+
+void Curve::computeCurvatureAndOrientation ()
+{
+#if 0
+ const_vertex_iterator v = vertices_begin(), vend = vertices_end(), v2, prevV, v0;
+ Vec2d p0, p1, p2;
+ Vec3r p;
+
+ p = (*v)->point2d();
+ p0 = Vec2d(p[0], p[1]);
+ prevV = v;
+ ++v;
+ p = (*v)->point2d();
+ p1 = Vec2d(p[0], p[1]);
+ Vec2d prevDir(p1 - p0);
+
+ for (; v! = vend; ++v) {
+ v2 = v;
+ ++v2;
+ if (v2 == vend)
+ break;
+ Vec3r p2 = (*v2)->point2d();
+
+ Vec2d BA = p0 - p1;
+ Vec2d BC = p2 - p1;
+ real lba = BA.norm(), lbc = BC.norm();
+ BA.normalizeSafe();
+ BC.normalizeSafe();
+ Vec2d normalCurvature = BA + BC;
+ Vec2d dir = Vec2d(BC - BA);
+ Vec2d normal = Vec2d(-dir[1], dir[0]);
+
+ normal.normalizeSafe();
+ real curvature = normalCurvature * normal;
+ if (lba + lbc > MY_EPSILON)
+ curvature /= (0.5 * lba + lbc);
+ if (dir.norm() < MY_EPSILON)
+ dir = 0.1 * prevDir;
+ (*v)->setCurvatureFredo(curvature);
+ (*v)->setDirectionFredo(dir);
+
+ prevV = v;
+ p0 = p1;
+ p1 = p2;
+ prevDir = dir;
+ prevDir.normalize();
+ }
+ (*v)->setCurvatureFredo((*prevV)->curvatureFredo());
+ (*v)->setDirectionFredo((*v)->point2d() - (*prevV)->point2d());
+ v0 = vertices_begin();
+ v2 = v0;
+ ++v2;
+ (*v0)->setCurvatureFredo((*v2)->curvatureFredo());
+ (*v0)->setDirectionFredo((*v2)->point2d() - (*v0)->point2d());
+
+ //closed curve case one day...
+
+ //
+ return;
+
+ //numerical degeneracy verification... we'll see later
+ const_vertex_iterator vLastReliable = vertices_begin();
+
+ v = vertices_begin();
+ p = (*v)->point2d();
+ p0 = Vec2d(p[0], p[1]);
+ prevV = v;
+ ++v;
+ p = (*v)->point2d();
+ p1 = Vec2d(p[0], p[1]);
+ bool isReliable = false;
+ if ((p1 - p0).norm > EPS_CURVA) {
+ vLastReliable = v;
+ isReliable = true;
+ }
+
+ for (; v != vend; ++v) {
+ v2 = v;
+ ++v2;
+ if (v2 == vend)
+ break;
+ Vec3r p2 = (*v2)->point2d();
+
+ Vec2d BA = p0 - p1;
+ Vec2d BC = p2 - p1;
+ real lba = BA.norm(), lbc = BC.norm();
+
+ if ((lba + lbc) < EPS_CURVA) {
+ isReliable = false;
+ cerr << "/";
+ }
+ else {
+ if (!isReliable) { //previous points were not reliable
+ const_vertex_iterator vfix = vLastReliable;
+ ++vfix;
+ for (; vfix != v; ++vfix) {
+ (*vfix)->setCurvatureFredo((*v)->curvatureFredo());
+ (*vfix)->setDirectionFredo((*v)->directionFredo());
+ }
+ }
+ isReliable = true;
+ vLastReliable = v;
+ }
+ prevV = v;
+ p0 = p1;
+ p1 = p2;
+ }
+#endif
+}
diff --git a/source/blender/freestyle/intern/stroke/Curve.h b/source/blender/freestyle/intern/stroke/Curve.h
new file mode 100644
index 00000000000..f451d83d65b
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Curve.h
@@ -0,0 +1,589 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_CURVE_H__
+#define __FREESTYLE_CURVE_H__
+
+/** \file blender/freestyle/intern/stroke/Curve.h
+ * \ingroup freestyle
+ * \brief Class to define a container for curves
+ * \author Stephane Grabli
+ * \date 11/01/2003
+ */
+
+#include <deque>
+
+#include "../geometry/Geom.h"
+
+//#include "../scene_graph/FrsMaterial.h"
+
+#include "../view_map/Interface0D.h"
+#include "../view_map/Interface1D.h"
+#include "../view_map/Silhouette.h"
+#include "../view_map/SilhouetteGeomEngine.h"
+
+#include "../system/BaseIterator.h"
+
+using namespace std;
+using namespace Geometry;
+
+/**********************************/
+/* */
+/* */
+/* CurvePoint */
+/* */
+/* */
+/**********************************/
+
+/*! Class to represent a point of a curve.
+ * A CurvePoint can be any point of a 1D curve (it doesn't have to be a vertex of the curve).
+ * Any Interface1D is built upon ViewEdges, themselves built upon FEdges. Therefore, a curve is basically
+ * a polyline made of a list SVertex.
+ * Thus, a CurvePoint is built by lineraly interpolating two SVertex.
+ * CurvePoint can be used as virtual points while querying 0D information along a curve at a given resolution.
+ */
+class LIB_STROKE_EXPORT CurvePoint : public Interface0D
+{
+public: // Implementation of Interface0D
+ /*! Returns the string "CurvePoint"*/
+ virtual string getExactTypeName() const
+ {
+ return "CurvePoint";
+ }
+
+ // Data access methods
+ /*! Returns the 3D X coordinate of the point */
+ virtual real getX() const
+ {
+ return _Point3d.x();
+ }
+
+ /*! Returns the 3D Y coordinate of the point */
+ virtual real getY() const
+ {
+ return _Point3d.y();
+ }
+
+ /*! Returns the 3D Z coordinate of the point */
+ virtual real getZ() const
+ {
+ return _Point3d.z();
+ }
+
+ /*! Returns the 3D point. */
+ virtual Vec3f getPoint3D() const
+ {
+ return _Point3d;
+ }
+
+ /*! Returns the projected 3D X coordinate of the point */
+ virtual real getProjectedX() const
+ {
+ return _Point2d.x();
+ }
+
+ /*! Returns the projected 3D Y coordinate of the point */
+ virtual real getProjectedY() const
+ {
+ return _Point2d.y();
+ }
+
+ /*! Returns the projected 3D Z coordinate of the point */
+ virtual real getProjectedZ() const
+ {
+ return _Point2d.z();
+ }
+
+ /*! Returns the 2D point. */
+ virtual Vec2f getPoint2D() const
+ {
+ return Vec2f((float)_Point2d.x(), (float)_Point2d.y());
+ }
+
+ virtual FEdge* getFEdge(Interface0D& inter);
+
+ /*! Returns the CurvePoint's Id */
+ virtual Id getId() const
+ {
+ Id id;
+ if (_t2d == 0)
+ return __A->getId();
+ else if (_t2d == 1)
+ return __B->getId();
+ return id;
+ }
+
+ /*! Returns the CurvePoint's Nature */
+ virtual Nature::VertexNature getNature() const
+ {
+ Nature::VertexNature nature = Nature::POINT;
+ if (_t2d == 0)
+ nature |= __A->getNature();
+ else if (_t2d == 1)
+ nature |= __B->getNature();
+ return nature;
+ }
+
+ /*! Cast the Interface0D in SVertex if it can be. */
+ virtual SVertex * castToSVertex()
+ {
+ if (_t2d == 0)
+ return __A;
+ else if (_t2d == 1)
+ return __B;
+ return Interface0D::castToSVertex();
+ }
+
+ /*! Cast the Interface0D in ViewVertex if it can be. */
+ virtual ViewVertex * castToViewVertex()
+ {
+ if (_t2d == 0)
+ return __A->castToViewVertex();
+ else if (_t2d == 1)
+ return __B->castToViewVertex();
+ return Interface0D::castToViewVertex();
+ }
+
+ /*! Cast the Interface0D in NonTVertex if it can be. */
+ virtual NonTVertex * castToNonTVertex()
+ {
+ if (_t2d == 0)
+ return __A->castToNonTVertex();
+ else if (_t2d == 1)
+ return __B->castToNonTVertex();
+ return Interface0D::castToNonTVertex();
+ }
+
+ /*! Cast the Interface0D in TVertex if it can be. */
+ virtual TVertex * castToTVertex()
+ {
+ if (_t2d == 0)
+ return __A->castToTVertex();
+ else if (_t2d == 1)
+ return __B->castToTVertex();
+ return Interface0D::castToTVertex();
+ }
+
+public:
+ typedef SVertex vertex_type;
+
+protected:
+ SVertex *__A;
+ SVertex *__B;
+ float _t2d;
+ //float _t3d;
+ Vec3r _Point2d;
+ Vec3r _Point3d;
+
+public:
+ /*! Defult Constructor. */
+ CurvePoint();
+
+ /*! Builds a CurvePoint from two SVertex and an interpolation parameter.
+ * \param iA
+ * The first SVertex
+ * \param iB
+ * The second SVertex
+ * \param t2d
+ * A 2D interpolation parameter used to linearly interpolate \a iA and \a iB
+ */
+ CurvePoint(SVertex *iA, SVertex *iB, float t2d);
+
+ /*! Builds a CurvePoint from two CurvePoint and an interpolation parameter.
+ * \param iA
+ * The first CurvePoint
+ * \param iB
+ * The second CurvePoint
+ * \param t2d
+ * The 2D interpolation parameter used to linearly interpolate \a iA and \a iB.
+ */
+ CurvePoint(CurvePoint *iA, CurvePoint *iB, float t2d);
+
+ //CurvePoint(SVertex *iA, SVertex *iB, float t2d, float t3d);
+
+ /*! Copy Constructor. */
+ CurvePoint(const CurvePoint& iBrother);
+
+ /*! Operator = */
+ CurvePoint& operator=(const CurvePoint& iBrother);
+
+ /*! Destructor */
+ virtual ~CurvePoint() {}
+
+ /*! Operator == */
+ bool operator==(const CurvePoint& b)
+ {
+ return ((__A == b.__A) && (__B == b.__B) && (_t2d == b._t2d));
+ }
+
+ /* accessors */
+ /*! Returns the first SVertex upon which the CurvePoint is built. */
+ inline SVertex *A()
+ {
+ return __A;
+ }
+
+ /*! Returns the second SVertex upon which the CurvePoint is built. */
+ inline SVertex *B()
+ {
+ return __B;
+ }
+
+ /*! Returns the interpolation parameter. */
+ inline float t2d() const
+ {
+ return _t2d;
+ }
+
+#if 0
+ inline const float t3d() const
+ {
+ return _t3d;
+ }
+#endif
+
+ /* modifiers */
+ /*! Sets the first SVertex upon which to build the CurvePoint. */
+ inline void setA(SVertex *iA)
+ {
+ __A = iA;
+ }
+
+ /*! Sets the second SVertex upon which to build the CurvePoint. */
+ inline void setB(SVertex *iB)
+ {
+ __B = iB;
+ }
+
+ /*! Sets the 2D interpolation parameter to use. */
+ inline void setT2d(float t)
+ {
+ _t2d = t;
+ }
+
+#if 0
+ inline void SetT3d(float t)
+ {
+ _t3d = t;
+ }
+#endif
+
+ /* Information access interface */
+
+ FEdge *fedge();
+
+ inline const Vec3r& point2d() const
+ {
+ return _Point2d;
+ }
+
+ inline const Vec3r& point3d() const
+ {
+ return _Point3d;
+ }
+
+ Vec3r normal() const;
+ //FrsMaterial material() const;
+ //Id shape_id() const;
+ const SShape *shape() const;
+ //float shape_importance() const;
+
+ //const unsigned qi() const;
+ occluder_container::const_iterator occluders_begin() const;
+ occluder_container::const_iterator occluders_end() const;
+ bool occluders_empty() const;
+ int occluders_size() const;
+ const Polygon3r& occludee() const;
+ const SShape *occluded_shape() const;
+ const bool occludee_empty() const;
+ real z_discontinuity() const;
+#if 0
+ float local_average_depth() const;
+ float local_depth_variance() const;
+ real local_average_density(float sigma = 2.3f) const;
+ Vec3r shaded_color() const;
+ Vec3r orientation2d() const;
+ Vec3r orientation3d() const;
+
+ real curvature2d() const
+ {
+ return viewedge()->curvature2d((_VertexA->point2d() + _VertexB->point2d()) / 2.0);
+ }
+
+ Vec3r curvature2d_as_vector() const;
+ /*! angle in radians */
+ real curvature2d_as_angle() const;
+#endif
+
+ real curvatureFredo() const;
+ Vec2d directionFredo() const;
+};
+
+
+/**********************************/
+/* */
+/* */
+/* Curve */
+/* */
+/* */
+/**********************************/
+
+namespace CurveInternal {
+
+class CurvePoint_const_traits;
+class CurvePoint_nonconst_traits;
+template<class Traits> class __point_iterator;
+class CurvePointIterator;
+
+} // end of namespace CurveInternal
+
+/*! Base class for curves made of CurvePoints.
+ * SVertex is the type of the initial curve vertices.
+ * A Chain is a specialization of a Curve.
+ */
+class LIB_STROKE_EXPORT Curve : public Interface1D
+{
+public:
+ typedef CurvePoint Vertex;
+ typedef CurvePoint Point;
+ typedef Point point_type;
+ typedef Vertex vertex_type;
+ typedef deque<Vertex*> vertex_container;
+
+ /* Iterator to iterate over a vertex edges */
+
+ typedef CurveInternal::__point_iterator<CurveInternal::CurvePoint_nonconst_traits > point_iterator;
+ typedef CurveInternal::__point_iterator<CurveInternal::CurvePoint_const_traits > const_point_iterator;
+ typedef point_iterator vertex_iterator ;
+ typedef const_point_iterator const_vertex_iterator ;
+
+protected:
+ vertex_container _Vertices;
+ double _Length;
+ Id _Id;
+ unsigned _nSegments; // number of segments
+
+public:
+ /*! Default Constructor. */
+ Curve()
+ {
+ _Length = 0;
+ _Id = 0;
+ _nSegments = 0;
+ }
+
+ /*! Builds a Curve from its id */
+ Curve(const Id& id)
+ {
+ _Length = 0;
+ _Id = id;
+ _nSegments = 0;
+ }
+
+ /*! Copy Constructor. */
+ Curve(const Curve& iBrother)
+ {
+ _Length = iBrother._Length;
+ _Vertices = iBrother._Vertices;
+ _Id = iBrother._Id;
+ _nSegments = 0;
+ }
+
+ /*! Destructor. */
+ virtual ~Curve();
+
+ /*! Returns the string "Curve" */
+ virtual string getExactTypeName() const
+ {
+ return "Curve";
+ }
+
+ /* fredo's curvature storage */
+ void computeCurvatureAndOrientation();
+
+ /*! Adds a single vertex (CurvePoint) at the end of the Curve */
+ inline void push_vertex_back(Vertex *iVertex)
+ {
+ if (!_Vertices.empty()) {
+ Vec3r vec_tmp(iVertex->point2d() - _Vertices.back()->point2d());
+ _Length += vec_tmp.norm();
+ ++_nSegments;
+ }
+ Vertex *new_vertex = new Vertex(*iVertex);
+ _Vertices.push_back(new_vertex);
+ }
+
+ /*! Adds a single vertex (SVertex) at the end of the Curve */
+ inline void push_vertex_back(SVertex *iVertex)
+ {
+ if (!_Vertices.empty()) {
+ Vec3r vec_tmp(iVertex->point2d() - _Vertices.back()->point2d());
+ _Length += vec_tmp.norm();
+ ++_nSegments;
+ }
+ Vertex *new_vertex = new Vertex(iVertex, 0, 0);
+ _Vertices.push_back(new_vertex);
+ }
+
+ /*! Adds a single vertex (CurvePoint) at the front of the Curve */
+ inline void push_vertex_front(Vertex *iVertex)
+ {
+ if (!_Vertices.empty()) {
+ Vec3r vec_tmp(iVertex->point2d() - _Vertices.front()->point2d());
+ _Length += vec_tmp.norm();
+ ++_nSegments;
+ }
+ Vertex *new_vertex = new Vertex(*iVertex);
+ _Vertices.push_front(new_vertex);
+ }
+
+ /*! Adds a single vertex (SVertex) at the front of the Curve */
+ inline void push_vertex_front(SVertex *iVertex)
+ {
+ if (!_Vertices.empty()) {
+ Vec3r vec_tmp(iVertex->point2d() - _Vertices.front()->point2d());
+ _Length += vec_tmp.norm();
+ ++_nSegments;
+ }
+ Vertex *new_vertex = new Vertex(iVertex, 0, 0);
+ _Vertices.push_front(new_vertex);
+ }
+
+ /*! Returns true is the Curve doesn't have any Vertex yet. */
+ inline bool empty() const
+ {
+ return _Vertices.empty();
+ }
+
+ /*! Returns the 2D length of the Curve. */
+ inline real getLength2D() const
+ {
+ return _Length;
+ }
+
+ /*! Returns the Id of the 1D element. */
+ virtual Id getId() const
+ {
+ return _Id;
+ }
+
+ /*! Returns the number of segments in the polyline constituing the Curve. */
+ inline unsigned int nSegments() const
+ {
+ return _nSegments;
+ }
+
+ inline void setId(const Id& id)
+ {
+ _Id = id;
+ }
+
+ /* Information access interface */
+
+#if 0
+ inline Vec3r shaded_color(int iCombination = 0) const;
+ inline Vec3r orientation2d(point_iterator it) const;
+ Vec3r orientation2d(int iCombination = 0) const;
+ Vec3r orientation3d(point_iterator it) const;
+ Vec3r orientation3d(int iCombination = 0) const;
+
+ real curvature2d(point_iterator it) const
+ {
+ return (*it)->curvature2d();
+ }
+
+ real curvature2d(int iCombination = 0) const;
+ FrsMaterial material() const;
+ int qi() const;
+ occluder_container::const_iterator occluders_begin() const;
+ occluder_container::const_iterator occluders_end() const;
+ int occluders_size() const;
+ bool occluders_empty() const;
+
+ const Polygon3r& occludee() const
+ {
+ return *(_FEdgeA->aFace());
+ }
+
+ const SShape *occluded_shape() const;
+ const bool occludee_empty() const;
+ real z_discontinuity(int iCombination = 0) const;
+ int shape_id() const;
+ const SShape *shape() const;
+ float shape_importance(int iCombination = 0) const;
+ float local_average_depth(int iCombination = 0) const;
+ float local_depth_variance(int iCombination = 0) const;
+ real local_average_density(float sigma = 2.3f, int iCombination = 0) const;
+ Vec3r curvature2d_as_vector(int iCombination = 0) const;
+ /*! angle in radians */
+ real curvature2d_as_angle(int iCombination = 0) const;
+#endif
+
+ /* advanced iterators access */
+ point_iterator points_begin(float step = 0);
+ const_point_iterator points_begin(float step = 0) const;
+ point_iterator points_end(float step = 0);
+ const_point_iterator points_end(float step = 0) const;
+
+ /* methods given for convenience */
+ point_iterator vertices_begin();
+ const_point_iterator vertices_begin() const;
+ point_iterator vertices_end();
+ const_point_iterator vertices_end() const;
+
+ // specialized iterators access
+ CurveInternal::CurvePointIterator curvePointsBegin(float t = 0.0f);
+ CurveInternal::CurvePointIterator curvePointsEnd(float t = 0.0f);
+
+ CurveInternal::CurvePointIterator curveVerticesBegin();
+ CurveInternal::CurvePointIterator curveVerticesEnd();
+
+ // Iterators access
+ /*! Returns an Interface0DIterator pointing onto the first vertex of the Curve and that can iterate
+ * over the \a vertices of the Curve.
+ */
+ virtual Interface0DIterator verticesBegin();
+
+ /*! Returns an Interface0DIterator pointing after the last vertex of the Curve and that can iterate
+ * over the \a vertices of the Curve.
+ */
+ virtual Interface0DIterator verticesEnd();
+
+ /*! Returns an Interface0DIterator pointing onto the first point of the Curve and that can iterate
+ * over the \a points of the Curve at any resolution.
+ * At each iteration a virtual temporary CurvePoint is created.
+ */
+ virtual Interface0DIterator pointsBegin(float t = 0.0f);
+
+ /*! Returns an Interface0DIterator pointing after the last point of the Curve and that can iterate
+ * over the \a points of the Curve at any resolution.
+ * At each iteration a virtual temporary CurvePoint is created.
+ */
+ virtual Interface0DIterator pointsEnd(float t = 0.0f);
+};
+
+#endif // __FREESTYLE_CURVE_H__
diff --git a/source/blender/freestyle/intern/stroke/CurveAdvancedIterators.h b/source/blender/freestyle/intern/stroke/CurveAdvancedIterators.h
new file mode 100644
index 00000000000..0c053bf1845
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/CurveAdvancedIterators.h
@@ -0,0 +1,383 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_CURVE_ADVANCED_ITERATORS_H__
+#define __FREESTYLE_CURVE_ADVANCED_ITERATORS_H__
+
+/** \file blender/freestyle/intern/stroke/CurveAdvancedIterators.h
+ * \ingroup freestyle
+ * \brief Iterators used to iterate over the elements of the Curve. Can't be used in python
+ * \author Stephane Grabli
+ * \date 01/08/2003
+ */
+
+#include "Stroke.h"
+
+namespace CurveInternal {
+
+class CurvePoint_const_traits : public Const_traits<CurvePoint*>
+{
+public:
+ typedef deque<CurvePoint*> vertex_container;
+ typedef vertex_container::const_iterator vertex_container_iterator;
+ typedef SVertex vertex_type;
+};
+
+class CurvePoint_nonconst_traits : public Nonconst_traits<CurvePoint*>
+{
+public:
+ typedef deque<CurvePoint*> vertex_container;
+ typedef vertex_container::iterator vertex_container_iterator;
+ typedef SVertex vertex_type;
+};
+
+/**********************************/
+/* */
+/* */
+/* CurvePoint Iterator */
+/* */
+/* */
+/**********************************/
+
+
+/*! iterator on a curve. Allows an iterating outside initial vertices. A CurvePoint is instanciated an returned
+ * when the iterator is dereferenced.
+ */
+template<class Traits>
+class __point_iterator : public IteratorBase<Traits, BidirectionalIteratorTag_Traits>
+{
+public:
+ typedef __point_iterator <Traits> Self;
+ typedef typename Traits::vertex_container_iterator vertex_container_iterator;
+ typedef typename Traits::vertex_type vertex_type;
+ typedef CurvePoint Point;
+ typedef Point point_type;
+
+ typedef __point_iterator<CurvePoint_nonconst_traits> iterator;
+ typedef __point_iterator<CurvePoint_const_traits> const_iterator;
+
+#if 0
+ typedef Vertex vertex_type ;
+ typedef vertex_container_iterator vertex_iterator_type;
+ typedef CurvePoint<Vertex> Point;
+ typedef Point point_type;
+#endif
+ typedef IteratorBase<Traits,BidirectionalIteratorTag_Traits> parent_class;
+#if 0
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ typedef bidirectional_iterator<CurvePoint<Vertex>, ptrdiff_t> bidirectional_point_iterator;
+#else
+ typedef iterator<bidirectional_iterator_tag, CurvePoint<Vertex>, ptrdiff_t> bidirectional_point_iterator;
+#endif
+#endif
+ friend class Curve;
+#if 0
+ friend class Curve::vertex_iterator;
+ friend class __point_iterator<CurvePoint_nonconst_traits>;
+ friend class iterator;
+#endif
+//protected:
+public:
+ float _CurvilinearLength;
+ float _step;
+ vertex_container_iterator __A;
+ vertex_container_iterator __B;
+ vertex_container_iterator _begin;
+ vertex_container_iterator _end;
+ int _n;
+ int _currentn;
+ float _t;
+ mutable Point *_Point;
+
+public:
+ inline __point_iterator(float step = 0.0f) : parent_class()
+ {
+ _step = step;
+ _CurvilinearLength = 0.0f;
+ _t = 0.0f;
+ _Point = 0;
+ _n = 0;
+ _currentn = 0;
+ }
+
+ inline __point_iterator(const iterator& iBrother) : parent_class()
+ {
+ __A = iBrother.__A;
+ __B = iBrother.__B;
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ _CurvilinearLength = iBrother._CurvilinearLength;
+ _step = iBrother._step;
+ _t = iBrother._t;
+ if (iBrother._Point == 0)
+ _Point = 0;
+ else
+ _Point = new Point(*(iBrother._Point));
+ _n = iBrother._n;
+ _currentn = iBrother._currentn;
+ }
+
+ inline __point_iterator(const const_iterator& iBrother) : parent_class()
+ {
+ __A = iBrother.__A;
+ __B = iBrother.__B;
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ _CurvilinearLength = iBrother._CurvilinearLength;
+ _step = iBrother._step;
+ _t = iBrother._t;
+ if (iBrother._Point == 0)
+ _Point = 0;
+ else
+ _Point = new Point(*(iBrother._Point));
+ _n = iBrother._n;
+ _currentn = iBrother._currentn;
+ }
+
+ inline Self& operator=(const Self& iBrother)
+ {
+ //((bidirectional_point_iterator*)this)->operator=(iBrother);
+ __A = iBrother.__A;
+ __B = iBrother.__B;
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ _CurvilinearLength = iBrother._CurvilinearLength;
+ _step = iBrother._step;
+ _t = iBrother._t;
+ if (iBrother._Point == 0)
+ _Point = 0;
+ else
+ _Point = new Point(*(iBrother._Point));
+ _n = iBrother._n;
+ _currentn = iBrother._currentn;
+ return *this;
+ }
+
+ virtual ~__point_iterator()
+ {
+ if (_Point != 0)
+ delete _Point;
+ }
+
+//protected: //FIXME
+public:
+ inline __point_iterator(vertex_container_iterator iA, vertex_container_iterator iB,
+ vertex_container_iterator ibegin, vertex_container_iterator iend,
+ int currentn, int n, float step, float t = 0.0f, float iCurvilinearLength = 0.0f)
+ : parent_class()
+ {
+ __A = iA;
+ __B = iB;
+ _begin = ibegin;
+ _end = iend;
+ _CurvilinearLength = iCurvilinearLength;
+ _step = step;
+ _t = t;
+ _Point = 0;
+ _n = n;
+ _currentn = currentn;
+ }
+
+public:
+ // operators
+ inline Self& operator++() // operator corresponding to ++i
+ {
+ increment();
+ return *this;
+ }
+
+ /* Operator corresponding to i++, i.e. it returns the value *and then* increments.
+ * That’s why we store the value in a temp.
+ */
+ inline Self operator++(int)
+ {
+ Self tmp = *this;
+ increment();
+ return tmp;
+ }
+
+ inline Self& operator--() // operator corresponding to --i
+ {
+ decrement();
+ return *this;
+ }
+
+ inline Self operator--(int) // operator corresponding to i--
+ {
+ Self tmp = *this;
+ decrement();
+ return tmp;
+ }
+
+ // comparibility
+ virtual bool operator!=(const Self& b) const
+ {
+ return ((__A != b.__A) || (__B != b.__B) || (_t != b._t));
+ }
+
+ virtual bool operator==(const Self& b) const
+ {
+ return !(*this != b);
+ }
+
+ // dereferencing
+ virtual typename Traits::reference operator*() const
+ {
+ if (_Point != 0) {
+ delete _Point;
+ _Point = 0;
+ }
+ if ((_currentn < 0) || (_currentn >= _n))
+ return _Point; // 0 in this case
+ return (_Point = new Point(*__A, *__B, _t));
+ }
+
+ virtual typename Traits::pointer operator->() const
+ {
+ return &(operator*());
+ }
+
+ virtual bool begin() const
+ {
+ if ((__A == _begin) && (_t < (float)M_EPSILON))
+ return true;
+ return false;
+ }
+
+ virtual bool end() const
+ {
+ if ((__B == _end))
+ return true;
+ return false;
+ }
+
+protected:
+ virtual void increment()
+ {
+ if (_Point != 0) {
+ delete _Point;
+ _Point = 0;
+ }
+ if ((_currentn == _n - 1) && (_t == 1.0f)) {
+ // we're setting the iterator to end
+ ++__A;
+ ++__B;
+ ++_currentn;
+ _t = 0.0f;
+ return;
+ }
+
+ if (0 == _step) { // means we iterate over initial vertices
+ Vec3r vec_tmp((*__B)->point2d() - (*__A)->point2d());
+ _CurvilinearLength += vec_tmp.norm();
+ if (_currentn == _n-1) {
+ _t = 1.0f;
+ return;
+ }
+ ++__B;
+ ++__A;
+ ++_currentn;
+ return;
+ }
+
+ // compute the new position:
+ Vec3r vec_tmp2((*__A)->point2d() - (*__B)->point2d());
+ float normAB = vec_tmp2.norm();
+
+ if (normAB > M_EPSILON) {
+ _CurvilinearLength += _step;
+ _t = _t + _step / normAB;
+ }
+ else {
+ _t = 1.0f; // AB is a null segment, we're directly at its end
+ }
+ //if normAB ~= 0, we don't change these values
+ if (_t >= 1) {
+ _CurvilinearLength -= normAB * (_t - 1);
+ if (_currentn == _n - 1) {
+ _t = 1.0f;
+ }
+ else {
+ _t = 0.0f;
+ ++_currentn;
+ ++__A;
+ ++__B;
+ }
+ }
+ }
+
+ virtual void decrement()
+ {
+ if (_Point != 0) {
+ delete _Point;
+ _Point = 0;
+ }
+
+ if (_t == 0.0f) { // we're at the beginning of the edge
+ _t = 1.0f;
+ --_currentn;
+ --__A;
+ --__B;
+ if (_currentn == _n - 1)
+ return;
+ }
+
+ if (0 == _step) { // means we iterate over initial vertices
+ Vec3r vec_tmp((*__B)->point2d() - (*__A)->point2d());
+ _CurvilinearLength -= vec_tmp.norm();
+ _t = 0;
+ return;
+ }
+
+ // compute the new position:
+ Vec3r vec_tmp2((*__A)->point2d() - (*__B)->point2d());
+ float normAB = vec_tmp2.norm();
+
+ if (normAB >M_EPSILON) {
+ _CurvilinearLength -= _step;
+ _t = _t - _step / normAB;
+ }
+ else {
+ _t = -1.0f; // We just need a negative value here
+ }
+
+ // round value
+ if (fabs(_t) < (float)M_EPSILON)
+ _t = 0.0f;
+ if (_t < 0) {
+ if (_currentn == 0)
+ _CurvilinearLength = 0.0f;
+ else
+ _CurvilinearLength += normAB * (-_t);
+ _t = 0.0f;
+ }
+ }
+};
+
+} // end of namespace CurveInternal
+
+#endif // __FREESTYLE_CURVE_ADVANCED_ITERATORS_H__
diff --git a/source/blender/freestyle/intern/stroke/CurveIterators.h b/source/blender/freestyle/intern/stroke/CurveIterators.h
new file mode 100644
index 00000000000..7d9e0e00ef1
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/CurveIterators.h
@@ -0,0 +1,302 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_CURVE_ITERATORS_H__
+#define __FREESTYLE_CURVE_ITERATORS_H__
+
+/** \file blender/freestyle/intern/stroke/CurveIterators.h
+ * \ingroup freestyle
+ * \brief Iterators used to iterate over the elements of the Curve
+ * \author Stephane Grabli
+ * \date 01/08/2003
+ */
+
+#include "Curve.h"
+#include "Stroke.h"
+
+namespace CurveInternal {
+
+/*! iterator on a curve. Allows an iterating outside
+* initial vertices. A CurvePoint is instanciated an returned
+* when the iterator is dereferenced.
+*/
+
+class CurvePointIterator : public Interface0DIteratorNested
+{
+public:
+ friend class ::Curve;
+
+public:
+ float _CurvilinearLength;
+ float _step;
+ ::Curve::vertex_container::iterator __A;
+ ::Curve::vertex_container::iterator __B;
+ ::Curve::vertex_container::iterator _begin;
+ ::Curve::vertex_container::iterator _end;
+ int _n;
+ int _currentn;
+ float _t;
+ mutable CurvePoint _Point;
+ float _CurveLength;
+
+public:
+ inline CurvePointIterator(float step = 0.0f) : Interface0DIteratorNested()
+ {
+ _step = step;
+ _CurvilinearLength = 0.0f;
+ _t = 0.0f;
+ //_Point = 0;
+ _n = 0;
+ _currentn = 0;
+ _CurveLength = 0;
+ }
+
+ inline CurvePointIterator(const CurvePointIterator& iBrother) : Interface0DIteratorNested()
+ {
+ __A = iBrother.__A;
+ __B = iBrother.__B;
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ _CurvilinearLength = iBrother._CurvilinearLength;
+ _step = iBrother._step;
+ _t = iBrother._t;
+ _Point = iBrother._Point;
+ _n = iBrother._n;
+ _currentn = iBrother._currentn;
+ _CurveLength = iBrother._CurveLength;
+ }
+
+ inline CurvePointIterator& operator=(const CurvePointIterator& iBrother)
+ {
+ __A = iBrother.__A;
+ __B = iBrother.__B;
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ _CurvilinearLength = iBrother._CurvilinearLength;
+ _step = iBrother._step;
+ _t = iBrother._t;
+ _Point = iBrother._Point;
+ _n = iBrother._n;
+ _currentn = iBrother._currentn;
+ _CurveLength = iBrother._CurveLength;
+ return *this;
+ }
+
+ virtual ~CurvePointIterator() {}
+
+protected:
+ inline CurvePointIterator(::Curve::vertex_container::iterator iA, ::Curve::vertex_container::iterator iB,
+ ::Curve::vertex_container::iterator ibegin, ::Curve::vertex_container::iterator iend,
+ int currentn, int n, float iCurveLength, float step, float t = 0.0f,
+ float iCurvilinearLength = 0.0f)
+ : Interface0DIteratorNested()
+ {
+ __A = iA;
+ __B = iB;
+ _begin = ibegin;
+ _end = iend;
+ _CurvilinearLength = iCurvilinearLength;
+ _step = step;
+ _t = t;
+ _n = n;
+ _currentn = currentn;
+ _CurveLength = iCurveLength;
+ }
+
+public:
+ virtual CurvePointIterator* copy() const
+ {
+ return new CurvePointIterator(*this);
+ }
+
+ inline Interface0DIterator castToInterface0DIterator() const
+ {
+ Interface0DIterator ret(new CurveInternal::CurvePointIterator(*this));
+ return ret;
+ }
+
+ virtual string getExactTypeName() const
+ {
+ return "CurvePointIterator";
+ }
+
+ // operators
+ inline CurvePointIterator& operator++() // operator corresponding to ++i
+ {
+ increment();
+ return *this;
+ }
+
+ inline CurvePointIterator& operator--() // operator corresponding to --i
+ {
+ decrement();
+ return *this;
+ }
+
+ // comparibility
+ virtual bool operator==(const Interface0DIteratorNested& b) const
+ {
+ const CurvePointIterator* it_exact = dynamic_cast<const CurvePointIterator*>(&b);
+ if (!it_exact)
+ return false;
+ return ((__A == it_exact->__A) && (__B == it_exact->__B) && (_t == it_exact->_t));
+ }
+
+ // dereferencing
+ virtual CurvePoint& operator*()
+ {
+ return (_Point = CurvePoint(*__A, *__B, _t));
+ }
+
+ virtual CurvePoint* operator->()
+ {
+ return &(operator*());
+ }
+
+ virtual bool isBegin() const
+ {
+ if ((__A == _begin) && (_t < (float)M_EPSILON))
+ return true;
+ return false;
+ }
+
+ virtual bool isEnd() const
+ {
+ if (__B == _end)
+ return true;
+ return false;
+ }
+
+//protected:
+ virtual int increment()
+ {
+ if ((_currentn == _n - 1) && (_t == 1.0f)) {
+ // we're setting the iterator to end
+ ++__A;
+ ++__B;
+ ++_currentn;
+ _t = 0.0f;
+ return 0;
+ }
+
+ if (0 == _step) { // means we iterate over initial vertices
+ Vec3r vec_tmp((*__B)->point2d() - (*__A)->point2d());
+ _CurvilinearLength += (float)vec_tmp.norm();
+ if (_currentn == _n - 1) {
+ _t = 1.0f;
+ return 0;
+ }
+ ++__B;
+ ++__A;
+ ++_currentn;
+ return 0;
+ }
+
+ // compute the new position:
+ Vec3r vec_tmp2((*__A)->point2d() - (*__B)->point2d());
+ float normAB = (float)vec_tmp2.norm();
+
+ if (normAB > M_EPSILON) {
+ _CurvilinearLength += _step;
+ _t = _t + _step / normAB;
+ }
+ else {
+ _t = 1.0f; // AB is a null segment, we're directly at its end
+ }
+ //if normAB ~= 0, we don't change these values
+ if (_t >= 1) {
+ _CurvilinearLength -= normAB * (_t - 1);
+ if (_currentn == _n - 1) {
+ _t = 1.0f;
+ }
+ else {
+ _t = 0.0f;
+ ++_currentn;
+ ++__A;
+ ++__B;
+ }
+ }
+ return 0;
+ }
+
+ virtual int decrement()
+ {
+ if (_t == 0.0f) { //we're at the beginning of the edge
+ _t = 1.0f;
+ --_currentn;
+ --__A;
+ --__B;
+ if (_currentn == _n - 1)
+ return 0;
+ }
+
+ if (0 == _step) { // means we iterate over initial vertices
+ Vec3r vec_tmp((*__B)->point2d() - (*__A)->point2d());
+ _CurvilinearLength -= (float)vec_tmp.norm();
+ _t = 0;
+ return 0;
+ }
+
+ // compute the new position:
+ Vec3r vec_tmp2((*__A)->point2d() - (*__B)->point2d());
+ float normAB = (float)vec_tmp2.norm();
+
+ if (normAB > M_EPSILON) {
+ _CurvilinearLength -= _step;
+ _t = _t - _step / normAB;
+ }
+ else {
+ _t = -1.0f; // We just need a negative value here
+ }
+
+ // round value
+ if (fabs(_t) < (float)M_EPSILON)
+ _t = 0.0f;
+ if (_t < 0) {
+ if (_currentn == 0)
+ _CurvilinearLength = 0.0f;
+ else
+ _CurvilinearLength += normAB * (-_t);
+ _t = 0.0f;
+ }
+ return 0;
+ }
+
+ virtual float t() const
+ {
+ return _CurvilinearLength;
+ }
+
+ virtual float u() const
+ {
+ return _CurvilinearLength / _CurveLength;
+ }
+};
+
+} // end of namespace CurveInternal
+
+#endif // __FREESTYLE_CURVE_ITERATORS_H__
diff --git a/source/blender/freestyle/intern/stroke/Modifiers.h b/source/blender/freestyle/intern/stroke/Modifiers.h
new file mode 100644
index 00000000000..daa02002b7b
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Modifiers.h
@@ -0,0 +1,74 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_MODIFIERS_H__
+#define __FREESTYLE_MODIFIERS_H__
+
+/** \file blender/freestyle/intern/stroke/Modifiers.h
+ * \ingroup freestyle
+ * \brief modifiers...
+ * \author Stephane Grabli
+ * \date 05/01/2003
+ */
+
+#include "TimeStamp.h"
+
+/* ----------------------------------------- *
+ * *
+ * modifiers *
+ * *
+ * ----------------------------------------- */
+
+/*! Base class for modifiers.
+ * Modifiers are used in the Operators in order to "mark" the processed Interface1D.
+ */
+template<class Edge>
+struct EdgeModifier : public unary_function<Edge, void>
+{
+ /*! Default construction */
+ EdgeModifier() : unary_function<Edge, void>() {}
+
+ /*! the () operator */
+ virtual void operator()(Edge& iEdge) {}
+};
+
+/*! Modifier that sets the time stamp of an Interface1D to the time stamp of the system. */
+template<class Edge>
+struct TimestampModifier : public EdgeModifier<Edge>
+{
+ /*! Default constructor */
+ TimestampModifier() : EdgeModifier<Edge>() {}
+
+ /*! The () operator. */
+ virtual void operator()(Edge& iEdge)
+ {
+ TimeStamp *timestamp = TimeStamp::instance();
+ iEdge.setTimeStamp(timestamp->getTimeStamp());
+ }
+};
+
+#endif // MODIFIERS_H
diff --git a/source/blender/freestyle/intern/stroke/Module.h b/source/blender/freestyle/intern/stroke/Module.h
new file mode 100644
index 00000000000..da6708e6ea9
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Module.h
@@ -0,0 +1,82 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_MODULE_H__
+#define __FREESTYLE_MODULE_H__
+
+/** \file blender/freestyle/intern/stroke/Module.h
+ * \ingroup freestyle
+ * \brief Set the type of the module
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include "Canvas.h"
+#include "StyleModule.h"
+
+class Module
+{
+public:
+ static void setAlwaysRefresh(bool b = true)
+ {
+ getCurrentStyleModule()->setAlwaysRefresh(b);
+ }
+
+ static void setCausal(bool b = true)
+ {
+ getCurrentStyleModule()->setCausal(b);
+ }
+
+ static void setDrawable(bool b = true)
+ {
+ getCurrentStyleModule()->setDrawable(b);
+ }
+
+ static bool getAlwaysRefresh()
+ {
+ return getCurrentStyleModule()->getAlwaysRefresh();
+ }
+
+ static bool getCausal()
+ {
+ return getCurrentStyleModule()->getCausal();
+ }
+
+ static bool getDrawable()
+ {
+ return getCurrentStyleModule()->getDrawable();
+ }
+
+private:
+ static StyleModule* getCurrentStyleModule()
+ {
+ Canvas *canvas = Canvas::getInstance();
+ return canvas->getCurrentStyleModule();
+ }
+};
+
+#endif // __FREESTYLE_MODULE_H__
diff --git a/source/blender/freestyle/intern/stroke/Operators.cpp b/source/blender/freestyle/intern/stroke/Operators.cpp
new file mode 100644
index 00000000000..e35a811fcab
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Operators.cpp
@@ -0,0 +1,1286 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/Operators.cpp
+ * \ingroup freestyle
+ * \brief Class gathering stroke creation algorithms
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include <algorithm>
+#include <stdexcept>
+
+#include "Operators.h"
+#include "Canvas.h"
+#include "Stroke.h"
+
+#include "BKE_global.h"
+
+LIB_STROKE_EXPORT Operators::I1DContainer Operators::_current_view_edges_set;
+LIB_STROKE_EXPORT Operators::I1DContainer Operators::_current_chains_set;
+LIB_STROKE_EXPORT Operators::I1DContainer *Operators::_current_set = NULL;
+LIB_STROKE_EXPORT Operators::StrokesContainer Operators::_current_strokes_set;
+
+int Operators::select(UnaryPredicate1D& pred)
+{
+ if (!_current_set)
+ return 0;
+ if (_current_set->empty())
+ return 0;
+ I1DContainer new_set;
+ I1DContainer rejected;
+ Functions1D::ChainingTimeStampF1D cts;
+ Functions1D::TimeStampF1D ts;
+ I1DContainer::iterator it = _current_set->begin();
+ I1DContainer::iterator itbegin = it;
+ while (it != _current_set->end()) {
+ Interface1D *i1d = *it;
+ cts(*i1d); // mark everyone's chaining time stamp anyway
+ if (pred(*i1d) < 0) {
+ new_set.clear();
+ rejected.clear();
+ return -1;
+ }
+ if (pred.result) {
+ new_set.push_back(i1d);
+ ts(*i1d);
+ }
+ else {
+ rejected.push_back(i1d);
+ }
+ ++it;
+ }
+ if ((*itbegin)->getExactTypeName() != "ViewEdge") {
+ for (it = rejected.begin(); it != rejected.end(); ++it)
+ delete *it;
+ }
+ rejected.clear();
+ _current_set->clear();
+ *_current_set = new_set;
+ return 0;
+}
+
+
+int Operators::chain(ViewEdgeInternal::ViewEdgeIterator& it, UnaryPredicate1D& pred, UnaryFunction1D_void& modifier)
+{
+ if (_current_view_edges_set.empty())
+ return 0;
+
+ unsigned id = 0;
+ ViewEdge *edge;
+ I1DContainer new_chains_set;
+
+ for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
+ it_edge != _current_view_edges_set.end();
+ ++it_edge)
+ {
+ if (pred(**it_edge) < 0)
+ goto error;
+ if (pred.result)
+ continue;
+
+ edge = dynamic_cast<ViewEdge*>(*it_edge);
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+
+ Chain *new_chain = new Chain(id);
+ ++id;
+ while (TRUE) {
+ new_chain->push_viewedge_back(*it, it.getOrientation());
+ if (modifier(**it) < 0) {
+ delete new_chain;
+ goto error;
+ }
+ ++it;
+ if (it.isEnd())
+ break;
+ if (pred(**it) < 0) {
+ delete new_chain;
+ goto error;
+ }
+ if (pred.result)
+ break;
+ }
+ new_chains_set.push_back(new_chain);
+ }
+
+ if (!new_chains_set.empty()) {
+ for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
+ _current_chains_set.push_back(*it);
+ }
+ new_chains_set.clear();
+ _current_set = &_current_chains_set;
+ }
+ return 0;
+
+error:
+ for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
+ delete (*it);
+ }
+ new_chains_set.clear();
+ return -1;
+}
+
+
+int Operators::chain(ViewEdgeInternal::ViewEdgeIterator& it, UnaryPredicate1D& pred)
+{
+ if (_current_view_edges_set.empty())
+ return 0;
+
+ unsigned id = 0;
+ Functions1D::IncrementChainingTimeStampF1D ts;
+ Predicates1D::EqualToChainingTimeStampUP1D pred_ts(TimeStamp::instance()->getTimeStamp() + 1);
+ ViewEdge *edge;
+ I1DContainer new_chains_set;
+
+ for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
+ it_edge != _current_view_edges_set.end();
+ ++it_edge)
+ {
+ if (pred(**it_edge) < 0)
+ goto error;
+ if (pred.result)
+ continue;
+ if (pred_ts(**it_edge) < 0)
+ goto error;
+ if (pred_ts.result)
+ continue;
+
+ edge = dynamic_cast<ViewEdge*>(*it_edge);
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+
+ Chain *new_chain = new Chain(id);
+ ++id;
+ while (TRUE) {
+ new_chain->push_viewedge_back(*it, it.getOrientation());
+ ts(**it);
+ ++it;
+ if (it.isEnd())
+ break;
+ if (pred(**it) < 0) {
+ delete new_chain;
+ goto error;
+ }
+ if (pred.result)
+ break;
+ if (pred_ts(**it) < 0) {
+ delete new_chain;
+ goto error;
+ }
+ if (pred_ts.result)
+ break;
+ }
+ new_chains_set.push_back(new_chain);
+ }
+
+ if (!new_chains_set.empty()) {
+ for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
+ _current_chains_set.push_back(*it);
+ }
+ new_chains_set.clear();
+ _current_set = &_current_chains_set;
+ }
+ return 0;
+
+error:
+ for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
+ delete (*it);
+ }
+ new_chains_set.clear();
+ return -1;
+}
+
+
+#if 0
+void Operators::bidirectionalChain(ViewEdgeIterator& it, UnaryPredicate1D& pred, UnaryFunction1D_void& modifier)
+{
+ if (_current_view_edges_set.empty())
+ return;
+
+ unsigned id = 0;
+ ViewEdge *edge;
+ Chain *new_chain;
+
+ for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
+ it_edge != _current_view_edges_set.end();
+ ++it_edge)
+ {
+ if (pred(**it_edge))
+ continue;
+
+ edge = dynamic_cast<ViewEdge*>(*it_edge);
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+
+ Chain *new_chain = new Chain(id);
+ ++id;
+#if 0 // FIXME
+ ViewEdgeIterator it_back(it);
+ --it_back;
+#endif
+ do {
+ new_chain->push_viewedge_back(*it, it.getOrientation());
+ modifier(**it);
+ ++it;
+ } while (!it.isEnd() && !pred(**it));
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+ --it;
+ while (!it.isEnd() && !pred(**it)) {
+ new_chain->push_viewedge_front(*it, it.getOrientation());
+ modifier(**it);
+ --it;
+ }
+
+ _current_chains_set.push_back(new_chain);
+ }
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+}
+
+void Operators::bidirectionalChain(ViewEdgeIterator& it, UnaryPredicate1D& pred)
+{
+ if (_current_view_edges_set.empty())
+ return;
+
+ unsigned id = 0;
+ Functions1D::IncrementChainingTimeStampF1D ts;
+ Predicates1D::EqualToChainingTimeStampUP1D pred_ts(TimeStamp::instance()->getTimeStamp() + 1);
+
+ ViewEdge *edge;
+ Chain *new_chain;
+
+ for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
+ it_edge != _current_view_edges_set.end();
+ ++it_edge)
+ {
+ if (pred(**it_edge) || pred_ts(**it_edge))
+ continue;
+
+ edge = dynamic_cast<ViewEdge*>(*it_edge);
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+
+ Chain *new_chain = new Chain(id);
+ ++id;
+#if 0 //FIXME
+ ViewEdgeIterator it_back(it);
+ --it_back;
+#endif
+ do {
+ new_chain->push_viewedge_back(*it, it.getOrientation());
+ ts(**it);
+ ++it;
+ } while (!it.isEnd() && !pred(**it) && !pred_ts(**it));
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+ --it;
+ while (!it.isEnd() && !pred(**it) && !pred_ts(**it)) {
+ new_chain->push_viewedge_front(*it, it.getOrientation());
+ ts(**it);
+ --it;
+ }
+
+ _current_chains_set.push_back(new_chain);
+ }
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+}
+#endif
+
+int Operators::bidirectionalChain(ChainingIterator& it, UnaryPredicate1D& pred)
+{
+ if (_current_view_edges_set.empty())
+ return 0;
+
+ unsigned id = 0;
+ Functions1D::IncrementChainingTimeStampF1D ts;
+ Predicates1D::EqualToChainingTimeStampUP1D pred_ts(TimeStamp::instance()->getTimeStamp() + 1);
+ ViewEdge *edge;
+ I1DContainer new_chains_set;
+
+ for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
+ it_edge != _current_view_edges_set.end();
+ ++it_edge)
+ {
+ if (pred(**it_edge) < 0)
+ goto error;
+ if (pred.result)
+ continue;
+ if (pred_ts(**it_edge) < 0)
+ goto error;
+ if (pred_ts.result)
+ continue;
+
+ edge = dynamic_cast<ViewEdge*>(*it_edge);
+ // re-init iterator
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+ it.setOrientation(true);
+ if (it.init() < 0)
+ goto error;
+
+ Chain *new_chain = new Chain(id);
+ ++id;
+#if 0 // FIXME
+ ViewEdgeIterator it_back(it);
+ --it_back;
+#endif
+ while (TRUE) {
+ new_chain->push_viewedge_back(*it, it.getOrientation());
+ ts(**it);
+ if (it.increment() < 0) {
+ delete new_chain;
+ goto error;
+ }
+ if (it.isEnd())
+ break;
+ if (pred(**it) < 0) {
+ delete new_chain;
+ goto error;
+ }
+ if (pred.result)
+ break;
+ }
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+ it.setOrientation(true);
+ if (it.decrement() < 0) {
+ delete new_chain;
+ goto error;
+ }
+ while (!it.isEnd()) {
+ if (pred(**it) < 0) {
+ delete new_chain;
+ goto error;
+ }
+ if (pred.result)
+ break;
+ new_chain->push_viewedge_front(*it, it.getOrientation());
+ ts(**it);
+ if (it.decrement() < 0) {
+ delete new_chain;
+ goto error;
+ }
+ }
+ new_chains_set.push_back(new_chain);
+ }
+
+ if (!new_chains_set.empty()) {
+ for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
+ _current_chains_set.push_back(*it);
+ }
+ new_chains_set.clear();
+ _current_set = &_current_chains_set;
+ }
+ return 0;
+
+error:
+ for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
+ delete (*it);
+ }
+ new_chains_set.clear();
+ return -1;
+}
+
+int Operators::bidirectionalChain(ChainingIterator& it)
+{
+ if (_current_view_edges_set.empty())
+ return 0;
+
+ unsigned id = 0;
+ Functions1D::IncrementChainingTimeStampF1D ts;
+ Predicates1D::EqualToChainingTimeStampUP1D pred_ts(TimeStamp::instance()->getTimeStamp() + 1);
+ ViewEdge *edge;
+ I1DContainer new_chains_set;
+
+ for (I1DContainer::iterator it_edge = _current_view_edges_set.begin();
+ it_edge != _current_view_edges_set.end();
+ ++it_edge)
+ {
+ if (pred_ts(**it_edge) < 0)
+ goto error;
+ if (pred_ts.result)
+ continue;
+
+ edge = dynamic_cast<ViewEdge*>(*it_edge);
+ // re-init iterator
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+ it.setOrientation(true);
+ if (it.init() < 0)
+ goto error;
+
+ Chain *new_chain = new Chain(id);
+ ++id;
+#if 0 // FIXME
+ ViewEdgeIterator it_back(it);
+ --it_back;
+#endif
+ do {
+ new_chain->push_viewedge_back(*it, it.getOrientation());
+ ts(**it);
+ if (it.increment() < 0) { // FIXME
+ delete new_chain;
+ goto error;
+ }
+ } while (!it.isEnd());
+ it.setBegin(edge);
+ it.setCurrentEdge(edge);
+ it.setOrientation(true);
+ if (it.decrement() < 0) { // FIXME
+ delete new_chain;
+ goto error;
+ }
+ while (!it.isEnd()) {
+ new_chain->push_viewedge_front(*it, it.getOrientation());
+ ts(**it);
+ if (it.decrement() < 0) { // FIXME
+ delete new_chain;
+ goto error;
+ }
+ }
+ new_chains_set.push_back(new_chain);
+ }
+
+ if (!new_chains_set.empty()) {
+ for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
+ _current_chains_set.push_back(*it);
+ }
+ new_chains_set.clear();
+ _current_set = &_current_chains_set;
+ }
+ return 0;
+
+error:
+ for (I1DContainer::iterator it = new_chains_set.begin(); it != new_chains_set.end(); ++it) {
+ delete (*it);
+ }
+ new_chains_set.clear();
+ return -1;
+}
+
+int Operators::sequentialSplit(UnaryPredicate0D& pred, float sampling)
+{
+ if (_current_chains_set.empty()) {
+ cerr << "Warning: current set empty" << endl;
+ return 0;
+ }
+ CurvePoint *point;
+ Chain *new_curve;
+ I1DContainer splitted_chains;
+ Interface0DIterator first;
+ Interface0DIterator end;
+ Interface0DIterator last;
+ Interface0DIterator it;
+ I1DContainer::iterator cit = _current_chains_set.begin(), citend = _current_chains_set.end();
+ for (; cit != citend; ++cit) {
+ Id currentId = (*cit)->getId();
+ new_curve = new Chain(currentId);
+ first = (*cit)->pointsBegin(sampling);
+ end = (*cit)->pointsEnd(sampling);
+ last = end;
+ --last;
+ it = first;
+
+ point = dynamic_cast<CurvePoint*>(&(*it));
+ new_curve->push_vertex_back(point);
+ ++it;
+ for (; it!= end; ++it) {
+ point = dynamic_cast<CurvePoint*>(&(*it));
+ new_curve->push_vertex_back(point);
+ if (pred(it) < 0) {
+ delete new_curve;
+ goto error;
+ }
+ if (pred.result && (it != last)) {
+ splitted_chains.push_back(new_curve);
+ currentId.setSecond(currentId.getSecond() + 1);
+ new_curve = new Chain(currentId);
+ new_curve->push_vertex_back(point);
+ }
+ }
+ if (new_curve->nSegments() == 0) {
+ delete new_curve;
+ return 0;
+ }
+
+ splitted_chains.push_back(new_curve);
+ }
+
+ // Update the current set of chains:
+ cit = _current_chains_set.begin();
+ for (; cit != citend; ++cit) {
+ delete (*cit);
+ }
+ _current_chains_set.clear();
+#if 0
+ _current_chains_set = splitted_chains;
+#else
+ for (cit = splitted_chains.begin(), citend = splitted_chains.end(); cit != citend; ++cit) {
+ if ((*cit)->getLength2D() < M_EPSILON) {
+ delete (*cit);
+ continue;
+ }
+ _current_chains_set.push_back(*cit);
+ }
+#endif
+ splitted_chains.clear();
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+ return 0;
+
+error:
+ cit = splitted_chains.begin();
+ citend = splitted_chains.end();
+ for (; cit != citend; ++cit) {
+ delete (*cit);
+ }
+ splitted_chains.clear();
+ return -1;
+}
+
+int Operators::sequentialSplit(UnaryPredicate0D& startingPred, UnaryPredicate0D& stoppingPred, float sampling)
+{
+ if (_current_chains_set.empty()) {
+ cerr << "Warning: current set empty" << endl;
+ return 0;
+ }
+ CurvePoint *point;
+ Chain *new_curve;
+ I1DContainer splitted_chains;
+ Interface0DIterator first;
+ Interface0DIterator end;
+ Interface0DIterator last;
+ Interface0DIterator itStart;
+ Interface0DIterator itStop;
+ I1DContainer::iterator cit = _current_chains_set.begin(), citend = _current_chains_set.end();
+ for (; cit != citend; ++cit) {
+ Id currentId = (*cit)->getId();
+ first = (*cit)->pointsBegin(sampling);
+ end = (*cit)->pointsEnd(sampling);
+ last = end;
+ --last;
+ itStart = first;
+ do {
+ itStop = itStart;
+ ++itStop;
+
+ new_curve = new Chain(currentId);
+ currentId.setSecond(currentId.getSecond() + 1);
+
+ point = dynamic_cast<CurvePoint*>(&(*itStart));
+ new_curve->push_vertex_back(point);
+ do {
+ point = dynamic_cast<CurvePoint*>(&(*itStop));
+ new_curve->push_vertex_back(point);
+ ++itStop;
+ if (itStop == end)
+ break;
+ if (stoppingPred(itStop) < 0) {
+ delete new_curve;
+ goto error;
+ }
+ } while (!stoppingPred.result);
+ if (itStop != end) {
+ point = dynamic_cast<CurvePoint*>(&(*itStop));
+ new_curve->push_vertex_back(point);
+ }
+ if (new_curve->nSegments() == 0) {
+ delete new_curve;
+ }
+ else {
+ splitted_chains.push_back(new_curve);
+ }
+ // find next start
+ do{
+ ++itStart;
+ if (itStart == end)
+ break;
+ if (startingPred(itStart) < 0)
+ goto error;
+ } while (!startingPred.result);
+ } while ((itStart!=end) && (itStart!=last));
+ }
+
+ // Update the current set of chains:
+ cit = _current_chains_set.begin();
+ for (; cit != citend; ++cit) {
+ delete (*cit);
+ }
+ _current_chains_set.clear();
+#if 0
+ _current_chains_set = splitted_chains;
+#else
+ for (cit = splitted_chains.begin(), citend = splitted_chains.end(); cit != citend; ++cit) {
+ if ((*cit)->getLength2D() < M_EPSILON) {
+ delete (*cit);
+ continue;
+ }
+ _current_chains_set.push_back(*cit);
+ }
+#endif
+ splitted_chains.clear();
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+ return 0;
+
+error:
+ cit = splitted_chains.begin();
+ citend = splitted_chains.end();
+ for (; cit != citend; ++cit) {
+ delete (*cit);
+ }
+ splitted_chains.clear();
+ return -1;
+}
+
+#include "CurveIterators.h"
+
+// Internal function
+static int __recursiveSplit(Chain *_curve, UnaryFunction0D<double>& func, UnaryPredicate1D& pred, float sampling,
+ Operators::I1DContainer& newChains, Operators::I1DContainer& splitted_chains)
+{
+ if (((_curve->nSegments() == 1) && (sampling == 0)) || (_curve->getLength2D() <= sampling)) {
+ newChains.push_back(_curve);
+ return 0;
+ }
+
+ CurveInternal::CurvePointIterator first = _curve->curvePointsBegin(sampling);
+ CurveInternal::CurvePointIterator second = first;
+ ++second;
+ CurveInternal::CurvePointIterator end = _curve->curvePointsEnd(sampling);
+ CurveInternal::CurvePointIterator it = second;
+ CurveInternal::CurvePointIterator split = second;
+ Interface0DIterator it0d = it.castToInterface0DIterator();
+ real _min = FLT_MAX; // func(it0d);
+ ++it;
+ CurveInternal::CurvePointIterator next = it;
+ ++next;
+
+ bool bsplit = false;
+ for (; ((it != end) && (next != end)); ++it, ++next) {
+ it0d = it.castToInterface0DIterator();
+ if (func(it0d) < 0)
+ return -1;
+ if (func.result < _min) {
+ _min = func.result;
+ split = it;
+ bsplit = true;
+ }
+ }
+
+ if (!bsplit) { // we didn't find any minimum
+ newChains.push_back(_curve);
+ return 0;
+ }
+
+ // retrieves the current splitting id
+ Id *newId = _curve->getSplittingId();
+ if (newId == 0) {
+ newId = new Id(_curve->getId());
+ _curve->setSplittingId(newId);
+ }
+
+ Chain *new_curve_a = new Chain(*newId);
+ newId->setSecond(newId->getSecond() + 1);
+ new_curve_a->setSplittingId(newId);
+ Chain *new_curve_b = new Chain(*newId);
+ newId->setSecond(newId->getSecond() + 1);
+ new_curve_b->setSplittingId(newId);
+
+ CurveInternal::CurvePointIterator vit = _curve->curveVerticesBegin(), vitend = _curve->curveVerticesEnd();
+ CurveInternal::CurvePointIterator vnext = vit;
+ ++vnext;
+
+ for (; (vit != vitend) && (vnext != vitend) && (vnext._CurvilinearLength < split._CurvilinearLength);
+ ++vit, ++vnext)
+ {
+ new_curve_a->push_vertex_back(&(*vit));
+ }
+ if ((vit == vitend) || (vnext == vitend)) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "The split takes place in bad location" << endl;
+ }
+ newChains.push_back(_curve);
+ delete new_curve_a;
+ delete new_curve_b;
+ return 0;
+ }
+
+ // build the two resulting chains
+ new_curve_a->push_vertex_back(&(*vit));
+ new_curve_a->push_vertex_back(&(*split));
+ new_curve_b->push_vertex_back(&(*split));
+
+ for (vit = vnext; vit != vitend; ++vit)
+ new_curve_b->push_vertex_back(&(*vit));
+
+ // let's check whether one or two of the two new curves satisfy the stopping condition or not.
+ // (if one of them satisfies it, we don't split)
+ if (pred(*new_curve_a) < 0 || (!pred.result && pred(*new_curve_b) < 0)) {
+ delete new_curve_a;
+ delete new_curve_b;
+ return -1;
+ }
+ if (pred.result) {
+ // we don't actually create these two chains
+ newChains.push_back(_curve);
+ delete new_curve_a;
+ delete new_curve_b;
+ return 0;
+ }
+ // here we know we'll split _curve:
+ splitted_chains.push_back(_curve);
+
+ __recursiveSplit(new_curve_a, func, pred, sampling, newChains, splitted_chains);
+ __recursiveSplit(new_curve_b, func, pred, sampling, newChains, splitted_chains);
+ return 0;
+}
+
+int Operators::recursiveSplit(UnaryFunction0D<double>& func, UnaryPredicate1D& pred, float sampling)
+{
+ if (_current_chains_set.empty()) {
+ cerr << "Warning: current set empty" << endl;
+ return 0;
+ }
+
+ Chain *currentChain = 0;
+ I1DContainer splitted_chains;
+ I1DContainer newChains;
+ I1DContainer::iterator cit = _current_chains_set.begin(), citend = _current_chains_set.end();
+ for (; cit != citend; ++cit) {
+ currentChain = dynamic_cast<Chain*>(*cit);
+ if (!currentChain)
+ continue;
+ // let's check the first one:
+ if (pred(*currentChain) < 0)
+ return -1;
+ if (!pred.result) {
+ __recursiveSplit(currentChain, func, pred, sampling, newChains, splitted_chains);
+ }
+ else {
+ newChains.push_back(currentChain);
+ }
+ }
+ // Update the current set of chains:
+ if (!splitted_chains.empty()) {
+ for (cit = splitted_chains.begin(), citend = splitted_chains.end(); cit != citend; ++cit) {
+ delete (*cit);
+ }
+ splitted_chains.clear();
+ }
+
+ _current_chains_set.clear();
+#if 0
+ _current_chains_set = newChains;
+#else
+ for (cit = newChains.begin(), citend = newChains.end(); cit != citend; ++cit) {
+ if ((*cit)->getLength2D() < M_EPSILON) {
+ delete (*cit);
+ continue;
+ }
+ _current_chains_set.push_back(*cit);
+ }
+#endif
+ newChains.clear();
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+ return 0;
+}
+
+
+// recursive split with pred 0D
+static int __recursiveSplit(Chain *_curve, UnaryFunction0D<double>& func, UnaryPredicate0D& pred0d,
+ UnaryPredicate1D& pred, float sampling,
+ Operators::I1DContainer& newChains, Operators::I1DContainer& splitted_chains)
+{
+ if (((_curve->nSegments() == 1) && (sampling == 0)) || (_curve->getLength2D() <= sampling)) {
+ newChains.push_back(_curve);
+ return 0;
+ }
+
+ CurveInternal::CurvePointIterator first = _curve->curvePointsBegin(sampling);
+ CurveInternal::CurvePointIterator second = first;
+ ++second;
+ CurveInternal::CurvePointIterator end = _curve->curvePointsEnd(sampling);
+ CurveInternal::CurvePointIterator it = second;
+ CurveInternal::CurvePointIterator split = second;
+ Interface0DIterator it0d = it.castToInterface0DIterator();
+#if 0
+ real _min = func(it0d);
+ ++it;
+#endif
+ real _min = FLT_MAX;
+ ++it;
+ real mean = 0.f;
+ //soc unused - real variance = 0.0f;
+ unsigned count = 0;
+ CurveInternal::CurvePointIterator next = it;
+ ++next;
+
+ bool bsplit = false;
+ for (; ((it != end) && (next != end)); ++it, ++next) {
+ ++count;
+ it0d = it.castToInterface0DIterator();
+ if (pred0d(it0d) < 0)
+ return -1;
+ if (!pred0d.result)
+ continue;
+ if (func(it0d) < 0)
+ return -1;
+ mean += func.result;
+ if (func.result < _min) {
+ _min = func.result;
+ split = it;
+ bsplit = true;
+ }
+ }
+ mean /= (float)count;
+
+ //if ((!bsplit) || (mean - _min > mean)) { // we didn't find any minimum
+ if (!bsplit) { // we didn't find any minimum
+ newChains.push_back(_curve);
+ return 0;
+ }
+
+ // retrieves the current splitting id
+ Id *newId = _curve->getSplittingId();
+ if (newId == NULL) {
+ newId = new Id(_curve->getId());
+ _curve->setSplittingId(newId);
+ }
+
+ Chain *new_curve_a = new Chain(*newId);
+ newId->setSecond(newId->getSecond() + 1);
+ new_curve_a->setSplittingId(newId);
+ Chain *new_curve_b = new Chain(*newId);
+ newId->setSecond(newId->getSecond() + 1);
+ new_curve_b->setSplittingId(newId);
+
+ CurveInternal::CurvePointIterator vit = _curve->curveVerticesBegin(), vitend = _curve->curveVerticesEnd();
+ CurveInternal::CurvePointIterator vnext = vit;
+ ++vnext;
+
+ for (;
+ (vit != vitend) && (vnext != vitend) && (vnext._CurvilinearLength < split._CurvilinearLength);
+ ++vit, ++vnext)
+ {
+ new_curve_a->push_vertex_back(&(*vit));
+ }
+ if ((vit == vitend) || (vnext == vitend)) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "The split takes place in bad location" << endl;
+ }
+ newChains.push_back(_curve);
+ delete new_curve_a;
+ delete new_curve_b;
+ return 0;
+ }
+
+ // build the two resulting chains
+ new_curve_a->push_vertex_back(&(*vit));
+ new_curve_a->push_vertex_back(&(*split));
+ new_curve_b->push_vertex_back(&(*split));
+
+ for (vit = vnext; vit != vitend; ++vit)
+ new_curve_b->push_vertex_back(&(*vit));
+
+ // let's check whether one or two of the two new curves satisfy the stopping condition or not.
+ // (if one of them satisfies it, we don't split)
+ if (pred(*new_curve_a) < 0 || (!pred.result && pred(*new_curve_b) < 0)) {
+ delete new_curve_a;
+ delete new_curve_b;
+ return -1;
+ }
+ if (pred.result) {
+ // we don't actually create these two chains
+ newChains.push_back(_curve);
+ delete new_curve_a;
+ delete new_curve_b;
+ return 0;
+ }
+ // here we know we'll split _curve:
+ splitted_chains.push_back(_curve);
+
+ __recursiveSplit(new_curve_a, func, pred0d, pred, sampling, newChains, splitted_chains);
+ __recursiveSplit(new_curve_b, func, pred0d, pred, sampling, newChains, splitted_chains);
+ return 0;
+}
+
+int Operators::recursiveSplit(UnaryFunction0D<double>& func, UnaryPredicate0D& pred0d, UnaryPredicate1D& pred,
+ float sampling)
+{
+ if (_current_chains_set.empty()) {
+ cerr << "Warning: current set empty" << endl;
+ return 0;
+ }
+
+ Chain *currentChain = 0;
+ I1DContainer splitted_chains;
+ I1DContainer newChains;
+ I1DContainer::iterator cit = _current_chains_set.begin(), citend = _current_chains_set.end();
+ for (; cit != citend; ++cit) {
+ currentChain = dynamic_cast<Chain*>(*cit);
+ if (!currentChain)
+ continue;
+ // let's check the first one:
+ if (pred(*currentChain) < 0)
+ return -1;
+ if (!pred.result) {
+ __recursiveSplit(currentChain, func, pred0d, pred, sampling, newChains, splitted_chains);
+ }
+ else {
+ newChains.push_back(currentChain);
+ }
+ }
+ // Update the current set of chains:
+ if (!splitted_chains.empty()) {
+ for (cit = splitted_chains.begin(), citend = splitted_chains.end(); cit != citend; ++cit) {
+ delete (*cit);
+ }
+ splitted_chains.clear();
+ }
+
+ _current_chains_set.clear();
+#if 0
+ _current_chains_set = newChains;
+#else
+ for (cit = newChains.begin(), citend = newChains.end(); cit != citend; ++cit) {
+ if ((*cit)->getLength2D() < M_EPSILON) {
+ delete (*cit);
+ continue;
+ }
+ _current_chains_set.push_back(*cit);
+ }
+#endif
+ newChains.clear();
+
+ if (!_current_chains_set.empty())
+ _current_set = &_current_chains_set;
+ return 0;
+}
+
+// Internal class
+class PredicateWrapper
+{
+public:
+ inline PredicateWrapper(BinaryPredicate1D& pred)
+ {
+ _pred = &pred;
+ }
+
+ inline bool operator()(Interface1D *i1, Interface1D *i2)
+ {
+ if ((*_pred)(*i1, *i2) < 0)
+ throw std::runtime_error("comparison failed");
+ return _pred->result;
+ }
+
+private:
+ BinaryPredicate1D *_pred;
+};
+
+int Operators::sort(BinaryPredicate1D& pred)
+{
+ if (!_current_set)
+ return 0;
+ PredicateWrapper wrapper(pred);
+ try {
+ std::sort(_current_set->begin(), _current_set->end(), wrapper);
+ }
+ catch (std::runtime_error &e) {
+ cerr << "Warning: Operator.sort(): " << e.what() << endl;
+ return -1;
+ }
+ return 0;
+}
+
+static Stroke *createStroke(Interface1D& inter)
+{
+ Stroke *stroke = new Stroke;
+ stroke->setId(inter.getId());
+
+ float currentCurvilignAbscissa = 0.0f;
+
+ Interface0DIterator it = inter.verticesBegin(), itend = inter.verticesEnd();
+ Interface0DIterator itfirst = it;
+
+ Vec2r current(it->getPoint2D());
+ Vec2r previous = current;
+ SVertex *sv;
+ CurvePoint *cp;
+ StrokeVertex *stroke_vertex = NULL;
+ bool hasSingularity = false;
+
+ do {
+ cp = dynamic_cast<CurvePoint*>(&(*it));
+ if (!cp) {
+ sv = dynamic_cast<SVertex*>(&(*it));
+ if (!sv) {
+ cerr << "Warning: unexpected Vertex type" << endl;
+ continue;
+ }
+ stroke_vertex = new StrokeVertex(sv);
+ }
+ else {
+ stroke_vertex = new StrokeVertex(cp);
+ }
+ current = stroke_vertex->getPoint2D();
+ Vec2r vec_tmp(current - previous);
+ real dist = vec_tmp.norm();
+ if (dist < 1.0e-6)
+ hasSingularity = true;
+ currentCurvilignAbscissa += dist;
+ stroke_vertex->setCurvilinearAbscissa(currentCurvilignAbscissa);
+ stroke->push_back(stroke_vertex);
+ previous = current;
+ ++it;
+ } while ((it != itend) && (it != itfirst));
+
+ if (it == itfirst) {
+ // Add last vertex:
+ cp = dynamic_cast<CurvePoint*>(&(*it));
+ if (!cp) {
+ sv = dynamic_cast<SVertex*>(&(*it));
+ if (!sv)
+ cerr << "Warning: unexpected Vertex type" << endl;
+ else
+ stroke_vertex = new StrokeVertex(sv);
+ }
+ else {
+ stroke_vertex = new StrokeVertex(cp);
+ }
+ current = stroke_vertex->getPoint2D();
+ Vec2r vec_tmp(current - previous);
+ real dist = vec_tmp.norm();
+ if (dist < 1.0e-6)
+ hasSingularity = true;
+ currentCurvilignAbscissa += dist;
+ stroke_vertex->setCurvilinearAbscissa(currentCurvilignAbscissa);
+ stroke->push_back(stroke_vertex);
+ }
+ // Discard the stroke if the number of stroke vertices is less than two
+ if (stroke->strokeVerticesSize() < 2) {
+ delete stroke;
+ return NULL;
+ }
+ stroke->setLength(currentCurvilignAbscissa);
+ if (hasSingularity) {
+ // Try to address singular points such that the distance between two subsequent vertices
+ // are smaller than epsilon.
+ Interface0DIterator v = stroke->verticesBegin();
+ Interface0DIterator vnext = v;
+ ++vnext;
+ Vec2r next((*v).getPoint2D());
+ while (!vnext.isEnd()) {
+ current = next;
+ next = (*vnext).getPoint2D();
+ if ((next - current).norm() < 1.0e-6) {
+ Interface0DIterator vprevious = v;
+ if (!vprevious.isBegin())
+ --vprevious;
+
+ // collect a set of overlapping vertices (except the first one)
+ std::vector<Interface0D *> overlapping_vertices;
+ do {
+ overlapping_vertices.push_back(&(*vnext));
+ current = next;
+ ++v;
+ ++vnext;
+ if (vnext.isEnd())
+ break;
+ next = (*vnext).getPoint2D();
+ } while ((next - current).norm() < 1.0e-6);
+
+ Vec2r target;
+ bool reverse;
+ if (!vnext.isEnd()) {
+ target = (*vnext).getPoint2D();
+ reverse = false;
+ }
+ else if (!vprevious.isBegin()) {
+ target = (*vprevious).getPoint2D();
+ reverse = true;
+ }
+ else {
+ // Discard the stroke because all stroke vertices are overlapping
+ delete stroke;
+ return NULL;
+ }
+ Vec2r dir(target - current);
+ real dist = dir.norm();
+ real len = 1.0e-3; // default offset length
+ int nvert = overlapping_vertices.size();
+ if (dist < len * nvert) {
+ len = dist / (nvert + 1);
+ }
+ dir.normalize();
+ Vec2r offset(dir * len);
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "#vert " << nvert << " len " << len << " reverse? " << reverse << endl;
+ }
+#endif
+ // add the offset to the overlapping vertices
+ StrokeVertex *sv;
+ std::vector<Interface0D *>::iterator it = overlapping_vertices.begin(),
+ itend = overlapping_vertices.end();
+ if (!reverse) {
+ int n = 1;
+ for (; it != itend; ++it) {
+ sv = dynamic_cast<StrokeVertex*>(*it);
+ sv->setPoint(sv->getPoint() + offset * n);
+ ++n;
+ }
+ }
+ else {
+ int n = nvert;
+ for (; it != itend; ++it) {
+ sv = dynamic_cast<StrokeVertex*>(*it);
+ sv->setPoint(sv->getPoint() + offset * n);
+ --n;
+ }
+ }
+
+ if (vnext.isEnd())
+ break;
+ }
+ ++v;
+ ++vnext;
+ }
+ }
+ {
+ // Check if the stroke no longer contains singular points
+ Interface0DIterator v = stroke->verticesBegin();
+ Interface0DIterator vnext = v;
+ ++vnext;
+ Vec2r next((*v).getPoint2D());
+ bool warning = false;
+ while (!vnext.isEnd()) {
+ current = next;
+ next = (*vnext).getPoint2D();
+ if ((next - current).norm() < 1.0e-6) {
+ warning = true;
+ break;
+ }
+ ++v;
+ ++vnext;
+ }
+ if (warning && G.debug & G_DEBUG_FREESTYLE) {
+ printf("Warning: stroke contains singular points.\n");
+ }
+ }
+ return stroke;
+}
+
+
+inline int applyShading(Stroke& stroke, vector<StrokeShader*>& shaders)
+{
+ for (vector<StrokeShader*>::iterator it = shaders.begin(); it != shaders.end(); ++it) {
+ if ((*it)->shade(stroke) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+int Operators::create(UnaryPredicate1D& pred, vector<StrokeShader*> shaders)
+{
+ //Canvas* canvas = Canvas::getInstance();
+ if (!_current_set) {
+ cerr << "Warning: current set empty" << endl;
+ return 0;
+ }
+ StrokesContainer new_strokes_set;
+ for (Operators::I1DContainer::iterator it = _current_set->begin(); it != _current_set->end(); ++it) {
+ if (pred(**it) < 0)
+ goto error;
+ if (!pred.result)
+ continue;
+
+ Stroke *stroke = createStroke(**it);
+ if (stroke) {
+ if (applyShading(*stroke, shaders) < 0) {
+ delete stroke;
+ goto error;
+ }
+ //canvas->RenderStroke(stroke);
+ new_strokes_set.push_back(stroke);
+ }
+ }
+
+ for (StrokesContainer::iterator it = new_strokes_set.begin(); it != new_strokes_set.end(); ++it) {
+ _current_strokes_set.push_back(*it);
+ }
+ new_strokes_set.clear();
+ return 0;
+
+error:
+ for (StrokesContainer::iterator it = new_strokes_set.begin(); it != new_strokes_set.end(); ++it) {
+ delete (*it);
+ }
+ new_strokes_set.clear();
+ return -1;
+}
+
+void Operators::reset()
+{
+ ViewMap *vm = ViewMap::getInstance();
+ if (!vm) {
+ cerr << "Error: no ViewMap computed yet" << endl;
+ return;
+ }
+ _current_view_edges_set.clear();
+ for (I1DContainer::iterator it = _current_chains_set.begin(); it != _current_chains_set.end(); ++it)
+ delete *it;
+ _current_chains_set.clear();
+#if 0
+ _current_view_edges_set.insert(_current_view_edges_set.begin(),
+ vm->ViewEdges().begin(),
+ vm->ViewEdges().end());
+#else
+ ViewMap::viewedges_container& vedges = vm->ViewEdges();
+ ViewMap::viewedges_container::iterator ve = vedges.begin(), veend = vedges.end();
+ for (; ve != veend; ++ve) {
+ if ((*ve)->getLength2D() < M_EPSILON)
+ continue;
+ _current_view_edges_set.push_back(*ve);
+ }
+#endif
+ _current_set = &_current_view_edges_set;
+ _current_strokes_set.clear();
+}
diff --git a/source/blender/freestyle/intern/stroke/Operators.h b/source/blender/freestyle/intern/stroke/Operators.h
new file mode 100644
index 00000000000..aafbc2350d9
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Operators.h
@@ -0,0 +1,274 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_OPERATORS_H__
+#define __FREESTYLE_OPERATORS_H__
+
+/** \file blender/freestyle/intern/stroke/Operators.h
+ * \ingroup freestyle
+ * \brief Class gathering stroke creation algorithms
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include <iostream>
+#include <vector>
+
+#include "Chain.h"
+#include "ChainingIterators.h"
+#include "Predicates0D.h"
+#include "Predicates1D.h"
+#include "StrokeShader.h"
+
+#include "../system/TimeStamp.h"
+
+#include "../view_map/Interface1D.h"
+#include "../view_map/ViewMap.h"
+
+/*! Class defining the operators used in a style module.
+ * There are 4 classes of operators: Selection, Chaining, Splitting and Creating. All these operators are
+ * user controlled in the scripting language through Functors, Predicates and Shaders that are taken as arguments.
+ */
+class LIB_STROKE_EXPORT Operators {
+
+public:
+ typedef vector<Interface1D*> I1DContainer;
+ typedef vector<Stroke*> StrokesContainer;
+
+ //
+ // Operators
+ //
+ ////////////////////////////////////////////////
+
+ /*! Selects the ViewEdges of the ViewMap verifying a specified condition.
+ * \param pred The predicate expressing this condition
+ */
+ static int select(UnaryPredicate1D& pred);
+
+ /*! Builds a set of chains from the current set of ViewEdges.
+ * Each ViewEdge of the current list starts a new chain. The chaining operator then iterates over the ViewEdges
+ * of the ViewMap using the user specified iterator.
+ * This operator only iterates using the increment operator and is therefore unidirectional.
+ * \param it
+ * The iterator on the ViewEdges of the ViewMap. It contains the chaining rule.
+ * \param pred
+ * The predicate on the ViewEdge that expresses the stopping condition.
+ * \param modifier
+ * A function that takes a ViewEdge as argument and that is used to modify the processed ViewEdge
+ * state (the timestamp incrementation is a typical illustration of such a modifier)
+ */
+ static int chain(ViewEdgeInternal::ViewEdgeIterator& it, UnaryPredicate1D& pred, UnaryFunction1D_void& modifier);
+
+ /*! Builds a set of chains from the current set of ViewEdges.
+ * Each ViewEdge of the current list starts a new chain. The chaining operator then iterates over the ViewEdges
+ * of the ViewMap using the user specified iterator.
+ * This operator only iterates using the increment operator and is therefore unidirectional.
+ * This chaining operator is different from the previous one because it doesn't take any modifier as argument.
+ * Indeed, the time stamp (insuring that a ViewEdge is processed one time) is automatically managed in this case.
+ * \param it
+ * The iterator on the ViewEdges of the ViewMap. It contains the chaining rule.
+ * \param pred
+ * The predicate on the ViewEdge that expresses the stopping condition.
+ */
+ static int chain(ViewEdgeInternal::ViewEdgeIterator& it, UnaryPredicate1D& pred);
+
+ /*! Builds a set of chains from the current set of ViewEdges.
+ * Each ViewEdge of the current list potentially starts a new chain. The chaining operator then iterates over
+ * the ViewEdges of the ViewMap using the user specified iterator.
+ * This operator iterates both using the increment and decrement operators and is therefore bidirectional.
+ * This operator works with a ChainingIterator which contains the chaining rules. It is this last one which can
+ * be told to chain only edges that belong to the selection or not to process twice a ViewEdge during the chaining.
+ * Each time a ViewEdge is added to a chain, its chaining time stamp is incremented. This allows you to keep track
+ * of the number of chains to which a ViewEdge belongs to.
+ * \param it
+ * The ChainingIterator on the ViewEdges of the ViewMap. It contains the chaining rule.
+ * \param pred
+ * The predicate on the ViewEdge that expresses the stopping condition.
+ */
+ static int bidirectionalChain(ChainingIterator& it, UnaryPredicate1D& pred);
+
+ /*! The only difference with the above bidirectional chaining algorithm is that we don't need to pass a stopping
+ * criterion. This might be desirable when the stopping criterion is already contained in the iterator definition.
+ * Builds a set of chains from the current set of ViewEdges.
+ * Each ViewEdge of the current list potentially starts a new chain. The chaining operator then iterates over
+ * the ViewEdges of the ViewMap using the user specified iterator.
+ * This operator iterates both using the increment and decrement operators and is therefore bidirectional.
+ * This operator works with a ChainingIterator which contains the chaining rules. It is this last one which can be
+ * told to chain only edges that belong to the selection or not to process twice a ViewEdge during the chaining.
+ * Each time a ViewEdge is added to a chain, its chaining time stamp is incremented. This allows you to keep track
+ * of the number of chains to which a ViewEdge belongs to.
+ * \param it
+ * The ChainingIterator on the ViewEdges of the ViewMap. It contains the chaining rule.
+ */
+ static int bidirectionalChain(ChainingIterator& it);
+
+ /*! Splits each chain of the current set of chains in a sequential way.
+ * The points of each chain are processed (with a specified sampling) sequentially.
+ * Each time a user specified starting condition is verified, a new chain begins and ends as soon as a
+ * user-defined stopping predicate is verified.
+ * This allows chains overlapping rather than chains partitioning.
+ * The first point of the initial chain is the first point of one of the resulting chains.
+ * The splitting ends when no more chain can start.
+ * \param startingPred
+ * The predicate on a point that expresses the starting condition
+ * \param stoppingPred
+ * The predicate on a point that expresses the stopping condition
+ * \param sampling
+ * The resolution used to sample the chain for the predicates evaluation. (The chain is not actually
+ * resampled, a virtual point only progresses along the curve using this resolution)
+ */
+ static int sequentialSplit(UnaryPredicate0D& startingPred, UnaryPredicate0D& stoppingPred, float sampling = 0.0f);
+
+ /*! Splits each chain of the current set of chains in a sequential way.
+ * The points of each chain are processed (with a specified sampling) sequentially and each time a user
+ * specified condition is verified, the chain is split into two chains.
+ * The resulting set of chains is a partition of the initial chain
+ * \param pred
+ * The predicate on a point that expresses the splitting condition
+ * \param sampling
+ * The resolution used to sample the chain for the predicate evaluation. (The chain is not actually
+ * resampled, a virtual point only progresses along the curve using this resolution)
+ */
+ static int sequentialSplit(UnaryPredicate0D& pred, float sampling = 0.0f);
+
+ /*! Splits the current set of chains in a recursive way.
+ * We process the points of each chain (with a specified sampling) to find the point minimizing a specified
+ * function. The chain is split in two at this point and the two new chains are processed in the same way.
+ * The recursivity level is controlled through a predicate 1D that expresses a stopping condition
+ * on the chain that is about to be processed.
+ * \param func
+ * The Unary Function evaluated at each point of the chain.
+ * The splitting point is the point minimizing this function
+ * \param pred
+ * The Unary Predicate ex pressing the recursivity stopping condition.
+ * This predicate is evaluated for each curve before it actually gets split.
+ * If pred(chain) is true, the curve won't be split anymore.
+ * \param sampling
+ * The resolution used to sample the chain for the predicates evaluation. (The chain is not actually
+ * resampled, a virtual point only progresses along the curve using this resolution)
+ */
+ static int recursiveSplit(UnaryFunction0D<double>& func, UnaryPredicate1D& pred, float sampling = 0);
+
+ /*! Splits the current set of chains in a recursive way.
+ * We process the points of each chain (with a specified sampling) to find the point minimizing a specified
+ * function. The chain is split in two at this point and the two new chains are processed in the same way.
+ * The user can specify a 0D predicate to make a first selection on the points that can potentially be split.
+ * A point that doesn't verify the 0D predicate won't be candidate in realizing the min.
+ * The recursivity level is controlled through a predicate 1D that expresses a stopping condition
+ * on the chain that is about to be processed.
+ * \param func
+ * The Unary Function evaluated at each point of the chain.
+ * The splitting point is the point minimizing this function
+ * \param pred0d
+ * The Unary Predicate 0D used to select the candidate points where the split can occur.
+ * For example, it is very likely that would rather have your chain splitting around its middle point
+ * than around one of its extremities. A 0D predicate working on the curvilinear abscissa allows
+ * to add this kind of constraints.
+ * \param pred
+ * The Unary Predicate ex pressing the recursivity stopping condition.
+ * This predicate is evaluated for each curve before it actually gets split.
+ * If pred(chain) is true, the curve won't be split anymore.
+ * \param sampling
+ * The resolution used to sample the chain for the predicates evaluation. (The chain is not actually
+ * resampled, a virtual point only progresses along the curve using this resolution)
+ */
+ static int recursiveSplit(UnaryFunction0D<double>& func, UnaryPredicate0D& pred0d, UnaryPredicate1D& pred,
+ float sampling = 0.0f);
+
+ /*! Sorts the current set of chains (or viewedges) according to the comparison predicate given as argument.
+ * \param pred
+ * The binary predicate used for the comparison
+ */
+ static int sort(BinaryPredicate1D& pred);
+
+ /*! Creates and shades the strokes from the current set of chains.
+ * A predicate can be specified to make a selection pass on the chains.
+ * \param pred
+ * The predicate that a chain must verify in order to be transform as a stroke
+ * \param shaders
+ * The list of shaders used to shade the strokes
+ */
+ static int create(UnaryPredicate1D& pred, vector<StrokeShader*> shaders);
+
+ //
+ // Data access
+ //
+ ////////////////////////////////////////////////
+
+ static ViewEdge *getViewEdgeFromIndex(unsigned i)
+ {
+ return dynamic_cast<ViewEdge*>(_current_view_edges_set[i]);
+ }
+
+ static Chain *getChainFromIndex(unsigned i)
+ {
+ return dynamic_cast<Chain*>(_current_chains_set[i]);
+ }
+
+ static Stroke *getStrokeFromIndex(unsigned i)
+ {
+ return _current_strokes_set[i];
+ }
+
+ static unsigned getViewEdgesSize()
+ {
+ return _current_view_edges_set.size();
+ }
+
+ static unsigned getChainsSize()
+ {
+ return _current_chains_set.size();
+ }
+
+ static unsigned getStrokesSize()
+ {
+ return _current_strokes_set.size();
+ }
+
+ //
+ // Not exported in Python
+ //
+ //////////////////////////////////////////////////
+
+ static StrokesContainer *getStrokesSet()
+ {
+ return &_current_strokes_set;
+ }
+
+ static void reset();
+
+private:
+ Operators() {}
+
+ static I1DContainer _current_view_edges_set;
+ static I1DContainer _current_chains_set;
+ static I1DContainer *_current_set;
+ static StrokesContainer _current_strokes_set;
+};
+
+#endif // __FREESTYLE_OPERATORS_H__
diff --git a/source/blender/freestyle/intern/stroke/PSStrokeRenderer.cpp b/source/blender/freestyle/intern/stroke/PSStrokeRenderer.cpp
new file mode 100644
index 00000000000..0b527f9f2af
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/PSStrokeRenderer.cpp
@@ -0,0 +1,106 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/PSStrokeRenderer.cpp
+ * \ingroup freestyle
+ * \brief Class to define the Postscript rendering of a stroke
+ * \author Stephane Grabli
+ * \date 10/26/2004
+ */
+
+#include "Canvas.h"
+#include "PSStrokeRenderer.h"
+
+PSStrokeRenderer::PSStrokeRenderer(const char *iFileName) : StrokeRenderer()
+{
+ if (!iFileName)
+ iFileName = "freestyle.ps";
+ // open the stream:
+ _ofstream.open(iFileName, ios::out);
+ if (!_ofstream.is_open()) {
+ cerr << "couldn't open the output file " << iFileName << endl;
+ }
+ _ofstream << "%!PS-Adobe-2.0 EPSF-2.0" << endl;
+ _ofstream << "%%Creator: Freestyle (http://artis.imag.fr/Software/Freestyle)" << endl;
+ _ofstream << "%%BoundingBox: " << 0 << " "<< 0 << " " << Canvas::getInstance()->width() << " "
+ << Canvas::getInstance()->height() << endl;
+ _ofstream << "%%EndComments" << endl;
+}
+
+PSStrokeRenderer::~PSStrokeRenderer()
+{
+ Close();
+}
+
+void PSStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
+{
+ RenderStrokeRepBasic(iStrokeRep);
+}
+
+void PSStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
+{
+ vector<Strip*>& strips = iStrokeRep->getStrips();
+ Strip::vertex_container::iterator v[3];
+ StrokeVertexRep *svRep[3];
+ Vec3r color[3];
+ for (vector<Strip*>::iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
+ Strip::vertex_container& vertices = (*s)->vertices();
+ v[0] = vertices.begin();
+ v[1] = v[0];
+ ++(v[1]);
+ v[2] = v[1];
+ ++(v[2]);
+
+ while (v[2] != vertices.end()) {
+ svRep[0] = *(v[0]);
+ svRep[1] = *(v[1]);
+ svRep[2] = *(v[2]);
+
+ color[0] = svRep[0]->color();
+ //color[1] = svRep[1]->color();
+ //color[2] = svRep[2]->color();
+
+ _ofstream << "newpath" << endl;
+ _ofstream << (color[0])[0] << " " << (color[0])[1] << " " << (color[0])[2] << " setrgbcolor" <<endl;
+ _ofstream << svRep[0]->point2d()[0] << " " <<svRep[0]->point2d()[1] << " moveto" << endl;
+ _ofstream << svRep[1]->point2d()[0] << " " <<svRep[1]->point2d()[1] << " lineto" << endl;
+ _ofstream << svRep[2]->point2d()[0] << " " <<svRep[2]->point2d()[1] << " lineto" << endl;
+ _ofstream << "closepath" << endl;
+ _ofstream << "fill" << endl;
+
+ ++v[0];
+ ++v[1];
+ ++v[2];
+ }
+ }
+}
+
+void PSStrokeRenderer::Close()
+{
+ if (_ofstream.is_open())
+ _ofstream.close();
+}
diff --git a/source/blender/freestyle/intern/stroke/PSStrokeRenderer.h b/source/blender/freestyle/intern/stroke/PSStrokeRenderer.h
new file mode 100644
index 00000000000..e01ec531471
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/PSStrokeRenderer.h
@@ -0,0 +1,69 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_PS_STROKE_RENDERER_H__
+#define __FREESTYLE_PS_STROKE_RENDERER_H__
+
+/** \file blender/freestyle/intern/stroke/PSStrokeRenderer.h
+ * \ingroup freestyle
+ * \brief Class to define the Postscript rendering of a stroke
+ * \author Stephane Grabli
+ * \date 10/26/2004
+ */
+
+#include <fstream>
+
+#include "StrokeRenderer.h"
+
+#include "../system/FreestyleConfig.h"
+
+/**********************************/
+/* */
+/* */
+/* PSStrokeRenderer */
+/* */
+/* */
+/**********************************/
+
+class LIB_STROKE_EXPORT PSStrokeRenderer : public StrokeRenderer
+{
+public:
+ PSStrokeRenderer(const char * iFileName = 0);
+ virtual ~PSStrokeRenderer();
+
+ /*! Renders a stroke rep */
+ virtual void RenderStrokeRep(StrokeRep *iStrokeRep) const;
+ virtual void RenderStrokeRepBasic(StrokeRep *iStrokeRep) const;
+
+ /*! Closes the output PS file */
+ void Close();
+
+protected:
+ mutable ofstream _ofstream;
+};
+
+#endif // __FREESTYLE_PS_STROKE_RENDERER_H__
diff --git a/source/blender/freestyle/intern/stroke/Predicates0D.h b/source/blender/freestyle/intern/stroke/Predicates0D.h
new file mode 100644
index 00000000000..796bbdef0f6
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Predicates0D.h
@@ -0,0 +1,186 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_PREDICATES_0D_H__
+#define __FREESTYLE_PREDICATES_0D_H__
+
+/** \file blender/freestyle/intern/stroke/Predicates0D.h
+ * \ingroup freestyle
+ * \brief Class gathering stroke creation algorithms
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include "../python/Director.h"
+
+#include "../view_map/Functions0D.h"
+
+//
+// UnaryPredicate0D (base class for predicates in 0D)
+//
+///////////////////////////////////////////////////////////
+
+/*! Base class for Unary Predicates that work on Interface0DIterator.
+ * A UnaryPredicate0D is a functor that evaluates a condition on a Interface0DIterator and returns
+ * true or false depending on whether this condition is satisfied or not.
+ * The UnaryPredicate0D is used by calling its () operator.
+ * Any inherited class must overload the () operator.
+ */
+class UnaryPredicate0D
+{
+public:
+ bool result;
+ PyObject *py_up0D;
+
+ /*! Default constructor. */
+ UnaryPredicate0D()
+ {
+ py_up0D = 0;
+ }
+
+ /*! Destructor. */
+ virtual ~UnaryPredicate0D() {}
+
+ /*! Returns the string of the name of the UnaryPredicate0D. */
+ virtual string getName() const
+ {
+ return "UnaryPredicate0D";
+ }
+
+ /*! The () operator. Must be overload by inherited classes.
+ * \param it
+ * The Interface0DIterator pointing onto the Interface0D at which we wish to evaluate the predicate.
+ * \return true if the condition is satisfied, false otherwise.
+ */
+ virtual int operator()(Interface0DIterator& it)
+ {
+ return Director_BPy_UnaryPredicate0D___call__(this, it);
+ }
+};
+
+
+//
+// BinaryPredicate0D (base class for predicates in 0D)
+//
+///////////////////////////////////////////////////////////
+
+/*! Base class for Binary Predicates working on Interface0D.
+ * A BinaryPredicate0D is typically an ordering relation between two Interface0D.
+ * It evaluates a relation between 2 Interface0D and returns true or false.
+ * It is used by calling the () operator.
+ */
+class BinaryPredicate0D
+{
+public:
+ bool result;
+ PyObject *py_bp0D;
+
+ /*! Default constructor. */
+ BinaryPredicate0D()
+ {
+ py_bp0D = 0;
+ }
+
+ /*! Destructor. */
+ virtual ~BinaryPredicate0D() {}
+
+ /*! Returns the string of the name of the binary predicate. */
+ virtual string getName() const
+ {
+ return "BinaryPredicate0D";
+ }
+
+ /*! The () operator. Must be overload by inherited classes.
+ * It evaluates a relation between 2 Interface0D.
+ * \param inter1
+ * The first Interface0D.
+ * \param inter2
+ * The second Interface0D.
+ * \return true or false.
+ */
+ virtual int operator()(Interface0D& inter1, Interface0D& inter2)
+ {
+ return Director_BPy_BinaryPredicate0D___call__(this, inter1, inter2);
+ }
+};
+
+
+//
+// Predicates definitions
+//
+///////////////////////////////////////////////////////////
+
+namespace Predicates0D {
+
+// TrueUP0D
+/*! Returns true any time */
+class TrueUP0D : public UnaryPredicate0D
+{
+public:
+ /*! Default constructor. */
+ TrueUP0D() {}
+
+ /*! Returns the string "TrueUP0D"*/
+ string getName() const
+ {
+ return "TrueUP0D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface0DIterator&)
+ {
+ result = true;
+ return 0;
+ }
+};
+
+// FalseUP0D
+/*! Returns false any time */
+class FalseUP0D : public UnaryPredicate0D
+{
+public:
+ /*! Default constructor. */
+ FalseUP0D() {}
+
+ /*! Returns the string "FalseUP0D"*/
+ string getName() const
+ {
+ return "FalseUP0D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface0DIterator&)
+ {
+ result = false;
+ return 0;
+ }
+};
+
+} // end of namespace Predicates0D
+
+#endif // __FREESTYLE_PREDICATES_0D_H__
diff --git a/source/blender/freestyle/intern/stroke/Predicates1D.h b/source/blender/freestyle/intern/stroke/Predicates1D.h
new file mode 100644
index 00000000000..18e4328c4d5
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Predicates1D.h
@@ -0,0 +1,589 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_PREDICATES_1D_H__
+#define __FREESTYLE_PREDICATES_1D_H__
+
+/** \file blender/freestyle/intern/stroke/Predicates1D.h
+ * \ingroup freestyle
+ * \brief Class gathering stroke creation algorithms
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include <string>
+
+#include "AdvancedFunctions1D.h"
+
+#include "../python/Director.h"
+
+#include "../system/TimeStamp.h"
+
+#include "../view_map/Interface1D.h"
+#include "../view_map/Functions1D.h"
+
+//
+// UnaryPredicate1D (base class for predicates in 1D)
+//
+///////////////////////////////////////////////////////////
+
+/*! Base class for Unary Predicates that work on Interface1D.
+ * A UnaryPredicate1D is a functor that evaluates a condition on a Interface1D and returns
+ * true or false depending on whether this condition is satisfied or not.
+ * The UnaryPredicate1D is used by calling its () operator.
+ * Any inherited class must overload the () operator.
+ */
+class UnaryPredicate1D
+{
+public:
+ bool result;
+ PyObject *py_up1D;
+
+ /*! Default constructor. */
+ UnaryPredicate1D()
+ {
+ py_up1D = NULL;
+ }
+
+ /*! Destructor. */
+ virtual ~UnaryPredicate1D() {}
+
+ /*! Returns the string of the name of the UnaryPredicate1D. */
+ virtual string getName() const
+ {
+ return "UnaryPredicate1D";
+ }
+
+ /*! The () operator. Must be overload by inherited classes.
+ * \param inter
+ * The Interface1D on which we wish to evaluate the predicate.
+ * \return true if the condition is satisfied, false otherwise.
+ */
+ virtual int operator()(Interface1D& inter)
+ {
+ return Director_BPy_UnaryPredicate1D___call__(this, inter);
+ }
+};
+
+
+//
+// BinaryPredicate1D (base class for predicates in 1D)
+//
+///////////////////////////////////////////////////////////
+
+/*! Base class for Binary Predicates working on Interface1D.
+ * A BinaryPredicate1D is typically an ordering relation between two Interface1D.
+ * It evaluates a relation between 2 Interface1D and returns true or false.
+ * It is used by calling the () operator.
+ */
+class BinaryPredicate1D
+{
+public:
+ bool result;
+ PyObject *py_bp1D;
+
+ /*! Default constructor. */
+ BinaryPredicate1D()
+ {
+ py_bp1D = NULL;
+ }
+
+ /*! Destructor. */
+ virtual ~BinaryPredicate1D() {}
+
+ /*! Returns the string of the name of the binary predicate. */
+ virtual string getName() const
+ {
+ return "BinaryPredicate1D";
+ }
+
+ /*! The () operator. Must be overload by inherited classes.
+ * It evaluates a relation between 2 Interface1D.
+ * \param inter1
+ * The first Interface1D.
+ * \param inter2
+ * The second Interface1D.
+ * \return true or false.
+ */
+ virtual int operator()(Interface1D& inter1, Interface1D& inter2)
+ {
+ return Director_BPy_BinaryPredicate1D___call__(this, inter1, inter2);
+ }
+};
+
+
+//
+// Predicates definitions
+//
+///////////////////////////////////////////////////////////
+
+namespace Predicates1D {
+
+// TrueUP1D
+/*! Returns true */
+class TrueUP1D : public UnaryPredicate1D
+{
+public:
+ /*! Constructor */
+ TrueUP1D() {}
+
+ /*! Returns the string "TrueUP1D"*/
+ string getName() const
+ {
+ return "TrueUP1D";
+ }
+
+ /*! the () operator */
+ int operator()(Interface1D&)
+ {
+ result = true;
+ return 0;
+ }
+};
+
+// FalseUP1D
+/*! Returns false */
+class FalseUP1D : public UnaryPredicate1D
+{
+public:
+ /*! Constructor */
+ FalseUP1D() {}
+
+ /*! Returns the string "FalseUP1D"*/
+ string getName() const
+ {
+ return "FalseUP1D";
+ }
+
+ /*! the () operator */
+ int operator()(Interface1D&)
+ {
+ result = false;
+ return 0;
+ }
+};
+
+// QuantitativeInvisibilityUP1D
+/*! Returns true if the Quantitative Invisibility evaluated at an Interface1D, using the QuantitativeInvisibilityF1D
+ * functor, equals a certain user-defined value.
+ */
+class QuantitativeInvisibilityUP1D : public UnaryPredicate1D
+{
+public:
+ /*! Builds the Predicate.
+ * \param qi
+ * The Quantitative Invisibility you want the Interface1D to have
+ */
+ QuantitativeInvisibilityUP1D(unsigned qi = 0) : _qi(qi) {}
+
+ /*! Returns the string "QuantitativeInvisibilityUP1D" */
+ string getName() const
+ {
+ return "QuantitativeInvisibilityUP1D";
+ }
+
+ /*! the () operator */
+ int operator()(Interface1D& inter)
+ {
+ Functions1D::QuantitativeInvisibilityF1D func;
+ if (func(inter) < 0)
+ return -1;
+ result = (func.result == _qi);
+ return 0;
+ }
+
+private:
+ unsigned _qi;
+};
+
+// ContourUP1D
+/*! Returns true if the Interface1D is a contour.
+ * An Interface1D is a contour if it is borded by a different shape on each of its sides.
+ */
+class ContourUP1D : public UnaryPredicate1D
+{
+private:
+ Functions1D::CurveNatureF1D _getNature;
+
+public:
+ /*! Returns the string "ContourUP1D"*/
+ string getName() const
+ {
+ return "ContourUP1D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface1D& inter)
+ {
+ if (_getNature(inter) < 0)
+ return -1;
+ if ((_getNature.result & Nature::SILHOUETTE) || (_getNature.result & Nature::BORDER)) {
+ Interface0DIterator it = inter.verticesBegin();
+ for (; !it.isEnd(); ++it) {
+ if (Functions0D::getOccludeeF0D(it) != Functions0D::getShapeF0D(it)) {
+ result = true;
+ return 0;
+ }
+ }
+ }
+ result = false;
+ return 0;
+ }
+};
+
+// ExternalContourUP1D
+/*! Returns true if the Interface1D is an external contour.
+ * An Interface1D is an external contour if it is borded by no shape on one of its sides.
+ */
+class ExternalContourUP1D : public UnaryPredicate1D
+{
+private:
+ Functions1D::CurveNatureF1D _getNature;
+
+public:
+ /*! Returns the string "ExternalContourUP1D" */
+ string getName() const
+ {
+ return "ExternalContourUP1D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface1D& inter)
+ {
+ if (_getNature(inter) < 0)
+ return -1;
+ if ((_getNature.result & Nature::SILHOUETTE) || (_getNature.result & Nature::BORDER)) {
+ set<ViewShape*> occluded;
+ Functions1D::getOccludeeF1D(inter, occluded);
+ for (set<ViewShape*>::iterator os = occluded.begin(), osend = occluded.end(); os != osend; ++os) {
+ if ((*os) == 0) {
+ result = true;
+ return 0;
+ }
+ }
+ }
+ result = false;
+ return 0;
+ }
+};
+
+// EqualToTimeStampUP1D
+/*! Returns true if the Interface1D's time stamp is equal to a certain user-defined value. */
+class EqualToTimeStampUP1D : public UnaryPredicate1D
+{
+protected:
+ unsigned _timeStamp;
+
+public:
+ EqualToTimeStampUP1D(unsigned ts) : UnaryPredicate1D()
+ {
+ _timeStamp = ts;
+ }
+
+ /*! Returns the string "EqualToTimeStampUP1D"*/
+ string getName() const
+ {
+ return "EqualToTimeStampUP1D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface1D& inter)
+ {
+ result = (inter.getTimeStamp() == _timeStamp);
+ return 0;
+ }
+};
+
+// EqualToChainingTimeStampUP1D
+/*! Returns true if the Interface1D's time stamp is equal to a certain user-defined value. */
+class EqualToChainingTimeStampUP1D : public UnaryPredicate1D
+{
+protected:
+ unsigned _timeStamp;
+
+public:
+ EqualToChainingTimeStampUP1D(unsigned ts) : UnaryPredicate1D()
+ {
+ _timeStamp = ts;
+ }
+
+ /*! Returns the string "EqualToChainingTimeStampUP1D"*/
+ string getName() const
+ {
+ return "EqualToChainingTimeStampUP1D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface1D& inter)
+ {
+ ViewEdge *edge = dynamic_cast<ViewEdge*>(&inter);
+ if (!edge)
+ {
+ result = false;
+ return 0;
+ }
+ result = (edge->getChainingTimeStamp() >= _timeStamp);
+ return 0;
+ }
+};
+
+// ShapeUP1D
+/*! Returns true if the shape to which the Interface1D belongs to has the same Id as the one specified by the user. */
+class ShapeUP1D: public UnaryPredicate1D
+{
+private:
+ Id _id;
+
+public:
+ /*! Builds the Predicate.
+ * \param idFirst
+ * The first Id component.
+ * \param idSecond
+ * The second Id component.
+ */
+ ShapeUP1D(unsigned idFirst, unsigned idSecond = 0) : UnaryPredicate1D()
+ {
+ _id = Id(idFirst, idSecond);
+ }
+
+ /*! Returns the string "ShapeUP1D"*/
+ string getName() const
+ {
+ return "ShapeUP1D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface1D& inter)
+ {
+ set<ViewShape*> shapes;
+ Functions1D::getShapeF1D(inter, shapes);
+ for (set<ViewShape*>::iterator s = shapes.begin(), send = shapes.end(); s != send; ++s) {
+ if ((*s)->getId() == _id) {
+ result = true;
+ return 0;
+ }
+ }
+ result = false;
+ return 0;
+ }
+};
+
+// WithinImageBoundaryUP1D
+/*! Returns true if the Interface1D is (partly) within the image boundary. */
+class WithinImageBoundaryUP1D: public UnaryPredicate1D
+{
+private:
+ real _xmin, _ymin, _xmax, _ymax;
+
+public:
+ /*! Builds the Predicate.
+ * \param xmin
+ * The X lower bound of the image boundary.
+ * \param ymin
+ * The Y lower bound of the image boundary.
+ * \param xmax
+ * The X upper bound of the image boundary.
+ * \param ymax
+ * The Y upper bound of the image boundary.
+ */
+ WithinImageBoundaryUP1D(const real xmin, const real ymin, const real xmax, const real ymax)
+ : _xmin(xmin), _ymin(ymin), _xmax(xmax), _ymax(ymax)
+ {
+ }
+
+ /*! Returns the string "WithinImageBoundaryUP1D" */
+ string getName() const
+ {
+ return "WithinImageBoundaryUP1D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface1D& inter)
+ {
+ // 1st pass: check if a point is within the image boundary.
+ Interface0DIterator it = inter.verticesBegin(), itend = inter.verticesEnd();
+ for (; it != itend; ++it) {
+ real x = (*it).getProjectedX();
+ real y = (*it).getProjectedY();
+ if (_xmin <= x && x <= _xmax && _ymin <= y && y <= _ymax) {
+ result = true;
+ return 0;
+ }
+ }
+ // 2nd pass: check if a line segment intersects with the image boundary.
+ it = inter.verticesBegin();
+ if (it != itend) {
+ Vec2r pmin(_xmin, _ymin);
+ Vec2r pmax(_xmax, _ymax);
+ Vec2r prev((*it).getPoint2D());
+ ++it;
+ for (; it != itend; ++it) {
+ Vec2r p((*it).getPoint2D());
+ if (GeomUtils::intersect2dSeg2dArea (pmin, pmax, prev, p)) {
+ result = true;
+ return 0;
+ }
+ prev = p;
+ }
+ }
+ result = false;
+ return 0;
+ }
+};
+
+//
+// Binary Predicates definitions
+//
+///////////////////////////////////////////////////////////
+
+// TrueBP1D
+/*! Returns true. */
+class TrueBP1D : public BinaryPredicate1D
+{
+public:
+ /*! Returns the string "TrueBP1D" */
+ string getName() const
+ {
+ return "TrueBP1D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface1D& i1, Interface1D& i2)
+ {
+ result = true;
+ return 0;
+ }
+};
+
+// FalseBP1D
+/*! Returns false. */
+class FalseBP1D : public BinaryPredicate1D
+{
+public:
+ /*! Returns the string "FalseBP1D" */
+ string getName() const
+ {
+ return "FalseBP1D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface1D& i1, Interface1D& i2)
+ {
+ result = false;
+ return 0;
+ }
+};
+
+// Length2DBP1D
+/*! Returns true if the 2D length of the Interface1D i1 is less than the 2D length of the Interface1D i2. */
+class Length2DBP1D : public BinaryPredicate1D
+{
+public:
+ /*! Returns the string "Length2DBP1D" */
+ string getName() const
+ {
+ return "Length2DBP1D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface1D& i1, Interface1D& i2)
+ {
+ result = (i1.getLength2D() > i2.getLength2D());
+ return 0;
+ }
+};
+
+// SameShapeIdBP1D
+/*! Returns true if the Interface1D i1 and i2 belong to the same shape. */
+class SameShapeIdBP1D : public BinaryPredicate1D
+{
+public:
+ /*! Returns the string "SameShapeIdBP1D" */
+ string getName() const
+ {
+ return "SameShapeIdBP1D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface1D& i1, Interface1D& i2)
+ {
+ set<ViewShape*> shapes1;
+ Functions1D::getShapeF1D(i1, shapes1);
+ set<ViewShape*> shapes2;
+ Functions1D::getShapeF1D(i2, shapes2);
+ // FIXME:// n2 algo, can do better...
+ for (set<ViewShape*>::iterator s = shapes1.begin(), send = shapes1.end(); s != send; ++s) {
+ Id current = (*s)->getId();
+ for (set<ViewShape*>::iterator s2 = shapes2.begin(), s2end = shapes2.end(); s2 != s2end; ++s2) {
+ if ((*s2)->getId() == current) {
+ result = true;
+ return 0;
+ }
+ }
+ }
+ result = false;
+ return 0;
+ }
+};
+
+// ViewMapGradientNormBP1D
+/*! Returns true if the evaluation of the Gradient norm Function is higher for Interface1D i1 than for i2. */
+class ViewMapGradientNormBP1D : public BinaryPredicate1D
+{
+private:
+ Functions1D::GetViewMapGradientNormF1D _func;
+
+public:
+ ViewMapGradientNormBP1D(int level, IntegrationType iType = MEAN, float sampling = 2.0)
+ : BinaryPredicate1D(), _func(level, iType, sampling)
+ {
+ }
+
+ /*! Returns the string "ViewMapGradientNormBP1D" */
+ string getName() const
+ {
+ return "ViewMapGradientNormBP1D";
+ }
+
+ /*! The () operator. */
+ int operator()(Interface1D& i1, Interface1D& i2)
+ {
+ if (_func(i1) < 0)
+ return -1;
+ real n1 = _func.result;
+ if (_func(i2) < 0)
+ return -1;
+ real n2 = _func.result;
+ result = (n1 > n2);
+ return 0;
+ }
+};
+
+} // end of namespace Predicates1D
+
+#endif // __FREESTYLE_PREDICATES_1D_H__
diff --git a/source/blender/freestyle/intern/stroke/QInformationMap.h b/source/blender/freestyle/intern/stroke/QInformationMap.h
new file mode 100644
index 00000000000..38a126d0f66
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/QInformationMap.h
@@ -0,0 +1,73 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_Q_INFORMATION_MAP_H__
+#define __FREESTYLE_Q_INFORMATION_MAP_H__
+
+/** \file blender/freestyle/intern/stroke/QInformationMap.h
+ * \ingroup freestyle
+ * \brief Class defining an information map using a QImage
+ * \author Stephane Grabli
+ * \date 04/01/2003
+ */
+
+#include <qimage.h>
+
+#include "InformationMap.h"
+
+class QInformationMap : public InformationMap
+{
+private:
+ QImage _map; // the image or a piece of image
+
+public:
+ QInformationMap();
+ QInformationMap(const QImage&);
+ QInformationMap(const QInformationMap&);
+ QInformationMap& operator=(const QInformationMap&);
+
+ //float getSmoothedPixel(int x, int y, float sigma = 0.2f);1
+ virtual float getMean(int x, int y);
+ virtual void retrieveMeanAndVariance(int x, int y, float &oMean, float &oVariance);
+
+ inline const QImage& map() const
+ {
+ return _map;
+ }
+
+ inline void setMap(const QImage& iMap, float iw, float ih)
+ {
+ _map = iMap.copy();
+ _w = iw;
+ _h = ih;
+ }
+
+protected:
+ virtual float computeGaussian(int x, int y);
+};
+
+#endif // __FREESTYLE_Q_INFORMATION_MAP_H__
diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp
new file mode 100644
index 00000000000..7e6aa62ac59
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Stroke.cpp
@@ -0,0 +1,954 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/Stroke.cpp
+ * \ingroup freestyle
+ * \brief Classes to define a stroke
+ * \author Stephane Grabli
+ * \date 09/09/2002
+ */
+
+#include "Stroke.h"
+#include "StrokeAdvancedIterators.h"
+#include "StrokeIterators.h"
+#include "StrokeRenderer.h"
+
+#include "BKE_global.h"
+
+/**********************************/
+/* */
+/* */
+/* StrokeAttribute */
+/* */
+/* */
+/**********************************/
+
+StrokeAttribute::StrokeAttribute()
+{
+ int i;
+ _alpha = 1.0f;
+ _thickness[0] = 1.0f;
+ _thickness[1] = 1.0f;
+ for (i = 0; i < 3; ++i)
+ _color[i] = 0.2f;
+ _color[0] = 0.8f;
+ _userAttributesReal = NULL;
+ _userAttributesVec2f = NULL;
+ _userAttributesVec3f = NULL;
+ _visible = true;
+}
+
+StrokeAttribute::StrokeAttribute(const StrokeAttribute& iBrother)
+{
+ _alpha = iBrother._alpha;
+ _thickness[0] = iBrother._thickness[0];
+ _thickness[1] = iBrother._thickness[1];
+ for (int i = 0; i < 3; ++i)
+ _color[i] = iBrother._color[i];
+ _visible = iBrother._visible;
+ if (iBrother._userAttributesReal)
+ _userAttributesReal = new realMap(*iBrother._userAttributesReal);
+ else
+ _userAttributesReal = NULL;
+ if (iBrother._userAttributesVec2f)
+ _userAttributesVec2f = new Vec2fMap(*iBrother._userAttributesVec2f);
+ else
+ _userAttributesVec2f = NULL;
+ if (iBrother._userAttributesVec3f)
+ _userAttributesVec3f = new Vec3fMap(*iBrother._userAttributesVec3f);
+ else
+ _userAttributesVec3f = NULL;
+}
+
+StrokeAttribute::StrokeAttribute(float iRColor, float iGColor, float iBColor, float iAlpha,
+ float iRThickness, float iLThickness)
+{
+ _color[0] = iRColor;
+ _color[1] = iGColor;
+ _color[2] = iBColor;
+
+ _alpha = iAlpha;
+
+ _thickness[0] = iRThickness;
+ _thickness[1] = iLThickness;
+
+ _visible = true;
+
+ _userAttributesReal = NULL;
+ _userAttributesVec2f = NULL;
+ _userAttributesVec3f = NULL;
+}
+
+StrokeAttribute::StrokeAttribute(const StrokeAttribute& a1, const StrokeAttribute& a2, float t)
+{
+ _alpha = (1 - t) * a1._alpha + t * a2._alpha;
+ _thickness[0] = (1 - t) * a1._thickness[0] + t * a2._thickness[0];
+ _thickness[1] = (1 - t) * a1._thickness[1] + t * a2._thickness[1];
+ for (int i = 0; i < 3; ++i)
+ _color[i] = (1 - t) * a1._color[i] + t * a2._color[i];
+
+ _visible = true;
+
+ // FIXME: to be checked (and enhanced)
+ if ((a1._userAttributesReal) && (a2._userAttributesReal)) {
+ if (a1._userAttributesReal->size() == a2._userAttributesReal->size()) {
+ _userAttributesReal = new realMap;
+ realMap::iterator it1 = a1._userAttributesReal->begin(), it1end = a1._userAttributesReal->end();
+ realMap::iterator it2 = a2._userAttributesReal->begin(), it2end = a2._userAttributesReal->end();
+ for (; it1 != it1end; ++it1) {
+ (*_userAttributesReal)[(*it1).first] = ((1 - t) * (*it1).second + t * (*it2).second);
+ }
+ }
+ }
+ else {
+ _userAttributesReal = NULL;
+ }
+ if ((a1._userAttributesVec2f) && (a2._userAttributesVec2f)) {
+ if (a1._userAttributesVec2f->size() == a2._userAttributesVec2f->size()) {
+ _userAttributesVec2f = new Vec2fMap;
+ Vec2fMap::iterator it1 = a1._userAttributesVec2f->begin(), it1end = a1._userAttributesVec2f->end();
+ Vec2fMap::iterator it2 = a2._userAttributesVec2f->begin(), it2end = a2._userAttributesVec2f->end();
+ for (; it1 != it1end; ++it1) {
+ (*_userAttributesVec2f)[(*it1).first] = ((1 - t) * (*it1).second + t * (*it2).second);
+ }
+ }
+ }
+ else {
+ _userAttributesVec2f = NULL;
+ }
+ if ((a1._userAttributesVec3f) && (a2._userAttributesVec3f)) {
+ if (a1._userAttributesVec3f->size() == a2._userAttributesVec3f->size()) {
+ _userAttributesVec3f = new Vec3fMap;
+ Vec3fMap::iterator it1 = a1._userAttributesVec3f->begin(), it1end = a1._userAttributesVec3f->end();
+ Vec3fMap::iterator it2 = a2._userAttributesVec3f->begin(), it2end = a2._userAttributesVec3f->end();
+ for (; it1 != it1end; ++it1) {
+ (*_userAttributesVec3f)[(*it1).first] = ((1 - t) * (*it1).second + t * (*it2).second);
+ }
+ }
+ }
+ else {
+ _userAttributesVec3f = NULL;
+ }
+}
+
+StrokeAttribute::~StrokeAttribute()
+{
+ if (_userAttributesReal) {
+ _userAttributesReal->clear();
+ delete _userAttributesReal;
+ }
+ if (_userAttributesVec2f) {
+ _userAttributesVec2f->clear();
+ delete _userAttributesVec2f;
+ }
+ if (_userAttributesVec3f) {
+ _userAttributesVec3f->clear();
+ delete _userAttributesVec3f;
+ }
+}
+
+StrokeAttribute& StrokeAttribute::operator=(const StrokeAttribute& iBrother)
+{
+ int i;
+ _alpha = iBrother._alpha;
+ _thickness[0] = iBrother._thickness[0];
+ _thickness[1] = iBrother._thickness[1];
+ for (i = 0; i < 3; ++i)
+ _color[i] = iBrother._color[i];
+ _visible = iBrother._visible;
+ if (iBrother._userAttributesReal) {
+ if (!_userAttributesReal)
+ _userAttributesReal = new realMap;
+ _userAttributesReal = new realMap(*(iBrother._userAttributesReal));
+ }
+ else {
+ _userAttributesReal = NULL;
+ }
+ if (iBrother._userAttributesVec2f) {
+ if (!_userAttributesVec2f)
+ _userAttributesVec2f = new Vec2fMap;
+ _userAttributesVec2f = new Vec2fMap(*(iBrother._userAttributesVec2f));
+ }
+ else {
+ _userAttributesVec2f = NULL;
+ }
+ if (iBrother._userAttributesVec3f) {
+ if (!_userAttributesVec3f)
+ _userAttributesVec3f = new Vec3fMap;
+ _userAttributesVec3f = new Vec3fMap(*(iBrother._userAttributesVec3f));
+ }
+ else {
+ _userAttributesVec3f = NULL;
+ }
+ return *this;
+}
+
+float StrokeAttribute::getAttributeReal(const char *iName) const
+{
+ if (!_userAttributesReal) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "StrokeAttribute warning: no real attribute was defined" << endl;
+ }
+ return 0.0f;
+ }
+ realMap::iterator a = _userAttributesReal->find(iName);
+ if (a == _userAttributesReal->end()) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "StrokeAttribute warning: no real attribute was added with the name " << iName << endl;
+ }
+ return 0.0f;
+ }
+ return (*a).second;
+}
+
+Vec2f StrokeAttribute::getAttributeVec2f(const char *iName) const
+{
+ if (!_userAttributesVec2f) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "StrokeAttribute warning: no Vec2f attribute was defined" << endl;
+ }
+ return 0;
+ }
+ Vec2fMap::iterator a = _userAttributesVec2f->find(iName);
+ if (a == _userAttributesVec2f->end()) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "StrokeAttribute warning: no Vec2f attribute was added with the name " << iName << endl;
+ }
+ return 0;
+ }
+ return (*a).second;
+}
+
+Vec3f StrokeAttribute::getAttributeVec3f(const char *iName) const
+{
+ if (!_userAttributesVec3f) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "StrokeAttribute warning: no Vec3f attribute was defined" << endl;
+ }
+ return 0;
+ }
+ Vec3fMap::iterator a = _userAttributesVec3f->find(iName);
+ if (a == _userAttributesVec3f->end()) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "StrokeAttribute warning: no Vec3f attribute was added with the name " << iName << endl;
+ }
+ return 0;
+ }
+ return (*a).second;
+}
+
+bool StrokeAttribute::isAttributeAvailableReal(const char *iName) const
+{
+ if (!_userAttributesReal) {
+ return false;
+ }
+ realMap::iterator a = _userAttributesReal->find(iName);
+ if (a == _userAttributesReal->end()) {
+ return false;
+ }
+ return true;
+}
+
+bool StrokeAttribute::isAttributeAvailableVec2f(const char *iName) const
+{
+ if (!_userAttributesVec2f) {
+ return false;
+ }
+ Vec2fMap::iterator a = _userAttributesVec2f->find(iName);
+ if (a == _userAttributesVec2f->end()) {
+ return false;
+ }
+ return true;
+}
+
+bool StrokeAttribute::isAttributeAvailableVec3f(const char *iName) const
+{
+ if (!_userAttributesVec3f) {
+ return false;
+ }
+ Vec3fMap::iterator a = _userAttributesVec3f->find(iName);
+ if (a == _userAttributesVec3f->end()) {
+ return false;
+ }
+ return true;
+}
+
+void StrokeAttribute::setAttributeReal(const char *iName, float att)
+{
+ if (!_userAttributesReal)
+ _userAttributesReal = new realMap;
+ (*_userAttributesReal)[iName] = att;
+}
+
+void StrokeAttribute::setAttributeVec2f(const char *iName, const Vec2f& att)
+{
+ if (!_userAttributesVec2f)
+ _userAttributesVec2f = new Vec2fMap;
+ (*_userAttributesVec2f)[iName] = att;
+}
+
+void StrokeAttribute::setAttributeVec3f(const char *iName, const Vec3f& att)
+{
+ if (!_userAttributesVec3f)
+ _userAttributesVec3f = new Vec3fMap;
+ (*_userAttributesVec3f)[iName] = att;
+}
+
+
+/**********************************/
+/* */
+/* */
+/* StrokeVertex */
+/* */
+/* */
+/**********************************/
+
+StrokeVertex::StrokeVertex() : CurvePoint()
+{
+ _CurvilignAbscissa = 0.0f;
+ _StrokeLength = 0.0f;
+}
+
+StrokeVertex::StrokeVertex(const StrokeVertex& iBrother) : CurvePoint(iBrother)
+{
+ _Attribute = iBrother._Attribute;
+ _CurvilignAbscissa = 0.0f;
+ _StrokeLength = 0.0f;
+}
+
+StrokeVertex::StrokeVertex(SVertex *iSVertex) : CurvePoint(iSVertex, 0, 0.0f)
+{
+ _CurvilignAbscissa = 0.0f;
+ _StrokeLength = 0.0f;
+}
+
+StrokeVertex::StrokeVertex(CurvePoint *iPoint) : CurvePoint(*iPoint)
+{
+ _CurvilignAbscissa = 0.0f;
+ _StrokeLength = 0.0f;
+}
+
+StrokeVertex::StrokeVertex(StrokeVertex *iA, StrokeVertex *iB, float t3) : CurvePoint(iA, iB, t3)
+{
+ // interpolate attributes:
+ _Attribute = StrokeAttribute(iA->attribute(), iB->attribute(), t3);
+ _CurvilignAbscissa = (1 - t3) * iA->curvilinearAbscissa() + t3 * iB->curvilinearAbscissa();
+ _StrokeLength = iA->strokeLength();
+}
+
+StrokeVertex::StrokeVertex(SVertex *iSVertex, const StrokeAttribute& iAttribute) : CurvePoint(iSVertex, 0, 0.0f)
+{
+ _Attribute = iAttribute;
+ _CurvilignAbscissa = 0.0f;
+ _StrokeLength = 0.0f;
+}
+
+StrokeVertex::~StrokeVertex() {}
+
+StrokeVertex& StrokeVertex::operator=(const StrokeVertex& iBrother)
+{
+ ((CurvePoint*)this)->operator=(iBrother);
+ _Attribute = iBrother._Attribute;
+
+ _CurvilignAbscissa = 0.0f;
+
+ _StrokeLength = 0.0f;
+ return *this;
+}
+
+
+
+/**********************************/
+/* */
+/* */
+/* Stroke */
+/* */
+/* */
+/**********************************/
+
+Stroke::Stroke()
+{
+ _Length = 0;
+ _id = 0;
+ _sampling = FLT_MAX;
+ //_mediumType = DEFAULT_STROKE;
+ _mediumType = OPAQUE_MEDIUM;
+ _textureId = 0;
+ _tips = false;
+ _rep = NULL;
+}
+
+Stroke::Stroke(const Stroke& iBrother)
+{
+ for (vertex_container::const_iterator v = iBrother._Vertices.begin(), vend = iBrother._Vertices.end();
+ v != vend;
+ v++)
+ {
+ _Vertices.push_back(*v);
+ }
+ _Length = 0;
+ _id = iBrother._id;
+ _ViewEdges = iBrother._ViewEdges;
+ _sampling = iBrother._sampling;
+ _mediumType = iBrother._mediumType;
+ _textureId = iBrother._textureId;
+ _tips = iBrother._tips;
+ if (iBrother._rep)
+ _rep = new StrokeRep(*(iBrother._rep));
+ else
+ _rep = NULL;
+}
+
+Stroke::~Stroke()
+{
+ if (!_Vertices.empty()) {
+ for (vertex_container::iterator v = _Vertices.begin(), vend = _Vertices.end(); v != vend; v++) {
+ delete (*v);
+ }
+ _Vertices.clear();
+ }
+
+ _ViewEdges.clear();
+ if (_rep) {
+ delete _rep;
+ _rep = NULL;
+ }
+}
+
+Stroke& Stroke::operator=(const Stroke& iBrother)
+{
+ if (!_Vertices.empty())
+ _Vertices.clear();
+
+ for (vertex_container::const_iterator v = iBrother._Vertices.begin(), vend = iBrother._Vertices.end();
+ v != vend;
+ v++)
+ {
+ _Vertices.push_back(*v);
+ }
+ _Length = iBrother._Length;
+ _id = iBrother._id;
+ _ViewEdges = iBrother._ViewEdges;
+ _sampling = iBrother._sampling;
+ if (_rep)
+ delete _rep;
+ if (iBrother._rep)
+ _rep = new StrokeRep(*(iBrother._rep));
+ return *this;
+}
+
+void Stroke::setLength(float iLength)
+{
+ _Length = iLength;
+ for (vertex_container::iterator v = _Vertices.begin(), vend = _Vertices.end(); v != vend; ++v) {
+ (*v)->setStrokeLength(iLength);
+ }
+}
+
+float Stroke::ComputeSampling(int iNVertices)
+{
+ if (iNVertices <= (int)_Vertices.size()) //soc
+ return _sampling;
+
+ float sampling = _Length / (float)(iNVertices - _Vertices.size() + 1);
+ return sampling;
+}
+
+class StrokeSegment
+{
+public:
+ StrokeInternal::StrokeVertexIterator _begin;
+ StrokeInternal::StrokeVertexIterator _end;
+ float _length;
+ int _n;
+ float _sampling;
+ bool _resampled;
+
+ StrokeSegment(StrokeInternal::StrokeVertexIterator ibegin, StrokeInternal::StrokeVertexIterator iend,
+ float ilength, int in, float isampling)
+ {
+ _begin = ibegin;
+ _end = iend;
+ _length = ilength;
+ _n = in;
+ _sampling = isampling;
+ _resampled = false;
+ }
+};
+
+void Stroke::Resample(int iNPoints)
+{
+ int vertsize = strokeVerticesSize();
+ if (iNPoints <= vertsize)
+ return;
+
+ StrokeInternal::StrokeVertexIterator it = strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator next = it;
+ ++next;
+ StrokeInternal::StrokeVertexIterator itend = strokeVerticesEnd();
+
+ vertex_container newVertices;
+ real t = 0.0f;
+ StrokeVertex *newVertex = NULL;
+ vector<StrokeSegment> strokeSegments;
+ int N = 0;
+ float meanlength = 0;
+ int nsegments = 0;
+ while ((it != itend) && (next != itend)) {
+ Vec2r a((it)->getPoint());
+ Vec2r b((next)->getPoint());
+ Vec2r vec_tmp(b - a);
+ real norm_var = vec_tmp.norm();
+ int numberOfPointsToAdd = (int)floor((iNPoints - strokeVerticesSize()) * norm_var / _Length);
+ float csampling = norm_var / (float)(numberOfPointsToAdd + 1);
+ strokeSegments.push_back(StrokeSegment(it, next, norm_var, numberOfPointsToAdd, csampling));
+ N += numberOfPointsToAdd;
+ meanlength += norm_var;
+ ++nsegments;
+ ++it;
+ ++next;
+ }
+ meanlength /= (float)nsegments;
+
+ // if we don't have enough points let's resample finer some segments
+ int NPointsToAdd = iNPoints - vertsize;
+ bool checkEveryone = false;
+ while (N < NPointsToAdd) {
+ for (vector<StrokeSegment>::iterator s = strokeSegments.begin(), send = strokeSegments.end(); s != send; ++s) {
+ if (s->_sampling == 0.0f)
+ continue;
+
+ if (s->_resampled == false) {
+ if ((!checkEveryone) && (s->_length < meanlength))
+ continue;
+ //resample
+ s->_n = s->_n + 1;
+ s->_sampling = s->_length / (float)(s->_n + 1);
+ s->_resampled = true;
+ N++;
+ if (N == NPointsToAdd)
+ break;
+ }
+ }
+ checkEveryone = true;
+ }
+ //actually resample:
+ for (vector<StrokeSegment>::iterator s = strokeSegments.begin(), send = strokeSegments.end(); s != send; ++s) {
+ newVertices.push_back(&(*(s->_begin)));
+ if (s->_sampling < _sampling)
+ _sampling = s->_sampling;
+
+ t = s->_sampling / s->_length;
+ for (int i = 0; i < s->_n; ++i) {
+ newVertex = new StrokeVertex(&(*(s->_begin)), &(*(s->_end)), t);
+ newVertices.push_back(newVertex);
+ t += s->_sampling / s->_length;
+ }
+ it = s->_begin;
+ next = s->_end;
+ }
+
+ // add last:
+ ++it;
+ ++next;
+ if ((it != itend) && (next == itend)/* && (t == 0.0f)*/)
+ newVertices.push_back(&(*it));
+
+ int newsize = newVertices.size();
+ if (newsize != iNPoints)
+ cerr << "Warning: incorrect points number" << endl;
+
+ _Vertices.clear();
+ _Vertices = newVertices;
+ newVertices.clear();
+
+ if (_rep) {
+ delete _rep;
+ _rep = new StrokeRep(this);
+ }
+}
+
+void Stroke::Resample(float iSampling)
+{
+ //cerr << "old size :" << strokeVerticesSize() << endl;
+ if (iSampling == 0)
+ return;
+ if (iSampling >= _sampling)
+ return;
+
+ _sampling = iSampling;
+ // Resample...
+ //real curvilinearLength = 0.0f;
+ vertex_container newVertices;
+ real t = 0.0f;
+ const real limit = 0.99;
+ StrokeVertex *newVertex = NULL;
+ StrokeInternal::StrokeVertexIterator it = strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator next = it;
+ ++next;
+ StrokeInternal::StrokeVertexIterator itend = strokeVerticesEnd();
+ while ((it != itend) && (next != itend)) {
+ newVertices.push_back(&(*it));
+ Vec2r a((it)->getPoint());
+ Vec2r b((next)->getPoint());
+ Vec2r vec_tmp(b - a);
+ real norm_var = vec_tmp.norm();
+ if (norm_var <= _sampling) {
+ //curvilinearLength += norm_var;
+ ++it;
+ ++next;
+ continue;
+ }
+
+ //curvilinearLength += _sampling;
+ t = _sampling / norm_var;
+ while (t < limit) {
+ newVertex = new StrokeVertex(&(*it), &(*next), t);
+ //newVertex->setCurvilinearAbscissa(curvilinearLength);
+ newVertices.push_back(newVertex);
+ t = t + _sampling / norm_var;
+ }
+ ++it;
+ ++next;
+ }
+ // add last:
+ if ((it != itend) && (next == itend)/* && (t == 0.f)*/)
+ newVertices.push_back(&(*it));
+
+ _Vertices.clear();
+ _Vertices = newVertices;
+ newVertices.clear();
+
+ if (_rep) {
+ delete _rep;
+ _rep = new StrokeRep(this);
+ }
+}
+
+void Stroke::RemoveVertex(StrokeVertex *iVertex)
+{
+ vertex_container::iterator it = _Vertices.begin(), itend = _Vertices.end();
+ for (; it != itend; ++it) {
+ if ((*it) == iVertex) {
+ delete iVertex;
+ it = _Vertices.erase(it); // it is now the element just after the erased element
+ break;
+ }
+ }
+ UpdateLength();
+}
+
+void Stroke::InsertVertex(StrokeVertex *iVertex, StrokeInternal::StrokeVertexIterator next)
+{
+ vertex_container::iterator it = _Vertices.begin(), itend = _Vertices.end();
+
+ vertex_container::iterator itnext = next.getIt();
+ _Vertices.insert(itnext, iVertex);
+ UpdateLength();
+}
+
+void Stroke::UpdateLength()
+{
+ // recompute curvilinear abscissa and stroke length
+ float curvabsc = 0.0f;
+ vertex_container::iterator it = _Vertices.begin(), itend = _Vertices.end();
+ vertex_container::iterator previous = it;
+ for (; it != itend; ++it) {
+ curvabsc += ((*it)->getPoint() - (*previous)->getPoint()).norm();
+ (*it)->setCurvilinearAbscissa(curvabsc);
+ previous = it;
+ }
+ _Length = curvabsc;
+ for (it = _Vertices.begin(); it != itend; ++it) {
+ (*it)->setStrokeLength(_Length);
+ }
+}
+
+//! embedding vertex iterator
+Stroke::const_vertex_iterator Stroke::vertices_begin() const
+{
+ return const_vertex_iterator(_Vertices.begin(), _Vertices.begin(), _Vertices.end());
+}
+
+Stroke::const_vertex_iterator Stroke::vertices_end() const
+{
+ return const_vertex_iterator(_Vertices.end(), _Vertices.begin(), _Vertices.end());
+}
+
+Stroke::vertex_iterator Stroke::vertices_end()
+{
+ return vertex_iterator(_Vertices.end(), _Vertices.begin(), _Vertices.end());
+}
+
+StrokeInternal::StrokeVertexIterator Stroke::strokeVerticesBegin(float t)
+{
+ if ((t != 0) && (t < _sampling))
+ Resample(t);
+ return StrokeInternal::StrokeVertexIterator(this->_Vertices.begin(), this->_Vertices.begin(),
+ this->_Vertices.end());
+}
+
+StrokeInternal::StrokeVertexIterator Stroke::strokeVerticesEnd()
+{
+ return StrokeInternal::StrokeVertexIterator(this->_Vertices.end(), this->_Vertices.begin(), this->_Vertices.end());
+}
+
+Interface0DIterator Stroke::verticesBegin()
+{
+Interface0DIterator ret(new StrokeInternal::StrokeVertexIterator(this->_Vertices.begin(), this->_Vertices.begin(),
+ this->_Vertices.end()));
+return ret;
+}
+
+Interface0DIterator Stroke::verticesEnd()
+{
+ Interface0DIterator ret(new StrokeInternal::StrokeVertexIterator(this->_Vertices.end(), this->_Vertices.begin(),
+ this->_Vertices.end()));
+ return ret;
+}
+
+Interface0DIterator Stroke::pointsBegin(float t)
+{
+ return verticesBegin(); // FIXME
+}
+
+Interface0DIterator Stroke::pointsEnd(float t)
+{
+ return verticesEnd();
+}
+
+void Stroke::ScaleThickness(float iFactor)
+{
+ for (vertex_container::iterator it = _Vertices.begin(), itend = _Vertices.end(); it != itend; ++it) {
+ StrokeAttribute& attr = (*it)->attribute();
+ attr.setThickness(iFactor * attr.getThicknessR(), iFactor * attr.getThicknessL());
+ }
+}
+
+void Stroke::Render(const StrokeRenderer *iRenderer)
+{
+ if (!_rep)
+ _rep = new StrokeRep(this);
+ iRenderer->RenderStrokeRep(_rep);
+}
+
+void Stroke::RenderBasic(const StrokeRenderer *iRenderer)
+{
+ if (!_rep)
+ _rep = new StrokeRep(this);
+ iRenderer->RenderStrokeRepBasic(_rep);
+}
+
+Stroke::vertex_iterator Stroke::vertices_begin(float sampling)
+{
+ // Resample if necessary
+ if ((sampling != 0) && (sampling < _sampling))
+ Resample(sampling);
+ return vertex_iterator(_Vertices.begin(), _Vertices.begin(), _Vertices.end());
+ //return _Vertices.begin();
+}
+
+#if 0
+Stroke::vertex_iterator Stroke::vertices_last()
+{
+ vertex_iterator res = vertices_begin();
+ vertex_iterator next = res;
+ ++next;
+ while (!next.end()) {
+ ++next;
+ ++res;
+ }
+ return res;
+}
+
+Stroke::const_vertex_iterator Stroke::vertices_last() const
+{
+ const_vertex_iterator res = vertices_begin();
+ const_vertex_iterator next = res;
+ ++next;
+ while (!next.end()) {
+ ++next;
+ ++res;
+ }
+ return res;
+}
+
+Stroke::vertex_container::reverse_iterator Stroke::vertices_last(float sampling)
+{
+ // Resample if necessary
+ if (sampling < _sampling)
+ Resample(sampling);
+ return _Vertices.rbegin();
+}
+
+
+inline Vec3r shaded_color(int iCombination = 0) const;
+
+inline Vec<3, real> Stroke::orientation2d(const_vertex_iterator it) const
+{
+ return iterator_edge_orientation2d_function<Stroke, const_vertex_iterator>(this, it);
+}
+
+Vec3r Stroke::orientation2d(int iCombination) const
+{
+ return edge_orientation2d_function<Stroke>(*this, iCombination);
+}
+
+inline Vec3r Stroke::orientation3d(const_vertex_iterator it) const
+{
+ return iterator_edge_orientation3d_function<Stroke, const_vertex_iterator>(*this, it);
+}
+
+Vec3r Stroke::orientation3d(int iCombination) const
+{
+ return edge_orientation3d_function<Stroke>(*this, iCombination);
+}
+
+Material Stroke::material() const
+{
+ const_vertex_iterator v = vertices_begin(), vend = strokeVerticesEnd();
+ Material mat = (*v)->material();
+ for (; v != vend; ++v) {
+ if (mat != (*v)->material())
+ Exception::raiseException();
+ }
+ return mat;
+}
+
+int Stroke::qi() const
+{
+ const_vertex_iterator v = vertices_begin(), vend = vertices_end();
+ int qi_= (*v)->qi();
+ for (; v != vend; ++v) {
+ if ((*v)->qi() != qi_)
+ Exception::raiseException();
+ }
+ return qi_;
+}
+
+inline occluder_container::const_iterator occluders_begin() const
+{
+ return _FEdgeA->occluders().begin();
+}
+
+inline occluder_container::const_iterator occluders_end() const
+{
+ return _FEdgeA->occluders().end();
+}
+
+int Stroke::occluders_size() const
+{
+ return qi();
+}
+
+bool Stroke::occluders_empty() const
+{
+ const_vertex_iterator v = vertices_begin(), vend = vertices_end();
+ bool empty = (*v)->occluders_empty();
+ for (; v != vend; ++v) {
+ if ((*v)->occluders_empty() != empty)
+ Exception::raiseException();
+ }
+ return empty;
+}
+
+#if 0
+inline const polygon3d& occludee() const
+{
+ return *(_FEdgeA->aFace());
+}
+#endif
+
+const SShape * Stroke::occluded_shape() const
+{
+ const_vertex_iterator v = vertices_begin(), vend = vertices_end();
+ const SShape *sshape = (*v)->occluded_shape();
+ for (; v != vend; ++v) {
+ if ((*v)->occluded_shape() != sshape)
+ Exception::raiseException();
+ }
+ return sshape;
+}
+
+const bool Stroke::occludee_empty() const
+{
+ const_vertex_iterator v = vertices_begin(), vend = vertices_end();
+ bool empty = (*v)->occludee_empty();
+ for (; v != vend; ++v) {
+ if ((*v)->occludee_empty() != empty)
+ Exception::raiseException();
+ }
+ return empty;
+}
+
+const SShape * Stroke::shape() const
+{
+ const_vertex_iterator v = vertices_begin(), vend = vertices_end();
+ const SShape *sshape = (*v)->shape();
+ for (; v != vend; ++v) {
+ if ((*v)->shape() != sshape)
+ Exception::raiseException();
+ }
+ return sshape;
+}
+
+real Stroke::z_discontinuity(int iCombination) const
+{
+ return z_discontinuity_edge_function<Stroke>(*this, iCombination);
+}
+
+Vec3r Stroke::curvature2d_as_vector(int iCombination) const
+{
+ return curvature2d_as_vector_edge_function<Stroke>(*this, iCombination);
+}
+
+real Stroke::curvature2d_as_angle(int iCombination) const
+{
+ return curvature2d_as_angle_edge_function<Stroke>(*this, iCombination);
+}
+
+float Stroke::shape_importance(int iCombination) const
+{
+ return shape_importance_edge_function<Stroke>(*this, iCombination);
+}
+
+
+float Stroke::local_average_depth(int iCombination ) const
+{
+ return local_average_depth_edge_function<Stroke >(*this, iCombination);
+}
+
+float Stroke::local_depth_variance(int iCombination) const
+{
+ return local_depth_variance_edge_function<Stroke>(*this, iCombination);
+}
+
+real Stroke::local_average_density(float sigma , int iCombination ) const
+{
+ return density_edge_function<Stroke>(*this, iCombination);
+}
+#endif
diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h
new file mode 100644
index 00000000000..51733a058a9
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/Stroke.h
@@ -0,0 +1,822 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_STROKE_H__
+#define __FREESTYLE_STROKE_H__
+
+/** \file blender/freestyle/intern/stroke/Stroke.h
+ * \ingroup freestyle
+ * \brief Classes to define a stroke
+ * \author Stephane Grabli
+ * \date 09/09/2002
+ */
+
+#include <map>
+#include <vector>
+
+#include "Curve.h"
+
+#include "../view_map/Interface1D.h"
+#include "../view_map/Silhouette.h"
+
+#include "../system/FreestyleConfig.h"
+#include "../system/StringUtils.h"
+
+
+//
+// StrokeAttribute
+//
+////////////////////////////////////////////////////////
+
+/*! Class to define an attribute associated to a Stroke Vertex.
+ * This attribute stores the color, alpha and thickness values for a Stroke Vertex.
+ */
+class LIB_STROKE_EXPORT StrokeAttribute
+{
+public:
+ /*! default constructor */
+ StrokeAttribute();
+
+ /*! Copy constructor */
+ StrokeAttribute(const StrokeAttribute& iBrother);
+
+ /*! Builds a stroke vertex attribute from a set of parameters.
+ * \param iRColor
+ * The Red Component value.
+ * \param iGColor
+ * The Green Component value.
+ * \param iBColor
+ * The Blue Component value.
+ * \param iAlpha
+ * The transparency value
+ * \param iRThickness
+ * The thickness of the stroke on the right
+ * \param iLThickness
+ * The Thickness of the stroke on the left
+ */
+ StrokeAttribute(float iRColor, float iGColor, float iBColor, float iAlpha, float iRThickness, float iLThickness);
+
+ /*! Interpolation constructor.
+ * Builds a StrokeAttribute from two StrokeAttributes and an interpolation parameter.
+ * \param a1
+ * The first Attribute.
+ * \param a2
+ * The second parameter.
+ * \param t
+ * The interpolation parameter.
+ */
+ StrokeAttribute(const StrokeAttribute& a1, const StrokeAttribute& a2, float t);
+
+ /*! destructor */
+ virtual ~StrokeAttribute();
+
+ /* operators */
+ /*! operator = */
+ StrokeAttribute& operator=(const StrokeAttribute& iBrother);
+
+ /* accessors */
+ /*! Returns the attribute's color.
+ * \return The array of 3 floats containing the R,G,B values of the attribute's color.
+ */
+ inline const float *getColor() const
+ {
+ return _color;
+ }
+
+ /*! Returns the R color component. */
+ inline const float getColorR() const
+ {
+ return _color[0];
+ }
+
+ /*! Returns the G color component. */
+ inline const float getColorG() const
+ {
+ return _color[1];
+ }
+
+ /*! Returns the B color component. */
+ inline const float getColorB() const
+ {
+ return _color[2];
+ }
+
+ /*! Returns the RGB color components. */
+ inline Vec3f getColorRGB() const
+ {
+ return Vec3f(_color[0], _color[1], _color[2]);
+ }
+
+ /*! Returns the alpha color component. */
+ inline float getAlpha() const
+ {
+ return _alpha;
+ }
+
+ /*! Returns the attribute's thickness.
+ * \return an array of 2 floats. the first value is the thickness on the right of the vertex when following
+ * the stroke, the second one is the thickness on the left.
+ */
+ inline const float *getThickness() const
+ {
+ return _thickness;
+ }
+
+ /*! Returns the thickness on the right of the vertex when following the stroke. */
+ inline const float getThicknessR() const
+ {
+ return _thickness[0];
+ }
+
+ /*! Returns the thickness on the left of the vertex when following the stroke. */
+ inline const float getThicknessL() const
+ {
+ return _thickness[1];
+ }
+
+ /*! Returns the thickness on the right and on the left of the vertex when following the stroke. */
+ inline Vec2f getThicknessRL() const
+ {
+ return Vec2f(_thickness[0], _thickness[1]);
+ }
+
+ /*! Returns true if the strokevertex is visible, false otherwise */
+ inline bool isVisible() const
+ {
+ return _visible;
+ }
+
+ /*! Returns an attribute of type real
+ * \param iName
+ * The name of the attribute
+ */
+ float getAttributeReal(const char *iName) const;
+
+ /*! Returns an attribute of type Vec2f
+ * \param iName
+ * The name of the attribute
+ */
+ Vec2f getAttributeVec2f(const char *iName) const;
+
+ /*! Returns an attribute of type Vec3f
+ * \param iName
+ * The name of the attribute
+ */
+ Vec3f getAttributeVec3f(const char *iName) const;
+
+ /*! Checks whether the attribute iName is availbale */
+ bool isAttributeAvailableReal(const char *iName) const;
+
+ /*! Checks whether the attribute iName is availbale */
+ bool isAttributeAvailableVec2f(const char *iName) const;
+
+ /*! Checks whether the attribute iName is availbale */
+ bool isAttributeAvailableVec3f(const char *iName) const;
+
+ /* modifiers */
+ /*! sets the attribute's color.
+ * \param r
+ * The new R value.
+ * \param g
+ * The new G value.
+ * \param b
+ * The new B value.
+ */
+ inline void setColor(float r, float g, float b)
+ {
+ _color[0] = r;
+ _color[1] = g;
+ _color[2] = b;
+ }
+
+ /*! sets the attribute's color.
+ * \param iRGB
+ * The new RGB values.
+ */
+ inline void setColor(const Vec3f& iRGB)
+ {
+ _color[0] = iRGB[0];
+ _color[1] = iRGB[1];
+ _color[2] = iRGB[2];
+ }
+
+ /*! sets the attribute's alpha value.
+ * \param alpha
+ * The new alpha value.
+ */
+ inline void setAlpha(float alpha)
+ {
+ _alpha = alpha;
+ }
+
+ /*! sets the attribute's thickness.
+ * \param tr
+ * The thickness on the right of the vertex when following the stroke.
+ * \param tl
+ * The thickness on the left of the vertex when following the stroke.
+ */
+ inline void setThickness(float tr, float tl)
+ {
+ _thickness[0] = tr;
+ _thickness[1] = tl;
+ }
+
+ /*! sets the attribute's thickness.
+ * \param tRL
+ * The thickness on the right and on the left of the vertex when following the stroke.
+ */
+ inline void setThickness(const Vec2f& tRL)
+ {
+ _thickness[0] = tRL[0];
+ _thickness[1] = tRL[1];
+ }
+
+ /*! sets the visible flag. True means visible. */
+ inline void setVisible(bool iVisible)
+ {
+ _visible = iVisible;
+ }
+
+ /*! Adds a user defined attribute of type real
+ * If there is no attribute of name iName, it is added.
+ * Otherwise, the new value replaces the old one.
+ * \param iName
+ * The name of the attribute
+ * \param att
+ * The attribute's value
+ */
+ void setAttributeReal(const char *iName, float att);
+
+ /*! Adds a user defined attribute of type Vec2f
+ * If there is no attribute of name iName, it is added.
+ * Otherwise, the new value replaces the old one.
+ * \param iName
+ * The name of the attribute
+ * \param att
+ * The attribute's value
+ */
+ void setAttributeVec2f(const char *iName, const Vec2f& att);
+
+ /*! Adds a user defined attribute of type Vec3f
+ * If there is no attribute of name iName, it is added.
+ * Otherwise, the new value replaces the old one.
+ * \param iName
+ * The name of the attribute
+ * \param att
+ * The attribute's value
+ */
+ void setAttributeVec3f(const char *iName, const Vec3f& att);
+
+private:
+ typedef std::map<const char*, float, StringUtils::ltstr> realMap;
+ typedef std::map<const char*, Vec2f, StringUtils::ltstr> Vec2fMap;
+ typedef std::map<const char*, Vec3f, StringUtils::ltstr> Vec3fMap;
+
+ float _color[3]; //! the color
+ float _alpha; //! alpha
+ float _thickness[2]; //! the thickness on the right and on the left of the backbone vertex (the stroke is oriented)
+ bool _visible;
+ realMap *_userAttributesReal;
+ Vec2fMap *_userAttributesVec2f;
+ Vec3fMap *_userAttributesVec3f;
+};
+
+
+//
+// StrokeVertex
+//
+////////////////////////////////////////////////////////
+
+/*! Class to define a stroke vertex. */
+class LIB_STROKE_EXPORT StrokeVertex : public CurvePoint
+{
+public: // Implementation of Interface0D
+ /*! Returns the string "StrokeVertex" */
+ virtual string getExactTypeName() const
+ {
+ return "StrokeVertex";
+ }
+
+private:
+ StrokeAttribute _Attribute; //! The attribute associated to the vertex
+ float _CurvilignAbscissa; //! the curvilign abscissa
+ float _StrokeLength; // stroke length
+
+public:
+ /*! default constructor */
+ StrokeVertex();
+
+ /*! Copy constructor */
+ StrokeVertex(const StrokeVertex& iBrother);
+
+ /*! Builds a stroke vertex from a SVertex */
+ StrokeVertex(SVertex *iSVertex);
+
+ /*! Builds a stroke vertex from a CurvePoint */
+ StrokeVertex(CurvePoint *iPoint);
+
+ /*! Builds Stroke Vertex from 2 stroke vertices and an interpolation parameter*/
+ StrokeVertex(StrokeVertex *iA, StrokeVertex *iB, float t3);
+
+ /*! Builds a stroke from a view vertex and an attribute */
+ StrokeVertex(SVertex *iSVertex, const StrokeAttribute& iAttribute);
+
+ /*! destructor */
+ virtual ~StrokeVertex();
+
+ /* operators */
+ /*! operator = */
+ StrokeVertex& operator=(const StrokeVertex& iBrother);
+
+ /* accessors */
+ /*! Returns the 2D point x coordinate */
+ inline real x() const
+ {
+ return _Point2d[0];
+ }
+
+ /*! Returns the 2D point y coordinate */
+ inline real y() const
+ {
+ return _Point2d[1];
+ }
+
+ /*! Returns the 2D point coordinates as a Vec2d */
+ Vec2f getPoint ()
+ {
+ return Vec2f((float)point2d()[0], (float)point2d()[1]);
+ }
+
+ /*! Returns the ith 2D point coordinate (i=0 or 1)*/
+ inline real operator[](const int i) const
+ {
+ return _Point2d[i];
+ }
+
+ /*! Returns the StrokeAttribute for this StrokeVertex */
+ inline const StrokeAttribute& attribute() const
+ {
+ return _Attribute;
+ }
+
+ /*! Returns a non-const reference to the StrokeAttribute of this StrokeVertex */
+ inline StrokeAttribute& attribute()
+ {
+ return _Attribute;
+ }
+
+ /*! Returns the curvilinear abscissa */
+ inline float curvilinearAbscissa() const
+ {
+ return _CurvilignAbscissa;
+ }
+
+ /*! Returns the length of the Stroke to which this StrokeVertex belongs */
+ inline float strokeLength() const
+ {
+ return _StrokeLength;
+ }
+
+ /*! Returns the curvilinear abscissa of this StrokeVertex in the Stroke */
+ inline float u() const
+ {
+ return _CurvilignAbscissa / _StrokeLength;
+ }
+
+ /* modifiers */
+ /*! sets the 2D x value */
+ inline void setX(real x)
+ {
+ _Point2d[0] = x;
+ }
+
+ /*! sets the 2D y value */
+ inline void setY(real y)
+ {
+ _Point2d[1] = y;
+ }
+
+ /*! sets the 2D x and y values */
+ inline void setPoint(real x, real y)
+ {
+ _Point2d[0] = x;
+ _Point2d[1] = y;
+ }
+
+ /*! sets the 2D x and y values */
+ inline void setPoint(const Vec2f& p)
+ {
+ _Point2d[0] = p[0];
+ _Point2d[1] = p[1];
+ }
+
+ /*! Returns a reference to the ith 2D point coordinate (i=0 or 1) */
+ inline real& operator[](const int i)
+ {
+ return _Point2d[i];
+ }
+
+ /*! sets the attribute. */
+ inline void setAttribute(const StrokeAttribute& iAttribute)
+ {
+ _Attribute = iAttribute;
+ }
+
+ /*! sets the curvilinear abscissa of this StrokeVertex in the Stroke */
+ inline void setCurvilinearAbscissa(float iAbscissa)
+ {
+ _CurvilignAbscissa = iAbscissa;
+ }
+
+ /*! sets the Stroke's length (it's only a value stored by the Stroke Vertex, it won't change the real
+ * Stroke's length.)
+ */
+ inline void setStrokeLength(float iLength)
+ {
+ _StrokeLength = iLength;
+ }
+
+ /* interface definition */
+ /* inherited */
+};
+
+
+//
+// Stroke
+//
+////////////////////////////////////////////////////////
+
+class StrokeRenderer;
+class StrokeRep;
+
+namespace StrokeInternal {
+
+class vertex_const_traits;
+class vertex_nonconst_traits;
+template<class Traits> class vertex_iterator_base;
+class StrokeVertexIterator;
+
+} // end of namespace StrokeInternal
+
+/*! Class to define a stroke.
+ * A stroke is made of a set of 2D vertices (StrokeVertex), regularly spaced out.
+ * This set of vertices defines the stroke's backbone geometry.
+ * Each of these stroke vertices defines the stroke's shape and appearance at this vertex position.
+ */
+class LIB_STROKE_EXPORT Stroke : public Interface1D
+{
+public: // Implementation of Interface1D
+ /*! Returns the string "Stroke" */
+ virtual string getExactTypeName() const
+ {
+ return "Stroke";
+ }
+
+ // Data access methods
+
+ /*! Returns the Id of the Stroke */
+ virtual Id getId() const
+ {
+ return _id;
+ }
+
+ /*! The different blending modes available to similate the interaction media-medium. */
+ typedef enum {
+ DRY_MEDIUM, /*!< To simulate a dry medium such as Pencil or Charcoal.*/
+ HUMID_MEDIUM, /*!< To simulate ink painting (color substraction blending).*/
+ OPAQUE_MEDIUM, /*!< To simulate an opaque medium (oil, spray...).*/
+ } MediumType;
+
+public:
+ typedef std::deque<StrokeVertex*> vertex_container; // the vertices container
+ typedef std::vector<ViewEdge*> viewedge_container; // the viewedges container
+ typedef StrokeInternal::vertex_iterator_base<StrokeInternal::vertex_nonconst_traits > vertex_iterator;
+ typedef StrokeInternal::vertex_iterator_base<StrokeInternal::vertex_const_traits> const_vertex_iterator;
+
+public:
+ //typedef StrokeVertex vertex_type;
+
+private:
+ vertex_container _Vertices; //! The stroke's backbone vertices
+ Id _id;
+ float _Length; // The stroke length
+ viewedge_container _ViewEdges;
+ float _sampling;
+ StrokeRenderer *_renderer; // mark implementation OpenGL renderer
+ MediumType _mediumType;
+ unsigned int _textureId;
+ bool _tips;
+ Vec2r _extremityOrientations[2]; // the orientations of the first and last extermity
+ StrokeRep *_rep;
+
+public:
+ /*! default constructor */
+ Stroke();
+
+ /*! copy constructor */
+ Stroke(const Stroke& iBrother);
+
+ /*! Builds a stroke from a set of StrokeVertex.
+ * This constructor is templated by an iterator type.
+ * This iterator type must allow the vertices parsing using the ++ operator.
+ * \param iBegin
+ * The iterator pointing to the first vertex.
+ * \param iEnd
+ * The iterator pointing to the end of the vertex list.
+ */
+ template<class InputVertexIterator>
+ Stroke(InputVertexIterator iBegin, InputVertexIterator iEnd);
+
+ /*! Destructor */
+ virtual ~Stroke();
+
+ /* operators */
+ /*! operator = */
+ Stroke& operator=(const Stroke& iBrother);
+
+ /*! Compute the sampling needed to get iNVertices vertices.
+ * If the specified number of vertices is less than the actual number of vertices, the actual sampling value
+ * is returned. (To remove Vertices, use the RemoveVertex() method of this class).
+ * \param iNVertices
+ * The number of StrokeVertices we eventually want in our Stroke.
+ * \return the sampling that must be used in the Resample(float) method.
+ * @see Resample(int)
+ * @see Resample(float)
+ */
+ float ComputeSampling(int iNVertices);
+
+ /*! Resampling method.
+ * Resamples the curve so that it eventually has iNPoints. That means it is going to add iNPoints-vertices_size,
+ * if vertices_size is the number of points we already have.
+ * If vertices_size >= iNPoints, no resampling is done.
+ * \param iNPoints
+ * The number of vertices we eventually want in our stroke.
+ */
+ void Resample(int iNPoints);
+
+ /*! Resampling method.
+ * Resamples the curve with a given sampling.
+ * If this sampling is < to the actual sampling value, no resampling is done.
+ * \param iSampling
+ * The new sampling value.
+ */
+ void Resample(float iSampling);
+
+ /*! Removes the stroke vertex iVertex
+ * from the stroke.
+ * The length and curvilinear abscissa are updated
+ * consequently.
+ */
+ void RemoveVertex(StrokeVertex *iVertex);
+
+ /*! Inserts the stroke vertex iVertex in the stroke before next.
+ * The length, curvilinear abscissa are updated consequently.
+ * \param iVertex
+ * The StrokeVertex to insert in the Stroke.
+ * \param next
+ * A StrokeVertexIterator pointing to the StrokeVeretx before which iVertex must be inserted.
+ */
+ void InsertVertex(StrokeVertex *iVertex, StrokeInternal::StrokeVertexIterator next);
+
+ /*! Updates the 2D length of the Stroke */
+ void UpdateLength();
+
+ /* Render method */
+ void ScaleThickness(float iFactor);
+ void Render(const StrokeRenderer *iRenderer);
+ void RenderBasic(const StrokeRenderer *iRenderer);
+
+ /* Iterator definition */
+
+ /* accessors */
+ /*! Returns the 2D length of the Stroke */
+ inline real getLength2D() const
+ {
+ return _Length;
+ }
+
+ /*! Returns a reference to the time stamp value of the stroke. */
+ /*! Returns the MediumType used for this Stroke. */
+ inline MediumType getMediumType() const
+ {
+ return _mediumType;
+ }
+
+ /*! Returns the id of the texture used to simulate th marks system for this Stroke */
+ inline unsigned int getTextureId() {return _textureId;}
+
+ /*! Returns true if this Stroke uses a texture with tips, false otherwise. */
+ inline bool hasTips() const
+ {
+ return _tips;
+ }
+
+ /* these advanced iterators are used only in C++ */
+ inline int vertices_size() const
+ {
+ return _Vertices.size();
+ }
+
+ inline viewedge_container::const_iterator viewedges_begin() const
+ {
+ return _ViewEdges.begin();
+ }
+
+ inline viewedge_container::iterator viewedges_begin()
+ {
+ return _ViewEdges.begin();
+ }
+
+ inline viewedge_container::const_iterator viewedges_end() const
+ {
+ return _ViewEdges.end();
+ }
+
+ inline viewedge_container::iterator viewedges_end()
+ {
+ return _ViewEdges.end();
+ }
+
+ inline int viewedges_size() const
+ {
+ return _ViewEdges.size();
+ }
+
+ inline Vec2r getBeginningOrientation() const
+ {
+ return _extremityOrientations[0];
+ }
+
+ inline real getBeginningOrientationX() const
+ {
+ return _extremityOrientations[0].x();
+ }
+
+ inline real getBeginningOrientationY() const
+ {
+ return _extremityOrientations[0].y();
+ }
+
+ inline Vec2r getEndingOrientation() const
+ {
+ return _extremityOrientations[1];
+ }
+
+ inline real getEndingOrientationX() const
+ {
+ return _extremityOrientations[1].x();
+ }
+
+ inline real getEndingOrientationY() const
+ {
+ return _extremityOrientations[1].y();
+ }
+
+
+ /* modifiers */
+ /*! sets the Id of the Stroke. */
+ inline void setId(const Id& id)
+ {
+ _id = id;
+ }
+
+ /*! sets the 2D length of the Stroke. */
+ void setLength(float iLength);
+
+ /*! sets the medium type that must be used for this Stroke. */
+ inline void setMediumType(MediumType iType)
+ {
+ _mediumType = iType;
+ }
+
+ /*! sets the texture id to be used to simulate the marks system for this Stroke. */
+ inline void setTextureId(unsigned int id)
+ {
+ _textureId = id;
+ }
+
+ /*! sets the flag telling whether this stroke is using a texture with tips or not. */
+ inline void setTips(bool iTips)
+ {
+ _tips = iTips;
+ }
+
+ inline void push_back(StrokeVertex *iVertex)
+ {
+ _Vertices.push_back(iVertex);
+ }
+
+ inline void push_front(StrokeVertex *iVertex)
+ {
+ _Vertices.push_front(iVertex);
+ }
+
+ inline void AddViewEdge(ViewEdge *iViewEdge)
+ {
+ _ViewEdges.push_back(iViewEdge);
+ }
+
+ inline void setBeginningOrientation(const Vec2r& iOrientation)
+ {
+ _extremityOrientations[0] = iOrientation;
+ }
+
+ inline void setBeginningOrientation(real x, real y)
+ {
+ _extremityOrientations[0] = Vec2r(x, y);
+ }
+
+ inline void setEndingOrientation(const Vec2r& iOrientation)
+ {
+ _extremityOrientations[1] = iOrientation;
+ }
+
+ inline void setEndingOrientation(real x, real y)
+ {
+ _extremityOrientations[1] = Vec2r(x, y);
+ }
+
+ /* Information access interface */
+
+ // embedding vertex iterator
+ const_vertex_iterator vertices_begin() const;
+ vertex_iterator vertices_begin(float t = 0.0f);
+ const_vertex_iterator vertices_end() const;
+ vertex_iterator vertices_end();
+
+ /*! Returns a StrokeVertexIterator pointing on the first StrokeVertex of the Stroke. One can specifly a sampling
+ * value to resample the Stroke on the fly if needed.
+ * \param t
+ * The resampling value with which we want our Stroke to be resampled.
+ * If 0 is specified, no resampling is done.
+ */
+ StrokeInternal::StrokeVertexIterator strokeVerticesBegin(float t = 0.0f);
+
+ /*! Returns a StrokeVertexIterator pointing after the last StrokeVertex of the Stroke. */
+ StrokeInternal::StrokeVertexIterator strokeVerticesEnd();
+
+ /*! Returns the number of StrokeVertex constituing the Stroke. */
+ inline unsigned int strokeVerticesSize() const
+ {
+ return _Vertices.size();
+ }
+
+ /*! Returns the i-th StrokeVertex constituting the Stroke. */
+ inline StrokeVertex& strokeVerticeAt(unsigned int i)
+ {
+ return *(_Vertices.at(i));
+ }
+
+ // Iterator access (Interface1D)
+ /*! Returns an Interface0DIterator pointing on the first StrokeVertex of the Stroke. */
+ virtual Interface0DIterator verticesBegin();
+
+ /*! Returns an Interface0DIterator pointing after the last StrokeVertex of the Stroke. */
+ virtual Interface0DIterator verticesEnd();
+
+ virtual Interface0DIterator pointsBegin(float t = 0.0f);
+ virtual Interface0DIterator pointsEnd(float t = 0.0f);
+};
+
+
+//
+// Implementation
+//
+////////////////////////////////////////////////////////
+
+
+template<class InputVertexIterator>
+Stroke::Stroke(InputVertexIterator iBegin, InputVertexIterator iEnd)
+{
+ for (InputVertexIterator v = iBegin, vend = iEnd; v != vend; v++) {
+ _Vertices.push_back(*v);
+ }
+ _Length = 0;
+ _id = 0;
+}
+
+#endif // __FREESTYLE_STROKE_H__
diff --git a/source/blender/freestyle/intern/stroke/StrokeAdvancedIterators.h b/source/blender/freestyle/intern/stroke/StrokeAdvancedIterators.h
new file mode 100644
index 00000000000..adaa5548bf9
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeAdvancedIterators.h
@@ -0,0 +1,191 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_STROKE_ADVANCED_ITERATORS_H__
+#define __FREESTYLE_STROKE_ADVANCED_ITERATORS_H__
+
+/** \file blender/freestyle/intern/stroke/StrokeAdvancedIterators.h
+ * \ingroup freestyle
+ * \brief Iterators used to iterate over the elements of the Stroke. Can't be used in python
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include "Stroke.h"
+
+namespace StrokeInternal {
+
+class vertex_const_traits : public Const_traits<StrokeVertex*>
+{
+public:
+ typedef std::deque<StrokeVertex*> vertex_container;
+ typedef vertex_container::const_iterator vertex_container_iterator;
+};
+
+class vertex_nonconst_traits : public Nonconst_traits<StrokeVertex*>
+{
+public:
+ typedef std::deque<StrokeVertex*> vertex_container; //! the vertices container
+ typedef vertex_container::iterator vertex_container_iterator;
+};
+
+
+template<class Traits>
+class vertex_iterator_base : public IteratorBase<Traits,BidirectionalIteratorTag_Traits>
+{
+public:
+ typedef vertex_iterator_base<Traits> Self;
+
+protected:
+ typedef IteratorBase<Traits,BidirectionalIteratorTag_Traits> parent_class;
+ typedef typename Traits::vertex_container_iterator vertex_container_iterator;
+ typedef vertex_iterator_base<vertex_nonconst_traits> iterator;
+ typedef vertex_iterator_base<vertex_const_traits> const_iterator;
+
+//protected:
+public:
+ vertex_container_iterator _it;
+ vertex_container_iterator _begin;
+ vertex_container_iterator _end;
+
+public:
+ friend class Stroke;
+ //friend class vertex_iterator;
+
+ inline vertex_iterator_base() : parent_class() {}
+
+ inline vertex_iterator_base(const iterator& iBrother) : parent_class()
+ {
+ _it = iBrother._it;
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ }
+
+ inline vertex_iterator_base(const const_iterator& iBrother) : parent_class()
+ {
+ _it = iBrother._it;
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ }
+
+//protected: //FIXME
+public:
+ inline vertex_iterator_base(vertex_container_iterator it, vertex_container_iterator begin,
+ vertex_container_iterator end)
+ : parent_class()
+ {
+ _it = it;
+ _begin = begin;
+ _end = end;
+ }
+
+public:
+ virtual ~vertex_iterator_base() {}
+
+ virtual bool begin() const
+ {
+ return (_it == _begin) ? true : false;
+ }
+
+ virtual bool end() const
+ {
+ return (_it == _end) ? true : false;
+ }
+
+ // operators
+ inline Self& operator++() // operator corresponding to ++i
+ {
+ ++_it;
+ return *(this);
+ }
+
+ /* Operator corresponding to i++, i.e. which returns the value *and then* increments.
+ * That's why we store the value in a temp.
+ */
+ inline Self operator++(int)
+ {
+ Self tmp = *this;
+ ++_it;
+ return tmp;
+ }
+
+ inline Self& operator--() // operator corresponding to --i
+ {
+ --_it;
+ return *(this);
+ }
+
+ inline Self operator--(int)
+ {
+ Self tmp = *this;
+ --_it;
+ return tmp;
+ }
+
+ // comparibility
+ virtual bool operator!=(const Self& b) const
+ {
+ return (_it != b._it);
+ }
+
+ virtual bool operator==(const Self& b) const
+ {
+ return !(*this != b);
+ }
+
+ // dereferencing
+ virtual typename Traits::reference operator*() const
+ {
+ return *(_it);
+ }
+
+ virtual typename Traits::pointer operator->() const
+ {
+ return &(operator*());
+ }
+
+ /*! accessors */
+ inline vertex_container_iterator it() const
+ {
+ return _it;
+ }
+
+ inline vertex_container_iterator getBegin() const
+ {
+ return _begin;
+ }
+
+ inline vertex_container_iterator getEnd() const
+ {
+ return _end;
+ }
+};
+
+} // end of namespace StrokeInternal
+
+#endif // __FREESTYLE_STROKE_ADVANCED_ITERATORS_H__
diff --git a/source/blender/freestyle/intern/stroke/StrokeIO.cpp b/source/blender/freestyle/intern/stroke/StrokeIO.cpp
new file mode 100644
index 00000000000..a101ec67618
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeIO.cpp
@@ -0,0 +1,73 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/StrokeIO.cpp
+ * \ingroup freestyle
+ * \brief Functions to manage I/O for the stroke
+ * \author Stephane Grabli
+ * \date 03/02/2004
+ */
+
+#include "StrokeAdvancedIterators.h"
+
+#include "StrokeIO.h"
+
+ostream& operator<<(ostream& out, const StrokeAttribute& iStrokeAttribute)
+{
+ out << " StrokeAttribute" << endl;
+ out << " color : (" << iStrokeAttribute.getColorR() << "," << iStrokeAttribute.getColorG()
+ << "," << iStrokeAttribute.getColorB() << ")" << endl;
+ out << " alpha : " << iStrokeAttribute.getAlpha() << endl;
+ out << " thickness : " << iStrokeAttribute.getThicknessR() << ", " << iStrokeAttribute.getThicknessL() << endl;
+ out << " visible : " << iStrokeAttribute.isVisible() << endl;
+ return out;
+}
+
+ostream& operator<<(ostream& out, const StrokeVertex& iStrokeVertex)
+{
+ out << " StrokeVertex" << endl;
+ out << " id : " << iStrokeVertex.getId() << endl;
+ out << " curvilinear length : " << iStrokeVertex.curvilinearAbscissa() << endl;
+ out << " 2d coordinates : (" << iStrokeVertex.getProjectedX() << "," << iStrokeVertex.getProjectedY()
+ << "," << iStrokeVertex.getProjectedZ() << ")" << endl;
+ out << " 3d coordinates : (" << iStrokeVertex.getX() << "," << iStrokeVertex.getY()
+ << "," << iStrokeVertex.getZ() << ")" << endl;
+ out << iStrokeVertex.attribute() << endl;
+ return out;
+}
+
+ostream& operator<<(ostream& out, const Stroke& iStroke)
+{
+ out << "Stroke" << endl;
+ out << " id : " << iStroke.getId() << endl;
+ out << " length : " << iStroke.getLength2D() << endl;
+ out << " medium type : " << iStroke.getMediumType() << endl;
+ for(Stroke::const_vertex_iterator v = iStroke.vertices_begin(), vend = iStroke.vertices_end(); v != vend; ++v) {
+ out << *(*v) << endl;
+ }
+ return out;
+}
diff --git a/source/blender/freestyle/intern/stroke/StrokeIO.h b/source/blender/freestyle/intern/stroke/StrokeIO.h
new file mode 100644
index 00000000000..789c9c92c93
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeIO.h
@@ -0,0 +1,53 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_STROKE_IO_H__
+#define __FREESTYLE_STROKE_IO_H__
+
+/** \file blender/freestyle/intern/stroke/StrokeIO.h
+ * \ingroup freestyle
+ * \brief Functions to manage I/O for the stroke
+ * \author Stephane Grabli
+ * \date 03/02/2004
+ */
+
+#include <iostream>
+
+#include "Stroke.h"
+
+#include "../system/FreestyleConfig.h"
+
+LIB_STROKE_EXPORT
+ostream& operator<<(ostream& out, const StrokeAttribute& iStrokeAttribute);
+
+LIB_STROKE_EXPORT
+ostream& operator<<(ostream& out, const StrokeVertex& iStrokeVertex);
+
+LIB_STROKE_EXPORT
+ostream& operator<<(ostream& out, const Stroke& iStroke);
+
+#endif // __FREESTYLE_STROKE_IO_H__
diff --git a/source/blender/freestyle/intern/stroke/StrokeIterators.h b/source/blender/freestyle/intern/stroke/StrokeIterators.h
new file mode 100644
index 00000000000..37f6a8843bd
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeIterators.h
@@ -0,0 +1,229 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_STROKE_ITERATORS_H__
+#define __FREESTYLE_STROKE_ITERATORS_H__
+
+/** \file blender/freestyle/intern/stroke/StrokeIterators.h
+ * \ingroup freestyle
+ * \brief Iterators used to iterate over the elements of the Stroke
+ * \author Stephane Grabli
+ * \date 01/07/2003
+ */
+
+#include "Stroke.h"
+
+namespace StrokeInternal {
+
+//
+// StrokeVertexIterator
+//
+/////////////////////////////////////////////////
+
+/*! Class defining an iterator designed to iterate over the StrokeVertex of a Stroke.
+ * An instance of a StrokeVertexIterator can only be obtained from a Stroke by calling strokeVerticesBegin() or
+ * strokeVerticesEnd().
+ * It is iterating over the same vertices as an Interface0DIterator.
+ * The difference resides in the object access. Indeed, an Interface0DIterator allows only an access to an
+ * Interface0D whereas we could need to access the specialized StrokeVertex type. In this case, one
+ * should use a StrokeVertexIterator.
+ * The castToInterface0DIterator() method is useful to get an Interface0DIterator from a StrokeVertexIterator in
+ * order to call any functions of the type UnaryFunction0D.
+ * \attention In the scripting language, you must call \code it2 = StrokeVertexIterator(it1) \endcode instead of
+ * \code it2 = it1 \endcode where \a it1 and \a it2 are 2 StrokeVertexIterator.
+ * Otherwise, incrementing \a it1 will also increment \a it2.
+ */
+class StrokeVertexIterator : public Interface0DIteratorNested
+{
+public:
+ /*! Default constructor. */
+ StrokeVertexIterator() {}
+
+ /*! Copy constructor. */
+ StrokeVertexIterator(const StrokeVertexIterator& vi)
+ {
+ _it = vi._it;
+ _begin = vi._begin;
+ _end = vi._end;
+ }
+
+ StrokeVertexIterator(const ::Stroke::vertex_container::iterator& it,
+ const ::Stroke::vertex_container::iterator& begin,
+ const ::Stroke::vertex_container::iterator& end)
+ {
+ _it = it;
+ _begin = begin;
+ _end = end;
+ }
+
+ virtual ~StrokeVertexIterator() {}
+
+ /*! Casts this StrokeVertexIterator into an Interface0DIterator.
+ * Useful for any call to a function of the type UnaryFunction0D.
+ */
+ inline Interface0DIterator castToInterface0DIterator() const
+ {
+ Interface0DIterator ret(new StrokeVertexIterator(*this));
+ return ret;
+ }
+
+ /*! operator=
+ * \attention In the scripting language, you must call \code it2 = StrokeVertexIterator(it1) \endcode instead of
+ * \code it2 = it1 \endcode, where \a it1 and \a it2 are 2 StrokeVertexIterator.
+ * Otherwise, incrementing \a it1 will also increment \a it2.
+ */
+ StrokeVertexIterator& operator=(const StrokeVertexIterator& vi)
+ {
+ _it = vi._it;
+ _begin = vi._begin;
+ _end = vi._end;
+ return *this;
+ }
+
+ /*! Returns the string "StrokeVertexIterator". */
+ virtual string getExactTypeName() const
+ {
+ return "StrokeVertexIterator";
+ }
+
+ /*! Returns a reference to the pointed StrokeVertex.
+ * In the scripting language, you must call "getObject()"instead.
+ */
+ virtual StrokeVertex& operator*()
+ {
+ return **_it;
+ }
+
+ /*! Returns a pointer to the pointed StrokeVertex.
+ * Can't be called in the scripting language.
+ */
+ virtual StrokeVertex* operator->()
+ {
+ return &(operator*());
+ }
+
+ /*! Increments. In the scripting language, call "increment()". */
+ virtual StrokeVertexIterator& operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ /*! Increments. In the scripting language, call "increment()". */
+ virtual StrokeVertexIterator operator++(int)
+ {
+ StrokeVertexIterator ret(*this);
+ increment();
+ return ret;
+ }
+
+ /*! Decrements. In the scripting language, call "decrement()". */
+ virtual StrokeVertexIterator& operator--()
+ {
+ decrement();
+ return *this;
+ }
+
+ /*! Decrements. In the scripting language, call "decrement()". */
+ virtual StrokeVertexIterator operator--(int)
+ {
+ StrokeVertexIterator ret(*this);
+ decrement();
+ return ret;
+ }
+
+ /*! Increments. */
+ virtual int increment()
+ {
+ ++_it;
+ return 0;
+ }
+
+ /*! Decrements. */
+ virtual int decrement()
+ {
+ --_it;
+ return 0;
+ }
+
+ /*! Returns true if the pointed StrokeVertex is the first of the Stroke. */
+ bool isBegin() const
+ {
+ return _it == _begin;
+ }
+
+ /*! Returns true if the pointed StrokeVertex is after the last StrokeVertex of the Stroke. */
+ bool isEnd() const
+ {
+ return _it == _end;
+ }
+
+ /*! operator == */
+ virtual bool operator==(const Interface0DIteratorNested& it) const
+ {
+ const StrokeVertexIterator* it_exact = dynamic_cast<const StrokeVertexIterator*>(&it);
+ if (!it_exact)
+ return false;
+ return (_it == it_exact->_it);
+ }
+
+ /*! Returns the curvilinear abscissa of the current point */
+ virtual float t() const
+ {
+ return (*_it)->curvilinearAbscissa();
+ }
+
+ /*! Returns the point's parameter in the stroke */
+ virtual float u() const
+ {
+ return (*_it)->u();
+ }
+
+ /*! Cloning method */
+ virtual StrokeVertexIterator* copy() const
+ {
+ return new StrokeVertexIterator(*this);
+ }
+
+ //
+ // Not exported in Python
+ //
+ //////////////////////////////////////////////////
+ const ::Stroke::vertex_container::iterator& getIt()
+ {
+ return _it;
+ }
+
+private:
+ ::Stroke::vertex_container::iterator _it;
+ ::Stroke::vertex_container::iterator _begin;
+ ::Stroke::vertex_container::iterator _end;
+};
+
+} // end of namespace StrokeInternal
+
+#endif // __FREESTYLE_STROKE_ITERATORS_H__
diff --git a/source/blender/freestyle/intern/stroke/StrokeLayer.cpp b/source/blender/freestyle/intern/stroke/StrokeLayer.cpp
new file mode 100644
index 00000000000..b12477c3e34
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeLayer.cpp
@@ -0,0 +1,70 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/StrokeLayer.cpp
+ * \ingroup freestyle
+ * \brief Class to define a layer of strokes.
+ * \author Stephane Grabli
+ * \date 18/12/2002
+ */
+
+#include "Canvas.h"
+#include "Stroke.h"
+#include "StrokeLayer.h"
+
+StrokeLayer::~StrokeLayer()
+{
+ clear();
+}
+
+void StrokeLayer::ScaleThickness(float iFactor)
+{
+ for (StrokeLayer::stroke_container::iterator s = _strokes.begin(), send = _strokes.end(); s != send; ++s) {
+ (*s)->ScaleThickness(iFactor);
+ }
+}
+
+void StrokeLayer::Render(const StrokeRenderer *iRenderer)
+{
+ for (StrokeLayer::stroke_container::iterator s = _strokes.begin(), send = _strokes.end(); s != send; ++s) {
+ (*s)->Render(iRenderer);
+ }
+}
+
+void StrokeLayer::RenderBasic(const StrokeRenderer *iRenderer)
+{
+ for (StrokeLayer::stroke_container::iterator s = _strokes.begin(), send = _strokes.end(); s != send; ++s) {
+ (*s)->RenderBasic(iRenderer);
+ }
+}
+
+void StrokeLayer::clear()
+{
+ for (stroke_container::iterator s = _strokes.begin(), send = _strokes.end(); s != send; ++s)
+ delete *s;
+ _strokes.clear();
+}
diff --git a/source/blender/freestyle/intern/stroke/StrokeLayer.h b/source/blender/freestyle/intern/stroke/StrokeLayer.h
new file mode 100644
index 00000000000..ff830db337a
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeLayer.h
@@ -0,0 +1,106 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_STROKE_LAYER_H__
+#define __FREESTYLE_STROKE_LAYER_H__
+
+/** \file blender/freestyle/intern/stroke/StrokeLayer.h
+ * \ingroup freestyle
+ * \brief Class to define a layer of strokes.
+ * \author Stephane Grabli
+ * \date 18/12/2002
+ */
+
+#include <deque>
+
+class Stroke;
+class StrokeRenderer;
+class StrokeLayer
+{
+public:
+ typedef std::deque<Stroke*> stroke_container;
+
+protected:
+ stroke_container _strokes;
+
+public:
+ StrokeLayer() {}
+
+ StrokeLayer(const stroke_container& iStrokes)
+ {
+ _strokes = iStrokes;
+ }
+
+ StrokeLayer(const StrokeLayer& iBrother)
+ {
+ _strokes = iBrother._strokes;
+ }
+
+ virtual ~StrokeLayer();
+
+ /*! Render method */
+ void ScaleThickness(float iFactor);
+ void Render(const StrokeRenderer *iRenderer);
+ void RenderBasic(const StrokeRenderer *iRenderer);
+
+ /*! clears the layer */
+ void clear();
+
+ /*! accessors */
+ inline stroke_container::iterator strokes_begin()
+ {
+ return _strokes.begin();
+ }
+
+ inline stroke_container::iterator strokes_end()
+ {
+ return _strokes.end();
+ }
+
+ inline int strokes_size() const
+ {
+ return _strokes.size();
+ }
+
+ inline bool empty() const
+ {
+ return _strokes.empty();
+ }
+
+ /*! modifiers */
+ inline void setStrokes(stroke_container& iStrokes)
+ {
+ _strokes = iStrokes;
+ }
+
+ inline void AddStroke(Stroke *iStroke)
+ {
+ _strokes.push_back(iStroke);
+ }
+};
+
+#endif // __FREESTYLE_STROKE_LAYER_H__
diff --git a/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp b/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp
new file mode 100644
index 00000000000..56c5f2b5001
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeRenderer.cpp
@@ -0,0 +1,138 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/StrokeRenderer.cpp
+ * \ingroup freestyle
+ * \brief Classes to render a stroke with OpenGL
+ * \author Fredo Durand
+ * \date 09/09/2002
+ */
+
+#include "StrokeRenderer.h"
+
+#include "../geometry/GeomUtils.h"
+
+using namespace std;
+
+/**********************************/
+/* */
+/* */
+/* StrokeRenderer */
+/* */
+/* */
+/**********************************/
+
+LIB_STROKE_EXPORT
+TextureManager *StrokeRenderer::_textureManager = 0;
+
+StrokeRenderer::StrokeRenderer() {}
+
+StrokeRenderer::~StrokeRenderer() {}
+
+bool StrokeRenderer::loadTextures()
+{
+ _textureManager->load();
+ return true;
+}
+
+
+/**********************************/
+/* */
+/* */
+/* TextureManager */
+/* */
+/* */
+/**********************************/
+
+
+LIB_STROKE_EXPORT
+TextureManager* TextureManager::_pInstance = 0;
+
+LIB_STROKE_EXPORT
+string TextureManager::_patterns_path;
+
+LIB_STROKE_EXPORT
+string TextureManager::_brushes_path;
+
+TextureManager::TextureManager()
+{
+ _hasLoadedTextures = false;
+ _pInstance = this;
+ _defaultTextureId = 0;
+}
+
+TextureManager::~TextureManager()
+{
+ if (!_brushesMap.empty())
+ _brushesMap.clear();
+ _pInstance = 0;
+}
+
+void TextureManager::load()
+{
+ if (_hasLoadedTextures)
+ return;
+ loadStandardBrushes();
+ _hasLoadedTextures = true;
+}
+
+unsigned TextureManager::getBrushTextureIndex(string name, Stroke::MediumType loadingMode)
+{
+ BrushTexture bt(name,loadingMode);
+ brushesMap::iterator b = _brushesMap.find(bt);
+ if (b == _brushesMap.end()) {
+ unsigned texId = loadBrush(name, loadingMode);
+ _brushesMap[bt] = texId;
+ return texId;
+ // XXX!
+ cerr << "brush file " << name << " not found" << endl;
+ return 0;
+ }
+ else {
+ return _brushesMap[bt];
+ }
+}
+
+void TextureManager::Options::setPatternsPath(const string& path)
+{
+ _patterns_path = path;
+}
+
+string TextureManager::Options::getPatternsPath()
+{
+ return _patterns_path;
+}
+
+void TextureManager::Options::setBrushesPath(const string& path)
+{
+ _brushes_path = path;
+}
+
+string TextureManager::Options::getBrushesPath()
+{
+ return _brushes_path;
+}
diff --git a/source/blender/freestyle/intern/stroke/StrokeRenderer.h b/source/blender/freestyle/intern/stroke/StrokeRenderer.h
new file mode 100644
index 00000000000..ab451a14496
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeRenderer.h
@@ -0,0 +1,145 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_STROKE_RENDERER_H__
+#define __FREESTYLE_STROKE_RENDERER_H__
+
+/** \file blender/freestyle/intern/stroke/StrokeRenderer.h
+ * \ingroup freestyle
+ * \brief Classes to render a stroke with OpenGL
+ * \author Fredo Durand
+ * \date 09/09/2002
+ */
+
+#include <map>
+#include <string.h>
+#include <utility>
+#include <vector>
+
+#include "Stroke.h"
+#include "StrokeRep.h"
+
+#include "../system/FreestyleConfig.h"
+
+/**********************************/
+/* */
+/* */
+/* TextureManager */
+/* */
+/* */
+/**********************************/
+
+
+/*! Class to load textures */
+class LIB_STROKE_EXPORT TextureManager
+{
+public:
+ TextureManager ();
+ virtual ~TextureManager ();
+
+ static TextureManager *getInstance()
+ {
+ return _pInstance;
+ }
+
+ void load();
+ unsigned getBrushTextureIndex(string name, Stroke::MediumType iType = Stroke::OPAQUE_MEDIUM);
+
+ inline bool hasLoaded() const
+ {
+ return _hasLoadedTextures;
+ }
+
+ inline unsigned int getDefaultTextureId() const
+ {
+ return _defaultTextureId;
+ }
+
+ struct LIB_STROKE_EXPORT Options
+ {
+ static void setPatternsPath(const string& path);
+ static string getPatternsPath();
+
+ static void setBrushesPath(const string& path);
+ static string getBrushesPath();
+ };
+
+protected:
+ virtual void loadStandardBrushes() = 0;
+ virtual unsigned loadBrush(string fileName, Stroke::MediumType = Stroke::OPAQUE_MEDIUM) = 0;
+
+ typedef std::pair<string,Stroke::MediumType> BrushTexture;
+ struct cmpBrushTexture
+ {
+ bool operator()(const BrushTexture& bt1, const BrushTexture& bt2) const
+ {
+ int r = strcmp(bt1.first.c_str(), bt2.first.c_str());
+ if (r != 0)
+ return (r < 0);
+ else
+ return (bt1.second < bt2.second);
+ }
+ };
+ typedef std::map<BrushTexture, unsigned, cmpBrushTexture> brushesMap;
+
+ static TextureManager *_pInstance;
+ bool _hasLoadedTextures;
+ brushesMap _brushesMap;
+ static string _patterns_path;
+ static string _brushes_path;
+ unsigned int _defaultTextureId;
+};
+
+
+/**********************************/
+/* */
+/* */
+/* StrokeRenderer */
+/* */
+/* */
+/**********************************/
+
+/*! Class to render a stroke. Creates a triangle strip and stores it strip is lazily created at the first rendering */
+class LIB_STROKE_EXPORT StrokeRenderer
+{
+public:
+ StrokeRenderer();
+ virtual ~StrokeRenderer();
+
+ /*! Renders a stroke rep */
+ virtual void RenderStrokeRep(StrokeRep *iStrokeRep) const = 0;
+ virtual void RenderStrokeRepBasic(StrokeRep *iStrokeRep) const = 0;
+
+ // initializes the texture manager
+ // lazy, checks if it has already been done
+ static bool loadTextures();
+
+ //static unsigned int getTextureIndex(unsigned int index);
+ static TextureManager *_textureManager;
+};
+
+#endif // __FREESTYLE_STROKE_RENDERER_H__
diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.cpp b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
new file mode 100644
index 00000000000..bc117925a4c
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
@@ -0,0 +1,789 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/StrokeRep.cpp
+ * \ingroup freestyle
+ * \brief Class to define the representation of a stroke (for display purpose)
+ * \author Stephane Grabli
+ * \date 05/03/2003
+ */
+
+#include "Stroke.h"
+#include "StrokeAdvancedIterators.h"
+#include "StrokeIterators.h"
+#include "StrokeRenderer.h"
+#include "StrokeRep.h"
+
+using namespace std;
+
+//
+// STROKE VERTEX REP
+/////////////////////////////////////
+
+StrokeVertexRep::StrokeVertexRep(const StrokeVertexRep& iBrother)
+{
+ _point2d = iBrother._point2d;
+ _texCoord = iBrother._texCoord;
+ _color = iBrother._color;
+ _alpha = iBrother._alpha;
+}
+
+//
+// STRIP
+/////////////////////////////////////
+
+Strip::Strip(const vector<StrokeVertex*>& iStrokeVertices, bool hasTips, bool beginTip, bool endTip)
+{
+ createStrip(iStrokeVertices);
+ if (!hasTips)
+ computeTexCoord (iStrokeVertices);
+ else
+ computeTexCoordWithTips (iStrokeVertices, beginTip, endTip);
+}
+
+Strip::Strip(const Strip& iBrother)
+{
+ if (!iBrother._vertices.empty()) {
+ for (vertex_container::const_iterator v = iBrother._vertices.begin(), vend = iBrother._vertices.end();
+ v != vend;
+ ++v)
+ {
+ _vertices.push_back(new StrokeVertexRep(**v));
+ }
+ }
+ _averageThickness = iBrother._averageThickness;
+}
+
+Strip::~Strip()
+{
+ if (!_vertices.empty()) {
+ for (vertex_container::iterator v = _vertices.begin(), vend = _vertices.end(); v != vend; ++v) {
+ delete (*v);
+ }
+ _vertices.clear();
+ }
+}
+
+//////////////////////////
+// Strip creation
+//////////////////////////
+
+#define EPS_SINGULARITY_RENDERER 0.05
+#define ZERO 0.00001
+#define MAX_RATIO_LENGTH_SINGU 2
+#define HUGE_COORD 1.0e4
+
+static bool notValid (Vec2r p)
+{
+ return (p[0] != p[0]) || (p[1] != p[1]) || (fabs(p[0]) > HUGE_COORD) || (fabs(p[1]) > HUGE_COORD) ||
+ (p[0] < -HUGE_COORD) || (p[1] < -HUGE_COORD);
+}
+
+static real crossP(const Vec2r& A, const Vec2r& B)
+{
+ return A[0] * B[1] - A[1] * B[0];
+}
+
+void Strip::createStrip (const vector<StrokeVertex*>& iStrokeVertices)
+{
+ //computeParameterization();
+ if (iStrokeVertices.size() < 2) {
+ cerr << "Warning: strip has less than 2 vertices" << endl;
+ return;
+ }
+ _vertices.reserve(2 * iStrokeVertices.size());
+ if (!_vertices.empty()) {
+ for (vertex_container::iterator v = _vertices.begin(), vend = _vertices.end(); v != vend; ++v) {
+ delete (*v);
+ }
+ _vertices.clear();
+ }
+ _averageThickness = 0.0;
+
+ vector<StrokeVertex*>::const_iterator v ,vend, v2, vPrev;
+ StrokeVertex *sv, *sv2, *svPrev;
+
+ //special case of first vertex
+ v = iStrokeVertices.begin();
+ sv = *v;
+ vPrev = v; //in case the stroke has only 2 vertices;
+ ++v;
+ sv2 = *v;
+ Vec2r dir(sv2->getPoint() - sv->getPoint());
+ Vec2r orthDir(-dir[1], dir[0]);
+ if (orthDir.norm() > ZERO)
+ orthDir.normalize();
+ Vec2r stripDir(orthDir);
+ // check whether the orientation was user defined
+ if (sv->attribute().isAttributeAvailableVec2f("orientation")) {
+ Vec2r userDir = sv->attribute().getAttributeVec2f("orientation");
+ userDir.normalize();
+ real dp = userDir * orthDir;
+ if (dp < 0)
+ userDir = userDir * (-1.0f);
+ stripDir = userDir;
+ }
+ const float *thickness = sv->attribute().getThickness();
+ _vertices.push_back(new StrokeVertexRep(sv->getPoint() + thickness[1] * stripDir));
+ _vertices.push_back(new StrokeVertexRep(sv->getPoint() - thickness[0] * stripDir));
+
+#if 0
+ Vec2r userDir = _stroke->getBeginningOrientation();
+ if (userDir != Vec2r(0, 0)) {
+ userDir.normalize();
+ real o1 = (orthDir * userDir);
+ real o2 = crossP(orthDir, userDir);
+ real orientation = o1 * o2;
+ if (orientation > 0) {
+ // then the vertex to move is v0
+ if (o1 > 0)
+ _vertex[0] = _vertex[1] + userDir;
+ else
+ _vertex[0] = _vertex[1] - userDir;
+ }
+ if (orientation < 0) {
+ // then we must move v1
+ if (o1 < 0)
+ _vertex[1] = _vertex[0] + userDir;
+ else
+ _vertex[1] = _vertex[0] - userDir;
+ }
+ }
+#endif
+
+ int i = 2; // 2 because we have already processed the first vertex
+
+ for (vend = iStrokeVertices.end(); v != vend; ++v) {
+ v2 = v;
+ ++v2;
+ if (v2 == vend)
+ break;
+ sv = (*v);
+ sv2 = (*v2);
+ svPrev = (*vPrev);
+ Vec2r p(sv->getPoint()), p2(sv2->getPoint()), pPrev(svPrev->getPoint());
+
+ //direction and orthogonal vector to the next segment
+ Vec2r dir(p2 - p);
+ float dirNorm = dir.norm();
+ dir.normalize();
+ Vec2r orthDir(-dir[1], dir[0]);
+ Vec2r stripDir = orthDir;
+ if (sv->attribute().isAttributeAvailableVec2f("orientation")) {
+ Vec2r userDir = sv->attribute().getAttributeVec2f("orientation");
+ userDir.normalize();
+ real dp = userDir * orthDir;
+ if (dp < 0)
+ userDir = userDir * (-1.0f);
+ stripDir = userDir;
+ }
+
+ //direction and orthogonal vector to the previous segment
+ Vec2r dirPrev(p - pPrev);
+ float dirPrevNorm = dirPrev.norm();
+ dirPrev.normalize();
+ Vec2r orthDirPrev(-dirPrev[1], dirPrev[0]);
+ Vec2r stripDirPrev = orthDirPrev;
+ if (svPrev->attribute().isAttributeAvailableVec2f("orientation")) {
+ Vec2r userDir = svPrev->attribute().getAttributeVec2f("orientation");
+ userDir.normalize();
+ real dp = userDir * orthDir;
+ if (dp < 0)
+ userDir = userDir * (-1.0f);
+ stripDirPrev = userDir;
+ }
+
+ const float *thickness = sv->attribute().getThickness();
+ _averageThickness += thickness[0] + thickness[1];
+ Vec2r pInter;
+ int interResult;
+
+ interResult = GeomUtils::intersect2dLine2dLine(Vec2r(pPrev + thickness[1] * stripDirPrev),
+ Vec2r(p + thickness[1] * stripDirPrev),
+ Vec2r(p + thickness[1] * stripDir),
+ Vec2r(p2 + thickness[1] * stripDir),
+ pInter);
+ if (interResult == GeomUtils::DO_INTERSECT)
+ _vertices.push_back(new StrokeVertexRep(pInter));
+ else
+ _vertices.push_back(new StrokeVertexRep(p + thickness[1] * stripDir));
+ ++i;
+
+ interResult = GeomUtils::intersect2dLine2dLine(Vec2r(pPrev - thickness[0] * stripDirPrev),
+ Vec2r(p - thickness[0] * stripDirPrev),
+ Vec2r(p - thickness[0] * stripDir),
+ Vec2r(p2 - thickness[0] * stripDir),
+ pInter);
+ if (interResult == GeomUtils::DO_INTERSECT)
+ _vertices.push_back(new StrokeVertexRep(pInter));
+ else
+ _vertices.push_back(new StrokeVertexRep(p - thickness[0] * stripDir));
+ ++i;
+
+ // if the angle is obtuse, we simply average the directions to avoid the singularity
+ stripDir = stripDir + stripDirPrev;
+ if ((dirNorm < ZERO) || (dirPrevNorm < ZERO) || (stripDir.norm() < ZERO)) {
+ stripDir[0] = 0;
+ stripDir[1] = 0;
+ }
+ else {
+ stripDir.normalize();
+ }
+
+ Vec2r vec_tmp(_vertices[i - 2]->point2d() - p);
+ if ((vec_tmp.norm() > thickness[1] * MAX_RATIO_LENGTH_SINGU) || (dirNorm < ZERO) || (dirPrevNorm < ZERO) ||
+ notValid(_vertices[i - 2]->point2d()) || (fabs(stripDir * dir) < EPS_SINGULARITY_RENDERER))
+ {
+ _vertices[i - 2]->setPoint2d(p + thickness[1] * stripDir);
+ }
+
+ vec_tmp = _vertices[i - 1]->point2d() - p;
+ if ((vec_tmp.norm() > thickness[0] * MAX_RATIO_LENGTH_SINGU) || (dirNorm < ZERO) || (dirPrevNorm < ZERO) ||
+ notValid(_vertices[i - 1]->point2d()) || (fabs(stripDir * dir) < EPS_SINGULARITY_RENDERER))
+ {
+ _vertices[i - 1]->setPoint2d(p - thickness[0] * stripDir);
+ }
+
+ vPrev = v;
+ } // end of for
+
+ //special case of last vertex
+ sv = *v;
+ sv2 = *vPrev;
+ dir = Vec2r(sv->getPoint() - sv2->getPoint());
+ orthDir = Vec2r(-dir[1], dir[0]);
+ if (orthDir.norm() > ZERO)
+ orthDir.normalize();
+ Vec2r stripDirLast(orthDir);
+ // check whether the orientation was user defined
+ if (sv->attribute().isAttributeAvailableVec2f("orientation")) {
+ Vec2r userDir = sv->attribute().getAttributeVec2f("orientation");
+ userDir.normalize();
+ real dp = userDir * orthDir;
+ if (dp < 0)
+ userDir = userDir * (-1.0f);
+ stripDirLast = userDir;
+ }
+ const float *thicknessLast = sv->attribute().getThickness();
+ _vertices.push_back(new StrokeVertexRep(sv->getPoint() + thicknessLast[1] * stripDirLast));
+ ++i;
+ _vertices.push_back(new StrokeVertexRep(sv->getPoint() - thicknessLast[0] * stripDirLast));
+ ++i;
+
+#if 0
+ int n = i - 1;
+ // check whether the orientation of the extremity was user defined
+ userDir = _stroke->getEndingOrientation();
+ if (userDir != Vec2r(0, 0)) {
+ userDir.normalize();
+ real o1 = (orthDir * userDir);
+ real o2 = crossP(orthDir, userDir);
+ real orientation = o1 * o2;
+ if (orientation > 0) {
+ // then the vertex to move is vn
+ if (o1 < 0)
+ _vertex[n] = _vertex[n - 1] + userDir;
+ else
+ _vertex[n] = _vertex[n - 1] - userDir;
+ }
+ if (orientation < 0) {
+ // then we must move vn-1
+ if (o1 > 0)
+ _vertex[n - 1] = _vertex[n] + userDir;
+ else
+ _vertex[n - 1] = _vertex[n] - userDir;
+ }
+ }
+#endif
+
+ _averageThickness /= float(iStrokeVertices.size() - 2);
+ //I did not use the first and last vertex for the average
+ if (iStrokeVertices.size() < 3)
+ _averageThickness = 0.5 * (thicknessLast[1] + thicknessLast[0] + thickness[0] + thickness[1]);
+
+ if (i != 2 * (int)iStrokeVertices.size())
+ cerr << "Warning: problem with stripe size\n";
+
+ cleanUpSingularities (iStrokeVertices);
+}
+
+// CLEAN UP
+/////////////////////////
+
+void Strip::cleanUpSingularities (const vector<StrokeVertex*>& iStrokeVertices)
+{
+ int k;
+ int sizeStrip = _vertices.size();
+
+ for (k = 0; k < sizeStrip; k++) {
+ if (notValid(_vertices[k]->point2d())) {
+ cerr << "Warning: strip vertex " << k << " non valid" << endl;
+ return;
+ }
+ }
+
+ //return;
+ if (iStrokeVertices.size() < 2)
+ return;
+ int i = 0, j;
+ vector<StrokeVertex*>::const_iterator v ,vend, v2, vPrev;
+ StrokeVertex *sv, *sv2; //soc unused - *svPrev;
+
+ bool singu1 = false, singu2 = false;
+ int timeSinceSingu1 = 0, timeSinceSingu2 = 0;
+
+ //special case of first vertex
+ v = iStrokeVertices.begin();
+ for (vend = iStrokeVertices.end(); v != vend; v++) {
+ v2 = v;
+ ++v2;
+ if (v2 == vend)
+ break;
+ sv = (*v);
+ sv2 = (*v2);
+ Vec2r p(sv->getPoint()), p2(sv2->getPoint());
+
+ Vec2r dir(p2-p);
+ if (dir.norm() > ZERO)
+ dir.normalize();
+ Vec2r dir1, dir2;
+ dir1 = _vertices[2 * i + 2]->point2d() - _vertices[2 * i]->point2d();
+ dir2 = _vertices[2 * i + 3]->point2d() - _vertices[2 * i + 1]->point2d();
+
+ if ((dir1 * dir) < -ZERO) {
+ singu1 = true;
+ timeSinceSingu1++;
+ }
+ else {
+ if (singu1) {
+ int toto = i - timeSinceSingu1;
+ if (toto < 0)
+ cerr << "Stephane dit \"Toto\"" << endl;
+ //traverse all the vertices of the singularity and average them
+ Vec2r avP(0.0, 0.0);
+ for (j = i - timeSinceSingu1; j < i + 1; j++)
+ avP=Vec2r(avP + _vertices[2 * j]->point2d());
+ avP = Vec2r( 1.0 / float(timeSinceSingu1 + 1) * avP);
+ for (j = i - timeSinceSingu1; j < i + 1; j++)
+ _vertices[2 * j]->setPoint2d(avP);
+ //_vertex[2 * j] = _vertex[2 * i];
+ singu1 = false;
+ timeSinceSingu1 = 0;
+ }
+ }
+ if ((dir2 * dir) < -ZERO) {
+ singu2 = true;
+ timeSinceSingu2++;
+ }
+ else {
+ if (singu2) {
+ int toto = i - timeSinceSingu2;
+ if (toto < 0)
+ cerr << "Stephane dit \"Toto\"" << endl;
+ //traverse all the vertices of the singularity and average them
+ Vec2r avP(0.0, 0.0);
+ for (j = i - timeSinceSingu2; j < i + 1; j++)
+ avP = Vec2r(avP + _vertices[2 * j + 1]->point2d());
+ avP = Vec2r(1.0 / float(timeSinceSingu2 + 1) * avP);
+ for (j = i - timeSinceSingu2; j < i + 1; j++)
+ _vertices[2 * j + 1]->setPoint2d(avP);
+ //_vertex[2 * j + 1] = _vertex[2 * i + 1];
+ singu2 = false;
+ timeSinceSingu2 = 0;
+ }
+ }
+ i++;
+ }
+
+ if (singu1) {
+ //traverse all the vertices of the singularity and average them
+ Vec2r avP(0.0, 0.0);
+ for (j = i - timeSinceSingu1; j < i; j++)
+ avP = Vec2r(avP + _vertices[2 * j]->point2d());
+ avP = Vec2r(1.0 / float(timeSinceSingu1) * avP);
+ for (j = i - timeSinceSingu1; j < i; j++)
+ _vertices[2 * j]->setPoint2d(avP);
+ }
+ if (singu2) {
+ //traverse all the vertices of the singularity and average them
+ Vec2r avP(0.0, 0.0);
+ for (j = i - timeSinceSingu2; j < i; j++)
+ avP = Vec2r(avP + _vertices[2 * j + 1]->point2d());
+ avP = Vec2r(1.0 / float(timeSinceSingu2) * avP);
+ for (j = i - timeSinceSingu2; j < i; j++)
+ _vertices[2 * j + 1]->setPoint2d(avP);
+ }
+
+ for (k=0; k<sizeStrip; k++) {
+ if (notValid(_vertices[k]->point2d())) {
+ cerr << "Warning: strip vertex " << k << " non valid after cleanup" << endl;
+ return;
+ }
+ }
+}
+
+
+// Texture coordinates
+////////////////////////////////
+
+void Strip::computeTexCoord (const vector<StrokeVertex*>& iStrokeVertices)
+{
+ vector<StrokeVertex*>::const_iterator v ,vend;
+ StrokeVertex *sv;
+ int i = 0;
+ for (v = iStrokeVertices.begin(), vend = iStrokeVertices.end(); v != vend; v++) {
+ sv = (*v);
+ _vertices[i]->setTexCoord(Vec2r((real)(sv->curvilinearAbscissa() / _averageThickness), 0));
+ _vertices[i]->setColor(Vec3r(sv->attribute().getColor()[0], sv->attribute().getColor()[1],
+ sv->attribute().getColor()[2]));
+ _vertices[i]->setAlpha(sv->attribute().getAlpha());
+ i++;
+ _vertices[i]->setTexCoord(Vec2r((real)(sv->curvilinearAbscissa() / _averageThickness), 1));
+ _vertices[i]->setColor(Vec3r(sv->attribute().getColor()[0], sv->attribute().getColor()[1],
+ sv->attribute().getColor()[2]));
+ _vertices[i]->setAlpha(sv->attribute().getAlpha());
+ i++;
+#if 0
+ cerr << "col=("<<sv->attribute().getColor()[0] << ", "
+ << sv->attribute().getColor()[1] << ", " << sv->attribute().getColor()[2] << ")" << endl;
+#endif
+ }
+}
+
+void Strip::computeTexCoordWithTips (const vector<StrokeVertex*>& iStrokeVertices, bool tipBegin, bool tipEnd)
+{
+ //soc unused - unsigned int sizeStrip = _vertices.size() + 8; //for the transition between the tip and the body
+ vector<StrokeVertex*>::const_iterator v, vend;
+ StrokeVertex *sv = NULL;
+
+ v = iStrokeVertices.begin();
+ vend = iStrokeVertices.end();
+ float l = (*v)->strokeLength() / _averageThickness;
+ int tiles = int(l);
+ float fact = (float(tiles) + 0.5) / l;
+ //soc unused - float uTip2 = float(tiles) + 0.25;
+ float u = 0;
+ float uPrev = 0;
+ int i = 0;
+ float t;
+ StrokeVertexRep *tvRep1, *tvRep2;
+
+#if 0
+ cerr << "l=" << l << " tiles=" << tiles << " _averageThicnkess="
+ << _averageThickness << " strokeLength=" << (*v)->strokeLength() << endl;
+#endif
+
+ vector<StrokeVertexRep*>::iterator currentSV = _vertices.begin();
+ StrokeVertexRep *svRep;
+ if (tipBegin) {
+ for (; v != vend; v++) {
+ sv = (*v);
+ svRep = *currentSV;
+ u = sv->curvilinearAbscissa() / _averageThickness * fact;
+ if (u > 0.25)
+ break;
+
+ svRep->setTexCoord(Vec2r((real)u, 0.5));
+ svRep->setColor(Vec3r(sv->attribute().getColor()[0], sv->attribute().getColor()[1],
+ sv->attribute().getColor()[2]));
+ svRep->setAlpha(sv->attribute().getAlpha());
+ i++;
+ ++currentSV;
+
+ svRep = *currentSV;
+ svRep->setTexCoord(Vec2r((real)u, 1));
+ svRep->setColor(Vec3r(sv->attribute().getColor()[0], sv->attribute().getColor()[1],
+ sv->attribute().getColor()[2]));
+ svRep->setAlpha(sv->attribute().getAlpha());
+ i++;
+ ++currentSV;
+ uPrev = u;
+ }
+ //first transition vertex
+
+ if (fabs(u - uPrev) > ZERO)
+ t = (0.25 - uPrev) / (u - uPrev);
+ else
+ t = 0;
+#if 0
+ if (!tiles)
+ t = 0.5;
+#endif
+ tvRep1 = new StrokeVertexRep(Vec2r((1 - t) * _vertices[i - 2]->point2d() + t * _vertices[i]->point2d()));
+ tvRep1->setTexCoord(Vec2r(0.25, 0.5));
+ tvRep1->setColor(Vec3r((1 - t) * _vertices[i - 2]->color() +
+ t * Vec3r(sv->attribute().getColor()[0], sv->attribute().getColor()[1],
+ sv->attribute().getColor()[2])));
+ tvRep1->setAlpha((1 - t) * _vertices[i - 2]->alpha() + t * sv->attribute().getAlpha());
+ i++;
+
+ tvRep2 = new StrokeVertexRep(Vec2r((1 - t) * _vertices[i - 2]->point2d() + t *_vertices[i]->point2d()));
+ tvRep2->setTexCoord(Vec2r(0.25, 1));
+ tvRep2->setColor(Vec3r((1 - t) * _vertices[i - 2]->color() +
+ t * Vec3r(sv->attribute().getColor()[0], sv->attribute().getColor()[1],
+ sv->attribute().getColor()[2])));
+ tvRep2->setAlpha((1 - t) * _vertices[i - 2]->alpha() + t * sv->attribute().getAlpha());
+ i++;
+
+ currentSV = _vertices.insert(currentSV, tvRep1);
+ ++currentSV;
+ currentSV = _vertices.insert(currentSV, tvRep2);
+ ++currentSV;
+
+ // copy the vertices with different texture coordinates
+ tvRep1 = new StrokeVertexRep(_vertices[i - 2]->point2d());
+ tvRep1->setTexCoord(Vec2r(0.25, 0));
+ tvRep1->setColor(_vertices[i - 2]->color());
+ tvRep1->setAlpha(_vertices[i - 2]->alpha());
+ i++;
+
+ tvRep2 = new StrokeVertexRep(_vertices[i - 2]->point2d());
+ tvRep2->setTexCoord(Vec2r(0.25, 0.5));
+ tvRep2->setColor(_vertices[i - 2]->color());
+ tvRep2->setAlpha(_vertices[i - 2]->alpha());
+ i++;
+
+ currentSV = _vertices.insert(currentSV, tvRep1);
+ ++currentSV;
+ currentSV = _vertices.insert(currentSV, tvRep2);
+ ++currentSV;
+ }
+ uPrev = 0;
+
+ //body of the stroke
+ for (; v != vend; v++) {
+ sv = (*v);
+ svRep = *currentSV;
+ u = sv->curvilinearAbscissa() / _averageThickness * fact - 0.25;
+ if (u > tiles)
+ break;
+
+ svRep->setTexCoord(Vec2r((real)u, 0));
+ svRep->setColor(Vec3r(sv->attribute().getColor()[0], sv->attribute().getColor()[1],
+ sv->attribute().getColor()[2]));
+ svRep->setAlpha(sv->attribute().getAlpha());
+ i++;
+ ++currentSV;
+
+ svRep = *currentSV;
+ svRep->setTexCoord(Vec2r((real)u, 0.5));
+ svRep->setColor(Vec3r(sv->attribute().getColor()[0], sv->attribute().getColor()[1],
+ sv->attribute().getColor()[2]));
+ svRep->setAlpha(sv->attribute().getAlpha());
+ i++;
+ ++currentSV;
+
+ uPrev = u;
+ }
+ if (tipEnd) {
+ //second transition vertex
+ if ((fabs(u - uPrev) > ZERO))
+ t = (float(tiles) - uPrev) / (u - uPrev);
+ else
+ t = 0;
+
+ tvRep1 = new StrokeVertexRep(Vec2r((1 - t) * _vertices[i - 2]->point2d() + t * _vertices[i]->point2d()));
+ tvRep1->setTexCoord(Vec2r((real)tiles, 0));
+ tvRep1->setColor(Vec3r((1 - t) * _vertices[i - 2]->color() +
+ t * Vec3r(sv->attribute().getColor()[0], sv->attribute().getColor()[1],
+ sv->attribute().getColor()[2])));
+ tvRep1->setAlpha((1 - t) * _vertices[i - 2]->alpha() + t * sv->attribute().getAlpha());
+ i++;
+
+ tvRep2 = new StrokeVertexRep(Vec2r((1 - t) * _vertices[i - 2]->point2d() + t * _vertices[i]->point2d()));
+ tvRep2->setTexCoord(Vec2r((real)tiles, 0.5));
+ tvRep2->setColor(Vec3r((1 - t) * _vertices[i - 2]->color() +
+ t * Vec3r(sv->attribute().getColor()[0], sv->attribute().getColor()[1],
+ sv->attribute().getColor()[2])));
+ tvRep2->setAlpha((1 - t) * _vertices[i - 2]->alpha() + t * sv->attribute().getAlpha());
+ i++;
+
+ currentSV = _vertices.insert(currentSV, tvRep1);
+ ++currentSV;
+ currentSV = _vertices.insert(currentSV, tvRep2);
+ ++currentSV;
+
+ //copy the vertices with different texture coordinates
+ tvRep1 = new StrokeVertexRep(_vertices[i - 2]->point2d());
+ tvRep1->setTexCoord(Vec2r(0.75, 0.5));
+ tvRep1->setColor(_vertices[i - 2]->color());
+ tvRep1->setAlpha(_vertices[i - 2]->alpha());
+ i++;
+
+ tvRep2 = new StrokeVertexRep(_vertices[i - 2]->point2d());
+ tvRep2->setTexCoord(Vec2r(0.75, 1));
+ tvRep2->setColor(_vertices[i - 2]->color());
+ tvRep2->setAlpha(_vertices[i - 2]->alpha());
+ i++;
+
+ currentSV = _vertices.insert(currentSV, tvRep1);
+ ++currentSV;
+ currentSV = _vertices.insert(currentSV, tvRep2);
+ ++currentSV;
+
+ //end tip
+ for (; v != vend; v++) {
+ sv = (*v);
+ svRep = *currentSV;
+ u = 0.75 + sv->curvilinearAbscissa() / _averageThickness * fact - float(tiles) - 0.25;
+
+ svRep->setTexCoord(Vec2r((real)u, 0.5));
+ svRep->setColor(Vec3r(sv->attribute().getColor()[0], sv->attribute().getColor()[1],
+ sv->attribute().getColor()[2]));
+ svRep->setAlpha(sv->attribute().getAlpha());
+ i++;
+ ++currentSV;
+
+ svRep = *currentSV;
+ svRep->setTexCoord(Vec2r((real)u, 1));
+ svRep->setColor(Vec3r(sv->attribute().getColor()[0], sv->attribute().getColor()[1],
+ sv->attribute().getColor()[2]));
+ svRep->setAlpha(sv->attribute().getAlpha());
+ i++;
+ ++currentSV;
+ }
+ }
+
+#if 0
+ cerr << "u=" << u << " i=" << i << "/" << _sizeStrip << endl;
+
+ for (i = 0; i < _sizeStrip; i++)
+ _alpha[i] = 1.0;
+
+ for (i = 0; i < _sizeStrip; i++)
+ cerr << "(" << _texCoord[i][0] << ", " << _texCoord[i][1] << ") ";
+ cerr << endl;
+
+ Vec2r vec_tmp;
+ for (i = 0; i < _sizeStrip / 2; i++)
+ vec_tmp = _vertex[2 * i] - _vertex[2 * i + 1];
+ if (vec_tmp.norm() > 4 * _averageThickness)
+ cerr << "Warning (from Fredo): There is a pb in the texture coordinates computation" << endl;
+#endif
+}
+
+//
+// StrokeRep
+/////////////////////////////////////
+
+StrokeRep::StrokeRep()
+{
+ _stroke = 0;
+ _strokeType = Stroke::OPAQUE_MEDIUM;
+ TextureManager *ptm = TextureManager::getInstance();
+ if (ptm)
+ _textureId = ptm->getDefaultTextureId();
+#if 0
+ _averageTextureAlpha = 0.5; //default value
+ if (_strokeType == OIL_STROKE)
+ _averageTextureAlpha = 0.75;
+ if (_strokeType >= NO_BLEND_STROKE)
+ _averageTextureAlpha = 1.0
+#endif
+}
+
+StrokeRep::StrokeRep(Stroke *iStroke)
+{
+ _stroke = iStroke;
+ _strokeType = iStroke->getMediumType();
+ _textureId = iStroke->getTextureId();
+ if (_textureId == 0) {
+ TextureManager *ptm = TextureManager::getInstance();
+ if (ptm)
+ _textureId = ptm->getDefaultTextureId();
+ }
+
+#if 0
+ _averageTextureAlpha = 0.5; //default value
+ if (_strokeType == OIL_STROKE)
+ _averageTextureAlpha = 0.75;
+ if (_strokeType >= NO_BLEND_STROKE)
+ _averageTextureAlpha = 1.0;
+#endif
+ create();
+}
+
+StrokeRep::StrokeRep(const StrokeRep& iBrother)
+{
+ //soc unused - int i = 0;
+ _stroke = iBrother._stroke;
+ _strokeType = iBrother._strokeType;
+ _textureId = iBrother._textureId;
+ for (vector<Strip*>::const_iterator s = iBrother._strips.begin(), send = iBrother._strips.end();
+ s != send;
+ ++s)
+ {
+ _strips.push_back(new Strip(**s));
+ }
+}
+
+StrokeRep::~StrokeRep()
+{
+ if (!_strips.empty()) {
+ for (vector<Strip*>::iterator s = _strips.begin(), send = _strips.end(); s != send; ++s) {
+ delete (*s);
+ }
+ _strips.clear();
+ }
+}
+
+void StrokeRep::create()
+{
+ vector<StrokeVertex*> strip;
+ StrokeInternal::StrokeVertexIterator v = _stroke->strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator vend = _stroke->strokeVerticesEnd();
+
+ bool first = true;
+ bool end = false;
+ while (v != vend) {
+ while ((v != vend) && (!(*v).attribute().isVisible())) {
+ ++v;
+ first = false;
+ }
+ while ((v != vend) && ((*v).attribute().isVisible())) {
+ strip.push_back(&(*v));
+ ++v;
+ }
+ if (v != vend) {
+ // add the last vertex and create
+ strip.push_back(&(*v));
+ }
+ else {
+ end = true;
+ }
+ if ((!strip.empty()) && (strip.size() > 1)) {
+ _strips.push_back(new Strip(strip, _stroke->hasTips(), first, end));
+ strip.clear();
+ }
+ first = false;
+ }
+}
+
+void StrokeRep::Render(const StrokeRenderer *iRenderer)
+{
+ iRenderer->RenderStrokeRep(this);
+}
diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.h b/source/blender/freestyle/intern/stroke/StrokeRep.h
new file mode 100644
index 00000000000..c8d84cb237a
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeRep.h
@@ -0,0 +1,217 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_STROKE_REP_H__
+#define __FREESTYLE_STROKE_REP_H__
+
+/** \file blender/freestyle/intern/stroke/StrokeRep.h
+ * \ingroup freestyle
+ * \brief Class to define the representation of a stroke (for display purpose)
+ * \author Stephane Grabli
+ * \date 05/03/2003
+ */
+
+#include "Stroke.h"
+
+#include "../geometry/Geom.h"
+
+using namespace Geometry;
+
+#if 0
+//symbolic constant to call the appropriate renderers and textures
+#define NO_TEXTURE_WITH_BLEND_STROKE -2
+#define NO_TEXTURE_STROKE -1
+#define PSEUDO_CHARCOAL_STROKE 0
+#define WASH_BRUSH_STROKE 1
+#define OIL_STROKE 2
+#define NO_BLEND_STROKE 3
+#define CHARCOAL_MIN_STROKE 4
+#define BRUSH_MIN_STROKE 5
+#define OPAQUE_DRY_STROKE 6
+#define OPAQUE_STROKE 7
+
+#define DEFAULT_STROKE 0
+
+#define NUMBER_STROKE_RENDERER 8
+
+#endif
+
+class StrokeVertexRep
+{
+public:
+ StrokeVertexRep(){}
+
+ StrokeVertexRep(const Vec2r& iPoint2d)
+ {
+ _point2d = iPoint2d;
+ }
+
+ StrokeVertexRep(const StrokeVertexRep& iBrother);
+
+ virtual ~StrokeVertexRep(){}
+
+ inline Vec2r& point2d()
+ {
+ return _point2d;
+ }
+
+ inline Vec2r& texCoord()
+ {
+ return _texCoord;
+ }
+
+ inline Vec3r& color()
+ {
+ return _color;
+ }
+
+ inline float alpha()
+ {
+ return _alpha;
+ }
+
+ inline void setPoint2d(const Vec2r& p)
+ {
+ _point2d = p;
+ }
+
+ inline void setTexCoord(const Vec2r& p)
+ {
+ _texCoord = p;
+ }
+
+ inline void setColor(const Vec3r& p)
+ {
+ _color = p;
+ }
+
+ inline void setAlpha(float a)
+ {
+ _alpha = a;
+ }
+
+protected:
+ Vec2r _point2d;
+ Vec2r _texCoord;
+ Vec3r _color;
+ float _alpha;
+};
+
+class Strip
+{
+public:
+ typedef std::vector<StrokeVertexRep*> vertex_container;
+
+protected:
+ vertex_container _vertices;
+ float _averageThickness;
+
+public:
+ Strip(const std::vector<StrokeVertex*>& iStrokeVertices, bool hasTips = false,
+ bool tipBegin = false, bool tipEnd = false);
+ Strip(const Strip& iBrother);
+ virtual ~Strip();
+
+protected:
+ void createStrip(const std::vector<StrokeVertex*>& iStrokeVertices);
+ void cleanUpSingularities(const std::vector<StrokeVertex*>& iStrokeVertices);
+ void computeTexCoord (const std::vector<StrokeVertex*>& iStrokeVertices);
+ void computeTexCoordWithTips (const std::vector<StrokeVertex*>& iStrokeVertices, bool tipBegin, bool tipEnd);
+
+public:
+ inline int sizeStrip() const
+ {
+ return _vertices.size();
+ }
+
+ inline vertex_container& vertices()
+ {
+ return _vertices;
+ }
+};
+
+class StrokeRep
+{
+protected:
+ Stroke *_stroke;
+ vector<Strip*> _strips;
+ Stroke::MediumType _strokeType;
+ unsigned int _textureId;
+
+ // float _averageTextureAlpha;
+
+public:
+ StrokeRep();
+ StrokeRep(const StrokeRep&);
+ StrokeRep(Stroke *iStroke);
+ virtual ~StrokeRep();
+
+ /*! Creates the strips */
+ virtual void create();
+
+ /*! Renders the stroke using a Renderer */
+ virtual void Render(const StrokeRenderer *iRenderer);
+
+ /*! accessors */
+ inline Stroke::MediumType getMediumType() const
+ {
+ return _strokeType;
+ }
+
+ inline unsigned getTextureId() const
+ {
+ return _textureId;
+ }
+
+ inline vector<Strip*>& getStrips()
+ {
+ return _strips;
+ }
+
+ inline unsigned int getNumberOfStrips() const
+ {
+ return _strips.size();
+ }
+
+ inline Stroke * getStroke()
+ {
+ return _stroke;
+ }
+
+ /*! modifiers */
+ inline void setMediumType(Stroke::MediumType itype)
+ {
+ _strokeType = itype;
+ }
+
+ inline void setTextureId(unsigned textureId)
+ {
+ _textureId = textureId;
+ }
+};
+
+#endif // __FREESTYLE_STROKE_REP_H__
diff --git a/source/blender/freestyle/intern/stroke/StrokeShader.h b/source/blender/freestyle/intern/stroke/StrokeShader.h
new file mode 100644
index 00000000000..c8364f7a737
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeShader.h
@@ -0,0 +1,107 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_STROKE_SHADERS_H__
+#define __FREESTYLE_STROKE_SHADERS_H__
+
+/** \file blender/freestyle/intern/stroke/StrokeShader.h
+ * \ingroup freestyle
+ * \brief Class defining StrokeShader
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include <iostream>
+#include <vector>
+
+#include "../python/Director.h"
+
+//
+// StrokeShader base class
+//
+//////////////////////////////////////////////////////
+
+class Stroke;
+
+/*! Base class for Stroke Shaders.
+ * Any Stroke Shader must inherit from this class and overload the shade() method.
+ * A StrokeShader is designed to modify any Stroke's attribute such as Thickness, Color,
+ * Geometry, Texture, Blending mode...
+ * The basic way to achieve this operation consists in iterating over the StrokeVertices of the Stroke
+ * and to modify each one's StrokeAttribute.
+ * Here is a python code example of such an iteration:
+ * \code
+ * it = ioStroke.strokeVerticesBegin()
+ * while not it.isEnd():
+ * att = it.getObject().attribute()
+ * ## perform here any attribute modification
+ * it.increment()
+ * \endcode
+ * Here is a C++ code example of such an iteration:
+ * \code
+ * for(StrokeInternal::StrokeVertexIterator v = ioStroke.strokeVerticesBegin(), vend = ioStroke.strokeVerticesEnd();
+ * v != vend;
+ * ++v)
+ * {
+ * StrokeAttribute& att = v->attribute();
+ * // perform any attribute modification here...
+ * }
+ * \endcode
+ */
+class LIB_STROKE_EXPORT StrokeShader
+{
+public:
+ PyObject *py_ss;
+
+ /*! Default constructor. */
+ StrokeShader()
+ {
+ py_ss = 0;
+ }
+
+ /*! Destructor. */
+ virtual ~StrokeShader() {}
+
+ /*! Returns the string corresponding to the shader's name. */
+ virtual string getName() const
+ {
+ return "StrokeShader";
+ }
+
+ /*! The shading method. This method must be overloaded by inherited classes.
+ * \param ioStroke
+ * The stroke we wish to shade. this Stroke is modified by the Shader (which typically
+ * modifies the Stroke's attribute's values such as Color, Thickness, Geometry...)
+ */
+ virtual int shade(Stroke& ioStroke) const
+ {
+ return Director_BPy_StrokeShader_shade( const_cast<StrokeShader *>(this), ioStroke);
+ }
+};
+
+#endif // __FREESTYLE_STROKE_SHADERS_H__
diff --git a/source/blender/freestyle/intern/stroke/StrokeTesselator.cpp b/source/blender/freestyle/intern/stroke/StrokeTesselator.cpp
new file mode 100644
index 00000000000..43cf1818fb0
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeTesselator.cpp
@@ -0,0 +1,94 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/stroke/StrokeTesselator.cpp
+ * \ingroup freestyle
+ * \brief Class to build a Node Tree designed to be displayed from a set of strokes structure.
+ * \author Stephane Grabli
+ * \date 26/03/2002
+ */
+
+#include "StrokeAdvancedIterators.h"
+#include "StrokeTesselator.h"
+
+#include "../scene_graph/OrientedLineRep.h"
+#include "../scene_graph/NodeGroup.h"
+#include "../scene_graph/NodeShape.h"
+
+LineRep *StrokeTesselator::Tesselate(Stroke *iStroke)
+{
+ if (0 == iStroke)
+ return 0;
+
+ LineRep* line;
+ line = new OrientedLineRep();
+
+ Stroke::vertex_iterator v,vend;
+ if (2 == iStroke->vertices_size()) {
+ line->setStyle(LineRep::LINES);
+ v = iStroke->vertices_begin();
+ StrokeVertex *svA = (*v);
+ v++;
+ StrokeVertex *svB = (*v);
+ Vec3r A((*svA)[0], (*svA)[1], 0);
+ Vec3r B((*svB)[0], (*svB)[1], 0);
+ line->AddVertex(A);
+ line->AddVertex(B);
+ }
+ else {
+ if (_overloadFrsMaterial)
+ line->setFrsMaterial(_FrsMaterial);
+
+ line->setStyle(LineRep::LINE_STRIP);
+
+ for (v = iStroke->vertices_begin(), vend = iStroke->vertices_end(); v != vend; v++) {
+ StrokeVertex *sv = (*v);
+ Vec3r V((*sv)[0], (*sv)[1], 0);
+ line->AddVertex(V);
+ }
+ }
+ line->setId(iStroke->getId());
+ line->ComputeBBox();
+
+ return line;
+}
+
+template<class StrokeVertexIterator>
+NodeGroup *StrokeTesselator::Tesselate(StrokeVertexIterator begin, StrokeVertexIterator end)
+{
+ NodeGroup *group = new NodeGroup;
+ NodeShape *tshape = new NodeShape;
+ group->AddChild(tshape);
+ //tshape->material().setDiffuse(0.0f, 0.0f, 0.0f, 1.0f);
+ tshape->setFrsMaterial(_FrsMaterial);
+
+ for (StrokeVertexIterator c = begin, cend = end; c != cend; c++) {
+ tshape->AddRep(Tesselate((*c)));
+ }
+
+ return group;
+}
diff --git a/source/blender/freestyle/intern/stroke/StrokeTesselator.h b/source/blender/freestyle/intern/stroke/StrokeTesselator.h
new file mode 100644
index 00000000000..e04f75a6f3e
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StrokeTesselator.h
@@ -0,0 +1,78 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_STROKE_TESSELATOR_H__
+#define __FREESTYLE_STROKE_TESSELATOR_H__
+
+/** \file blender/freestyle/intern/stroke/StrokeTesselator.h
+ * \ingroup freestyle
+ * \brief Class to build a Node Tree designed to be displayed from a set of strokes structure.
+ * \author Stephane Grabli
+ * \date 26/03/2002
+ */
+
+#include "Stroke.h"
+
+#include "../scene_graph/LineRep.h"
+
+class StrokeTesselator
+{
+public:
+ inline StrokeTesselator()
+ {
+ _FrsMaterial.setDiffuse(0, 0, 0, 1);
+ _overloadFrsMaterial = false;
+ }
+
+ virtual ~StrokeTesselator() {}
+
+ /*! Builds a line rep contained from a Stroke */
+ LineRep *Tesselate(Stroke *iStroke);
+
+ /*! Builds a set of lines rep contained under a a NodeShape, itself contained under a NodeGroup
+ * from a set of strokes.
+ */
+ template<class StrokeIterator>
+ NodeGroup *Tesselate(StrokeIterator begin, StrokeIterator end);
+
+ inline void setFrsMaterial(const FrsMaterial& iMaterial)
+ {
+ _FrsMaterial = iMaterial;
+ _overloadFrsMaterial = true;
+ }
+
+ inline const FrsMaterial& frs_material() const
+ {
+ return _FrsMaterial;
+ }
+
+private:
+ FrsMaterial _FrsMaterial;
+ bool _overloadFrsMaterial;
+};
+
+#endif // __FREESTYLE_STROKE_TESSELATOR_H__
diff --git a/source/blender/freestyle/intern/stroke/StyleModule.h b/source/blender/freestyle/intern/stroke/StyleModule.h
new file mode 100644
index 00000000000..12f645f125b
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/StyleModule.h
@@ -0,0 +1,184 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_STYLE_MODULE_H__
+#define __FREESTYLE_STYLE_MODULE_H__
+
+/** \file blender/freestyle/intern/stroke/StyleModule.h
+ * \ingroup freestyle
+ * \brief Class representing a style module
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include <iostream>
+#include <string>
+
+#include "Operators.h"
+#include "StrokeLayer.h"
+#include "StrokeShader.h"
+
+#include "../system/Interpreter.h"
+#include "../system/StringUtils.h"
+
+using namespace std;
+
+class StyleModule
+{
+public:
+ StyleModule(const string& file_name, Interpreter *inter) : _file_name(file_name)
+ {
+ _always_refresh = false;
+ _causal = false;
+ _drawable = true;
+ _modified = true;
+ _displayed = true;
+ _inter = inter;
+ }
+
+ virtual ~StyleModule() {}
+
+ StrokeLayer *execute()
+ {
+ if (!_inter) {
+ cerr << "Error: no interpreter was found to execute the script" << endl;
+ return NULL;
+ }
+
+ if (!_drawable) {
+ cerr << "Error: not drawable" << endl;
+ return NULL;
+ }
+
+ Operators::reset();
+
+ if (interpret()) {
+ cerr << "Error: interpretation failed" << endl;
+ Operators::reset();
+ return NULL;
+ }
+
+ Operators::StrokesContainer *strokes_set = Operators::getStrokesSet();
+ if (strokes_set->empty()) {
+ cerr << "Error: strokes set empty" << endl;
+ Operators::reset();
+ return NULL;
+ }
+
+ StrokeLayer *sl = new StrokeLayer;
+ for (Operators::StrokesContainer::iterator it = strokes_set->begin(); it != strokes_set->end(); ++it)
+ sl->AddStroke(*it);
+
+ Operators::reset();
+ return sl;
+ }
+
+protected:
+ virtual int interpret()
+ {
+ return _inter->interpretFile(_file_name);
+ }
+
+public:
+ // accessors
+ const string getFileName() const
+ {
+ return _file_name;
+ }
+
+ bool getAlwaysRefresh() const
+ {
+ return _always_refresh;
+ }
+
+ bool getCausal() const
+ {
+ return _causal;
+ }
+
+ bool getDrawable() const
+ {
+ return _drawable;
+ }
+
+ bool getModified() const
+ {
+ return _modified;
+ }
+
+ bool getDisplayed() const
+ {
+ return _displayed;
+ }
+
+ // modifiers
+ void setFileName(const string& file_name)
+ {
+ _file_name = file_name;
+ }
+
+ void setAlwaysRefresh(bool b = true)
+ {
+ _always_refresh = b;
+ }
+
+ void setCausal(bool b = true)
+ {
+ _causal = b;
+ }
+
+ void setDrawable(bool b = true)
+ {
+ _drawable = b;
+ }
+
+ void setModified(bool b = true)
+ {
+ if (_always_refresh)
+ return;
+ _modified = b;
+ }
+
+ void setDisplayed(bool b = true)
+ {
+ _displayed = b;
+ }
+
+private:
+ string _file_name;
+ bool _always_refresh;
+ bool _causal;
+ bool _drawable;
+ bool _modified;
+ bool _displayed;
+
+protected:
+ Interpreter *_inter;
+};
+
+#endif // __FREESTYLE_STYLE_MODULE_H__
diff --git a/source/blender/freestyle/intern/stroke/TextStrokeRenderer.cpp b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.cpp
new file mode 100644
index 00000000000..ea5af287bbe
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.cpp
@@ -0,0 +1,73 @@
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+# include "TextStrokeRenderer.h"
+# include "Canvas.h"
+# include "StrokeIterators.h"
+
+TextStrokeRenderer::TextStrokeRenderer(const char* iFileName)
+:StrokeRenderer(){
+ if(!iFileName)
+ iFileName = "freestyle.txt";
+ // open the stream:
+ _ofstream.open(iFileName, ios::out);
+ if(!_ofstream.is_open()){
+ cerr << "couldn't open the output file " << iFileName << endl;
+ }
+ _ofstream << "%!FREESTYLE" << endl;
+ _ofstream << "%Creator: Freestyle (http://artis.imag.fr/Software/Freestyle)" << endl;
+ // Bounding box
+ _ofstream << 0 << " "<< 0 << " " << Canvas::getInstance()->width() << " " << Canvas::getInstance()->height() << endl;
+ _ofstream << "%u x y z tleft tright r g b ..." << endl;
+}
+
+TextStrokeRenderer::~TextStrokeRenderer(){
+ Close();
+}
+
+void TextStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const{
+ RenderStrokeRepBasic(iStrokeRep);
+}
+
+void TextStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const{
+ Stroke *stroke = iStrokeRep->getStroke();
+ if(!stroke){
+ cerr << "no stroke associated with Rep" << endl;
+ return;
+ }
+
+ StrokeInternal::StrokeVertexIterator v = stroke->strokeVerticesBegin();
+ StrokeAttribute att;
+ while(!v.isEnd()){
+ att = v->attribute();
+ _ofstream << v->u() << " " << v->getProjectedX() << " " << v->getProjectedY() << " " << v->getProjectedZ() << " " \
+ << att.getThicknessL() << " " << att.getThicknessR() << " " \
+ << att.getColorR() << " " << att.getColorG() << " " << att.getColorB() << " ";
+ ++v;
+ }
+ _ofstream << endl;
+}
+
+void TextStrokeRenderer::Close(){
+ if(_ofstream.is_open())
+ _ofstream.close();
+}
+
diff --git a/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h
new file mode 100644
index 00000000000..cc6f5c05073
--- /dev/null
+++ b/source/blender/freestyle/intern/stroke/TextStrokeRenderer.h
@@ -0,0 +1,68 @@
+//
+// Filename : TextStrokeRenderer.h
+// Author(s) : Stephane Grabli
+// Purpose : Class to define the text rendering of a stroke
+// Format:
+// x y width height // bbox
+// //list of vertices :
+// t x y z t1 t2 r g b alpha ...
+// ...
+// Date of creation : 01/14/2005
+//
+///////////////////////////////////////////////////////////////////////////////
+
+
+//
+// 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.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TEXTSTROKERENDERER_H
+# define TEXTSTROKERENDERER_H
+
+# include "StrokeRenderer.h"
+# include "../system/FreestyleConfig.h"
+# include <fstream>
+
+/**********************************/
+/* */
+/* */
+/* TextStrokeRenderer */
+/* */
+/* */
+/**********************************/
+
+class LIB_STROKE_EXPORT TextStrokeRenderer : public StrokeRenderer
+{
+public:
+ TextStrokeRenderer(const char * iFileName = 0);
+ virtual ~TextStrokeRenderer();
+
+ /*! Renders a stroke rep */
+ virtual void RenderStrokeRep(StrokeRep *iStrokeRep) const;
+ virtual void RenderStrokeRepBasic(StrokeRep *iStrokeRep) const;
+
+ /*! Closes the output file */
+ void Close();
+
+protected:
+ mutable ofstream _ofstream;
+};
+
+#endif // TEXTSTROKERENDERER_H
+
diff --git a/source/blender/freestyle/intern/system/BaseIterator.h b/source/blender/freestyle/intern/system/BaseIterator.h
new file mode 100644
index 00000000000..836f6c83eb8
--- /dev/null
+++ b/source/blender/freestyle/intern/system/BaseIterator.h
@@ -0,0 +1,97 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_BASE_ITERATOR_H__
+#define __FREESTYLE_BASE_ITERATOR_H__
+
+/** \file blender/freestyle/intern/system/BaseIterator.h
+ * \ingroup freestyle
+ * \brief Classes defining the basic "Iterator" design pattern
+ * \author Stephane Grabli
+ * \date 18/03/2003
+ */
+
+#include <iterator>
+
+// use for iterators defintions
+template <class Element>
+class Nonconst_traits;
+
+template <class Element>
+class Const_traits
+{
+public:
+ typedef Element value_type;
+ typedef const Element& reference;
+ typedef const Element *pointer;
+ typedef ptrdiff_t difference_type;
+ typedef Nonconst_traits<Element> Non_const_traits;
+};
+
+template <class Element>
+class Nonconst_traits
+{
+public:
+ typedef Element value_type;
+ typedef Element& reference;
+ typedef Element *pointer;
+ typedef ptrdiff_t difference_type;
+ typedef Nonconst_traits<Element> Non_const_traits;
+};
+
+class InputIteratorTag_Traits
+{
+public:
+ typedef std::input_iterator_tag iterator_category;
+};
+
+class BidirectionalIteratorTag_Traits
+{
+public:
+ typedef std::bidirectional_iterator_tag iterator_category;
+};
+
+template<class Traits, class IteratorTagTraits>
+class IteratorBase
+{
+public:
+ virtual ~IteratorBase() {}
+
+ virtual bool begin() const = 0;
+ virtual bool end() const = 0;
+
+ typedef typename IteratorTagTraits::iterator_category iterator_category;
+ typedef typename Traits::value_type value_type;
+ typedef typename Traits::difference_type difference_type;
+ typedef typename Traits::pointer pointer;
+ typedef typename Traits::reference reference;
+
+protected:
+ IteratorBase() {}
+};
+
+#endif // BASEITERATOR_H
diff --git a/source/blender/freestyle/intern/system/BaseObject.cpp b/source/blender/freestyle/intern/system/BaseObject.cpp
new file mode 100644
index 00000000000..2088585c33b
--- /dev/null
+++ b/source/blender/freestyle/intern/system/BaseObject.cpp
@@ -0,0 +1,36 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/system/BaseObject.cpp
+ * \ingroup freestyle
+ * \brief Base Class for most shared objects (Node, Rep). Defines the addRef, release system.
+ * \brief Inspired by COM IUnknown system.
+ * \author Stephane Grabli
+ * \date 06/02/2002
+ */
+
+#include "BaseObject.h"
diff --git a/source/blender/freestyle/intern/system/BaseObject.h b/source/blender/freestyle/intern/system/BaseObject.h
new file mode 100644
index 00000000000..1fe2770c313
--- /dev/null
+++ b/source/blender/freestyle/intern/system/BaseObject.h
@@ -0,0 +1,77 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_BASE_OBJECT_H__
+#define __FREESTYLE_BASE_OBJECT_H__
+
+/** \file blender/freestyle/intern/system/BaseObject.h
+ * \ingroup freestyle
+ * \brief Base Class for most shared objects (Node, Rep). Defines the addRef, release system.
+ * \brief Inspired by COM IUnknown system.
+ * \author Stephane Grabli
+ * \date 06/02/2002
+ */
+
+#include "FreestyleConfig.h"
+
+class LIB_SYSTEM_EXPORT BaseObject
+{
+public:
+ inline BaseObject()
+ {
+ _ref_counter = 0;
+ }
+
+ virtual ~BaseObject() {}
+
+ /*! At least makes a release on this.
+ * The BaseObject::destroy method must be explicitely called at the end of any overloaded destroy
+ */
+ virtual int destroy()
+ {
+ return release();
+ }
+
+ /*! Increments the reference counter */
+ inline int addRef()
+ {
+ return ++_ref_counter;
+ }
+
+ /*! Decrements the reference counter */
+ inline int release()
+ {
+ if (_ref_counter)
+ _ref_counter--;
+ return _ref_counter;
+ }
+
+private:
+ unsigned _ref_counter;
+};
+
+#endif // __FREESTYLE_BASE_OBJECT_H__
diff --git a/source/blender/freestyle/intern/system/Cast.h b/source/blender/freestyle/intern/system/Cast.h
new file mode 100644
index 00000000000..02dd5699214
--- /dev/null
+++ b/source/blender/freestyle/intern/system/Cast.h
@@ -0,0 +1,49 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_CAST_H__
+#define __FREESTYLE_CAST_H__
+
+/** \file blender/freestyle/intern/system/Cast.h
+ * \ingroup freestyle
+ * \brief Cast function
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+namespace Cast
+{
+ template <class T, class U>
+ U *cast(T *in)
+ {
+ if (!in)
+ return NULL;
+ return dynamic_cast<U*>(in);
+ }
+} // end of namespace Cast
+
+#endif // __FREESTYLE_CAST_H__
diff --git a/source/blender/freestyle/intern/system/Exception.cpp b/source/blender/freestyle/intern/system/Exception.cpp
new file mode 100644
index 00000000000..7c7c16fdf40
--- /dev/null
+++ b/source/blender/freestyle/intern/system/Exception.cpp
@@ -0,0 +1,37 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/system/Exception.cpp
+ * \ingroup freestyle
+ * \brief Singleton to manage exceptions
+ * \author Stephane Grabli
+ * \date 10/01/2003
+ */
+
+#include "Exception.h"
+
+Exception::exception_type Exception::_exception = Exception::NO_EXCEPTION;
diff --git a/source/blender/freestyle/intern/system/Exception.h b/source/blender/freestyle/intern/system/Exception.h
new file mode 100644
index 00000000000..b9bfa00cf97
--- /dev/null
+++ b/source/blender/freestyle/intern/system/Exception.h
@@ -0,0 +1,70 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_EXCEPTION_H__
+#define __FREESTYLE_EXCEPTION_H__
+
+/** \file blender/freestyle/intern/system/Exception.h
+ * \ingroup freestyle
+ * \brief Singleton to manage exceptions
+ * \author Stephane Grabli
+ * \date 10/01/2003
+ */
+
+#include "FreestyleConfig.h"
+
+class LIB_SYSTEM_EXPORT Exception
+{
+public:
+ typedef enum {
+ NO_EXCEPTION,
+ UNDEFINED,
+ } exception_type;
+
+ static int getException()
+ {
+ exception_type e = _exception;
+ _exception = NO_EXCEPTION;
+ return e;
+ }
+
+ static int raiseException(exception_type exception = UNDEFINED)
+ {
+ _exception = exception;
+ return _exception;
+ }
+
+ static void reset()
+ {
+ _exception = NO_EXCEPTION;
+ }
+
+private:
+ static exception_type _exception;
+};
+
+#endif // __FREESTYLE_EXCEPTION_H__
diff --git a/source/blender/freestyle/intern/system/FreestyleConfig.h b/source/blender/freestyle/intern/system/FreestyleConfig.h
new file mode 100644
index 00000000000..9d81af1be3b
--- /dev/null
+++ b/source/blender/freestyle/intern/system/FreestyleConfig.h
@@ -0,0 +1,96 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_CONFIG_H__
+#define __FREESTYLE_CONFIG_H__
+
+/** \file blender/freestyle/intern/system/Config.h
+ * \ingroup freestyle
+ * \brief Configuration definitions
+ * \author Emmanuel Turquin
+ * \date 25/02/2003
+ */
+
+#include <string>
+
+#include "BLI_math.h"
+
+using namespace std;
+
+namespace Config {
+
+// Directory separators
+// TODO Use Blender's stuff for such things!
+#ifdef WIN32
+ static const string DIR_SEP("\\");
+ static const string PATH_SEP(";");
+#else
+ static const string DIR_SEP("/");
+ static const string PATH_SEP(":");
+#endif // WIN32
+
+// DLL import/export macros for Win32
+
+#ifndef LIB_SYSTEM_EXPORT
+# define LIB_SYSTEM_EXPORT
+#endif // LIB_SYSTEM_EXPORT
+
+#ifndef LIB_IMAGE_EXPORT
+# define LIB_IMAGE_EXPORT
+#endif // LIB_IMAGE_EXPORT
+
+#ifndef LIB_GEOMETRY_EXPORT
+# define LIB_GEOMETRY_EXPORT
+#endif // LIB_GEOMETRY_EXPORT
+
+#ifndef LIB_SCENE_GRAPH_EXPORT
+# define LIB_SCENE_GRAPH_EXPORT
+#endif // LIB_SCENE_GRAPH_EXPORT
+
+#ifndef LIB_WINGED_EDGE_EXPORT
+# define LIB_WINGED_EDGE_EXPORT
+#endif // LIB_WINGED_EDGE_EXPORT
+
+#ifndef LIB_VIEW_MAP_EXPORT
+# define LIB_VIEW_MAP_EXPORT
+#endif // LIB_VIEW_MAP_EXPORT
+
+#ifndef LIB_STROKE_EXPORT
+# define LIB_STROKE_EXPORT
+#endif // LIB_STROKE_EXPORT
+
+#ifndef LIB_RENDERING_EXPORT
+# define LIB_RENDERING_EXPORT
+#endif // LIB_RENDERING_EXPORT
+
+#ifndef LIB_WRAPPER_EXPORT
+# define LIB_WRAPPER_EXPORT
+#endif // LIB_WRAPPER_EXPORT
+
+} // end of namespace Config
+
+#endif // __FREESTYLE_CONFIG_H__
diff --git a/source/blender/freestyle/intern/system/Id.h b/source/blender/freestyle/intern/system/Id.h
new file mode 100644
index 00000000000..d6e39bff167
--- /dev/null
+++ b/source/blender/freestyle/intern/system/Id.h
@@ -0,0 +1,142 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_ID_H__
+#define __FREESTYLE_ID_H__
+
+/** \file blender/freestyle/intern/system/Id.h
+ * \ingroup freestyle
+ * \brief Identification system
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+/*! Class used to tag any object by an id.
+ * It is made of two unsigned integers.
+ */
+class Id
+{
+public:
+ typedef unsigned id_type;
+
+ /*! Default constructor */
+ Id()
+ {
+ _first = 0;
+ _second = 0;
+ }
+
+ /*! Builds an Id from an integer.
+ * The second number is set to 0.
+ */
+ Id(id_type id)
+ {
+ _first = id;
+ _second = 0;
+ }
+
+ /*! Builds the Id from the two numbers */
+ Id(id_type ifirst, id_type isecond)
+ {
+ _first = ifirst;
+ _second = isecond;
+ }
+
+ /*! Copy constructor */
+ Id(const Id& iBrother)
+ {
+ _first = iBrother._first;
+ _second = iBrother._second;
+ }
+
+ /*! Operator= */
+ Id& operator=(const Id& iBrother)
+ {
+ _first = iBrother._first;
+ _second = iBrother._second;
+ return *this;
+ }
+
+ /*! Returns the first Id number */
+ id_type getFirst() const
+ {
+ return _first;
+ }
+
+ /*! Returns the second Id number */
+ id_type getSecond() const
+ {
+ return _second;
+ }
+
+ /*! Sets the first number constituing the Id */
+ void setFirst(id_type first)
+ {
+ _first = first;
+ }
+
+ /*! Sets the second number constituing the Id */
+ void setSecond(id_type second)
+ {
+ _second = second;
+ }
+
+ /*! Operator== */
+ bool operator==(const Id& id) const
+ {
+ return ((_first == id._first) && (_second == id._second));
+ }
+
+ /*! Operator!= */
+ bool operator!=(const Id& id) const
+ {
+ return !((*this) == id);
+ }
+
+ /*! Operator< */
+ bool operator<(const Id& id) const
+ {
+ if (_first < id._first)
+ return true;
+ if (_first == id._first && _second < id._second)
+ return true;
+ return false;
+ }
+
+private:
+ id_type _first;
+ id_type _second;
+};
+
+// stream operator
+inline std::ostream& operator<<(std::ostream& s, const Id& id)
+{
+ s << "[" << id.getFirst() << ", " << id.getSecond() << "]";
+ return s;
+}
+
+# endif // __FREESTYLE_ID_H__
diff --git a/source/blender/freestyle/intern/system/Interpreter.h b/source/blender/freestyle/intern/system/Interpreter.h
new file mode 100644
index 00000000000..7928db9aed2
--- /dev/null
+++ b/source/blender/freestyle/intern/system/Interpreter.h
@@ -0,0 +1,65 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_INTERPRETER_H__
+#define __FREESTYLE_INTERPRETER_H__
+
+/** \file blender/freestyle/intern/system/Interpreter.h
+ * \ingroup freestyle
+ * \brief Base Class of all script interpreters
+ * \author Emmanuel Turquin
+ * \date 17/04/2003
+ */
+
+#include <string>
+
+using namespace std;
+
+class LIB_SYSTEM_EXPORT Interpreter
+{
+public:
+ Interpreter()
+ {
+ _language = "Unknown";
+ }
+
+ virtual ~Interpreter() {}; //soc
+
+ virtual int interpretFile(const string& filename) = 0;
+
+ virtual string getLanguage() const
+ {
+ return _language;
+ }
+
+ virtual void reset() = 0;
+
+protected:
+ string _language;
+};
+
+#endif // __FREESTYLE_INTERPRETER_H__
diff --git a/source/blender/freestyle/intern/system/Iterator.cpp b/source/blender/freestyle/intern/system/Iterator.cpp
new file mode 100644
index 00000000000..2e89880b3d7
--- /dev/null
+++ b/source/blender/freestyle/intern/system/Iterator.cpp
@@ -0,0 +1,32 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/system/Iterator.cpp
+ * \ingroup freestyle
+ */
+
+#include "Iterator.h"
diff --git a/source/blender/freestyle/intern/system/Iterator.h b/source/blender/freestyle/intern/system/Iterator.h
new file mode 100644
index 00000000000..9cd0f16275b
--- /dev/null
+++ b/source/blender/freestyle/intern/system/Iterator.h
@@ -0,0 +1,75 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_ITERATOR_H__
+#define __FREESTYLE_ITERATOR_H__
+
+/** \file blender/freestyle/intern/system/Iterator.h
+ * \ingroup freestyle
+ */
+
+#include <iostream>
+#include <string>
+
+using namespace std;
+
+class Iterator
+{
+public:
+ virtual ~Iterator() {}
+
+ virtual string getExactTypeName() const
+ {
+ return "Iterator";
+ }
+
+ virtual int increment()
+ {
+ cerr << "Warning: increment() not implemented" << endl;
+ return 0;
+ }
+
+ virtual int decrement()
+ {
+ cerr << "Warning: decrement() not implemented" << endl;
+ return 0;
+ }
+
+ virtual bool isBegin() const
+ {
+ cerr << "Warning: isBegin() not implemented" << endl;
+ return false;
+ }
+
+ virtual bool isEnd() const
+ {
+ cerr << "Warning: isEnd() not implemented" << endl;
+ return false;
+ }
+};
+
+#endif // __FREESTYLE_ITERATOR_H__
diff --git a/source/blender/freestyle/intern/system/PointerSequence.h b/source/blender/freestyle/intern/system/PointerSequence.h
new file mode 100644
index 00000000000..c97f4516d00
--- /dev/null
+++ b/source/blender/freestyle/intern/system/PointerSequence.h
@@ -0,0 +1,96 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_POINTER_SEQUENCE_H__
+#define __FREESTYLE_POINTER_SEQUENCE_H__
+
+/** \file blender/freestyle/intern/system/PointerSequence.h
+ * \ingroup freestyle
+ * \brief Simple RAII wrappers for std:: sequential containers
+ * \author 22/11/2010
+ * \date 18/03/2003
+ *
+ * PointerSequence
+ *
+ * Produces a wrapped version of a sequence type (std::vector, std::deque, std::list) that will take ownership of
+ * pointers tht it stores. Those pointers will be deleted in its destructor.
+ *
+ * Because the contained pointers are wholly owned by the sequence, you cannot make a copy of the sequence.
+ * Making a copy would result in a double free.
+ *
+ * This is a no-frills class that provides no additional facilities. The user is responsible for managing any
+ * pointers that are removed from the list, and for making sure that any pointers contained in the class are not
+ * deleted elsewhere. Because this class does no reference counting, the user must also make sure that any pointer
+ * appears only once in the sequence.
+ *
+ * If more sophisticated facilities are needed, use tr1::shared_ptr or boost::shared_ptr.
+ * This class is only intended to allow one to eke by in projects where tr1 or boost are not available.
+ *
+ * Usage: The template takes two parameters, the standard container, and the class held in the container. This is a
+ * limitation of C++ templates, where T::iterator is not a type when T is a template parameter. If anyone knows a way
+ * around this limitation, then the second parameter can be eliminated.
+ *
+ * Example:
+ * PointerSequence<vector<Widget*>, Widget*> v;
+ * v.push_back(new Widget);
+ * cout << v[0] << endl; // operator[] is provided by std::vector, not by PointerSequence
+ * v.destroy(); // Deletes all pointers in sequence and sets them to NULL.
+ *
+ * The idiom for removing a pointer from a sequence is:
+ * Widget* w = v[3];
+ * v.erase(v.begin() + 3); // or v[3] = 0;
+ * The user is now responsible for disposing of w properly.
+ */
+
+#include <algorithm>
+
+template <typename C, typename T>
+class PointerSequence : public C
+{
+ PointerSequence (PointerSequence& other);
+ PointerSequence& operator=(PointerSequence& other);
+
+ static void destroyer(T t)
+ {
+ delete t;
+ }
+
+public:
+ PointerSequence () {};
+
+ ~PointerSequence ()
+ {
+ destroy();
+ }
+
+ void destroy ()
+ {
+ for_each(this->begin(), this->end(), destroyer);
+ }
+};
+
+#endif // __FREESTYLE_POINTER_SEQUENCE_H__
diff --git a/source/blender/freestyle/intern/system/Precision.h b/source/blender/freestyle/intern/system/Precision.h
new file mode 100644
index 00000000000..c2a9e24e635
--- /dev/null
+++ b/source/blender/freestyle/intern/system/Precision.h
@@ -0,0 +1,44 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_PRECISION_H__
+#define __FREESTYLE_PRECISION_H__
+
+/** \file blender/freestyle/intern/system/Precision.h
+ * \ingroup freestyle
+ * \brief Define the float precision used in the program
+ * \author Stephane Grabli
+ * \date 30/07/2002
+ */
+
+typedef double real;
+
+#ifndef SWIG
+ static const real M_EPSILON = 0.00000001;
+#endif // SWIG
+
+#endif // __FREESTYLE_PRECISION_H__
diff --git a/source/blender/freestyle/intern/system/ProgressBar.h b/source/blender/freestyle/intern/system/ProgressBar.h
new file mode 100644
index 00000000000..2837c148754
--- /dev/null
+++ b/source/blender/freestyle/intern/system/ProgressBar.h
@@ -0,0 +1,96 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_PROGRESS_BAR_H__
+#define __FREESTYLE_PROGRESS_BAR_H__
+
+/** \file blender/freestyle/intern/system/ProgressBar.h
+ * \ingroup freestyle
+ * \brief Class to encapsulate a progress bar
+ * \author Stephane Grabli
+ * \date 27/08/2002
+ */
+
+#include <string>
+
+using namespace std;
+
+class ProgressBar
+{
+public:
+ inline ProgressBar()
+ {
+ _numtotalsteps = 0;
+ _progress = 0;
+ }
+
+ virtual ~ProgressBar() {}
+
+ virtual void reset()
+ {
+ _numtotalsteps = 0;
+ _progress = 0;
+ }
+
+ virtual void setTotalSteps(unsigned n)
+ {
+ _numtotalsteps = n;
+ }
+
+ virtual void setProgress(unsigned i)
+ {
+ _progress = i;
+ }
+
+ virtual void setLabelText(const string& s)
+ {
+ _label = s;
+ }
+
+ /*! accessors */
+ inline unsigned int getTotalSteps() const
+ {
+ return _numtotalsteps;
+ }
+
+ inline unsigned int getProgress() const
+ {
+ return _progress;
+ }
+
+ inline string getLabelText() const
+ {
+ return _label;
+ }
+
+protected:
+ unsigned _numtotalsteps;
+ unsigned _progress;
+ string _label;
+};
+
+#endif // __FREESTYLE_PROGRESS_BAR_H__
diff --git a/source/blender/freestyle/intern/system/PseudoNoise.cpp b/source/blender/freestyle/intern/system/PseudoNoise.cpp
new file mode 100644
index 00000000000..27158bfd4aa
--- /dev/null
+++ b/source/blender/freestyle/intern/system/PseudoNoise.cpp
@@ -0,0 +1,116 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/system/PseudoNoise.cpp
+ * \ingroup freestyle
+ * \brief Class to define a pseudo Perlin noise
+ * \author Fredo Durand
+ * \date 16/06/2003
+ */
+
+#include <math.h>
+
+#include "PseudoNoise.h"
+#include "RandGen.h"
+
+static const unsigned NB_VALUE_NOISE = 512;
+
+real *PseudoNoise::_values;
+
+PseudoNoise::PseudoNoise() {}
+
+void PseudoNoise::init(long seed)
+{
+ _values = new real[NB_VALUE_NOISE];
+ RandGen::srand48(seed);
+ for (unsigned int i = 0; i < NB_VALUE_NOISE; i++)
+ _values[i] = -1.0 + 2.0 * RandGen::drand48();
+}
+
+real PseudoNoise::linearNoise(real x)
+{
+ real tmp;
+ int i = modf(x, &tmp) * NB_VALUE_NOISE;
+ real x1 = _values[i], x2 = _values[(i + 1) % NB_VALUE_NOISE];
+ real t = modf(x * NB_VALUE_NOISE, &tmp);
+ return x1 * (1 - t) + x2 * t;
+}
+
+static real LanczosWindowed(real t)
+{
+ if (fabs(t) > 2)
+ return 0;
+ if (fabs(t) < M_EPSILON)
+ return 1.0;
+ return sin(M_PI * t) / (M_PI * t) * sin(M_PI * t / 2.0) / (M_PI * t / 2.0);
+}
+
+real PseudoNoise::smoothNoise(real x)
+{
+ real tmp;
+ int i = modf(x, &tmp) * NB_VALUE_NOISE;
+ int h = i - 1;
+ if (h < 0) {
+ h = NB_VALUE_NOISE + h;
+ }
+
+ real x1 = _values[i], x2 = _values[(i + 1) % NB_VALUE_NOISE];
+ real x0 = _values[h], x3 = _values[(i + 2) % NB_VALUE_NOISE];
+
+ real t = modf(x * NB_VALUE_NOISE, &tmp);
+ real y0 = LanczosWindowed(-1 -t);
+ real y1 = LanczosWindowed(-t);
+ real y2 = LanczosWindowed(1 - t);
+ real y3 = LanczosWindowed(2 - t);
+#if 0
+ cerr << "x0=" << x0 << " x1=" << x1 << " x2=" << x2 << " x3=" << x3 << endl;
+ cerr << "y0=" << y0 << " y1=" << y1 << " y2=" << y2 << " y3=" << y3 << " :" << endl;
+#endif
+ return (x0 * y0 + x1 * y1 + x2 * y2 + x3 * y3) / (y0 + y1 + y2 + y3);
+}
+
+real PseudoNoise::turbulenceSmooth(real x, unsigned nbOctave)
+{
+ real y = 0;
+ real k = 1.0;
+ for (unsigned int i = 0; i < nbOctave; i++) {
+ y = y + k * smoothNoise(x * k);
+ k = k / 2.0;
+ }
+ return y;
+}
+
+real PseudoNoise::turbulenceLinear(real x, unsigned nbOctave)
+{
+ real y = 0;
+ real k = 1.0;
+ for (unsigned int i = 0; i < nbOctave; i++) {
+ y = y + k * linearNoise(x * k);
+ k = k / 2.0;
+ }
+ return y;
+}
diff --git a/source/blender/freestyle/intern/system/PseudoNoise.h b/source/blender/freestyle/intern/system/PseudoNoise.h
new file mode 100644
index 00000000000..7b414ae76e5
--- /dev/null
+++ b/source/blender/freestyle/intern/system/PseudoNoise.h
@@ -0,0 +1,60 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_PSEUDO_NOISE_H__
+#define __FREESTYLE_PSEUDO_NOISE_H__
+
+/** \file blender/freestyle/intern/system/PseudoNoise.h
+ * \ingroup freestyle
+ * \brief Class to define a pseudo Perlin noise
+ * \author Fredo Durand
+ * \date 16/06/2003
+ */
+
+#include "FreestyleConfig.h"
+#include "Precision.h"
+
+class LIB_SYSTEM_EXPORT PseudoNoise
+{
+public:
+ PseudoNoise();
+
+ virtual ~PseudoNoise() {}
+
+ real smoothNoise(real x);
+ real linearNoise(real x);
+
+ real turbulenceSmooth(real x, unsigned nbOctave = 8);
+ real turbulenceLinear(real x, unsigned nbOctave = 8);
+
+ static void init(long seed);
+
+protected:
+ static real *_values;
+};
+
+#endif // __FREESTYLE_PSEUDO_NOISE_H__
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.cpp b/source/blender/freestyle/intern/system/PythonInterpreter.cpp
new file mode 100644
index 00000000000..aa8df8f418b
--- /dev/null
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.cpp
@@ -0,0 +1,38 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/system/PythonInterpreter.cpp
+ * \ingroup freestyle
+ * \brief Python Interpreter
+ * \author Emmanuel Turquin
+ * \date 17/04/2003
+ */
+
+#include "PythonInterpreter.h"
+
+string PythonInterpreter::_path = "";
+bool PythonInterpreter::_initialized = false;
diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h
new file mode 100644
index 00000000000..6093b6e4dcd
--- /dev/null
+++ b/source/blender/freestyle/intern/system/PythonInterpreter.h
@@ -0,0 +1,198 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_PYTHON_INTERPRETER_H__
+#define __FREESTYLE_PYTHON_INTERPRETER_H__
+
+/** \file blender/freestyle/intern/system/PythonInterpreter.h
+ * \ingroup freestyle
+ * \brief Python Interpreter
+ * \author Emmanuel Turquin
+ * \date 17/04/2003
+ */
+
+#include <iostream>
+#include <Python.h>
+
+#include "StringUtils.h"
+#include "Interpreter.h"
+
+//soc
+extern "C" {
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_text_types.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+#include "BKE_text.h"
+
+#include "BPY_extern.h"
+
+}
+
+class LIB_SYSTEM_EXPORT PythonInterpreter : public Interpreter
+{
+public:
+ PythonInterpreter()
+ {
+ _language = "Python";
+ _context = 0;
+ //Py_Initialize();
+ }
+
+ virtual ~PythonInterpreter()
+ {
+ //Py_Finalize();
+ }
+
+ void setContext(bContext *C)
+ {
+ _context = C;
+ }
+
+ int interpretFile(const string& filename)
+ {
+ initPath();
+
+ ReportList *reports = CTX_wm_reports(_context);
+ BKE_reports_clear(reports);
+ char *fn = const_cast<char*>(filename.c_str());
+#if 0
+ int status = BPY_filepath_exec(_context, fn, reports);
+#else
+ int status;
+ Text *text = BKE_text_load(fn, G.main->name);
+ if (text) {
+ status = BPY_text_exec(_context, text, reports, false);
+ BKE_text_unlink(G.main, text);
+ BKE_libblock_free(&G.main->text, text);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR, "Cannot open file: %s", fn);
+ status = 0;
+ }
+#endif
+
+ if (status != 1) {
+ cerr << "\nError executing Python script from PythonInterpreter::interpretFile" << endl;
+ cerr << "File: " << fn << endl;
+ cerr << "Errors: " << endl;
+ BKE_reports_print(reports, RPT_ERROR);
+ return 1;
+ }
+
+ // cleaning up
+ BKE_reports_clear(reports);
+
+ return 0;
+ }
+
+ int interpretText(struct Text *text, const string& name) {
+ initPath();
+
+ ReportList *reports = CTX_wm_reports(_context);
+
+ BKE_reports_clear(reports);
+
+ if (!BPY_text_exec(_context, text, reports, false)) {
+ cerr << "\nError executing Python script from PythonInterpreter::interpretText" << endl;
+ cerr << "Name: " << name << endl;
+ cerr << "Errors: " << endl;
+ BKE_reports_print(reports, RPT_ERROR);
+ return 1;
+ }
+
+ BKE_reports_clear(reports);
+
+ return 0;
+ }
+
+ struct Options
+ {
+ static void setPythonPath(const string& path)
+ {
+ _path = path;
+ }
+
+ static string getPythonPath()
+ {
+ return _path;
+ }
+ };
+
+ void reset()
+ {
+ Py_Finalize();
+ Py_Initialize();
+ _initialized = false;
+ }
+
+private:
+ bContext *_context;
+
+ void initPath()
+ {
+ if (_initialized)
+ return;
+
+ vector<string> pathnames;
+ StringUtils::getPathName(_path, "", pathnames);
+
+ struct Text *text = BKE_text_add("tmp_freestyle_initpath.txt");
+ string cmd = "import sys\n";
+ txt_insert_buf(text, const_cast<char*>(cmd.c_str()));
+
+ for (vector<string>::const_iterator it = pathnames.begin(); it != pathnames.end(); ++it) {
+ if (!it->empty()) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Adding Python path: " << *it << endl;
+ }
+ cmd = "sys.path.append(r\"" + *it + "\")\n";
+ txt_insert_buf(text, const_cast<char *>(cmd.c_str()));
+ }
+ }
+
+ BPY_text_exec(_context, text, NULL, false);
+
+ // cleaning up
+ BKE_text_unlink(G.main, text);
+ BKE_libblock_free(&G.main->text, text);
+
+ //PyRun_SimpleString("from Freestyle import *");
+ _initialized = true;
+ }
+
+ static bool _initialized;
+ static string _path;
+};
+
+#endif // __FREESTYLE_PYTHON_INTERPRETER_H__
diff --git a/source/blender/freestyle/intern/system/RandGen.cpp b/source/blender/freestyle/intern/system/RandGen.cpp
new file mode 100644
index 00000000000..193df1b4239
--- /dev/null
+++ b/source/blender/freestyle/intern/system/RandGen.cpp
@@ -0,0 +1,132 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/system/RandGen.cpp
+ * \ingroup freestyle
+ * \brief Pseudo-random number generator
+ * \author Fredo Durand
+ * \date 20/05/2003
+ */
+
+#include "RandGen.h"
+
+//
+// Macro definitions
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#define N 16
+#define MASK ((unsigned)(1 << (N - 1)) + (1 << (N - 1)) - 1)
+#define X0 0x330E
+#define X1 0xABCD
+#define X2 0x1234
+#define A0 0xE66D
+#define A1 0xDEEC
+#define A2 0x5
+#define C 0xB
+#define HI_BIT (1L << (2 * N - 1))
+
+#define LOW(x) ((unsigned)(x) & MASK)
+#define HIGH(x) LOW((x) >> N)
+
+#define MUL(x, y, z) \
+ { \
+ long l = (long)(x) * (long)(y); \
+ (z)[0] = LOW(l); \
+ (z)[1] = HIGH(l); \
+ }
+
+#define CARRY(x, y) ((unsigned long)((long)(x) + (long)(y)) > MASK)
+#define ADDEQU(x, y, z) (z = CARRY(x, (y)), x = LOW(x + (y)))
+#define SET3(x, x0, x1, x2) ((x)[0] = (x0), (x)[1] = (x1), (x)[2] = (x2))
+#define SETLOW(x, y, n) SET3(x, LOW((y)[n]), LOW((y)[(n)+1]), LOW((y)[(n)+2]))
+#define SEED(x0, x1, x2) (SET3(x, x0, x1, x2), SET3(a, A0, A1, A2), c = C)
+
+#define REST(v) \
+ for (i = 0; i < 3; i++) { \
+ xsubi[i] = x[i]; \
+ x[i] = temp[i]; \
+ } \
+ return (v); \
+ (void) 0
+
+#define NEST(TYPE, f, F) \
+ TYPE f(register unsigned short *xsubi) { \
+ register int i; \
+ register TYPE v; \
+ unsigned temp[3]; \
+ for (i = 0; i < 3; i++) { \
+ temp[i] = x[i]; \
+ x[i] = LOW(xsubi[i]); \
+ } \
+ v = F(); \
+ REST(v); \
+ }
+
+static unsigned x[3] = {
+ X0,
+ X1,
+ X2
+};
+static unsigned a[3] = {
+ A0,
+ A1,
+ A2
+};
+static unsigned c = C;
+
+//
+// Methods implementation
+//
+///////////////////////////////////////////////////////////////////////////////
+
+real RandGen::drand48()
+{
+ static real two16m = 1.0 / (1L << N);
+ next();
+ return (two16m * (two16m * (two16m * x[0] + x[1]) + x[2]));
+}
+
+void RandGen::srand48(long seedval)
+{
+ SEED(X0, LOW(seedval), HIGH(seedval));
+}
+
+void RandGen::next()
+{
+ unsigned p[2], q[2], r[2], carry0, carry1;
+
+ MUL(a[0], x[0], p);
+ ADDEQU(p[0], c, carry0);
+ ADDEQU(p[1], carry0, carry1);
+ MUL(a[0], x[1], q);
+ ADDEQU(p[1], q[0], carry0);
+ MUL(a[1], x[0], r);
+ x[2] = LOW(carry0 + carry1 + CARRY(p[1], r[0]) + q[1] + r[1] + a[0] * x[2] + a[1] * x[1] + a[2] * x[0]);
+ x[1] = LOW(p[1] + r[0]);
+ x[0] = LOW(p[0]);
+}
diff --git a/source/blender/freestyle/intern/system/RandGen.h b/source/blender/freestyle/intern/system/RandGen.h
new file mode 100644
index 00000000000..914b405d7f3
--- /dev/null
+++ b/source/blender/freestyle/intern/system/RandGen.h
@@ -0,0 +1,54 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_RAND_GEN_H__
+#define __FREESTYLE_RAND_GEN_H__
+
+/** \file blender/freestyle/intern/system/RandGen.h
+ * \ingroup freestyle
+ * \brief Pseudo-random number generator
+ * \author Fredo Durand
+ * \date 20/05/2003
+ */
+
+// TODO Check whether we could replace this with BLI rand stuff...
+
+#include "FreestyleConfig.h"
+
+#include "../system/Precision.h"
+
+class LIB_SYSTEM_EXPORT RandGen
+{
+public:
+ static real drand48();
+ static void srand48(long value);
+
+private:
+ static void next();
+};
+
+#endif // __FREESTYLE_RAND_GEN_H__
diff --git a/source/blender/freestyle/intern/system/RenderMonitor.h b/source/blender/freestyle/intern/system/RenderMonitor.h
new file mode 100644
index 00000000000..bd50e0c5392
--- /dev/null
+++ b/source/blender/freestyle/intern/system/RenderMonitor.h
@@ -0,0 +1,63 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_RENDER_MONITOR_H__
+#define __FREESTYLE_RENDER_MONITOR_H__
+
+/** \file blender/freestyle/intern/system/BaseIterator.h
+ * \ingroup freestyle
+ * \brief Classes defining the basic "Iterator" design pattern
+ * \author Stephane Grabli
+ * \date 18/03/2003
+ */
+
+extern "C" {
+
+#include "render_types.h"
+
+}
+
+class RenderMonitor
+{
+public:
+ inline RenderMonitor(Render *re)
+ {
+ _re = re;
+ }
+
+ virtual ~RenderMonitor() {}
+
+ inline bool testBreak()
+ {
+ return _re && _re->test_break(_re->tbh);
+ }
+
+protected:
+ Render *_re;
+};
+
+#endif // __FREESTYLE_RENDER_MONITOR_H__
diff --git a/source/blender/freestyle/intern/system/StringUtils.cpp b/source/blender/freestyle/intern/system/StringUtils.cpp
new file mode 100644
index 00000000000..ee06d3d1f4b
--- /dev/null
+++ b/source/blender/freestyle/intern/system/StringUtils.cpp
@@ -0,0 +1,89 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/system/StringUtils.cpp
+ * \ingroup freestyle
+ * \brief String utilities
+ * \author Emmanuel Turquin
+ * \date 20/05/2003
+ */
+
+//soc #include <qfileinfo.h>
+
+#include "FreestyleConfig.h"
+#include "StringUtils.h"
+
+namespace StringUtils {
+
+void getPathName(const string& path, const string& base, vector<string>& pathnames)
+{
+ string dir;
+ string res;
+ char cleaned[FILE_MAX];
+ unsigned size = path.size();
+
+ pathnames.push_back(base);
+
+ for (unsigned int pos = 0, sep = path.find(Config::PATH_SEP, pos);
+ pos < size;
+ pos = sep + 1, sep = path.find(Config::PATH_SEP, pos))
+ {
+ if (sep == (unsigned)string::npos)
+ sep = size;
+
+ dir = path.substr(pos, sep - pos);
+
+ BLI_strncpy(cleaned, dir.c_str(), FILE_MAX);
+ BLI_cleanup_file(NULL, cleaned);
+ res = toAscii(string(cleaned));
+
+ if (!base.empty())
+ res += Config::DIR_SEP + base;
+
+ pathnames.push_back(res);
+ }
+}
+
+string toAscii(const string &str)
+{
+ stringstream out("");
+ char s;
+
+ for (unsigned int i = 0; i < str.size() ; i++) {
+ s = ((char)(str.at(i) & 0x7F));
+ out << s;
+ }
+
+ return out.str();
+}
+
+const char *toAscii(const char *str)
+{
+ return toAscii(string(str)).c_str();
+}
+
+} // end of namespace StringUtils
diff --git a/source/blender/freestyle/intern/system/StringUtils.h b/source/blender/freestyle/intern/system/StringUtils.h
new file mode 100644
index 00000000000..d8970da0dce
--- /dev/null
+++ b/source/blender/freestyle/intern/system/StringUtils.h
@@ -0,0 +1,75 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_STRING_UTILS_H__
+#define __FREESTYLE_STRING_UTILS_H__
+
+/** \file blender/freestyle/intern/system/StringUtils.h
+ * \ingroup freestyle
+ * \brief String utilities
+ * \author Emmanuel Turquin
+ * \date 20/05/2003
+ */
+
+#include <cstring>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "FreestyleConfig.h"
+
+//soc
+extern "C" {
+
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+
+}
+
+using namespace std;
+
+namespace StringUtils {
+
+LIB_SYSTEM_EXPORT
+void getPathName(const string& path, const string& base, vector<string>& pathnames);
+string toAscii(const string &str);
+const char *toAscii(const char *str);
+
+// STL related
+struct ltstr
+{
+ bool operator()(const char *s1, const char *s2) const
+ {
+ return strcmp(s1, s2) < 0;
+ }
+};
+
+} // end of namespace StringUtils
+
+#endif // __FREESTYLE_STRING_UTILS_H__
diff --git a/source/blender/freestyle/intern/system/TimeStamp.cpp b/source/blender/freestyle/intern/system/TimeStamp.cpp
new file mode 100644
index 00000000000..6a7f0b00b79
--- /dev/null
+++ b/source/blender/freestyle/intern/system/TimeStamp.cpp
@@ -0,0 +1,38 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/system/TimeStamp.cpp
+ * \ingroup freestyle
+ * \brief Class defining a singleton used as timestamp
+ * \author Stephane Grabli
+ * \date 12/12/2002
+ */
+
+#include "TimeStamp.h"
+
+LIB_SYSTEM_EXPORT
+TimeStamp *TimeStamp::_instance = 0;
diff --git a/source/blender/freestyle/intern/system/TimeStamp.h b/source/blender/freestyle/intern/system/TimeStamp.h
new file mode 100644
index 00000000000..6f9bb3d4e44
--- /dev/null
+++ b/source/blender/freestyle/intern/system/TimeStamp.h
@@ -0,0 +1,78 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_TIME_STAMP_H__
+#define __FREESTYLE_TIME_STAMP_H__
+
+/** \file blender/freestyle/intern/system/TimeStamp.h
+ * \ingroup freestyle
+ * \brief Class defining a singleton used as timestamp
+ * \author Stephane Grabli
+ * \date 12/12/2002
+ */
+
+#include "FreestyleConfig.h"
+
+class LIB_SYSTEM_EXPORT TimeStamp
+{
+public:
+ static inline TimeStamp *instance()
+ {
+ if (_instance == NULL)
+ _instance = new TimeStamp;
+ return _instance;
+ }
+
+ inline unsigned getTimeStamp() const
+ {
+ return _time_stamp;
+ }
+
+ inline void increment()
+ {
+ ++_time_stamp;
+ }
+
+ inline void reset()
+ {
+ _time_stamp = 1;
+ }
+
+protected:
+ TimeStamp()
+ {
+ _time_stamp = 1;
+ }
+
+ TimeStamp(const TimeStamp&) {}
+
+private:
+ static TimeStamp *_instance;
+ unsigned _time_stamp;
+};
+
+#endif // __FREESTYLE_TIME_STAMP_H__
diff --git a/source/blender/freestyle/intern/system/TimeUtils.h b/source/blender/freestyle/intern/system/TimeUtils.h
new file mode 100644
index 00000000000..d42813dd560
--- /dev/null
+++ b/source/blender/freestyle/intern/system/TimeUtils.h
@@ -0,0 +1,64 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_TIME_UTILS_H__
+#define __FREESTYLE_TIME_UTILS_H__
+
+/** \file blender/freestyle/intern/system/TimeUtils.h
+ * \ingroup freestyle
+ * \brief Class to measure ellapsed time
+ * \author Stephane Grabli
+ * \date 10/04/2002
+ */
+
+#include <time.h>
+
+#include "FreestyleConfig.h"
+
+class Chronometer
+{
+public:
+ inline Chronometer() {}
+ inline ~Chronometer() {}
+
+ inline clock_t start()
+ {
+ _start = clock();
+ return _start;
+ }
+
+ inline double stop()
+ {
+ clock_t stop = clock();
+ return (double)(stop - _start) / CLOCKS_PER_SEC;
+ }
+
+private:
+ clock_t _start;
+};
+
+#endif // __FREESTYLE_TIME_UTILS_H__
diff --git a/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp b/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp
new file mode 100644
index 00000000000..24cef37f381
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp
@@ -0,0 +1,124 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.cpp
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2011-2-5
+ */
+
+#include "ArbitraryGridDensityProvider.h"
+
+#include "BKE_global.h"
+
+ArbitraryGridDensityProvider::ArbitraryGridDensityProvider(OccluderSource& source, const real proscenium[4],
+ unsigned numCells)
+: GridDensityProvider(source), numCells(numCells)
+{
+ initialize (proscenium);
+}
+
+ArbitraryGridDensityProvider::ArbitraryGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform, unsigned numCells)
+: GridDensityProvider(source), numCells(numCells)
+{
+ real proscenium[4];
+ calculateQuickProscenium(transform, bbox, proscenium);
+
+ initialize (proscenium);
+}
+
+ArbitraryGridDensityProvider::ArbitraryGridDensityProvider(OccluderSource& source, unsigned numCells)
+: GridDensityProvider(source), numCells(numCells)
+{
+ real proscenium[4];
+ calculateOptimalProscenium(source, proscenium);
+
+ initialize (proscenium);
+}
+
+ArbitraryGridDensityProvider::~ArbitraryGridDensityProvider() {}
+
+void ArbitraryGridDensityProvider::initialize(const real proscenium[4])
+{
+ float prosceniumWidth = (proscenium[1] - proscenium[0]);
+ float prosceniumHeight = (proscenium[3] - proscenium[2]);
+ real cellArea = prosceniumWidth * prosceniumHeight / numCells;
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << prosceniumWidth << " x " << prosceniumHeight << " grid with cells of area " << cellArea << "." << endl;
+ }
+
+ _cellSize = sqrt(cellArea);
+ // Now we know how many cells make each side of our grid
+ _cellsX = ceil(prosceniumWidth / _cellSize);
+ _cellsY = ceil(prosceniumHeight / _cellSize);
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << _cellsX << "x" << _cellsY << " cells of size " << _cellSize << " square." << endl;
+ }
+
+ // Make sure the grid exceeds the proscenium by a small amount
+ float safetyZone = 0.1f;
+ if (_cellsX * _cellSize < prosceniumWidth * (1.0 + safetyZone)) {
+ _cellsX = prosceniumWidth * (1.0 + safetyZone) / _cellSize;
+ }
+ if (_cellsY * _cellSize < prosceniumHeight * (1.0 + safetyZone)) {
+ _cellsY = prosceniumHeight * (1.0 + safetyZone) / _cellSize;
+ }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << _cellsX << "x" << _cellsY << " cells of size " << _cellSize << " square." << endl;
+ }
+
+ // Find grid origin
+ _cellOrigin[0] = ((proscenium[0] + proscenium[1]) / 2.0) - (_cellsX / 2.0) * _cellSize;
+ _cellOrigin[1] = ((proscenium[2] + proscenium[3]) / 2.0) - (_cellsY / 2.0) * _cellSize;
+}
+
+ArbitraryGridDensityProviderFactory::ArbitraryGridDensityProviderFactory(unsigned numCells)
+: numCells(numCells)
+{
+}
+
+ArbitraryGridDensityProviderFactory::~ArbitraryGridDensityProviderFactory() {}
+
+auto_ptr<GridDensityProvider> ArbitraryGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source,
+ const real proscenium[4])
+{
+ return auto_ptr<GridDensityProvider>(new ArbitraryGridDensityProvider(source, proscenium, numCells));
+}
+
+auto_ptr<GridDensityProvider>
+ArbitraryGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform)
+{
+ return auto_ptr<GridDensityProvider>(new ArbitraryGridDensityProvider(source, bbox, transform, numCells));
+}
+
+auto_ptr<GridDensityProvider> ArbitraryGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source)
+{
+ return auto_ptr<GridDensityProvider>(new ArbitraryGridDensityProvider(source, numCells));
+}
diff --git a/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.h b/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.h
new file mode 100644
index 00000000000..f8d43f19936
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.h
@@ -0,0 +1,75 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_ARBITRARY_GRID_DENSITY_PROVIDER_H__
+#define __FREESTYLE_ARBITRARY_GRID_DENSITY_PROVIDER_H__
+
+/** \file blender/freestyle/intern/view_map/ArbitraryGridDensityProvider.h
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2011-2-5
+ */
+
+#include "GridDensityProvider.h"
+
+class ArbitraryGridDensityProvider : public GridDensityProvider
+{
+ // Disallow copying and assignment
+ ArbitraryGridDensityProvider(const ArbitraryGridDensityProvider& other);
+ ArbitraryGridDensityProvider& operator=(const ArbitraryGridDensityProvider& other);
+
+public:
+ ArbitraryGridDensityProvider(OccluderSource& source, const real proscenium[4], unsigned numCells);
+ ArbitraryGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform, unsigned numCells);
+ ArbitraryGridDensityProvider(OccluderSource& source, unsigned numCells);
+ virtual ~ArbitraryGridDensityProvider();
+
+protected:
+ unsigned numCells;
+
+private:
+ void initialize (const real proscenium[4]);
+};
+
+class ArbitraryGridDensityProviderFactory : public GridDensityProviderFactory
+{
+public:
+ ArbitraryGridDensityProviderFactory(unsigned numCells);
+ ~ArbitraryGridDensityProviderFactory();
+
+ auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]);
+ auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform);
+ auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source);
+
+protected:
+ unsigned numCells;
+};
+
+#endif // __FREESTYLE_ARBITRARY_GRID_DENSITY_PROVIDER_H__
diff --git a/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp b/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp
new file mode 100644
index 00000000000..d293ed8189f
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp
@@ -0,0 +1,138 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.cpp
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2011-2-9
+ */
+
+#include "AverageAreaGridDensityProvider.h"
+
+#include "BKE_global.h"
+
+AverageAreaGridDensityProvider::AverageAreaGridDensityProvider(OccluderSource& source, const real proscenium[4],
+ real sizeFactor)
+: GridDensityProvider(source)
+{
+ initialize (proscenium, sizeFactor);
+}
+
+AverageAreaGridDensityProvider::AverageAreaGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform, real sizeFactor)
+: GridDensityProvider(source)
+{
+ real proscenium[4];
+ calculateQuickProscenium(transform, bbox, proscenium);
+
+ initialize(proscenium, sizeFactor);
+}
+
+AverageAreaGridDensityProvider::AverageAreaGridDensityProvider(OccluderSource& source, real sizeFactor)
+: GridDensityProvider(source)
+{
+ real proscenium[4];
+ calculateOptimalProscenium(source, proscenium);
+
+ initialize(proscenium, sizeFactor);
+}
+
+AverageAreaGridDensityProvider::~AverageAreaGridDensityProvider() {}
+
+void AverageAreaGridDensityProvider::initialize(const real proscenium[4], real sizeFactor)
+{
+ float prosceniumWidth = (proscenium[1] - proscenium[0]);
+ float prosceniumHeight = (proscenium[3] - proscenium[2]);
+
+ real cellArea = 0.0;
+ unsigned numFaces = 0;
+ for (source.begin(); source.isValid(); source.next()) {
+ Polygon3r& poly(source.getGridSpacePolygon());
+ Vec3r min, max;
+ poly.getBBox(min, max);
+ cellArea += (max[0] - min[0]) * (max[1] - min[1]);
+ ++numFaces;
+ }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Total area: " << cellArea << ". Number of faces: " << numFaces << "." << endl;
+ }
+ cellArea /= numFaces;
+ cellArea *= sizeFactor;
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Building grid with average area " << cellArea << endl;
+ }
+
+ _cellSize = sqrt(cellArea);
+ // Now we know how many cells make each side of our grid
+ _cellsX = ceil(prosceniumWidth / _cellSize);
+ _cellsY = ceil(prosceniumHeight / _cellSize);
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << _cellsX << "x" << _cellsY << " cells of size " << _cellSize << " square." << endl;
+ }
+
+ // Make sure the grid exceeds the proscenium by a small amount
+ float safetyZone = 0.1f;
+ if (_cellsX * _cellSize < prosceniumWidth * (1.0 + safetyZone)) {
+ _cellsX = prosceniumWidth * (1.0 + safetyZone) / _cellSize;
+ }
+ if (_cellsY * _cellSize < prosceniumHeight * (1.0 + safetyZone)) {
+ _cellsY = prosceniumHeight * (1.0 + safetyZone) / _cellSize;
+ }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << _cellsX << "x" << _cellsY << " cells of size " << _cellSize << " square." << endl;
+ }
+
+ // Find grid origin
+ _cellOrigin[0] = ((proscenium[0] + proscenium[1]) / 2.0) - (_cellsX / 2.0) * _cellSize;
+ _cellOrigin[1] = ((proscenium[2] + proscenium[3]) / 2.0) - (_cellsY / 2.0) * _cellSize;
+}
+
+AverageAreaGridDensityProviderFactory::AverageAreaGridDensityProviderFactory(real sizeFactor)
+: sizeFactor(sizeFactor)
+{
+}
+
+AverageAreaGridDensityProviderFactory::~AverageAreaGridDensityProviderFactory() {}
+
+auto_ptr<GridDensityProvider>
+AverageAreaGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const real proscenium[4])
+{
+ return auto_ptr<GridDensityProvider>(new AverageAreaGridDensityProvider(source, proscenium, sizeFactor));
+}
+
+auto_ptr<GridDensityProvider>
+AverageAreaGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform)
+{
+ return auto_ptr<GridDensityProvider>(new AverageAreaGridDensityProvider(source, bbox, transform, sizeFactor));
+}
+
+auto_ptr<GridDensityProvider> AverageAreaGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source)
+{
+ return auto_ptr<GridDensityProvider>(new AverageAreaGridDensityProvider(source, sizeFactor));
+}
diff --git a/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.h b/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.h
new file mode 100644
index 00000000000..05d2ae1ed9d
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.h
@@ -0,0 +1,72 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_AVERAGE_AREA_GRID_DENSITY_PROVIDER_H__
+#define __FREESTYLE_AVERAGE_AREA_GRID_DENSITY_PROVIDER_H__
+
+/** \file blender/freestyle/intern/view_map/AverageAreaGridDensityProvider.h
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2011-2-9
+ */
+
+#include "GridDensityProvider.h"
+
+class AverageAreaGridDensityProvider : public GridDensityProvider
+{
+ // Disallow copying and assignment
+ AverageAreaGridDensityProvider(const AverageAreaGridDensityProvider& other);
+ AverageAreaGridDensityProvider& operator=(const AverageAreaGridDensityProvider& other);
+
+public:
+ AverageAreaGridDensityProvider(OccluderSource& source, const real proscenium[4], real sizeFactor);
+ AverageAreaGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform, real sizeFactor);
+ AverageAreaGridDensityProvider(OccluderSource& source, real sizeFactor);
+ virtual ~AverageAreaGridDensityProvider();
+
+private:
+ void initialize (const real proscenium[4], real sizeFactor);
+};
+
+class AverageAreaGridDensityProviderFactory : public GridDensityProviderFactory
+{
+public:
+ AverageAreaGridDensityProviderFactory(real sizeFactor);
+ ~AverageAreaGridDensityProviderFactory();
+
+ auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]);
+ auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform);
+ auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source);
+
+protected:
+ real sizeFactor;
+};
+
+#endif // __FREESTYLE_AVERAGE_AREA_GRID_DENSITY_PROVIDER_H__
diff --git a/source/blender/freestyle/intern/view_map/BoxGrid.cpp b/source/blender/freestyle/intern/view_map/BoxGrid.cpp
new file mode 100644
index 00000000000..c83ab44a259
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/BoxGrid.cpp
@@ -0,0 +1,241 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/BoxGrid.cpp
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2011-1-29
+ */
+
+#include <algorithm>
+#include <stdexcept>
+
+#include "BoxGrid.h"
+
+#include "BKE_global.h"
+
+using namespace std;
+
+// Helper Classes
+
+// OccluderData
+///////////////
+
+// Cell
+/////////
+
+BoxGrid::Cell::Cell() {}
+
+BoxGrid::Cell::~Cell() {}
+
+void BoxGrid::Cell::setDimensions(real x, real y, real sizeX, real sizeY)
+{
+ const real epsilon = 1.0e-06;
+ boundary[0] = x - epsilon;
+ boundary[1] = x + sizeX + epsilon;
+ boundary[2] = y - epsilon;
+ boundary[3] = y + sizeY + epsilon;
+}
+
+bool BoxGrid::Cell::compareOccludersByShallowestPoint(const BoxGrid::OccluderData *a, const BoxGrid::OccluderData *b)
+{
+ return a->shallowest < b->shallowest;
+}
+
+void BoxGrid::Cell::indexPolygons()
+{
+ // Sort occluders by their shallowest points.
+ sort(faces.begin(), faces.end(), compareOccludersByShallowestPoint);
+}
+
+// Iterator
+//////////////////
+
+BoxGrid::Iterator::Iterator (BoxGrid& grid, Vec3r& center, real epsilon)
+: _target(grid.transform(center)), _foundOccludee(false)
+{
+ // Find target cell
+ _cell = grid.findCell(_target);
+ #if BOX_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Searching for occluders of edge centered at " << _target << " in cell ["
+ << _cell->boundary[0] << ", " << _cell->boundary[1] << ", " << _cell->boundary[2]
+ << ", " << _cell->boundary[3] << "] (" << _cell->faces.size() << " occluders)" << endl;
+ }
+ #endif
+
+ // Set iterator
+ _current = _cell->faces.begin();
+}
+
+BoxGrid::Iterator::~Iterator() {}
+
+// BoxGrid
+/////////////////
+
+BoxGrid::BoxGrid(OccluderSource& source, GridDensityProvider& density, ViewMap *viewMap, Vec3r& viewpoint,
+ bool enableQI)
+: _viewpoint(viewpoint), _enableQI(enableQI)
+{
+ // Generate Cell structure
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Generate Cell structure" << endl;
+ }
+ assignCells(source, density, viewMap);
+
+ // Fill Cells
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Distribute occluders" << endl;
+ }
+ distributePolygons(source);
+
+ // Reorganize Cells
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Reorganize cells" << endl;
+ }
+ reorganizeCells();
+
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Ready to use BoxGrid" << endl;
+ }
+}
+
+BoxGrid::~BoxGrid() {}
+
+void BoxGrid::assignCells (OccluderSource& source, GridDensityProvider& density, ViewMap *viewMap)
+{
+ _cellSize = density.cellSize();
+ _cellsX = density.cellsX();
+ _cellsY = density.cellsY();
+ _cellOrigin[0] = density.cellOrigin(0);
+ _cellOrigin[1] = density.cellOrigin(1);
+
+ // Now allocate the cell table and fill it with default (empty) cells
+ _cells.resize(_cellsX * _cellsY);
+ for (cellContainer::iterator i = _cells.begin(), end = _cells.end(); i != end; ++i) {
+ (*i) = NULL;
+ }
+
+ // Identify cells that will be used, and set the dimensions for each
+ ViewMap::fedges_container& fedges = viewMap->FEdges();
+ for (ViewMap::fedges_container::iterator f = fedges.begin(), fend = fedges.end(); f != fend; ++f) {
+ if ((*f)->isInImage()) {
+ Vec3r point = transform((*f)->center3d());
+ unsigned int i, j;
+ getCellCoordinates(point, i, j);
+ if (_cells[i * _cellsY + j] == NULL) {
+ // This is an uninitialized cell
+ real x, y, width, height;
+
+ x = _cellOrigin[0] + _cellSize * i;
+ width = _cellSize;
+
+ y = _cellOrigin[1] + _cellSize * j;
+ height = _cellSize;
+
+ // Initialize cell
+ Cell* b = _cells[i * _cellsY + j] = new Cell();
+ b->setDimensions(x, y, width, height);
+ }
+ }
+ }
+}
+
+void BoxGrid::distributePolygons(OccluderSource& source)
+{
+ unsigned long nFaces = 0;
+ unsigned long nKeptFaces = 0;
+
+ for (source.begin(); source.isValid(); source.next()) {
+ OccluderData *occluder = NULL;
+
+ try {
+ if (insertOccluder(source, occluder)) {
+ _faces.push_back(occluder);
+ ++nKeptFaces;
+ }
+ }
+ catch (...) {
+ // If an exception was thrown, _faces.push_back() cannot have succeeded.
+ // occluder is not owned by anyone, and must be deleted.
+ // If the exception was thrown before or during new OccluderData(), then
+ // occluder is NULL, and this delete is harmless.
+ delete occluder;
+ throw;
+ }
+ ++nFaces;
+ }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Distributed " << nFaces << " occluders. Retained " << nKeptFaces << "." << endl;
+ }
+}
+
+void BoxGrid::reorganizeCells()
+{
+ // Sort the occluders by shallowest point
+ for (vector<Cell*>::iterator i = _cells.begin(), end = _cells.end(); i != end; ++i) {
+ if (*i != NULL) {
+ (*i)->indexPolygons();
+ }
+ }
+}
+
+void BoxGrid::getCellCoordinates(const Vec3r& point, unsigned& x, unsigned& y)
+{
+ x = min(_cellsX - 1, (unsigned) floor (max((double) 0.0f, point[0] - _cellOrigin[0]) / _cellSize));
+ y = min(_cellsY - 1, (unsigned) floor (max((double) 0.0f, point[1] - _cellOrigin[1]) / _cellSize));
+}
+
+BoxGrid::Cell* BoxGrid::findCell(const Vec3r& point)
+{
+ unsigned int x, y;
+ getCellCoordinates(point, x, y);
+ return _cells[x * _cellsY + y];
+}
+
+bool BoxGrid::orthographicProjection() const
+{
+ return true;
+}
+
+const Vec3r& BoxGrid::viewpoint() const
+{
+ return _viewpoint;
+}
+
+bool BoxGrid::enableQI() const
+{
+ return _enableQI;
+}
+
+BoxGrid::Transform::Transform() : GridHelpers::Transform() {}
+
+Vec3r BoxGrid::Transform::operator()(const Vec3r& point) const
+{
+ return Vec3r(point[0], point[1], -point[2]);
+}
diff --git a/source/blender/freestyle/intern/view_map/BoxGrid.h b/source/blender/freestyle/intern/view_map/BoxGrid.h
new file mode 100644
index 00000000000..50ca1622e99
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/BoxGrid.h
@@ -0,0 +1,417 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_BOX_GRID_H__
+#define __FREESTYLE_BOX_GRID_H__
+
+/** \file blender/freestyle/intern/view_map/BoxGrid.h
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2011-1-29
+ */
+
+#define BOX_GRID_LOGGING FALSE
+
+// I would like to avoid using deque because including ViewMap.h and <deque> or <vector>
+// separately results in redefinitions of identifiers. ViewMap.h already includes <vector>
+// so it should be a safe fall-back.
+//#include <vector>
+//#include <deque>
+
+#include "GridDensityProvider.h"
+#include "OccluderSource.h"
+#include "ViewMap.h"
+
+#include "../geometry/BBox.h"
+#include "../geometry/GridHelpers.h"
+#include "../geometry/Polygon.h"
+
+#include "../system/PointerSequence.h"
+
+#include "../winged_edge/WEdge.h"
+
+#include "BKE_global.h"
+
+class BoxGrid
+{
+public:
+ // Helper classes
+ struct OccluderData
+ {
+ explicit OccluderData(OccluderSource& source, Polygon3r& p);
+ Polygon3r poly;
+ Polygon3r cameraSpacePolygon;
+ real shallowest, deepest;
+ // N.B. We could, of course, store face in poly's userdata member, like the old ViewMapBuilder code does.
+ // However, code comments make it clear that userdata is deprecated, so we avoid the temptation
+ // to save 4 or 8 bytes.
+ WFace* face;
+ };
+
+private:
+ struct Cell
+ {
+ // Can't store Cell in a vector without copy and assign
+ // Cell(const Cell& other);
+ // Cell& operator=(const Cell& other);
+
+ explicit Cell();
+ ~Cell();
+
+ static bool compareOccludersByShallowestPoint(const OccluderData *a, const OccluderData *b);
+
+ void setDimensions(real x, real y, real sizeX, real sizeY);
+ void checkAndInsert(OccluderSource& source, Polygon3r& poly, OccluderData*& occluder);
+ void indexPolygons();
+
+ real boundary[4];
+ //deque<OccluderData*> faces;
+ vector<OccluderData*> faces;
+ };
+
+public:
+ /* Iterator needs to allow the user to avoid full 3D comparison in two cases:
+ *
+ * (1) Where (*current)->deepest < target[2], where the occluder is unambiguously in front of the target point.
+ *
+ * (2) Where (*current)->shallowest > target[2], where the occluder is unambiguously in back of the target point.
+ *
+ * In addition, when used by OptimizedFindOccludee, Iterator should stop iterating as soon as it has an
+ * occludee candidate and (*current)->shallowest > candidate[2], because at that point forward no new occluder
+ * could possibly be a better occludee.
+ */
+ class Iterator
+ {
+ public:
+ // epsilon is not used in this class, but other grids with the same interface may need an epsilon
+ explicit Iterator(BoxGrid& grid, Vec3r& center, real epsilon = 1.0e-06);
+ ~Iterator();
+ void initBeforeTarget();
+ void initAfterTarget();
+ void nextOccluder();
+ void nextOccludee();
+ bool validBeforeTarget();
+ bool validAfterTarget();
+ WFace *getWFace() const;
+ Polygon3r *getCameraSpacePolygon();
+ void reportDepth(Vec3r origin, Vec3r u, real t);
+
+ private:
+ bool testOccluder(bool wantOccludee);
+ void markCurrentOccludeeCandidate(real depth);
+
+ Cell *_cell;
+ Vec3r _target;
+ bool _foundOccludee;
+ real _occludeeDepth;
+ //deque<OccluderData*>::iterator _current, _occludeeCandidate;
+ vector<OccluderData*>::iterator _current, _occludeeCandidate;
+ };
+
+ class Transform : public GridHelpers::Transform
+ {
+ public:
+ explicit Transform();
+ explicit Transform(Transform& other);
+ Vec3r operator()(const Vec3r& point) const;
+ };
+
+private:
+ // Prevent implicit copies and assignments.
+ BoxGrid(const BoxGrid& other);
+ BoxGrid& operator=(const BoxGrid& other);
+
+public:
+ explicit BoxGrid(OccluderSource& source, GridDensityProvider& density, ViewMap *viewMap, Vec3r& viewpoint,
+ bool enableQI);
+ virtual ~BoxGrid();
+
+ // Generate Cell structure
+ void assignCells(OccluderSource& source, GridDensityProvider& density, ViewMap *viewMap);
+ // Fill Cells
+ void distributePolygons(OccluderSource& source);
+ // Insert one polygon into each matching cell, return true if any cell consumes the polygon
+ bool insertOccluder(OccluderSource& source, OccluderData*& occluder);
+ // Sort occluders in each cell
+ void reorganizeCells();
+
+ Cell *findCell(const Vec3r& point);
+
+ // Accessors:
+ bool orthographicProjection() const;
+ const Vec3r& viewpoint() const;
+ bool enableQI() const;
+ Transform transform;
+
+private:
+ void getCellCoordinates(const Vec3r& point, unsigned& x, unsigned& y);
+
+ typedef PointerSequence<vector<Cell*>, Cell*> cellContainer;
+ //typedef PointerSequence<deque<OccluderData*>, OccluderData*> occluderContainer;
+ typedef PointerSequence<vector<OccluderData*>, OccluderData*> occluderContainer;
+ unsigned _cellsX, _cellsY;
+ float _cellSize;
+ float _cellOrigin[2];
+ cellContainer _cells;
+ occluderContainer _faces;
+ Vec3r _viewpoint;
+ bool _enableQI;
+};
+
+inline void BoxGrid::Iterator::initBeforeTarget()
+{
+ _current = _cell->faces.begin();
+ while (_current != _cell->faces.end() && !testOccluder(false)) {
+ ++_current;
+ }
+}
+
+inline void BoxGrid::Iterator::initAfterTarget()
+{
+ if (_foundOccludee) {
+ #if BOX_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\tStarting occludee search from occludeeCandidate at depth "
+ << _occludeeDepth << std::endl;
+ }
+ #endif
+ _current = _occludeeCandidate;
+ return;
+ }
+
+ #if BOX_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\tStarting occludee search from current position" << std::endl;
+ }
+ #endif
+
+ while (_current != _cell->faces.end() && !testOccluder(true)) {
+ ++_current;
+ }
+}
+
+inline bool BoxGrid::Iterator::testOccluder(bool wantOccludee)
+{
+ // End-of-list is not even a valid iterator position
+ if (_current == _cell->faces.end()) {
+ // Returning true seems strange, but it will break us out of whatever loop is calling testOccluder,
+ // and _current = _cell->face.end() will make the calling routine give up.
+ return true;
+ }
+ #if BOX_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\tTesting occluder " << (*_current)->poly.getVertices()[0];
+ for (unsigned int i = 1; i < (*_current)->poly.getVertices().size(); ++i) {
+ std::cout << ", " << (*_current)->poly.getVertices()[i];
+ }
+ std::cout << " from shape " << (*_current)->face->GetVertex(0)->shape()->GetId() << std::endl;
+ }
+ #endif
+
+ // If we have an occluder candidate and we are unambiguously after it, abort
+ if (_foundOccludee && (*_current)->shallowest > _occludeeDepth) {
+ #if BOX_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\t\tAborting: shallowest > occludeeCandidate->deepest" << std::endl;
+ }
+ #endif
+ _current = _cell->faces.end();
+
+ // See note above
+ return true;
+ }
+
+ // Specific continue or stop conditions when searching for each type
+ if (wantOccludee) {
+ if ((*_current)->deepest < _target[2]) {
+ #if BOX_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\t\tSkipping: shallower than target while looking for occludee" << std::endl;
+ }
+ #endif
+ return false;
+ }
+ }
+ else {
+ if ((*_current)->shallowest > _target[2]) {
+ #if BOX_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\t\tStopping: deeper than target while looking for occluder" << std::endl;
+ }
+ #endif
+ return true;
+ }
+ }
+
+ // Depthwise, this is a valid occluder.
+
+ // Check to see if target is in the 2D bounding box
+ Vec3r bbMin, bbMax;
+ (*_current)->poly.getBBox(bbMin, bbMax);
+ if (_target[0] < bbMin[0] || _target[0] > bbMax[0] || _target[1] < bbMin[1] || _target[1] > bbMax[1]) {
+ #if BOX_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\t\tSkipping: bounding box violation" << std::endl;
+ }
+ #endif
+ return false;
+ }
+
+ // We've done all the corner cutting we can.
+ // Let the caller work out whether or not the geometry is correct.
+ return true;
+}
+
+inline void BoxGrid::Iterator::reportDepth(Vec3r origin, Vec3r u, real t)
+{
+ // The reported depth is the length of a ray in camera space
+ // We need to convert it into a Z-value in grid space
+ real depth = -(origin + (u * t))[2];
+ #if BOX_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\t\tReporting depth of occluder/ee: " << depth;
+ }
+ #endif
+ if (depth > _target[2]) {
+ #if BOX_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << " is deeper than target" << std::endl;
+ }
+ #endif
+ // If the current occluder is the best occludee so far, save it.
+ if (! _foundOccludee || _occludeeDepth > depth) {
+ markCurrentOccludeeCandidate(depth);
+ }
+ }
+ else {
+ #if BOX_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << std::endl;
+ }
+ #endif
+ }
+}
+
+inline void BoxGrid::Iterator::nextOccluder()
+{
+ if (_current != _cell->faces.end()) {
+ do {
+ ++_current;
+ } while (_current != _cell->faces.end() && ! testOccluder(false));
+ }
+}
+
+inline void BoxGrid::Iterator::nextOccludee()
+{
+ if (_current != _cell->faces.end()) {
+ do {
+ ++_current;
+ } while (_current != _cell->faces.end() && ! testOccluder(true));
+ }
+}
+
+inline bool BoxGrid::Iterator::validBeforeTarget()
+{
+ return _current != _cell->faces.end() && (*_current)->shallowest <= _target[2];
+}
+
+inline bool BoxGrid::Iterator::validAfterTarget()
+{
+ return _current != _cell->faces.end();
+}
+
+inline void BoxGrid::Iterator::markCurrentOccludeeCandidate(real depth)
+{
+ #if BOX_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\t\tFound occludeeCandidate at depth " << depth << std::endl;
+ }
+ #endif
+ _occludeeCandidate = _current;
+ _occludeeDepth = depth;
+ _foundOccludee = true;
+}
+
+inline WFace* BoxGrid::Iterator::getWFace() const
+{
+ return (*_current)->face;
+}
+
+inline Polygon3r* BoxGrid::Iterator::getCameraSpacePolygon()
+{
+ return &((*_current)->cameraSpacePolygon);
+}
+
+inline BoxGrid::OccluderData::OccluderData(OccluderSource& source, Polygon3r& p)
+: poly(p),
+ cameraSpacePolygon(source.getCameraSpacePolygon()),
+ face(source.getWFace())
+{
+ // Set shallowest and deepest based on bbox
+ Vec3r min, max;
+ poly.getBBox(min, max);
+ shallowest = min[2];
+ deepest = max[2];
+}
+
+inline void BoxGrid::Cell::checkAndInsert(OccluderSource& source, Polygon3r& poly, OccluderData*& occluder)
+{
+ if (GridHelpers::insideProscenium (boundary, poly)) {
+ if (occluder == NULL) {
+ // Disposal of occluder will be handled in BoxGrid::distributePolygons(),
+ // or automatically by BoxGrid::_faces;
+ occluder = new OccluderData(source, poly);
+ }
+ faces.push_back(occluder);
+ }
+}
+
+inline bool BoxGrid::insertOccluder(OccluderSource& source, OccluderData*& occluder)
+{
+ Polygon3r& poly(source.getGridSpacePolygon());
+ occluder = NULL;
+
+ Vec3r bbMin, bbMax;
+ poly.getBBox(bbMin, bbMax);
+ // Check overlapping cells
+ unsigned startX, startY, endX, endY;
+ getCellCoordinates(bbMin, startX, startY);
+ getCellCoordinates(bbMax, endX, endY);
+
+ for (unsigned int i = startX; i <= endX; ++i) {
+ for (unsigned int j = startY; j <= endY; ++j) {
+ if (_cells[i * _cellsY + j] != NULL) {
+ _cells[i * _cellsY + j]->checkAndInsert(source, poly, occluder);
+ }
+ }
+ }
+
+ return occluder != NULL;
+}
+
+#endif // __FREESTYLE_BOX_GRID_H__
diff --git a/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp b/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp
new file mode 100644
index 00000000000..2c9a9def4fc
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/CulledOccluderSource.cpp
@@ -0,0 +1,287 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/CulledOccluderSource.cpp
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2010-12-21
+ */
+
+#include "CulledOccluderSource.h"
+
+#include "FRS_freestyle.h"
+
+#include "../geometry/GridHelpers.h"
+
+#include "BKE_global.h"
+
+CulledOccluderSource::CulledOccluderSource(const GridHelpers::Transform& t, WingedEdge& we, ViewMap& viewMap,
+ bool extensiveFEdgeSearch)
+: OccluderSource(t, we), rejected(0), gridSpaceOccluderProsceniumInitialized(false)
+{
+ cullViewEdges(viewMap, extensiveFEdgeSearch);
+
+ // If we have not found any visible FEdges during our cull, then there is nothing to iterate over.
+ // Short-circuit everything.
+ valid = gridSpaceOccluderProsceniumInitialized;
+
+ if (valid && ! testCurrent()) {
+ next();
+ }
+}
+
+CulledOccluderSource::~CulledOccluderSource() {}
+
+bool CulledOccluderSource::testCurrent()
+{
+ if (valid) {
+ // The test for gridSpaceOccluderProsceniumInitialized should not be necessary
+ return gridSpaceOccluderProsceniumInitialized &&
+ GridHelpers::insideProscenium(gridSpaceOccluderProscenium, cachedPolygon);
+ }
+ return false;
+}
+
+bool CulledOccluderSource::next()
+{
+ while (OccluderSource::next()) {
+ if (testCurrent()) {
+ ++rejected;
+ return true;
+ }
+ }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "Finished generating occluders. Rejected " << rejected << " faces." << std::endl;
+ }
+ return false;
+}
+
+void CulledOccluderSource::getOccluderProscenium(real proscenium[4])
+{
+ for (unsigned int i = 0; i < 4; ++i) {
+ proscenium[i] = gridSpaceOccluderProscenium[i];
+ }
+}
+
+static inline real distance2D(const Vec3r & point, const real origin[2])
+{
+ return ::hypot((point[0] - origin[0]), (point[1] - origin[1]));
+}
+
+static inline bool crossesProscenium(real proscenium[4], FEdge *fe)
+{
+ Vec2r min(proscenium[0], proscenium[2]);
+ Vec2r max(proscenium[1], proscenium[3]);
+ Vec2r A(fe->vertexA()->getProjectedX(), fe->vertexA()->getProjectedY());
+ Vec2r B(fe->vertexB()->getProjectedX(), fe->vertexB()->getProjectedY());
+
+ return GeomUtils::intersect2dSeg2dArea (min, max, A, B);
+}
+
+static inline bool insideProscenium(real proscenium[4], const Vec3r& point)
+{
+ return !(point[0] < proscenium[0] || point[0] > proscenium[1] ||
+ point[1] < proscenium[2] || point[1] > proscenium[3]);
+}
+
+void CulledOccluderSource::cullViewEdges(ViewMap& viewMap, bool extensiveFEdgeSearch)
+{
+ // Cull view edges by marking them as non-displayable.
+ // This avoids the complications of trying to delete edges from the ViewMap.
+
+ // Non-displayable view edges will be skipped over during visibility calculation.
+
+ // View edges will be culled according to their position w.r.t. the viewport proscenium (viewport + 5% border,
+ // or some such).
+
+ // Get proscenium boundary for culling
+ real viewProscenium[4];
+ GridHelpers::getDefaultViewProscenium(viewProscenium);
+ real prosceniumOrigin[2];
+ prosceniumOrigin[0] = (viewProscenium[1] - viewProscenium[0]) / 2.0;
+ prosceniumOrigin[1] = (viewProscenium[3] - viewProscenium[2]) / 2.0;
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Proscenium culling:" << endl;
+ cout << "Proscenium: [" << viewProscenium[0] << ", " << viewProscenium[1] << ", " << viewProscenium[2]
+ << ", " << viewProscenium[3] << "]"<< endl;
+ cout << "Origin: [" << prosceniumOrigin[0] << ", " << prosceniumOrigin[1] << "]"<< endl;
+ }
+
+ // A separate occluder proscenium will also be maintained, starting out the same as the viewport proscenium, and
+ // expanding as necessary so that it encompasses the center point of at least one feature edge in each
+ // retained view edge.
+ // The occluder proscenium will be used later to cull occluding triangles before they are inserted into the Grid.
+ // The occluder proscenium starts out the same size as the view proscenium
+ GridHelpers::getDefaultViewProscenium(occluderProscenium);
+
+ // XXX Freestyle is inconsistent in its use of ViewMap::viewedges_container and vector<ViewEdge*>::iterator.
+ // Probably all occurences of vector<ViewEdge*>::iterator should be replaced ViewMap::viewedges_container
+ // throughout the code.
+ // For each view edge
+ ViewMap::viewedges_container::iterator ve, veend;
+
+ for (ve = viewMap.ViewEdges().begin(), veend = viewMap.ViewEdges().end(); ve != veend; ve++) {
+ // Overview:
+ // Search for a visible feature edge
+ // If none: mark view edge as non-displayable
+ // Otherwise:
+ // Find a feature edge with center point inside occluder proscenium.
+ // If none exists, find the feature edge with center point closest to viewport origin.
+ // Expand occluder proscenium to enclose center point.
+
+ // For each feature edge, while bestOccluderTarget not found and view edge not visibile
+ bool bestOccluderTargetFound = false;
+ FEdge *bestOccluderTarget = NULL;
+ real bestOccluderDistance = 0.0;
+ FEdge *festart = (*ve)->fedgeA();
+ FEdge *fe = festart;
+ // All ViewEdges start culled
+ (*ve)->setIsInImage(false);
+
+ // For simple visibility calculation: mark a feature edge that is known to have a center point inside
+ // the occluder proscenium. Cull all other feature edges.
+ do {
+ // All FEdges start culled
+ fe->setIsInImage(false);
+
+ // Look for the visible edge that can most easily be included in the occluder proscenium.
+ if (!bestOccluderTargetFound) {
+ // If center point is inside occluder proscenium,
+ if (insideProscenium(occluderProscenium, fe->center2d())) {
+ // Use this feature edge for visibility deterimination
+ fe->setIsInImage(true);
+ expandGridSpaceOccluderProscenium(fe);
+ // Mark bestOccluderTarget as found
+ bestOccluderTargetFound = true;
+ bestOccluderTarget = fe;
+ }
+ else {
+ real d = distance2D(fe->center2d(), prosceniumOrigin);
+ // If center point is closer to viewport origin than current target
+ if (bestOccluderTarget == NULL || d < bestOccluderDistance) {
+ // Then store as bestOccluderTarget
+ bestOccluderDistance = d;
+ bestOccluderTarget = fe;
+ }
+ }
+ }
+
+ // If feature edge crosses the view proscenium
+ if (!(*ve)->isInImage() && crossesProscenium(viewProscenium, fe)) {
+ // Then the view edge will be included in the image
+ (*ve)->setIsInImage(true);
+ }
+ fe = fe->nextEdge();
+ } while (fe != NULL && fe != festart && !(bestOccluderTargetFound && (*ve)->isInImage()));
+
+ // Either we have run out of FEdges, or we already have the one edge we need to determine visibility
+ // Cull all remaining edges.
+ while (fe != NULL && fe != festart) {
+ fe->setIsInImage(false);
+ fe = fe->nextEdge();
+ }
+
+ // If bestOccluderTarget was not found inside the occluder proscenium,
+ // we need to expand the occluder proscenium to include it.
+ if ((*ve)->isInImage() && bestOccluderTarget != NULL && ! bestOccluderTargetFound) {
+ // Expand occluder proscenium to enclose bestOccluderTarget
+ Vec3r point = bestOccluderTarget->center2d();
+ if (point[0] < occluderProscenium[0]) {
+ occluderProscenium[0] = point[0];
+ }
+ else if (point[0] > occluderProscenium[1]) {
+ occluderProscenium[1] = point[0];
+ }
+ if (point[1] < occluderProscenium[2]) {
+ occluderProscenium[2] = point[1];
+ }
+ else if (point[1] > occluderProscenium[3]) {
+ occluderProscenium[3] = point[1];
+ }
+ // Use bestOccluderTarget for visibility determination
+ bestOccluderTarget->setIsInImage(true);
+ }
+ }
+
+ // We are done calculating the occluder proscenium.
+ // Expand the occluder proscenium by an epsilon to avoid rounding errors.
+ const real epsilon = 1.0e-6;
+ occluderProscenium[0] -= epsilon;
+ occluderProscenium[1] += epsilon;
+ occluderProscenium[2] -= epsilon;
+ occluderProscenium[3] += epsilon;
+
+ // For "Normal" or "Fast" style visibility computation only:
+
+ // For more detailed visibility calculation, make a second pass through the view map, marking all feature edges
+ // with center points inside the final occluder proscenium. All of these feature edges can be considered during
+ // visibility calculation.
+
+ // So far we have only found one FEdge per ViewEdge. The "Normal" and "Fast" styles of visibility computation
+ // want to consider many FEdges for each ViewEdge.
+ // Here we re-scan the view map to find any usable FEdges that we skipped on the first pass, or that have become
+ // usable because the occluder proscenium has been expanded since the edge was visited on the first pass.
+ if (extensiveFEdgeSearch) {
+ // For each view edge,
+ for (ve = viewMap.ViewEdges().begin(), veend = viewMap.ViewEdges().end(); ve != veend; ve++) {
+ if (!(*ve)->isInImage()) {
+ continue;
+ }
+ // For each feature edge,
+ FEdge *festart = (*ve)->fedgeA();
+ FEdge *fe = festart;
+ do {
+ // If not (already) visible and center point inside occluder proscenium,
+ if (!fe->isInImage() && insideProscenium(occluderProscenium, fe->center2d())) {
+ // Use the feature edge for visibility determination
+ fe->setIsInImage(true);
+ expandGridSpaceOccluderProscenium(fe);
+ }
+ fe = fe->nextEdge();
+ } while (fe != NULL && fe != festart);
+ }
+ }
+
+ // Up until now, all calculations have been done in camera space.
+ // However, the occluder source's iteration and the grid that consumes the occluders both work in gridspace,
+ // so we need a version of the occluder proscenium in gridspace.
+ // Set the gridspace occlude proscenium
+}
+
+void CulledOccluderSource::expandGridSpaceOccluderProscenium(FEdge *fe)
+{
+ if (gridSpaceOccluderProsceniumInitialized) {
+ GridHelpers::expandProscenium(gridSpaceOccluderProscenium, transform(fe->center3d()));
+ }
+ else {
+ const Vec3r& point = transform(fe->center3d());
+ gridSpaceOccluderProscenium[0] = gridSpaceOccluderProscenium[1] = point[0];
+ gridSpaceOccluderProscenium[2] = gridSpaceOccluderProscenium[3] = point[1];
+ gridSpaceOccluderProsceniumInitialized = true;
+ }
+}
diff --git a/source/blender/freestyle/intern/view_map/CulledOccluderSource.h b/source/blender/freestyle/intern/view_map/CulledOccluderSource.h
new file mode 100644
index 00000000000..a9c5484ca9c
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/CulledOccluderSource.h
@@ -0,0 +1,69 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_CULLED_OCCLUDER_SOURCE_H__
+#define __FREESTYLE_CULLED_OCCLUDER_SOURCE_H__
+
+/** \file blender/freestyle/intern/view_map/CulledOccluderSource.h
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2010-12-21
+ */
+
+#include "OccluderSource.h"
+#include "ViewMap.h"
+
+class CulledOccluderSource : public OccluderSource
+{
+ // Disallow copying and assignment
+ CulledOccluderSource(const CulledOccluderSource& other);
+ CulledOccluderSource& operator=(const CulledOccluderSource& other);
+
+public:
+ CulledOccluderSource(const GridHelpers::Transform& transform, WingedEdge& we, ViewMap& viewMap,
+ bool extensiveFEdgeSearch = true);
+ virtual ~CulledOccluderSource();
+
+ void cullViewEdges(ViewMap& viewMap, bool extensiveFEdgeSearch);
+
+ bool next();
+
+ void getOccluderProscenium(real proscenium[4]);
+
+private:
+ bool testCurrent();
+ void expandGridSpaceOccluderProscenium(FEdge *fe);
+
+ real occluderProscenium[4];
+ real gridSpaceOccluderProscenium[4];
+
+ unsigned long rejected;
+ bool gridSpaceOccluderProsceniumInitialized;
+};
+
+#endif // __FREESTYLE_CULLED_OCCLUDER_SOURCE_H__
diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
new file mode 100644
index 00000000000..2ded242e9ea
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
@@ -0,0 +1,761 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/FEdgeXDetector.cpp
+ * \ingroup freestyle
+ * \brief Detects/flags/builds extended features edges on the WXEdge structure
+ * \author Stephane Grabli
+ * \date 26/10/2003
+ */
+
+#include <float.h>
+#include <math.h>
+
+#include "FEdgeXDetector.h"
+
+#include "../geometry/GeomUtils.h"
+#include "../geometry/normal_cycle.h"
+
+#include "BKE_global.h"
+
+void FEdgeXDetector::processShapes(WingedEdge& we)
+{
+ bool progressBarDisplay = false;
+ Vec3r Min, Max;
+ vector<WShape*> wshapes = we.getWShapes();
+ WXShape *wxs;
+
+ if (_pProgressBar != NULL) {
+ _pProgressBar->reset();
+ _pProgressBar->setLabelText("Detecting feature lines");
+ _pProgressBar->setTotalSteps(wshapes.size() * 3);
+ _pProgressBar->setProgress(0);
+ progressBarDisplay = true;
+ }
+
+ for (vector<WShape*>::const_iterator it = wshapes.begin(); it != wshapes.end(); it++) {
+ if (_pRenderMonitor && _pRenderMonitor->testBreak())
+ break;
+ wxs = dynamic_cast<WXShape*>(*it);
+ wxs->bbox(Min, Max);
+ _bbox_diagonal = (Max - Min).norm();
+ if (_changes) {
+ vector<WFace*>& wfaces = wxs->GetFaceList();
+ for (vector<WFace*>::iterator wf = wfaces.begin(), wfend = wfaces.end(); wf != wfend; ++wf) {
+ WXFace *wxf = dynamic_cast<WXFace*>(*wf);
+ wxf->Clear();
+ }
+ _computeViewIndependant = true;
+ }
+ else if (!(wxs)->getComputeViewIndependantFlag()) {
+ wxs->Reset();
+ _computeViewIndependant = false;
+ }
+ else {
+ _computeViewIndependant = true;
+ }
+ preProcessShape(wxs);
+ if (progressBarDisplay)
+ _pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
+ processBorderShape(wxs);
+ if (_computeMaterialBoundaries)
+ processMaterialBoundaryShape(wxs);
+ processCreaseShape(wxs);
+ if (_computeRidgesAndValleys)
+ processRidgesAndValleysShape(wxs);
+ if (_computeSuggestiveContours)
+ processSuggestiveContourShape(wxs);
+ processSilhouetteShape(wxs);
+ processEdgeMarksShape(wxs);
+ if (progressBarDisplay)
+ _pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
+
+ // build smooth edges:
+ buildSmoothEdges(wxs);
+
+ // Post processing for suggestive contours
+ if (_computeSuggestiveContours)
+ postProcessSuggestiveContourShape(wxs);
+ if (progressBarDisplay)
+ _pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
+
+ wxs->setComputeViewIndependantFlag(false);
+ _computeViewIndependant = false;
+ _changes = false;
+
+ // reset user data
+ (*it)->ResetUserData();
+ }
+}
+
+// GENERAL STUFF
+////////////////
+void FEdgeXDetector::preProcessShape(WXShape *iWShape)
+{
+ _meanK1 = 0;
+ _meanKr = 0;
+ _minK1 = FLT_MAX;
+ _maxK1 = -FLT_MAX;
+ _minKr = FLT_MAX;
+ _maxKr = -FLT_MAX;
+ _nPoints = 0;
+ _meanEdgeSize = iWShape->getMeanEdgeSize();
+
+ vector<WFace*>& wfaces = iWShape->GetFaceList();
+ vector<WFace*>::iterator f, fend;
+ // view dependant stuff
+ for (f = wfaces.begin(), fend = wfaces.end(); f != fend; ++f) {
+ preProcessFace((WXFace*)(*f));
+ }
+
+ if (_computeRidgesAndValleys || _computeSuggestiveContours) {
+ vector<WVertex*>& wvertices = iWShape->getVertexList();
+ for (vector<WVertex*>::iterator wv = wvertices.begin(), wvend = wvertices.end(); wv != wvend; ++wv) {
+ // Compute curvatures
+ WXVertex *wxv = dynamic_cast<WXVertex*>(*wv);
+ computeCurvatures(wxv);
+ }
+ _meanK1 /= (real)(_nPoints);
+ _meanKr /= (real)(_nPoints);
+ }
+}
+
+void FEdgeXDetector::preProcessFace(WXFace *iFace)
+{
+ Vec3r firstPoint = iFace->GetVertex(0)->GetVertex();
+ Vec3r N = iFace->GetNormal();
+
+ // Compute the dot product between V (=_Viewpoint - firstPoint) and N:
+ Vec3r V;
+ if (_orthographicProjection) {
+ V = Vec3r(0.0, 0.0, _Viewpoint.z() - firstPoint.z());
+ }
+ else {
+ V = Vec3r(_Viewpoint - firstPoint);
+ }
+ N.normalize();
+ V.normalize();
+ iFace->setDotP(N * V);
+
+ // compute the distance between the face center and the viewpoint:
+ if (_orthographicProjection) {
+ iFace->setZ(iFace->center().z() - _Viewpoint.z());
+ }
+ else {
+ Vec3r dist_vec(iFace->center() - _Viewpoint);
+ iFace->setZ(dist_vec.norm());
+ }
+}
+
+void FEdgeXDetector::computeCurvatures(WXVertex *vertex)
+{
+ // TODO: for some reason, the 'vertex' may have no associated edges
+ // (i.e., WVertex::_EdgeList is empty), which causes a crash due to
+ // a subsequent call of WVertex::_EdgeList.front().
+ if (vertex->GetEdges().empty()) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("Warning: WVertex %d has no associated edges.\n", vertex->GetId());
+ }
+ return;
+ }
+
+ // CURVATURE LAYER
+ // store all the curvature datas for each vertex
+
+ //soc unused - real K1, K2
+ real cos2theta, sin2theta;
+ Vec3r e1, n, v;
+ // one vertex curvature info :
+ CurvatureInfo *C;
+ float radius = _sphereRadius * _meanEdgeSize;
+
+ // view independant stuff
+ if (_computeViewIndependant) {
+ C = new CurvatureInfo();
+ vertex->setCurvatures(C);
+ OGF::NormalCycle ncycle;
+ ncycle.begin();
+ if (radius > 0) {
+ OGF::compute_curvature_tensor(vertex, radius, ncycle);
+ }
+ else {
+ OGF::compute_curvature_tensor_one_ring(vertex, ncycle);
+ }
+ ncycle.end();
+ C->K1 = ncycle.kmin();
+ C->K2 = ncycle.kmax();
+ C->e1 = ncycle.Kmax(); //ncycle.kmin() * ncycle.Kmax();
+ C->e2 = ncycle.Kmin(); //ncycle.kmax() * ncycle.Kmin();
+
+ real absK1 = fabs(C->K1);
+ _meanK1 += absK1;
+ if (absK1 > _maxK1)
+ _maxK1 = absK1;
+ if (absK1 < _minK1)
+ _minK1 = absK1;
+ }
+ // view dependant
+ C = vertex->curvatures();
+ if (C == 0)
+ return;
+
+ // compute radial curvature :
+ n = C->e1 ^ C->e2;
+ if (_orthographicProjection) {
+ v = Vec3r(0.0, 0.0, _Viewpoint.z() - vertex->GetVertex().z());
+ }
+ else {
+ v = Vec3r(_Viewpoint - vertex->GetVertex());
+ }
+ C->er = v - (v * n) * n;
+ C->er.normalize();
+ e1 = C->e1;
+ e1.normalize();
+ cos2theta = C->er * e1;
+ cos2theta *= cos2theta;
+ sin2theta = 1 - cos2theta;
+ C->Kr = C->K1 * cos2theta + C->K2 * sin2theta;
+ real absKr = fabs(C->Kr);
+ _meanKr += absKr;
+ if (absKr > _maxKr)
+ _maxKr = absKr;
+ if (absKr < _minKr)
+ _minKr = absKr;
+
+ ++_nPoints;
+}
+
+// SILHOUETTE
+/////////////
+void FEdgeXDetector::processSilhouetteShape(WXShape *iWShape)
+{
+ // Make a first pass on every polygons in order to compute all their silhouette relative values:
+ vector<WFace*>& wfaces = iWShape->GetFaceList();
+ vector<WFace*>::iterator f, fend;
+ for (f = wfaces.begin(), fend = wfaces.end(); f != fend; ++f) {
+ ProcessSilhouetteFace((WXFace*)(*f));
+ }
+
+ // Make a pass on the edges to detect the silhouette edges that are not smooth
+ vector<WEdge*>::iterator we, weend;
+ vector<WEdge*> &wedges = iWShape->getEdgeList();
+ for (we = wedges.begin(), weend = wedges.end(); we != weend; ++we) {
+ ProcessSilhouetteEdge((WXEdge*)(*we));
+ }
+}
+
+void FEdgeXDetector::ProcessSilhouetteFace(WXFace *iFace)
+{
+ // SILHOUETTE LAYER
+ Vec3r normal;
+ // Compute the dot products between View direction and N at each vertex of the face:
+ Vec3r point;
+ int closestPointId = 0;
+ real dist, minDist = FLT_MAX;
+ int numVertices = iFace->numberOfVertices();
+ WXFaceLayer *faceLayer = new WXFaceLayer(iFace, Nature::SILHOUETTE, true);
+ for (int i = 0; i < numVertices; i++) {
+ point = iFace->GetVertex(i)->GetVertex();
+ normal = iFace->GetVertexNormal(i);
+ normal.normalize();
+ Vec3r V;
+ if (_orthographicProjection) {
+ V = Vec3r(0.0, 0.0, _Viewpoint.z() - point.z());
+ }
+ else {
+ V = Vec3r(_Viewpoint - point);
+ }
+ V.normalize();
+ real d = normal * V;
+ faceLayer->PushDotP(d);
+ // Find the point the closest to the viewpoint
+ if (_orthographicProjection) {
+ dist = point.z() - _Viewpoint.z();
+ }
+ else {
+ Vec3r dist_vec(point - _Viewpoint);
+ dist = dist_vec.norm();
+ }
+ if (dist < minDist) {
+ minDist = dist;
+ closestPointId = i;
+ }
+ }
+ // Set the closest point id:
+ faceLayer->setClosestPointIndex(closestPointId);
+ // Add this layer to the face:
+ iFace->AddSmoothLayer(faceLayer);
+}
+
+void FEdgeXDetector::ProcessSilhouetteEdge(WXEdge *iEdge)
+{
+ if (iEdge->nature() & Nature::BORDER)
+ return;
+ // SILHOUETTE ?
+ //-------------
+ WXFace *fA = (WXFace *)iEdge->GetaOEdge()->GetaFace();
+ WXFace *fB = (WXFace *)iEdge->GetaOEdge()->GetbFace();
+
+ if ((fA->front()) ^ (fB->front())) { // fA->visible XOR fB->visible (true if one is 0 and the other is 1)
+ // The only edges we want to set as silhouette edges in this way are the ones with 2 different normals for 1 vertex
+ // for these two faces
+ //--------------------
+ // In reality we only test the normals for 1 of the 2 vertices.
+ if (fA->GetVertexNormal(iEdge->GetaVertex()) == fB->GetVertexNormal(iEdge->GetaVertex()))
+ return;
+ iEdge->AddNature(Nature::SILHOUETTE);
+ if (fB->front())
+ iEdge->setOrder(1);
+ else
+ iEdge->setOrder(-1);
+ }
+}
+
+// BORDER
+/////////
+void FEdgeXDetector::processBorderShape(WXShape *iWShape)
+{
+ if (!_computeViewIndependant)
+ return;
+ // Make a pass on the edges to detect the BORDER
+ vector<WEdge*>::iterator we, weend;
+ vector<WEdge*> &wedges = iWShape->getEdgeList();
+ for (we = wedges.begin(), weend = wedges.end(); we != weend; ++we) {
+ ProcessBorderEdge((WXEdge *)(*we));
+ }
+}
+
+void FEdgeXDetector::ProcessBorderEdge(WXEdge *iEdge)
+{
+ // first check whether it is a border edge: BORDER ?
+ //---------
+ if (iEdge->GetaFace() == 0) {
+ // it is a border edge
+ iEdge->AddNature(Nature::BORDER);
+ }
+}
+
+
+// CREASE
+/////////
+void FEdgeXDetector::processCreaseShape(WXShape *iWShape)
+{
+ if (!_computeViewIndependant)
+ return;
+
+ // Make a pass on the edges to detect the CREASE
+ vector<WEdge*>::iterator we, weend;
+ vector<WEdge*> &wedges = iWShape->getEdgeList();
+ for (we = wedges.begin(), weend = wedges.end(); we != weend; ++we) {
+ ProcessCreaseEdge((WXEdge *)(*we));
+ }
+}
+
+void FEdgeXDetector::ProcessCreaseEdge(WXEdge *iEdge)
+{
+ // CREASE ?
+ //---------
+ if (iEdge->nature() & Nature::BORDER)
+ return;
+ WXFace *fA = (WXFace *)iEdge->GetaOEdge()->GetaFace();
+ WXFace *fB = (WXFace *)iEdge->GetaOEdge()->GetbFace();
+
+ WVertex *aVertex = iEdge->GetaVertex();
+ if ((fA->GetVertexNormal(aVertex) * fB->GetVertexNormal(aVertex)) <= _creaseAngle)
+ iEdge->AddNature(Nature::CREASE);
+}
+
+// RIDGES AND VALLEYS
+/////////////////////
+void FEdgeXDetector::processRidgesAndValleysShape(WXShape *iWShape)
+{
+ // Don't forget to add the built layer to the face at the end of the ProcessFace:
+ //iFace->AddSmoothLayer(faceLayer);
+
+ if (!_computeViewIndependant)
+ return;
+
+ // Here the curvatures must already have been computed
+ vector<WFace*>& wfaces = iWShape->GetFaceList();
+ vector<WFace*>::iterator f, fend;
+ for (f = wfaces.begin(), fend = wfaces.end(); f != fend; ++f) {
+ ProcessRidgeFace((WXFace*)(*f));
+ }
+}
+
+
+// RIDGES
+/////////
+void FEdgeXDetector::ProcessRidgeFace(WXFace *iFace)
+{
+ WXFaceLayer *flayer = new WXFaceLayer(iFace, Nature::RIDGE|Nature::VALLEY, false);
+ iFace->AddSmoothLayer(flayer);
+
+ unsigned int numVertices = iFace->numberOfVertices();
+ for (unsigned int i = 0; i < numVertices; ++i) {
+ WVertex *wv = iFace->GetVertex(i);
+ WXVertex *wxv = dynamic_cast<WXVertex*>(wv);
+ flayer->PushDotP(wxv->curvatures()->K1);
+ }
+
+ real threshold = 0;
+ //real threshold = _maxK1 - (_maxK1 - _meanK1) / 20.0;
+
+ if (flayer->nPosDotP() != numVertices) {
+ if ((fabs(flayer->dotP(0)) < threshold) && (fabs(flayer->dotP(1)) < threshold) &&
+ (fabs(flayer->dotP(2)) < threshold))
+ {
+ flayer->ReplaceDotP(0, 0);
+ flayer->ReplaceDotP(1, 0);
+ flayer->ReplaceDotP(2, 0);
+ }
+ }
+}
+
+#if 0
+void FEdgeXDetector::ProcessRidgeFace(WXFace *iFace)
+{
+ // RIDGE LAYER
+ // Compute the RidgeFunction, that is the derivative of the ppal curvature along e1 at each vertex of the face
+ WVertex *v;
+ Vec3r v1v2;
+ real t;
+ vector<WXFaceLayer*> SmoothLayers;
+ WXFaceLayer *faceLayer;
+ Face_Curvature_Info *layer_info;
+ real K1_a(0), K1_b(0);
+ Vec3r Inter_a, Inter_b;
+
+ // find the ridge layer of the face
+ iFace->retrieveSmoothLayers(Nature::RIDGE, SmoothLayers);
+ if ( SmoothLayers.size()!=1 )
+ return;
+ faceLayer = SmoothLayers[0];
+ // retrieve the curvature info of this layer
+ layer_info = (Face_Curvature_Info *)faceLayer->userdata;
+
+ int numVertices = iFace->numberOfVertices();
+ for (int i = 0; i < numVertices; i++) {
+ v = iFace->GetVertex(i);
+ // vec_curvature_info[i] contains the curvature info of this vertex
+ Vec3r e2 = layer_info->vec_curvature_info[i]->K2*layer_info->vec_curvature_info[i]->e2;
+ Vec3r e1 = layer_info->vec_curvature_info[i]->K1*layer_info->vec_curvature_info[i]->e1;
+ e2.normalize();
+
+ WVertex::face_iterator fit = v->faces_begin();
+ WVertex::face_iterator fitend = v->faces_end();
+ for (; fit != fitend; ++fit) {
+ WXFace *wxf = dynamic_cast<WXFace*>(*fit);
+ WOEdge *oppositeEdge;
+ if (!(wxf->getOppositeEdge(v, oppositeEdge)))
+ continue;
+ v1v2 = oppositeEdge->GetbVertex()->GetVertex() - oppositeEdge->GetaVertex()->GetVertex();
+ GeomUtils::intersection_test res;
+ res = GeomUtils::intersectRayPlane(oppositeEdge->GetaVertex()->GetVertex(), v1v2, e2, -(v->GetVertex()*e2),
+ t, 1.0e-06);
+ if ((res == GeomUtils::DO_INTERSECT) && (t >= 0.0) && (t <= 1.0)) {
+ vector<WXFaceLayer*> second_ridge_layer;
+ wxf->retrieveSmoothLayers(Nature::RIDGE, second_ridge_layer);
+ if (second_ridge_layer.size() != 1)
+ continue;
+ Face_Curvature_Info *second_layer_info = (Face_Curvature_Info*)second_ridge_layer[0]->userdata;
+
+ unsigned index1 = wxf->GetIndex(oppositeEdge->GetaVertex());
+ unsigned index2 = wxf->GetIndex(oppositeEdge->GetbVertex());
+ real K1_1 = second_layer_info->vec_curvature_info[index1]->K1;
+ real K1_2 = second_layer_info->vec_curvature_info[index2]->K1;
+ real K1 = (1.0 - t) * K1_1 + t * K1_2;
+ Vec3r inter((1.0 - t) * oppositeEdge->GetaVertex()->GetVertex() +
+ t * oppositeEdge->GetbVertex()->GetVertex());
+ Vec3r vtmp(inter - v->GetVertex());
+ // is it K1_a or K1_b ?
+ if (vtmp * e1 > 0) {
+ K1_b = K1;
+ Inter_b = inter;
+ }
+ else {
+ K1_a = K1;
+ Inter_a = inter;
+ }
+ }
+ }
+ // Once we have K1 along the the ppal direction compute the derivative : K1b - K1a put it in DotP
+ //real d = fabs(K1_b) - fabs(K1_a);
+ real d = 0;
+ real threshold = _meanK1 + (_maxK1 - _meanK1) / 7.0;
+ //real threshold = _meanK1;
+ //if ((fabs(K1_b) > threshold) || ((fabs(K1_a) > threshold)))
+ d = (K1_b) - (K1_a) / (Inter_b - Inter_a).norm();
+ faceLayer->PushDotP(d);
+ //faceLayer->PushDotP(layer_info->vec_curvature_info[i]->K1);
+ }
+
+ // Make the values relevant by checking whether all principal directions have the "same" direction:
+ Vec3r e0((layer_info->vec_curvature_info[0]->K1 * layer_info->vec_curvature_info[0]->e1));
+ e0.normalize();
+ Vec3r e1((layer_info->vec_curvature_info[1]->K1 * layer_info->vec_curvature_info[1]->e1));
+ e1.normalize();
+ Vec3r e2((layer_info->vec_curvature_info[2]->K1 * layer_info->vec_curvature_info[2]->e1));
+ e2.normalize();
+ if (e0 * e1 < 0)
+ // invert dotP[1]
+ faceLayer->ReplaceDotP(1, -faceLayer->dotP(1));
+ if (e0 * e2 < 0)
+ // invert dotP[2]
+ faceLayer->ReplaceDotP(2, -faceLayer->dotP(2));
+
+#if 0 // remove the weakest values;
+ real minDiff = (_maxK1 - _minK1) / 10.0;
+ real minDiff = _meanK1;
+ if ((faceLayer->dotP(0) < minDiff) && (faceLayer->dotP(1) < minDiff) && (faceLayer->dotP(2) < minDiff)) {
+ faceLayer->ReplaceDotP(0, 0);
+ faceLayer->ReplaceDotP(1, 0);
+ faceLayer->ReplaceDotP(2, 0);
+ }
+#endif
+}
+#endif
+
+// SUGGESTIVE CONTOURS
+//////////////////////
+
+void FEdgeXDetector::processSuggestiveContourShape(WXShape *iWShape)
+{
+ // Here the curvatures must already have been computed
+ vector<WFace*>& wfaces = iWShape->GetFaceList();
+ vector<WFace*>::iterator f, fend;
+ for (f = wfaces.begin(), fend = wfaces.end(); f != fend; ++f) {
+ ProcessSuggestiveContourFace((WXFace*)(*f));
+ }
+}
+
+void FEdgeXDetector::ProcessSuggestiveContourFace(WXFace *iFace)
+{
+ WXFaceLayer *faceLayer = new WXFaceLayer(iFace, Nature::SUGGESTIVE_CONTOUR, true);
+ iFace->AddSmoothLayer(faceLayer);
+
+ unsigned int numVertices = iFace->numberOfVertices();
+ for (unsigned int i = 0; i < numVertices; ++i) {
+ WVertex *wv = iFace->GetVertex(i);
+ WXVertex *wxv = dynamic_cast<WXVertex*>(wv);
+ faceLayer->PushDotP(wxv->curvatures()->Kr);
+ }
+
+#if 0 // FIXME: find a more clever way to compute the threshold
+ real threshold = _meanKr;
+ if (faceLayer->nPosDotP()!=numVertices) {
+ if ((fabs(faceLayer->dotP(0)) < threshold) && (fabs(faceLayer->dotP(1)) < threshold) &&
+ (fabs(faceLayer->dotP(2)) < threshold)) {
+ faceLayer->ReplaceDotP(0, 0);
+ faceLayer->ReplaceDotP(1, 0);
+ faceLayer->ReplaceDotP(2, 0);
+ }
+ }
+#endif
+}
+
+void FEdgeXDetector::postProcessSuggestiveContourShape(WXShape *iShape)
+{
+ vector<WFace*>& wfaces = iShape->GetFaceList();
+ vector<WFace*>::iterator f, fend;
+ for (f = wfaces.begin(), fend = wfaces.end(); f != fend; ++f) {
+ postProcessSuggestiveContourFace((WXFace*)(*f));
+ }
+}
+
+void FEdgeXDetector::postProcessSuggestiveContourFace(WXFace *iFace)
+{
+ // Compute the derivative of the radial curvature in the radial direction, at the two extremities of the smooth edge.
+ // If the derivative is smaller than a given threshold _kr_derivative_epsilon, discard the edge.
+
+ // Find the suggestive contour layer of the face (zero or one edge).
+ vector<WXFaceLayer*> sc_layers;
+ iFace->retrieveSmoothEdgesLayers(Nature::SUGGESTIVE_CONTOUR, sc_layers);
+ if (sc_layers.empty())
+ return;
+
+ WXFaceLayer *sc_layer;
+ sc_layer = sc_layers[0];
+
+ // Compute the derivative value at each vertex of the face, and add it in a vector.
+ vector<real> kr_derivatives;
+
+ unsigned vertices_nb = iFace->numberOfVertices();
+ WXVertex *v, *opposite_vertex_a, *opposite_vertex_b;
+ WXFace *wxf;
+ WOEdge *opposite_edge;
+ Vec3r normal_vec, radial_normal_vec, er_vec, v_vec, inter, inter1, inter2, tmp_vec;
+ GeomUtils::intersection_test res;
+ real kr(0), kr1(0), kr2(0), t;
+
+ for (unsigned int i = 0; i < vertices_nb; ++i) {
+ v = (WXVertex*)(iFace->GetVertex(i));
+
+ // v is a singular vertex, skip it.
+ if (v->isBoundary()) {
+ kr_derivatives.push_back(0);
+ continue;
+ }
+
+ v_vec = v->GetVertex();
+ er_vec = v->curvatures()->er;
+
+ // For each vertex, iterate on its adjacent faces.
+ for (WVertex::face_iterator fit = v->faces_begin(), fitend = v->faces_end(); fit != fitend; ++fit) {
+ wxf = dynamic_cast<WXFace*>(*fit);
+ if (!wxf->getOppositeEdge(v, opposite_edge))
+ continue;
+
+ opposite_vertex_a = (WXVertex *)opposite_edge->GetaVertex();
+ opposite_vertex_b = (WXVertex *)opposite_edge->GetbVertex();
+ normal_vec = wxf->GetVertexNormal(v); // FIXME: what about e1 ^ e2 ?
+ radial_normal_vec = er_vec ^ normal_vec;
+
+ // Test wether the radial plan intersects with the edge at the opposite of v.
+ res = GeomUtils::intersectRayPlane(opposite_vertex_a->GetVertex(), opposite_edge->GetVec(),
+ radial_normal_vec, -(v_vec * radial_normal_vec),
+ t, 1.0e-06);
+
+ // If there is an intersection, compute the value of the derivative ath that point.
+ if ((res == GeomUtils::DO_INTERSECT) && (t >= 0) && (t <= 1)) {
+ kr = t * opposite_vertex_a->curvatures()->Kr + (1 - t) * opposite_vertex_b->curvatures()->Kr;
+ inter = opposite_vertex_a->GetVertex() + t * opposite_edge->GetVec();
+ tmp_vec = inter - v->GetVertex();
+ // Is it kr1 or kr2?
+ if (tmp_vec * er_vec > 0) {
+ kr2 = kr;
+ inter2 = inter;
+ }
+ else {
+ kr1 = kr;
+ inter1 = inter;
+ }
+ }
+ }
+
+ // Now we have kr1 and kr2 along the radial direction, for one vertex of iFace.
+ // We have to compute the derivative of kr for that vertex, equal to:
+ // (kr2 - kr1) / dist(inter1, inter2).
+ // Then we add it to the vector of derivatives.
+ v->curvatures()->dKr = (kr2 - kr1) / (inter2 - inter1).norm();
+ kr_derivatives.push_back(v->curvatures()->dKr);
+ }
+
+ // At that point, we have the derivatives for each vertex of iFace.
+ // All we have to do now is to use linear interpolation to compute the values at the extremities of the smooth edge.
+ WXSmoothEdge *sc_edge = sc_layer->getSmoothEdge();
+ WOEdge *sc_oedge = sc_edge->woea();
+ t = sc_edge->ta();
+ if (t * kr_derivatives[iFace->GetIndex(sc_oedge->GetaVertex())] +
+ (1 - t) * kr_derivatives[iFace->GetIndex(sc_oedge->GetbVertex())] < _kr_derivative_epsilon)
+ {
+ sc_layer->removeSmoothEdge();
+ return;
+ }
+ sc_oedge = sc_edge->woeb();
+ t = sc_edge->tb();
+ if (t * kr_derivatives[iFace->GetIndex(sc_oedge->GetaVertex())] +
+ (1 - t) * kr_derivatives[iFace->GetIndex(sc_oedge->GetbVertex())] < _kr_derivative_epsilon)
+ {
+ sc_layer->removeSmoothEdge();
+ }
+}
+
+// MATERIAL_BOUNDARY
+////////////////////
+void FEdgeXDetector::processMaterialBoundaryShape(WXShape *iWShape)
+{
+ if (!_computeViewIndependant)
+ return;
+ // Make a pass on the edges to detect material boundaries
+ vector<WEdge*>::iterator we, weend;
+ vector<WEdge*> &wedges = iWShape->getEdgeList();
+ for (we = wedges.begin(), weend = wedges.end(); we != weend; ++we) {
+ ProcessMaterialBoundaryEdge((WXEdge*)(*we));
+ }
+}
+
+void FEdgeXDetector::ProcessMaterialBoundaryEdge(WXEdge *iEdge)
+{
+ // check whether the edge is a material boundary?
+ WFace *aFace = iEdge->GetaFace();
+ WFace *bFace = iEdge->GetbFace();
+ if (aFace && bFace && aFace->frs_materialIndex() != bFace->frs_materialIndex()) {
+ iEdge->AddNature(Nature::MATERIAL_BOUNDARY);
+ }
+}
+
+// EDGE MARKS
+/////////////
+void FEdgeXDetector::processEdgeMarksShape(WXShape *iShape)
+{
+ // Make a pass on the edges to detect material boundaries
+ vector<WEdge*>::iterator we, weend;
+ vector<WEdge*> &wedges = iShape->getEdgeList();
+ for (we = wedges.begin(), weend = wedges.end(); we != weend; ++we) {
+ ProcessEdgeMarks((WXEdge*)(*we));
+ }
+}
+
+void FEdgeXDetector::ProcessEdgeMarks(WXEdge *iEdge)
+{
+ if (iEdge->GetMark()) {
+ iEdge->AddNature(Nature::EDGE_MARK);
+ }
+}
+
+// Build Smooth edges
+/////////////////////
+void FEdgeXDetector::buildSmoothEdges(WXShape *iShape)
+{
+ bool hasSmoothEdges = false;
+
+ // Make a last pass to build smooth edges from the previous stored values:
+ //--------------------------------------------------------------------------
+ vector<WFace*>& wfaces = iShape->GetFaceList();
+ for (vector<WFace*>::iterator f = wfaces.begin(), fend = wfaces.end(); f != fend; ++f) {
+ vector<WXFaceLayer*>& faceLayers = ((WXFace*)(*f))->getSmoothLayers();
+ for (vector<WXFaceLayer*>::iterator wxfl = faceLayers.begin(), wxflend = faceLayers.end();
+ wxfl != wxflend;
+ ++wxfl)
+ {
+ if ((*wxfl)->BuildSmoothEdge())
+ hasSmoothEdges = true;
+ }
+ }
+
+ if (hasSmoothEdges && !_computeRidgesAndValleys && !_computeSuggestiveContours) {
+ vector<WVertex*>& wvertices = iShape->getVertexList();
+ for (vector<WVertex*>::iterator wv = wvertices.begin(), wvend = wvertices.end(); wv != wvend; ++wv) {
+ // Compute curvatures
+ WXVertex *wxv = dynamic_cast<WXVertex*>(*wv);
+ computeCurvatures(wxv);
+ }
+ _meanK1 /= (real)(_nPoints);
+ _meanKr /= (real)(_nPoints);
+ }
+}
diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.h b/source/blender/freestyle/intern/view_map/FEdgeXDetector.h
new file mode 100644
index 00000000000..1b211264402
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.h
@@ -0,0 +1,241 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_FEDGE_X_DETECTOR_H__
+#define __FREESTYLE_FEDGE_X_DETECTOR_H__
+
+/** \file blender/freestyle/intern/view_map/FEdgeXDetector.h
+ * \ingroup freestyle
+ * \brief Detects/flags/builds extended features edges on the WXEdge structure
+ * \author Stephane Grabli
+ * \date 26/10/2003
+ */
+
+#include <vector>
+
+#include "../geometry/Geom.h"
+
+#include "../system/FreestyleConfig.h"
+#include "../system/ProgressBar.h"
+#include "../system/RenderMonitor.h"
+
+#include "../winged_edge/Curvature.h"
+#include "../winged_edge/WXEdge.h"
+
+using namespace Geometry;
+
+/*! This class takes as input a WXEdge structure and fills it */
+class LIB_VIEW_MAP_EXPORT FEdgeXDetector
+{
+public:
+ FEdgeXDetector()
+ {
+ _pProgressBar = NULL;
+ _pRenderMonitor = NULL;
+ _computeViewIndependant = true;
+ _bbox_diagonal = 1.0;
+ _meanEdgeSize = 0;
+ _computeRidgesAndValleys = true;
+ _computeSuggestiveContours = true;
+ _computeMaterialBoundaries = true;
+ _sphereRadius = 1.0;
+ _orthographicProjection = false;
+ _faceSmoothness = false;
+ _changes = false;
+ _kr_derivative_epsilon = 0.0;
+ _creaseAngle = 0.7; // angle of 134.43 degrees
+ }
+
+ virtual ~FEdgeXDetector() {}
+
+ /*! Process shapes from a WingedEdge containing a list of WShapes */
+ virtual void processShapes(WingedEdge&);
+
+ // GENERAL STUFF
+ virtual void preProcessShape(WXShape *iShape);
+ virtual void preProcessFace(WXFace *iFace);
+ virtual void computeCurvatures(WXVertex *iVertex);
+
+ // SILHOUETTE
+ virtual void processSilhouetteShape(WXShape *iShape);
+ virtual void ProcessSilhouetteFace(WXFace *iFace);
+ virtual void ProcessSilhouetteEdge(WXEdge *iEdge);
+
+ // CREASE
+ virtual void processCreaseShape(WXShape *iShape);
+ virtual void ProcessCreaseEdge(WXEdge *iEdge);
+
+ /*! Sets the minimum angle for detecting crease edges
+ * \param angle
+ * The angular threshold in degrees (between 0 and 180) for detecting crease edges. An edge is considered
+ * a crease edge if the angle between two faces sharing the edge is smaller than the given threshold.
+ */
+ // XXX angle should be in radian...
+ inline void setCreaseAngle(real angle)
+ {
+ if (angle < 0.0)
+ angle = 0.0;
+ else if (angle > 180.0)
+ angle = 180.0;
+ angle = cos(M_PI * (180.0 - angle) / 180.0);
+ if (angle != _creaseAngle) {
+ _creaseAngle = angle;
+ _changes = true;
+ }
+ }
+
+ // BORDER
+ virtual void processBorderShape(WXShape *iShape);
+ virtual void ProcessBorderEdge(WXEdge *iEdge);
+
+ // RIDGES AND VALLEYS
+ virtual void processRidgesAndValleysShape(WXShape *iShape);
+ virtual void ProcessRidgeFace(WXFace *iFace);
+
+ // SUGGESTIVE CONTOURS
+ virtual void processSuggestiveContourShape(WXShape *iShape);
+ virtual void ProcessSuggestiveContourFace(WXFace *iFace);
+ virtual void postProcessSuggestiveContourShape(WXShape *iShape);
+ virtual void postProcessSuggestiveContourFace(WXFace *iFace);
+ /*! Sets the minimal derivative of the radial curvature for suggestive contours
+ * \param dkr
+ * The minimal derivative of the radial curvature
+ */
+ inline void setSuggestiveContourKrDerivativeEpsilon(real dkr)
+ {
+ if (dkr != _kr_derivative_epsilon) {
+ _kr_derivative_epsilon = dkr;
+ _changes = true;
+ }
+ }
+
+ // MATERIAL BOUNDARY
+ virtual void processMaterialBoundaryShape(WXShape *iWShape);
+ virtual void ProcessMaterialBoundaryEdge(WXEdge *iEdge);
+
+ // EDGE MARKS
+ virtual void processEdgeMarksShape(WXShape *iShape);
+ virtual void ProcessEdgeMarks(WXEdge *iEdge);
+
+ // EVERYBODY
+ virtual void buildSmoothEdges(WXShape *iShape);
+
+ /*! Sets the current viewpoint */
+ inline void setViewpoint(const Vec3r& ivp)
+ {
+ _Viewpoint = ivp;
+ }
+
+ inline void enableOrthographicProjection(bool b)
+ {
+ _orthographicProjection = b;
+ }
+
+ inline void enableRidgesAndValleysFlag(bool b)
+ {
+ _computeRidgesAndValleys = b;
+ }
+
+ inline void enableSuggestiveContours(bool b)
+ {
+ _computeSuggestiveContours = b;
+ }
+
+ inline void enableMaterialBoundaries(bool b)
+ {
+ _computeMaterialBoundaries = b;
+ }
+
+ inline void enableFaceSmoothness(bool b)
+ {
+ if (b != _faceSmoothness) {
+ _faceSmoothness = b;
+ _changes=true;
+ }
+ }
+
+ inline void enableFaceMarks(bool b)
+ {
+ if (b != _faceMarks) {
+ _faceMarks = b;
+ _changes=true;
+ }
+ }
+
+ /*! Sets the radius of the geodesic sphere around each vertex (for the curvature computation)
+ * \param r
+ * The radius of the sphere expressed as a ratio of the mean edge size
+ */
+ inline void setSphereRadius(real r)
+ {
+ if (r != _sphereRadius) {
+ _sphereRadius = r;
+ _changes=true;
+ }
+ }
+
+ inline void setProgressBar(ProgressBar *iProgressBar)
+ {
+ _pProgressBar = iProgressBar;
+ }
+
+ inline void setRenderMonitor(RenderMonitor *iRenderMonitor)
+ {
+ _pRenderMonitor = iRenderMonitor;
+ }
+
+protected:
+ Vec3r _Viewpoint;
+ real _bbox_diagonal; // diagonal of the current processed shape bbox
+ //oldtmp values
+ bool _computeViewIndependant;
+ real _meanK1;
+ real _meanKr;
+ real _minK1;
+ real _minKr;
+ real _maxK1;
+ real _maxKr;
+ unsigned _nPoints;
+ real _meanEdgeSize;
+ bool _orthographicProjection;
+
+ bool _computeRidgesAndValleys;
+ bool _computeSuggestiveContours;
+ bool _computeMaterialBoundaries;
+ bool _faceSmoothness;
+ bool _faceMarks;
+ real _sphereRadius; // expressed as a ratio of the mean edge size
+ real _creaseAngle; // [-1, 1] compared with the inner product of face normals
+ bool _changes;
+
+ real _kr_derivative_epsilon;
+
+ ProgressBar *_pProgressBar;
+ RenderMonitor *_pRenderMonitor;
+};
+
+#endif // __FREESTYLE_FEDGE_X_DETECTOR_H__
diff --git a/source/blender/freestyle/intern/view_map/Functions0D.cpp b/source/blender/freestyle/intern/view_map/Functions0D.cpp
new file mode 100644
index 00000000000..9e8557b0fd3
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/Functions0D.cpp
@@ -0,0 +1,376 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/Functions0D.cpp
+ * \ingroup freestyle
+ * \brief Functions taking 0D input
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include "Functions0D.h"
+#include "ViewMap.h"
+
+#include "BKE_global.h"
+
+using namespace std;
+
+namespace Functions0D {
+
+// Internal function
+FEdge *getFEdge(Interface0D& it1, Interface0D& it2)
+{
+ return it1.getFEdge(it2);
+}
+
+void getFEdges(Interface0DIterator& it, FEdge *&fe1, FEdge *&fe2)
+{
+ // count number of vertices
+ Interface0DIterator prev = it, next = it;
+ ++next;
+ int count = 1;
+ if (!it.isBegin() && !next.isEnd()) {
+ count = 3;
+ }
+ if (count < 3) {
+ // if we only have 2 vertices
+ FEdge *fe = 0;
+ Interface0DIterator tmp = it;
+ if (it.isBegin()) {
+ ++tmp;
+ fe = it->getFEdge(*tmp);
+ }
+ else {
+ --tmp;
+ fe = it->getFEdge(*tmp);
+ }
+ fe1 = fe;
+ fe2 = NULL;
+ }
+ else {
+ // we have more than 2 vertices
+ bool begin = false, last = false;
+ Interface0DIterator previous = it;
+ if (!previous.isBegin())
+ --previous;
+ else
+ begin = true;
+ Interface0DIterator next = it;
+ ++next;
+ if (next.isEnd())
+ last = true;
+ if (begin) {
+ fe1 = it->getFEdge(*next);
+ fe2 = NULL;
+ }
+ else if (last) {
+ fe1 = previous->getFEdge(*it);
+ fe2 = NULL;
+ }
+ else {
+ fe1 = previous->getFEdge(*it);
+ fe2 = it->getFEdge(*next);
+ }
+ }
+}
+
+void getViewEdges(Interface0DIterator &it, ViewEdge *&ve1, ViewEdge *&ve2)
+{
+ FEdge *fe1, *fe2;
+ getFEdges(it, fe1, fe2);
+ ve1 = fe1->viewedge();
+ if (fe2 != NULL) {
+ ve2 = fe2->viewedge();
+ if (ve2 == ve1)
+ ve2 = NULL;
+ }
+ else {
+ ve2 = NULL;
+ }
+}
+
+ViewShape *getShapeF0D(Interface0DIterator& it)
+{
+ ViewEdge *ve1, *ve2;
+ getViewEdges(it, ve1, ve2);
+ return ve1->viewShape();
+}
+
+void getOccludersF0D(Interface0DIterator& it, set<ViewShape*>& oOccluders)
+{
+ ViewEdge *ve1, *ve2;
+ getViewEdges(it, ve1, ve2);
+ occluder_container::const_iterator oit = ve1->occluders_begin();
+ occluder_container::const_iterator oitend = ve1->occluders_end();
+
+ for (; oit != oitend; ++oit)
+ oOccluders.insert((*oit));
+
+ if (ve2 != NULL) {
+ oit = ve2->occluders_begin();
+ oitend = ve2->occluders_end();
+ for (; oit != oitend; ++oit)
+ oOccluders.insert((*oit));
+ }
+}
+
+ViewShape *getOccludeeF0D(Interface0DIterator& it)
+{
+ ViewEdge *ve1, *ve2;
+ getViewEdges(it, ve1, ve2);
+ ViewShape *aShape = ve1->aShape();
+ return aShape;
+}
+
+//
+int VertexOrientation2DF0D::operator()(Interface0DIterator& iter)
+{
+ Vec2f A, C;
+ Vec2f B(iter->getProjectedX(), iter->getProjectedY());
+ if (iter.isBegin()) {
+ A = Vec2f(iter->getProjectedX(), iter->getProjectedY());
+ }
+ else {
+ Interface0DIterator previous = iter;
+ --previous ;
+ A = Vec2f(previous->getProjectedX(), previous->getProjectedY());
+ }
+ Interface0DIterator next = iter;
+ ++next;
+ if (next.isEnd())
+ C = Vec2f(iter->getProjectedX(), iter->getProjectedY());
+ else
+ C = Vec2f(next->getProjectedX(), next->getProjectedY());
+
+ Vec2f AB(B - A);
+ if (AB.norm() != 0)
+ AB.normalize();
+ Vec2f BC(C - B);
+ if (BC.norm() != 0)
+ BC.normalize();
+ result = AB + BC;
+ if (result.norm() != 0)
+ result.normalize();
+ return 0;
+}
+
+int VertexOrientation3DF0D::operator()(Interface0DIterator& iter)
+{
+ Vec3r A, C;
+ Vec3r B(iter->getX(), iter->getY(), iter->getZ());
+ if (iter.isBegin()) {
+ A = Vec3r(iter->getX(), iter->getY(), iter->getZ());
+ }
+ else {
+ Interface0DIterator previous = iter;
+ --previous ;
+ A = Vec3r(previous->getX(), previous->getY(), previous->getZ());
+ }
+ Interface0DIterator next = iter;
+ ++next ;
+ if (next.isEnd())
+ C = Vec3r(iter->getX(), iter->getY(), iter->getZ());
+ else
+ C = Vec3r(next->getX(), next->getY(), next->getZ());
+
+ Vec3r AB(B - A);
+ if (AB.norm() != 0)
+ AB.normalize();
+ Vec3r BC(C - B);
+ if (BC.norm() != 0)
+ BC.normalize();
+ result = AB + BC;
+ if (result.norm() != 0)
+ result.normalize();
+ return 0;
+}
+
+int Curvature2DAngleF0D::operator()(Interface0DIterator& iter)
+{
+ Interface0DIterator tmp1 = iter, tmp2 = iter;
+ ++tmp2;
+ unsigned count = 1;
+ while ((!tmp1.isBegin()) && (count < 3)) {
+ --tmp1;
+ ++count;
+ }
+ while ((!tmp2.isEnd()) && (count < 3)) {
+ ++tmp2;
+ ++count;
+ }
+ if (count < 3) {
+ // if we only have 2 vertices
+ result = 0;
+ return 0;
+ }
+
+ Interface0DIterator v = iter;
+ if (iter.isBegin())
+ ++v;
+ Interface0DIterator next = v;
+ ++next;
+ if (next.isEnd()) {
+ next = v;
+ --v;
+ }
+ Interface0DIterator prev = v;
+ --prev;
+
+ Vec2r A(prev->getProjectedX(), prev->getProjectedY());
+ Vec2r B(v->getProjectedX(), v->getProjectedY());
+ Vec2r C(next->getProjectedX(), next->getProjectedY());
+ Vec2r AB(B - A);
+ Vec2r BC(C - B);
+ Vec2r N1(-AB[1], AB[0]);
+ if (N1.norm() != 0)
+ N1.normalize();
+ Vec2r N2(-BC[1], BC[0]);
+ if (N2.norm() != 0)
+ N2.normalize();
+ if ((N1.norm() == 0) && (N2.norm() == 0)) {
+ Exception::raiseException();
+ result = 0;
+ return -1;
+ }
+ double cosin = N1 * N2;
+ if (cosin > 1)
+ cosin = 1;
+ if (cosin < -1)
+ cosin = -1;
+ result = acos(cosin);
+ return 0;
+}
+
+int ZDiscontinuityF0D::operator()(Interface0DIterator& iter)
+{
+ FEdge *fe1, *fe2;
+ getFEdges(iter, fe1, fe2);
+ result = fe1->z_discontinuity();
+ if (fe2 != NULL) {
+ result += fe2->z_discontinuity();
+ result /= 2.0f;
+ }
+ return 0;
+}
+
+int Normal2DF0D::operator()(Interface0DIterator& iter)
+{
+ FEdge *fe1, *fe2;
+ getFEdges(iter, fe1, fe2);
+ Vec3f e1(fe1->orientation2d());
+ Vec2f n1(e1[1], -e1[0]);
+ Vec2f n(n1);
+ if (fe2 != NULL) {
+ Vec3f e2(fe2->orientation2d());
+ Vec2f n2(e2[1], -e2[0]);
+ n += n2;
+ }
+ n.normalize();
+ result = n;
+ return 0;
+}
+
+int MaterialF0D::operator()(Interface0DIterator& iter)
+{
+ FEdge *fe1, *fe2;
+ getFEdges(iter, fe1, fe2);
+ if (fe1 == NULL)
+ return -1;
+ if (fe1->isSmooth())
+ result = ((FEdgeSmooth*)fe1)->frs_material();
+ else
+ result = ((FEdgeSharp*)fe1)->bFrsMaterial();
+#if 0
+ const SShape *sshape = getShapeF0D(iter);
+ return sshape->material();
+#endif
+ return 0;
+}
+
+int ShapeIdF0D::operator()(Interface0DIterator& iter)
+{
+ ViewShape *vshape = getShapeF0D(iter);
+ result = vshape->getId();
+ return 0;
+}
+
+int QuantitativeInvisibilityF0D::operator()(Interface0DIterator& iter)
+{
+ ViewEdge *ve1, *ve2;
+ getViewEdges(iter, ve1, ve2);
+ unsigned int qi1, qi2;
+ qi1 = ve1->qi();
+ if (ve2 != NULL) {
+ qi2 = ve2->qi();
+ if (qi2 != qi1) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "QuantitativeInvisibilityF0D: ambiguous evaluation for point " << iter->getId() << endl;
+ }
+ }
+ }
+ result = qi1;
+ return 0;
+}
+
+int CurveNatureF0D::operator()(Interface0DIterator& iter)
+{
+ Nature::EdgeNature nat = 0;
+ ViewEdge *ve1, *ve2;
+ getViewEdges(iter, ve1, ve2);
+ nat |= ve1->getNature();
+ if (ve2 != NULL)
+ nat |= ve2->getNature();
+ result = nat;
+ return 0;
+}
+
+int GetOccludersF0D::operator()(Interface0DIterator& iter)
+{
+ set<ViewShape*> occluders;
+ getOccludersF0D(iter, occluders);
+ result.clear();
+ //vsOccluders.insert(vsOccluders.begin(), occluders.begin(), occluders.end());
+ for (set<ViewShape*>::iterator it = occluders.begin(), itend = occluders.end(); it != itend; ++it) {
+ result.push_back((*it));
+ }
+ return 0;
+}
+
+int GetShapeF0D::operator()(Interface0DIterator& iter)
+{
+ result = getShapeF0D(iter);
+ return 0;
+}
+
+int GetOccludeeF0D::operator()(Interface0DIterator& iter)
+{
+ result = getOccludeeF0D(iter);
+ return 0;
+}
+
+} // end of namespace Functions0D
diff --git a/source/blender/freestyle/intern/view_map/Functions0D.h b/source/blender/freestyle/intern/view_map/Functions0D.h
new file mode 100644
index 00000000000..03ab008736c
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/Functions0D.h
@@ -0,0 +1,532 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_FUNCTIONS_0D_H__
+#define __FREESTYLE_FUNCTIONS_0D_H__
+
+/** \file blender/freestyle/intern/view_map/Functions0D.h
+ * \ingroup freestyle
+ * \brief Functions taking 0D input
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include <set>
+#include <vector>
+
+#include "Interface0D.h"
+
+#include "../geometry/Geom.h"
+
+#include "../python/Director.h"
+
+#include "../scene_graph/FrsMaterial.h"
+
+#include "../system/Exception.h"
+#include "../system/Precision.h"
+
+class FEdge;
+class ViewEdge;
+class SShape;
+
+using namespace Geometry;
+
+//
+// UnaryFunction0D (base class for functions in 0D)
+//
+///////////////////////////////////////////////////////////
+
+/*! Base class for Unary Functions (functors) working on Interface0DIterator.
+ * A unary function will be used by calling its operator() on an Interface0DIterator.
+ * \attention In the scripting language, there exists several prototypes depending on the returned value type.
+ * For example, you would inherit from a UnaryFunction0DDouble if you wish to define a function that returns a double.
+ * The different existing prototypes are:
+ * - UnaryFunction0DVoid
+ * - UnaryFunction0DUnsigned
+ * - UnaryFunction0DReal
+ * - UnaryFunction0DFloat
+ * - UnaryFunction0DDouble
+ * - UnaryFunction0DVec2f
+ * - UnaryFunction0DVec3f
+ */
+template <class T>
+class /*LIB_VIEW_MAP_EXPORT*/ UnaryFunction0D
+{
+public:
+ T result;
+ PyObject *py_uf0D;
+
+ /*! The type of the value returned by the functor. */
+ typedef T ReturnedValueType;
+
+ /*! Default constructor. */
+ UnaryFunction0D()
+ {
+ py_uf0D = NULL;
+ }
+
+ /*! Destructor; */
+ virtual ~UnaryFunction0D() {}
+
+ /*! Returns the string "UnaryFunction0D" */
+ virtual string getName() const
+ {
+ return "UnaryFunction0D";
+ }
+
+ /*! The operator ().
+ * \param iter
+ * An Interface0DIterator pointing onto the point at which we wish to evaluate the function.
+ * \return the result of the function of type T.
+ */
+ virtual int operator()(Interface0DIterator& iter)
+ {
+ return Director_BPy_UnaryFunction0D___call__(this, py_uf0D, iter);
+ }
+};
+
+#ifdef SWIG
+%feature("director") UnaryFunction0D<void>;
+%feature("director") UnaryFunction0D<unsigned>;
+%feature("director") UnaryFunction0D<float>;
+%feature("director") UnaryFunction0D<double>;
+%feature("director") UnaryFunction0D<Vec2f>;
+%feature("director") UnaryFunction0D<Vec3f>;
+%feature("director") UnaryFunction0D<Id>;
+
+%template(UnaryFunction0DVoid) UnaryFunction0D<void>;
+%template(UnaryFunction0DUnsigned) UnaryFunction0D<unsigned>;
+%template(UnaryFunction0DFloat) UnaryFunction0D<float>;
+%template(UnaryFunction0DDouble) UnaryFunction0D<double>;
+%template(UnaryFunction0DVec2f) UnaryFunction0D<Vec2f>;
+%template(UnaryFunction0DVec3f) UnaryFunction0D<Vec3f>;
+%template(UnaryFunction0DId) UnaryFunction0D<Id>;
+%template(UnaryFunction0DViewShape) UnaryFunction0D<ViewShape*>;
+%template(UnaryFunction0DVectorViewShape) UnaryFunction0D<std::vector<ViewShape*> >;
+#endif // SWIG
+
+//
+// Functions definitions
+//
+///////////////////////////////////////////////////////////
+class ViewShape;
+
+namespace Functions0D {
+
+// GetXF0D
+/*! Returns the X 3D coordinate of an Interface0D. */
+class LIB_VIEW_MAP_EXPORT GetXF0D : public UnaryFunction0D<real>
+{
+public:
+ /*! Returns the string "GetXF0D" */
+ string getName() const
+ {
+ return "GetXF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter)
+ {
+ result = iter->getX();
+ return 0;
+ }
+};
+
+// GetYF0D
+/*! Returns the Y 3D coordinate of an Interface0D. */
+class LIB_VIEW_MAP_EXPORT GetYF0D : public UnaryFunction0D<real>
+{
+public:
+ /*! Returns the string "GetYF0D" */
+ string getName() const
+ {
+ return "GetYF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter)
+ {
+ result = iter->getY();
+ return 0;
+ }
+};
+
+// GetZF0D
+/*! Returns the Z 3D coordinate of an Interface0D. */
+class LIB_VIEW_MAP_EXPORT GetZF0D : public UnaryFunction0D<real>
+{
+public:
+ /*! Returns the string "GetZF0D" */
+ string getName() const
+ {
+ return "GetZF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter)
+ {
+ result = iter->getZ();
+ return 0;
+ }
+};
+
+// GetProjectedXF0D
+/*! Returns the X 3D projected coordinate of an Interface0D. */
+class LIB_VIEW_MAP_EXPORT GetProjectedXF0D : public UnaryFunction0D<real>
+{
+public:
+ /*! Returns the string "GetProjectedXF0D" */
+ string getName() const
+ {
+ return "GetProjectedXF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter)
+ {
+ result = iter->getProjectedX();
+ return 0;
+ }
+};
+
+// GetProjectedYF0D
+/*! Returns the Y projected 3D coordinate of an Interface0D. */
+class LIB_VIEW_MAP_EXPORT GetProjectedYF0D : public UnaryFunction0D<real>
+{
+public:
+ /*! Returns the string "GetProjectedYF0D" */
+ string getName() const
+ {
+ return "GetProjectedYF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter)
+ {
+ result = iter->getProjectedY();
+ return 0;
+ }
+};
+
+// GetProjectedZF0D
+/*! Returns the Z projected 3D coordinate of an Interface0D. */
+class LIB_VIEW_MAP_EXPORT GetProjectedZF0D : public UnaryFunction0D<real>
+{
+public:
+ /*! Returns the string "GetProjectedZF0D" */
+ string getName() const
+ {
+ return "GetProjectedZF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter)
+ {
+ result = iter->getProjectedZ();
+ return 0;
+ }
+};
+
+// GetCurvilinearAbscissaF0D
+/*! Returns the curvilinear abscissa of an Interface0D in the context of its 1D element. */
+class LIB_VIEW_MAP_EXPORT GetCurvilinearAbscissaF0D : public UnaryFunction0D<float>
+{
+public:
+ /*! Returns the string "GetCurvilinearAbscissaF0D" */
+ string getName() const
+ {
+ return "GetCurvilinearAbscissaF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter)
+ {
+ result = iter.t();
+ return 0;
+ }
+};
+
+// GetParameterF0D
+/*! Returns the parameter of an Interface0D in the context of its 1D element. */
+class LIB_VIEW_MAP_EXPORT GetParameterF0D : public UnaryFunction0D<float>
+{
+public:
+ /*! Returns the string "GetCurvilinearAbscissaF0D" */
+ string getName() const
+ {
+ return "GetParameterF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter)
+ {
+ result = iter.u();
+ return 0;
+ }
+};
+
+// VertexOrientation2DF0D
+/*! Returns a Vec2r giving the 2D oriented tangent to the 1D element to which the Interface0DIterator& belongs to and
+ * evaluated at the Interface0D pointed by this Interface0DIterator&.
+ */
+class LIB_VIEW_MAP_EXPORT VertexOrientation2DF0D : public UnaryFunction0D<Vec2f>
+{
+public:
+ /*! Returns the string "VertexOrientation2DF0D" */
+ string getName() const
+ {
+ return "VertexOrientation2DF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// VertexOrientation3DF0D
+/*! Returns a Vec3r giving the 3D oriented tangent to the 1D element to which the Interface0DIterator& belongs to and
+ * evaluated at the Interface0D pointed by this Interface0DIterator&.
+ */
+class LIB_VIEW_MAP_EXPORT VertexOrientation3DF0D : public UnaryFunction0D<Vec3f>
+{
+public:
+ /*! Returns the string "VertexOrientation3DF0D" */
+ string getName() const
+ {
+ return "VertexOrientation3DF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// Curvature2DAngleF0D
+/*! Returns a real giving the 2D curvature (as an angle) of the 1D element to which the Interface0DIterator&
+ * belongs to and evaluated at the Interface0D pointed by this Interface0DIterator&.
+ */
+class LIB_VIEW_MAP_EXPORT Curvature2DAngleF0D : public UnaryFunction0D<real>
+{
+public:
+ /*! Returns the string "Curvature2DAngleF0D" */
+ string getName() const
+ {
+ return "Curvature2DAngleF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// ZDiscontinuity
+/*! Returns a real giving the distance between and Interface0D and the shape that lies behind (occludee).
+ * This distance is evaluated in the camera space and normalized between 0 and 1. Therefore, if no oject is occluded
+ * by the shape to which the Interface0D belongs to, 1 is returned.
+ */
+class LIB_VIEW_MAP_EXPORT ZDiscontinuityF0D : public UnaryFunction0D<real>
+{
+public:
+ /*! Returns the string "ZDiscontinuityF0D" */
+ string getName() const
+ {
+ return "ZDiscontinuityF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// Normal2DF0D
+/*! Returns a Vec2f giving the normalized 2D normal to the 1D element to which the Interface0DIterator& belongs to and
+ * evaluated at the Interface0D pointed by this Interface0DIterator&.
+ */
+class LIB_VIEW_MAP_EXPORT Normal2DF0D : public UnaryFunction0D<Vec2f>
+{
+public:
+ /*! Returns the string "Normal2DF0D" */
+ string getName() const
+ {
+ return "Normal2DF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// MaterialF0D
+/*! Returns the material of the object evaluated at the Interface0D.
+ * This evaluation can be ambiguous (in the case of a TVertex for example.
+ * This functor tries to remove this ambiguity using the context offered by the 1D element to which the
+ * Interface0DIterator& belongs to and by arbitrary chosing the material of the face that lies on its left when
+ * following the 1D element if there are two different materials on each side of the point.
+ * However, there still can be problematic cases, and the user willing to deal with this cases in a specific way
+ * should implement its own getMaterial functor.
+ */
+class LIB_VIEW_MAP_EXPORT MaterialF0D : public UnaryFunction0D<FrsMaterial>
+{
+public:
+ /*! Returns the string "MaterialF0D" */
+ string getName() const
+ {
+ return "MaterialF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// ShapeIdF0D
+/*! Returns the Id of the Shape the Interface0D belongs to.
+ * This evaluation can be ambiguous (in the case of a TVertex for example).
+ * This functor tries to remove this ambiguity using the context offered by the 1D element to which the
+ * Interface0DIterator& belongs to.
+ * However, there still can be problematic cases, and the user willing to deal with this cases in a specific way
+ * should implement its own getShapeIdF0D functor.
+ */
+class LIB_VIEW_MAP_EXPORT ShapeIdF0D : public UnaryFunction0D<Id>
+{
+public:
+ /*! Returns the string "ShapeIdF0D" */
+ string getName() const
+ {
+ return "ShapeIdF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// QiF0D
+/*! Returns the quantitative invisibility of this Interface0D.
+* This evaluation can be ambiguous (in the case of a TVertex for example).
+* This functor tries to remove this ambiguity using the context offered by the 1D element to which the
+* Interface0DIterator& belongs to.
+* However, there still can be problematic cases, and the user willing to deal with this cases in a specific way
+* should implement its own getQIF0D functor.
+*/
+class LIB_VIEW_MAP_EXPORT QuantitativeInvisibilityF0D : public UnaryFunction0D<unsigned int>
+{
+public:
+ /*! Returns the string "QuantitativeInvisibilityF0D" */
+ string getName() const
+ {
+ return "QuantitativeInvisibilityF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// CurveNatureF0D
+/*! Returns the Nature::EdgeNature of the 1D element the Interface0DIterator& belongs to. */
+class LIB_VIEW_MAP_EXPORT CurveNatureF0D : public UnaryFunction0D<Nature::EdgeNature>
+{
+public:
+ /*! Returns the string "QuantitativeInvisibilityF0D" */
+ string getName() const
+ {
+ return "CurveNatureF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// GetShapeF0D
+/*! Returns the ViewShape* containing the Interface0D */
+class LIB_VIEW_MAP_EXPORT GetShapeF0D : public UnaryFunction0D< ViewShape*>
+{
+public:
+ /*! Returns the string "GetShapeF0D" */
+ string getName() const
+ {
+ return "GetShapeF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// GetOccludersF0D
+/*! Returns a vector containing the ViewShape* occluding the Interface0D */
+class LIB_VIEW_MAP_EXPORT GetOccludersF0D : public UnaryFunction0D< std::vector<ViewShape*> >
+{
+public:
+ /*! Returns the string "GetOccludersF0D" */
+ string getName() const
+ {
+ return "GetOccludersF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+// GetOccludeeF0D
+/*! Returns the ViewShape* "occluded" by the Interface0D */
+class LIB_VIEW_MAP_EXPORT GetOccludeeF0D: public UnaryFunction0D< ViewShape*>
+{
+public:
+ /*! Returns the string "GetOccludeeF0D" */
+ string getName() const
+ {
+ return "GetOccludeeF0D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface0DIterator& iter);
+};
+
+
+/////////////////////////// Internal ////////////////////////////
+
+// getFEdge
+LIB_VIEW_MAP_EXPORT
+FEdge *getFEdge(Interface0D& it1, Interface0D& it2);
+
+// getFEdges
+LIB_VIEW_MAP_EXPORT
+void getFEdges(Interface0DIterator& it, FEdge *&fe1, FEdge *&fe2);
+
+// getViewEdges
+LIB_VIEW_MAP_EXPORT
+void getViewEdges(Interface0DIterator& it, ViewEdge *&ve1, ViewEdge *&ve2);
+
+// getShapeF0D
+LIB_VIEW_MAP_EXPORT
+ViewShape *getShapeF0D(Interface0DIterator& it);
+
+// getOccludersF0D
+LIB_VIEW_MAP_EXPORT
+void getOccludersF0D(Interface0DIterator& it, std::set<ViewShape*>& oOccluders);
+
+// getOccludeeF0D
+LIB_VIEW_MAP_EXPORT
+ViewShape *getOccludeeF0D(Interface0DIterator& it);
+
+} // end of namespace Functions0D
+
+#endif // __FREESTYLE_FUNCTIONS_0D_H__
diff --git a/source/blender/freestyle/intern/view_map/Functions1D.cpp b/source/blender/freestyle/intern/view_map/Functions1D.cpp
new file mode 100644
index 00000000000..f17a568ffee
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/Functions1D.cpp
@@ -0,0 +1,271 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/Functions1D.cpp
+ * \ingroup freestyle
+ * \brief Functions taking 1D input
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+# include "Functions1D.h"
+
+using namespace std;
+
+namespace Functions1D {
+
+int GetXF1D::operator()(Interface1D& inter)
+{
+ result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ return 0;
+}
+
+int GetYF1D::operator()(Interface1D& inter)
+{
+ result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ return 0;
+}
+
+int GetZF1D::operator()(Interface1D& inter)
+{
+ result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ return 0;
+}
+
+int GetProjectedXF1D::operator()(Interface1D& inter)
+{
+ result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ return 0;
+}
+
+int GetProjectedYF1D::operator()(Interface1D& inter)
+{
+ result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ return 0;
+}
+
+int GetProjectedZF1D::operator()(Interface1D& inter)
+{
+ result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ return 0;
+}
+
+int Orientation2DF1D::operator()(Interface1D& inter)
+{
+ FEdge *fe = dynamic_cast<FEdge*>(&inter);
+ if (fe) {
+ Vec3r res = fe->orientation2d();
+ result = Vec2f(res[0], res[1]);
+ }
+ else {
+ result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ }
+ return 0;
+}
+
+int Orientation3DF1D::operator()(Interface1D& inter)
+{
+ result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ return 0;
+}
+
+int ZDiscontinuityF1D::operator()(Interface1D& inter)
+{
+ result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ return 0;
+}
+
+int QuantitativeInvisibilityF1D::operator()(Interface1D& inter)
+{
+ ViewEdge *ve = dynamic_cast<ViewEdge*>(&inter);
+ if (ve) {
+ result = ve->qi();
+ return 0;
+ }
+ FEdge *fe = dynamic_cast<FEdge*>(&inter);
+ if (fe) {
+ result = ve->qi();
+ return 0;
+ }
+ result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ return 0;
+}
+
+int CurveNatureF1D::operator()(Interface1D& inter)
+{
+ ViewEdge *ve = dynamic_cast<ViewEdge*>(&inter);
+ if (ve) {
+ result = ve->getNature();
+ }
+ else {
+ // we return a nature that contains every natures of the viewedges spanned by the chain.
+ Nature::EdgeNature nat = Nature::NO_FEATURE;
+ Interface0DIterator it = inter.verticesBegin();
+ while (!it.isEnd()) {
+ nat |= _func(it);
+ ++it;
+ }
+ result = nat;
+ }
+ return 0;
+}
+
+int TimeStampF1D::operator()(Interface1D& inter)
+{
+ TimeStamp *timestamp = TimeStamp::instance();
+ inter.setTimeStamp(timestamp->getTimeStamp());
+ return 0;
+}
+
+int ChainingTimeStampF1D::operator()(Interface1D& inter)
+{
+ TimeStamp *timestamp = TimeStamp::instance();
+ ViewEdge *ve = dynamic_cast<ViewEdge*>(&inter);
+ if (ve)
+ ve->setChainingTimeStamp(timestamp->getTimeStamp());
+ return 0;
+}
+
+int IncrementChainingTimeStampF1D::operator()(Interface1D& inter)
+{
+ ViewEdge *ve = dynamic_cast<ViewEdge*>(&inter);
+ if (ve)
+ ve->setChainingTimeStamp(ve->getChainingTimeStamp()+1);
+ return 0;
+}
+
+int GetShapeF1D::operator()(Interface1D& inter)
+{
+ vector<ViewShape*> shapesVector;
+ set<ViewShape*> shapesSet;
+ ViewEdge *ve = dynamic_cast<ViewEdge*>(&inter);
+ if (ve) {
+ shapesVector.push_back(ve->viewShape());
+ }
+ else {
+ Interface0DIterator it = inter.verticesBegin(), itend = inter.verticesEnd();
+ for (; it != itend; ++it)
+ shapesSet.insert(Functions0D::getShapeF0D(it));
+ shapesVector.insert<set<ViewShape*>::iterator>(shapesVector.begin(), shapesSet.begin(), shapesSet.end());
+ }
+ result = shapesVector;
+ return 0;
+}
+
+int GetOccludersF1D::operator()(Interface1D& inter)
+{
+ vector<ViewShape*> shapesVector;
+ set<ViewShape*> shapesSet;
+ ViewEdge *ve = dynamic_cast<ViewEdge*>(&inter);
+ if (ve) {
+ result = ve->occluders();
+ }
+ else {
+ Interface0DIterator it = inter.verticesBegin(), itend = inter.verticesEnd();
+ for (; it != itend; ++it) {
+ Functions0D::getOccludersF0D(it, shapesSet);
+ }
+ shapesVector.insert(shapesVector.begin(), shapesSet.begin(), shapesSet.end());
+ result = shapesVector;
+ }
+ return 0;
+}
+
+int GetOccludeeF1D::operator()(Interface1D& inter)
+{
+ vector<ViewShape*> shapesVector;
+ set<ViewShape*> shapesSet;
+ ViewEdge *ve = dynamic_cast<ViewEdge*>(&inter);
+ if (ve) {
+ ViewShape *aShape = ve->aShape();
+ shapesVector.push_back(aShape);
+ }
+ else {
+ Interface0DIterator it = inter.verticesBegin(), itend = inter.verticesEnd();
+ for (; it != itend; ++it) {
+ shapesSet.insert(Functions0D::getOccludeeF0D(it));
+ }
+ shapesVector.insert<set<ViewShape*>::iterator>(shapesVector.begin(), shapesSet.begin(), shapesSet.end());
+ }
+ result = shapesVector;
+ return 0;
+}
+
+// Internal
+////////////
+
+void getOccludeeF1D(Interface1D& inter, set<ViewShape*>& oShapes)
+{
+ ViewEdge *ve = dynamic_cast<ViewEdge*>(&inter);
+ if (ve) {
+ ViewShape *aShape = ve->aShape();
+ if (aShape == 0) {
+ oShapes.insert(0);
+ return;
+ }
+ oShapes.insert(aShape);
+ }
+ else {
+ Interface0DIterator it = inter.verticesBegin(), itend = inter.verticesEnd();
+ for (; it != itend; ++it)
+ oShapes.insert(Functions0D::getOccludeeF0D(it));
+ }
+}
+
+void getOccludersF1D(Interface1D& inter, set<ViewShape*>& oShapes)
+{
+ ViewEdge *ve = dynamic_cast<ViewEdge*>(&inter);
+ if (ve) {
+ vector<ViewShape*>& occluders = ve->occluders();
+ oShapes.insert<vector<ViewShape*>::iterator>(occluders.begin(), occluders.end());
+ }
+ else {
+ Interface0DIterator it = inter.verticesBegin(), itend = inter.verticesEnd();
+ for (; it != itend; ++it) {
+ set<ViewShape*> shapes;
+ Functions0D::getOccludersF0D(it, shapes);
+ for (set<ViewShape*>::iterator s = shapes.begin(), send = shapes.end(); s != send; ++s)
+ oShapes.insert(*s);
+ }
+ }
+}
+
+void getShapeF1D(Interface1D& inter, set<ViewShape*>& oShapes)
+{
+ ViewEdge *ve = dynamic_cast<ViewEdge*>(&inter);
+ if (ve) {
+ oShapes.insert(ve->viewShape());
+ }
+ else {
+ Interface0DIterator it = inter.verticesBegin(), itend = inter.verticesEnd();
+ for (; it != itend; ++it)
+ oShapes.insert(Functions0D::getShapeF0D(it));
+ }
+}
+
+} // end of namespace Functions1D
diff --git a/source/blender/freestyle/intern/view_map/Functions1D.h b/source/blender/freestyle/intern/view_map/Functions1D.h
new file mode 100644
index 00000000000..f1885aa1762
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/Functions1D.h
@@ -0,0 +1,627 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_FUNCTIONS_1D_H__
+#define __FREESTYLE_FUNCTIONS_1D_H__
+
+/** \file blender/freestyle/intern/view_map/Functions1D.h
+ * \ingroup freestyle
+ * \brief Functions taking 1D input
+ * \author Stephane Grabli
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include "Functions0D.h"
+#include "Interface1D.h"
+#include "ViewMap.h"
+
+#include "../system/FreestyleConfig.h"
+#include "../system/Precision.h"
+#include "../system/TimeStamp.h"
+
+#include "../python/Director.h"
+
+//
+// UnaryFunction1D (base class for functions in 1D)
+//
+///////////////////////////////////////////////////////////
+
+/*! Base class for Unary Functions (functors) working on Interface1D.
+ * A unary function will be used by calling its operator() on an Interface1D.
+ * \attention In the scripting language, there exists several prototypes depending on the returned value type.
+ * For example, you would inherit from a UnaryFunction1DDouble if you wish to define a function that returns a double.
+ * The different existing prototypes are:
+ * - UnaryFunction1DVoid
+ * - UnaryFunction1DUnsigned
+ * - UnaryFunction1DReal
+ * - UnaryFunction1DFloat
+ * - UnaryFunction1DDouble
+ * - UnaryFunction1DVec2f
+ * - UnaryFunction1DVec3f
+ */
+template <class T>
+class /*LIB_VIEW_MAP_EXPORT*/ UnaryFunction1D
+{
+public:
+ T result;
+ PyObject *py_uf1D;
+
+ /*! The type of the value returned by the functor. */
+ typedef T ReturnedValueType;
+
+ /*! Default constructor */
+ UnaryFunction1D()
+ {
+ _integration = MEAN;
+ }
+
+ /*! Builds a UnaryFunction1D from an integration type.
+ * \param iType
+ * In case the result for the Interface1D would be obtained by evaluating a 0D function over the different
+ * Interface0D of the Interface1D, \a iType tells which integration method to use.
+ * The default integration method is the MEAN.
+ */
+ UnaryFunction1D(IntegrationType iType)
+ {
+ _integration = iType;
+ }
+
+ /*! destructor. */
+ virtual ~UnaryFunction1D() {}
+
+ /*! returns the string "UnaryFunction1D". */
+ virtual string getName() const
+ {
+ return "UnaryFunction1D";
+ }
+
+ /*! The operator ().
+ * \param inter
+ * The Interface1D on which we wish to evaluate the function.
+ * \return the result of the function of type T.
+ */
+ virtual int operator()(Interface1D& inter)
+ {
+ return Director_BPy_UnaryFunction1D___call__(this, py_uf1D, inter);
+ }
+
+ /*! Sets the integration method */
+ void setIntegrationType(IntegrationType integration)
+ {
+ _integration = integration;
+ }
+
+ /*! Returns the integration method. */
+ IntegrationType getIntegrationType() const
+ {
+ return _integration;
+ }
+
+protected:
+ IntegrationType _integration;
+};
+
+
+class UnaryFunction1D_void
+{
+public:
+ PyObject *py_uf1D;
+
+ UnaryFunction1D_void()
+ {
+ _integration = MEAN;
+ }
+
+ UnaryFunction1D_void(IntegrationType iType)
+ {
+ _integration = iType;
+ }
+
+ virtual ~UnaryFunction1D_void() {}
+
+ virtual string getName() const
+ {
+ return "UnaryFunction1D_void";
+ }
+
+ int operator()(Interface1D& inter)
+ {
+ return Director_BPy_UnaryFunction1D___call__(this, py_uf1D, inter);
+ }
+
+ void setIntegrationType(IntegrationType integration)
+ {
+ _integration = integration;
+ }
+
+ IntegrationType getIntegrationType() const
+ {
+ return _integration;
+ }
+
+protected:
+ IntegrationType _integration;
+};
+
+
+//
+// Functions definitions
+//
+///////////////////////////////////////////////////////////
+
+namespace Functions1D {
+
+// GetXF1D
+/*! Returns the X 3D coordinate of an Interface1D. */
+class LIB_VIEW_MAP_EXPORT GetXF1D : public UnaryFunction1D<real>
+{
+private:
+ Functions0D::GetXF0D _func;
+
+public:
+ /*! Builds the functor.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ GetXF1D(IntegrationType iType) : UnaryFunction1D<real>(iType) {}
+
+ /*! Returns the string "GetXF1D" */
+ string getName() const
+ {
+ return "GetXF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// GetYF1D
+/*! Returns the Y 3D coordinate of an Interface1D. */
+class LIB_VIEW_MAP_EXPORT GetYF1D : public UnaryFunction1D<real>
+{
+private:
+Functions0D::GetYF0D _func;
+
+public:
+ /*! Builds the functor.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ GetYF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType) {}
+
+ /*! Returns the string "GetYF1D" */
+ string getName() const
+ {
+ return "GetYF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// GetZF1D
+/*! Returns the Z 3D coordinate of an Interface1D. */
+class LIB_VIEW_MAP_EXPORT GetZF1D : public UnaryFunction1D<real>
+{
+private:
+ Functions0D::GetZF0D _func;
+
+public:
+ /*! Builds the functor.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ GetZF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType) {}
+
+ /*! Returns the string "GetZF1D" */
+ string getName() const
+ {
+ return "GetZF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// GetProjectedXF1D
+/*! Returns the projected X 3D coordinate of an Interface1D. */
+class LIB_VIEW_MAP_EXPORT GetProjectedXF1D : public UnaryFunction1D<real>
+{
+private:
+ Functions0D::GetProjectedXF0D _func;
+
+public:
+ /*! Builds the functor.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ GetProjectedXF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType) {}
+
+ /*! Returns the string "GetProjectedXF1D" */
+ string getName() const
+ {
+ return "GetProjectedXF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// GetProjectedYF1D
+/*! Returns the projected Y 3D coordinate of an Interface1D. */
+class LIB_VIEW_MAP_EXPORT GetProjectedYF1D : public UnaryFunction1D<real>
+{
+private:
+ Functions0D::GetProjectedYF0D _func;
+
+public:
+ /*! Builds the functor.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ GetProjectedYF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType) {}
+
+ /*! Returns the string "GetProjectedYF1D" */
+ string getName() const
+ {
+ return "GetProjectedYF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// GetProjectedZF1D
+/*! Returns the projected Z 3D coordinate of an Interface1D. */
+class LIB_VIEW_MAP_EXPORT GetProjectedZF1D : public UnaryFunction1D<real>
+{
+private:
+ Functions0D::GetProjectedZF0D _func;
+
+public:
+ /*! Builds the functor.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ GetProjectedZF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType) {}
+
+ /*! Returns the string "GetProjectedZF1D" */
+ string getName() const
+ {
+ return "GetProjectedZF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// Orientation2DF1D
+/*! Returns the 2D orientation as a Vec2f*/
+class LIB_VIEW_MAP_EXPORT Orientation2DF1D : public UnaryFunction1D<Vec2f>
+{
+private:
+ Functions0D::VertexOrientation2DF0D _func;
+
+public:
+ /*! Builds the functor.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ Orientation2DF1D(IntegrationType iType = MEAN) : UnaryFunction1D<Vec2f>(iType) {}
+
+ /*! Returns the string "Orientation2DF1D" */
+ string getName() const
+ {
+ return "Orientation2DF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// Orientation3DF1D
+/*! Returns the 3D orientation as a Vec3f. */
+class LIB_VIEW_MAP_EXPORT Orientation3DF1D : public UnaryFunction1D<Vec3f>
+{
+private:
+ Functions0D::VertexOrientation3DF0D _func;
+
+public:
+ /*! Builds the functor.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ Orientation3DF1D(IntegrationType iType = MEAN) : UnaryFunction1D<Vec3f>(iType) {}
+
+ /*! Returns the string "Orientation3DF1D" */
+ string getName() const
+ {
+ return "Orientation3DF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// ZDiscontinuityF1D
+/*! Returns a real giving the distance between and Interface1D and the shape that lies behind (occludee).
+ * This distance is evaluated in the camera space and normalized between 0 and 1. Therefore, if no oject is occluded
+ * by the shape to which the Interface1D belongs to, 1 is returned.
+ */
+class LIB_VIEW_MAP_EXPORT ZDiscontinuityF1D : public UnaryFunction1D<real>
+{
+private:
+ Functions0D::ZDiscontinuityF0D _func;
+
+public:
+ /*! Builds the functor.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ ZDiscontinuityF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType) {}
+
+ /*! Returns the string "ZDiscontinuityF1D" */
+ string getName() const
+ {
+ return "ZDiscontinuityF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// QuantitativeInvisibilityF1D
+/*! Returns the Quantitative Invisibility of an Interface1D element.
+ * If the Interface1D is a ViewEdge, then there is no ambiguity concerning the result. But, if the Interface1D
+ * results of a chaining (chain, stroke), then it might be made of several 1D elements of different
+ * Quantitative Invisibilities.
+ */
+class LIB_VIEW_MAP_EXPORT QuantitativeInvisibilityF1D : public UnaryFunction1D<unsigned>
+{
+private:
+ Functions0D::QuantitativeInvisibilityF0D _func;
+
+public:
+ /*! Builds the functor.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ QuantitativeInvisibilityF1D(IntegrationType iType = MEAN) : UnaryFunction1D<unsigned int>(iType) {}
+
+ /*! Returns the string "QuantitativeInvisibilityF1D" */
+ string getName() const
+ {
+ return "QuantitativeInvisibilityF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// CurveNatureF1D
+/*! Returns the nature of the Interface1D (silhouette, ridge, crease...).
+ * Except if the Interface1D is a ViewEdge, this result might be ambiguous.
+ * Indeed, the Interface1D might result from the gathering of several 1D elements, each one being of a different
+ * nature. An integration method, such as the MEAN, might give, in this case, irrelevant results.
+ */
+class LIB_VIEW_MAP_EXPORT CurveNatureF1D : public UnaryFunction1D<Nature::EdgeNature>
+{
+private:
+ Functions0D::CurveNatureF0D _func;
+
+public:
+ /*! Builds the functor.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ CurveNatureF1D(IntegrationType iType = MEAN) : UnaryFunction1D<Nature::EdgeNature>(iType) {}
+
+ /*! Returns the string "CurveNatureF1D" */
+ string getName() const
+ {
+ return "CurveNatureF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// TimeStampF1D
+/*! Returns the time stamp of the Interface1D. */
+class LIB_VIEW_MAP_EXPORT TimeStampF1D : public UnaryFunction1D_void
+{
+public:
+ /*! Returns the string "TimeStampF1D" */
+ string getName() const
+ {
+ return "TimeStampF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// IncrementChainingTimeStampF1D
+/*! Increments the chaining time stamp of the Interface1D. */
+class LIB_VIEW_MAP_EXPORT IncrementChainingTimeStampF1D : public UnaryFunction1D_void
+{
+public:
+ /*! Returns the string "IncrementChainingTimeStampF1D" */
+ string getName() const
+ {
+ return "IncrementChainingTimeStampF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// ChainingTimeStampF1D
+/*! Sets the chaining time stamp of the Interface1D. */
+class LIB_VIEW_MAP_EXPORT ChainingTimeStampF1D : public UnaryFunction1D_void
+{
+public:
+ /*! Returns the string "ChainingTimeStampF1D" */
+ string getName() const
+ {
+ return "ChainingTimeStampF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+
+// Curvature2DAngleF1D
+/*! Returns the 2D curvature as an angle for an Interface1D. */
+class LIB_VIEW_MAP_EXPORT Curvature2DAngleF1D : public UnaryFunction1D<real>
+{
+public:
+ /*! Builds the functor.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ Curvature2DAngleF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType) {}
+
+ /*! Returns the string "Curvature2DAngleF1D" */
+ string getName() const
+ {
+ return "Curvature2DAngleF1D";
+ }
+
+ /*! the () operator.*/
+ int operator()(Interface1D& inter)
+ {
+ result = integrate(_fun, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ return 0;
+ }
+
+private:
+ Functions0D::Curvature2DAngleF0D _fun;
+};
+
+// Normal2DF1D
+/*! Returns the 2D normal for an interface 1D. */
+class LIB_VIEW_MAP_EXPORT Normal2DF1D : public UnaryFunction1D<Vec2f>
+{
+public:
+ /*! Builds the functor.
+ * \param iType
+ * The integration method used to compute a single value from a set of values.
+ */
+ Normal2DF1D(IntegrationType iType = MEAN) : UnaryFunction1D<Vec2f>(iType) {}
+
+ /*! Returns the string "Normal2DF1D" */
+ string getName() const
+ {
+ return "Normal2DF1D";
+ }
+
+ /*! the () operator.*/
+ int operator()(Interface1D& inter)
+ {
+ result = integrate(_fun, inter.verticesBegin(), inter.verticesEnd(), _integration);
+ return 0;
+ }
+
+private:
+ Functions0D::Normal2DF0D _fun;
+};
+
+// GetShapeF1D
+/*! Returns list of shapes covered by this Interface1D. */
+class LIB_VIEW_MAP_EXPORT GetShapeF1D : public UnaryFunction1D<std::vector<ViewShape*> >
+{
+public:
+ /*! Builds the functor. */
+ GetShapeF1D() : UnaryFunction1D<std::vector<ViewShape*> >() {}
+
+ /*! Returns the string "GetShapeF1D" */
+ string getName() const
+ {
+ return "GetShapeF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// GetOccludersF1D
+/*! Returns list of occluding shapes covered by this Interface1D. */
+class LIB_VIEW_MAP_EXPORT GetOccludersF1D : public UnaryFunction1D<std::vector<ViewShape*> >
+{
+public:
+ /*! Builds the functor. */
+ GetOccludersF1D() : UnaryFunction1D<std::vector<ViewShape*> >() {}
+
+ /*! Returns the string "GetOccludersF1D" */
+ string getName() const
+ {
+ return "GetOccludersF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// GetOccludeeF1D
+/*! Returns list of occluded shapes covered by this Interface1D. */
+class LIB_VIEW_MAP_EXPORT GetOccludeeF1D : public UnaryFunction1D<std::vector<ViewShape*> >
+{
+public:
+ /*! Builds the functor. */
+ GetOccludeeF1D() : UnaryFunction1D<std::vector<ViewShape*> >() {}
+
+ /*! Returns the string "GetOccludeeF1D" */
+ string getName() const
+ {
+ return "GetOccludeeF1D";
+ }
+
+ /*! the () operator. */
+ int operator()(Interface1D& inter);
+};
+
+// internal
+////////////
+
+// getOccludeeF1D
+LIB_VIEW_MAP_EXPORT
+void getOccludeeF1D(Interface1D& inter, set<ViewShape*>& oShapes);
+
+// getOccludersF1D
+LIB_VIEW_MAP_EXPORT
+void getOccludersF1D(Interface1D& inter, set<ViewShape*>& oShapes);
+
+// getShapeF1D
+LIB_VIEW_MAP_EXPORT
+void getShapeF1D(Interface1D& inter, set<ViewShape*>& oShapes);
+
+} // end of namespace Functions1D
+
+#endif // __FREESTYLE_FUNCTIONS_1D_H__
diff --git a/source/blender/freestyle/intern/view_map/GridDensityProvider.h b/source/blender/freestyle/intern/view_map/GridDensityProvider.h
new file mode 100644
index 00000000000..5fe7d095358
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/GridDensityProvider.h
@@ -0,0 +1,152 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_GRID_DENSITY_PROVIDER_H__
+#define __FREESTYLE_GRID_DENSITY_PROVIDER_H__
+
+/** \file blender/freestyle/intern/view_map/GridDensityProvider.h
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2011-2-5
+ */
+
+#include <stdexcept>
+#include <memory>
+
+#include "OccluderSource.h"
+
+#include "../geometry/BBox.h"
+
+#include "BKE_global.h"
+
+class GridDensityProvider
+{
+ // Disallow copying and assignment
+ GridDensityProvider(const GridDensityProvider& other);
+ GridDensityProvider& operator=(const GridDensityProvider& other);
+
+public:
+ GridDensityProvider(OccluderSource& source) : source(source) {}
+
+ virtual ~GridDensityProvider() {};
+
+ float cellSize()
+ {
+ return _cellSize;
+ }
+
+ unsigned cellsX()
+ {
+ return _cellsX;
+ }
+
+ unsigned cellsY()
+ {
+ return _cellsY;
+ }
+
+ float cellOrigin(int index)
+ {
+ if (index < 2) {
+ return _cellOrigin[index];
+ }
+ else {
+ throw new out_of_range("GridDensityProvider::cellOrigin can take only indexes of 0 or 1.");
+ }
+ }
+
+ static void calculateOptimalProscenium(OccluderSource& source, real proscenium[4])
+ {
+ source.begin();
+ if (source.isValid()) {
+ const Vec3r& initialPoint = source.getGridSpacePolygon().getVertices()[0];
+ proscenium[0] = proscenium[1] = initialPoint[0];
+ proscenium[2] = proscenium[3] = initialPoint[1];
+ while (source.isValid()) {
+ GridHelpers::expandProscenium (proscenium, source.getGridSpacePolygon());
+ source.next();
+ }
+ }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Proscenium: (" << proscenium[0] << ", " << proscenium[1] << ", " << proscenium[2]
+ << ", " << proscenium[3] << ")" << endl;
+ }
+ }
+
+ static void calculateQuickProscenium(const GridHelpers::Transform& transform, const BBox<Vec3r>& bbox,
+ real proscenium[4])
+ {
+ real z;
+ // We want to use the z-coordinate closest to the camera to determine the proscenium face
+ if (::fabs(bbox.getMin()[2]) < ::fabs(bbox.getMax()[2])) {
+ z = bbox.getMin()[2];
+ }
+ else {
+ z = bbox.getMax()[2];
+ }
+ // Now calculate the proscenium according to the min and max values of the x and y coordinates
+ Vec3r minPoint = transform(Vec3r(bbox.getMin()[0], bbox.getMin()[1], z));
+ Vec3r maxPoint = transform(Vec3r(bbox.getMax()[0], bbox.getMax()[1], z));
+ proscenium[0] = std::min(minPoint[0], maxPoint[0]);
+ proscenium[1] = std::max(minPoint[0], maxPoint[0]);
+ proscenium[2] = std::min(minPoint[1], maxPoint[1]);
+ proscenium[3] = std::max(minPoint[1], maxPoint[1]);
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Bounding box: " << minPoint << " to " << maxPoint << endl;
+ cout << "Proscenium : " << proscenium[0] << ", " << proscenium[1] << ", " << proscenium[2] << ", "
+ << proscenium[3] << endl;
+ }
+ }
+
+protected:
+ OccluderSource& source;
+ unsigned _cellsX, _cellsY;
+ float _cellSize;
+ float _cellOrigin[2];
+};
+
+class GridDensityProviderFactory
+{
+ // Disallow copying and assignment
+ GridDensityProviderFactory (const GridDensityProviderFactory& other);
+ GridDensityProviderFactory& operator= (const GridDensityProviderFactory& other);
+
+public:
+ GridDensityProviderFactory() {}
+
+ virtual auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]) = 0;
+
+ virtual auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform) = 0;
+
+ virtual auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source) = 0;
+
+ virtual ~GridDensityProviderFactory () {}
+};
+
+#endif // __FREESTYLE_GRID_DENSITY_PROVIDER_H__
diff --git a/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp b/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp
new file mode 100644
index 00000000000..5e17c85808b
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp
@@ -0,0 +1,84 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.cpp
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2011-2-8
+ */
+
+#include "HeuristicGridDensityProviderFactory.h"
+
+HeuristicGridDensityProviderFactory::HeuristicGridDensityProviderFactory(real sizeFactor, unsigned numFaces)
+: sizeFactor(sizeFactor), numFaces(numFaces)
+{
+}
+
+HeuristicGridDensityProviderFactory::~HeuristicGridDensityProviderFactory() {}
+
+auto_ptr<GridDensityProvider>
+HeuristicGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const real proscenium[4])
+{
+ auto_ptr<AverageAreaGridDensityProvider> avg(new AverageAreaGridDensityProvider(source, proscenium, sizeFactor));
+ auto_ptr<Pow23GridDensityProvider> p23(new Pow23GridDensityProvider(source, proscenium, numFaces));
+ if (avg->cellSize() > p23->cellSize()) {
+ return (auto_ptr<GridDensityProvider>) p23;
+ }
+ else {
+ return (auto_ptr<GridDensityProvider>) avg;
+ }
+}
+
+auto_ptr<GridDensityProvider>
+HeuristicGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform)
+{
+ auto_ptr<AverageAreaGridDensityProvider> avg(new AverageAreaGridDensityProvider(source, bbox,
+ transform, sizeFactor));
+ auto_ptr<Pow23GridDensityProvider> p23(new Pow23GridDensityProvider(source, bbox, transform, numFaces));
+ if (avg->cellSize() > p23->cellSize()) {
+ return (auto_ptr<GridDensityProvider>) p23;
+ }
+ else {
+ return (auto_ptr<GridDensityProvider>) avg;
+ }
+}
+
+auto_ptr<GridDensityProvider> HeuristicGridDensityProviderFactory::newGridDensityProvider(OccluderSource& source)
+{
+ real proscenium[4];
+ GridDensityProvider::calculateOptimalProscenium(source, proscenium);
+ auto_ptr<AverageAreaGridDensityProvider> avg(new AverageAreaGridDensityProvider(source, proscenium, sizeFactor));
+ auto_ptr<Pow23GridDensityProvider> p23(new Pow23GridDensityProvider(source, proscenium, numFaces));
+ if (avg->cellSize() > p23->cellSize()) {
+ return (auto_ptr<GridDensityProvider>) p23;
+ }
+ else {
+ return (auto_ptr<GridDensityProvider>) avg;
+ }
+}
diff --git a/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.h b/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.h
new file mode 100644
index 00000000000..a7557f04565
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.h
@@ -0,0 +1,60 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_HEURISTIC_GRID_DENSITY_PROVIDER_FACTORY_H__
+#define __FREESTYLE_HEURISTIC_GRID_DENSITY_PROVIDER_FACTORY_H__
+
+/** \file blender/freestyle/intern/view_map/HeuristicGridDensityProviderFactory.h
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2011-2-8
+ */
+
+//#include <memory> // provided by GridDensityProvider.h
+
+#include "AverageAreaGridDensityProvider.h"
+//#include "GridDensityProvider.h" // provided by *GridDensityProvider.h below
+#include "Pow23GridDensityProvider.h"
+
+class HeuristicGridDensityProviderFactory : public GridDensityProviderFactory
+{
+public:
+ HeuristicGridDensityProviderFactory(real sizeFactor, unsigned numFaces);
+ ~HeuristicGridDensityProviderFactory();
+
+ auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]);
+ auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform);
+ auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source);
+
+protected:
+ real sizeFactor;
+ unsigned numFaces;
+};
+
+#endif // __FREESTYLE_HEURISTIC_GRID_DENSITY_PROVIDER_FACTORY_H__
diff --git a/source/blender/freestyle/intern/view_map/Interface0D.h b/source/blender/freestyle/intern/view_map/Interface0D.h
new file mode 100644
index 00000000000..bbf93deadb7
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/Interface0D.h
@@ -0,0 +1,390 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_INTERFACE_0D_H__
+#define __FREESTYLE_INTERFACE_0D_H__
+
+/** \file blender/freestyle/intern/view_map/Interface0D.h
+ * \ingroup freestyle
+ * \brief Interface to 0D elts
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include <iostream>
+#include <Python.h>
+#include <string>
+
+#include "../geometry/Geom.h"
+
+#include "../system/Id.h"
+#include "../system/Iterator.h" //soc
+#include "../system/Precision.h"
+
+#include "../winged_edge/Nature.h"
+
+using namespace std;
+
+//
+// Interface0D
+//
+//////////////////////////////////////////////////
+
+class FEdge;
+class SVertex;
+class ViewVertex;
+class NonTVertex;
+class TVertex;
+
+/*! Base class for any 0D element. */
+class Interface0D
+{
+public:
+ /*! Default constructor */
+ Interface0D() {}
+ virtual ~Interface0D() {}; //soc
+
+ /*! Returns the string "Interface0D". */
+ virtual string getExactTypeName() const
+ {
+ return "Interface0D";
+ }
+
+ // Data access methods
+
+ /*! Returns the 3D x coordinate of the point. */
+ virtual real getX() const
+ {
+ PyErr_SetString(PyExc_TypeError, "method getX() not properly overridden");
+ return 0;
+ }
+
+ /*! Returns the 3D y coordinate of the point. */
+ virtual real getY() const
+ {
+ PyErr_SetString(PyExc_TypeError, "method getY() not properly overridden");
+ return 0;
+ }
+
+ /*! Returns the 3D z coordinate of the point. */
+ virtual real getZ() const
+ {
+ PyErr_SetString(PyExc_TypeError, "method getZ() not properly overridden");
+ return 0;
+ }
+
+ /*! Returns the 3D point. */
+ virtual Geometry::Vec3f getPoint3D() const
+ {
+ PyErr_SetString(PyExc_TypeError, "method getPoint3D() not properly overridden");
+ return 0;
+ }
+
+ /*! Returns the 2D x coordinate of the point. */
+ virtual real getProjectedX() const
+ {
+ PyErr_SetString(PyExc_TypeError, "method getProjectedX() not properly overridden");
+ return 0;
+ }
+
+ /*! Returns the 2D y coordinate of the point. */
+ virtual real getProjectedY() const
+ {
+ PyErr_SetString(PyExc_TypeError, "method getProjectedY() not properly overridden");
+ return 0;
+ }
+
+ /*! Returns the 2D z coordinate of the point. */
+ virtual real getProjectedZ() const
+ {
+ PyErr_SetString(PyExc_TypeError, "method getProjectedZ() not properly overridden");
+ return 0;
+ }
+
+ /*! Returns the 2D point. */
+ virtual Geometry::Vec2f getPoint2D() const
+ {
+ PyErr_SetString(PyExc_TypeError, "method getPoint2D() not properly overridden");
+ return 0;
+ }
+
+ /*! Returns the FEdge that lies between this Interface0D and the Interface0D given as argument. */
+ virtual FEdge* getFEdge(Interface0D&)
+ {
+ PyErr_SetString(PyExc_TypeError, "method getFEdge() not properly overridden");
+ return 0;
+ }
+
+ /*! Returns the Id of the point. */
+ virtual Id getId() const
+ {
+ PyErr_SetString(PyExc_TypeError, "method getId() not properly overridden");
+ return 0;
+ }
+
+ /*! Returns the nature of the point. */
+ virtual Nature::VertexNature getNature() const
+ {
+ PyErr_SetString(PyExc_TypeError, "method getNature() not properly overridden");
+ return Nature::POINT;
+ }
+
+
+ /*! Cast the Interface0D in SVertex if it can be. */
+ virtual SVertex *castToSVertex()
+ {
+ PyErr_SetString(PyExc_TypeError, "method castToSVertex() not properly overridden");
+ return 0;
+ }
+
+ /*! Cast the Interface0D in ViewVertex if it can be. */
+ virtual ViewVertex * castToViewVertex()
+ {
+ PyErr_SetString(PyExc_TypeError, "method castToViewVertex() not properly overridden");
+ return 0;
+ }
+
+ /*! Cast the Interface0D in NonTVertex if it can be. */
+ virtual NonTVertex *castToNonTVertex()
+ {
+ PyErr_SetString(PyExc_TypeError, "method castToNonTVertex() not properly overridden");
+ return 0;
+ }
+
+ /*! Cast the Interface0D in TVertex if it can be. */
+ virtual TVertex *castToTVertex()
+ {
+ PyErr_SetString(PyExc_TypeError, "method castToTVertex() not properly overridden");
+ return 0;
+ }
+};
+
+
+//
+// Interface0DIteratorNested
+//
+//////////////////////////////////////////////////
+
+class Interface0DIteratorNested : public Iterator
+{
+public:
+ virtual ~Interface0DIteratorNested() {}
+
+ virtual string getExactTypeName() const
+ {
+ return "Interface0DIteratorNested";
+ }
+
+ virtual Interface0D& operator*() = 0;
+
+ virtual Interface0D* operator->()
+ {
+ return &(operator*());
+ }
+
+ virtual int increment() = 0;
+
+ virtual int decrement() = 0;
+
+ virtual bool isBegin() const = 0;
+
+ virtual bool isEnd() const = 0;
+
+ virtual bool operator==(const Interface0DIteratorNested& it) const = 0;
+
+ virtual bool operator!=(const Interface0DIteratorNested& it) const
+ {
+ return !(*this == it);
+ }
+
+ /*! Returns the curvilinear abscissa */
+ virtual float t() const = 0;
+
+ /*! Returns the point parameter 0<u<1 */
+ virtual float u() const = 0;
+
+ virtual Interface0DIteratorNested* copy() const = 0;
+};
+
+
+//
+// Interface0DIterator
+//
+//////////////////////////////////////////////////
+
+/*! Class defining an iterator over Interface0D elements.
+ * An instance of this iterator is always obtained from a 1D element.
+ * \attention In the scripting language, you must call \code it2 = Interface0DIterator(it1) \endcode instead of
+ * \code it2 = it1 \endcode where \a it1 and \a it2 are 2 Interface0DIterator.
+ * Otherwise, incrementing \a it1 will also increment \a it2.
+ */
+class Interface0DIterator : public Iterator
+{
+public:
+ Interface0DIterator(Interface0DIteratorNested* it = NULL)
+ {
+ _iterator = it;
+ }
+
+ /*! Copy constructor */
+ Interface0DIterator(const Interface0DIterator& it)
+ {
+ _iterator = it._iterator->copy();
+ }
+
+ /*! Destructor */
+ virtual ~Interface0DIterator()
+ {
+ if (_iterator)
+ delete _iterator;
+ }
+
+ /*! Operator =
+ * \attention In the scripting language, you must call \code it2 = Interface0DIterator(it1) \endcode instead of
+ * \code it2 = it1 \endcode where \a it1 and \a it2 are 2 Interface0DIterator.
+ * Otherwise, incrementing \a it1 will also increment \a it2.
+ */
+ Interface0DIterator& operator=(const Interface0DIterator& it)
+ {
+ if(_iterator)
+ delete _iterator;
+ _iterator = it._iterator->copy();
+ return *this;
+ }
+
+ /*! Returns the string "Interface0DIterator". */
+ virtual string getExactTypeName() const
+ {
+ if (!_iterator)
+ return "Interface0DIterator";
+ return _iterator->getExactTypeName() + "Proxy";
+ }
+
+ // FIXME test it != 0 (exceptions ?)
+
+ /*! Returns a reference to the pointed Interface0D.
+ * In the scripting language, you must call "getObject()" instead using this operator.
+ */
+ Interface0D& operator*()
+ {
+ return _iterator->operator*();
+ }
+
+ /*! Returns a pointer to the pointed Interface0D.
+ * Can't be called in the scripting language.
+ */
+ Interface0D *operator->()
+ {
+ return &(operator*());
+ }
+
+ /*! Increments. In the scripting language, call "increment()". */
+ Interface0DIterator& operator++()
+ {
+ _iterator->increment();
+ return *this;
+ }
+
+ /*! Increments. In the scripting language, call "increment()". */
+ Interface0DIterator operator++(int)
+ {
+ Interface0DIterator ret(*this);
+ _iterator->increment();
+ return ret;
+ }
+
+ /*! Decrements. In the scripting language, call "decrement()". */
+ Interface0DIterator& operator--()
+ {
+ _iterator->decrement();
+ return *this;
+ }
+
+ /*! Decrements. In the scripting language, call "decrement()". */
+ Interface0DIterator operator--(int)
+ {
+ Interface0DIterator ret(*this);
+ _iterator->decrement();
+ return ret;
+ }
+
+ /*! Increments. */
+ virtual int increment()
+ {
+ return _iterator->increment();
+ }
+
+ /*! Decrements. */
+ virtual int decrement()
+ {
+ return _iterator->decrement();
+ }
+
+ /*! Returns true if the pointed Interface0D is the first of the 1D element containing the points over which
+ * we're iterating.
+ */
+ virtual bool isBegin() const
+ {
+ return _iterator->isBegin();
+ }
+
+ /*! Returns true if the pointed Interface0D is after the after the last point of the 1D element we're
+ * iterating from. */
+ virtual bool isEnd() const
+ {
+ return _iterator->isEnd();
+ }
+
+ /*! operator == . */
+ bool operator==(const Interface0DIterator& it) const
+ {
+ return _iterator->operator==(*(it._iterator));
+ }
+
+ /*! operator != . */
+ bool operator!=(const Interface0DIterator& it) const
+ {
+ return !(*this == it);
+ }
+
+ /*! Returns the curvilinear abscissa. */
+ inline float t() const
+ {
+ return _iterator->t();
+ }
+
+ /*! Returns the point parameter in the curve 0<=u<=1. */
+ inline float u() const
+ {
+ return _iterator->u();
+ }
+
+protected:
+ Interface0DIteratorNested *_iterator;
+};
+
+#endif // __FREESTYLE_INTERFACE_0D_H__
diff --git a/source/blender/freestyle/intern/view_map/Interface1D.h b/source/blender/freestyle/intern/view_map/Interface1D.h
new file mode 100644
index 00000000000..440c6f275b8
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/Interface1D.h
@@ -0,0 +1,230 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_INTERFACE_1D_H__
+#define __FREESTYLE_INTERFACE_1D_H__
+
+/** \file blender/freestyle/intern/view_map/Interface1D.h
+ * \ingroup freestyle
+ * \brief Interface 1D and related tools definitions
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+#include <float.h>
+#include <iostream>
+#include <Python.h>
+#include <string>
+
+#include "Functions0D.h"
+
+#include "../system/Id.h"
+#include "../system/Precision.h"
+
+#include "../winged_edge/Nature.h"
+
+using namespace std;
+
+// Integration method
+/*! The different integration methods that can be invoked to integrate into a single value the set of values obtained
+ * from each 0D element of a 1D element.
+ */
+typedef enum {
+ MEAN, /*!< The value computed for the 1D element is the mean of the values obtained for the 0D elements.*/
+ MIN, /*!< The value computed for the 1D element is the minimum of the values obtained for the 0D elements.*/
+ MAX, /*!< The value computed for the 1D element is the maximum of the values obtained for the 0D elements.*/
+ FIRST, /*!< The value computed for the 1D element is the first of the values obtained for the 0D elements.*/
+ LAST /*!< The value computed for the 1D element is the last of the values obtained for the 0D elements.*/
+} IntegrationType;
+
+/*! Returns a single value from a set of values evaluated at each 0D element of this 1D element.
+ * \param fun
+ * The UnaryFunction0D used to compute a value at each Interface0D.
+ * \param it
+ * The Interface0DIterator used to iterate over the 0D elements of this 1D element. The integration will occur
+ * over the 0D elements starting from the one pointed by it.
+ * \param it_end
+ * The Interface0DIterator pointing the end of the 0D elements of the 1D element.
+ * \param integration_type
+ * The integration method used to compute a single value from a set of values.
+ * \return the single value obtained for the 1D element.
+ */
+template <class T>
+T integrate(UnaryFunction0D<T>& fun, Interface0DIterator it, Interface0DIterator it_end,
+ IntegrationType integration_type = MEAN)
+{
+ T res;
+ unsigned size;
+ switch (integration_type) {
+ case MIN:
+ fun(it);
+ res = fun.result;
+ ++it;
+ for (; !it.isEnd(); ++it) {
+ fun(it);
+ if (fun.result < res)
+ res = fun.result;
+ }
+ break;
+ case MAX:
+ fun(it);
+ res = fun.result;
+ ++it;
+ for (; !it.isEnd(); ++it) {
+ fun(it);
+ if (fun.result > res)
+ res = fun.result;
+ }
+ break;
+ case FIRST:
+ fun(it);
+ res = fun.result;
+ break;
+ case LAST:
+ fun(--it_end);
+ res = fun.result;
+ break;
+ case MEAN:
+ default:
+ fun(it);
+ res = fun.result;
+ ++it;
+ for (size = 1; !it.isEnd(); ++it, ++size) {
+ fun(it);
+ res += fun.result;
+ }
+ res /= (size ? size : 1);
+ break;
+ }
+ return res;
+}
+
+//
+// Interface1D
+//
+//////////////////////////////////////////////////
+
+/*! Base class for any 1D element. */
+class Interface1D
+{
+public:
+ /*! Default constructor */
+ Interface1D()
+ {
+ _timeStamp = 0;
+ }
+
+ virtual ~Interface1D() {}; //soc
+
+ /*! Returns the string "Interface1D". */
+ virtual string getExactTypeName() const
+ {
+ return "Interface1D";
+ }
+
+ // Iterator access
+
+ /*! Returns an iterator over the Interface1D vertices, pointing to the first vertex. */
+ virtual Interface0DIterator verticesBegin()
+ {
+ PyErr_SetString(PyExc_TypeError, "method verticesBegin() not properly overridden");
+ return Interface0DIterator();
+ }
+
+ /*! Returns an iterator over the Interface1D vertices, pointing after the last vertex. */
+ virtual Interface0DIterator verticesEnd()
+ {
+ PyErr_SetString(PyExc_TypeError, "method verticesEnd() not properly overridden");
+ return Interface0DIterator();
+ }
+
+ /*! Returns an iterator over the Interface1D points, pointing to the first point. The difference with
+ * verticesBegin() is that here we can iterate over points of the 1D element at a any given sampling.
+ * Indeed, for each iteration, a virtual point is created.
+ * \param t
+ * The sampling with which we want to iterate over points of this 1D element.
+ */
+ virtual Interface0DIterator pointsBegin(float t = 0.0f)
+ {
+ PyErr_SetString(PyExc_TypeError, "method pointsBegin() not properly overridden");
+ return Interface0DIterator();
+ }
+
+ /*! Returns an iterator over the Interface1D points, pointing after the last point. The difference with
+ * verticesEnd() is that here we can iterate over points of the 1D element at a any given sampling.
+ * Indeed, for each iteration, a virtual point is created.
+ * \param t
+ * The sampling with which we want to iterate over points of this 1D element.
+ */
+ virtual Interface0DIterator pointsEnd(float t = 0.0f)
+ {
+ PyErr_SetString(PyExc_TypeError, "method pointsEnd() not properly overridden");
+ return Interface0DIterator();
+ }
+
+ // Data access methods
+
+ /*! Returns the 2D length of the 1D element. */
+ virtual real getLength2D() const
+ {
+ PyErr_SetString(PyExc_TypeError, "method getLength2D() not properly overridden");
+ return 0;
+ }
+
+ /*! Returns the Id of the 1D element. */
+ virtual Id getId() const
+ {
+ PyErr_SetString(PyExc_TypeError, "method getId() not properly overridden");
+ return Id(0, 0);
+ }
+
+
+ // FIXME: ce truc n'a rien a faire la...(c une requete complexe qui doit etre ds les Function1D)
+ /*! Returns the nature of the 1D element. */
+ virtual Nature::EdgeNature getNature() const
+ {
+ PyErr_SetString(PyExc_TypeError, "method getNature() not properly overridden");
+ return Nature::NO_FEATURE;
+ }
+
+ /*! Returns the time stamp of the 1D element. Mainly used for selection. */
+ virtual unsigned getTimeStamp() const
+ {
+ return _timeStamp;
+ }
+
+ /*! Sets the time stamp for the 1D element. */
+ inline void setTimeStamp(unsigned iTimeStamp)
+ {
+ _timeStamp = iTimeStamp;
+ }
+
+protected:
+ unsigned _timeStamp;
+};
+
+#endif // __FREESTYLE_INTERFACE_1D_H__
diff --git a/source/blender/freestyle/intern/view_map/OccluderSource.cpp b/source/blender/freestyle/intern/view_map/OccluderSource.cpp
new file mode 100644
index 00000000000..0cbad57b44a
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/OccluderSource.cpp
@@ -0,0 +1,150 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/OccluderSource.cpp
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2010-12-21
+ */
+
+#include <algorithm>
+
+#include "OccluderSource.h"
+
+#include "BKE_global.h"
+
+OccluderSource::OccluderSource(const GridHelpers::Transform& t, WingedEdge& we)
+: wingedEdge(we), valid(false), transform(t)
+{
+ begin();
+}
+
+OccluderSource::~OccluderSource() {}
+
+void OccluderSource::buildCachedPolygon()
+{
+ vector<Vec3r> vertices(GridHelpers::enumerateVertices((*currentFace)->getEdgeList()));
+ // This doesn't work, because our functor's polymorphism won't survive the copy:
+ // std::transform(vertices.begin(), vertices.end(), vertices.begin(), transform);
+ // so we have to do:
+ for (vector<Vec3r>::iterator i = vertices.begin(); i != vertices.end(); ++i) {
+ (*i) = transform(*i);
+ }
+ cachedPolygon = Polygon3r(vertices, transform((*currentFace)->GetNormal()));
+}
+
+void OccluderSource::begin()
+{
+ vector<WShape*>& wshapes = wingedEdge.getWShapes();
+ currentShape = wshapes.begin();
+ shapesEnd = wshapes.end();
+ valid = false;
+ if (currentShape != shapesEnd) {
+ vector<WFace*>& wFaces = (*currentShape)->GetFaceList();
+ currentFace = wFaces.begin();
+ facesEnd = wFaces.end();
+
+ if (currentFace != facesEnd) {
+ buildCachedPolygon();
+ valid = true;
+ }
+ }
+}
+
+bool OccluderSource::next() {
+ if (valid) {
+ ++currentFace;
+ while (currentFace == facesEnd) {
+ ++currentShape;
+ if (currentShape == shapesEnd) {
+ valid = false;
+ return false;
+ }
+ else {
+ vector<WFace*>& wFaces = (*currentShape)->GetFaceList();
+ currentFace = wFaces.begin();
+ facesEnd = wFaces.end();
+ }
+ }
+ buildCachedPolygon();
+ return true;
+ }
+ return false;
+}
+
+bool OccluderSource::isValid()
+{
+ // Or:
+ // return currentShapes != shapesEnd && currentFace != facesEnd;
+ return valid;
+}
+
+WFace *OccluderSource::getWFace()
+{
+ return valid ? *currentFace : NULL;
+}
+
+Polygon3r OccluderSource::getCameraSpacePolygon()
+{
+ return Polygon3r(GridHelpers::enumerateVertices((*currentFace)->getEdgeList()), (*currentFace)->GetNormal());
+}
+
+Polygon3r& OccluderSource::getGridSpacePolygon()
+{
+ return cachedPolygon;
+}
+
+void OccluderSource::getOccluderProscenium(real proscenium[4])
+{
+ begin();
+ const Vec3r& initialPoint = cachedPolygon.getVertices()[0];
+ proscenium[0] = proscenium[1] = initialPoint[0];
+ proscenium[2] = proscenium[3] = initialPoint[1];
+ while (isValid()) {
+ GridHelpers::expandProscenium (proscenium, cachedPolygon);
+ next();
+ }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Proscenium: (" << proscenium[0] << ", " << proscenium[1] << ", " << proscenium[2] << ", "
+ << proscenium[3] << ")" << endl;
+ }
+}
+
+real OccluderSource::averageOccluderArea()
+{
+ real area = 0.0;
+ unsigned numFaces = 0;
+ for (begin(); isValid(); next()) {
+ Vec3r min, max;
+ cachedPolygon.getBBox(min, max);
+ area += (max[0] - min[0]) * (max[1] - min[1]);
+ ++numFaces;
+ }
+ area /= numFaces;
+ return area;
+}
diff --git a/source/blender/freestyle/intern/view_map/OccluderSource.h b/source/blender/freestyle/intern/view_map/OccluderSource.h
new file mode 100644
index 00000000000..14f8f54fa1a
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/OccluderSource.h
@@ -0,0 +1,76 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_OCCLUDER_SOURCE_H__
+#define __FREESTYLE_OCCLUDER_SOURCE_H__
+
+/** \file blender/freestyle/intern/view_map/OccluderSource.h
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2010-12-21
+ */
+
+#include "../geometry/GridHelpers.h"
+
+#include "../winged_edge/WEdge.h"
+
+class OccluderSource
+{
+ // Disallow copying and assignment
+ OccluderSource(const OccluderSource& other);
+ OccluderSource& operator=(const OccluderSource& other);
+
+public:
+ OccluderSource(const GridHelpers::Transform& transform, WingedEdge& we);
+ virtual ~OccluderSource();
+
+ void begin();
+ virtual bool next();
+ bool isValid();
+
+ WFace *getWFace();
+ Polygon3r getCameraSpacePolygon();
+ Polygon3r& getGridSpacePolygon();
+
+ virtual void getOccluderProscenium(real proscenium[4]);
+ virtual real averageOccluderArea();
+
+protected:
+ WingedEdge& wingedEdge;
+ vector<WShape*>::const_iterator currentShape, shapesEnd;
+ vector<WFace*>::const_iterator currentFace, facesEnd;
+
+ bool valid;
+
+ Polygon3r cachedPolygon;
+ const GridHelpers::Transform& transform;
+
+ void buildCachedPolygon();
+};
+
+#endif // __FREESTYLE_OCCLUDER_SOURCE_H__
diff --git a/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp b/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp
new file mode 100644
index 00000000000..10c6265ebb4
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp
@@ -0,0 +1,123 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/Pow23GridDensityProvider.cpp
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2011-2-8
+ */
+
+#include "Pow23GridDensityProvider.h"
+
+#include "BKE_global.h"
+
+Pow23GridDensityProvider::Pow23GridDensityProvider(OccluderSource& source, const real proscenium[4], unsigned numFaces)
+: GridDensityProvider(source), numFaces(numFaces)
+{
+ initialize (proscenium);
+}
+
+Pow23GridDensityProvider::Pow23GridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform, unsigned numFaces)
+: GridDensityProvider(source), numFaces(numFaces)
+{
+ real proscenium[4];
+ calculateQuickProscenium(transform, bbox, proscenium);
+
+ initialize (proscenium);
+}
+
+Pow23GridDensityProvider::Pow23GridDensityProvider(OccluderSource& source, unsigned numFaces)
+: GridDensityProvider(source), numFaces(numFaces)
+{
+ real proscenium[4];
+ calculateOptimalProscenium(source, proscenium);
+
+ initialize (proscenium);
+}
+
+Pow23GridDensityProvider::~Pow23GridDensityProvider () {}
+
+void Pow23GridDensityProvider::initialize(const real proscenium[4])
+{
+ float prosceniumWidth = (proscenium[1] - proscenium[0]);
+ float prosceniumHeight = (proscenium[3] - proscenium[2]);
+ real cellArea = prosceniumWidth * prosceniumHeight / pow(numFaces, 2.0f / 3.0f);
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << prosceniumWidth << " x " << prosceniumHeight << " grid with cells of area " << cellArea << "." << endl;
+ }
+
+ _cellSize = sqrt(cellArea);
+ // Now we know how many cells make each side of our grid
+ _cellsX = ceil(prosceniumWidth / _cellSize);
+ _cellsY = ceil(prosceniumHeight / _cellSize);
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << _cellsX << "x" << _cellsY << " cells of size " << _cellSize << " square." << endl;
+ }
+
+ // Make sure the grid exceeds the proscenium by a small amount
+ float safetyZone = 0.1;
+ if (_cellsX * _cellSize < prosceniumWidth * (1.0 + safetyZone)) {
+ _cellsX = prosceniumWidth * (1.0 + safetyZone) / _cellSize;
+ }
+ if (_cellsY * _cellSize < prosceniumHeight * (1.0 + safetyZone)) {
+ _cellsY = prosceniumHeight * (1.0 + safetyZone) / _cellSize;
+ }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << _cellsX << "x" << _cellsY << " cells of size " << _cellSize << " square." << endl;
+ }
+
+ // Find grid origin
+ _cellOrigin[0] = ((proscenium[0] + proscenium[1]) / 2.0) - (_cellsX / 2.0) * _cellSize;
+ _cellOrigin[1] = ((proscenium[2] + proscenium[3]) / 2.0) - (_cellsY / 2.0) * _cellSize;
+}
+
+Pow23GridDensityProviderFactory::Pow23GridDensityProviderFactory(unsigned numFaces)
+: numFaces(numFaces)
+{
+}
+
+Pow23GridDensityProviderFactory::~Pow23GridDensityProviderFactory () {}
+
+auto_ptr<GridDensityProvider>
+Pow23GridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const real proscenium[4])
+{
+ return auto_ptr<GridDensityProvider>(new Pow23GridDensityProvider(source, proscenium, numFaces));
+}
+
+auto_ptr<GridDensityProvider>
+Pow23GridDensityProviderFactory::newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform)
+{
+ return auto_ptr<GridDensityProvider>(new Pow23GridDensityProvider(source, bbox, transform, numFaces));
+}
+
+auto_ptr<GridDensityProvider> Pow23GridDensityProviderFactory::newGridDensityProvider(OccluderSource& source)
+{
+ return auto_ptr<GridDensityProvider>(new Pow23GridDensityProvider(source, numFaces));
+}
diff --git a/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.h b/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.h
new file mode 100644
index 00000000000..0e26793cec7
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/Pow23GridDensityProvider.h
@@ -0,0 +1,75 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_POW_23_GRID_DENSITY_PROVIDER_H__
+#define __FREESTYLE_POW_23_GRID_DENSITY_PROVIDER_H__
+
+/** \file blender/freestyle/intern/view_map/Pow23GridDensityProvider.h
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2011-2-8
+ */
+
+#include "GridDensityProvider.h"
+
+class Pow23GridDensityProvider : public GridDensityProvider
+{
+ // Disallow copying and assignment
+ Pow23GridDensityProvider(const Pow23GridDensityProvider& other);
+ Pow23GridDensityProvider& operator=(const Pow23GridDensityProvider& other);
+
+public:
+ Pow23GridDensityProvider(OccluderSource& source, const real proscenium[4], unsigned numFaces);
+ Pow23GridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox, const GridHelpers::Transform& transform,
+ unsigned numFaces);
+ Pow23GridDensityProvider(OccluderSource& source, unsigned numFaces);
+ virtual ~Pow23GridDensityProvider();
+
+protected:
+ unsigned numFaces;
+
+private:
+ void initialize(const real proscenium[4]);
+};
+
+class Pow23GridDensityProviderFactory : public GridDensityProviderFactory
+{
+public:
+ Pow23GridDensityProviderFactory(unsigned numFaces);
+ ~Pow23GridDensityProviderFactory();
+
+ auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const real proscenium[4]);
+ auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source, const BBox<Vec3r>& bbox,
+ const GridHelpers::Transform& transform);
+ auto_ptr<GridDensityProvider> newGridDensityProvider(OccluderSource& source);
+
+protected:
+ unsigned numFaces;
+};
+
+#endif // __FREESTYLE_POW_23_GRID_DENSITY_PROVIDER_H__
diff --git a/source/blender/freestyle/intern/view_map/Silhouette.cpp b/source/blender/freestyle/intern/view_map/Silhouette.cpp
new file mode 100644
index 00000000000..104040fd2a5
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/Silhouette.cpp
@@ -0,0 +1,414 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/Silhouette.cpp
+ * \ingroup freestyle
+ * \brief Classes to define a silhouette structure
+ * \author Stephane Grabli
+ * \date 25/03/2002
+ */
+
+#include "Silhouette.h"
+#include "ViewMap.h"
+
+/**********************************/
+/* */
+/* */
+/* SVertex */
+/* */
+/* */
+/**********************************/
+
+Nature::VertexNature SVertex::getNature() const
+{
+ Nature::VertexNature nature = Nature::S_VERTEX;
+ if (_pViewVertex)
+ nature |= _pViewVertex->getNature();
+ return nature;
+}
+
+SVertex *SVertex::castToSVertex()
+{
+ return this;
+}
+
+ViewVertex *SVertex::castToViewVertex()
+{
+ return _pViewVertex;
+}
+
+NonTVertex *SVertex::castToNonTVertex()
+{
+ return dynamic_cast<NonTVertex*>(_pViewVertex);
+}
+
+TVertex *SVertex::castToTVertex()
+{
+ return dynamic_cast<TVertex*>(_pViewVertex);
+}
+
+float SVertex::shape_importance() const
+{
+ return shape()->importance();
+}
+
+#if 0
+Material SVertex::material() const
+{
+ return _Shape->material();
+}
+#endif
+
+Id SVertex::shape_id() const
+{
+ return _Shape->getId();
+}
+
+const SShape *SVertex::shape() const
+{
+ return _Shape;
+}
+
+const int SVertex::qi() const
+{
+ if (getNature() & Nature::T_VERTEX)
+ Exception::raiseException();
+ return (_FEdges[0])->qi();
+}
+
+occluder_container::const_iterator SVertex::occluders_begin() const
+{
+ if (getNature() & Nature::T_VERTEX)
+ Exception::raiseException();
+ return (_FEdges[0])->occluders_begin();
+}
+
+occluder_container::const_iterator SVertex::occluders_end() const
+{
+ if (getNature() & Nature::T_VERTEX)
+ Exception::raiseException();
+ return (_FEdges[0])->occluders_end();
+}
+
+bool SVertex::occluders_empty() const
+{
+ if (getNature() & Nature::T_VERTEX)
+ Exception::raiseException();
+ return (_FEdges[0])->occluders_empty();
+}
+
+int SVertex::occluders_size() const
+{
+ if (getNature() & Nature::T_VERTEX)
+ Exception::raiseException();
+ return (_FEdges[0])->occluders_size();
+}
+
+const Polygon3r& SVertex::occludee() const
+{
+ if (getNature() & Nature::T_VERTEX)
+ Exception::raiseException();
+ return (_FEdges[0])->occludee();
+}
+
+const SShape *SVertex::occluded_shape() const
+{
+ if (getNature() & Nature::T_VERTEX)
+ Exception::raiseException();
+ return (_FEdges[0])->occluded_shape();
+}
+
+const bool SVertex::occludee_empty() const
+{
+ if (getNature() & Nature::T_VERTEX)
+ Exception::raiseException();
+ return (_FEdges[0])->occludee_empty();
+}
+
+real SVertex::z_discontinuity() const
+{
+ if (getNature() & Nature::T_VERTEX)
+ Exception::raiseException();
+ return (_FEdges[0])->z_discontinuity();
+}
+
+FEdge *SVertex::fedge()
+{
+ if (getNature() & Nature::T_VERTEX)
+ return NULL;
+ return _FEdges[0];
+}
+
+FEdge *SVertex::getFEdge(Interface0D& inter)
+{
+ FEdge *result = NULL;
+ SVertex *iVertexB = dynamic_cast<SVertex*>(&inter);
+ if (!iVertexB)
+ return result;
+ vector<FEdge*>::const_iterator fe = _FEdges.begin(), feend = _FEdges.end();
+ for (; fe != feend; ++fe) {
+ if ((((*fe)->vertexA() == this) && ((*fe)->vertexB() == iVertexB)) ||
+ (((*fe)->vertexB() == this) && ((*fe)->vertexA() == iVertexB)))
+ result = (*fe);
+ }
+ if ((result == 0) && (getNature() & Nature::T_VERTEX)) {
+ SVertex *brother;
+ ViewVertex *vvertex = viewvertex();
+ TVertex *tvertex = dynamic_cast<TVertex*>(vvertex);
+ if (tvertex) {
+ brother = tvertex->frontSVertex();
+ if (this == brother)
+ brother = tvertex->backSVertex();
+ const vector<FEdge*>& fedges = brother->fedges();
+ for (fe = fedges.begin(), feend = fedges.end(); fe != feend; ++fe) {
+ if ((((*fe)->vertexA() == brother) && ((*fe)->vertexB() == iVertexB)) ||
+ (((*fe)->vertexB() == brother) && ((*fe)->vertexA() == iVertexB)))
+ result = (*fe);
+ }
+ }
+ }
+ if ((result == 0) && (iVertexB->getNature() & Nature::T_VERTEX)) {
+ SVertex *brother;
+ ViewVertex *vvertex = iVertexB->viewvertex();
+ TVertex *tvertex = dynamic_cast<TVertex*>(vvertex);
+ if (tvertex) {
+ brother = tvertex->frontSVertex();
+ if (iVertexB == brother)
+ brother = tvertex->backSVertex();
+ for (fe = _FEdges.begin(), feend = _FEdges.end(); fe != feend; ++fe) {
+ if ((((*fe)->vertexA() == this) && ((*fe)->vertexB() == brother)) ||
+ (((*fe)->vertexB() == this) && ((*fe)->vertexA() == brother)))
+ result = (*fe);
+ }
+ }
+ }
+
+ return result;
+}
+
+
+/**********************************/
+/* */
+/* */
+/* FEdge */
+/* */
+/* */
+/**********************************/
+
+
+int FEdge::viewedge_nature() const
+{
+ return _ViewEdge->getNature();
+}
+
+#if 0
+float FEdge::viewedge_length() const
+{
+ return _ViewEdge->viewedge_length();
+}
+#endif
+
+const SShape *FEdge::occluded_shape() const
+{
+ ViewShape *aShape = _ViewEdge->aShape();
+ if (aShape == 0)
+ return 0;
+ return aShape->sshape();
+}
+
+float FEdge::shape_importance() const
+{
+ return _VertexA->shape()->importance();
+}
+
+int FEdge::invisibility() const
+{
+ return _ViewEdge->qi();
+}
+
+occluder_container::const_iterator FEdge::occluders_begin() const
+{
+ return _ViewEdge->occluders_begin();
+}
+
+occluder_container::const_iterator FEdge::occluders_end() const
+{
+ return _ViewEdge->occluders_end();
+}
+
+bool FEdge::occluders_empty() const
+{
+ return _ViewEdge->occluders_empty();
+}
+
+int FEdge::occluders_size() const
+{
+ return _ViewEdge->occluders_size();
+}
+
+const bool FEdge::occludee_empty() const
+{
+ return _ViewEdge->occludee_empty();
+}
+
+Id FEdge::shape_id() const
+{
+ return _VertexA->shape()->getId();
+}
+
+const SShape *FEdge::shape() const
+{
+ return _VertexA->shape();
+}
+
+real FEdge::z_discontinuity() const
+{
+ if (!(getNature() & Nature::SILHOUETTE) && !(getNature() & Nature::BORDER)) {
+ return 0;
+ }
+
+ BBox<Vec3r> box = ViewMap::getInstance()->getScene3dBBox();
+
+ Vec3r bbox_size_vec(box.getMax() - box.getMin());
+ real bboxsize = bbox_size_vec.norm();
+ if (occludee_empty()) {
+ //return FLT_MAX;
+ return 1.0;
+ //return bboxsize;
+ }
+
+#if 0
+ real result;
+ z_discontinuity_functor<SVertex> _functor;
+ Evaluate<SVertex, z_discontinuity_functor<SVertex> >(&_functor, iCombination, result);
+#endif
+ Vec3r middle((_VertexB->point3d() - _VertexA->point3d()));
+ middle /= 2;
+ Vec3r disc_vec(middle - _occludeeIntersection);
+ real res = disc_vec.norm() / bboxsize;
+
+ return res;
+ //return fabs((middle.z() - _occludeeIntersection.z()));
+}
+
+#if 0
+float FEdge::local_average_depth(int iCombination ) const
+{
+ float result;
+ local_average_depth_functor<SVertex> functor;
+ Evaluate(&functor, iCombination, result);
+
+ return result;
+}
+
+float FEdge::local_depth_variance(int iCombination ) const
+{
+ float result;
+
+ local_depth_variance_functor<SVertex> functor;
+
+ Evaluate(&functor, iCombination, result);
+
+ return result;
+}
+
+real FEdge::local_average_density( float sigma, int iCombination) const
+{
+ float result;
+
+ density_functor<SVertex> functor(sigma);
+
+ Evaluate(&functor, iCombination, result);
+
+ return result;
+}
+
+Vec3r FEdge::normal(int& oException /* = Exception::NO_EXCEPTION */)
+{
+ Vec3r Na = _VertexA->normal(oException);
+ if (oException != Exception::NO_EXCEPTION)
+ return Na;
+ Vec3r Nb = _VertexB->normal(oException);
+ if (oException != Exception::NO_EXCEPTION)
+ return Nb;
+ return (Na + Nb) / 2.0;
+}
+
+Vec3r FEdge::curvature2d_as_vector(int iCombination) const
+{
+ Vec3r result;
+ curvature2d_as_vector_functor<SVertex> _functor;
+ Evaluate<Vec3r, curvature2d_as_vector_functor<SVertex> >(&_functor, iCombination, result);
+ return result;
+}
+
+real FEdge::curvature2d_as_angle(int iCombination) const
+{
+ real result;
+ curvature2d_as_angle_functor<SVertex> _functor;
+ Evaluate<real, curvature2d_as_angle_functor<SVertex> >(&_functor, iCombination, result);
+ return result;
+}
+#endif
+
+/**********************************/
+/* */
+/* */
+/* FEdgeSharp */
+/* */
+/* */
+/**********************************/
+
+#if 0
+Material FEdge::material() const
+{
+ return _VertexA->shape()->material();
+}
+#endif
+
+const FrsMaterial& FEdgeSharp::aFrsMaterial() const
+{
+ return _VertexA->shape()->frs_material(_aFrsMaterialIndex);
+}
+
+const FrsMaterial& FEdgeSharp::bFrsMaterial() const
+{
+ return _VertexA->shape()->frs_material(_bFrsMaterialIndex);
+}
+
+/**********************************/
+/* */
+/* */
+/* FEdgeSmooth */
+/* */
+/* */
+/**********************************/
+
+const FrsMaterial& FEdgeSmooth::frs_material() const
+{
+ return _VertexA->shape()->frs_material(_FrsMaterialIndex);
+}
diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h
new file mode 100644
index 00000000000..2efe111add5
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/Silhouette.h
@@ -0,0 +1,1876 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_SILHOUETTE_H__
+#define __FREESTYLE_SILHOUETTE_H__
+
+/** \file blender/freestyle/intern/view_map/Silhouette.h
+ * \ingroup freestyle
+ * \brief Classes to define a silhouette structure
+ * \author Stephane Grabli
+ * \date 25/03/2002
+ */
+
+#include <float.h>
+#include <iostream>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "Interface0D.h"
+#include "Interface1D.h"
+
+#include "../geometry/BBox.h"
+#include "../geometry/Geom.h"
+#include "../geometry/Polygon.h"
+
+#include "../scene_graph/FrsMaterial.h"
+
+#include "../system/Exception.h"
+#include "../system/FreestyleConfig.h"
+
+#include "../winged_edge/Curvature.h"
+
+using namespace std;
+using namespace Geometry;
+
+class ViewShape;
+typedef vector<ViewShape*> occluder_container;
+
+/**********************************/
+/* */
+/* */
+/* SVertex */
+/* */
+/* */
+/**********************************/
+
+class FEdge;
+class ViewVertex;
+class SShape;
+
+/*! Class to define a vertex of the embedding. */
+class LIB_VIEW_MAP_EXPORT SVertex : public Interface0D
+{
+public: // Implementation of Interface0D
+ /*! Returns the string "SVertex" .*/
+ virtual string getExactTypeName() const
+ {
+ return "SVertex";
+ }
+
+ // Data access methods
+ /*! Returns the 3D x coordinate of the vertex .*/
+ virtual real getX() const
+ {
+ return _Point3D.x();
+ }
+
+ /*! Returns the 3D y coordinate of the vertex .*/
+ virtual real getY() const
+ {
+ return _Point3D.y();
+ }
+
+ /*! Returns the 3D z coordinate of the vertex .*/
+ virtual real getZ() const
+ {
+ return _Point3D.z();
+ }
+
+ /*! Returns the 3D point. */
+ virtual Vec3f getPoint3D() const
+ {
+ return _Point3D;
+ }
+
+ /*! Returns the projected 3D x coordinate of the vertex .*/
+ virtual real getProjectedX() const
+ {
+ return _Point2D.x();
+ }
+
+ /*! Returns the projected 3D y coordinate of the vertex .*/
+ virtual real getProjectedY() const
+ {
+ return _Point2D.y();
+ }
+
+ /*! Returns the projected 3D z coordinate of the vertex .*/
+ virtual real getProjectedZ() const
+ {
+ return _Point2D.z();
+ }
+
+ /*! Returns the 2D point. */
+ virtual Vec2f getPoint2D() const
+ {
+ return Vec2f((float)_Point2D.x(), (float)_Point2D.y());
+ }
+
+ /*! Returns the FEdge that lies between this Svertex and the Interface0D given as argument. */
+ virtual FEdge *getFEdge(Interface0D&);
+
+ /*! Returns the Id of the vertex .*/
+ virtual Id getId() const
+ {
+ return _Id;
+ }
+
+ /*! Returns the nature of the vertex .*/
+ virtual Nature::VertexNature getNature() const;
+
+ /*! Cast the Interface0D in SVertex if it can be. */
+ virtual SVertex *castToSVertex();
+
+ /*! Cast the Interface0D in ViewVertex if it can be. */
+ virtual ViewVertex *castToViewVertex();
+
+ /*! Cast the Interface0D in NonTVertex if it can be. */
+ virtual NonTVertex *castToNonTVertex();
+
+ /*! Cast the Interface0D in TVertex if it can be. */
+ virtual TVertex *castToTVertex();
+
+public:
+ typedef vector<FEdge*> fedges_container;
+
+private:
+ Id _Id;
+ Vec3r _Point3D;
+ Vec3r _Point2D;
+ set<Vec3r> _Normals;
+ vector<FEdge*> _FEdges; // the edges containing this vertex
+ SShape *_Shape; // the shape to which belongs the vertex
+ ViewVertex *_pViewVertex; // The associated viewvertex, in case there is one.
+ real _curvatureFredo;
+ Vec2r _directionFredo;
+ CurvatureInfo *_curvature_info;
+
+public:
+ /*! A field that can be used by the user to store any data.
+ * This field must be reseted afterwards using ResetUserData().
+ */
+ void *userdata;
+
+ /*! Default constructor.*/
+ inline SVertex()
+ {
+ _Id = 0;
+ userdata = NULL;
+ _Shape = NULL;
+ _pViewVertex = 0;
+ _curvature_info = 0;
+ }
+
+ /*! Builds a SVertex from 3D coordinates and an Id. */
+ inline SVertex(const Vec3r &iPoint3D, const Id& id)
+ {
+ _Point3D = iPoint3D;
+ _Id = id;
+ userdata = NULL;
+ _Shape = NULL;
+ _pViewVertex = 0;
+ _curvature_info = 0;
+ }
+
+ /*! Copy constructor. */
+ inline SVertex(SVertex& iBrother)
+ {
+ _Id = iBrother._Id;
+ _Point3D = iBrother.point3D();
+ _Point2D = iBrother.point2D();
+ _Normals = iBrother._Normals;
+ _FEdges = iBrother.fedges();
+ _Shape = iBrother.shape();
+ _pViewVertex = iBrother._pViewVertex;
+ if (!(iBrother._curvature_info))
+ _curvature_info = 0;
+ else
+ _curvature_info = new CurvatureInfo(*(iBrother._curvature_info));
+ iBrother.userdata = this;
+ userdata = 0;
+ }
+
+ /*! Destructor. */
+ virtual ~SVertex()
+ {
+ if (_curvature_info)
+ delete _curvature_info;
+ }
+
+ /*! Cloning method. */
+ virtual SVertex *duplicate()
+ {
+ SVertex *clone = new SVertex(*this);
+ return clone;
+ }
+
+ /*! operator == */
+ virtual bool operator==(const SVertex& iBrother)
+ {
+ return ((_Point2D == iBrother._Point2D) && (_Point3D == iBrother._Point3D));
+ }
+
+ /* accessors */
+ inline const Vec3r& point3D() const
+ {
+ return _Point3D;
+ }
+
+ inline const Vec3r& point2D() const
+ {
+ return _Point2D;
+ }
+
+ /*! Returns the set of normals for this Vertex.
+ * In a smooth surface, a vertex has exactly one normal.
+ * In a sharp surface, a vertex can have any number of normals.
+ */
+ inline set<Vec3r> normals()
+ {
+ return _Normals;
+ }
+
+ /*! Returns the number of different normals for this vertex. */
+ inline unsigned normalsSize() const
+ {
+ return _Normals.size();
+ }
+
+ inline const vector<FEdge*>& fedges()
+ {
+ return _FEdges;
+ }
+
+ inline fedges_container::iterator fedges_begin()
+ {
+ return _FEdges.begin();
+ }
+
+ inline fedges_container::iterator fedges_end()
+ {
+ return _FEdges.end();
+ }
+
+ inline SShape *shape()
+ {
+ return _Shape;
+ }
+
+ inline real z() const
+ {
+ return _Point2D[2];
+ }
+
+ /*! If this SVertex is also a ViewVertex, this method returns a pointer onto this ViewVertex.
+ * 0 is returned otherwise.
+ */
+ inline ViewVertex *viewvertex()
+ {
+ return _pViewVertex;
+ }
+
+ /*! modifiers */
+ /*! Sets the 3D coordinates of the SVertex. */
+ inline void setPoint3D(const Vec3r &iPoint3D)
+ {
+ _Point3D = iPoint3D;
+ }
+
+ /*! Sets the 3D projected coordinates of the SVertex. */
+ inline void setPoint2D(const Vec3r &iPoint2D)
+ {
+ _Point2D = iPoint2D;
+ }
+
+ /*! Adds a normal to the Svertex's set of normals. If the same normal is already in the set, nothing changes. */
+ inline void AddNormal(const Vec3r& iNormal)
+ {
+ _Normals.insert(iNormal); // if iNormal in the set already exists, nothing is done
+ }
+
+ void setCurvatureInfo(CurvatureInfo *ci)
+ {
+ if (_curvature_info) // Q. is this an error condition? (T.K. 02-May-2011)
+ delete _curvature_info;
+ _curvature_info = ci;
+ }
+
+ const CurvatureInfo *getCurvatureInfo() const
+ {
+ return _curvature_info;
+ }
+
+ /* Fredo's normal and curvature*/
+ void setCurvatureFredo(real c)
+ {
+ _curvatureFredo = c;
+ }
+
+ void setDirectionFredo(Vec2r d)
+ {
+ _directionFredo = d;
+ }
+
+ real curvatureFredo ()
+ {
+ return _curvatureFredo;
+ }
+
+ const Vec2r directionFredo ()
+ {
+ return _directionFredo;
+ }
+
+ /*! Sets the Id */
+ inline void setId(const Id& id)
+ {
+ _Id = id;
+ }
+
+ inline void setFEdges(const vector<FEdge*>& iFEdges)
+ {
+ _FEdges = iFEdges;
+ }
+
+ inline void setShape(SShape *iShape)
+ {
+ _Shape = iShape;
+ }
+
+ inline void setViewVertex(ViewVertex *iViewVertex)
+ {
+ _pViewVertex = iViewVertex;
+ }
+
+ /*! Add an FEdge to the list of edges emanating from this SVertex. */
+ inline void AddFEdge(FEdge *iFEdge)
+ {
+ _FEdges.push_back(iFEdge);
+ }
+
+ /* replaces edge 1 by edge 2 in the list of edges */
+ inline void Replace(FEdge *e1, FEdge *e2)
+ {
+ vector<FEdge*>::iterator insertedfe;
+ for (vector<FEdge*>::iterator fe = _FEdges.begin(),fend = _FEdges.end(); fe != fend; fe++) {
+ if ((*fe) == e1) {
+ insertedfe = _FEdges.insert(fe, e2);// inserts e2 before fe.
+ // returns an iterator pointing toward e2. fe is invalidated.
+ // we want to remove e1, but we can't use fe anymore:
+ ++insertedfe; // insertedfe points now to e1
+ _FEdges.erase(insertedfe);
+ return;
+ }
+ }
+ }
+
+public:
+ /* Information access interface */
+ FEdge *fedge(); // for non T vertex
+
+ inline const Vec3r& point2d() const
+ {
+ return point2D();
+ }
+
+ inline const Vec3r& point3d() const
+ {
+ return point3D();
+ }
+
+ inline Vec3r normal() const
+ {
+ if (_Normals.size() == 1)
+ return (*(_Normals.begin()));
+ Exception::raiseException();
+ return *(_Normals.begin());
+ }
+
+ //Material material() const ;
+ Id shape_id() const;
+ const SShape *shape() const;
+ float shape_importance() const;
+
+ const int qi() const;
+ occluder_container::const_iterator occluders_begin() const;
+ occluder_container::const_iterator occluders_end() const;
+ bool occluders_empty() const;
+ int occluders_size() const;
+ const Polygon3r& occludee() const;
+ const SShape *occluded_shape() const;
+ const bool occludee_empty() const;
+ real z_discontinuity() const;
+#if 0
+ inline float local_average_depth() const;
+ inline float local_depth_variance() const;
+ inline real local_average_density(float sigma = 2.3f) const;
+ inline Vec3r shaded_color() const;
+ inline Vec3r orientation2d() const;
+ inline Vec3r orientation3d() const;
+ inline Vec3r curvature2d_as_vector() const;
+ /*! angle in radians */
+ inline real curvature2d_as_angle() const;
+#endif
+};
+
+/**********************************/
+/* */
+/* */
+/* FEdge */
+/* */
+/* */
+/**********************************/
+
+class ViewEdge;
+
+/*! Base Class for feature edges.
+ * This FEdge can represent a silhouette, a crease, a ridge/valley, a border or a suggestive contour.
+ * For silhouettes, the FEdge is oriented such as, the visible face lies on the left of the edge.
+ * For borders, the FEdge is oriented such as, the face lies on the left of the edge.
+ * An FEdge can represent an initial edge of the mesh or runs accross a face of the initial mesh depending
+ * on the smoothness or sharpness of the mesh.
+ * This class is specialized into a smooth and a sharp version since their properties slightly vary from
+ * one to the other.
+ */
+class LIB_VIEW_MAP_EXPORT FEdge : public Interface1D
+{
+public: // Implementation of Interface0D
+ /*! Returns the string "FEdge". */
+ virtual string getExactTypeName() const
+ {
+ return "FEdge";
+ }
+
+ // Data access methods
+
+ /*! Returns the 2D length of the FEdge. */
+ virtual real getLength2D() const
+ {
+ if (!_VertexA || !_VertexB)
+ return 0;
+ return (_VertexB->getPoint2D() - _VertexA->getPoint2D()).norm();
+ }
+
+ /*! Returns the Id of the FEdge. */
+ virtual Id getId() const
+ {
+ return _Id;
+ }
+
+public:
+ // An edge can only be of one kind (SILHOUETTE or BORDER, etc...)
+ // For an multi-nature edge there must be several different FEdge.
+ // DEBUG:
+ // Vec3r A;
+ // Vec3r u;
+ // vector<Polygon3r> _Occludees;
+ // Vec3r intersection;
+ // vector<Vec3i> _Cells;
+
+protected:
+ SVertex *_VertexA;
+ SVertex *_VertexB;
+ Id _Id;
+ Nature::EdgeNature _Nature;
+ //vector<Polygon3r> _Occluders; // visibility // NOT HANDLED BY THE COPY CONSTRUCTOR!!
+
+ FEdge *_NextEdge; // next edge on the chain
+ FEdge *_PreviousEdge;
+ ViewEdge *_ViewEdge;
+ // Sometimes we need to deport the visibility computation onto another edge. For example the exact edges use
+ // edges of the mesh to compute their visibility
+
+ Polygon3r _aFace; // The occluded face which lies on the right of a silhouette edge
+ Vec3r _occludeeIntersection;
+ bool _occludeeEmpty;
+
+ bool _isSmooth;
+
+ bool _isInImage;
+
+public:
+ /*! A field that can be used by the user to store any data.
+ * This field must be reseted afterwards using ResetUserData().
+ */
+ void *userdata;
+
+ /*! Default constructor */
+ inline FEdge()
+ {
+ userdata = NULL;
+ _VertexA = NULL;
+ _VertexB = NULL;
+ _Nature = Nature::NO_FEATURE;
+ _NextEdge = NULL;
+ _PreviousEdge = NULL;
+ _ViewEdge = NULL;
+ //_hasVisibilityPoint = false;
+ _occludeeEmpty = true;
+ _isSmooth = false;
+ _isInImage = true;
+ }
+
+ /*! Builds an FEdge going from vA to vB. */
+ inline FEdge(SVertex *vA, SVertex *vB)
+ {
+ userdata = NULL;
+ _VertexA = vA;
+ _VertexB = vB;
+ _Nature = Nature::NO_FEATURE;
+ _NextEdge = NULL;
+ _PreviousEdge = NULL;
+ _ViewEdge = NULL;
+ //_hasVisibilityPoint = false;
+ _occludeeEmpty = true;
+ _isSmooth = false;
+ _isInImage = true;
+ }
+
+ /*! Copy constructor */
+ inline FEdge(FEdge& iBrother)
+ {
+ _VertexA = iBrother.vertexA();
+ _VertexB = iBrother.vertexB();
+ _NextEdge = iBrother.nextEdge();
+ _PreviousEdge = iBrother._PreviousEdge;
+ _Nature = iBrother.getNature();
+ _Id = iBrother._Id;
+ _ViewEdge = iBrother._ViewEdge;
+ //_hasVisibilityPoint = iBrother._hasVisibilityPoint;
+ //_VisibilityPointA = iBrother._VisibilityPointA;
+ //_VisibilityPointB = iBrother._VisibilityPointB;
+ _aFace = iBrother._aFace;
+ _occludeeEmpty = iBrother._occludeeEmpty;
+ _isSmooth = iBrother._isSmooth;
+ _isInImage = iBrother._isInImage;
+ iBrother.userdata = this;
+ userdata = 0;
+ }
+
+ /*! Destructor */
+ virtual ~FEdge() {}
+
+ /*! Cloning method. */
+ virtual FEdge *duplicate()
+ {
+ FEdge *clone = new FEdge(*this);
+ return clone;
+ }
+
+ /* accessors */
+ /*! Returns the first SVertex. */
+ inline SVertex *vertexA()
+ {
+ return _VertexA;
+ }
+
+ /*! Returns the second SVertex. */
+ inline SVertex* vertexB()
+ {
+ return _VertexB;
+ }
+
+ /*! Returns the first SVertex if i=0, the seccond SVertex if i=1. */
+ inline SVertex* operator[](const unsigned short int& i) const
+ {
+ return (i % 2 == 0) ? _VertexA : _VertexB;
+ }
+
+ /*! Returns the nature of the FEdge. */
+ inline Nature::EdgeNature getNature() const
+ {
+ return _Nature;
+ }
+
+ /*! Returns the FEdge following this one in the ViewEdge.
+ * If this FEdge is the last of the ViewEdge, 0 is returned.
+ */
+ inline FEdge *nextEdge()
+ {
+ return _NextEdge;
+ }
+
+ /*! Returns the Edge preceding this one in the ViewEdge.
+ * If this FEdge is the first one of the ViewEdge, 0 is returned.
+ */
+ inline FEdge *previousEdge()
+ {
+ return _PreviousEdge;
+ }
+
+ inline SShape *shape()
+ {
+ return _VertexA->shape();
+ }
+
+#if 0
+ inline int invisibility() const
+ {
+ return _Occluders.size();
+ }
+#endif
+
+ int invisibility() const;
+
+#if 0
+ inline const vector<Polygon3r>& occluders() const
+ {
+ return _Occluders;
+ }
+#endif
+
+ /*! Returns a pointer to the ViewEdge to which this FEdge belongs to. */
+ inline ViewEdge *viewedge() const
+ {
+ return _ViewEdge;
+ }
+
+ inline Vec3r center3d()
+ {
+ return Vec3r((_VertexA->point3D() + _VertexB->point3D()) / 2.0);
+ }
+
+ inline Vec3r center2d()
+ {
+ return Vec3r((_VertexA->point2D() + _VertexB->point2D()) / 2.0);
+ }
+
+#if 0
+ inline bool hasVisibilityPoint() const
+ {
+ return _hasVisibilityPoint;
+ }
+
+ inline Vec3r visibilityPointA() const
+ {
+ return _VisibilityPointA;
+ }
+
+ inline Vec3r visibilityPointB() const
+ {
+ return _VisibilityPointB;
+ }
+#endif
+
+ inline const Polygon3r& aFace() const
+ {
+ return _aFace;
+ }
+
+ inline const Vec3r& getOccludeeIntersection()
+ {
+ return _occludeeIntersection;
+ }
+
+ inline bool getOccludeeEmpty()
+ {
+ return _occludeeEmpty;
+ }
+
+ /*! Returns true if this FEdge is a smooth FEdge. */
+ inline bool isSmooth() const
+ {
+ return _isSmooth;
+ }
+
+ inline bool isInImage () const
+ {
+ return _isInImage;
+ }
+
+ /* modifiers */
+ /*! Sets the first SVertex. */
+ inline void setVertexA(SVertex *vA)
+ {
+ _VertexA = vA;
+ }
+
+ /*! Sets the second SVertex. */
+ inline void setVertexB(SVertex *vB)
+ {
+ _VertexB = vB;
+ }
+
+ /*! Sets the FEdge Id . */
+ inline void setId(const Id& id)
+ {
+ _Id = id;
+ }
+
+ /*! Sets the pointer to the next FEdge. */
+ inline void setNextEdge(FEdge *iEdge)
+ {
+ _NextEdge = iEdge;
+ }
+
+ /*! Sets the pointer to the previous FEdge. */
+ inline void setPreviousEdge(FEdge *iEdge)
+ {
+ _PreviousEdge = iEdge;
+ }
+
+ /*! Sets the nature of this FEdge. */
+ inline void setNature(Nature::EdgeNature iNature)
+ {
+ _Nature = iNature;
+ }
+
+#if 0
+ inline void AddOccluder(Polygon3r& iPolygon)
+ {
+ _Occluders.push_back(iPolygon);
+ }
+#endif
+
+ /*! Sets the ViewEdge to which this FEdge belongs to. */
+ inline void setViewEdge(ViewEdge *iViewEdge)
+ {
+ _ViewEdge = iViewEdge;
+ }
+
+#if 0
+ inline void setHasVisibilityPoint(bool iBool)
+ {
+ _hasVisibilityPoint = iBool;
+ }
+
+ inline void setVisibilityPointA(const Vec3r& iPoint)
+ {
+ _VisibilityPointA = iPoint;
+ }
+
+ inline void setVisibilityPointB(const Vec3r& iPoint)
+ {
+ _VisibilityPointB = iPoint;
+ }
+#endif
+
+ inline void setaFace(Polygon3r& iFace)
+ {
+ _aFace = iFace;
+ }
+
+ inline void setOccludeeIntersection(const Vec3r& iPoint)
+ {
+ _occludeeIntersection = iPoint;
+ }
+
+ inline void setOccludeeEmpty(bool iempty)
+ {
+ _occludeeEmpty = iempty;
+ }
+
+ /*! Sets the flag telling whether this FEdge is smooth or sharp.
+ * true for Smooth, false for Sharp.
+ */
+ inline void setSmooth(bool iFlag)
+ {
+ _isSmooth = iFlag;
+ }
+
+ inline void setIsInImage (bool iFlag)
+ {
+ _isInImage = iFlag;
+ }
+
+ /* checks whether two FEdge have a common vertex.
+ * Returns a pointer on the common vertex if it exists, NULL otherwise.
+ */
+ static inline SVertex *CommonVertex(FEdge *iEdge1, FEdge *iEdge2)
+ {
+ if ((NULL == iEdge1) || (NULL == iEdge2))
+ return NULL;
+
+ SVertex *sv1 = iEdge1->vertexA();
+ SVertex *sv2 = iEdge1->vertexB();
+ SVertex *sv3 = iEdge2->vertexA();
+ SVertex *sv4 = iEdge2->vertexB();
+
+ if ((sv1 == sv3) || (sv1 == sv4)) {
+ return sv1;
+ }
+ else if ((sv2 == sv3) || (sv2 == sv4)) {
+ return sv2;
+ }
+
+ return NULL;
+ }
+
+ inline const SVertex *min2d() const
+ {
+ if (_VertexA->point2D() < _VertexB->point2D())
+ return _VertexA;
+ else
+ return _VertexB;
+ }
+
+ inline const SVertex *max2d() const
+ {
+ if (_VertexA->point2D() < _VertexB->point2D())
+ return _VertexB;
+ else
+ return _VertexA;
+ }
+
+ /* Information access interface */
+
+ //Material material() const;
+ Id shape_id() const;
+ const SShape *shape() const;
+ float shape_importance() const;
+
+ inline const int qi() const
+ {
+ return invisibility();
+ }
+
+ occluder_container::const_iterator occluders_begin() const;
+ occluder_container::const_iterator occluders_end() const;
+ bool occluders_empty() const;
+ int occluders_size() const;
+
+ inline const Polygon3r& occludee() const
+ {
+ return aFace();
+ }
+
+ const SShape *occluded_shape() const;
+
+#if 0
+ inline const bool occludee_empty() const
+ {
+ return _occludeeEmpty;
+ }
+#endif
+
+ const bool occludee_empty() const;
+ real z_discontinuity() const;
+
+#if 0
+ inline float local_average_depth(int iCombination = 0) const;
+ inline float local_depth_variance(int iCombination = 0) const;
+ inline real local_average_density(float sigma = 2.3f, int iCombination = 0) const;
+ inline Vec3r shaded_color(int iCombination = 0) const {}
+#endif
+
+ int viewedge_nature() const;
+
+ //float viewedge_length() const;
+
+ inline Vec3r orientation2d() const
+ {
+ return Vec3r(_VertexB->point2d() - _VertexA->point2d());
+ }
+
+ inline Vec3r orientation3d() const
+ {
+ return Vec3r(_VertexB->point3d() - _VertexA->point3d());
+ }
+
+#if 0
+ inline real curvature2d() const
+ {
+ return viewedge()->curvature2d((_VertexA->point2d() + _VertexB->point2d()) / 2.0);
+ }
+
+ inline Vec3r curvature2d_as_vector(int iCombination = 0) const;
+
+ /* angle in degrees*/
+ inline real curvature2d_as_angle(int iCombination = 0) const;
+#endif
+
+ // Iterator access (Interface1D)
+ /*! Returns an iterator over the 2 (!) SVertex pointing to the first SVertex. */
+ virtual inline Interface0DIterator verticesBegin();
+
+ /*! Returns an iterator over the 2 (!) SVertex pointing after the last SVertex. */
+ virtual inline Interface0DIterator verticesEnd();
+
+ /*! Returns an iterator over the FEdge points, pointing to the first point. The difference with verticesBegin()
+ * is that here we can iterate over points of the FEdge at a any given sampling.
+ * Indeed, for each iteration, a virtual point is created.
+ * \param t
+ * The sampling with which we want to iterate over points of this FEdge.
+ */
+ virtual inline Interface0DIterator pointsBegin(float t = 0.0f);
+
+ /*! Returns an iterator over the FEdge points, pointing after the last point. The difference with verticesEnd()
+ * is that here we can iterate over points of the FEdge at a any given sampling.
+ * Indeed, for each iteration, a virtual point is created.
+ * \param t
+ * The sampling with which we want to iterate over points of this FEdge.
+ */
+ virtual inline Interface0DIterator pointsEnd(float t = 0.0f);
+};
+
+//
+// SVertexIterator
+//
+/////////////////////////////////////////////////
+
+namespace FEdgeInternal {
+
+class SVertexIterator : public Interface0DIteratorNested
+{
+public:
+ SVertexIterator()
+ {
+ _vertex = NULL;
+ _edge = NULL;
+ }
+
+ SVertexIterator(const SVertexIterator& vi)
+ {
+ _vertex = vi._vertex;
+ _edge = vi._edge;
+ }
+
+ SVertexIterator(SVertex *v, FEdge *edge)
+ {
+ _vertex = v;
+ _edge = edge;
+ }
+
+ SVertexIterator& operator=(const SVertexIterator& vi)
+ {
+ _vertex = vi._vertex;
+ _edge = vi._edge;
+ return *this;
+ }
+
+ virtual string getExactTypeName() const
+ {
+ return "SVertexIterator";
+ }
+
+ virtual SVertex& operator*()
+ {
+ return *_vertex;
+ }
+
+ virtual SVertex *operator->()
+ {
+ return &(operator*());
+ }
+
+ virtual SVertexIterator& operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ virtual SVertexIterator operator++(int)
+ {
+ SVertexIterator ret(*this);
+ increment();
+ return ret;
+ }
+
+ virtual SVertexIterator& operator--()
+ {
+ decrement();
+ return *this;
+ }
+
+ virtual SVertexIterator operator--(int)
+ {
+ SVertexIterator ret(*this);
+ decrement();
+ return ret;
+ }
+
+ virtual int increment()
+ {
+ if (_vertex == _edge->vertexB()) {
+ _vertex = 0;
+ return 0;
+ }
+ _vertex = _edge->vertexB();
+ return 0;
+ }
+
+ virtual int decrement()
+ {
+ if (_vertex == _edge->vertexA()) {
+ _vertex = 0;
+ return 0;
+ }
+ _vertex = _edge->vertexA();
+ return 0;
+ }
+
+ virtual bool isBegin() const
+ {
+ return _vertex == _edge->vertexA();
+ }
+
+ virtual bool isEnd() const
+ {
+ return _vertex == _edge->vertexB();
+ }
+
+ virtual bool operator==(const Interface0DIteratorNested& it) const
+ {
+ const SVertexIterator *it_exact = dynamic_cast<const SVertexIterator*>(&it);
+ if (!it_exact)
+ return false;
+ return ((_vertex == it_exact->_vertex) && (_edge == it_exact->_edge));
+ }
+
+ virtual float t() const
+ {
+ if (_vertex == _edge->vertexA()) {
+ return 0.0f;
+ }
+ return ((float)_edge->getLength2D());
+ }
+ virtual float u() const
+ {
+ if (_vertex == _edge->vertexA()) {
+ return 0.0f;
+ }
+ return 1.0f;
+ }
+
+ virtual SVertexIterator *copy() const
+ {
+ return new SVertexIterator(*this);
+ }
+
+private:
+ SVertex *_vertex;
+ FEdge *_edge;
+};
+
+} // end of namespace FEdgeInternal
+
+// Iterator access (implementation)
+
+Interface0DIterator FEdge::verticesBegin()
+{
+ Interface0DIterator ret(new FEdgeInternal::SVertexIterator(_VertexA, this));
+ return ret;
+}
+
+Interface0DIterator FEdge::verticesEnd()
+{
+ Interface0DIterator ret(new FEdgeInternal::SVertexIterator(0, this));
+ return ret;
+}
+
+Interface0DIterator FEdge::pointsBegin(float t)
+{
+ return verticesBegin();
+}
+
+Interface0DIterator FEdge::pointsEnd(float t)
+{
+ return verticesEnd();
+}
+
+/*! Class defining a sharp FEdge. A Sharp FEdge corresponds to an initial edge of the input mesh.
+ * It can be a silhouette, a crease or a border. If it is a crease edge, then it is borded
+ * by two faces of the mesh. Face a lies on its right whereas Face b lies on its left.
+ * If it is a border edge, then it doesn't have any face on its right, and thus Face a = 0.
+ */
+class LIB_VIEW_MAP_EXPORT FEdgeSharp : public FEdge
+{
+protected:
+ Vec3r _aNormal; // When following the edge, normal of the right face
+ Vec3r _bNormal; // When following the edge, normal of the left face
+ unsigned _aFrsMaterialIndex;
+ unsigned _bFrsMaterialIndex;
+ bool _aFaceMark;
+ bool _bFaceMark;
+
+public:
+ /*! Returns the string "FEdgeSharp" . */
+ virtual string getExactTypeName() const
+ {
+ return "FEdgeSharp";
+ }
+
+ /*! Default constructor. */
+ inline FEdgeSharp() : FEdge()
+ {
+ _aFrsMaterialIndex = _bFrsMaterialIndex = 0;
+ _aFaceMark = _bFaceMark = false;
+ }
+
+ /*! Builds an FEdgeSharp going from vA to vB. */
+ inline FEdgeSharp(SVertex *vA, SVertex *vB) : FEdge(vA, vB)
+ {
+ _aFrsMaterialIndex = _bFrsMaterialIndex = 0;
+ _aFaceMark = _bFaceMark = false;
+ }
+
+ /*! Copy constructor. */
+ inline FEdgeSharp(FEdgeSharp& iBrother) : FEdge(iBrother)
+ {
+ _aNormal = iBrother._aNormal;
+ _bNormal = iBrother._bNormal;
+ _aFrsMaterialIndex = iBrother._aFrsMaterialIndex;
+ _bFrsMaterialIndex = iBrother._bFrsMaterialIndex;
+ _aFaceMark = iBrother._aFaceMark;
+ _bFaceMark = iBrother._bFaceMark;
+ }
+
+ /*! Destructor. */
+ virtual ~FEdgeSharp() {}
+
+ /*! Cloning method. */
+ virtual FEdge *duplicate()
+ {
+ FEdge *clone = new FEdgeSharp(*this);
+ return clone;
+ }
+
+ /*! Returns the normal to the face lying on the right of the FEdge. If this FEdge is a border,
+ * it has no Face on its right and therefore, no normal.
+ */
+ inline const Vec3r& normalA()
+ {
+ return _aNormal;
+ }
+
+ /*! Returns the normal to the face lying on the left of the FEdge. */
+ inline const Vec3r& normalB()
+ {
+ return _bNormal;
+ }
+
+ /*! Returns the index of the material of the face lying on the
+ * right of the FEdge. If this FEdge is a border,
+ * it has no Face on its right and therefore, no material.
+ */
+ inline unsigned aFrsMaterialIndex() const
+ {
+ return _aFrsMaterialIndex;
+ }
+
+ /*! Returns the material of the face lying on the right of the FEdge. If this FEdge is a border,
+ * it has no Face on its right and therefore, no material.
+ */
+ const FrsMaterial& aFrsMaterial() const;
+
+ /*! Returns the index of the material of the face lying on the left of the FEdge. */
+ inline unsigned bFrsMaterialIndex() const
+ {
+ return _bFrsMaterialIndex;
+ }
+
+ /*! Returns the material of the face lying on the left of the FEdge. */
+ const FrsMaterial& bFrsMaterial() const;
+
+ /*! Returns the face mark of the face lying on the right of the FEdge.
+ * If this FEdge is a border, it has no Face on its right and thus false is returned.
+ */
+ inline bool aFaceMark() const
+ {
+ return _aFaceMark;
+ }
+
+ /*! Returns the face mark of the face lying on the left of the FEdge. */
+ inline bool bFaceMark() const
+ {
+ return _bFaceMark;
+ }
+
+ /*! Sets the normal to the face lying on the right of the FEdge. */
+ inline void setNormalA(const Vec3r& iNormal)
+ {
+ _aNormal = iNormal;
+ }
+
+ /*! Sets the normal to the face lying on the left of the FEdge. */
+ inline void setNormalB(const Vec3r& iNormal)
+ {
+ _bNormal = iNormal;
+ }
+
+ /*! Sets the index of the material lying on the right of the FEdge.*/
+ inline void setaFrsMaterialIndex(unsigned i)
+ {
+ _aFrsMaterialIndex = i;
+ }
+
+ /*! Sets the index of the material lying on the left of the FEdge.*/
+ inline void setbFrsMaterialIndex(unsigned i)
+ {
+ _bFrsMaterialIndex = i;
+ }
+
+ /*! Sets the face mark of the face lying on the right of the FEdge. */
+ inline void setaFaceMark(bool iFaceMark)
+ {
+ _aFaceMark = iFaceMark;
+ }
+
+ /*! Sets the face mark of the face lying on the left of the FEdge. */
+ inline void setbFaceMark(bool iFaceMark)
+ {
+ _bFaceMark = iFaceMark;
+ }
+};
+
+/*! Class defining a smooth edge. This kind of edge typically runs across a face of the input mesh. It can be
+ * a silhouette, a ridge or valley, a suggestive contour.
+ */
+class LIB_VIEW_MAP_EXPORT FEdgeSmooth : public FEdge
+{
+protected:
+ Vec3r _Normal;
+ unsigned _FrsMaterialIndex;
+#if 0
+ bool _hasVisibilityPoint;
+ Vec3r _VisibilityPointA; // The edge on which the visibility will be computed represented
+ Vec3r _VisibilityPointB; // using its 2 extremity points A and B
+#endif
+ void *_Face; // In case of exact silhouette, Face is the WFace crossed by Fedge
+ // NOT HANDLED BY THE COPY CONSTRUCTEUR
+ bool _FaceMark;
+
+public:
+ /*! Returns the string "FEdgeSmooth" . */
+ virtual string getExactTypeName() const
+ {
+ return "FEdgeSmooth";
+ }
+
+ /*! Default constructor. */
+ inline FEdgeSmooth() : FEdge()
+ {
+ _Face = NULL;
+ _FaceMark = false;
+ _FrsMaterialIndex = 0;
+ _isSmooth = true;
+ }
+
+ /*! Builds an FEdgeSmooth going from vA to vB. */
+ inline FEdgeSmooth(SVertex *vA, SVertex *vB) : FEdge(vA, vB)
+ {
+ _Face = NULL;
+ _FaceMark = false;
+ _FrsMaterialIndex = 0;
+ _isSmooth = true;
+ }
+
+ /*! Copy constructor. */
+ inline FEdgeSmooth(FEdgeSmooth& iBrother) : FEdge(iBrother)
+ {
+ _Normal = iBrother._Normal;
+ _Face = iBrother._Face;
+ _FaceMark = iBrother._FaceMark;
+ _FrsMaterialIndex = iBrother._FrsMaterialIndex;
+ _isSmooth = true;
+ }
+
+ /*! Destructor. */
+ virtual ~FEdgeSmooth() {}
+
+ /*! Cloning method. */
+ virtual FEdge *duplicate()
+ {
+ FEdge *clone = new FEdgeSmooth(*this);
+ return clone;
+ }
+
+ inline void *face() const
+ {
+ return _Face;
+ }
+
+ /*! Returns the face mark of the face it is running across. */
+ inline bool faceMark() const
+ {
+ return _FaceMark;
+ }
+
+ /*! Returns the normal to the Face it is running accross. */
+ inline const Vec3r& normal()
+ {
+ return _Normal;
+ }
+
+ /*! Returns the index of the material of the face it is running accross. */
+ inline unsigned frs_materialIndex() const
+ {
+ return _FrsMaterialIndex;
+ }
+
+ /*! Returns the material of the face it is running accross. */
+ const FrsMaterial& frs_material() const;
+
+ inline void setFace(void *iFace)
+ {
+ _Face = iFace;
+ }
+
+ /*! Sets the face mark of the face it is running across. */
+ inline void setFaceMark(bool iFaceMark)
+ {
+ _FaceMark = iFaceMark;
+ }
+
+ /*! Sets the normal to the Face it is running accross. */
+ inline void setNormal(const Vec3r& iNormal)
+ {
+ _Normal = iNormal;
+ }
+
+ /*! Sets the index of the material of the face it is running accross. */
+ inline void setFrsMaterialIndex(unsigned i)
+ {
+ _FrsMaterialIndex = i;
+ }
+};
+
+
+/**********************************/
+/* */
+/* */
+/* SShape */
+/* */
+/* */
+/**********************************/
+
+
+/*! Class to define a feature shape. It is the gathering of feature elements from an identified input shape */
+class LIB_VIEW_MAP_EXPORT SShape
+{
+private:
+ vector<FEdge*> _chains; // list of fedges that are chains starting points.
+ vector<SVertex*> _verticesList; // list of all vertices
+ vector<FEdge*> _edgesList; // list of all edges
+ Id _Id;
+ string _Name;
+ BBox<Vec3r> _BBox;
+ vector<FrsMaterial> _FrsMaterials;
+
+ float _importance;
+
+ ViewShape *_ViewShape;
+
+public:
+ /*! A field that can be used by the user to store any data.
+ * This field must be reseted afterwards using ResetUserData().
+ */
+ void *userdata; // added by E.T.
+
+ /*! Default constructor */
+ inline SShape()
+ {
+ userdata = NULL;
+ _importance = 0.0f;
+ _ViewShape = NULL;
+ }
+
+ /*! Copy constructor */
+ inline SShape(SShape& iBrother)
+ {
+ userdata = NULL;
+ _Id = iBrother._Id;
+ _Name = iBrother._Name;
+ _BBox = iBrother.bbox();
+ _FrsMaterials = iBrother._FrsMaterials;
+ _importance = iBrother._importance;
+ _ViewShape = iBrother._ViewShape;
+
+ //---------
+ // vertices
+ //---------
+ vector<SVertex*>::iterator sv, svend;
+ vector<SVertex*>& verticesList = iBrother.getVertexList();
+ for (sv = verticesList.begin(), svend = verticesList.end(); sv != svend; sv++) {
+ SVertex *newv = new SVertex(*(*sv));
+ newv->setShape(this);
+ _verticesList.push_back(newv);
+ }
+
+ //------
+ // edges
+ //------
+ vector<FEdge*>::iterator e, eend;
+ vector<FEdge*>& edgesList = iBrother.getEdgeList();
+ for (e = edgesList.begin(), eend = edgesList.end(); e != eend; e++) {
+ FEdge *newe = (*e)->duplicate();
+ _edgesList.push_back(newe);
+ }
+
+ //-------------------------
+ // starting chain edges
+ //-------------------------
+ vector<FEdge*>::iterator fe, fend;
+ vector<FEdge*>& fedges = iBrother.getChains();
+ for (fe = fedges.begin(), fend = fedges.end(); fe != fend; fe++) {
+ _chains.push_back((FEdge*)((*fe)->userdata));
+ }
+
+ //-------------------------
+ // remap edges in vertices:
+ //-------------------------
+ for (sv = _verticesList.begin(), svend = _verticesList.end(); sv != svend; sv++) {
+ const vector<FEdge*>& fedgeList = (*sv)->fedges();
+ vector<FEdge*> newfedgelist;
+ for (vector<FEdge*>::const_iterator fed = fedgeList.begin(), fedend = fedgeList.end();
+ fed != fedend;
+ fed++)
+ {
+ FEdge *current = *fed;
+ newfedgelist.push_back((FEdge*)current->userdata);
+ }
+ (*sv)->setFEdges(newfedgelist);
+ }
+
+ //-------------------------------------
+ // remap vertices and nextedge in edges:
+ //-------------------------------------
+ for (e = _edgesList.begin(), eend = _edgesList.end(); e != eend; e++) {
+ (*e)->setVertexA((SVertex*)((*e)->vertexA()->userdata));
+ (*e)->setVertexB((SVertex*)((*e)->vertexB()->userdata));
+ (*e)->setNextEdge((FEdge*)((*e)->nextEdge()->userdata));
+ (*e)->setPreviousEdge((FEdge*)((*e)->previousEdge()->userdata));
+ }
+
+ // reset all brothers userdata to NULL:
+ //-------------------------------------
+ //---------
+ // vertices
+ //---------
+ for (sv = _verticesList.begin(), svend = _verticesList.end(); sv != svend; sv++) {
+ (*sv)->userdata = NULL;
+ }
+
+ //------
+ // edges
+ //------
+ for (e = _edgesList.begin(), eend = _edgesList.end(); e != eend; e++) {
+ (*e)->userdata = NULL;
+ }
+ }
+
+ /*! Cloning method. */
+ virtual SShape * duplicate()
+ {
+ SShape *clone = new SShape(*this);
+ return clone;
+ }
+
+ /*! Destructor. */
+ virtual inline ~SShape()
+ {
+ vector<SVertex*>::iterator sv, svend;
+ vector<FEdge*>::iterator e, eend;
+ if (0 != _verticesList.size()) {
+ for (sv = _verticesList.begin(), svend = _verticesList.end(); sv != svend; sv++) {
+ delete (*sv);
+ }
+ _verticesList.clear();
+ }
+
+ if (0 != _edgesList.size()) {
+ for (e = _edgesList.begin(), eend = _edgesList.end(); e != eend; e++) {
+ delete (*e);
+ }
+ _edgesList.clear();
+ }
+
+ //! Clear the chains list
+ //-----------------------
+ if (0 != _chains.size()) {
+ _chains.clear();
+ }
+ }
+
+ /*! Adds a FEdge to the list of FEdges. */
+ inline void AddEdge(FEdge *iEdge)
+ {
+ _edgesList.push_back(iEdge);
+ }
+
+ /*! Adds a SVertex to the list of SVertex of this Shape.
+ * The SShape attribute of the SVertex is also set to 'this'.
+ */
+ inline void AddNewVertex(SVertex *iv)
+ {
+ iv->setShape(this);
+ _verticesList.push_back(iv);
+ }
+
+ inline void AddChain(FEdge *iEdge)
+ {
+ _chains.push_back(iEdge);
+ }
+
+ inline SVertex *CreateSVertex(const Vec3r& P3D, const Vec3r& P2D, const Id& id)
+ {
+ SVertex *Ia = new SVertex(P3D, id);
+ Ia->setPoint2D(P2D);
+ AddNewVertex(Ia);
+ return Ia;
+ }
+
+ /*! Splits an edge into several edges.
+ * The edge's vertices are passed rather than the edge itself. This way, all feature edges (SILHOUETTE,
+ * CREASE, BORDER) are splitted in the same time.
+ * The processed edges are flagged as done (using the userdata flag).One single new vertex is created whereas
+ * several splitted edges might created for the different kinds of edges. These new elements are added to the lists
+ * maintained by the shape.
+ * New chains are also created.
+ * ioA
+ * The first vertex for the edge that gets splitted
+ * ioB
+ * The second vertex for the edge that gets splitted
+ * iParameters
+ * A vector containing 2D real vectors indicating the parameters giving the intersections coordinates in
+ * 3D and in 2D. These intersections points must be sorted from B to A.
+ * Each parameter defines the intersection point I as I=A+T*AB. T<0 and T>1 are then incorrect insofar as
+ * they give intersections points that lie outside the segment.
+ * ioNewEdges
+ * The edges that are newly created (the initial edges are not included) are added to this list.
+ */
+ inline void SplitEdge(FEdge *fe, const vector<Vec2r>& iParameters, vector<FEdge*>& ioNewEdges)
+ {
+ SVertex *ioA = fe->vertexA();
+ SVertex *ioB = fe->vertexB();
+ Vec3r A = ioA->point3D();
+ Vec3r B = ioB->point3D();
+ Vec3r a = ioA->point2D();
+ Vec3r b = ioB->point2D();
+
+ Vec3r newpoint3d,newpoint2d;
+ vector<SVertex*> intersections;
+ real t, T;
+ for (vector<Vec2r>::const_iterator p = iParameters.begin(), pend = iParameters.end(); p != pend; p++) {
+ T = (*p)[0];
+ t = (*p)[1];
+
+ if ((t < 0) || (t > 1))
+ cerr << "Warning: Intersection out of range for edge " << ioA->getId() << " - " << ioB->getId() << endl;
+
+ // compute the 3D and 2D coordinates for the intersections points:
+ newpoint3d = Vec3r(A + T * (B - A));
+ newpoint2d = Vec3r(a + t * (b - a));
+
+ // create new SVertex:
+ // (we keep B's id)
+ SVertex *newVertex = new SVertex(newpoint3d, ioB->getId());
+ newVertex->setPoint2D(newpoint2d);
+
+ // Add this vertex to the intersections list:
+ intersections.push_back(newVertex);
+
+ // Add this vertex to this sshape:
+ AddNewVertex(newVertex);
+ }
+
+ for (vector<SVertex*>::iterator sv = intersections.begin(), svend = intersections.end(); sv != svend; sv++) {
+ //SVertex *svA = fe->vertexA();
+ SVertex *svB = fe->vertexB();
+
+ // We split edge AB into AA' and A'B. A' and A'B are created.
+ // AB becomes (address speaking) AA'. B is updated.
+ //--------------------------------------------------
+ // The edge AB becomes edge AA'.
+ (fe)->setVertexB((*sv));
+ // a new edge, A'B is created.
+ FEdge *newEdge;
+ if (fe->isSmooth()) {
+ newEdge = new FEdgeSmooth((*sv), svB);
+ FEdgeSmooth *se = dynamic_cast<FEdgeSmooth*>(newEdge);
+ FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth*>(fe);
+ se->setFrsMaterialIndex(fes->frs_materialIndex());
+ }
+ else {
+ newEdge = new FEdgeSharp((*sv), svB);
+ FEdgeSharp *se = dynamic_cast<FEdgeSharp*>(newEdge);
+ FEdgeSharp *fes = dynamic_cast<FEdgeSharp*>(fe);
+ se->setaFrsMaterialIndex(fes->aFrsMaterialIndex());
+ se->setbFrsMaterialIndex(fes->bFrsMaterialIndex());
+ }
+
+ newEdge->setNature((fe)->getNature());
+
+ // to build a new chain:
+ AddChain(newEdge);
+ // add the new edge to the sshape edges list.
+ AddEdge(newEdge);
+ // add new edge to the list of new edges passed as argument:
+ ioNewEdges.push_back(newEdge);
+
+ // update edge A'B for the next pointing edge
+ newEdge->setNextEdge((fe)->nextEdge());
+ fe->nextEdge()->setPreviousEdge(newEdge);
+ Id id(fe->getId().getFirst(), fe->getId().getSecond() + 1);
+ newEdge->setId(fe->getId());
+ fe->setId(id);
+
+ // update edge AA' for the next pointing edge
+ //ioEdge->setNextEdge(newEdge);
+ (fe)->setNextEdge(NULL);
+
+ // update vertex pointing edges list:
+ // -- vertex B --
+ svB->Replace((fe), newEdge);
+ // -- vertex A' --
+ (*sv)->AddFEdge((fe));
+ (*sv)->AddFEdge(newEdge);
+ }
+ }
+
+ /* splits an edge into 2 edges. The new vertex and edge are added to the sshape list of vertices and edges
+ * a new chain is also created.
+ * returns the new edge.
+ * ioEdge
+ * The edge that gets splitted
+ * newpoint
+ * x,y,z coordinates of the new point.
+ */
+ inline FEdge *SplitEdgeIn2(FEdge *ioEdge, SVertex *ioNewVertex)
+ {
+ //soc unused - SVertex *A = ioEdge->vertexA();
+ SVertex *B = ioEdge->vertexB();
+
+ // We split edge AB into AA' and A'B. A' and A'B are created.
+ // AB becomes (address speaking) AA'. B is updated.
+ //--------------------------------------------------
+ // a new edge, A'B is created.
+ FEdge *newEdge;
+ if (ioEdge->isSmooth()) {
+ newEdge = new FEdgeSmooth(ioNewVertex, B);
+ FEdgeSmooth *se = dynamic_cast<FEdgeSmooth*>(newEdge);
+ FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth*>(ioEdge);
+ se->setNormal(fes->normal());
+ se->setFrsMaterialIndex(fes->frs_materialIndex());
+ }
+ else {
+ newEdge = new FEdgeSharp(ioNewVertex, B);
+ FEdgeSharp *se = dynamic_cast<FEdgeSharp*>(newEdge);
+ FEdgeSharp *fes = dynamic_cast<FEdgeSharp*>(ioEdge);
+ se->setNormalA(fes->normalA());
+ se->setNormalB(fes->normalB());
+ se->setaFrsMaterialIndex(fes->aFrsMaterialIndex());
+ se->setbFrsMaterialIndex(fes->bFrsMaterialIndex());
+ }
+ newEdge->setNature(ioEdge->getNature());
+
+ if (ioEdge->nextEdge() != 0)
+ ioEdge->nextEdge()->setPreviousEdge(newEdge);
+
+ // update edge A'B for the next pointing edge
+ newEdge->setNextEdge(ioEdge->nextEdge());
+ // update edge A'B for the previous pointing edge
+ newEdge->setPreviousEdge(0); // because it is now a TVertex
+ Id id(ioEdge->getId().getFirst(), ioEdge->getId().getSecond() + 1);
+ newEdge->setId(ioEdge->getId());
+ ioEdge->setId(id);
+
+ // update edge AA' for the next pointing edge
+ ioEdge->setNextEdge(0); // because it is now a TVertex
+
+ // update vertex pointing edges list:
+ // -- vertex B --
+ B->Replace(ioEdge, newEdge);
+ // -- vertex A' --
+ ioNewVertex->AddFEdge(ioEdge);
+ ioNewVertex->AddFEdge(newEdge);
+
+ // to build a new chain:
+ AddChain(newEdge);
+ AddEdge(newEdge); // FIXME ??
+
+ // The edge AB becomes edge AA'.
+ ioEdge->setVertexB(ioNewVertex);
+
+ if (ioEdge->isSmooth()) {
+ ((FEdgeSmooth*)newEdge)->setFace(((FEdgeSmooth*)ioEdge)->face());
+ }
+
+ return newEdge;
+ }
+
+ /*! Sets the Bounding Box of the Shape */
+ inline void setBBox(const BBox<Vec3r>& iBBox)
+ {
+ _BBox = iBBox;
+ }
+
+ /*! Compute the bbox of the sshape */
+ inline void ComputeBBox()
+ {
+ if (0 == _verticesList.size())
+ return;
+
+ Vec3r firstVertex = _verticesList[0]->point3D();
+ real XMax = firstVertex[0];
+ real YMax = firstVertex[1];
+ real ZMax = firstVertex[2];
+
+ real XMin = firstVertex[0];
+ real YMin = firstVertex[1];
+ real ZMin = firstVertex[2];
+
+ vector<SVertex*>::iterator v, vend;
+ // parse all the coordinates to find the Xmax, YMax, ZMax
+ for (v = _verticesList.begin(), vend = _verticesList.end(); v != vend; v++) {
+ Vec3r vertex = (*v)->point3D();
+ // X
+ real x = vertex[0];
+ if (x > XMax)
+ XMax = x;
+ else if (x < XMin)
+ XMin = x;
+
+ // Y
+ real y = vertex[1];
+ if (y > YMax)
+ YMax = y;
+ else if (y < YMin)
+ YMin = y;
+
+ // Z
+ real z = vertex[2];
+ if (z > ZMax)
+ ZMax = z;
+ else if (z < ZMin)
+ ZMin = z;
+ }
+
+ setBBox(BBox<Vec3r>(Vec3r(XMin, YMin, ZMin), Vec3r(XMax, YMax, ZMax)));
+ }
+
+ inline void RemoveEdgeFromChain(FEdge *iEdge)
+ {
+ for (vector<FEdge*>::iterator fe = _chains.begin(), feend = _chains.end(); fe != feend; fe++) {
+ if (iEdge == (*fe)) {
+ _chains.erase(fe);
+ break;
+ }
+ }
+ }
+
+ inline void RemoveEdge(FEdge *iEdge)
+ {
+ for (vector<FEdge*>::iterator fe = _edgesList.begin(), feend = _edgesList.end(); fe != feend; fe++) {
+ if (iEdge == (*fe)) {
+ _edgesList.erase(fe);
+ break;
+ }
+ }
+ }
+
+ /* accessors */
+ /*! Returns the list of SVertex of the Shape. */
+ inline vector<SVertex*>& getVertexList()
+ {
+ return _verticesList;
+ }
+
+ /*! Returns the list of FEdges of the Shape. */
+ inline vector<FEdge*>& getEdgeList()
+ {
+ return _edgesList;
+ }
+
+ inline vector<FEdge*>& getChains()
+ {
+ return _chains;
+ }
+
+ /*! Returns the bounding box of the shape. */
+ inline const BBox<Vec3r>& bbox()
+ {
+ return _BBox;
+ }
+
+ /*! Returns the ith material of the shape. */
+ inline const FrsMaterial& frs_material(unsigned i) const
+ {
+ return _FrsMaterials[i];
+ }
+
+ /*! Returns the list of materials of the Shape. */
+ inline const vector<FrsMaterial>& frs_materials() const
+ {
+ return _FrsMaterials;
+ }
+
+ inline ViewShape *viewShape()
+ {
+ return _ViewShape;
+ }
+
+ inline float importance() const
+ {
+ return _importance;
+ }
+
+ /*! Returns the Id of the Shape. */
+ inline Id getId() const
+ {
+ return _Id;
+ }
+
+ /*! Returns the name of the Shape. */
+ inline const string& getName() const
+ {
+ return _Name;
+ }
+
+ /* Modififers */
+ /*! Sets the Id of the shape.*/
+ inline void setId(Id id)
+ {
+ _Id = id;
+ }
+
+ /*! Sets the name of the shape.*/
+ inline void setName(const string& name)
+ {
+ _Name = name;
+ }
+
+ /*! Sets the list of materials for the shape */
+ inline void setFrsMaterials(const vector<FrsMaterial>& iMaterials)
+ {
+ _FrsMaterials = iMaterials;
+ }
+
+ inline void setViewShape(ViewShape *iShape)
+ {
+ _ViewShape = iShape;
+ }
+
+ inline void setImportance(float importance)
+ {
+ _importance = importance;
+ }
+};
+
+#endif // __FREESTYLE_SILHOUETTE_H__
diff --git a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp
new file mode 100644
index 00000000000..2de6be4c68a
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp
@@ -0,0 +1,322 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp
+ * \ingroup freestyle
+ * \brief Class to perform all geometric operations dedicated to silhouette. That, for example, implies that
+ * this geom engine has as member data the viewpoint, transformations, projections...
+ * \author Stephane Grabli
+ * \date 03/09/2002
+ */
+
+#include "Silhouette.h"
+#include "SilhouetteGeomEngine.h"
+
+#include "../geometry/GeomUtils.h"
+
+#include "BKE_global.h"
+
+using namespace std;
+
+Vec3r SilhouetteGeomEngine::_Viewpoint = Vec3r(0, 0, 0);
+real SilhouetteGeomEngine::_translation[3] = {0, 0, 0};
+real SilhouetteGeomEngine::_modelViewMatrix[4][4] = {
+ {1, 0, 0, 0},
+ {0, 1, 0, 0},
+ {0, 0, 1, 0},
+ {0, 0, 0, 1}
+};
+real SilhouetteGeomEngine::_projectionMatrix[4][4] = {
+ {1, 0, 0, 0},
+ {0, 1, 0, 0},
+ {0, 0, 1, 0},
+ {0, 0, 0, 1}
+};
+real SilhouetteGeomEngine::_transform[4][4] = {
+ {1, 0, 0, 0},
+ {0, 1, 0, 0},
+ {0, 0, 1, 0},
+ {0, 0, 0, 1}
+};
+int SilhouetteGeomEngine::_viewport[4] = {1, 1, 1, 1};
+real SilhouetteGeomEngine::_Focal = 0.0;
+
+real SilhouetteGeomEngine::_glProjectionMatrix[4][4] = {
+ {1, 0, 0, 0},
+ {0, 1, 0, 0},
+ {0, 0, 1, 0},
+ {0, 0, 0, 1}
+};
+real SilhouetteGeomEngine::_glModelViewMatrix[4][4] = {
+ {1, 0, 0, 0},
+ {0, 1, 0, 0},
+ {0, 0, 1, 0},
+ {0, 0, 0, 1}
+};
+real SilhouetteGeomEngine::_znear = 0.0;
+real SilhouetteGeomEngine::_zfar = 100.0;
+bool SilhouetteGeomEngine::_isOrthographicProjection = false;
+
+SilhouetteGeomEngine *SilhouetteGeomEngine::_pInstance = NULL;
+
+void SilhouetteGeomEngine::setTransform(const real iModelViewMatrix[4][4], const real iProjectionMatrix[4][4],
+ const int iViewport[4], real iFocal)
+{
+ unsigned int i, j;
+ _translation[0] = iModelViewMatrix[3][0];
+ _translation[1] = iModelViewMatrix[3][1];
+ _translation[2] = iModelViewMatrix[3][2];
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ _modelViewMatrix[i][j] = iModelViewMatrix[j][i];
+ _glModelViewMatrix[i][j] = iModelViewMatrix[i][j];
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ _projectionMatrix[i][j] = iProjectionMatrix[j][i];
+ _glProjectionMatrix[i][j] = iProjectionMatrix[i][j];
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ _transform[i][j] = 0;
+ for (unsigned int k = 0; k < 4; k++)
+ _transform[i][j] += _projectionMatrix[i][k] * _modelViewMatrix[k][j];
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ _viewport[i] = iViewport[i];
+ }
+ _Focal = iFocal;
+
+ _isOrthographicProjection = (iProjectionMatrix[3][3] != 0.0);
+}
+
+void SilhouetteGeomEngine::setFrustum(real iZNear, real iZFar)
+{
+ _znear = iZNear;
+ _zfar = iZFar;
+}
+
+void SilhouetteGeomEngine::retrieveViewport(int viewport[4])
+{
+ memcpy(viewport, _viewport, 4 * sizeof(int));
+}
+
+//#define HUGE 1.0e9
+
+void SilhouetteGeomEngine::ProjectSilhouette(vector<SVertex*>& ioVertices)
+{
+ Vec3r newPoint;
+#if 0
+ real min = HUGE;
+ real max = -HUGE;
+#endif
+ vector<SVertex*>::iterator sv, svend;
+ const real depth = _zfar - _znear;
+ const real fac = (depth < 1.0e-6) ? 1.0 : 1.0 / depth;
+
+ for (sv = ioVertices.begin(), svend = ioVertices.end(); sv != svend; sv++) {
+ GeomUtils::fromWorldToImage((*sv)->point3D(), newPoint, _modelViewMatrix, _projectionMatrix, _viewport);
+ newPoint[2] = (-newPoint[2] - _znear) * fac; // normalize Z between 0 and 1
+ (*sv)->setPoint2D(newPoint);
+#if 0
+ cerr << (*sv)->point2d().z() << " ";
+ real d = (*sv)->point2d()[2];
+ if (d > max)
+ max =d;
+ if (d < min)
+ min =d;
+#endif
+ }
+#if 0
+ for (sv = ioVertices.begin(), svend = ioVertices.end(); sv != svend; sv++) {
+ Vec3r P((*sv)->point2d());
+ (*sv)->setPoint2D(Vec3r(P[0], P[1], 1.0 - (P[2] - min) / (max - min)));
+ //cerr << (*sv)->point2d()[2] << " ";
+ }
+#endif
+}
+
+void SilhouetteGeomEngine::ProjectSilhouette(SVertex *ioVertex)
+{
+ Vec3r newPoint;
+#if 0
+ real min = HUGE;
+ real max = -HUGE;
+ vector<SVertex*>::iterator sv, svend;
+#endif
+ const real depth = _zfar - _znear;
+ const real fac = (depth < 1.0e-6) ? 1.0 : 1.0 / depth;
+ GeomUtils::fromWorldToImage(ioVertex->point3D(), newPoint, _modelViewMatrix, _projectionMatrix, _viewport);
+ newPoint[2] = (-newPoint[2] - _znear) * fac; // normalize Z between 0 and 1
+ ioVertex->setPoint2D(newPoint);
+}
+
+real SilhouetteGeomEngine::ImageToWorldParameter(FEdge *fe, real t)
+{
+ if (_isOrthographicProjection)
+ return t;
+
+ // we need to compute for each parameter t the corresponding parameter T which gives the intersection in 3D.
+ real T;
+
+ // suffix w for world, c for camera, r for retina, i for image
+ Vec3r Aw = (fe)->vertexA()->point3D();
+ Vec3r Bw = (fe)->vertexB()->point3D();
+ Vec3r Ac, Bc;
+ GeomUtils::fromWorldToCamera(Aw, Ac, _modelViewMatrix);
+ GeomUtils::fromWorldToCamera(Bw, Bc, _modelViewMatrix);
+ Vec3r ABc = Bc - Ac;
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Ac " << Ac << endl;
+ cout << "Bc " << Bc << endl;
+ cout << "ABc " << ABc << endl;
+ }
+#endif
+ Vec3r Ai = (fe)->vertexA()->point2D();
+ Vec3r Bi = (fe)->vertexB()->point2D();
+ Vec3r Ii = Ai + t * (Bi - Ai); // the intersection point in the 2D image space
+ Vec3r Ir, Ic;
+ GeomUtils::fromImageToRetina(Ii, Ir, _viewport);
+
+ real alpha, beta, denom;
+ real m11 = _projectionMatrix[0][0];
+ real m13 = _projectionMatrix[0][2];
+ real m22 = _projectionMatrix[1][1];
+ real m23 = _projectionMatrix[1][2];
+
+ if (fabs(ABc[0]) > 1.0e-6) {
+ alpha = ABc[2] / ABc[0];
+ beta = Ac[2] - alpha * Ac[0];
+ denom = alpha * (Ir[0] + m13) + m11;
+ if (fabs(denom) < 1.0e-6)
+ goto iter;
+ Ic[0] = -beta * (Ir[0] + m13) / denom;
+#if 0
+ Ic[1] = -(Ir[1] + m23) * (alpha * Ic[0] + beta) / m22;
+ Ic[2] = alpha * (Ic[0] - Ac[0]) + Ac[2];
+#endif
+ T = (Ic[0] - Ac[0]) / ABc[0];
+
+ }
+ else if (fabs(ABc[1]) > 1.0e-6) {
+ alpha = ABc[2] / ABc[1];
+ beta = Ac[2] - alpha * Ac[1];
+ denom = alpha * (Ir[1] + m23) + m22;
+ if (fabs(denom) < 1.0e-6)
+ goto iter;
+ Ic[1] = -beta * (Ir[1] + m23) / denom;
+#if 0
+ Ic[0] = -(Ir[0] + m13) * (alpha * Ic[1] + beta) / m11;
+ Ic[2] = alpha * (Ic[1] - Ac[1]) + Ac[2];
+#endif
+ T = (Ic[1] - Ac[1]) / ABc[1];
+ }
+ else {
+iter:
+ bool x_coords, less_than;
+ if (fabs(Bi[0] - Ai[0]) > 1.0e-6) {
+ x_coords = true;
+ less_than = Ai[0] < Bi[0];
+ }
+ else {
+ x_coords = false;
+ less_than = Ai[1] < Bi[1];
+ }
+ Vec3r Pc, Pr, Pi;
+ real T_sta = 0.0;
+ real T_end = 1.0;
+ real delta_x, delta_y, dist, dist_threshold = 1.0e-6;
+ int i, max_iters = 100;
+ for (i = 0; i < max_iters; i++) {
+ T = T_sta + 0.5 * (T_end - T_sta);
+ Pc = Ac + T * ABc;
+ GeomUtils::fromCameraToRetina(Pc, Pr, _projectionMatrix);
+ GeomUtils::fromRetinaToImage(Pr, Pi, _viewport);
+ delta_x = Ii[0] - Pi[0];
+ delta_y = Ii[1] - Pi[1];
+ dist = sqrt(delta_x * delta_x + delta_y * delta_y);
+ if (dist < dist_threshold)
+ break;
+ if (x_coords) {
+ if (less_than) {
+ if (Pi[0] < Ii[0])
+ T_sta = T;
+ else
+ T_end = T;
+ }
+ else {
+ if (Pi[0] > Ii[0])
+ T_sta = T;
+ else
+ T_end = T;
+ }
+ }
+ else {
+ if (less_than) {
+ if (Pi[1] < Ii[1])
+ T_sta = T;
+ else
+ T_end = T;
+ }
+ else {
+ if (Pi[1] > Ii[1])
+ T_sta = T;
+ else
+ T_end = T;
+ }
+ }
+ }
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("SilhouetteGeomEngine::ImageToWorldParameter(): #iters = %d, dist = %e\n", i, dist);
+ }
+#endif
+ if (i == max_iters && G.debug & G_DEBUG_FREESTYLE) {
+ printf("SilhouetteGeomEngine::ImageToWorldParameter(): reached to max_iters (dist = %e)\n", dist);
+ }
+ }
+
+ return T;
+}
+
+Vec3r SilhouetteGeomEngine::WorldToImage(const Vec3r& M)
+{
+ const real depth = _zfar - _znear;
+ const real fac = (depth < 1.0e-6) ? 1.0 : 1.0 / depth;
+ Vec3r newPoint;
+ GeomUtils::fromWorldToImage(M, newPoint, _transform, _viewport);
+ newPoint[2] = (-newPoint[2] - _znear) * fac; // normalize Z between 0 and 1
+ return newPoint;
+}
diff --git a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.h b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.h
new file mode 100644
index 00000000000..d6ee159fe88
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.h
@@ -0,0 +1,136 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_SILHOUETTE_GEOM_ENGINE_H__
+#define __FREESTYLE_SILHOUETTE_GEOM_ENGINE_H__
+
+/** \file blender/freestyle/intern/view_map/SilhouetteGeomEngine.h
+ * \ingroup freestyle
+ * \brief Class to perform all geometric operations dedicated to silhouette. That, for example, implies that
+ * this geom engine has as member data the viewpoint, transformations, projections...
+ * \author Stephane Grabli
+ * \date 03/09/2002
+ */
+
+#include <vector>
+
+#include "../geometry/Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace Geometry;
+
+class SVertex;
+class FEdge;
+
+class LIB_VIEW_MAP_EXPORT SilhouetteGeomEngine
+{
+private:
+ // The viewpoint under which the silhouette has to be computed
+ static Vec3r _Viewpoint;
+ static real _translation[3];
+ // the model view matrix (_modelViewMatrix[i][j] means element of line i and column j)
+ static real _modelViewMatrix[4][4];
+ // the projection matrix (_projectionMatrix[i][j] means element of line i and column j)
+ static real _projectionMatrix[4][4];
+ // the global transformation from world to screen (projection included)
+ // (_transform[i][j] means element of line i and column j)
+ static real _transform[4][4];
+ // the viewport
+ static int _viewport[4];
+ static real _Focal;
+
+ static real _znear;
+ static real _zfar;
+
+ // GL style (column major) projection matrix
+ static real _glProjectionMatrix[4][4];
+ // GL style (column major) model view matrix
+ static real _glModelViewMatrix[4][4];
+
+ static bool _isOrthographicProjection;
+
+ static SilhouetteGeomEngine *_pInstance;
+
+public:
+ /*! retrieves an instance on the singleton */
+ static SilhouetteGeomEngine *getInstance()
+ {
+ if(0 == _pInstance) {
+ _pInstance = new SilhouetteGeomEngine;
+ }
+ return _pInstance;
+ }
+
+ /*! Sets the current viewpoint */
+ static inline void setViewpoint(const Vec3r& ivp)
+ {
+ _Viewpoint = ivp;
+ }
+
+ /*! Sets the current transformation
+ * iModelViewMatrix
+ * The 4x4 model view matrix, in column major order (openGL like).
+ * iProjection matrix
+ * The 4x4 projection matrix, in column major order (openGL like).
+ * iViewport
+ * The viewport. 4 real array: origin.x, origin.y, width, length
+ * iFocal
+ * The focal length
+ */
+ static void setTransform(const real iModelViewMatrix[4][4], const real iProjectionMatrix[4][4],
+ const int iViewport[4], real iFocal);
+
+ /*! Sets the current znear and zfar */
+ static void setFrustum(real iZNear, real iZFar);
+
+ /* accessors */
+ static void retrieveViewport(int viewport[4]);
+
+ /*! Projects the silhouette in camera coordinates
+ * This method modifies the ioEdges passed as argument.
+ * ioVertices
+ * The vertices to project. It is modified during the operation.
+ */
+ static void ProjectSilhouette(std::vector<SVertex*>& ioVertices);
+ static void ProjectSilhouette(SVertex *ioVertex);
+
+ /*! transforms the parameter t defining a 2D intersection for edge fe in order to obtain
+ * the parameter giving the corresponding 3D intersection.
+ * Returns the 3D parameter
+ * fe
+ * The edge
+ * t
+ * The parameter for the 2D intersection.
+ */
+ static real ImageToWorldParameter(FEdge *fe, real t);
+
+ /*! From world to image */
+ static Vec3r WorldToImage(const Vec3r& M);
+};
+
+#endif // __FREESTYLE_SILHOUETTE_GEOM_ENGINE_H__
diff --git a/source/blender/freestyle/intern/view_map/SphericalGrid.cpp b/source/blender/freestyle/intern/view_map/SphericalGrid.cpp
new file mode 100644
index 00000000000..4582fb40b61
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/SphericalGrid.cpp
@@ -0,0 +1,249 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/SphericalGrid.cpp
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2010-12-19
+ */
+
+#include <algorithm>
+#include <stdexcept>
+
+#include "SphericalGrid.h"
+
+#include "BKE_global.h"
+
+using namespace std;
+
+// Helper Classes
+
+// OccluderData
+///////////////
+
+// Cell
+/////////
+
+SphericalGrid::Cell::Cell() {}
+
+SphericalGrid::Cell::~Cell() {}
+
+void SphericalGrid::Cell::setDimensions(real x, real y, real sizeX, real sizeY)
+{
+ const real epsilon = 1.0e-06;
+ boundary[0] = x - epsilon;
+ boundary[1] = x + sizeX + epsilon;
+ boundary[2] = y - epsilon;
+ boundary[3] = y + sizeY + epsilon;
+}
+
+bool SphericalGrid::Cell::compareOccludersByShallowestPoint(const SphericalGrid::OccluderData *a,
+ const SphericalGrid::OccluderData *b)
+{
+ return a->shallowest < b->shallowest;
+}
+
+void SphericalGrid::Cell::indexPolygons()
+{
+ // Sort occluders by their shallowest points.
+ sort(faces.begin(), faces.end(), compareOccludersByShallowestPoint);
+}
+
+// Iterator
+//////////////////
+
+SphericalGrid::Iterator::Iterator(SphericalGrid& grid, Vec3r& center, real epsilon)
+: _target(SphericalGrid::Transform::sphericalProjection(center)), _foundOccludee(false)
+{
+ // Find target cell
+ _cell = grid.findCell(_target);
+ #if SPHERICAL_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Searching for occluders of edge centered at " << _target << " in cell ["
+ << _cell->boundary[0] << ", " << _cell->boundary[1] << ", " << _cell->boundary[2]
+ << ", " << _cell->boundary[3] << "] (" << _cell->faces.size() << " occluders)" << endl;
+ }
+ #endif
+
+ // Set iterator
+ _current = _cell->faces.begin();
+}
+
+SphericalGrid::Iterator::~Iterator() {}
+
+// SphericalGrid
+/////////////////
+
+SphericalGrid::SphericalGrid(OccluderSource& source, GridDensityProvider& density, ViewMap *viewMap,
+ Vec3r& viewpoint, bool enableQI)
+: _viewpoint(viewpoint), _enableQI(enableQI)
+{
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Generate Cell structure" << endl;
+ }
+ // Generate Cell structure
+ assignCells(source, density, viewMap);
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Distribute occluders" << endl;
+ }
+ // Fill Cells
+ distributePolygons(source);
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Reorganize cells" << endl;
+ }
+ // Reorganize Cells
+ reorganizeCells();
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Ready to use SphericalGrid" << endl;
+ }
+}
+
+SphericalGrid::~SphericalGrid() {}
+
+void SphericalGrid::assignCells(OccluderSource& source, GridDensityProvider& density, ViewMap *viewMap)
+{
+ _cellSize = density.cellSize();
+ _cellsX = density.cellsX();
+ _cellsY = density.cellsY();
+ _cellOrigin[0] = density.cellOrigin(0);
+ _cellOrigin[1] = density.cellOrigin(1);
+
+ // Now allocate the cell table and fill it with default (empty) cells
+ _cells.resize(_cellsX * _cellsY);
+ for (cellContainer::iterator i = _cells.begin(), end = _cells.end(); i != end; ++i) {
+ (*i) = NULL;
+ }
+
+ // Identify cells that will be used, and set the dimensions for each
+ ViewMap::fedges_container& fedges = viewMap->FEdges();
+ for (ViewMap::fedges_container::iterator f = fedges.begin(), fend = fedges.end(); f != fend; ++f) {
+ if ((*f)->isInImage()) {
+ Vec3r point = SphericalGrid::Transform::sphericalProjection((*f)->center3d());
+ unsigned i, j;
+ getCellCoordinates(point, i, j);
+ if (_cells[i * _cellsY + j] == NULL) {
+ // This is an uninitialized cell
+ real x, y, width, height;
+
+ x = _cellOrigin[0] + _cellSize * i;
+ width = _cellSize;
+
+ y = _cellOrigin[1] + _cellSize * j;
+ height = _cellSize;
+
+ // Initialize cell
+ Cell* b = _cells[i * _cellsY + j] = new Cell();
+ b->setDimensions(x, y, width, height);
+ }
+ }
+ }
+}
+
+void SphericalGrid::distributePolygons(OccluderSource& source)
+{
+ unsigned long nFaces = 0;
+ unsigned long nKeptFaces = 0;
+
+ for (source.begin(); source.isValid(); source.next()) {
+ OccluderData *occluder = NULL;
+
+ try {
+ if (insertOccluder(source, occluder)) {
+ _faces.push_back(occluder);
+ ++nKeptFaces;
+ }
+ }
+ catch (...) {
+ // If an exception was thrown, _faces.push_back() cannot have succeeded. Occluder is not owned by anyone,
+ // and must be deleted. If the exception was thrown before or during new OccluderData(), then
+ // occluder is NULL, and this delete is harmless.
+ delete occluder;
+ throw;
+ }
+ ++nFaces;
+ }
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Distributed " << nFaces << " occluders. Retained " << nKeptFaces << "." << endl;
+ }
+}
+
+void SphericalGrid::reorganizeCells()
+{
+ // Sort the occluders by shallowest point
+ for (vector<Cell*>::iterator i = _cells.begin(), end = _cells.end(); i != end; ++i) {
+ if (*i != NULL) {
+ (*i)->indexPolygons();
+ }
+ }
+}
+
+void SphericalGrid::getCellCoordinates(const Vec3r& point, unsigned& x, unsigned& y)
+{
+ x = min(_cellsX - 1, (unsigned) floor (max((double) 0.0f, point[0] - _cellOrigin[0]) / _cellSize));
+ y = min(_cellsY - 1, (unsigned) floor (max((double) 0.0f, point[1] - _cellOrigin[1]) / _cellSize));
+}
+
+SphericalGrid::Cell *SphericalGrid::findCell(const Vec3r& point)
+{
+ unsigned x, y;
+ getCellCoordinates(point, x, y);
+ return _cells[x * _cellsY + y];
+}
+
+bool SphericalGrid::orthographicProjection() const
+{
+ return false;
+}
+
+const Vec3r& SphericalGrid::viewpoint() const
+{
+ return _viewpoint;
+}
+
+bool SphericalGrid::enableQI() const
+{
+ return _enableQI;
+}
+
+SphericalGrid::Transform::Transform () : GridHelpers::Transform() {}
+
+Vec3r SphericalGrid::Transform::operator()(const Vec3r& point) const
+{
+ return sphericalProjection(point);
+}
+
+Vec3r SphericalGrid::Transform::sphericalProjection(const Vec3r& M)
+{
+ Vec3r newPoint;
+
+ newPoint[0] = ::atan(M[0] / M[2]);
+ newPoint[1] = ::atan(M[1] / M[2]);
+ newPoint[2] = ::sqrt(M[0] * M[0] + M[1] * M[1] + M[2] * M[2]);
+
+ return newPoint;
+}
diff --git a/source/blender/freestyle/intern/view_map/SphericalGrid.h b/source/blender/freestyle/intern/view_map/SphericalGrid.h
new file mode 100644
index 00000000000..57ed117a935
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/SphericalGrid.h
@@ -0,0 +1,423 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_SPHERICAL_GRID_H__
+#define __FREESTYLE_SPHERICAL_GRID_H__
+
+/** \file blender/freestyle/intern/view_map/SphericalGrid.h
+ * \ingroup freestyle
+ * \brief Class to define a cell grid surrounding the projected image of a scene
+ * \author Alexander Beels
+ * \date 2010-12-19
+ */
+
+#define SPHERICAL_GRID_LOGGING FALSE
+
+// I would like to avoid using deque because including ViewMap.h and <deque> or <vector> separately results in
+// redefinitions of identifiers. ViewMap.h already includes <vector> so it should be a safe fall-back.
+//#include <vector>
+//#include <deque>
+
+#include "GridDensityProvider.h"
+#include "OccluderSource.h"
+#include "ViewMap.h"
+
+#include "../geometry/Polygon.h"
+#include "../geometry/BBox.h"
+#include "../geometry/GridHelpers.h"
+
+#include "../system/PointerSequence.h"
+
+#include "../winged_edge/WEdge.h"
+
+#include "BKE_global.h"
+
+class SphericalGrid
+{
+public:
+ // Helper classes
+ struct OccluderData
+ {
+ explicit OccluderData (OccluderSource& source, Polygon3r& p);
+ Polygon3r poly;
+ Polygon3r cameraSpacePolygon;
+ real shallowest, deepest;
+ // N.B. We could, of course, store face in poly's userdata member, like the old ViewMapBuilder code does.
+ // However, code comments make it clear that userdata is deprecated, so we avoid the temptation to save
+ // 4 or 8 bytes.
+ WFace *face;
+ };
+
+private:
+ struct Cell
+ {
+ // Can't store Cell in a vector without copy and assign
+ //Cell(const Cell& other);
+ //Cell& operator=(const Cell& other);
+
+ explicit Cell();
+ ~Cell();
+
+ static bool compareOccludersByShallowestPoint(const OccluderData *a, const OccluderData *b);
+
+ void setDimensions(real x, real y, real sizeX, real sizeY);
+ void checkAndInsert(OccluderSource& source, Polygon3r& poly, OccluderData*& occluder);
+ void indexPolygons();
+
+ real boundary[4];
+ //deque<OccluderData*> faces;
+ vector<OccluderData*> faces;
+ };
+
+public:
+ /*! Iterator needs to allow the user to avoid full 3D comparison in two cases:
+ *
+ * (1) Where (*current)->deepest < target[2], where the occluder is unambiguously in front of the target point.
+ *
+ * (2) Where (*current)->shallowest > target[2], where the occluder is unambiguously in back of the target point.
+ *
+ * In addition, when used by OptimizedFindOccludee, Iterator should stop iterating as soon as it has an occludee
+ * candidate and (*current)->shallowest > candidate[2], because at that point forward no new occluder could
+ * possibly be a better occludee.
+ */
+
+ class Iterator
+ {
+ public:
+ // epsilon is not used in this class, but other grids with the same interface may need an epsilon
+ explicit Iterator(SphericalGrid& grid, Vec3r& center, real epsilon = 1.0e-06);
+ ~Iterator();
+ void initBeforeTarget();
+ void initAfterTarget();
+ void nextOccluder();
+ void nextOccludee();
+ bool validBeforeTarget();
+ bool validAfterTarget();
+ WFace *getWFace() const;
+ Polygon3r *getCameraSpacePolygon();
+ void reportDepth(Vec3r origin, Vec3r u, real t);
+ private:
+ bool testOccluder(bool wantOccludee);
+ void markCurrentOccludeeCandidate(real depth);
+
+ Cell *_cell;
+ Vec3r _target;
+ bool _foundOccludee;
+ real _occludeeDepth;
+ //deque<OccluderData*>::iterator _current, _occludeeCandidate;
+ vector<OccluderData*>::iterator _current, _occludeeCandidate;
+ };
+
+ class Transform : public GridHelpers::Transform
+ {
+ public:
+ explicit Transform();
+ explicit Transform(Transform& other);
+ Vec3r operator()(const Vec3r& point) const;
+ static Vec3r sphericalProjection(const Vec3r& M);
+ };
+
+private:
+ // Prevent implicit copies and assignments.
+ SphericalGrid(const SphericalGrid& other);
+ SphericalGrid& operator=(const SphericalGrid& other);
+
+public:
+ explicit SphericalGrid(OccluderSource& source, GridDensityProvider& density, ViewMap *viewMap,
+ Vec3r& viewpoint, bool enableQI);
+ virtual ~SphericalGrid();
+
+ // Generate Cell structure
+ void assignCells(OccluderSource& source, GridDensityProvider& density, ViewMap *viewMap);
+ // Fill Cells
+ void distributePolygons(OccluderSource& source);
+ // Insert one polygon into each matching cell, return true if any cell consumes the polygon
+ bool insertOccluder(OccluderSource& source, OccluderData*& occluder);
+ // Sort occluders in each cell
+ void reorganizeCells();
+
+ Cell *findCell(const Vec3r& point);
+
+ // Accessors:
+ bool orthographicProjection() const;
+ const Vec3r& viewpoint() const;
+ bool enableQI() const;
+
+private:
+ void getCellCoordinates(const Vec3r& point, unsigned& x, unsigned& y);
+
+ typedef PointerSequence<vector<Cell*>, Cell*> cellContainer;
+ //typedef PointerSequence<deque<OccluderData*>, OccluderData*> occluderContainer;
+ typedef PointerSequence<vector<OccluderData*>, OccluderData*> occluderContainer;
+ unsigned _cellsX, _cellsY;
+ float _cellSize;
+ float _cellOrigin[2];
+ cellContainer _cells;
+ occluderContainer _faces;
+ Vec3r _viewpoint;
+ bool _enableQI;
+};
+
+inline void SphericalGrid::Iterator::initBeforeTarget()
+{
+ _current = _cell->faces.begin();
+ while (_current != _cell->faces.end() && !testOccluder(false)) {
+ ++_current;
+ }
+}
+
+inline void SphericalGrid::Iterator::initAfterTarget()
+{
+ if (_foundOccludee) {
+ #if SPHERICAL_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\tStarting occludee search from occludeeCandidate at depth "
+ << _occludeeDepth << std::endl;
+ }
+ #endif
+ _current = _occludeeCandidate;
+ return;
+ }
+
+ #if SPHERICAL_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\tStarting occludee search from current position" << std::endl;
+ }
+ #endif
+
+ while (_current != _cell->faces.end() && !testOccluder(true)) {
+ ++_current;
+ }
+}
+
+inline bool SphericalGrid::Iterator::testOccluder(bool wantOccludee)
+{
+ // End-of-list is not even a valid iterator position
+ if (_current == _cell->faces.end()) {
+ // Returning true seems strange, but it will break us out of whatever loop is calling testOccluder, and
+ // _current=_cell->face.end() will make the calling routine give up.
+ return true;
+ }
+ #if SPHERICAL_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\tTesting occluder " << (*_current)->poly.getVertices()[0];
+ for (unsigned int i = 1; i < (*_current)->poly.getVertices().size(); ++i) {
+ std::cout << ", " << (*_current)->poly.getVertices()[i];
+ }
+ std::cout << " from shape " << (*_current)->face->GetVertex(0)->shape()->GetId() << std::endl;
+ }
+ #endif
+
+ // If we have an occluder candidate and we are unambiguously after it, abort
+ if (_foundOccludee && (*_current)->shallowest > _occludeeDepth) {
+ #if SPHERICAL_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\t\tAborting: shallowest > occludeeCandidate->deepest" << std::endl;
+ }
+ #endif
+ _current = _cell->faces.end();
+
+ // See note above
+ return true;
+ }
+
+ // Specific continue or stop conditions when searching for each type
+ if (wantOccludee) {
+ if ((*_current)->deepest < _target[2]) {
+ #if SPHERICAL_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\t\tSkipping: shallower than target while looking for occludee" << std::endl;
+ }
+ #endif
+ return false;
+ }
+ }
+ else {
+ if ((*_current)->shallowest > _target[2]) {
+ #if SPHERICAL_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\t\tStopping: deeper than target while looking for occluder" << std::endl;
+ }
+ #endif
+ return true;
+ }
+ }
+
+ // Depthwise, this is a valid occluder.
+
+ // Check to see if target is in the 2D bounding box
+ Vec3r bbMin, bbMax;
+ (*_current)->poly.getBBox(bbMin, bbMax);
+ if (_target[0] < bbMin[0] || _target[0] > bbMax[0] || _target[1] < bbMin[1] || _target[1] > bbMax[1]) {
+ #if SPHERICAL_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\t\tSkipping: bounding box violation" << std::endl;
+ }
+ #endif
+ return false;
+ }
+
+ // We've done all the corner cutting we can. Let the caller work out whether or not the geometry is correct.
+ return true;
+}
+
+inline void SphericalGrid::Iterator::reportDepth(Vec3r origin, Vec3r u, real t)
+{
+ // The reported depth is the length of a ray in camera space. We need to convert it into the distance from viewpoint
+ // If origin is the viewpoint, depth == t. A future optimization could allow the caller to tell us if origin is
+ // viewponit or target, at the cost of changing the OptimizedGrid API.
+ real depth = (origin + u * t).norm();
+ #if SPHERICAL_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\t\tReporting depth of occluder/ee: " << depth;
+ }
+ #endif
+ if (depth > _target[2]) {
+ #if SPHERICAL_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << " is deeper than target" << std::endl;
+ }
+ #endif
+ // If the current occluder is the best occludee so far, save it.
+ if (! _foundOccludee || _occludeeDepth > depth) {
+ markCurrentOccludeeCandidate(depth);
+ }
+ }
+ else {
+ #if SPHERICAL_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << std::endl;
+ }
+ #endif
+ }
+}
+
+inline void SphericalGrid::Iterator::nextOccluder()
+{
+ if (_current != _cell->faces.end()) {
+ do {
+ ++_current;
+ } while (_current != _cell->faces.end() && !testOccluder(false));
+ }
+}
+
+inline void SphericalGrid::Iterator::nextOccludee()
+{
+ if (_current != _cell->faces.end()) {
+ do {
+ ++_current;
+ } while (_current != _cell->faces.end() && !testOccluder(true));
+ }
+}
+
+inline bool SphericalGrid::Iterator::validBeforeTarget()
+{
+ return _current != _cell->faces.end() && (*_current)->shallowest <= _target[2];
+}
+
+inline bool SphericalGrid::Iterator::validAfterTarget()
+{
+ return _current != _cell->faces.end();
+}
+
+inline void SphericalGrid::Iterator::markCurrentOccludeeCandidate(real depth)
+{
+ #if SPHERICAL_GRID_LOGGING
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ std::cout << "\t\tFound occludeeCandidate at depth " << depth << std::endl;
+ }
+ #endif
+ _occludeeCandidate = _current;
+ _occludeeDepth = depth;
+ _foundOccludee = true;
+}
+
+inline WFace *SphericalGrid::Iterator::getWFace() const
+{
+ return (*_current)->face;
+}
+
+inline Polygon3r *SphericalGrid::Iterator::getCameraSpacePolygon()
+{
+ return &((*_current)->cameraSpacePolygon);
+}
+
+inline SphericalGrid::OccluderData::OccluderData (OccluderSource& source, Polygon3r& p)
+: poly(p), cameraSpacePolygon(source.getCameraSpacePolygon()), face(source.getWFace())
+{
+ const Vec3r viewpoint(0, 0, 0);
+ // Get the point on the camera-space polygon that is closest to the viewpoint
+ // shallowest is the distance from the viewpoint to that point
+ shallowest = GridHelpers::distancePointToPolygon(viewpoint, cameraSpacePolygon);
+
+ // Get the point on the camera-space polygon that is furthest from the viewpoint
+ // deepest is the distance from the viewpoint to that point
+ deepest = cameraSpacePolygon.getVertices()[2].norm();
+ for (unsigned int i = 0; i < 2; ++i) {
+ real t = cameraSpacePolygon.getVertices()[i].norm();
+ if (t > deepest) {
+ deepest = t;
+ }
+ }
+}
+
+inline void SphericalGrid::Cell::checkAndInsert(OccluderSource& source, Polygon3r& poly, OccluderData*& occluder)
+{
+ if (GridHelpers::insideProscenium (boundary, poly)) {
+ if (occluder == NULL) {
+ // Disposal of occluder will be handled in SphericalGrid::distributePolygons(),
+ // or automatically by SphericalGrid::_faces;
+ occluder = new OccluderData(source, poly);
+ }
+ faces.push_back(occluder);
+ }
+}
+
+inline bool SphericalGrid::insertOccluder(OccluderSource& source, OccluderData*& occluder)
+{
+ Polygon3r& poly(source.getGridSpacePolygon());
+ occluder = NULL;
+
+ Vec3r bbMin, bbMax;
+ poly.getBBox(bbMin, bbMax);
+ // Check overlapping cells
+ unsigned startX, startY, endX, endY;
+ getCellCoordinates(bbMin, startX, startY);
+ getCellCoordinates(bbMax, endX, endY);
+
+ for (unsigned int i = startX; i <= endX; ++i) {
+ for (unsigned int j = startY; j <= endY; ++j) {
+ if (_cells[i * _cellsY + j] != NULL) {
+ _cells[i * _cellsY + j]->checkAndInsert(source, poly, occluder);
+ }
+ }
+ }
+
+ return occluder != NULL;
+}
+
+#endif // __FREESTYLE_SPHERICAL_GRID_H__
diff --git a/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp b/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp
new file mode 100644
index 00000000000..120ef46667b
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp
@@ -0,0 +1,302 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/SteerbaleViewMap.cpp
+ * \ingroup freestyle
+ * \brief Convenient access to the steerable ViewMap to which any element of the ViewMap belongs to.
+ * \author Stephane Grabli
+ * \date 01/07/2003
+ */
+
+#include <math.h>
+//soc #include <qimage.h>
+//soc #include <qstring.h>
+#include <sstream>
+
+#include "Silhouette.h"
+#include "SteerableViewMap.h"
+
+#include "../geometry/Geom.h"
+
+#include "../image/ImagePyramid.h"
+#include "../image/Image.h"
+
+#include "BKE_global.h"
+
+extern "C" {
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+}
+
+using namespace Geometry;
+
+SteerableViewMap::SteerableViewMap(unsigned int nbOrientations)
+{
+ _nbOrientations = nbOrientations;
+ _bound = cos(M_PI/(float)_nbOrientations);
+ for (unsigned int i = 0; i < _nbOrientations; ++i) {
+ _directions.push_back(Vec2d(cos((float)i * M_PI / (float)_nbOrientations),
+ sin((float)i * M_PI / (float)_nbOrientations)));
+ }
+ Build();
+}
+
+void SteerableViewMap::Build()
+{
+ _imagesPyramids = new ImagePyramid * [_nbOrientations + 1]; // one more map to store the complete visible VM
+ memset((_imagesPyramids), 0, (_nbOrientations + 1) * sizeof(ImagePyramid *));
+}
+
+SteerableViewMap::SteerableViewMap(const SteerableViewMap& iBrother)
+{
+ _nbOrientations = iBrother._nbOrientations;
+ unsigned int i;
+ _bound = iBrother._bound;
+ _directions = iBrother._directions;
+ _mapping = iBrother._mapping;
+ _imagesPyramids = new ImagePyramid * [_nbOrientations + 1]; // one more map to store the complete visible VM
+ for (i = 0; i < _nbOrientations + 1; ++i)
+ _imagesPyramids[i] = new GaussianPyramid(*(dynamic_cast<GaussianPyramid*>(iBrother._imagesPyramids[i])));
+}
+
+SteerableViewMap::~SteerableViewMap()
+{
+ Clear();
+}
+
+void SteerableViewMap::Clear()
+{
+ unsigned int i;
+ if (_imagesPyramids) {
+ for (i = 0; i <= _nbOrientations; ++i) {
+ if (_imagesPyramids[i])
+ delete (_imagesPyramids)[i];
+ }
+ delete[] _imagesPyramids;
+ _imagesPyramids = 0;
+ }
+ if (!_mapping.empty()) {
+ for (map<unsigned int, double*>::iterator m = _mapping.begin(), mend = _mapping.end(); m != mend; ++m) {
+ delete[] (*m).second;
+ }
+ _mapping.clear();
+ }
+}
+
+void SteerableViewMap::Reset()
+{
+ Clear();
+ Build();
+}
+
+double SteerableViewMap::ComputeWeight(const Vec2d& dir, unsigned i)
+{
+ double dotp = fabs(dir * _directions[i]);
+ if (dotp < _bound)
+ return 0.0;
+ if (dotp > 1.0)
+ dotp = 1.0;
+
+ return cos((float)_nbOrientations / 2.0 * acos(dotp));
+}
+
+double *SteerableViewMap::AddFEdge(FEdge *iFEdge)
+{
+ unsigned i;
+ unsigned id = iFEdge->getId().getFirst();
+ map<unsigned int, double* >::iterator o = _mapping.find(id);
+ if (o != _mapping.end()) {
+ return (*o).second;
+ }
+ double *res = new double[_nbOrientations];
+ for (i = 0; i < _nbOrientations; ++i) {
+ res[i] = 0.0;
+ }
+ Vec3r o2d3 = iFEdge->orientation2d();
+ Vec2r o2d2(o2d3.x(), o2d3.y());
+ real norm = o2d2.norm();
+ if (norm < 1.0e-6) {
+ return res;
+ }
+ o2d2 /= norm;
+
+ for (i = 0; i < _nbOrientations; ++i) {
+ res[i] = ComputeWeight(o2d2, i);
+ }
+ _mapping[id] = res;
+ return res;
+}
+
+unsigned SteerableViewMap::getSVMNumber(const Vec2f& orient)
+{
+ Vec2f dir(orient);
+ //soc unsigned res = 0;
+ real norm = dir.norm();
+ if (norm < 1.0e-6) {
+ return _nbOrientations + 1;
+ }
+ dir /= norm;
+ double maxw = 0.0f;
+ unsigned winner = _nbOrientations + 1;
+ for (unsigned int i = 0; i < _nbOrientations; ++i) {
+ double w = ComputeWeight(dir, i);
+ if (w > maxw) {
+ maxw = w;
+ winner = i;
+ }
+ }
+ return winner;
+}
+
+unsigned SteerableViewMap::getSVMNumber(unsigned id)
+{
+ map<unsigned int, double* >::iterator o = _mapping.find(id);
+ if (o != _mapping.end()) {
+ double *wvalues = (*o).second;
+ double maxw = 0.0;
+ unsigned winner = _nbOrientations + 1;
+ for (unsigned i = 0; i < _nbOrientations; ++i) {
+ double w = wvalues[i];
+ if (w > maxw) {
+ maxw = w;
+ winner = i;
+ }
+ }
+ return winner;
+ }
+ return _nbOrientations + 1;
+}
+
+void SteerableViewMap::buildImagesPyramids(GrayImage **steerableBases, bool copy, unsigned iNbLevels, float iSigma)
+{
+ for (unsigned int i = 0; i <= _nbOrientations; ++i) {
+ ImagePyramid *svm = (_imagesPyramids)[i];
+ if (svm)
+ delete svm;
+ if (copy)
+ svm = new GaussianPyramid(*(steerableBases[i]), iNbLevels, iSigma);
+ else
+ svm = new GaussianPyramid(steerableBases[i], iNbLevels, iSigma);
+ _imagesPyramids[i] = svm;
+ }
+}
+
+float SteerableViewMap::readSteerableViewMapPixel(unsigned iOrientation, int iLevel, int x, int y)
+{
+ ImagePyramid *pyramid = _imagesPyramids[iOrientation];
+ if (!pyramid) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Warning: this steerable ViewMap level doesn't exist" << endl;
+ }
+ return 0.0f;
+ }
+ if ((x < 0) || (x >= pyramid->width()) || (y < 0) || (y >= pyramid->height()))
+ return 0;
+ //float v = pyramid->pixel(x, pyramid->height() - 1 - y, iLevel) * 255.0f;
+ // We encode both the directionality and the lines counting on 8 bits (because of frame buffer). Thus, we allow
+ // until 8 lines to pass through the same pixel, so that we can discretize the Pi/_nbOrientations angle into
+ // 32 slices. Therefore, for example, in the vertical direction, a vertical line will have the value 32 on
+ // each pixel it passes through.
+ float v = pyramid->pixel(x, pyramid->height() - 1 - y, iLevel) / 32.0f;
+ return v;
+}
+
+float SteerableViewMap::readCompleteViewMapPixel(int iLevel, int x, int y)
+{
+ return readSteerableViewMapPixel(_nbOrientations, iLevel, x, y);
+}
+
+unsigned int SteerableViewMap::getNumberOfPyramidLevels() const
+{
+ if (_imagesPyramids[0])
+ return _imagesPyramids[0]->getNumberOfLevels();
+ return 0;
+}
+
+void SteerableViewMap::saveSteerableViewMap() const
+{
+ for (unsigned int i = 0; i <= _nbOrientations; ++i) {
+ if (_imagesPyramids[i] == 0) {
+ cerr << "SteerableViewMap warning: orientation " << i
+ << " of steerable View Map whas not been computed yet" << endl;
+ continue;
+ }
+ int ow = _imagesPyramids[i]->width(0);
+ int oh = _imagesPyramids[i]->height(0);
+
+ //soc QString base("SteerableViewMap");
+ string base("SteerableViewMap");
+ stringstream filename;
+
+ for (int j = 0; j < _imagesPyramids[i]->getNumberOfLevels(); ++j) { //soc
+ float coeff = 1.0f; // 1 / 255.0f; // 100 * 255; // * pow(2, j);
+ //soc QImage qtmp(ow, oh, QImage::Format_RGB32);
+ ImBuf *ibuf = IMB_allocImBuf(ow, oh, 32, IB_rect);
+ int rowbytes = ow * 4;
+ char *pix;
+
+ for (int y = 0; y < oh; ++y) { //soc
+ for (int x = 0; x < ow; ++x) { //soc
+ int c = (int)(coeff * _imagesPyramids[i]->pixel(x, y, j));
+ if (c > 255)
+ c = 255;
+ //int c = (int)(_imagesPyramids[i]->pixel(x, y, j));
+
+ //soc qtmp.setPixel(x, y, qRgb(c, c, c));
+ pix = (char*)ibuf->rect + y * rowbytes + x * 4;
+ pix[0] = pix [1] = pix[2] = c;
+ }
+ }
+
+ //soc qtmp.save(base+QString::number(i)+"-"+QString::number(j)+".png", "PNG");
+ filename << base;
+ filename << i << "-" << j << ".png";
+ ibuf->ftype = PNG;
+ IMB_saveiff(ibuf, const_cast<char *>(filename.str().c_str()), 0);
+ }
+#if 0
+ QString base("SteerableViewMap");
+ for (unsigned j = 0; j < _imagesPyramids[i]->getNumberOfLevels(); ++j) {
+ GrayImage *img = _imagesPyramids[i]->getLevel(j);
+ int ow = img->width();
+ int oh = img->height();
+ float coeff = 1.0f; // 100 * 255; // * pow(2, j);
+ QImage qtmp(ow, oh, 32);
+ for (unsigned int y = 0; y < oh; ++y) {
+ for (unsigned int x = 0; x < ow; ++x) {
+ int c = (int)(coeff * img->pixel(x, y));
+ if (c > 255)
+ c = 255;
+ //int c = (int)(_imagesPyramids[i]->pixel(x, y, j));
+ qtmp.setPixel(x, y, qRgb(c, c, c));
+ }
+ }
+ qtmp.save(base + QString::number(i) + "-" + QString::number(j) + ".png", "PNG");
+ }
+#endif
+ }
+}
diff --git a/source/blender/freestyle/intern/view_map/SteerableViewMap.h b/source/blender/freestyle/intern/view_map/SteerableViewMap.h
new file mode 100644
index 00000000000..a4a67c3fa7e
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/SteerableViewMap.h
@@ -0,0 +1,154 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_STEERABLE_VIEW_MAP_H__
+#define __FREESTYLE_STEERABLE_VIEW_MAP_H__
+
+/** \file blender/freestyle/intern/view_map/SteerbaleViewMap.h
+ * \ingroup freestyle
+ * \brief Convenient access to the steerable ViewMap to which any element of the ViewMap belongs to.
+ * \author Stephane Grabli
+ * \date 01/07/2003
+ */
+
+#include <map>
+
+#include "../geometry/Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace Geometry;
+
+using namespace std;
+
+class FEdge;
+class ImagePyramid;
+class GrayImage;
+
+/*! This class checks for every FEdge in which steerable it belongs and stores the mapping allowing to retrieve
+ * this information from the FEdge Id.
+ */
+class LIB_VIEW_MAP_EXPORT SteerableViewMap
+{
+protected:
+ // for each vector the list of nbOrientations weigths corresponding to its contributions
+ // to the nbOrientations directional maps
+ map<unsigned int, double*> _mapping;
+ unsigned _nbOrientations;
+ ImagePyramid **_imagesPyramids; // the pyramids of images storing the different SVM
+
+ // internal
+ double _bound; // cos(Pi/N)
+ vector<Vec2d> _directions;
+
+public:
+ SteerableViewMap(unsigned int nbOrientations = 4);
+ SteerableViewMap(const SteerableViewMap& iBrother);
+ virtual ~SteerableViewMap();
+
+ /*! Resets everything */
+ virtual void Reset();
+
+ /*! Adds a FEdge to steerable VM.
+ * Returns the nbOrientations weigths corresponding to the FEdge contributions to the nbOrientations
+ * directional maps.
+ */
+ double *AddFEdge(FEdge *iFEdge);
+
+ /*! Compute the weight of direction dir for orientation iNOrientation */
+ double ComputeWeight(const Vec2d& dir, unsigned iNOrientation);
+
+ /*! Returns the number of the SVM to which a direction belongs to.
+ * \param dir
+ * The direction
+ */
+ unsigned getSVMNumber(const Vec2f& dir);
+
+ /*! Returns the number of the SVM to which a FEdge belongs most.
+ * \param id
+ * The First element of the Id struct of the FEdge we're intersted in.
+ */
+ unsigned getSVMNumber(unsigned id);
+
+ /*! Builds _nbOrientations+1 pyramids of images from the _nbOrientations+1 base images of the steerable viewmap.
+ * \param steerableBases
+ * The _nbOrientations+1 images constituing the basis for the steerable pyramid.
+ * \param copy
+ * If false, the data is not duplicated, and Canvas deals with the memory management of these
+ * _nbOrientations+1 images. If true, data is copied, and it's up to the caller to delete the images.
+ * \params iNbLevels
+ * The number of levels desired for each pyramid.
+ * If iNbLevels == 0, the complete pyramid is built.
+ * \param iSigma
+ * The sigma that will be used for the gaussian blur
+ */
+ void buildImagesPyramids(GrayImage **steerableBases, bool copy = false, unsigned iNbLevels = 4,
+ float iSigma = 1.0f);
+
+ /*! Reads a pixel value in one of the VewMap density steerable pyramids.
+ * Returns a value between 0 and 1.
+ * \param iOrientation
+ * the number telling which orientation we need to check.
+ * There are _nbOrientations+1 oriented ViewMaps:
+ * 0 -> the ViewMap containing every horizontal lines
+ * 1 -> the ViewMap containing every lines whose orientation is around PI/4
+ * 2 -> the ViewMap containing every vertical lines
+ * 3 -> the ViewMap containing every lines whose orientation is around 3PI/4
+ * 4 -> the complete ViewMap
+ * \param iLevel
+ * The level of the pyramid we want to read
+ * \param x
+ * The abscissa of the desired pixel specified in level0 coordinate system. The origin is the lower left corner.
+ * \param y
+ * The ordinate of the desired pixel specified in level0 coordinate system. The origin is the lower left corner.
+ */
+ float readSteerableViewMapPixel(unsigned iOrientation, int iLevel, int x, int y);
+
+ /*! Reads a pixel in the one of the level of the pyramid containing the images of the complete ViewMap.
+ * Returns a value between 0 and 1.
+ * Equivalent to : readSteerableViewMapPixel(nbOrientations, x, y)
+ */
+ float readCompleteViewMapPixel(int iLevel, int x, int y);
+
+ /*! Returns the number of levels in the pyramids */
+ unsigned int getNumberOfPyramidLevels() const;
+
+ /*! Returns the number of orientations */
+ unsigned int getNumberOfOrientations() const
+ {
+ return _nbOrientations;
+ }
+
+ /*! for debug purposes */
+ void saveSteerableViewMap() const;
+
+protected:
+ void Clear();
+ void Build();
+};
+
+#endif // __FREESTYLE_STEERABLE_VIEW_MAP_H__
diff --git a/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp
new file mode 100644
index 00000000000..56c32d8e134
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp
@@ -0,0 +1,753 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp
+ * \ingroup freestyle
+ * \brief Class to build view edges and the underlying chains of feature edges...
+ * \author Stephane Grabli
+ * \date 27/10/2003
+ */
+
+#include <list>
+
+#include "SilhouetteGeomEngine.h"
+#include "ViewEdgeXBuilder.h"
+#include "ViewMap.h"
+
+#include "../winged_edge/WXEdge.h"
+
+using namespace std;
+
+void ViewEdgeXBuilder::Init(ViewShape *oVShape)
+{
+ if (0 == oVShape)
+ return;
+
+ // for design conveniance, we store the current SShape.
+ _pCurrentSShape = oVShape->sshape();
+ if (0 == _pCurrentSShape)
+ return;
+
+ _pCurrentVShape = oVShape;
+
+ // Reset previous data
+ //--------------------
+ if (!_SVertexMap.empty())
+ _SVertexMap.clear();
+}
+
+void ViewEdgeXBuilder::BuildViewEdges(WXShape *iWShape, ViewShape *oVShape, vector<ViewEdge*>& ioVEdges,
+ vector<ViewVertex*>& ioVVertices, vector<FEdge*>& ioFEdges,
+ vector<SVertex*>& ioSVertices)
+{
+ // Reinit structures
+ Init(oVShape);
+
+ /* ViewEdge *vedge; */ /* UNUSED */
+ // Let us build the smooth stuff
+ //----------------------------------------
+ // We parse all faces to find the ones that contain smooth edges
+ vector<WFace*>& wfaces = iWShape->GetFaceList();
+ vector<WFace*>::iterator wf, wfend;
+ WXFace *wxf;
+ for (wf = wfaces.begin(), wfend = wfaces.end(); wf != wfend; wf++) {
+ wxf = dynamic_cast<WXFace*>(*wf);
+ if (false == ((wxf))->hasSmoothEdges()) // does it contain at least one smooth edge ?
+ continue;
+ // parse all smooth layers:
+ vector<WXFaceLayer*>& smoothLayers = wxf->getSmoothLayers();
+ for (vector<WXFaceLayer*>::iterator sl = smoothLayers.begin(), slend = smoothLayers.end(); sl != slend; ++sl) {
+ if (!(*sl)->hasSmoothEdge())
+ continue;
+ if (stopSmoothViewEdge((*sl))) // has it been parsed already ?
+ continue;
+ // here we know that we're dealing with a face layer that has not been processed yet and that contains
+ // a smooth edge.
+ /* vedge =*/ /* UNUSED */ BuildSmoothViewEdge(OWXFaceLayer(*sl, true));
+ }
+ }
+
+ // Now let's build sharp view edges:
+ //----------------------------------
+ // Reset all userdata for WXEdge structure
+ //----------------------------------------
+ //iWShape->ResetUserData();
+
+ WXEdge *wxe;
+ vector<WEdge*>& wedges = iWShape->getEdgeList();
+ //------------------------------
+ for (vector<WEdge*>::iterator we = wedges.begin(), weend = wedges.end(); we != weend; we++) {
+ wxe = dynamic_cast<WXEdge*>(*we);
+ if (Nature::NO_FEATURE == wxe->nature())
+ continue;
+
+ if (!stopSharpViewEdge(wxe)) {
+ bool b = true;
+ if (wxe->order() == -1)
+ b = false;
+ BuildSharpViewEdge(OWXEdge(wxe, b));
+ }
+ }
+
+ // Reset all userdata for WXEdge structure
+ //----------------------------------------
+ iWShape->ResetUserData();
+
+ // Add all these new edges to the scene's feature edges list:
+ //-----------------------------------------------------------
+ vector<FEdge*>& newedges = _pCurrentSShape->getEdgeList();
+ vector<SVertex*>& newVertices = _pCurrentSShape->getVertexList();
+ vector<ViewVertex*>& newVVertices = _pCurrentVShape->vertices();
+ vector<ViewEdge*>& newVEdges = _pCurrentVShape->edges();
+
+ // inserts in ioFEdges, at its end, all the edges of newedges
+ ioFEdges.insert(ioFEdges.end(), newedges.begin(), newedges.end());
+ ioSVertices.insert(ioSVertices.end(), newVertices.begin(), newVertices.end());
+ ioVVertices.insert(ioVVertices.end(), newVVertices.begin(), newVVertices.end());
+ ioVEdges.insert(ioVEdges.end(), newVEdges.begin(), newVEdges.end());
+}
+
+ViewEdge *ViewEdgeXBuilder::BuildSmoothViewEdge(const OWXFaceLayer& iFaceLayer)
+{
+ // Find first edge:
+ OWXFaceLayer first = iFaceLayer;
+ OWXFaceLayer currentFace = first;
+
+ // bidirectional chaining.
+ // first direction
+ list<OWXFaceLayer> facesChain;
+ unsigned size = 0;
+ while (!stopSmoothViewEdge(currentFace.fl)) {
+ facesChain.push_back(currentFace);
+ ++size;
+ currentFace.fl->userdata = (void *)1; // processed
+ // Find the next edge!
+ currentFace = FindNextFaceLayer(currentFace);
+ }
+ OWXFaceLayer end = facesChain.back();
+ // second direction
+ currentFace = FindPreviousFaceLayer(first);
+ while (!stopSmoothViewEdge(currentFace.fl)) {
+ facesChain.push_front(currentFace);
+ ++size;
+ currentFace.fl->userdata = (void *)1; // processed
+ // Find the previous edge!
+ currentFace = FindPreviousFaceLayer(currentFace);
+ }
+ first = facesChain.front();
+
+ if (iFaceLayer.fl->nature() & Nature::RIDGE) {
+ if (size < 4) {
+ return 0;
+ }
+ }
+
+ // Start a new chain edges
+ ViewEdge *newVEdge = new ViewEdge;
+ newVEdge->setId(_currentViewId);
+ ++_currentViewId;
+
+ _pCurrentVShape->AddEdge(newVEdge);
+
+ // build FEdges
+ FEdge *feprevious = NULL;
+ FEdge *fefirst = NULL;
+ FEdge *fe = NULL;
+ for (list<OWXFaceLayer>::iterator fl = facesChain.begin(), flend = facesChain.end(); fl != flend; ++fl) {
+ fe = BuildSmoothFEdge(feprevious, (*fl));
+ if (feprevious && fe == feprevious)
+ continue;
+ fe->setViewEdge(newVEdge);
+ if (!fefirst)
+ fefirst = fe;
+ feprevious = fe;
+ }
+ // Store the chain starting edge:
+ _pCurrentSShape->AddChain(fefirst);
+ newVEdge->setNature(iFaceLayer.fl->nature());
+ newVEdge->setFEdgeA(fefirst);
+ newVEdge->setFEdgeB(fe);
+
+ // is it a closed loop ?
+ if ((first == end) && (size != 1)) {
+ fefirst->setPreviousEdge(fe);
+ fe->setNextEdge(fefirst);
+ newVEdge->setA(0);
+ newVEdge->setB(0);
+ }
+ else {
+ ViewVertex *vva = MakeViewVertex(fefirst->vertexA());
+ ViewVertex *vvb = MakeViewVertex(fe->vertexB());
+
+ ((NonTVertex*)vva)->AddOutgoingViewEdge(newVEdge);
+ ((NonTVertex*)vvb)->AddIncomingViewEdge(newVEdge);
+
+ newVEdge->setA(vva);
+ newVEdge->setB(vvb);
+ }
+
+ return newVEdge;
+}
+
+ViewEdge *ViewEdgeXBuilder::BuildSharpViewEdge(const OWXEdge& iWEdge)
+{
+ // Start a new sharp chain edges
+ ViewEdge *newVEdge = new ViewEdge;
+ newVEdge->setId(_currentViewId);
+ ++_currentViewId;
+ unsigned size = 0;
+
+ _pCurrentVShape->AddEdge(newVEdge);
+
+ // Find first edge:
+ OWXEdge firstWEdge = iWEdge;
+ /* OWXEdge previousWEdge = firstWEdge; */ /* UNUSED */
+ OWXEdge currentWEdge = firstWEdge;
+ list<OWXEdge> edgesChain;
+#if 0 /* TK 02-Sep-2012 Experimental fix for incorrect view edge visibility. */
+ // bidirectional chaining
+ // first direction:
+ while (!stopSharpViewEdge(currentWEdge.e)) {
+ edgesChain.push_back(currentWEdge);
+ ++size;
+ currentWEdge.e->userdata = (void *)1; // processed
+ // Find the next edge!
+ currentWEdge = FindNextWEdge(currentWEdge);
+ }
+ OWXEdge endWEdge = edgesChain.back();
+ // second direction
+ currentWEdge = FindPreviousWEdge(firstWEdge);
+ while (!stopSharpViewEdge(currentWEdge.e)) {
+ edgesChain.push_front(currentWEdge);
+ ++size;
+ currentWEdge.e->userdata = (void *)1; // processed
+ // Find the previous edge!
+ currentWEdge = FindPreviousWEdge(currentWEdge);
+ }
+#else
+ edgesChain.push_back(currentWEdge);
+ ++size;
+ currentWEdge.e->userdata = (void *)1; // processed
+ OWXEdge endWEdge = edgesChain.back();
+#endif
+ firstWEdge = edgesChain.front();
+
+ // build FEdges
+ FEdge *feprevious = NULL;
+ FEdge *fefirst = NULL;
+ FEdge *fe = NULL;
+ for (list<OWXEdge>::iterator we = edgesChain.begin(), weend = edgesChain.end(); we != weend; ++we) {
+ fe = BuildSharpFEdge(feprevious, (*we));
+ fe->setViewEdge(newVEdge);
+ if (!fefirst)
+ fefirst = fe;
+ feprevious = fe;
+ }
+ // Store the chain starting edge:
+ _pCurrentSShape->AddChain(fefirst);
+ newVEdge->setNature(iWEdge.e->nature());
+ newVEdge->setFEdgeA(fefirst);
+ newVEdge->setFEdgeB(fe);
+
+ // is it a closed loop ?
+ if ((firstWEdge == endWEdge) && (size != 1)) {
+ fefirst->setPreviousEdge(fe);
+ fe->setNextEdge(fefirst);
+ newVEdge->setA(0);
+ newVEdge->setB(0);
+ }
+ else {
+ ViewVertex *vva = MakeViewVertex(fefirst->vertexA());
+ ViewVertex *vvb = MakeViewVertex(fe->vertexB());
+
+ ((NonTVertex*)vva)->AddOutgoingViewEdge(newVEdge);
+ ((NonTVertex*)vvb)->AddIncomingViewEdge(newVEdge);
+
+ newVEdge->setA(vva);
+ newVEdge->setB(vvb);
+ }
+
+ return newVEdge;
+}
+
+OWXFaceLayer ViewEdgeXBuilder::FindNextFaceLayer(const OWXFaceLayer& iFaceLayer)
+{
+ WXFace *nextFace = NULL;
+ WOEdge *woeend;
+ real tend;
+ if (iFaceLayer.order) {
+ woeend = iFaceLayer.fl->getSmoothEdge()->woeb();
+ tend = iFaceLayer.fl->getSmoothEdge()->tb();
+ }
+ else {
+ woeend = iFaceLayer.fl->getSmoothEdge()->woea();
+ tend = iFaceLayer.fl->getSmoothEdge()->ta();
+ }
+ // special case of EDGE_VERTEX config:
+ if ((tend == 0.0) || (tend == 1.0)) {
+ WVertex *nextVertex;
+ if (tend == 0.0)
+ nextVertex = woeend->GetaVertex();
+ else
+ nextVertex = woeend->GetbVertex();
+ if (nextVertex->isBoundary()) // if it's a non-manifold vertex -> ignore
+ return OWXFaceLayer(0, true);
+ bool found = false;
+ WVertex::face_iterator f = nextVertex->faces_begin();
+ WVertex::face_iterator fend = nextVertex->faces_end();
+ while ((!found) && (f != fend)) {
+ nextFace = dynamic_cast<WXFace*>(*f);
+ if ((0 != nextFace) && (nextFace != iFaceLayer.fl->getFace())) {
+ vector<WXFaceLayer*> sameNatureLayers;
+ nextFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers);
+ // don't know... Maybe should test whether this face has also a vertex_edge configuration.
+ if (sameNatureLayers.size() == 1) {
+ WXFaceLayer *winner = sameNatureLayers[0];
+ // check face mark continuity
+ if (winner->getFace()->GetMark() != iFaceLayer.fl->getFace()->GetMark())
+ return OWXFaceLayer(NULL, true);
+ if (woeend == winner->getSmoothEdge()->woea()->twin())
+ return OWXFaceLayer(winner, true);
+ else
+ return OWXFaceLayer(winner, false);
+ }
+ }
+ ++f;
+ }
+ }
+ else {
+ nextFace = dynamic_cast<WXFace*>(iFaceLayer.fl->getFace()->GetBordingFace(woeend));
+ if (!nextFace)
+ return OWXFaceLayer(NULL, true);
+ // if the next face layer has either no smooth edge or no smooth edge of same nature, no next face
+ if (!nextFace->hasSmoothEdges())
+ return OWXFaceLayer(NULL,true);
+ vector<WXFaceLayer*> sameNatureLayers;
+ nextFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers);
+ // don't know how to deal with several edges of same nature on a single face
+ if ((sameNatureLayers.empty()) || (sameNatureLayers.size() != 1)) {
+ return OWXFaceLayer(NULL, true);
+ }
+ else {
+ WXFaceLayer *winner = sameNatureLayers[0];
+ // check face mark continuity
+ if (winner->getFace()->GetMark() != iFaceLayer.fl->getFace()->GetMark())
+ return OWXFaceLayer(NULL, true);
+ if (woeend == winner->getSmoothEdge()->woea()->twin())
+ return OWXFaceLayer(winner, true);
+ else
+ return OWXFaceLayer(winner, false);
+ }
+ }
+ return OWXFaceLayer(NULL, true);
+}
+
+OWXFaceLayer ViewEdgeXBuilder::FindPreviousFaceLayer(const OWXFaceLayer& iFaceLayer)
+{
+ WXFace *previousFace = NULL;
+ WOEdge *woebegin;
+ real tend;
+ if (iFaceLayer.order) {
+ woebegin = iFaceLayer.fl->getSmoothEdge()->woea();
+ tend = iFaceLayer.fl->getSmoothEdge()->ta();
+ }
+ else {
+ woebegin = iFaceLayer.fl->getSmoothEdge()->woeb();
+ tend = iFaceLayer.fl->getSmoothEdge()->tb();
+ }
+
+ // special case of EDGE_VERTEX config:
+ if ((tend == 0.0) || (tend == 1.0)) {
+ WVertex *previousVertex;
+ if (tend == 0.0)
+ previousVertex = woebegin->GetaVertex();
+ else
+ previousVertex = woebegin->GetbVertex();
+ if (previousVertex->isBoundary()) // if it's a non-manifold vertex -> ignore
+ return OWXFaceLayer(NULL, true);
+ bool found = false;
+ WVertex::face_iterator f = previousVertex->faces_begin();
+ WVertex::face_iterator fend = previousVertex->faces_end();
+ for (; (!found) && (f != fend); ++f) {
+ previousFace = dynamic_cast<WXFace*>(*f);
+ if ((0 != previousFace) && (previousFace!=iFaceLayer.fl->getFace())) {
+ vector<WXFaceLayer*> sameNatureLayers;
+ previousFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers);
+ // don't know... Maybe should test whether this face has also a vertex_edge configuration
+ if (sameNatureLayers.size() == 1) {
+ WXFaceLayer *winner = sameNatureLayers[0];
+ // check face mark continuity
+ if (winner->getFace()->GetMark() != iFaceLayer.fl->getFace()->GetMark())
+ return OWXFaceLayer(NULL, true);
+ if (woebegin == winner->getSmoothEdge()->woeb()->twin())
+ return OWXFaceLayer(winner, true);
+ else
+ return OWXFaceLayer(winner, false);
+ }
+ }
+ }
+ }
+ else {
+ previousFace = dynamic_cast<WXFace*>(iFaceLayer.fl->getFace()->GetBordingFace(woebegin));
+ if (0 == previousFace)
+ return OWXFaceLayer(NULL, true);
+ // if the next face layer has either no smooth edge or no smooth edge of same nature, no next face
+ if (!previousFace->hasSmoothEdges())
+ return OWXFaceLayer(NULL, true);
+ vector<WXFaceLayer*> sameNatureLayers;
+ previousFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers);
+ // don't know how to deal with several edges of same nature on a single face
+ if ((sameNatureLayers.empty()) || (sameNatureLayers.size() != 1)) {
+ return OWXFaceLayer(NULL, true);
+ }
+ else {
+ WXFaceLayer *winner = sameNatureLayers[0];
+ // check face mark continuity
+ if (winner->getFace()->GetMark() != iFaceLayer.fl->getFace()->GetMark())
+ return OWXFaceLayer(NULL, true);
+ if (woebegin == winner->getSmoothEdge()->woeb()->twin())
+ return OWXFaceLayer(winner, true);
+ else
+ return OWXFaceLayer(winner, false);
+ }
+ }
+ return OWXFaceLayer(NULL, true);
+}
+
+FEdge *ViewEdgeXBuilder::BuildSmoothFEdge(FEdge *feprevious, const OWXFaceLayer& ifl)
+{
+ WOEdge *woea, *woeb;
+ real ta, tb;
+ SVertex *va, *vb;
+ FEdgeSmooth *fe;
+ // retrieve exact silhouette data
+ WXSmoothEdge *se = ifl.fl->getSmoothEdge();
+
+ if (ifl.order) {
+ woea = se->woea();
+ woeb = se->woeb();
+ ta = se->ta();
+ tb = se->tb();
+ }
+ else {
+ woea = se->woeb();
+ woeb = se->woea();
+ ta = se->tb();
+ tb = se->ta();
+ }
+
+ Vec3r normal;
+ // Make the 2 Svertices
+ if (feprevious == 0) { // that means that we don't have any vertex already built for that face
+ Vec3r A1(woea->GetaVertex()->GetVertex());
+ Vec3r A2(woea->GetbVertex()->GetVertex());
+ Vec3r A(A1 + ta * (A2 - A1));
+
+ va = MakeSVertex(A, false);
+ // Set normal:
+ Vec3r NA1(ifl.fl->getFace()->GetVertexNormal(woea->GetaVertex()));
+ Vec3r NA2(ifl.fl->getFace()->GetVertexNormal(woea->GetbVertex()));
+ Vec3r na((1 - ta) * NA1 + ta * NA2);
+ na.normalize();
+ va->AddNormal(na);
+ normal = na;
+
+ // Set CurvatureInfo
+ CurvatureInfo *curvature_info_a =
+ new CurvatureInfo(*(dynamic_cast<WXVertex*>(woea->GetaVertex())->curvatures()),
+ *(dynamic_cast<WXVertex*>(woea->GetbVertex())->curvatures()), ta);
+ va->setCurvatureInfo(curvature_info_a);
+ }
+ else {
+ va = feprevious->vertexB();
+ }
+
+ Vec3r B1(woeb->GetaVertex()->GetVertex());
+ Vec3r B2(woeb->GetbVertex()->GetVertex());
+ Vec3r B(B1 + tb * (B2 - B1));
+
+ if (feprevious && (B - va->point3D()).norm() < 1.0e-6)
+ return feprevious;
+
+ vb = MakeSVertex(B, false);
+ // Set normal:
+ Vec3r NB1(ifl.fl->getFace()->GetVertexNormal(woeb->GetaVertex()));
+ Vec3r NB2(ifl.fl->getFace()->GetVertexNormal(woeb->GetbVertex()));
+ Vec3r nb((1 - tb) * NB1 + tb * NB2);
+ nb.normalize();
+ normal += nb;
+ vb->AddNormal(nb);
+
+ // Set CurvatureInfo
+ CurvatureInfo *curvature_info_b =
+ new CurvatureInfo(*(dynamic_cast<WXVertex*>(woeb->GetaVertex())->curvatures()),
+ *(dynamic_cast<WXVertex*>(woeb->GetbVertex())->curvatures()), tb);
+ vb->setCurvatureInfo(curvature_info_b);
+
+ // Creates the corresponding feature edge
+ fe = new FEdgeSmooth(va, vb);
+ fe->setNature(ifl.fl->nature());
+ fe->setId(_currentFId);
+ fe->setFrsMaterialIndex(ifl.fl->getFace()->frs_materialIndex());
+ fe->setFace(ifl.fl->getFace());
+ fe->setFaceMark(ifl.fl->getFace()->GetMark());
+ if (feprevious == 0)
+ normal.normalize();
+ fe->setNormal(normal);
+ fe->setPreviousEdge(feprevious);
+ if (feprevious)
+ feprevious->setNextEdge(fe);
+ _pCurrentSShape->AddEdge(fe);
+ va->AddFEdge(fe);
+ vb->AddFEdge(fe);
+
+ ++_currentFId;
+ ifl.fl->userdata = fe;
+ return fe;
+}
+
+bool ViewEdgeXBuilder::stopSmoothViewEdge(WXFaceLayer *iFaceLayer)
+{
+ if (0 == iFaceLayer)
+ return true;
+ if (iFaceLayer->userdata == 0)
+ return false;
+ return true;
+}
+
+int ViewEdgeXBuilder::retrieveFaceMarks(WXEdge *iEdge)
+{
+ WFace *aFace = iEdge->GetaFace();
+ WFace *bFace = iEdge->GetbFace();
+ int result = 0;
+ if (aFace && aFace->GetMark())
+ result += 1;
+ if (bFace && bFace->GetMark())
+ result += 2;
+ return result;
+}
+
+OWXEdge ViewEdgeXBuilder::FindNextWEdge(const OWXEdge& iEdge)
+{
+ if (Nature::NO_FEATURE == iEdge.e->nature())
+ return OWXEdge(NULL, true);
+
+ WVertex *v;
+ if (true == iEdge.order)
+ v = iEdge.e->GetbVertex();
+ else
+ v = iEdge.e->GetaVertex();
+
+ if (((WXVertex*)v)->isFeature())
+ return 0; /* XXX eeek? NULL? OWXEdge(NULL, true/false)?*/
+
+ int faceMarks = retrieveFaceMarks(iEdge.e);
+ vector<WEdge*>& vEdges = (v)->GetEdges();
+ for (vector<WEdge*>::iterator ve = vEdges.begin(), veend = vEdges.end(); ve != veend; ve++) {
+ WXEdge *wxe = dynamic_cast<WXEdge*>(*ve);
+ if (wxe == iEdge.e)
+ continue; // same edge as the one processed
+
+ if (wxe->nature() != iEdge.e->nature())
+ continue;
+
+ // check face mark continuity
+ if (retrieveFaceMarks(wxe) != faceMarks)
+ continue;
+
+ if (wxe->GetaVertex() == v) {
+ // That means that the face necesarily lies on the edge left.
+ // So the vertex order is OK.
+ return OWXEdge(wxe, true);
+ }
+ else {
+ // That means that the face necesarily lies on the edge left.
+ // So the vertex order is OK.
+ return OWXEdge(wxe, false);
+ }
+ }
+ // we did not find:
+ return OWXEdge(NULL, true);
+}
+
+OWXEdge ViewEdgeXBuilder::FindPreviousWEdge(const OWXEdge& iEdge)
+{
+ if (Nature::NO_FEATURE == iEdge.e->nature())
+ return OWXEdge(NULL, true);
+
+ WVertex *v;
+ if (true == iEdge.order)
+ v = iEdge.e->GetaVertex();
+ else
+ v = iEdge.e->GetbVertex();
+
+ if (((WXVertex*)v)->isFeature())
+ return 0;
+
+ int faceMarks = retrieveFaceMarks(iEdge.e);
+ vector<WEdge*>& vEdges = (v)->GetEdges();
+ for (vector<WEdge*>::iterator ve = vEdges.begin(), veend = vEdges.end(); ve != veend; ve++) {
+ WXEdge *wxe = dynamic_cast<WXEdge*>(*ve);
+ if (wxe == iEdge.e)
+ continue; // same edge as the one processed
+
+ if (wxe->nature() != iEdge.e->nature())
+ continue;
+
+ // check face mark continuity
+ if (retrieveFaceMarks(wxe) != faceMarks)
+ continue;
+
+ if (wxe->GetbVertex() == v) {
+ return OWXEdge(wxe, true);
+ }
+ else {
+ return OWXEdge(wxe, false);
+ }
+ }
+ // we did not find:
+ return OWXEdge(NULL, true);
+}
+
+FEdge *ViewEdgeXBuilder::BuildSharpFEdge(FEdge *feprevious, const OWXEdge& iwe)
+{
+ SVertex *va, *vb;
+ FEdgeSharp *fe;
+ WXVertex *wxVA, *wxVB;
+ if (iwe.order) {
+ wxVA = (WXVertex *)iwe.e->GetaVertex();
+ wxVB = (WXVertex *)iwe.e->GetbVertex();
+ }
+ else {
+ wxVA = (WXVertex *)iwe.e->GetbVertex();
+ wxVB = (WXVertex *)iwe.e->GetaVertex();
+ }
+ // Make the 2 SVertex
+ va = MakeSVertex(wxVA->GetVertex(), true);
+ vb = MakeSVertex(wxVB->GetVertex(), true);
+
+ // get the faces normals and the material indices
+ Vec3r normalA, normalB;
+ unsigned matA(0), matB(0);
+ bool faceMarkA = false, faceMarkB = false;
+ if (iwe.order) {
+ normalB = (iwe.e->GetbFace()->GetNormal());
+ matB = (iwe.e->GetbFace()->frs_materialIndex());
+ faceMarkB = (iwe.e->GetbFace()->GetMark());
+ if (!(iwe.e->nature() & Nature::BORDER)) {
+ normalA = (iwe.e->GetaFace()->GetNormal());
+ matA = (iwe.e->GetaFace()->frs_materialIndex());
+ faceMarkA = (iwe.e->GetaFace()->GetMark());
+ }
+ }
+ else {
+ normalA = (iwe.e->GetbFace()->GetNormal());
+ matA = (iwe.e->GetbFace()->frs_materialIndex());
+ faceMarkA = (iwe.e->GetbFace()->GetMark());
+ if (!(iwe.e->nature() & Nature::BORDER)) {
+ normalB = (iwe.e->GetaFace()->GetNormal());
+ matB = (iwe.e->GetaFace()->frs_materialIndex());
+ faceMarkB = (iwe.e->GetaFace()->GetMark());
+ }
+ }
+ // Creates the corresponding feature edge
+ fe = new FEdgeSharp(va, vb);
+ fe->setNature(iwe.e->nature());
+ fe->setId(_currentFId);
+ fe->setaFrsMaterialIndex(matA);
+ fe->setbFrsMaterialIndex(matB);
+ fe->setaFaceMark(faceMarkA);
+ fe->setbFaceMark(faceMarkB);
+ fe->setNormalA(normalA);
+ fe->setNormalB(normalB);
+ fe->setPreviousEdge(feprevious);
+ if (feprevious)
+ feprevious->setNextEdge(fe);
+ _pCurrentSShape->AddEdge(fe);
+ va->AddFEdge(fe);
+ vb->AddFEdge(fe);
+ //Add normals:
+ va->AddNormal(normalA);
+ va->AddNormal(normalB);
+ vb->AddNormal(normalA);
+ vb->AddNormal(normalB);
+
+ ++_currentFId;
+ iwe.e->userdata = fe;
+ return fe;
+}
+
+bool ViewEdgeXBuilder::stopSharpViewEdge(WXEdge *iEdge)
+{
+ if (0 == iEdge)
+ return true;
+ if (iEdge->userdata == 0)
+ return false;
+ return true;
+}
+
+SVertex *ViewEdgeXBuilder::MakeSVertex(Vec3r& iPoint)
+{
+ SVertex *va = new SVertex(iPoint, _currentSVertexId);
+ SilhouetteGeomEngine::ProjectSilhouette(va);
+ ++_currentSVertexId;
+ // Add the svertex to the SShape svertex list:
+ _pCurrentSShape->AddNewVertex(va);
+ return va;
+}
+
+SVertex *ViewEdgeXBuilder::MakeSVertex(Vec3r& iPoint, bool shared)
+{
+ SVertex *va;
+ if (!shared) {
+ va = MakeSVertex(iPoint);
+ }
+ else {
+ // Check whether the iPoint is already in the table
+ SVertexMap::const_iterator found = _SVertexMap.find(iPoint);
+ if (shared && found != _SVertexMap.end()) {
+ va = (*found).second;
+ }
+ else {
+ va = MakeSVertex(iPoint);
+ // Add the svertex into the table using iPoint as the key
+ _SVertexMap[iPoint] = va;
+ }
+ }
+ return va;
+}
+
+ViewVertex *ViewEdgeXBuilder::MakeViewVertex(SVertex *iSVertex)
+{
+ ViewVertex *vva = iSVertex->viewvertex();
+ if (vva)
+ return vva;
+ vva = new NonTVertex(iSVertex);
+ // Add the view vertex to the ViewShape svertex list:
+ _pCurrentVShape->AddVertex(vva);
+ return vva;
+}
diff --git a/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.h b/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.h
new file mode 100644
index 00000000000..2883919a852
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.h
@@ -0,0 +1,288 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_VIEW_EDGE_X_BUILDER_H__
+#define __FREESTYLE_VIEW_EDGE_X_BUILDER_H__
+
+/** \file blender/freestyle/intern/view_map/ViewEdgeXBuilder.h
+ * \ingroup freestyle
+ * \brief Class to build view edges and the underlying chains of feature edges...
+ * \author Stephane Grabli
+ * \date 27/10/2003
+ */
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#if 0 // soc
+#if defined(__GNUC__) && (__GNUC__ >= 3)
+//hash_map is not part of the C++ standard anymore; hash_map.h has been kept though for backward compatibility
+# include <hash_map.h>
+#else
+# include <hash_map>
+#endif
+#endif
+
+#include "Interface1D.h"
+
+#include "../geometry/Geom.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace Geometry;
+using namespace std;
+
+class SVertex;
+
+/*! Defines a hash table used for searching the SVertex */
+struct SVertexHasher
+{
+#define _MUL 950706376UL
+#define _MOD 2147483647UL
+ inline size_t operator()(const Vec3r& p) const
+ {
+ size_t res = ((unsigned long)(p[0] * _MUL)) % _MOD;
+ res = ((res + (unsigned long)(p[1]) * _MUL)) % _MOD;
+ return ((res +(unsigned long)(p[2]) * _MUL)) % _MOD;
+ }
+#undef _MUL
+#undef _MOD
+};
+
+// Key_compare predicate for hash_map. In particular, return false if equal.
+struct epsilonEquals
+{
+ bool operator()(const Vec3r& v1, const Vec3r& v2) const
+ {
+ real norm = (v1 - v2).norm();
+ return (norm < 1.0e-06);
+ }
+};
+
+
+// typedef hash_map<Vec3r, SVertex*, SVertexHasher, epsilonEquals> SVertexMap;
+typedef map<Vec3r , SVertex*> SVertexMap;
+
+class WXFaceLayer;
+
+/*! class to describe an oriented smooth edge */
+class OWXFaceLayer
+{
+public:
+ WXFaceLayer *fl;
+ bool order;
+
+ OWXFaceLayer()
+ {
+ fl = NULL;
+ order = true;
+ }
+
+ OWXFaceLayer(WXFaceLayer *ifl, bool iOrder = true)
+ {
+ fl = ifl;
+ order = iOrder;
+ }
+
+ OWXFaceLayer& operator=(const OWXFaceLayer& iBrother)
+ {
+ fl = iBrother.fl;
+ order = iBrother.order;
+ return *this;
+ }
+
+ bool operator==(const OWXFaceLayer& b)
+ {
+ return ((fl == b.fl) && (order == b.order));
+ }
+
+ bool operator!=(const OWXFaceLayer& b)
+ {
+ return !(*this == b);
+ }
+};
+
+class WXEdge;
+
+/*! class to describe an oriented sharp edge */
+class OWXEdge
+{
+public:
+ WXEdge *e;
+ bool order;
+
+ OWXEdge()
+ {
+ e = NULL;
+ order = true;
+ }
+
+ OWXEdge(WXEdge *ie, bool iOrder = true)
+ {
+ e = ie;
+ order = iOrder;
+ }
+
+ OWXEdge& operator=(const OWXEdge& iBrother)
+ {
+ e = iBrother.e;
+ order = iBrother.order;
+ return *this;
+ }
+
+ bool operator==(const OWXEdge& b)
+ {
+ return ((e == b.e) && (order == b.order));
+ }
+
+ bool operator!=(const OWXEdge& b)
+ {
+ return !(*this == b);
+ }
+};
+
+class WOEdge;
+class WXEdge;
+class WXShape;
+class SVertex;
+class FEdge;
+class ViewVertex;
+class ViewEdge;
+class ViewShape;
+
+class LIB_VIEW_MAP_EXPORT ViewEdgeXBuilder
+{
+protected:
+ int _currentViewId; // Id for view edges
+ int _currentFId; // Id for FEdges
+ int _currentSVertexId; // Id for SVertex
+
+public:
+ inline ViewEdgeXBuilder()
+ {
+ _currentViewId = 1;
+ _currentFId = 0;
+ _currentSVertexId = 0;
+ }
+
+ virtual ~ViewEdgeXBuilder() {}
+
+ /*! Builds a view shape from a WXShape in which the feature edges are flagged
+ * Builds chains of feature edges (so ViewEdges) from a WXShape
+ * iWShape
+ * The Winged Edge structure in which all silhouette edges and vertices are flagged.
+ * oViewShape
+ * The Silhouette Shape in which the chains must be added.
+ * ioVEdges
+ * The list of new ViewEdges.
+ * ioVVertices
+ * THe new ViewVertices
+ * ioFEdges
+ * A list in which all new FEdges are added
+ * ioSVertices
+ * A list of SVertex where all created SVertex are added.
+ */
+ virtual void BuildViewEdges(WXShape *iWShape, ViewShape *oVShape, std::vector<ViewEdge*>& ioVEdges,
+ std::vector<ViewVertex*>& ioVVertices, std::vector<FEdge*>& ioFEdges,
+ std::vector<SVertex*>& ioSVertices);
+
+ /*! Builds a smooth view edge, starting the face iFace. */
+ ViewEdge *BuildSmoothViewEdge(const OWXFaceLayer& iFaceLayer);
+
+ /*! Makes a sharp viewedge */
+ ViewEdge *BuildSharpViewEdge(const OWXEdge& iWEdge);
+
+public:
+ /*! accessors */
+ inline int currentViewId() const
+ {
+ return _currentViewId;
+ }
+
+ inline int currentFId() const
+ {
+ return _currentFId;
+ }
+
+ inline int currentSVertexId() const
+ {
+ return _currentSVertexId;
+ }
+
+ /*! modifiers */
+ inline void setCurrentViewId(int id)
+ {
+ _currentViewId = id;
+ }
+
+ inline void setCurrentFId(int id)
+ {
+ _currentFId = id;
+ }
+
+ inline void setCurrentSVertexId(int id)
+ {
+ _currentSVertexId = id;
+ }
+
+protected:
+ /*! Init the view edges building */
+ virtual void Init(ViewShape *oVShape);
+
+ // SMOOTH //
+ /*! checks whether a face has already been processed or not */
+ bool stopSmoothViewEdge(WXFaceLayer *iFaceLayer);
+ OWXFaceLayer FindNextFaceLayer(const OWXFaceLayer& iFaceLayer);
+ OWXFaceLayer FindPreviousFaceLayer(const OWXFaceLayer& iFaceLayer);
+ FEdge *BuildSmoothFEdge(FEdge *feprevious, const OWXFaceLayer& ifl);
+
+ // SHARP //
+ /*! checks whether a WEdge has already been processed or not */
+ bool stopSharpViewEdge(WXEdge *iFace);
+ int retrieveFaceMarks(WXEdge *iEdge);
+ OWXEdge FindNextWEdge(const OWXEdge& iEdge);
+ OWXEdge FindPreviousWEdge(const OWXEdge& iEdge);
+ FEdge *BuildSharpFEdge(FEdge *feprevious, const OWXEdge& iwe);
+
+ // GENERAL //
+ /*! Instanciate a SVertex */
+ SVertex *MakeSVertex(Vec3r& iPoint);
+ /*! Instanciate a SVertex if it hasn't been already created */
+ SVertex *MakeSVertex(Vec3r& iPoint, bool shared);
+ /*! instanciate a ViewVertex from a SVertex, if it doesn't exist yet */
+ ViewVertex *MakeViewVertex(SVertex *iSVertex);
+
+ //oldtmp values
+ //IdHashTable _hashtable;
+ //VVIdHashTable _multivertexHashTable;
+ SVertexMap _SVertexMap;
+ SShape *_pCurrentSShape;
+ ViewShape *_pCurrentVShape;
+};
+
+#endif // __FREESTYLE_VIEW_EDGE_X_BUILDER_H__
diff --git a/source/blender/freestyle/intern/view_map/ViewMap.cpp b/source/blender/freestyle/intern/view_map/ViewMap.cpp
new file mode 100644
index 00000000000..9f8b5e08200
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ViewMap.cpp
@@ -0,0 +1,753 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/ViewMap.cpp
+ * \ingroup freestyle
+ * \brief Classes to define a View Map (ViewVertex, ViewEdge, etc.)
+ * \author Stephane Grabli
+ * \date 03/09/2002
+ */
+
+#include <float.h>
+
+#include "ViewMap.h"
+#include "ViewMapAdvancedIterators.h"
+#include "ViewMapIterators.h"
+
+#include "../geometry/GeomUtils.h"
+
+/**********************************/
+/* */
+/* */
+/* ViewMap */
+/* */
+/* */
+/**********************************/
+
+ViewMap *ViewMap::_pInstance = NULL;
+
+ViewMap::~ViewMap()
+{
+ // The view vertices must be deleted here as some of them are shared between two shapes:
+ for (vector<ViewVertex*>::iterator vv = _VVertices.begin(), vvend = _VVertices.end(); vv != vvend; vv++) {
+ delete (*vv);
+ }
+ _VVertices.clear();
+
+ for (vector<ViewShape*>::iterator vs = _VShapes.begin(), vsend = _VShapes.end(); vs != vsend; vs++) {
+ delete (*vs);
+ }
+ _VShapes.clear();
+
+ _FEdges.clear();
+ _SVertices.clear();
+ _VEdges.clear();
+}
+
+ViewShape *ViewMap::viewShape(unsigned id)
+{
+ int index = _shapeIdToIndex[id];
+ return _VShapes[ index ];
+}
+
+void ViewMap::AddViewShape(ViewShape *iVShape)
+{
+ _shapeIdToIndex[iVShape->getId().getFirst()] = _VShapes.size();
+ _VShapes.push_back(iVShape);
+}
+
+const FEdge *ViewMap::getClosestFEdge(real x, real y) const
+{
+ // find the closest of this candidates:
+ real minDist = DBL_MAX;
+ FEdge *winner = NULL;
+ for (fedges_container::const_iterator fe = _FEdges.begin(), feend = _FEdges.end(); fe != feend; fe++) {
+ Vec2d A((*fe)->vertexA()->point2D()[0], (*fe)->vertexA()->point2D()[1]);
+ Vec2d B((*fe)->vertexB()->point2D()[0], (*fe)->vertexB()->point2D()[1]);
+ real dist = GeomUtils::distPointSegment<Vec2r>(Vec2r(x, y), A, B);
+ if (dist < minDist) {
+ minDist = dist;
+ winner = (*fe);
+ }
+ }
+
+ return winner;
+}
+
+const ViewEdge *ViewMap::getClosestViewEdge(real x, real y) const
+{
+ // find the closest of this candidates:
+ real minDist = DBL_MAX;
+ FEdge *winner = NULL;
+ for (fedges_container::const_iterator fe = _FEdges.begin(), feend = _FEdges.end(); fe != feend; fe++) {
+ Vec2d A((*fe)->vertexA()->point2D()[0], (*fe)->vertexA()->point2D()[1]);
+ Vec2d B((*fe)->vertexB()->point2D()[0], (*fe)->vertexB()->point2D()[1]);
+ real dist = GeomUtils::distPointSegment<Vec2r>(Vec2r(x, y), A, B);
+ if (dist < minDist) {
+ minDist = dist;
+ winner = (*fe);
+ }
+ }
+ if (!winner)
+ return NULL;
+
+ return winner->viewedge();
+}
+
+
+TVertex *ViewMap::CreateTVertex(const Vec3r& iA3D, const Vec3r& iA2D, FEdge *iFEdgeA,
+ const Vec3r& iB3D, const Vec3r& iB2D, FEdge *iFEdgeB, const Id& id)
+{
+ ViewShape *vshapeA = iFEdgeA->viewedge()->viewShape();
+ SShape *shapeA = iFEdgeA->shape();
+ ViewShape *vshapeB = iFEdgeB->viewedge()->viewShape();
+ SShape *shapeB = iFEdgeB->shape();
+
+ SVertex *Ia = shapeA->CreateSVertex(iA3D, iA2D, iFEdgeA->vertexA()->getId());
+ SVertex *Ib = shapeB->CreateSVertex(iB3D, iB2D, iFEdgeB->vertexA()->getId());
+
+ // depending on which of these 2 svertices is the nearest from the viewpoint, we're going to build the TVertex
+ // by giving them in an order or another (the first one must be the nearest)
+ real dista = Ia->point2D()[2];
+ real distb = Ib->point2D()[2];
+
+ TVertex *tvertex;
+ if (dista < distb)
+ tvertex = new TVertex(Ia, Ib);
+ else
+ tvertex = new TVertex(Ib, Ia);
+
+ tvertex->setId(id);
+
+ // add these vertices to the view map
+ AddViewVertex(tvertex);
+ AddSVertex(Ia);
+ AddSVertex(Ib);
+
+ // and this T Vertex to the view shapes:
+ vshapeA->AddVertex(tvertex);
+ vshapeB->AddVertex(tvertex);
+
+ return tvertex;
+}
+
+ViewVertex *ViewMap::InsertViewVertex(SVertex *iVertex, vector<ViewEdge*>& newViewEdges)
+{
+ NonTVertex *vva = dynamic_cast<NonTVertex*>(iVertex->viewvertex());
+ if (vva)
+ return vva;
+ // because it is not already a ViewVertex, this SVertex must have only 2 FEdges. The incoming one still belongs
+ // to ioEdge, the outgoing one now belongs to newVEdge
+ const vector<FEdge*>& fedges = iVertex->fedges();
+ if (fedges.size() != 2) {
+ cerr << "ViewMap warning: Can't split the ViewEdge" << endl;
+ return NULL;
+ }
+ FEdge *fend(0), *fbegin(0);
+ for (vector<FEdge*>::const_iterator fe = fedges.begin(), feend = fedges.end(); fe != feend; ++fe) {
+ if ((*fe)->vertexB() == iVertex) {
+ fend = (*fe);
+ }
+ if ((*fe)->vertexA() == iVertex) {
+ fbegin = (*fe);
+ }
+ if ((fbegin!=0) && (fend!=0))
+ break;
+ }
+ ViewEdge *ioEdge = fbegin->viewedge();
+ ViewShape * vshape = ioEdge->viewShape();
+ vva = new NonTVertex(iVertex);
+ // if the ViewEdge is a closed loop, we don't create a new VEdge
+ if (ioEdge->A() == 0) {
+ // closed loop
+ ioEdge->setA(vva);
+ ioEdge->setB(vva);
+ // update sshape
+ vshape->sshape()->RemoveEdgeFromChain(ioEdge->fedgeA());
+ vshape->sshape()->RemoveEdgeFromChain(ioEdge->fedgeB());
+
+ ioEdge->setFEdgeA(fbegin);
+ ioEdge->setFEdgeB(fend);
+
+ // Update FEdges
+ fend->setNextEdge(NULL);
+ fbegin->setPreviousEdge(NULL);
+
+ // update new View Vertex:
+ vva->AddOutgoingViewEdge(ioEdge);
+ vva->AddIncomingViewEdge(ioEdge);
+
+ vshape->sshape()->AddChain(ioEdge->fedgeA());
+ vshape->sshape()->AddChain(ioEdge->fedgeB());
+ }
+ else {
+ // Create new ViewEdge
+ ViewEdge *newVEdge = new ViewEdge(vva, ioEdge->B(), fbegin, ioEdge->fedgeB(), vshape);
+ newVEdge->setId(Id(ioEdge->getId().getFirst(), ioEdge->getId().getSecond() + 1));
+ newVEdge->setNature(ioEdge->getNature());
+ //newVEdge->UpdateFEdges(); // done in the ViewEdge constructor
+ // Update old ViewEdge
+ ioEdge->setB(vva);
+ ioEdge->setFEdgeB(fend);
+
+ // Update FEdges
+ fend->setNextEdge(NULL);
+ fbegin->setPreviousEdge(NULL);
+
+ // update new View Vertex:
+ vva->AddOutgoingViewEdge(newVEdge);
+ vva->AddIncomingViewEdge(ioEdge);
+ // update ViewShape
+ //vshape->AddEdge(newVEdge);
+ // update SShape
+ vshape->sshape()->AddChain(fbegin);
+ // update ViewMap
+ //_VEdges.push_back(newVEdge);
+ newViewEdges.push_back(newVEdge);
+ }
+
+ // update ViewShape
+ vshape->AddVertex(vva);
+
+ // update ViewMap
+ _VVertices.push_back(vva);
+
+ return vva;
+}
+
+#if 0
+FEdge *ViewMap::Connect(FEdge *ioEdge, SVertex *ioVertex, vector<ViewEdge*>& oNewVEdges)
+{
+ SShape *sshape = ioEdge->shape();
+ FEdge *newFEdge = sshape->SplitEdgeIn2(ioEdge, ioVertex);
+ AddFEdge(newFEdge);
+ InsertViewVertex(ioVertex, oNewVEdges);
+ return newFEdge;
+}
+#endif
+
+/**********************************/
+/* */
+/* */
+/* TVertex */
+/* */
+/* */
+/**********************************/
+
+// is dve1 before dve2 ? (does it have a smaller angle ?)
+static bool ViewEdgeComp(ViewVertex::directedViewEdge& dve1, ViewVertex::directedViewEdge& dve2)
+{
+ FEdge *fe1;
+ if (dve1.second)
+ fe1 = dve1.first->fedgeB();
+ else
+ fe1 = dve1.first->fedgeA();
+ FEdge *fe2;
+ if (dve2.second)
+ fe2 = dve2.first->fedgeB();
+ else
+ fe2 = dve2.first->fedgeA();
+
+ Vec3r V1 = fe1->orientation2d();
+ Vec2r v1(V1.x(), V1.y());
+ v1.normalize();
+ Vec3r V2 = fe2->orientation2d();
+ Vec2r v2(V2.x(), V2.y());
+ v2.normalize();
+ if (v1.y() > 0) {
+ if (v2.y() < 0)
+ return true;
+ else
+ return (v1.x() > v2.x());
+ }
+ else {
+ if (v2.y() > 0)
+ return false;
+ else
+ return (v1.x() < v2.x());
+ }
+ return false;
+}
+
+void TVertex::setFrontEdgeA(ViewEdge *iFrontEdgeA, bool incoming)
+{
+ if (!iFrontEdgeA) {
+ cerr << "Warning: null pointer passed as argument of TVertex::setFrontEdgeA()" << endl;
+ return;
+ }
+ _FrontEdgeA = directedViewEdge(iFrontEdgeA, incoming);
+ if (!_sortedEdges.empty()) {
+ edge_pointers_container::iterator dve = _sortedEdges.begin(), dveend = _sortedEdges.end();
+ for (; (dve != dveend) && ViewEdgeComp(**dve, _FrontEdgeA); ++dve);
+ _sortedEdges.insert( dve, &_FrontEdgeA);
+ }
+ else {
+ _sortedEdges.push_back(&_FrontEdgeA);
+ }
+}
+
+void TVertex::setFrontEdgeB(ViewEdge *iFrontEdgeB, bool incoming)
+{
+ if (!iFrontEdgeB) {
+ cerr << "Warning: null pointer passed as argument of TVertex::setFrontEdgeB()" << endl;
+ return;
+ }
+ _FrontEdgeB = directedViewEdge(iFrontEdgeB, incoming);
+ if (!_sortedEdges.empty()) {
+ edge_pointers_container::iterator dve = _sortedEdges.begin(), dveend = _sortedEdges.end();
+ for (; (dve != dveend) && ViewEdgeComp(**dve, _FrontEdgeB); ++dve);
+ _sortedEdges.insert(dve, &_FrontEdgeB);
+ }
+ else {
+ _sortedEdges.push_back(&_FrontEdgeB);
+ }
+}
+
+void TVertex::setBackEdgeA(ViewEdge *iBackEdgeA, bool incoming)
+{
+ if (!iBackEdgeA) {
+ cerr << "Warning: null pointer passed as argument of TVertex::setBackEdgeA()" << endl;
+ return;
+ }
+ _BackEdgeA = directedViewEdge(iBackEdgeA, incoming);
+ if (!_sortedEdges.empty()) {
+ edge_pointers_container::iterator dve = _sortedEdges.begin(), dveend = _sortedEdges.end();
+ for (; (dve != dveend) && ViewEdgeComp(**dve, _BackEdgeA); ++dve);
+ _sortedEdges.insert(dve, &_BackEdgeA);
+ }
+ else {
+ _sortedEdges.push_back(&_BackEdgeA);
+ }
+}
+
+void TVertex::setBackEdgeB(ViewEdge *iBackEdgeB, bool incoming)
+{
+ if (!iBackEdgeB) {
+ cerr << "Warning: null pointer passed as argument of TVertex::setBackEdgeB()" << endl;
+ return;
+ }
+ _BackEdgeB = directedViewEdge(iBackEdgeB, incoming);
+ if (!_sortedEdges.empty()) {
+ edge_pointers_container::iterator dve = _sortedEdges.begin(), dveend = _sortedEdges.end();
+ for (; (dve != dveend) && ViewEdgeComp(**dve, _BackEdgeB); ++dve);
+ _sortedEdges.insert(dve, &_BackEdgeB);
+ }
+ else {
+ _sortedEdges.push_back(&_BackEdgeB);
+ }
+}
+
+void TVertex::Replace(ViewEdge *iOld, ViewEdge *iNew)
+{
+ // theoritically, we only replace edges for which this
+ // view vertex is the B vertex
+ if ((iOld == _FrontEdgeA.first) && (_FrontEdgeA.first->B() == this)) {
+ _FrontEdgeA.first = iNew;
+ return;
+ }
+ if ((iOld == _FrontEdgeB.first) && (_FrontEdgeB.first->B() == this)) {
+ _FrontEdgeB.first = iNew;
+ return;
+ }
+ if ((iOld == _BackEdgeA.first) && (_BackEdgeA.first->B() == this)) {
+ _BackEdgeA.first = iNew;
+ return;
+ }
+ if ((iOld == _BackEdgeB.first) && (_BackEdgeB.first->B() == this)) {
+ _BackEdgeB.first = iNew;
+ return;
+ }
+}
+
+/*! iterators access */
+ViewVertex::edge_iterator TVertex::edges_begin()
+{
+ //return edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, _FrontEdgeA);
+ return edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin());
+}
+
+ViewVertex::const_edge_iterator TVertex::edges_begin() const
+{
+ //return const_edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, _FrontEdgeA);
+ return const_edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin());
+}
+
+ViewVertex::edge_iterator TVertex::edges_end()
+{
+ //return edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, directedViewEdge(0,true));
+ return edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.end());
+}
+
+ViewVertex::const_edge_iterator TVertex::edges_end() const
+{
+ //return const_edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, directedViewEdge(0, true));
+ return const_edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.end());
+}
+
+ViewVertex::edge_iterator TVertex::edges_iterator(ViewEdge *iEdge)
+{
+ for (edge_pointers_container::iterator it = _sortedEdges.begin(), itend = _sortedEdges.end(); it != itend; it++) {
+ if ((*it)->first == iEdge)
+ return edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), it);
+ }
+ return edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin());
+
+#if 0
+ directedViewEdge dEdge;
+ if (_FrontEdgeA.first == iEdge)
+ dEdge = _FrontEdgeA;
+ else if (_FrontEdgeB.first == iEdge)
+ dEdge = _FrontEdgeB;
+ else if (_BackEdgeA.first == iEdge)
+ dEdge = _BackEdgeA;
+ else if (_BackEdgeB.first == iEdge)
+ dEdge = _BackEdgeB;
+ return edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, dEdge);
+#endif
+}
+
+ViewVertex::const_edge_iterator TVertex::edges_iterator(ViewEdge *iEdge) const
+{
+ for (edge_pointers_container::const_iterator it = _sortedEdges.begin(), itend = _sortedEdges.end();
+ it != itend;
+ it++)
+ {
+ if ((*it)->first == iEdge)
+ return const_edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), it);
+ }
+ return const_edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin());
+
+#if 0
+ directedViewEdge dEdge;
+ if (_FrontEdgeA.first == iEdge)
+ dEdge = _FrontEdgeA;
+ else if (_FrontEdgeB.first == iEdge)
+ dEdge = _FrontEdgeB;
+ else if (_BackEdgeA.first == iEdge)
+ dEdge = _BackEdgeA;
+ else if (_BackEdgeB.first == iEdge)
+ dEdge = _BackEdgeB;
+ return const_edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, dEdge);
+#endif
+}
+
+ViewVertexInternal::orientedViewEdgeIterator TVertex::edgesBegin()
+{
+ return ViewVertexInternal::orientedViewEdgeIterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin());
+}
+
+ViewVertexInternal::orientedViewEdgeIterator TVertex::edgesEnd()
+{
+ return ViewVertexInternal::orientedViewEdgeIterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.end());
+}
+
+ViewVertexInternal::orientedViewEdgeIterator TVertex::edgesIterator(ViewEdge *iEdge)
+{
+ for (edge_pointers_container::iterator it = _sortedEdges.begin(), itend = _sortedEdges.end(); it != itend; it++) {
+ if ((*it)->first == iEdge)
+ return ViewVertexInternal::orientedViewEdgeIterator(_sortedEdges.begin(), _sortedEdges.end(), it);
+ }
+ return ViewVertexInternal::orientedViewEdgeIterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin());
+}
+
+/**********************************/
+/* */
+/* */
+/* NonTVertex */
+/* */
+/* */
+/**********************************/
+
+void NonTVertex::AddOutgoingViewEdge(ViewEdge *iVEdge){
+ // let's keep the viewedges ordered in CCW order in the 2D image plan
+ directedViewEdge idve(iVEdge, false);
+ if (!_ViewEdges.empty()) {
+ edges_container::iterator dve = _ViewEdges.begin(), dveend = _ViewEdges.end();
+ for (; (dve != dveend) && ViewEdgeComp(*dve, idve); ++dve);
+ _ViewEdges.insert(dve, idve);
+ }
+ else {
+ _ViewEdges.push_back(idve);
+ }
+}
+
+void NonTVertex::AddIncomingViewEdge(ViewEdge *iVEdge)
+{
+ // let's keep the viewedges ordered in CCW order in the 2D image plan
+ directedViewEdge idve(iVEdge, true);
+ if (!_ViewEdges.empty()) {
+ edges_container::iterator dve = _ViewEdges.begin(), dveend = _ViewEdges.end();
+ for (; (dve != dveend) && ViewEdgeComp(*dve, idve); ++dve);
+ _ViewEdges.insert(dve, idve);
+ }
+ else {
+ _ViewEdges.push_back(idve);
+ }
+}
+
+/*! iterators access */
+ViewVertex::edge_iterator NonTVertex::edges_begin()
+{
+ return edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin());
+}
+
+ViewVertex::const_edge_iterator NonTVertex::edges_begin() const
+{
+ return const_edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin());
+}
+
+ViewVertex::edge_iterator NonTVertex::edges_end()
+{
+ return edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.end());
+}
+
+ViewVertex::const_edge_iterator NonTVertex::edges_end() const
+{
+ return const_edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.end());
+}
+
+ViewVertex::edge_iterator NonTVertex::edges_iterator(ViewEdge *iEdge)
+{
+ for (edges_container::iterator it = _ViewEdges.begin(), itend = _ViewEdges.end(); it != itend; it++) {
+ if ((it)->first == iEdge)
+ return edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), it);
+ }
+ return edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin());
+}
+
+ViewVertex::const_edge_iterator NonTVertex::edges_iterator(ViewEdge *iEdge) const
+{
+ for (edges_container::const_iterator it = _ViewEdges.begin(), itend = _ViewEdges.end(); it != itend; it++) {
+ if ((it)->first == iEdge)
+ return const_edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), it);
+ }
+ return const_edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin());
+}
+
+ViewVertexInternal::orientedViewEdgeIterator NonTVertex::edgesBegin()
+{
+ return ViewVertexInternal::orientedViewEdgeIterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin());
+}
+
+ViewVertexInternal::orientedViewEdgeIterator NonTVertex::edgesEnd()
+{
+ return ViewVertexInternal::orientedViewEdgeIterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.end());
+}
+
+ViewVertexInternal::orientedViewEdgeIterator NonTVertex::edgesIterator(ViewEdge *iEdge)
+{
+ for (edges_container::iterator it = _ViewEdges.begin(), itend = _ViewEdges.end(); it != itend; it++) {
+ if ((it)->first == iEdge)
+ return ViewVertexInternal::orientedViewEdgeIterator(_ViewEdges.begin(), _ViewEdges.end(), it);
+ }
+ return ViewVertexInternal::orientedViewEdgeIterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin());
+}
+
+/**********************************/
+/* */
+/* */
+/* ViewEdge */
+/* */
+/* */
+/**********************************/
+
+real ViewEdge::getLength2D() const
+{
+ float length = 0.0f;
+ ViewEdge::const_fedge_iterator itlast = fedge_iterator_last();
+ ViewEdge::const_fedge_iterator it = fedge_iterator_begin(), itend = fedge_iterator_end();
+ Vec2r seg;
+ do {
+ seg = Vec2r((*it)->orientation2d()[0], (*it)->orientation2d()[1]);
+ length += seg.norm();
+ ++it;
+ } while ((it != itend) && (it != itlast));
+ return length;
+}
+
+//! view edge iterator
+ViewEdge::edge_iterator ViewEdge::ViewEdge_iterator()
+{
+ return edge_iterator(this);
+}
+
+ViewEdge::const_edge_iterator ViewEdge::ViewEdge_iterator() const
+{
+ return const_edge_iterator((ViewEdge*)this);
+}
+
+//! feature edge iterator
+ViewEdge::fedge_iterator ViewEdge::fedge_iterator_begin()
+{
+ return fedge_iterator(this->_FEdgeA, this->_FEdgeB);
+}
+
+ViewEdge::const_fedge_iterator ViewEdge::fedge_iterator_begin() const
+{
+ return const_fedge_iterator(this->_FEdgeA, this->_FEdgeB);
+}
+
+ViewEdge::fedge_iterator ViewEdge::fedge_iterator_last()
+{
+ return fedge_iterator(this->_FEdgeB, this->_FEdgeB);
+}
+
+ViewEdge::const_fedge_iterator ViewEdge::fedge_iterator_last() const
+{
+ return const_fedge_iterator(this->_FEdgeB, this->_FEdgeB);
+}
+
+ViewEdge::fedge_iterator ViewEdge::fedge_iterator_end()
+{
+ return fedge_iterator(0, this->_FEdgeB);
+}
+
+ViewEdge::const_fedge_iterator ViewEdge::fedge_iterator_end() const
+{
+ return const_fedge_iterator(0, this->_FEdgeB);
+}
+
+//! embedding vertex iterator
+ViewEdge::const_vertex_iterator ViewEdge::vertices_begin() const
+{
+ return const_vertex_iterator(this->_FEdgeA->vertexA(), 0, _FEdgeA);
+}
+
+ViewEdge::vertex_iterator ViewEdge::vertices_begin()
+{
+ return vertex_iterator(this->_FEdgeA->vertexA(), 0, _FEdgeA);
+}
+
+ViewEdge::const_vertex_iterator ViewEdge::vertices_last() const
+{
+ return const_vertex_iterator(this->_FEdgeB->vertexB(), _FEdgeB, 0);
+}
+
+ViewEdge::vertex_iterator ViewEdge::vertices_last()
+{
+ return vertex_iterator(this->_FEdgeB->vertexB(), _FEdgeB, 0);
+}
+
+ViewEdge::const_vertex_iterator ViewEdge::vertices_end() const
+{
+ return const_vertex_iterator(0, _FEdgeB, 0);
+}
+
+ViewEdge::vertex_iterator ViewEdge::vertices_end()
+{
+ return vertex_iterator(0, _FEdgeB, 0);
+}
+
+Interface0DIterator ViewEdge::verticesBegin()
+{
+ Interface0DIterator ret(new ViewEdgeInternal::SVertexIterator(this->_FEdgeA->vertexA(),
+ this->_FEdgeA->vertexA(), NULL, _FEdgeA, 0.0f));
+ return ret;
+}
+
+Interface0DIterator ViewEdge::verticesEnd()
+{
+ Interface0DIterator ret(new ViewEdgeInternal::SVertexIterator(NULL, this->_FEdgeA->vertexA(),
+ _FEdgeB, NULL, getLength2D()));
+ return ret;
+}
+
+Interface0DIterator ViewEdge::pointsBegin(float t)
+{
+ return verticesBegin();
+}
+
+Interface0DIterator ViewEdge::pointsEnd(float t)
+{
+ return verticesEnd();
+}
+
+ /**********************************/
+ /* */
+ /* */
+ /* ViewShape */
+ /* */
+ /* */
+ /**********************************/
+
+ViewShape::~ViewShape()
+{
+ _Vertices.clear();
+
+ if (!(_Edges.empty())) {
+ for (vector<ViewEdge*>::iterator e = _Edges.begin(), eend = _Edges.end(); e != eend; e++) {
+ delete (*e);
+ }
+ _Edges.clear();
+ }
+
+ if (_SShape) {
+ delete _SShape;
+ _SShape = NULL;
+ }
+}
+
+void ViewShape::RemoveEdge(ViewEdge *iViewEdge)
+{
+ FEdge *fedge = iViewEdge->fedgeA();
+ for (vector<ViewEdge*>::iterator ve = _Edges.begin(), veend = _Edges.end(); ve != veend; ve++) {
+ if (iViewEdge == (*ve)) {
+ _Edges.erase(ve);
+ _SShape->RemoveEdge(fedge);
+ break;
+ }
+ }
+}
+
+void ViewShape::RemoveVertex(ViewVertex *iViewVertex)
+{
+ for (vector<ViewVertex*>::iterator vv = _Vertices.begin(), vvend = _Vertices.end(); vv != vvend; vv++) {
+ if (iViewVertex == (*vv)) {
+ _Vertices.erase(vv);
+ break;
+ }
+ }
+}
+
+/**********************************/
+/* */
+/* */
+/* ViewEdge */
+/* */
+/* */
+/**********************************/
+
+void ViewEdge::UpdateFEdges()
+{
+ FEdge *currentEdge = _FEdgeA;
+ do {
+ currentEdge->setViewEdge(this);
+ currentEdge = currentEdge->nextEdge();
+ } while ((currentEdge != NULL) && (currentEdge != _FEdgeB));
+ // last one
+ _FEdgeB->setViewEdge(this);
+}
diff --git a/source/blender/freestyle/intern/view_map/ViewMap.h b/source/blender/freestyle/intern/view_map/ViewMap.h
new file mode 100644
index 00000000000..e29b2ae7cd6
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ViewMap.h
@@ -0,0 +1,1779 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_VIEW_MAP_H__
+#define __FREESTYLE_VIEW_MAP_H__
+
+/** \file blender/freestyle/intern/view_map/ViewMap.h
+ * \ingroup freestyle
+ * \brief Classes to define a View Map (ViewVertex, ViewEdge, etc.)
+ * \author Stephane Grabli
+ * \date 03/09/2002
+ */
+
+#include <map>
+
+#include "Interface0D.h"
+#include "Interface1D.h"
+#include "Silhouette.h" // defines the embedding
+
+#include "../geometry/GeomUtils.h"
+
+#include "../system/BaseIterator.h"
+#include "../system/FreestyleConfig.h"
+
+/**********************************/
+/* */
+/* */
+/* ViewMap */
+/* */
+/* */
+/**********************************/
+
+
+/* Density
+ * Mean area depth value
+ * distance to a point
+ */
+
+class ViewVertex;
+class ViewEdge;
+class ViewShape;
+class TVertex;
+
+/*! Class defining the ViewMap.*/
+class LIB_VIEW_MAP_EXPORT ViewMap
+{
+public:
+ typedef vector<ViewEdge*> viewedges_container;
+ typedef vector<ViewVertex*> viewvertices_container;
+ typedef vector<ViewShape*> viewshapes_container;
+ typedef vector<SVertex*> svertices_container;
+ typedef vector<FEdge*> fedges_container;
+ typedef map<int, int> id_to_index_map;
+
+private:
+ static ViewMap *_pInstance;
+ viewshapes_container _VShapes; // view shapes
+ viewedges_container _VEdges; // view edges
+ viewvertices_container _VVertices; // view vertices
+ fedges_container _FEdges; // feature edges (embedded edges)
+ svertices_container _SVertices; // embedded vertices
+ BBox<Vec3r> _scene3DBBox;
+ // Mapping between the WShape or VShape id to the VShape index in the _VShapes vector. Used in the method
+ // viewShape(int id) to access a shape from its id.
+ id_to_index_map _shapeIdToIndex;
+
+public:
+ /*! A field that can be used by the user to store any data.
+ * This field must be reseted afterwards using ResetUserData().
+ */
+ void *userdata;
+
+ /*! Default constructor. */
+ ViewMap()
+ {
+ _pInstance = this;
+ userdata = NULL;
+ }
+
+ /*! Destructor. */
+ virtual ~ViewMap();
+
+ /*! Gets the viewedge the nearest to the 2D position specified as argument */
+ const ViewEdge *getClosestViewEdge(real x, real y) const;
+
+ /*! Gets the Fedge the nearest to the 2D position specified as argument */
+ const FEdge *getClosestFEdge(real x, real y) const;
+
+ /* accessors */
+ /*! The ViewMap is a singleton class. This static method returns the instance of the ViewMap. */
+ static inline ViewMap *getInstance()
+ {
+ return _pInstance;
+ }
+
+ /* Returns the list of ViewShapes of the scene. */
+ inline viewshapes_container& ViewShapes()
+ {
+ return _VShapes;
+ }
+
+ /* Returns the list of ViewEdges of the scene. */
+ inline viewedges_container& ViewEdges()
+ {
+ return _VEdges;
+ }
+
+ /* Returns the list of ViewVertices of the scene. */
+ inline viewvertices_container& ViewVertices()
+ {
+ return _VVertices;
+ }
+
+ /* Returns the list of FEdges of the scene. */
+ inline fedges_container& FEdges()
+ {
+ return _FEdges;
+ }
+
+ /* Returns the list of SVertices of the scene. */
+ inline svertices_container& SVertices()
+ {
+ return _SVertices;
+ }
+
+ /* Returns an iterator pointing onto the first ViewEdge of the list. */
+ inline viewedges_container::iterator viewedges_begin()
+ {
+ return _VEdges.begin();
+ }
+
+ inline viewedges_container::iterator viewedges_end()
+ {
+ return _VEdges.end();
+ }
+
+ inline int viewedges_size()
+ {
+ return _VEdges.size();
+ }
+
+ ViewShape *viewShape(unsigned index);
+
+ id_to_index_map& shapeIdToIndexMap()
+ {
+ return _shapeIdToIndex;
+ }
+
+ /*! Returns the scene 3D bounding box. */
+ inline BBox<Vec3r> getScene3dBBox() const
+ {
+ return _scene3DBBox;
+ }
+
+ /* modifiers */
+ void AddViewShape(ViewShape *iVShape);
+
+ inline void AddViewEdge(ViewEdge *iVEdge)
+ {
+ _VEdges.push_back(iVEdge);
+ }
+
+ inline void AddViewVertex(ViewVertex *iVVertex)
+ {
+ _VVertices.push_back(iVVertex);
+ }
+
+ inline void AddFEdge(FEdge *iFEdge)
+ {
+ _FEdges.push_back(iFEdge);
+ }
+
+ inline void AddSVertex(SVertex *iSVertex)
+ {
+ _SVertices.push_back(iSVertex);
+ }
+
+ /*! Sets the scene 3D bounding box. */
+ inline void setScene3dBBox(const BBox<Vec3r>& bbox)
+ {
+ _scene3DBBox = bbox;
+ }
+
+ /* Creates a T vertex in the view map.
+ * A T vertex is the intersection between 2 FEdges (before these ones are splitted).
+ * The TVertex is a 2D intersection but it corresponds to a 3D point on each of the 2 FEdges.
+ * iA3D
+ * The 3D coordinates of the point corresponding to the intersection on the first edge.
+ * iA2D
+ * The x,y,z 2D coordinates of the projection of iA3D
+ * iFEdgeA
+ * The first FEdge
+ * iB3D
+ * The 3D coordinates of the point corresponding to the intersection on the second edge.
+ * iB2D
+ * The x,y,z 2D coordinates of the projection of iB3D
+ * iFEdgeB
+ * The second FEdge
+ * id
+ * The id that must be given to that TVertex
+ */
+ TVertex *CreateTVertex(const Vec3r& iA3D, const Vec3r& iA2D, FEdge *iFEdgeA, const Vec3r& iB3D, const Vec3r& iB2D,
+ FEdge *iFEdgeB, const Id& id);
+
+ /* Updates the structures to take into account the fact that a SVertex must now be considered as a ViewVertex
+ * iVertex
+ * The SVertex on top of which the ViewVertex is built (it is necessarily a NonTVertex because it is a SVertex)
+ * newViewEdges
+ * The new ViewEdges that must be add to the ViewMap
+ */
+ ViewVertex *InsertViewVertex(SVertex *iVertex, vector<ViewEdge*>& newViewEdges);
+
+ /* connects a FEdge to the graph trough a SVertex */
+ //FEdge *Connect(FEdge *ioEdge, SVertex *ioVertex);
+};
+
+/**********************************/
+/* */
+/* */
+/* ViewVertex */
+/* */
+/* */
+/**********************************/
+
+class ViewEdge;
+class SShape;
+
+namespace ViewVertexInternal {
+
+class edge_const_traits;
+class edge_nonconst_traits;
+template<class Traits> class edge_iterator_base;
+class orientedViewEdgeIterator;
+
+} // end of namespace ViewEdgeInternal
+
+/*! Class to define a view vertex.
+ * A view vertex is a feature vertex corresponding to a point of the image graph, where the characteristics of an
+ * edge might change (nature, visibility, ...).
+ * A ViewVertex can be of two kinds: a TVertex when it corresponds to the intersection between two ViewEdges or a
+ * NonTVertex when it corresponds to a vertex of the initial input mesh (it is the case for vertices such as corners
+ * for example). Thus, this class can be specialized into two classes, the TVertex class and the NonTVertex class.
+ */
+class LIB_VIEW_MAP_EXPORT ViewVertex : public Interface0D
+{
+public: // Implementation of Interface0D
+ /*! Returns the string "ViewVertex". */
+ virtual string getExactTypeName() const
+ {
+ return "ViewVertex";
+ }
+
+public:
+ friend class ViewShape;
+ typedef pair<ViewEdge*, bool> directedViewEdge; // if bool = true, the ViewEdge is incoming
+
+ typedef vector<directedViewEdge> edges_container;
+
+ typedef ViewVertexInternal::edge_iterator_base<ViewVertexInternal::edge_nonconst_traits> edge_iterator;
+ typedef ViewVertexInternal::edge_iterator_base<ViewVertexInternal::edge_const_traits> const_edge_iterator;
+
+private:
+ Nature::VertexNature _Nature;
+
+public:
+ /*! A field that can be used by the user to store any data.
+ * This field must be reseted afterwards using ResetUserData().
+ */
+ void *userdata;
+
+ /*! Default constructor.*/
+ inline ViewVertex()
+ {
+ userdata = NULL;
+ _Nature = Nature::VIEW_VERTEX;
+ }
+
+ inline ViewVertex(Nature::VertexNature nature)
+ {
+ userdata = NULL;
+ _Nature = Nature::VIEW_VERTEX | nature;
+ }
+
+protected:
+ /*! Copy constructor. */
+ inline ViewVertex(ViewVertex& iBrother)
+ {
+ _Nature = iBrother._Nature;
+ iBrother.userdata = this;
+ userdata = NULL;
+ }
+
+ /*! Cloning method. */
+ virtual ViewVertex *duplicate() = 0;
+
+public:
+ /*! Destructor. */
+ virtual ~ViewVertex() {}
+
+ /* accessors */
+ /*! Returns the nature of the vertex .*/
+ virtual Nature::VertexNature getNature() const
+ {
+ return _Nature;
+ }
+
+ /* modifiers */
+ /*! Sets the nature of the vertex. */
+ inline void setNature(Nature::VertexNature iNature)
+ {
+ _Nature = iNature;
+ }
+
+ /* Replaces old edge by new edge */
+ virtual void Replace(ViewEdge *, ViewEdge *) {}
+
+public:
+ /* iterators access */
+ // allows iteration on the edges that comes from/goes to this vertex in CCW order (order defined in 2D in the
+ // image plan)
+ virtual edge_iterator edges_begin() = 0;
+ virtual const_edge_iterator edges_begin() const = 0;
+ virtual edge_iterator edges_end() = 0;
+ virtual const_edge_iterator edges_end() const = 0;
+ virtual edge_iterator edges_iterator(ViewEdge *iEdge) = 0;
+ virtual const_edge_iterator edges_iterator(ViewEdge *iEdge) const = 0;
+
+ // Iterator access
+ /*! Returns an iterator over the ViewEdges that goes to or comes from this ViewVertex pointing to the first
+ * ViewEdge of the list. The orientedViewEdgeIterator allows to iterate in CCW order over these ViewEdges
+ * and to get the orientation for each ViewEdge (incoming/outgoing).
+ */
+ virtual ViewVertexInternal::orientedViewEdgeIterator edgesBegin() = 0;
+
+ /*! Returns an orientedViewEdgeIterator over the ViewEdges around this ViewVertex, pointing after the last ViewEdge.
+ */
+ virtual ViewVertexInternal::orientedViewEdgeIterator edgesEnd() = 0;
+
+ /*! Returns an orientedViewEdgeIterator pointing to the ViewEdge given as argument. */
+ virtual ViewVertexInternal::orientedViewEdgeIterator edgesIterator(ViewEdge *iEdge) = 0;
+};
+
+/**********************************/
+/* */
+/* */
+/* TVertex */
+/* */
+/* */
+/**********************************/
+
+/*! class to define a T vertex, i.e. an intersection between two edges.
+ * It points towards 2 SVertex and 4 View edges.
+ * Among these ViewEdges, 2 are front and 2 are back.
+ * Basically the front edge hides part of the back edge.
+ * So, among the back edges, 1 is of invisibility n and the other of visibility n+1
+ */
+class LIB_VIEW_MAP_EXPORT TVertex : public ViewVertex
+{
+public:
+ typedef vector<directedViewEdge*> edge_pointers_container;
+
+public: // Implementation of Interface0D
+ /*! Returns the string "TVertex". */
+ virtual string getExactTypeName() const
+ {
+ return "TVertex";
+ }
+
+ // Data access methods
+ /* Returns the 3D x coordinate of the vertex. Ambiguous in this case. */
+ virtual real getX() const
+ {
+ cerr << "Warning: getX() undefined for this point" << endl;
+ return _FrontSVertex->point3D().x();
+ }
+
+ virtual real getY() const
+ {
+ cerr << "Warning: getX() undefined for this point" << endl;
+ return _FrontSVertex->point3D().y();
+ }
+
+ virtual real getZ() const
+ {
+ cerr << "Warning: getX() undefined for this point" << endl;
+ return _FrontSVertex->point3D().z();
+ }
+
+ /*! Returns the 3D point. */
+ virtual Vec3f getPoint3D() const
+ {
+ cerr << "Warning: getPoint3D() undefined for this point" << endl;
+ return _FrontSVertex->getPoint3D();
+ }
+
+ /*! Returns the projected 3D x coordinate of the vertex. */
+ virtual real getProjectedX() const
+ {
+ return _FrontSVertex->point2D().x();
+ }
+
+ /*! Returns the projected 3D y coordinate of the vertex. */
+ virtual real getProjectedY() const
+ {
+ return _FrontSVertex->point2D().y();
+ }
+
+ virtual real getProjectedZ() const
+ {
+ return _FrontSVertex->point2D().z();
+ }
+
+ /*! Returns the 2D point. */
+ virtual Vec2f getPoint2D() const
+ {
+ return _FrontSVertex->getPoint2D();
+ }
+
+ /*! Returns the Id of the TVertex. */
+ virtual Id getId() const
+ {
+ return _Id;
+ }
+
+ /*! Cast the Interface0D in SVertex if it can be. */
+ // it can't
+ virtual ViewVertex *castToViewVertex()
+ {
+ return this;
+ }
+
+ /*! Cast the Interface0D in TVertex if it can be. */
+ virtual TVertex *castToTVertex()
+ {
+ return this;
+ }
+
+private:
+ SVertex *_FrontSVertex;
+ SVertex *_BackSVertex;
+ directedViewEdge _FrontEdgeA;
+ directedViewEdge _FrontEdgeB;
+ directedViewEdge _BackEdgeA;
+ directedViewEdge _BackEdgeB;
+ Id _Id; // id to identify t vertices . these id will be negative in order not to be mixed with NonTVertex ids.
+ edge_pointers_container _sortedEdges; // the list of the four ViewEdges, ordered in CCW order (in the image plan)
+
+public:
+ /*! Default constructor.*/
+ inline TVertex() : ViewVertex(Nature::T_VERTEX)
+ {
+ _FrontSVertex = NULL;
+ _BackSVertex = NULL;
+ _FrontEdgeA.first = 0;
+ _FrontEdgeB.first = 0;
+ _BackEdgeA.first = 0;
+ _BackEdgeB.first = 0;
+ }
+
+ inline TVertex(SVertex *svFront, SVertex *svBack) : ViewVertex(Nature::T_VERTEX)
+ {
+ _FrontSVertex = svFront;
+ _BackSVertex = svBack;
+ _FrontEdgeA.first = 0;
+ _FrontEdgeB.first = 0;
+ _BackEdgeA.first = 0;
+ _BackEdgeB.first = 0;
+ svFront->setViewVertex(this);
+ svBack->setViewVertex(this);
+ }
+
+protected:
+ /*! Copy constructor. */
+ inline TVertex(TVertex& iBrother) : ViewVertex(iBrother)
+ {
+ _FrontSVertex = iBrother._FrontSVertex;
+ _BackSVertex = iBrother._BackSVertex;
+ _FrontEdgeA = iBrother._FrontEdgeA;
+ _FrontEdgeB = iBrother._FrontEdgeB;
+ _BackEdgeA = iBrother._BackEdgeA;
+ _BackEdgeB = iBrother._BackEdgeB;
+ _sortedEdges = iBrother._sortedEdges;
+ }
+
+ /*! Cloning method. */
+ virtual ViewVertex *duplicate()
+ {
+ TVertex *clone = new TVertex(*this);
+ return clone;
+ }
+
+public:
+ /* accessors */
+ /*! Returns the SVertex that is closer to the viewpoint. */
+ inline SVertex *frontSVertex()
+ {
+ return _FrontSVertex;
+ }
+
+ /*! Returns the SVertex that is further away from the viewpoint. */
+ inline SVertex *backSVertex()
+ {
+ return _BackSVertex;
+ }
+
+ inline directedViewEdge& frontEdgeA()
+ {
+ return _FrontEdgeA;
+ }
+
+ inline directedViewEdge& frontEdgeB()
+ {
+ return _FrontEdgeB;
+ }
+
+ inline directedViewEdge& backEdgeA()
+ {
+ return _BackEdgeA;
+ }
+
+ inline directedViewEdge& backEdgeB()
+ {
+ return _BackEdgeB;
+ }
+
+ /* modifiers */
+ /*! Sets the SVertex that is closer to the viewpoint. */
+ inline void setFrontSVertex(SVertex *iFrontSVertex)
+ {
+ _FrontSVertex = iFrontSVertex;
+ _FrontSVertex->setViewVertex(this);
+ }
+
+ /*! Sets the SVertex that is further away from the viewpoint. */
+ inline void setBackSVertex(SVertex *iBackSVertex)
+ {
+ _BackSVertex = iBackSVertex;
+ _BackSVertex->setViewVertex(this);
+ }
+
+ void setFrontEdgeA(ViewEdge *iFrontEdgeA, bool incoming = true);
+ void setFrontEdgeB(ViewEdge *iFrontEdgeB, bool incoming = true);
+ void setBackEdgeA(ViewEdge *iBackEdgeA, bool incoming = true);
+ void setBackEdgeB(ViewEdge *iBackEdgeB, bool incoming = true);
+
+ /*! Sets the Id. */
+ inline void setId(const Id& iId)
+ {
+ _Id = iId;
+ }
+
+ /*! Returns the SVertex (among the 2) belonging to the FEdge iFEdge */
+ inline SVertex *getSVertex(FEdge *iFEdge)
+ {
+ const vector<FEdge*>& vfEdges = _FrontSVertex->fedges();
+ vector<FEdge*>::const_iterator fe, fend;
+ for (fe = vfEdges.begin(), fend = vfEdges.end(); fe != fend; fe++) {
+ if ((*fe) == iFEdge)
+ return _FrontSVertex;
+ }
+
+ const vector<FEdge*>& vbEdges = _BackSVertex->fedges();
+ for (fe = vbEdges.begin(), fend = vbEdges.end(); fe != fend; fe++) {
+ if ((*fe) == iFEdge)
+ return _BackSVertex;
+ }
+ return NULL;
+ }
+
+ virtual void Replace(ViewEdge *iOld, ViewEdge *iNew);
+
+ /*! returns the mate edge of iEdgeA.
+ * For example, if iEdgeA is frontEdgeA, then frontEdgeB is returned. If iEdgeA is frontEdgeB then frontEdgeA
+ * is returned. Same for back edges
+ */
+ virtual ViewEdge *mate(ViewEdge *iEdgeA)
+ {
+ if (iEdgeA == _FrontEdgeA.first)
+ return _FrontEdgeB.first;
+ if (iEdgeA == _FrontEdgeB.first)
+ return _FrontEdgeA.first;
+ if (iEdgeA == _BackEdgeA.first)
+ return _BackEdgeB.first;
+ if (iEdgeA == _BackEdgeB.first)
+ return _BackEdgeA.first;
+ return NULL;
+ }
+
+ /* iterators access */
+ virtual edge_iterator edges_begin();
+ virtual const_edge_iterator edges_begin() const;
+ virtual edge_iterator edges_end();
+ virtual const_edge_iterator edges_end() const;
+ virtual edge_iterator edges_iterator(ViewEdge *iEdge);
+ virtual const_edge_iterator edges_iterator(ViewEdge *iEdge) const;
+
+ /*! Returns an iterator over the ViewEdges that goes to or comes from this ViewVertex pointing to the first
+ * ViewEdge of the list. The orientedViewEdgeIterator allows to iterate in CCW order over these ViewEdges
+ * and to get the orientation for each ViewEdge (incoming/outgoing).
+ */
+ virtual ViewVertexInternal::orientedViewEdgeIterator edgesBegin();
+
+ /*! Returns an orientedViewEdgeIterator over the ViewEdges around this ViewVertex, pointing after the last ViewEdge.
+ */
+ virtual ViewVertexInternal::orientedViewEdgeIterator edgesEnd();
+
+ /*! Returns an orientedViewEdgeIterator pointing to the ViewEdge given as argument. */
+ virtual ViewVertexInternal::orientedViewEdgeIterator edgesIterator(ViewEdge *iEdge);
+};
+
+
+/**********************************/
+/* */
+/* */
+/* NonTVertex */
+/* */
+/* */
+/**********************************/
+
+
+// (non T vertex)
+/*! View vertex for corners, cusps, etc...
+ * Associated to a single SVertex.
+ * Can be associated to 2 or several view edges
+ */
+class LIB_VIEW_MAP_EXPORT NonTVertex : public ViewVertex
+{
+public:
+ typedef vector<directedViewEdge> edges_container;
+
+public: // Implementation of Interface0D
+ /*! Returns the string "ViewVertex". */
+ virtual string getExactTypeName() const
+ {
+ return "NonTVertex";
+ }
+
+ // Data access methods
+ /*! Returns the 3D x coordinate of the vertex. */
+ virtual real getX() const
+ {
+ return _SVertex->point3D().x();
+ }
+
+ /*! Returns the 3D y coordinate of the vertex. */
+ virtual real getY() const
+ {
+ return _SVertex->point3D().y();
+ }
+
+ /*! Returns the 3D z coordinate of the vertex. */
+ virtual real getZ() const
+ {
+ return _SVertex->point3D().z();
+ }
+
+ /*! Returns the 3D point. */
+ virtual Vec3f getPoint3D() const
+ {
+ return _SVertex->getPoint3D();
+ }
+
+ /*! Returns the projected 3D x coordinate of the vertex. */
+ virtual real getProjectedX() const
+ {
+ return _SVertex->point2D().x();
+ }
+
+ /*! Returns the projected 3D y coordinate of the vertex. */
+ virtual real getProjectedY() const
+ {
+ return _SVertex->point2D().y();
+ }
+
+ /*! Returns the projected 3D z coordinate of the vertex. */
+ virtual real getProjectedZ() const
+ {
+ return _SVertex->point2D().z();
+ }
+
+ /*! Returns the 2D point. */
+ virtual Vec2f getPoint2D() const
+ {
+ return _SVertex->getPoint2D();
+ }
+
+ /*! Returns the Id of the vertex. */
+ virtual Id getId() const
+ {
+ return _SVertex->getId();
+ }
+
+ /*! Cast the Interface0D in SVertex if it can be. */
+ virtual SVertex *castToSVertex()
+ {
+ return _SVertex;
+ }
+
+ /*! Cast the Interface0D in ViewVertex if it can be. */
+ virtual ViewVertex *castToViewVertex()
+ {
+ return this;
+ }
+
+ /*! Cast the Interface0D in NonTVertex if it can be. */
+ virtual NonTVertex *castToNonTVertex()
+ {
+ return this;
+ }
+
+private:
+ SVertex *_SVertex;
+ edges_container _ViewEdges;
+
+public:
+ /*! Default constructor.*/
+ inline NonTVertex() : ViewVertex(Nature::NON_T_VERTEX)
+ {
+ _SVertex = NULL;
+ }
+
+ /*! Builds a NonTVertex from a SVertex. */
+ inline NonTVertex(SVertex* iSVertex) : ViewVertex(Nature::NON_T_VERTEX)
+ {
+ _SVertex = iSVertex;
+ _SVertex->setViewVertex(this);
+ }
+
+protected:
+ /*! Copy constructor. */
+ inline NonTVertex(NonTVertex& iBrother) : ViewVertex(iBrother)
+ {
+ _SVertex = iBrother._SVertex;
+ _SVertex->setViewVertex(this);
+ _ViewEdges = iBrother._ViewEdges;
+ }
+
+ /*! Cloning method. */
+ virtual ViewVertex *duplicate()
+ {
+ NonTVertex *clone = new NonTVertex(*this);
+ return clone;
+ }
+
+public:
+ /*! destructor. */
+ virtual ~NonTVertex() {}
+
+ /* accessors */
+ /*! Returns the SVertex on top of which this NonTVertex is built. */
+ inline SVertex *svertex()
+ {
+ return _SVertex;
+ }
+
+ inline edges_container& viewedges()
+ {
+ return _ViewEdges;
+ }
+
+ /* modifiers */
+ /*! Sets the SVertex on top of which this NonTVertex is built. */
+ inline void setSVertex(SVertex *iSVertex)
+ {
+ _SVertex = iSVertex;
+ _SVertex->setViewVertex(this);
+ }
+
+ inline void setViewEdges(const vector<directedViewEdge>& iViewEdges)
+ {
+ _ViewEdges = iViewEdges;
+ }
+
+ void AddIncomingViewEdge(ViewEdge *iVEdge);
+ void AddOutgoingViewEdge(ViewEdge *iVEdge);
+
+ inline void AddViewEdge(ViewEdge *iVEdge, bool incoming = true)
+ {
+ if (incoming)
+ AddIncomingViewEdge(iVEdge);
+ else
+ AddOutgoingViewEdge(iVEdge);
+ }
+
+ /* Replaces old edge by new edge */
+ virtual void Replace(ViewEdge *iOld, ViewEdge *iNew)
+ {
+ edges_container::iterator insertedve;
+ for (edges_container::iterator ve = _ViewEdges.begin(), vend = _ViewEdges.end(); ve != vend; ve++) {
+ if ((ve)->first == iOld) {
+ insertedve = _ViewEdges.insert(ve, directedViewEdge(iNew, ve->second));// inserts e2 before ve.
+ // returns an iterator pointing toward e2. ve is invalidated.
+ // we want to remove e1, but we can't use ve anymore:
+ insertedve++; // insertedve points now to e1
+ _ViewEdges.erase(insertedve);
+ return;
+ }
+ }
+ }
+
+ /* iterators access */
+ virtual edge_iterator edges_begin();
+ virtual const_edge_iterator edges_begin() const;
+ virtual edge_iterator edges_end();
+ virtual const_edge_iterator edges_end() const;
+ virtual edge_iterator edges_iterator(ViewEdge *iEdge);
+ virtual const_edge_iterator edges_iterator(ViewEdge *iEdge) const;
+
+ /*! Returns an iterator over the ViewEdges that goes to or comes from this ViewVertex pointing to the first
+ * ViewEdge of the list. The orientedViewEdgeIterator allows to iterate in CCW order over these ViewEdges
+ * and to get the orientation for each ViewEdge (incoming/outgoing).
+ */
+ virtual ViewVertexInternal::orientedViewEdgeIterator edgesBegin();
+
+ /*! Returns an orientedViewEdgeIterator over the ViewEdges around this ViewVertex, pointing after the last ViewEdge.
+ */
+ virtual ViewVertexInternal::orientedViewEdgeIterator edgesEnd();
+
+ /*! Returns an orientedViewEdgeIterator pointing to the ViewEdge given as argument. */
+ virtual ViewVertexInternal::orientedViewEdgeIterator edgesIterator(ViewEdge *iEdge);
+};
+
+/**********************************/
+/* */
+/* */
+/* ViewEdge */
+/* */
+/* */
+/**********************************/
+
+/* Geometry(normals...)
+ * Nature of edges
+ * 2D spaces (1or2, material, z...)
+ * Parent Shape
+ * 3D Shading, material
+ * Importance
+ * Occluders
+ */
+class ViewShape;
+
+namespace ViewEdgeInternal {
+
+template<class Traits> class edge_iterator_base;
+template<class Traits> class fedge_iterator_base;
+template<class Traits> class vertex_iterator_base;
+
+} // end of namespace ViewEdgeInternal
+
+/*! Class defining a ViewEdge. A ViewEdge in an edge of the image graph. it connnects two ViewVertex.
+ * It is made by connecting a set of FEdges.
+ */
+class LIB_VIEW_MAP_EXPORT ViewEdge : public Interface1D
+{
+public: // Implementation of Interface0D
+ /*! Returns the string "ViewEdge". */
+ virtual string getExactTypeName() const
+ {
+ return "ViewEdge";
+ }
+
+ // Data access methods
+ /*! Returns the Id of the vertex. */
+ virtual Id getId() const
+ {
+ return _Id;
+ }
+
+ /*! Returns the nature of the ViewEdge. */
+ virtual Nature::EdgeNature getNature() const
+ {
+ return _Nature;
+ }
+
+public:
+ typedef SVertex vertex_type;
+ friend class ViewShape;
+ // for ViewEdge iterator
+ typedef ViewEdgeInternal::edge_iterator_base<Nonconst_traits<ViewEdge*> > edge_iterator;
+ typedef ViewEdgeInternal::edge_iterator_base<Const_traits<ViewEdge*> > const_edge_iterator;
+ // for fedge iterator
+ typedef ViewEdgeInternal::fedge_iterator_base<Nonconst_traits<FEdge*> > fedge_iterator;
+ typedef ViewEdgeInternal::fedge_iterator_base<Const_traits<FEdge*> > const_fedge_iterator;
+ // for svertex iterator
+ typedef ViewEdgeInternal::vertex_iterator_base<Nonconst_traits<SVertex*> > vertex_iterator;
+ typedef ViewEdgeInternal::vertex_iterator_base<Const_traits<SVertex*> > const_vertex_iterator;
+
+private:
+ ViewVertex *__A; // edge starting vertex
+ ViewVertex *__B; // edge ending vertex
+ Nature::EdgeNature _Nature; // nature of view edge
+ ViewShape *_Shape; // shape to which the view edge belongs
+ FEdge *_FEdgeA; // first edge of the embedded fedges chain
+ FEdge *_FEdgeB; // last edge of the embedded fedges chain
+ Id _Id;
+ unsigned _ChainingTimeStamp;
+ // The silhouette view edge separates 2 2D spaces. The one on the left is necessarly the Shape _Shape (the one to
+ // which this edge belongs to) and _aShape is the one on its right
+ // NOT HANDLED BY THE COPY CONSTRUCTOR
+ ViewShape *_aShape;
+ int _qi;
+ vector<ViewShape*> _Occluders;
+ bool _isInImage;
+
+ // tmp
+ Id *_splittingId;
+
+public:
+ /*! A field that can be used by the user to store any data.
+ * This field must be reseted afterwards using ResetUserData().
+ */
+ void *userdata;
+
+ /*! Default constructor. */
+ inline ViewEdge()
+ {
+ __A = NULL;
+ __B = NULL;
+ _FEdgeA = NULL;
+ _FEdgeB = NULL;
+ _ChainingTimeStamp = 0;
+ _qi = 0;
+ _aShape = NULL;
+ userdata = NULL;
+ _splittingId = NULL;
+ _isInImage = true;
+ }
+
+ inline ViewEdge(ViewVertex *iA, ViewVertex *iB)
+ {
+ __A = iA;
+ __B = iB;
+ _FEdgeA = NULL;
+ _FEdgeB = NULL;
+ _Shape = 0;
+ _ChainingTimeStamp = 0;
+ _qi = 0;
+ _aShape = NULL;
+ userdata = NULL;
+ _splittingId = NULL;
+ _isInImage = true;
+ }
+
+ inline ViewEdge(ViewVertex *iA, ViewVertex *iB, FEdge *iFEdgeA)
+ {
+ __A = iA;
+ __B = iB;
+ _FEdgeA = iFEdgeA;
+ _FEdgeB = NULL;
+ _Shape = NULL;
+ _ChainingTimeStamp = 0;
+ _qi = 0;
+ _aShape = NULL;
+ userdata = NULL;
+ _splittingId = NULL;
+ _isInImage = true;
+ }
+
+ inline ViewEdge(ViewVertex *iA, ViewVertex *iB, FEdge *iFEdgeA, FEdge *iFEdgeB, ViewShape *iShape)
+ {
+ __A = iA;
+ __B = iB;
+ _FEdgeA = iFEdgeA;
+ _FEdgeB = iFEdgeB;
+ _Shape = iShape;
+ _ChainingTimeStamp = 0;
+ _qi = 0;
+ _aShape = NULL;
+ userdata = NULL;
+ _splittingId = NULL;
+ _isInImage = true;
+ UpdateFEdges(); // tells every FEdge between iFEdgeA and iFEdgeB that this is theit ViewEdge
+ }
+
+//soc protected:
+ /*! Copy constructor. */
+ inline ViewEdge(ViewEdge& iBrother)
+ {
+ __A = iBrother.__A;
+ __B = iBrother.__B;
+ _FEdgeA = iBrother._FEdgeA;
+ _FEdgeB = iBrother._FEdgeB;
+ _Nature = iBrother._Nature;
+ _Shape = NULL;
+ _Id = iBrother._Id;
+ _ChainingTimeStamp = iBrother._ChainingTimeStamp;
+ _aShape = iBrother._aShape;
+ _qi = iBrother._qi;
+ _splittingId = NULL;
+ _isInImage = iBrother._isInImage;
+ iBrother.userdata = this;
+ userdata = NULL;
+ }
+
+ /*! Cloning method. */
+ virtual ViewEdge *duplicate()
+ {
+ ViewEdge *clone = new ViewEdge(*this);
+ return clone;
+ }
+
+public:
+ /*! Destructor. */
+ virtual ~ViewEdge()
+ {
+#if 0
+ if (_aFace) {
+ delete _aFace;
+ _aFace = NULL;
+ }
+#endif
+ // only the last splitted deletes this id
+ if (_splittingId) {
+ if (*_splittingId == _Id)
+ delete _splittingId;
+ }
+ }
+
+ /* accessors */
+ /*! Returns the first ViewVertex. */
+ inline ViewVertex *A()
+ {
+ return __A;
+ }
+
+ /*! Returns the second ViewVertex. */
+ inline ViewVertex *B()
+ {
+ return __B;
+ }
+
+ /*! Returns the first FEdge that constitues this ViewEdge. */
+ inline FEdge *fedgeA()
+ {
+ return _FEdgeA;
+ }
+
+ /*! Returns the last FEdge that constitues this ViewEdge. */
+ inline FEdge *fedgeB()
+ {
+ return _FEdgeB;
+ }
+
+ /*! Returns the ViewShape to which this ViewEdge belongs to .*/
+ inline ViewShape *viewShape()
+ {
+ return _Shape;
+ }
+
+ /*! Returns the shape that is occluded by the ViewShape to which this ViewEdge belongs to. If no object is occluded,
+ * NULL is returned.
+ * \return The occluded ViewShape.
+ */
+ inline ViewShape *aShape()
+ {
+ return _aShape;
+ }
+
+ /*! Tells whether this ViewEdge forms a closed loop or not. */
+ inline bool isClosed()
+ {
+ if (!__B)
+ return true;
+ return false;
+ }
+
+ /*! Returns the time stamp of this ViewEdge. */
+ inline unsigned getChainingTimeStamp()
+ {
+ return _ChainingTimeStamp;
+ }
+
+ inline const ViewShape *aShape() const
+ {
+ return _aShape;
+ }
+
+ inline const ViewShape *bShape() const
+ {
+ return _Shape;
+ }
+
+ inline vector<ViewShape*>& occluders()
+ {
+ return _Occluders;
+ }
+
+ inline Id *splittingId()
+ {
+ return _splittingId;
+ }
+
+ inline bool isInImage() const
+ {
+ return _isInImage;
+ }
+
+ /* modifiers */
+ /*! Sets the first ViewVertex of the ViewEdge. */
+ inline void setA(ViewVertex *iA)
+ {
+ __A = iA;
+ }
+
+ /*! Sets the last ViewVertex of the ViewEdge. */
+ inline void setB(ViewVertex *iB)
+ {
+ __B = iB;
+ }
+
+ /*! Sets the nature of the ViewEdge. */
+ inline void setNature(Nature::EdgeNature iNature)
+ {
+ _Nature = iNature;
+ }
+
+ /*! Sets the first FEdge of the ViewEdge. */
+ inline void setFEdgeA(FEdge *iFEdge)
+ {
+ _FEdgeA = iFEdge;
+ }
+
+ /*! Sets the last FEdge of the ViewEdge. */
+ inline void setFEdgeB(FEdge *iFEdge)
+ {
+ _FEdgeB = iFEdge;
+ }
+
+ /*! Sets the ViewShape to which this ViewEdge belongs to.*/
+ inline void setShape(ViewShape *iVShape)
+ {
+ _Shape = iVShape;
+ }
+
+ /*! Sets the ViewEdge id. */
+ inline void setId(const Id& id)
+ {
+ _Id = id;
+ }
+
+ /*! Sets Viewedge to this for all embedded fedges */
+ void UpdateFEdges();
+
+ /*! Sets the occluded ViewShape */
+ inline void setaShape(ViewShape *iShape)
+ {
+ _aShape = iShape;
+ }
+
+ /*! Sets the quantitative invisibility value. */
+ inline void setQI(int qi)
+ {
+ _qi = qi;
+ }
+
+ /*! Sets the time stamp value. */
+ inline void setChainingTimeStamp(unsigned ts)
+ {
+ _ChainingTimeStamp = ts;
+ }
+
+ inline void AddOccluder(ViewShape *iShape)
+ {
+ _Occluders.push_back(iShape);
+ }
+
+ inline void setSplittingId(Id *id)
+ {
+ _splittingId = id;
+ }
+
+ inline void setIsInImage(bool iFlag)
+ {
+ _isInImage = iFlag;
+ }
+
+ /* stroke interface definition */
+ inline bool intersect_2d_area(const Vec2r& iMin, const Vec2r& iMax) const
+ {
+ // parse edges to check if one of them is intersection the region:
+ FEdge *current = _FEdgeA;
+ do {
+ if (GeomUtils::intersect2dSeg2dArea(iMin, iMax,
+ Vec2r(current->vertexA()->point2D()[0],
+ current->vertexA()->point2D()[1]),
+ Vec2r(current->vertexB()->point2D()[0],
+ current->vertexB()->point2D()[1])))
+ {
+ return true;
+ }
+ current = current->nextEdge();
+ } while ((current != 0) && (current != _FEdgeA));
+
+ return false;
+ }
+
+ inline bool include_in_2d_area(const Vec2r& iMin, const Vec2r& iMax) const
+ {
+ // parse edges to check if all of them are intersection the region:
+ FEdge *current = _FEdgeA;
+
+ do {
+ if (!GeomUtils::include2dSeg2dArea(iMin, iMax,
+ Vec2r(current->vertexA()->point2D()[0],
+ current->vertexA()->point2D()[1]),
+ Vec2r(current->vertexB()->point2D()[0],
+ current->vertexB()->point2D()[1])))
+ {
+ return false;
+ }
+ current = current->nextEdge();
+ } while ((current != 0) && (current != _FEdgeA));
+
+ return true;
+ }
+
+ /* Information access interface */
+
+#if 0
+ inline Nature::EdgeNature viewedge_nature() const
+ {
+ return getNature();
+ }
+
+ float viewedge_length() const;
+#endif
+
+ /*! Returns the 2D length of the Viewedge. */
+ real getLength2D() const;
+
+#if 0
+ inline Material material() const
+ {
+ return _FEdgeA->vertexA()->shape()->material();
+ }
+#endif
+
+ inline int qi() const
+ {
+ return _qi;
+ }
+
+ inline occluder_container::const_iterator occluders_begin() const
+ {
+ return _Occluders.begin();
+ }
+
+ inline occluder_container::const_iterator occluders_end() const
+ {
+ return _Occluders.end();
+ }
+
+ inline int occluders_size() const
+ {
+ return _Occluders.size();
+ }
+
+ inline bool occluders_empty() const
+ {
+ return _Occluders.empty();
+ }
+
+ inline const Polygon3r& occludee() const
+ {
+ return (_FEdgeA->aFace());
+ }
+
+ inline const SShape *occluded_shape() const;
+
+ inline const bool occludee_empty() const
+ {
+ if (_aShape == 0)
+ return true;
+ return false;
+ }
+
+ //inline real z_discontinuity(int iCombination = 0) const;
+
+ inline Id shape_id() const
+ {
+ return _FEdgeA->vertexA()->shape()->getId();
+ }
+
+ inline const SShape *shape() const
+ {
+ return _FEdgeA->vertexA()->shape();
+ }
+
+ inline float shape_importance() const
+ {
+ return _FEdgeA->shape_importance();
+ }
+
+ /* iterators access */
+ // view edge iterator
+ edge_iterator ViewEdge_iterator();
+ const_edge_iterator ViewEdge_iterator() const;
+ // feature edge iterator
+ fedge_iterator fedge_iterator_begin();
+ const_fedge_iterator fedge_iterator_begin() const;
+ fedge_iterator fedge_iterator_last();
+ const_fedge_iterator fedge_iterator_last() const;
+ fedge_iterator fedge_iterator_end();
+ const_fedge_iterator fedge_iterator_end() const;
+ // embedding vertex iterator
+ const_vertex_iterator vertices_begin() const;
+ vertex_iterator vertices_begin();
+ const_vertex_iterator vertices_last() const;
+ vertex_iterator vertices_last();
+ const_vertex_iterator vertices_end() const;
+ vertex_iterator vertices_end();
+
+ // Iterator access (Interface1D)
+ /*! Returns an Interface0DIterator to iterate over the SVertex constituing the embedding of this ViewEdge.
+ * The returned Interface0DIterator points to the first SVertex of the ViewEdge.
+ */
+ virtual Interface0DIterator verticesBegin();
+
+ /*! Returns an Interface0DIterator to iterate over the SVertex constituing the embedding of this ViewEdge.
+ * The returned Interface0DIterator points after the last SVertex of the ViewEdge.
+ */
+ virtual Interface0DIterator verticesEnd();
+
+ /*! Returns an Interface0DIterator to iterate over the points of this ViewEdge at a given resolution.
+ * The returned Interface0DIterator points on the first Point of the ViewEdge.
+ * \param t
+ * the sampling value.
+ */
+ virtual Interface0DIterator pointsBegin(float t = 0.0f);
+
+ /*! Returns an Interface0DIterator to iterate over the points of this ViewEdge at a given resolution.
+ * The returned Interface0DIterator points after the last Point of the ViewEdge.
+ * \param t
+ * the sampling value.
+ */
+ virtual Interface0DIterator pointsEnd(float t = 0.0f);
+};
+
+
+/**********************************/
+/* */
+/* */
+/* ViewShape */
+/* */
+/* */
+/**********************************/
+
+/*! Class gathering the elements of the ViewMap (ViewVertex, ViewEdge) that are issued from the same input shape. */
+class LIB_VIEW_MAP_EXPORT ViewShape
+{
+private:
+ vector<ViewVertex*> _Vertices;
+ vector<ViewEdge*> _Edges;
+ SShape *_SShape;
+
+public:
+ /*! A field that can be used by the user to store any data.
+ * This field must be reseted afterwards using ResetUserData().
+ */
+ void *userdata;
+
+ /*! Default constructor.*/
+ inline ViewShape()
+ {
+ userdata = NULL;
+ _SShape = NULL;
+ }
+
+ /*! Builds a ViewShape from a SShape. */
+ inline ViewShape(SShape *iSShape)
+ {
+ userdata = NULL;
+ _SShape = iSShape;
+ //_SShape->setViewShape(this);
+ }
+
+ /*! Copy constructor. */
+ inline ViewShape(ViewShape& iBrother)
+ {
+ userdata = NULL;
+ vector<ViewVertex*>::iterator vv,vvend;
+ vector<ViewEdge*>::iterator ve, veend;
+
+ _SShape = iBrother._SShape;
+
+ vector<ViewVertex*>& vvertices = iBrother.vertices();
+ // duplicate vertices
+ for (vv = vvertices.begin(), vvend = vvertices.end(); vv != vvend; vv++) {
+ ViewVertex *newVertex = (*vv)->duplicate();
+ AddVertex(newVertex);
+ }
+
+ vector<ViewEdge*>& vvedges = iBrother.edges();
+ // duplicate edges
+ for (ve = vvedges.begin(), veend = vvedges.end(); ve != veend; ve++) {
+ ViewEdge *newEdge = (*ve)->duplicate();
+ AddEdge(newEdge); // here the shape is set as the edge's shape
+ }
+
+ //-------------------------
+ // remap edges in vertices:
+ //-------------------------
+ for (vv = _Vertices.begin(), vvend = _Vertices.end(); vv != vvend; vv++) {
+ switch ((*vv)->getNature()) {
+ case Nature::T_VERTEX:
+ {
+ TVertex *v = (TVertex*)(*vv);
+ ViewEdge *veFrontA = (ViewEdge*)(v)->frontEdgeA().first->userdata;
+ ViewEdge *veFrontB = (ViewEdge*)(v)->frontEdgeB().first->userdata;
+ ViewEdge *veBackA = (ViewEdge*)(v)->backEdgeA().first->userdata;
+ ViewEdge *veBackB = (ViewEdge*)(v)->backEdgeB().first->userdata;
+
+ v->setFrontEdgeA(veFrontA, v->frontEdgeA().second);
+ v->setFrontEdgeB(veFrontB, v->frontEdgeB().second);
+ v->setBackEdgeA(veBackA, v->backEdgeA().second);
+ v->setBackEdgeB(veBackB, v->backEdgeB().second);
+ }
+ break;
+ case Nature::NON_T_VERTEX:
+ {
+ NonTVertex *v = (NonTVertex*)(*vv);
+ vector<ViewVertex::directedViewEdge>& vedges = (v)->viewedges();
+ vector<ViewVertex::directedViewEdge> newEdges;
+ for (vector<ViewVertex::directedViewEdge>::iterator ve = vedges.begin(), veend = vedges.end();
+ ve != veend;
+ ve++)
+ {
+ ViewEdge *current = (ViewEdge*)((ve)->first)->userdata;
+ newEdges.push_back(ViewVertex::directedViewEdge(current, ve->second));
+ }
+ (v)->setViewEdges(newEdges);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ //-------------------------------------
+ // remap vertices in edges:
+ //-------------------------------------
+ for (ve = _Edges.begin(), veend = _Edges.end(); ve != veend; ve++) {
+ (*ve)->setA((ViewVertex*)((*ve)->A()->userdata));
+ (*ve)->setB((ViewVertex*)((*ve)->B()->userdata));
+ //---------------------------------------
+ // Update all embedded FEdges
+ //---------------------------------------
+ (*ve)->UpdateFEdges();
+ }
+
+ // reset all brothers userdata to NULL:
+ //-------------------------------------
+ //---------
+ // vertices
+ //---------
+ for (vv = vvertices.begin(), vvend = vvertices.end(); vv != vvend; vv++) {
+ (*vv)->userdata = NULL;
+ }
+
+ //------
+ // edges
+ //------
+ for (ve = vvedges.begin(), veend = vvedges.end(); ve != veend; ve++) {
+ (*ve)->userdata = NULL;
+ }
+ }
+
+ /*! Cloning method. */
+ virtual ViewShape *duplicate()
+ {
+ ViewShape *clone = new ViewShape(*this);
+ return clone;
+ }
+
+ /*! Destructor. */
+ virtual ~ViewShape();
+
+ /* splits a view edge into several view edges.
+ * fe
+ * The FEdge that gets splitted
+ * iViewVertices
+ * The view vertices corresponding to the different intersections for the edge fe.
+ * This list need to be sorted such as the first view vertex is the farther away from fe->vertexA.
+ * ioNewEdges
+ * The feature edges that are newly created (the initial edges are not included) are added to this list.
+ * ioNewViewEdges
+ * The view edges that are newly created (the initial edges are not included) are added to this list.
+ */
+ inline void SplitEdge(FEdge *fe, const vector<TVertex*>& iViewVertices, vector<FEdge*>& ioNewEdges,
+ vector<ViewEdge*>& ioNewViewEdges);
+
+ /* accessors */
+ /*! Returns the SShape on top of which this ViewShape is built. */
+ inline SShape *sshape()
+ {
+ return _SShape;
+ }
+
+ /*! Returns the SShape on top of which this ViewShape is built. */
+ inline const SShape *sshape() const
+ {
+ return _SShape;
+ }
+
+ /*! Returns the list of ViewVertex contained in this ViewShape. */
+ inline vector<ViewVertex*>& vertices()
+ {
+ return _Vertices;
+ }
+
+ /*! Returns the list of ViewEdge contained in this ViewShape. */
+ inline vector<ViewEdge*>& edges()
+ {
+ return _Edges;
+ }
+
+ /*! Returns the ViewShape id. */
+ inline Id getId() const
+ {
+ return _SShape->getId();
+ }
+
+ /*! Returns the ViewShape id. */
+ inline const string& getName() const
+ {
+ return _SShape->getName();
+ }
+
+ /* modifiers */
+ /*! Sets the SShape on top of which the ViewShape is built. */
+ inline void setSShape(SShape *iSShape)
+ {
+ _SShape = iSShape;
+ }
+
+ /*! Sets the list of ViewVertex contained in this ViewShape. */
+ inline void setVertices(const vector<ViewVertex*>& iVertices)
+ {
+ _Vertices = iVertices;
+ }
+
+ /*! Sets the list of ViewEdge contained in this ViewShape. */
+ inline void setEdges(const vector<ViewEdge*>& iEdges)
+ {
+ _Edges = iEdges;
+ }
+
+ /*! Adds a ViewVertex to the list. */
+ inline void AddVertex(ViewVertex *iVertex)
+ {
+ _Vertices.push_back(iVertex);
+ //_SShape->AddNewVertex(iVertex->svertex());
+ }
+
+ /*! Adds a ViewEdge to the list */
+ inline void AddEdge(ViewEdge *iEdge)
+ {
+ _Edges.push_back(iEdge);
+ iEdge->setShape(this);
+ //_SShape->AddNewEdge(iEdge->fedge());
+ }
+
+ /* removes the view edge iViewEdge in the View Shape and the associated FEdge chain entry in the underlying SShape
+ */
+ void RemoveEdge(ViewEdge *iViewEdge);
+
+ /* removes the view vertex iViewVertex in the View Shape. */
+ void RemoveVertex(ViewVertex *iViewVertex);
+};
+
+
+/*
+ #############################################
+ #############################################
+ #############################################
+ ###### ######
+ ###### I M P L E M E N T A T I O N ######
+ ###### ######
+ #############################################
+ #############################################
+ #############################################
+*/
+/* for inline functions */
+
+void ViewShape::SplitEdge(FEdge *fe, const vector<TVertex*>& iViewVertices, vector<FEdge*>& ioNewEdges,
+ vector<ViewEdge*>& ioNewViewEdges)
+{
+ ViewEdge *vEdge = fe->viewedge();
+
+ // We first need to sort the view vertices from farther to closer to fe->vertexA
+ SVertex *sv, *sv2;
+ ViewVertex *vva, *vvb;
+ vector<TVertex*>::const_iterator vv, vvend;
+ for (vv = iViewVertices.begin(), vvend = iViewVertices.end(); vv != vvend; vv++) {
+ // Add the viewvertices to the ViewShape
+ AddVertex((*vv));
+
+ // retrieve the correct SVertex from the view vertex
+ //--------------------------------------------------
+ sv = (*vv)->frontSVertex();
+ sv2 = (*vv)->backSVertex();
+
+ if (sv->shape() != sv2->shape()) {
+ if (sv->shape() != _SShape)
+ sv = sv2;
+ }
+ else {
+ // if the shape is the same we can safely differ the two vertices using their ids:
+ if (sv->getId() != fe->vertexA()->getId())
+ sv = sv2;
+ }
+
+ vva = vEdge->A();
+ vvb = vEdge->B();
+
+ // We split Fedge AB into AA' and A'B. A' and A'B are created.
+ // AB becomes (address speaking) AA'. B is updated.
+ //--------------------------------------------------
+ SShape *shape = fe->shape();
+
+ // a new edge, A'B is created.
+ FEdge *newEdge = shape->SplitEdgeIn2(fe, sv);
+ /* One of the two FEdges (fe and newEdge) may have a 2D length less than M_EPSILON.
+ * (22 Feb 2011, T.K.)
+ */
+
+ ioNewEdges.push_back(newEdge);
+ ViewEdge *newVEdge;
+
+ if ((vva == 0) || (vvb == 0)) { // that means we're dealing with a closed viewedge (loop)
+ // remove the chain that was starting by the fedge A of vEdge (which is different from fe !!!!)
+ shape->RemoveEdgeFromChain(vEdge->fedgeA());
+ // we set
+ vEdge->setA(*vv);
+ vEdge->setB(*vv);
+ vEdge->setFEdgeA(newEdge);
+ //FEdge *previousEdge = newEdge->previousEdge();
+ vEdge->setFEdgeB(fe);
+ newVEdge = vEdge;
+ vEdge->fedgeA()->setViewEdge(newVEdge);
+ }
+ else {
+ // while we create the view edge, it updates the "ViewEdge" pointer of every underlying FEdges to this.
+ newVEdge = new ViewEdge((*vv), vvb); //, newEdge, vEdge->fedgeB());
+ newVEdge->setNature((fe)->getNature());
+ newVEdge->setFEdgeA(newEdge);
+ //newVEdge->setFEdgeB(fe);
+ // If our original viewedge is made of one FEdge, then
+ if ((vEdge->fedgeA() == vEdge->fedgeB()) || (fe == vEdge->fedgeB()))
+ newVEdge->setFEdgeB(newEdge);
+ else
+ newVEdge->setFEdgeB(vEdge->fedgeB()); //MODIF
+
+ Id *newId = vEdge->splittingId();
+ if (newId == 0) {
+ newId = new Id(vEdge->getId());
+ vEdge->setSplittingId(newId);
+ }
+ newId->setSecond(newId->getSecond() + 1);
+ newVEdge->setId(*newId);
+ newVEdge->setSplittingId(newId);
+#if 0
+ Id id(vEdge->getId().getFirst(), vEdge->getId().getSecond() + 1);
+ newVEdge->setId(vEdge->getId());
+ vEdge->setId(id);
+#endif
+
+ AddEdge(newVEdge); // here this shape is set as the edge's shape
+
+ // add new edge to the list of new edges passed as argument:
+ ioNewViewEdges.push_back(newVEdge);
+
+ if (0 != vvb)
+ vvb->Replace((vEdge), newVEdge);
+
+ // we split the view edge:
+ vEdge->setB((*vv));
+ vEdge->setFEdgeB(fe); //MODIF
+
+ // Update fedges so that they point to the new viewedge:
+ newVEdge->UpdateFEdges();
+ }
+ // check whether this vertex is a front vertex or a back one
+ if (sv == (*vv)->frontSVertex()) {
+ // -- View Vertex A' --
+ (*vv)->setFrontEdgeA(vEdge, true);
+ (*vv)->setFrontEdgeB(newVEdge, false);
+ }
+ else {
+ // -- View Vertex A' --
+ (*vv)->setBackEdgeA(vEdge, true);
+ (*vv)->setBackEdgeB(newVEdge, false);
+ }
+ }
+}
+
+/**********************************/
+/* */
+/* */
+/* ViewEdge */
+/* */
+/* */
+/**********************************/
+
+#if 0
+inline Vec3r ViewEdge::orientation2d(int iCombination) const
+{
+ return edge_orientation2d_function<ViewEdge>(*this, iCombination);
+}
+
+inline Vec3r ViewEdge::orientation3d(int iCombination) const
+{
+ return edge_orientation3d_function<ViewEdge>(*this, iCombination);
+}
+
+inline real ViewEdge::z_discontinuity(int iCombination) const
+{
+ return z_discontinuity_edge_function<ViewEdge>(*this, iCombination);
+}
+
+inline float ViewEdge::local_average_depth(int iCombination ) const
+{
+ return local_average_depth_edge_function<ViewEdge>(*this, iCombination);
+}
+
+inline float ViewEdge::local_depth_variance(int iCombination) const
+{
+ return local_depth_variance_edge_function<ViewEdge>(*this, iCombination);
+}
+
+inline real ViewEdge::local_average_density(float sigma, int iCombination) const
+{
+ return density_edge_function<ViewEdge>(*this, iCombination);
+}
+#endif
+
+inline const SShape * ViewEdge::occluded_shape() const
+{
+ if (0 == _aShape)
+ return 0;
+ return _aShape->sshape();
+}
+
+#if 0
+inline Vec3r ViewEdge::curvature2d_as_vector(int iCombination) const
+{
+ return curvature2d_as_vector_edge_function<ViewEdge>(*this, iCombination);
+}
+
+inline real ViewEdge::curvature2d_as_angle(int iCombination) const
+{
+ return curvature2d_as_angle_edge_function<ViewEdge>(*this, iCombination);
+}
+#endif
+
+#endif // __FREESTYLE_VIEW_MAP_H__
diff --git a/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h b/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h
new file mode 100644
index 00000000000..ff6557b7d86
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h
@@ -0,0 +1,789 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_VIEW_MAP_ADVANCED_ITERATORS_H__
+#define __FREESTYLE_VIEW_MAP_ADVANCED_ITERATORS_H__
+
+/** \file blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h
+ * \ingroup freestyle
+ * \brief Iterators used to iterate over the various elements of the ViewMap.
+ * These iterators can't be exported to python.
+ * \author Stephane Grabli
+ * \date 01/07/2003
+ */
+
+#include "ViewMap.h"
+
+#include "../system/Iterator.h" //soc
+
+/**********************************/
+/* */
+/* */
+/* ViewMap */
+/* */
+/* */
+/**********************************/
+
+/**********************************/
+/* */
+/* */
+/* ViewVertex */
+/* */
+/* */
+/**********************************/
+
+namespace ViewVertexInternal {
+
+class edge_const_traits : public Const_traits< ::ViewVertex::directedViewEdge>
+{
+public:
+ typedef vector< ::ViewVertex::directedViewEdge> edges_container;
+ typedef edges_container::const_iterator edges_container_iterator;
+ typedef vector< ::ViewVertex::directedViewEdge*> edge_pointers_container;
+ typedef edge_pointers_container::const_iterator edge_pointers_container_iterator;
+};
+
+class edge_nonconst_traits : public Nonconst_traits< ::ViewVertex::directedViewEdge>
+{
+public:
+ typedef vector< ::ViewVertex::directedViewEdge> edges_container;
+ typedef edges_container::iterator edges_container_iterator;
+ typedef vector< ::ViewVertex::directedViewEdge*> edge_pointers_container;
+ typedef edge_pointers_container::iterator edge_pointers_container_iterator;
+};
+
+template<class Traits>
+class edge_iterator_base : public IteratorBase<Traits,InputIteratorTag_Traits>
+{
+public:
+ typedef typename Traits::value_type value_type;
+ typedef typename Traits::difference_type difference_type;
+ typedef typename Traits::pointer pointer;
+ typedef typename Traits::reference reference;
+ typedef edge_iterator_base<Traits> Self;
+ typedef typename Traits::edges_container_iterator edges_container_iterator;
+ typedef typename Traits::edge_pointers_container_iterator edge_pointers_container_iterator;
+ typedef edge_iterator_base<edge_nonconst_traits> iterator;
+ typedef edge_iterator_base<edge_const_traits> const_iterator;
+
+public:
+ friend class ViewVertex;
+ friend class TVertex;
+ friend class NonTVertex;
+ friend class ViewEdge;
+ friend class edge_iterator;
+
+protected:
+ Nature::VertexNature _Nature; // the nature of the underlying vertex
+ // T vertex attributes
+ edge_pointers_container_iterator _tbegin;
+ edge_pointers_container_iterator _tend;
+ edge_pointers_container_iterator _tvertex_iter;
+
+#if 0
+ mutable value_type _tvertex_iter;
+ value_type _feA;
+ value_type _feB;
+ value_type _beA;
+ value_type _beB;
+#endif
+
+ // Non TVertex attributes
+ edges_container_iterator _begin;
+ edges_container_iterator _end;
+ edges_container_iterator _nontvertex_iter;
+
+ typedef IteratorBase<Traits,InputIteratorTag_Traits> parent_class;
+
+public:
+ inline edge_iterator_base() : parent_class() {}
+
+ inline edge_iterator_base(Nature::VertexNature iNature) : parent_class()
+ {
+ _Nature = iNature;
+ }
+
+ edge_iterator_base(const edge_iterator_base<edge_nonconst_traits>& iBrother) : parent_class(iBrother)
+ {
+ _Nature = iBrother._Nature;
+ if (_Nature & Nature::T_VERTEX) {
+#if 0
+ _feA = iBrother._feA;
+ _feB = iBrother._feB;
+ _beA = iBrother._beA;
+ _beB = iBrother._beB;
+ _tvertex_iter = iBrother._tvertex_iter;
+#endif
+ _tbegin = iBrother._tbegin;
+ _tend = iBrother._tend;
+ _tvertex_iter = iBrother._tvertex_iter;
+ }
+ else {
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ _nontvertex_iter = iBrother._nontvertex_iter;
+ }
+ }
+
+ edge_iterator_base(const edge_iterator_base<edge_const_traits>& iBrother) : parent_class(iBrother)
+ {
+ _Nature = iBrother._Nature;
+ if (_Nature & Nature::T_VERTEX) {
+#if 0
+ _feA = iBrother._feA;
+ _feB = iBrother._feB;
+ _beA = iBrother._beA;
+ _beB = iBrother._beB;
+ _tvertex_iter = iBrother._tvertex_iter;
+#endif
+ _tbegin = iBrother._tbegin;
+ _tend = iBrother._tend;
+ _tvertex_iter = iBrother._tvertex_iter;
+ }
+ else {
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ _nontvertex_iter = iBrother._nontvertex_iter;
+ }
+ }
+
+ virtual ~edge_iterator_base() {}
+
+//protected://FIXME
+public:
+#if 0
+ inline edge_iterator_base(value_type ifeA, value_type ifeB, value_type ibeA, value_type ibeB, value_type iter)
+ : parent_class()
+ {
+ _Nature = Nature::T_VERTEX;
+ _feA = ifeA;
+ _feB = ifeB;
+ _beA = ibeA;
+ _beB = ibeB;
+ _tvertex_iter = iter;
+ }
+#endif
+
+ inline edge_iterator_base(edge_pointers_container_iterator begin, edge_pointers_container_iterator end,
+ edge_pointers_container_iterator iter)
+ : parent_class()
+ {
+ _Nature = Nature::T_VERTEX;
+ _tbegin = begin;
+ _tend = end;
+ _tvertex_iter = iter;
+ }
+
+ inline edge_iterator_base(edges_container_iterator begin, edges_container_iterator end,
+ edges_container_iterator iter)
+ : parent_class()
+ {
+ _Nature = Nature::NON_T_VERTEX;
+ _begin = begin;
+ _end = end;
+ _nontvertex_iter = iter;
+ }
+
+public:
+ virtual bool begin() const
+ {
+ if (_Nature & Nature::T_VERTEX)
+ return (_tvertex_iter == _tbegin);
+ //return (_tvertex_iter == _feA);
+ else
+ return (_nontvertex_iter == _begin);
+ }
+
+ virtual bool end() const
+ {
+ if (_Nature & Nature::T_VERTEX)
+ //return (_tvertex_iter.first == 0);
+ return (_tvertex_iter == _tend);
+ else
+ return (_nontvertex_iter == _end);
+ }
+
+ // operators
+ // operator corresponding to ++i
+ virtual Self& operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ // operator corresponding to i++, i.e. which returns the value *and then* increments it.
+ // That's why we store the value in a temp.
+ virtual Self operator++(int) // opérateur correspondant à i++
+ {
+ Self tmp = *this;
+ increment();
+ return tmp;
+ }
+
+ // comparibility
+ virtual bool operator!=(const Self& b) const
+ {
+ if (_Nature & Nature::T_VERTEX)
+ return (_tvertex_iter != b._tvertex_iter);
+ else
+ return (_nontvertex_iter != b._nontvertex_iter);
+ }
+
+ virtual bool operator==(const Self& b) const
+ {
+ return !(*this != b);
+ }
+
+ // dereferencing
+ virtual reference operator*() const
+ {
+ if (_Nature & Nature::T_VERTEX)
+ //return _tvertex_iter;
+ return **_tvertex_iter;
+ else
+ return (*_nontvertex_iter);
+ }
+
+ virtual pointer operator->() const
+ {
+ return &(operator*());
+ }
+
+protected:
+ inline void increment()
+ {
+ if (_Nature & Nature::T_VERTEX) {
+ value_type tmp = (**_tvertex_iter);
+ ++_tvertex_iter;
+ value_type tmp2 = (**_tvertex_iter);
+ if (tmp2.first == tmp.first)
+ ++_tvertex_iter;
+#if 0
+ // Hack to deal with cusp. the result of a cusp is a TVertex having two identical viewedges.
+ // In order to iterate properly, we chose to to skip these last ones.
+ if (_feB.first == _beA.first) {
+ if (_feA.first == _beB.first) {
+ _tvertex_iter.first = 0;
+ return;
+ }
+
+ if (_tvertex_iter.first == _feA.first)
+ _tvertex_iter.first = _beB.first;
+ else if (_tvertex_iter.first == _beB.first)
+ _tvertex_iter.first = 0;
+ else
+ _tvertex_iter.first = _feA.first;
+ return;
+ }
+ if (_feA.first == _beB.first) {
+ if (_feB.first == _beA.first) {
+ _tvertex_iter.first = 0;
+ return;
+ }
+
+ if (_tvertex_iter.first == _feB.first)
+ _tvertex_iter.first = _beA.first;
+ else if (_tvertex_iter.first == _beA.first)
+ _tvertex_iter.first = 0;
+ else
+ _tvertex_iter.first = _feB.first;
+ return;
+ }
+ // End of hack
+
+ if (_tvertex_iter.first == _feA.first) {
+ // we return bea or beb
+ // choose one of them
+ _tvertex_iter.first = _feB.first;
+ return;
+ }
+ if (_tvertex_iter.first == _feB.first) {
+ _tvertex_iter.first = _beA.first;
+ return;
+ }
+ if (_tvertex_iter.first == _beA.first) {
+ _tvertex_iter.first = _beB.first;
+ return;
+ }
+ if (_tvertex_iter.first == _beB.first) {
+ _tvertex_iter.first = 0;
+ return;
+ }
+#endif
+ }
+ else {
+ ++_nontvertex_iter;
+ }
+ }
+};
+
+} // ViewVertexInternal namespace
+
+/**********************************/
+/* */
+/* */
+/* ViewEdge */
+/* */
+/* */
+/**********************************/
+
+namespace ViewEdgeInternal {
+
+/*!----------------------*/
+/*! Iterators definition */
+/*!----------------------*/
+template<class Traits>
+class edge_iterator_base : public IteratorBase<Traits,BidirectionalIteratorTag_Traits>
+{
+public:
+ typedef typename Traits::value_type value_type;
+ typedef typename Traits::difference_type difference_type;
+ typedef typename Traits::pointer pointer;
+ typedef typename Traits::reference reference;
+ typedef edge_iterator_base<Traits> Self;
+
+public:
+ mutable value_type _ViewEdge;
+ //friend class edge_iterator_base<Nonconst_traits<ViewEdge*> >;
+ //friend class edge_iterator_base<Const_traits<ViewEdge*> >;
+ value_type _first;
+ bool _orientation;
+ typedef IteratorBase<Traits,BidirectionalIteratorTag_Traits> parent_class;
+
+public:
+ friend class ViewEdge;
+ inline edge_iterator_base() : parent_class()
+ {
+ _orientation = true;
+ _first = 0;
+ }
+
+ inline edge_iterator_base(const edge_iterator_base<Nonconst_traits< ::ViewEdge*> >& iBrother) : parent_class()
+ {
+ _ViewEdge = iBrother._ViewEdge;
+ _first = iBrother._first;
+ _orientation = iBrother._orientation;
+ }
+
+ inline edge_iterator_base(const edge_iterator_base<Const_traits< ::ViewEdge*> >& iBrother) : parent_class()
+ {
+ _ViewEdge = iBrother._ViewEdge;
+ _first = iBrother._first;
+ _orientation = iBrother._orientation;
+ }
+
+//protected://FIXME
+public:
+ inline edge_iterator_base(value_type iEdge, bool orientation = true) : parent_class()
+ {
+ _ViewEdge = iEdge;
+ _first = iEdge;
+ _orientation = orientation;
+ }
+
+public:
+ virtual Self *clone() const
+ {
+ return new edge_iterator_base(*this);
+ }
+
+ virtual ~edge_iterator_base() {}
+
+public:
+ virtual bool orientation()
+ {
+ return _orientation;
+ }
+
+ virtual void set_edge(value_type iVE)
+ {
+ _ViewEdge = iVE;
+ }
+
+ virtual void set_orientation(bool iOrientation)
+ {
+ _orientation = iOrientation;
+ }
+
+ virtual void change_orientation()
+ {
+ _orientation = !_orientation;
+ }
+
+ // operators
+ // operator corresponding to ++i
+ inline Self& operator++()
+ {
+ //++_ViewEdge->getTimeStamp();
+ increment();
+ return *this;
+ }
+
+ // operator corresponding to i++, i.e. which returns the value *and then* increments it.
+ // That's why we store the value in a temp.
+ inline Self operator++(int)
+ {
+ //++_ViewEdge->getTimeStamp();
+ Self tmp = *this;
+ increment();
+ return tmp;
+ }
+
+ // operator corresponding to --i
+ inline Self& operator--()
+ {
+ //++_ViewEdge->getTimeStamp();
+ decrement();
+ return *this;
+ }
+
+ // operator corresponding to i--, i.e. which returns the value *and then* increments it.
+ // That's why we store the value in a temp.
+ inline Self operator--(int)
+ {
+ //++_ViewEdge->getTimeStamp();
+ Self tmp = *this;
+ decrement();
+ return tmp;
+ }
+
+ // comparibility
+ virtual bool operator!=(const Self& b) const
+ {
+ return (_ViewEdge != b._ViewEdge);
+ }
+
+ virtual bool operator==(const Self& b) const
+ {
+ return !(*this != b);
+ }
+
+ // dereferencing
+ virtual reference operator*() const
+ {
+ return (_ViewEdge);
+ }
+
+ virtual pointer operator->() const
+ {
+ return &(operator*());
+ }
+
+public:
+ virtual bool begin() const
+ {
+ return (_ViewEdge == _first) ? true : false;
+ }
+
+ virtual bool end() const
+ {
+ return (_ViewEdge == 0) ? true : false;
+ }
+
+protected:
+ virtual void increment() {}
+ virtual void decrement() {}
+};
+
+template<class Traits>
+class fedge_iterator_base : public IteratorBase<Traits,BidirectionalIteratorTag_Traits>
+{
+public:
+ typedef typename Traits::value_type value_type;
+ typedef typename Traits::difference_type difference_type;
+ typedef typename Traits::pointer pointer;
+ typedef typename Traits::reference reference;
+ typedef fedge_iterator_base<Traits> Self;
+
+public:
+ typedef IteratorBase<Traits,BidirectionalIteratorTag_Traits> parent_class;
+ mutable value_type _FEdge;
+ value_type _first;
+ value_type _FEdgeB; // last fedge of the view edge
+
+public:
+ friend class ::ViewEdge;
+ friend class fedge_iterator;
+
+ inline fedge_iterator_base() : parent_class() {}
+
+ inline fedge_iterator_base(const fedge_iterator_base<Nonconst_traits<FEdge*> >& iBrother) : parent_class()
+ {
+ _FEdge = iBrother._FEdge;
+ _first = iBrother._first;
+ _FEdgeB = iBrother._FEdgeB;
+ }
+
+ inline fedge_iterator_base(const fedge_iterator_base<Const_traits<FEdge*> >& iBrother) : parent_class()
+ {
+ _FEdge = iBrother._FEdge;
+ _first = iBrother._first;
+ _FEdgeB = iBrother._FEdgeB;
+ }
+
+//protected://FIXME
+public:
+ inline fedge_iterator_base(value_type iEdge, value_type iFEdgeB) : parent_class()
+ {
+ _FEdge = iEdge;
+ _first = iEdge;
+ _FEdgeB = iFEdgeB;
+ }
+
+public:
+ virtual ~fedge_iterator_base() {}
+
+ // operators
+ // operator corresponding to ++i.
+ inline Self& operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ // operator corresponding to i++, i.e. which returns the value *and then* increments it.
+ // That's why we store the value in a temp.
+ inline Self operator++(int)
+ {
+ Self tmp = *this;
+ increment();
+ return tmp;
+ }
+
+ // operator corresponding to --i
+ inline Self& operator--()
+ {
+ decrement();
+ return *this;
+ }
+
+ // operator corresponding to i--, i.e. which returns the value *and then* increments it.
+ // That's why we store the value in a temp.
+ inline Self operator--(int)
+ {
+ Self tmp = *this;
+ decrement();
+ return tmp;
+ }
+
+ // comparibility
+ virtual bool operator!=(const Self& b) const
+ {
+ return (_FEdge != b._FEdge);
+ }
+
+ virtual bool operator==(const Self& b) const
+ {
+ return !(*this != b);
+ }
+
+ // dereferencing
+ virtual reference operator*() const
+ {
+ return (_FEdge);
+ }
+
+ virtual pointer operator->() const
+ {
+ return &(operator*());
+ }
+
+public:
+ virtual bool begin() const
+ {
+ return (_FEdge == _first) ? true : false;
+ }
+
+ virtual bool end() const
+ {
+ return (_FEdge == 0) ? true : false;
+ }
+
+protected:
+ virtual void increment()
+ {
+ _FEdge = _FEdge->nextEdge(); // we don't change or
+ }
+
+ virtual void decrement()
+ {
+ if (0 == _FEdge) {
+ _FEdge = _FEdgeB;
+ return;
+ }
+ _FEdge = _FEdge->previousEdge(); // we don't change or
+ }
+};
+
+template<class Traits>
+class vertex_iterator_base : public IteratorBase<Traits,BidirectionalIteratorTag_Traits>
+{
+public:
+ typedef typename Traits::value_type value_type;
+ typedef typename Traits::difference_type difference_type;
+ typedef typename Traits::pointer pointer;
+ typedef typename Traits::reference reference;
+ typedef vertex_iterator_base<Traits> Self;
+
+protected:
+ typedef IteratorBase<Traits,BidirectionalIteratorTag_Traits> parent_class;
+
+public:
+ mutable value_type _SVertex;
+ FEdge *_NextFEdge;
+ FEdge *_PreviousFEdge;
+
+public:
+ friend class ViewEdge;
+ friend class vertex_iterator;
+
+ inline vertex_iterator_base() : parent_class() {}
+
+ inline vertex_iterator_base(const vertex_iterator_base<Const_traits<SVertex*> >& iBrother) : parent_class()
+ {
+ _SVertex = iBrother._SVertex;
+ _NextFEdge = iBrother._NextFEdge;
+ _PreviousFEdge = iBrother._PreviousFEdge;
+ }
+
+ inline vertex_iterator_base(const vertex_iterator_base<Nonconst_traits<SVertex*> >& iBrother) : parent_class()
+ {
+ _SVertex = iBrother._SVertex;
+ _NextFEdge = iBrother._NextFEdge;
+ _PreviousFEdge = iBrother._PreviousFEdge;
+ }
+
+//protected://FIXME
+public:
+ inline vertex_iterator_base(value_type iVertex, FEdge *iPreviousFEdge, FEdge *iNextFEdge) : parent_class()
+ {
+ _SVertex = iVertex;
+ _NextFEdge = iNextFEdge;
+ _PreviousFEdge = iPreviousFEdge;
+ }
+
+public:
+ virtual ~vertex_iterator_base() {}
+
+ virtual bool begin() const
+ {
+ return (_PreviousFEdge == 0) ? true : false;
+ }
+
+ virtual bool end() const
+ {
+ return (_SVertex == 0) ? true : false;
+ }
+
+ // operators
+ // operator corresponding to ++i
+ inline Self& operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ // operator corresponding to i++, i.e. which returns the value *and then* increments it.
+ // That's why we store the value in a temp.
+ inline Self operator++(int)
+ {
+ Self tmp = *this;
+ increment();
+ return tmp;
+ }
+
+ // operator corresponding to --i
+ inline Self& operator--()
+ {
+ decrement();
+ return *this;
+ }
+
+ // operator corresponding to --i, i.e. which returns the value *and then* increments it.
+ // That's why we store the value in a temp.
+ inline Self operator--(int)
+ {
+ Self tmp = *this;
+ decrement();
+ return tmp;
+ }
+
+ // comparibility
+ virtual bool operator!=(const Self& b) const
+ {
+ return (_SVertex != b._SVertex);
+ }
+
+ virtual bool operator==(const Self& b) const
+ {
+ return !(*this != b);
+ }
+
+ // dereferencing
+ virtual reference operator*() const
+ {
+ return (_SVertex);
+ }
+
+ virtual pointer operator->() const
+ {
+ return &(operator*());
+ }
+
+protected:
+ virtual void increment()
+ {
+ if (!_NextFEdge) {
+ _SVertex = NULL;
+ return;
+ }
+ _SVertex = _NextFEdge->vertexB();
+ _PreviousFEdge = _NextFEdge;
+ _NextFEdge = _NextFEdge->nextEdge();
+ }
+
+ virtual void decrement()
+ {
+#if 0
+ if (!_SVertex) {
+ _SVertex = _PreviousFEdge->vertexB();
+ return;
+ }
+#endif
+ if (!_PreviousFEdge) {
+ _SVertex = NULL;
+ return;
+ }
+ _SVertex = _PreviousFEdge->vertexA();
+ _NextFEdge = _PreviousFEdge;
+ _PreviousFEdge = _PreviousFEdge->previousEdge();
+ }
+};
+
+} // end of namespace ViewEdgeInternal
+
+#endif // __FREESTYLE_VIEW_MAP_ADVANCED_ITERATORS_H__
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
new file mode 100644
index 00000000000..ea959bfd81d
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
@@ -0,0 +1,2390 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/ViewMapBuilder.cpp
+ * \ingroup freestyle
+ * \brief Class to build silhouette edges from a Winged-Edge structure
+ * \author Stephane Grabli
+ * \date 25/03/2002
+ */
+
+#include <algorithm>
+#include <memory>
+#include <stdexcept>
+
+#include "FRS_freestyle.h"
+
+#include "BoxGrid.h"
+#include "CulledOccluderSource.h"
+#include "HeuristicGridDensityProviderFactory.h"
+#include "OccluderSource.h"
+#include "SphericalGrid.h"
+#include "ViewMapBuilder.h"
+
+#include "../geometry/GridHelpers.h"
+#include "../geometry/GeomUtils.h"
+
+#include "../winged_edge/WFillGrid.h"
+
+#include "BKE_global.h"
+
+// XXX Grmll... G is used as template's typename parameter :/
+const Global &_global = G;
+
+#define LOGGING FALSE
+
+using namespace std;
+
+template <typename G, typename I>
+static void findOccludee(FEdge *fe, G& grid, I& occluders, real epsilon, WFace **oaWFace,
+ Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector<WVertex*>& faceVertices)
+{
+ WFace *face = NULL;
+ if (fe->isSmooth()) {
+ FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth*>(fe);
+ face = (WFace*)fes->face();
+ }
+ WFace *oface;
+ bool skipFace;
+
+ WVertex::incoming_edge_iterator ie;
+
+ *oaWFace = NULL;
+ if (((fe)->getNature() & Nature::SILHOUETTE) || ((fe)->getNature() & Nature::BORDER)) {
+ // we cast a ray from A in the same direction but looking behind
+ Vec3r v(-u[0], -u[1], -u[2]);
+ bool noIntersection = true;
+ real mint = FLT_MAX;
+
+ for (occluders.initAfterTarget(); occluders.validAfterTarget(); occluders.nextOccludee()) {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tEvaluating intersection for occludee " << occluders.getWFace() << " and ray " << A
+ << " * " << u << endl;
+ }
+ #endif
+ oface = occluders.getWFace();
+ Polygon3r *p = occluders.getCameraSpacePolygon();
+ real d = -((p->getVertices())[0] * p->getNormal());
+ real t, t_u, t_v;
+
+ if (0 != face) {
+ skipFace = false;
+
+ if (face == oface)
+ continue;
+
+ if (faceVertices.empty())
+ continue;
+
+ for (vector<WVertex*>::iterator fv = faceVertices.begin(), fvend = faceVertices.end();
+ fv != fvend;
+ ++fv)
+ {
+ if ((*fv)->isBoundary())
+ continue;
+ WVertex::incoming_edge_iterator iebegin = (*fv)->incoming_edges_begin();
+ WVertex::incoming_edge_iterator ieend = (*fv)->incoming_edges_end();
+ for (ie = iebegin; ie != ieend; ++ie) {
+ if ((*ie) == 0)
+ continue;
+
+ WFace *sface = (*ie)->GetbFace();
+ if (sface == oface) {
+ skipFace = true;
+ break;
+ }
+ }
+ if (skipFace)
+ break;
+ }
+ if (skipFace)
+ continue;
+ }
+ else {
+ // check whether the edge and the polygon plane are coincident:
+ //-------------------------------------------------------------
+ //first let us compute the plane equation.
+ if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, p->getNormal(), d, t, epsilon))
+ {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tRejecting occluder for target coincidence." << endl;
+ }
+ #endif
+ continue;
+ }
+ }
+
+ if (p->rayIntersect(A, v, t, t_u, t_v)) {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tRay " << A << " * " << v << " intersects at time " << t << endl;
+ cout << "\t\t(v * normal) == " << (v * p->getNormal()) << " for normal " << p->getNormal() << endl;
+ }
+ #endif
+ if (fabs(v * p->getNormal()) > 0.0001) {
+ if ((t > 0.0)) { // && (t<1.0))
+ if (t < mint) {
+ *oaWFace = oface;
+ mint = t;
+ noIntersection = false;
+ fe->setOccludeeIntersection(Vec3r(A + t * v));
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tIs occludee" << endl;
+ }
+ #endif
+ }
+ }
+ }
+
+ occluders.reportDepth(A, v, t);
+ }
+ }
+
+ if (noIntersection)
+ *oaWFace = NULL;
+ }
+}
+
+template <typename G, typename I>
+static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge *ve, WFace **oaFace)
+{
+ Vec3r A;
+ Vec3r edge;
+ Vec3r origin;
+ A = Vec3r(((fe)->vertexA()->point3D() + (fe)->vertexB()->point3D()) / 2.0);
+ edge = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D());
+ origin = Vec3r((fe)->vertexA()->point3D());
+ Vec3r u;
+ if (grid.orthographicProjection()) {
+ u = Vec3r(0.0, 0.0, grid.viewpoint().z() - A.z());
+ }
+ else {
+ u = Vec3r(grid.viewpoint() - A);
+ }
+ u.normalize();
+
+ vector<WVertex*> faceVertices;
+
+ WFace *face = NULL;
+ if (fe->isSmooth()) {
+ FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth*>(fe);
+ face = (WFace*)fes->face();
+ }
+
+ if (face) {
+ face->RetrieveVertexList(faceVertices);
+ }
+
+ I occluders(grid, A, epsilon);
+ findOccludee<G, I>(fe, grid, occluders, epsilon, oaFace, u, A, origin, edge, faceVertices);
+}
+
+// computeVisibility takes a pointer to foundOccluders, instead of using a reference,
+// so that computeVeryFastVisibility can skip the AddOccluders step with minimal overhead.
+template <typename G, typename I>
+static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon, ViewEdge *ve, WFace **oaWFace,
+ set<ViewShape*> *foundOccluders)
+{
+ int qi = 0;
+
+ Vec3r center;
+ Vec3r edge;
+ Vec3r origin;
+
+ center = fe->center3d();
+ edge = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D());
+ origin = Vec3r(fe->vertexA()->point3D());
+
+ Vec3r vp;
+ if (grid.orthographicProjection()) {
+ vp = Vec3r(center.x(), center.y(), grid.viewpoint().z());
+ }
+ else {
+ vp = Vec3r(grid.viewpoint());
+ }
+ Vec3r u(vp - center);
+ real raylength = u.norm();
+ u.normalize();
+
+ WFace *face = NULL;
+ if (fe->isSmooth()) {
+ FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth*>(fe);
+ face = (WFace*)fes->face();
+ }
+ vector<WVertex*> faceVertices;
+ WVertex::incoming_edge_iterator ie;
+
+ WFace *oface;
+ bool skipFace;
+
+ if (face)
+ face->RetrieveVertexList(faceVertices);
+
+ I occluders(grid, center, epsilon);
+
+ for (occluders.initBeforeTarget(); occluders.validBeforeTarget(); occluders.nextOccluder()) {
+ // If we're dealing with an exact silhouette, check whether we must take care of this occluder of not.
+ // (Indeed, we don't consider the occluders that share at least one vertex with the face containing this edge).
+ //-----------
+ oface = occluders.getWFace();
+ Polygon3r *p = occluders.getCameraSpacePolygon();
+ real t, t_u, t_v;
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tEvaluating intersection for occluder " << (p->getVertices())[0] << (p->getVertices())[1]
+ << (p->getVertices())[2] << endl << "\t\t\tand ray " << vp << " * " << u << " (center " << center << ")"
+ << endl;
+ }
+ #endif
+
+ #if LOGGING
+ Vec3r v(vp - center);
+ real rl = v.norm();
+ v.normalize();
+ vector<Vec3r> points;
+ // Iterate over vertices, storing projections in points
+ for (vector<WOEdge*>::const_iterator woe = oface->getEdgeList().begin(), woend = oface->getEdgeList().end();
+ woe != woend;
+ woe++)
+ {
+ points.push_back(Vec3r((*woe)->GetaVertex()->GetVertex()));
+ }
+ Polygon3r p1(points, oface->GetNormal());
+ Vec3r v1((p1.getVertices())[0]);
+ real d = -(v1 * p->getNormal());
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tp: " << (p->getVertices())[0] << (p->getVertices())[1] << (p->getVertices())[2] << ", norm: "
+ << p->getNormal() << endl;
+ cout << "\t\tp1: " << (p1.getVertices())[0] << (p1.getVertices())[1] << (p1.getVertices())[2] << ", norm: "
+ << p1.getNormal() << endl;
+ }
+ #else
+ real d = -((p->getVertices())[0] * p->getNormal());
+ #endif
+
+ if (face)
+ {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tDetermining face adjacency...";
+ }
+ #endif
+ skipFace = false;
+
+ if (face == oface) {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << " Rejecting occluder for face concurrency." << endl;
+ }
+ #endif
+ continue;
+ }
+
+
+ for (vector<WVertex*>::iterator fv = faceVertices.begin(), fvend = faceVertices.end(); fv != fvend; ++fv) {
+ if ((*fv)->isBoundary())
+ continue;
+
+ WVertex::incoming_edge_iterator iebegin = (*fv)->incoming_edges_begin();
+ WVertex::incoming_edge_iterator ieend = (*fv)->incoming_edges_end();
+ for (ie = iebegin; ie != ieend; ++ie) {
+ if ((*ie) == 0)
+ continue;
+
+ WFace *sface = (*ie)->GetbFace();
+ //WFace *sfacea = (*ie)->GetaFace();
+ //if ((sface == oface) || (sfacea == oface))
+ if (sface == oface) {
+ skipFace = true;
+ break;
+ }
+ }
+ if (skipFace)
+ break;
+ }
+ if (skipFace) {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << " Rejecting occluder for face adjacency." << endl;
+ }
+ #endif
+ continue;
+ }
+ }
+ else {
+ // check whether the edge and the polygon plane are coincident:
+ //-------------------------------------------------------------
+ //first let us compute the plane equation.
+ if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, p->getNormal(), d, t, epsilon)) {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tRejecting occluder for target coincidence." << endl;
+ }
+ #endif
+ continue;
+ }
+ }
+
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ real x;
+ if (p1.rayIntersect(center, v, x, t_u, t_v)) {
+ cout << "\t\tRay should intersect at time " << (rl - x) << ". Center: " << center << ", V: " << v
+ << ", RL: " << rl << ", T:" << x << endl;
+ }
+ else {
+ cout << "\t\tRay should not intersect. Center: " << center << ", V: " << v << ", RL: " << rl << endl;
+ }
+ }
+ #endif
+
+ if (p->rayIntersect(center, u, t, t_u, t_v)) {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tRay " << center << " * " << u << " intersects at time " << t << " (raylength is "
+ << raylength << ")" << endl;
+ cout << "\t\t(u * normal) == " << (u * p->getNormal()) << " for normal " << p->getNormal() << endl;
+ }
+ #endif
+ if (fabs(u * p->getNormal()) > 0.0001) {
+ if ((t > 0.0) && (t < raylength)) {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tIs occluder" << endl;
+ }
+ #endif
+ if ( foundOccluders != NULL ) {
+ ViewShape *vshape = viewMap->viewShape(oface->GetVertex(0)->shape()->GetId());
+ foundOccluders->insert(vshape);
+ }
+ ++qi;
+
+ if (! grid.enableQI())
+ break;
+ }
+
+ occluders.reportDepth(center, u, t);
+ }
+ }
+ }
+
+ // Find occludee
+ findOccludee<G, I>(fe, grid, occluders, epsilon, oaWFace, u, center, origin, edge, faceVertices);
+
+ return qi;
+}
+
+// computeCumulativeVisibility returns the lowest x such that the majority of FEdges have QI <= x
+//
+// This was probably the original intention of the "normal" algorithm on which computeDetailedVisibility is based.
+// But because the "normal" algorithm chooses the most popular QI, without considering any other values, a ViewEdge
+// with FEdges having QIs of 0, 21, 22, 23, 24 and 25 will end up having a total QI of 0, even though most of the
+// FEdges are heavily occluded. computeCumulativeVisibility will treat this case as a QI of 22 because 3 out of
+// 6 occluders have QI <= 22.
+
+template <typename G, typename I>
+static void computeCumulativeVisibility(ViewMap *ioViewMap, G& grid, real epsilon, RenderMonitor *iRenderMonitor)
+{
+ vector<ViewEdge*>& vedges = ioViewMap->ViewEdges();
+
+ FEdge *fe, *festart;
+ int nSamples = 0;
+ vector<WFace*> wFaces;
+ WFace *wFace = NULL;
+ unsigned tmpQI = 0;
+ unsigned qiClasses[256];
+ unsigned maxIndex, maxCard;
+ unsigned qiMajority;
+ for (vector<ViewEdge*>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
+ if (iRenderMonitor && iRenderMonitor->testBreak())
+ break;
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "Processing ViewEdge " << (*ve)->getId() << endl;
+ }
+ #endif
+ // Find an edge to test
+ if (!(*ve)->isInImage()) {
+ // This view edge has been proscenium culled
+ (*ve)->setQI(255);
+ (*ve)->setaShape(0);
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tCulled." << endl;
+ }
+ #endif
+ continue;
+ }
+
+ // Test edge
+ festart = (*ve)->fedgeA();
+ fe = (*ve)->fedgeA();
+ qiMajority = 0;
+ do {
+ if (fe != NULL && fe->isInImage()) {
+ qiMajority++;
+ }
+ fe = fe->nextEdge();
+ } while (fe && fe != festart);
+
+ if (qiMajority == 0) {
+ // There are no occludable FEdges on this ViewEdge
+ // This should be impossible.
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "View Edge in viewport without occludable FEdges: " << (*ve)->getId() << endl;
+ }
+ // We can recover from this error:
+ // Treat this edge as fully visible with no occludee
+ (*ve)->setQI(0);
+ (*ve)->setaShape(0);
+ continue;
+ }
+ else {
+ ++qiMajority;
+ qiMajority >>= 1;
+ }
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tqiMajority: " << qiMajority << endl;
+ }
+ #endif
+
+ tmpQI = 0;
+ maxIndex = 0;
+ maxCard = 0;
+ nSamples = 0;
+ memset(qiClasses, 0, 256 * sizeof(*qiClasses));
+ set<ViewShape*> foundOccluders;
+
+ fe = (*ve)->fedgeA();
+ do {
+ if (!fe || !fe->isInImage()) {
+ fe = fe->nextEdge();
+ continue;
+ }
+ if ((maxCard < qiMajority)) {
+ //ARB: change &wFace to wFace and use reference in called function
+ tmpQI = computeVisibility<G, I>(ioViewMap, fe, grid, epsilon, *ve, &wFace, &foundOccluders);
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tFEdge: visibility " << tmpQI << endl;
+ }
+ #endif
+
+ //ARB: This is an error condition, not an alert condition.
+ // Some sort of recovery or abort is necessary.
+ if (tmpQI >= 256) {
+ cerr << "Warning: too many occluding levels" << endl;
+ //ARB: Wild guess: instead of aborting or corrupting memory, treat as tmpQI == 255
+ tmpQI = 255;
+ }
+
+ if (++qiClasses[tmpQI] > maxCard) {
+ maxCard = qiClasses[tmpQI];
+ maxIndex = tmpQI;
+ }
+ }
+ else {
+ //ARB: FindOccludee is redundant if ComputeRayCastingVisibility has been called
+ //ARB: change &wFace to wFace and use reference in called function
+ findOccludee<G, I>(fe, grid, epsilon, *ve, &wFace);
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tFEdge: occludee only (" << (wFace != NULL ? "found" : "not found") << ")" << endl;
+ }
+ #endif
+ }
+
+ // Store test results
+ if (wFace) {
+ vector<Vec3r> vertices;
+ for (int i = 0, numEdges = wFace->numberOfEdges(); i < numEdges; ++i) {
+ vertices.push_back(Vec3r(wFace->GetVertex(i)->GetVertex()));
+ }
+ Polygon3r poly(vertices, wFace->GetNormal());
+ poly.userdata = (void *)wFace;
+ fe->setaFace(poly);
+ wFaces.push_back(wFace);
+ fe->setOccludeeEmpty(false);
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tFound occludee" << endl;
+ }
+ #endif
+ }
+ else {
+ fe->setOccludeeEmpty(true);
+ }
+
+ ++nSamples;
+ fe = fe->nextEdge();
+ } while ((maxCard < qiMajority) && (fe) && (fe != festart));
+
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tFinished with " << nSamples << " samples, maxCard = " << maxCard << endl;
+ }
+ #endif
+
+ // ViewEdge
+ // qi --
+ // Find the minimum value that is >= the majority of the QI
+ for (unsigned count = 0, i = 0; i < 256; ++i) {
+ count += qiClasses[i];
+ if (count >= qiMajority) {
+ (*ve)->setQI(i);
+ break;
+ }
+ }
+ // occluders --
+ // I would rather not have to go through the effort of creating this set and then copying out its contents.
+ // Is there a reason why ViewEdge::_Occluders cannot be converted to a set<>?
+ for (set<ViewShape*>::iterator o = foundOccluders.begin(), oend = foundOccluders.end(); o != oend; ++o) {
+ (*ve)->AddOccluder((*o));
+ }
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tConclusion: QI = " << maxIndex << ", " << (*ve)->occluders_size() << " occluders." << endl;
+ }
+ #else
+ (void)maxIndex;
+ #endif
+ // occludee --
+ if (!wFaces.empty()) {
+ if (wFaces.size() <= (float)nSamples / 2.0f) {
+ (*ve)->setaShape(0);
+ }
+ else {
+ ViewShape *vshape = ioViewMap->viewShape((*wFaces.begin())->GetVertex(0)->shape()->GetId());
+ (*ve)->setaShape(vshape);
+ }
+ }
+
+ wFaces.clear();
+ }
+}
+
+template <typename G, typename I>
+static void computeDetailedVisibility(ViewMap *ioViewMap, G& grid, real epsilon, RenderMonitor *iRenderMonitor)
+{
+ vector<ViewEdge*>& vedges = ioViewMap->ViewEdges();
+
+ FEdge *fe, *festart;
+ int nSamples = 0;
+ vector<WFace*> wFaces;
+ WFace *wFace = NULL;
+ unsigned tmpQI = 0;
+ unsigned qiClasses[256];
+ unsigned maxIndex, maxCard;
+ unsigned qiMajority;
+ for (vector<ViewEdge*>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
+ if (iRenderMonitor && iRenderMonitor->testBreak())
+ break;
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "Processing ViewEdge " << (*ve)->getId() << endl;
+ }
+ #endif
+ // Find an edge to test
+ if (!(*ve)->isInImage()) {
+ // This view edge has been proscenium culled
+ (*ve)->setQI(255);
+ (*ve)->setaShape(0);
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tCulled." << endl;
+ }
+ #endif
+ continue;
+ }
+
+ // Test edge
+ festart = (*ve)->fedgeA();
+ fe = (*ve)->fedgeA();
+ qiMajority = 0;
+ do {
+ if (fe != NULL && fe->isInImage()) {
+ qiMajority++;
+ }
+ fe = fe->nextEdge();
+ } while (fe && fe != festart);
+
+ if (qiMajority == 0) {
+ // There are no occludable FEdges on this ViewEdge
+ // This should be impossible.
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "View Edge in viewport without occludable FEdges: " << (*ve)->getId() << endl;
+ }
+ // We can recover from this error:
+ // Treat this edge as fully visible with no occludee
+ (*ve)->setQI(0);
+ (*ve)->setaShape(0);
+ continue;
+ }
+ else {
+ ++qiMajority;
+ qiMajority >>= 1;
+ }
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tqiMajority: " << qiMajority << endl;
+ }
+ #endif
+
+ tmpQI = 0;
+ maxIndex = 0;
+ maxCard = 0;
+ nSamples = 0;
+ memset(qiClasses, 0, 256 * sizeof(*qiClasses));
+ set<ViewShape*> foundOccluders;
+
+ fe = (*ve)->fedgeA();
+ do {
+ if (fe == NULL || ! fe->isInImage()) {
+ fe = fe->nextEdge();
+ continue;
+ }
+ if ((maxCard < qiMajority)) {
+ //ARB: change &wFace to wFace and use reference in called function
+ tmpQI = computeVisibility<G, I>(ioViewMap, fe, grid, epsilon, *ve, &wFace, &foundOccluders);
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tFEdge: visibility " << tmpQI << endl;
+ }
+ #endif
+
+ //ARB: This is an error condition, not an alert condition.
+ // Some sort of recovery or abort is necessary.
+ if (tmpQI >= 256) {
+ cerr << "Warning: too many occluding levels" << endl;
+ //ARB: Wild guess: instead of aborting or corrupting memory, treat as tmpQI == 255
+ tmpQI = 255;
+ }
+
+ if (++qiClasses[tmpQI] > maxCard) {
+ maxCard = qiClasses[tmpQI];
+ maxIndex = tmpQI;
+ }
+ }
+ else {
+ //ARB: FindOccludee is redundant if ComputeRayCastingVisibility has been called
+ //ARB: change &wFace to wFace and use reference in called function
+ findOccludee<G, I>(fe, grid, epsilon, *ve, &wFace);
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tFEdge: occludee only (" << (wFace != NULL ? "found" : "not found") << ")" << endl;
+ }
+ #endif
+ }
+
+ // Store test results
+ if (wFace) {
+ vector<Vec3r> vertices;
+ for (int i = 0, numEdges = wFace->numberOfEdges(); i < numEdges; ++i) {
+ vertices.push_back(Vec3r(wFace->GetVertex(i)->GetVertex()));
+ }
+ Polygon3r poly(vertices, wFace->GetNormal());
+ poly.userdata = (void *)wFace;
+ fe->setaFace(poly);
+ wFaces.push_back(wFace);
+ fe->setOccludeeEmpty(false);
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tFound occludee" << endl;
+ }
+ #endif
+ }
+ else {
+ fe->setOccludeeEmpty(true);
+ }
+
+ ++nSamples;
+ fe = fe->nextEdge();
+ } while ((maxCard < qiMajority) && (fe) && (fe != festart));
+
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tFinished with " << nSamples << " samples, maxCard = " << maxCard << endl;
+ }
+ #endif
+
+ // ViewEdge
+ // qi --
+ (*ve)->setQI(maxIndex);
+ // occluders --
+ // I would rather not have to go through the effort of creating this this set and then copying out its contents.
+ // Is there a reason why ViewEdge::_Occluders cannot be converted to a set<>?
+ for (set<ViewShape*>::iterator o = foundOccluders.begin(), oend = foundOccluders.end(); o != oend; ++o) {
+ (*ve)->AddOccluder((*o));
+ }
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tConclusion: QI = " << maxIndex << ", " << (*ve)->occluders_size() << " occluders." << endl;
+ }
+ #endif
+ // occludee --
+ if (!wFaces.empty()) {
+ if (wFaces.size() <= (float)nSamples / 2.0f) {
+ (*ve)->setaShape(0);
+ }
+ else {
+ ViewShape *vshape = ioViewMap->viewShape((*wFaces.begin())->GetVertex(0)->shape()->GetId());
+ (*ve)->setaShape(vshape);
+ }
+ }
+
+ wFaces.clear();
+ }
+}
+
+template <typename G, typename I>
+static void computeFastVisibility(ViewMap *ioViewMap, G& grid, real epsilon)
+{
+ vector<ViewEdge*>& vedges = ioViewMap->ViewEdges();
+
+ FEdge *fe, *festart;
+ unsigned nSamples = 0;
+ vector<WFace*> wFaces;
+ WFace *wFace = NULL;
+ unsigned tmpQI = 0;
+ unsigned qiClasses[256];
+ unsigned maxIndex, maxCard;
+ unsigned qiMajority;
+ bool even_test;
+ for (vector<ViewEdge*>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
+ // Find an edge to test
+ if (!(*ve)->isInImage()) {
+ // This view edge has been proscenium culled
+ (*ve)->setQI(255);
+ (*ve)->setaShape(0);
+ continue;
+ }
+
+ // Test edge
+ festart = (*ve)->fedgeA();
+ fe = (*ve)->fedgeA();
+
+ even_test = true;
+ qiMajority = 0;
+ do {
+ if (even_test && fe && fe->isInImage()) {
+ qiMajority++;
+ even_test = !even_test;
+ }
+ fe = fe->nextEdge();
+ } while (fe && fe != festart);
+
+ if (qiMajority == 0 ) {
+ // There are no occludable FEdges on this ViewEdge
+ // This should be impossible.
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "View Edge in viewport without occludable FEdges: " << (*ve)->getId() << endl;
+ }
+ // We can recover from this error:
+ // Treat this edge as fully visible with no occludee
+ (*ve)->setQI(0);
+ (*ve)->setaShape(0);
+ continue;
+ }
+ else {
+ ++qiMajority;
+ qiMajority >>= 1;
+ }
+
+ even_test = true;
+ maxIndex = 0;
+ maxCard = 0;
+ nSamples = 0;
+ memset(qiClasses, 0, 256 * sizeof(*qiClasses));
+ set<ViewShape*> foundOccluders;
+
+ fe = (*ve)->fedgeA();
+ do {
+ if (!fe || !fe->isInImage()) {
+ fe = fe->nextEdge();
+ continue;
+ }
+ if (even_test) {
+ if ((maxCard < qiMajority)) {
+ //ARB: change &wFace to wFace and use reference in called function
+ tmpQI = computeVisibility<G, I>(ioViewMap, fe, grid, epsilon, *ve, &wFace, &foundOccluders);
+
+ //ARB: This is an error condition, not an alert condition.
+ // Some sort of recovery or abort is necessary.
+ if (tmpQI >= 256) {
+ cerr << "Warning: too many occluding levels" << endl;
+ //ARB: Wild guess: instead of aborting or corrupting memory, treat as tmpQI == 255
+ tmpQI = 255;
+ }
+
+ if (++qiClasses[tmpQI] > maxCard) {
+ maxCard = qiClasses[tmpQI];
+ maxIndex = tmpQI;
+ }
+ }
+ else {
+ //ARB: FindOccludee is redundant if ComputeRayCastingVisibility has been called
+ //ARB: change &wFace to wFace and use reference in called function
+ findOccludee<G, I>(fe, grid, epsilon, *ve, &wFace);
+ }
+
+ if (wFace) {
+ vector<Vec3r> vertices;
+ for (int i = 0, numEdges = wFace->numberOfEdges(); i < numEdges; ++i) {
+ vertices.push_back(Vec3r(wFace->GetVertex(i)->GetVertex()));
+ }
+ Polygon3r poly(vertices, wFace->GetNormal());
+ poly.userdata = (void *)wFace;
+ fe->setaFace(poly);
+ wFaces.push_back(wFace);
+ }
+ ++nSamples;
+ }
+
+ even_test = ! even_test;
+ fe = fe->nextEdge();
+ } while ((maxCard < qiMajority) && (fe) && (fe != festart));
+
+ // qi --
+ (*ve)->setQI(maxIndex);
+
+ // occluders --
+ for (set<ViewShape*>::iterator o = foundOccluders.begin(), oend = foundOccluders.end(); o != oend; ++o) {
+ (*ve)->AddOccluder((*o));
+ }
+
+ // occludee --
+ if (!wFaces.empty()) {
+ if (wFaces.size() < nSamples / 2) {
+ (*ve)->setaShape(0);
+ }
+ else {
+ ViewShape *vshape = ioViewMap->viewShape((*wFaces.begin())->GetVertex(0)->shape()->GetId());
+ (*ve)->setaShape(vshape);
+ }
+ }
+
+ wFaces.clear();
+ }
+}
+
+template <typename G, typename I>
+static void computeVeryFastVisibility(ViewMap *ioViewMap, G& grid, real epsilon)
+{
+ vector<ViewEdge*>& vedges = ioViewMap->ViewEdges();
+
+ FEdge *fe;
+ unsigned qi = 0;
+ WFace *wFace = 0;
+
+ for (vector<ViewEdge*>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
+ // Find an edge to test
+ if (!(*ve)->isInImage()) {
+ // This view edge has been proscenium culled
+ (*ve)->setQI(255);
+ (*ve)->setaShape(0);
+ continue;
+ }
+ fe = (*ve)->fedgeA();
+ // Find a FEdge inside the occluder proscenium to test for visibility
+ FEdge *festart = fe;
+ while (fe && !fe->isInImage() && fe != festart) {
+ fe = fe->nextEdge();
+ }
+
+ // Test edge
+ if (!fe || !fe->isInImage()) {
+ // There are no occludable FEdges on this ViewEdge
+ // This should be impossible.
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "View Edge in viewport without occludable FEdges: " << (*ve)->getId() << endl;
+ }
+ // We can recover from this error:
+ // Treat this edge as fully visible with no occludee
+ qi = 0;
+ wFace = NULL;
+ }
+ else {
+ qi = computeVisibility<G, I>(ioViewMap, fe, grid, epsilon, *ve, &wFace, NULL);
+ }
+
+ // Store test results
+ if (wFace) {
+ vector<Vec3r> vertices;
+ for (int i = 0, numEdges = wFace->numberOfEdges(); i < numEdges; ++i) {
+ vertices.push_back(Vec3r(wFace->GetVertex(i)->GetVertex()));
+ }
+ Polygon3r poly(vertices, wFace->GetNormal());
+ poly.userdata = (void *)wFace;
+ fe->setaFace(poly); // This works because setaFace *copies* the polygon
+ ViewShape *vshape = ioViewMap->viewShape(wFace->GetVertex(0)->shape()->GetId());
+ (*ve)->setaShape(vshape);
+ }
+ else {
+ (*ve)->setaShape(0);
+ }
+ (*ve)->setQI(qi);
+ }
+}
+
+void ViewMapBuilder::BuildGrid(WingedEdge& we, const BBox<Vec3r>& bbox, unsigned int sceneNumFaces)
+{
+ _Grid->clear();
+ Vec3r size;
+ for (unsigned int i = 0; i < 3; i++) {
+ size[i] = fabs(bbox.getMax()[i] - bbox.getMin()[i]);
+ size[i] += size[i]/10.0; // let make the grid 1/10 bigger to avoid numerical errors while computing triangles/cells intersections
+ if (size[i] == 0) {
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "Warning: the bbox size is 0 in dimension " << i << endl;
+ }
+ }
+ }
+ _Grid->configure(Vec3r(bbox.getMin() - size / 20.0), size, sceneNumFaces);
+
+ // Fill in the grid:
+ WFillGrid fillGridRenderer(_Grid, &we);
+ fillGridRenderer.fillGrid();
+
+ // DEBUG
+ _Grid->displayDebug();
+}
+
+ViewMap *ViewMapBuilder::BuildViewMap(WingedEdge& we, visibility_algo iAlgo, real epsilon,
+ const BBox<Vec3r>& bbox, unsigned int sceneNumFaces)
+{
+ _ViewMap = new ViewMap;
+ _currentId = 1;
+ _currentFId = 0;
+ _currentSVertexId = 0;
+
+ // Builds initial view edges
+ computeInitialViewEdges(we);
+
+ // Detects cusps
+ computeCusps(_ViewMap);
+
+ // Compute intersections
+ ComputeIntersections(_ViewMap, sweep_line, epsilon);
+
+ // Compute visibility
+ ComputeEdgesVisibility(_ViewMap, we, bbox, sceneNumFaces, iAlgo, epsilon);
+
+ return _ViewMap;
+}
+
+static inline real distance2D(const Vec3r & point, const real origin[2])
+{
+ return ::hypot((point[0] - origin[0]), (point[1] - origin[1]));
+}
+
+static inline bool crossesProscenium(real proscenium[4], FEdge *fe)
+{
+ Vec2r min(proscenium[0], proscenium[2]);
+ Vec2r max(proscenium[1], proscenium[3]);
+ Vec2r A(fe->vertexA()->getProjectedX(), fe->vertexA()->getProjectedY());
+ Vec2r B(fe->vertexB()->getProjectedX(), fe->vertexB()->getProjectedY());
+
+ return GeomUtils::intersect2dSeg2dArea (min, max, A, B);
+}
+
+static inline bool insideProscenium(real proscenium[4], const Vec3r& point)
+{
+ return !(point[0] < proscenium[0] || point[0] > proscenium[1] ||
+ point[1] < proscenium[2] || point[1] > proscenium[3]);
+}
+
+void ViewMapBuilder::CullViewEdges(ViewMap *ioViewMap, real viewProscenium[4], real occluderProscenium[4],
+ bool extensiveFEdgeSearch)
+{
+ // Cull view edges by marking them as non-displayable.
+ // This avoids the complications of trying to delete edges from the ViewMap.
+
+ // Non-displayable view edges will be skipped over during visibility calculation.
+
+ // View edges will be culled according to their position w.r.t. the viewport proscenium (viewport + 5% border,
+ // or some such).
+
+ // Get proscenium boundary for culling
+ GridHelpers::getDefaultViewProscenium(viewProscenium);
+ real prosceniumOrigin[2];
+ prosceniumOrigin[0] = (viewProscenium[1] - viewProscenium[0]) / 2.0;
+ prosceniumOrigin[1] = (viewProscenium[3] - viewProscenium[2]) / 2.0;
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "Proscenium culling:" << endl;
+ cout << "Proscenium: [" << viewProscenium[0] << ", " << viewProscenium[1] << ", " << viewProscenium[2]
+ << ", " << viewProscenium[3] << "]"<< endl;
+ cout << "Origin: [" << prosceniumOrigin[0] << ", " << prosceniumOrigin[1] << "]"<< endl;
+ }
+
+ // A separate occluder proscenium will also be maintained, starting out the same as the viewport proscenium, and
+ // expanding as necessary so that it encompasses the center point of at least one feature edge in each retained view
+ // edge.
+ // The occluder proscenium will be used later to cull occluding triangles before they are inserted into the Grid.
+ // The occluder proscenium starts out the same size as the view proscenium
+ GridHelpers::getDefaultViewProscenium(occluderProscenium);
+
+ // N.B. Freestyle is inconsistent in its use of ViewMap::viewedges_container and vector<ViewEdge*>::iterator.
+ // Probably all occurences of vector<ViewEdge*>::iterator should be replaced ViewMap::viewedges_container
+ // throughout the code.
+ // For each view edge
+ ViewMap::viewedges_container::iterator ve, veend;
+
+ for (ve = ioViewMap->ViewEdges().begin(), veend = ioViewMap->ViewEdges().end(); ve != veend; ve++) {
+ // Overview:
+ // Search for a visible feature edge
+ // If none: mark view edge as non-displayable
+ // Otherwise:
+ // Find a feature edge with center point inside occluder proscenium.
+ // If none exists, find the feature edge with center point closest to viewport origin.
+ // Expand occluder proscenium to enclose center point.
+
+ // For each feature edge, while bestOccluderTarget not found and view edge not visibile
+ bool bestOccluderTargetFound = false;
+ FEdge *bestOccluderTarget = NULL;
+ real bestOccluderDistance = 0.0;
+ FEdge *festart = (*ve)->fedgeA();
+ FEdge *fe = festart;
+ // All ViewEdges start culled
+ (*ve)->setIsInImage(false);
+
+ // For simple visibility calculation: mark a feature edge that is known to have a center point inside the
+ // occluder proscenium. Cull all other feature edges.
+ do {
+ // All FEdges start culled
+ fe->setIsInImage(false);
+
+ // Look for the visible edge that can most easily be included in the occluder proscenium.
+ if (!bestOccluderTargetFound) {
+ // If center point is inside occluder proscenium,
+ if (insideProscenium(occluderProscenium, fe->center2d())) {
+ // Use this feature edge for visibility deterimination
+ fe->setIsInImage(true);
+ // Mark bestOccluderTarget as found
+ bestOccluderTargetFound = true;
+ bestOccluderTarget = fe;
+ }
+ else {
+ real d = distance2D(fe->center2d(), prosceniumOrigin);
+ // If center point is closer to viewport origin than current target
+ if (bestOccluderTarget == NULL || d < bestOccluderDistance) {
+ // Then store as bestOccluderTarget
+ bestOccluderDistance = d;
+ bestOccluderTarget = fe;
+ }
+ }
+ }
+
+ // If feature edge crosses the view proscenium
+ if (!(*ve)->isInImage() && crossesProscenium(viewProscenium, fe)) {
+ // Then the view edge will be included in the image
+ (*ve)->setIsInImage(true);
+ }
+ fe = fe->nextEdge();
+ } while (fe && fe != festart && !(bestOccluderTargetFound && (*ve)->isInImage()));
+
+ // Either we have run out of FEdges, or we already have the one edge we need to determine visibility
+ // Cull all remaining edges.
+ while (fe && fe != festart) {
+ fe->setIsInImage(false);
+ fe = fe->nextEdge();
+ }
+
+ // If bestOccluderTarget was not found inside the occluder proscenium, we need to expand the occluder
+ // proscenium to include it.
+ if ((*ve)->isInImage() && bestOccluderTarget != NULL && !bestOccluderTargetFound) {
+ // Expand occluder proscenium to enclose bestOccluderTarget
+ Vec3r point = bestOccluderTarget->center2d();
+ if (point[0] < occluderProscenium[0]) {
+ occluderProscenium[0] = point[0];
+ }
+ else if (point[0] > occluderProscenium[1]) {
+ occluderProscenium[1] = point[0];
+ }
+ if (point[1] < occluderProscenium[2]) {
+ occluderProscenium[2] = point[1];
+ }
+ else if (point[1] > occluderProscenium[3]) {
+ occluderProscenium[3] = point[1];
+ }
+ // Use bestOccluderTarget for visibility determination
+ bestOccluderTarget->setIsInImage(true);
+ }
+ }
+
+ // We are done calculating the occluder proscenium.
+ // Expand the occluder proscenium by an epsilon to avoid rounding errors.
+ const real epsilon = 1.0e-6;
+ occluderProscenium[0] -= epsilon;
+ occluderProscenium[1] += epsilon;
+ occluderProscenium[2] -= epsilon;
+ occluderProscenium[3] += epsilon;
+
+ // For "Normal" or "Fast" style visibility computation only:
+
+ // For more detailed visibility calculation, make a second pass through the view map, marking all feature edges
+ // with center points inside the final occluder proscenium. All of these feature edges can be considered during
+ // visibility calculation.
+
+ // So far we have only found one FEdge per ViewEdge. The "Normal" and "Fast" styles of visibility computation
+ // want to consider many FEdges for each ViewEdge.
+ // Here we re-scan the view map to find any usable FEdges that we skipped on the first pass, or that have become
+ // usable because the occluder proscenium has been expanded since the edge was visited on the first pass.
+ if (extensiveFEdgeSearch) {
+ // For each view edge,
+ for (ve = ioViewMap->ViewEdges().begin(), veend = ioViewMap->ViewEdges().end(); ve != veend; ve++) {
+ if (!(*ve)->isInImage()) {
+ continue;
+ }
+ // For each feature edge,
+ FEdge *festart = (*ve)->fedgeA();
+ FEdge *fe = festart;
+ do {
+ // If not (already) visible and center point inside occluder proscenium,
+ if (!fe->isInImage() && insideProscenium(occluderProscenium, fe->center2d())) {
+ // Use the feature edge for visibility determination
+ fe->setIsInImage(true);
+ }
+ fe = fe->nextEdge();
+ } while (fe && fe != festart);
+ }
+ }
+}
+
+void ViewMapBuilder::computeInitialViewEdges(WingedEdge& we)
+{
+ vector<WShape*> wshapes = we.getWShapes();
+ SShape *psShape;
+
+ for (vector<WShape*>::const_iterator it = wshapes.begin(); it != wshapes.end(); it++) {
+ if (_pRenderMonitor && _pRenderMonitor->testBreak())
+ break;
+
+ // create the embedding
+ psShape = new SShape;
+ psShape->setId((*it)->GetId());
+ psShape->setName((*it)->getName());
+ psShape->setFrsMaterials((*it)->frs_materials()); // FIXME
+
+ // create the view shape
+ ViewShape *vshape = new ViewShape(psShape);
+ // add this view shape to the view map:
+ _ViewMap->AddViewShape(vshape);
+
+ // we want to number the view edges in a unique way for the while scene.
+ _pViewEdgeBuilder->setCurrentViewId(_currentId);
+ // we want to number the feature edges in a unique way for the while scene.
+ _pViewEdgeBuilder->setCurrentFId(_currentFId);
+ // we want to number the SVertex in a unique way for the while scene.
+ _pViewEdgeBuilder->setCurrentSVertexId(_currentFId);
+ _pViewEdgeBuilder->BuildViewEdges(dynamic_cast<WXShape*>(*it), vshape, _ViewMap->ViewEdges(),
+ _ViewMap->ViewVertices(), _ViewMap->FEdges(), _ViewMap->SVertices());
+
+ _currentId = _pViewEdgeBuilder->currentViewId() + 1;
+ _currentFId = _pViewEdgeBuilder->currentFId() + 1;
+ _currentSVertexId = _pViewEdgeBuilder->currentSVertexId() + 1;
+
+ psShape->ComputeBBox();
+ }
+}
+
+void ViewMapBuilder::computeCusps(ViewMap *ioViewMap)
+{
+ vector<ViewVertex*> newVVertices;
+ vector<ViewEdge*> newVEdges;
+ ViewMap::viewedges_container& vedges = ioViewMap->ViewEdges();
+ ViewMap::viewedges_container::iterator ve = vedges.begin(), veend = vedges.end();
+ for (; ve != veend; ++ve) {
+ if (_pRenderMonitor && _pRenderMonitor->testBreak())
+ break;
+ if ((!((*ve)->getNature() & Nature::SILHOUETTE)) || (!((*ve)->fedgeA()->isSmooth())))
+ continue;
+ FEdge *fe = (*ve)->fedgeA();
+ FEdge *fefirst = fe;
+ bool first = true;
+ bool positive = true;
+ do {
+ FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth*>(fe);
+ Vec3r A((fes)->vertexA()->point3d());
+ Vec3r B((fes)->vertexB()->point3d());
+ Vec3r AB(B - A);
+ AB.normalize();
+ Vec3r m((A + B) / 2.0);
+ Vec3r crossP(AB ^ (fes)->normal());
+ crossP.normalize();
+ Vec3r viewvector;
+ if (_orthographicProjection) {
+ viewvector = Vec3r(0.0, 0.0, m.z() - _viewpoint.z());
+ }
+ else {
+ viewvector = Vec3r(m - _viewpoint);
+ }
+ viewvector.normalize();
+ if (first) {
+ if (((crossP) * (viewvector)) > 0)
+ positive = true;
+ else
+ positive = false;
+ first = false;
+ }
+ // If we're in a positive part, we need a stronger negative value to change
+ NonTVertex *cusp = NULL;
+ if (positive) {
+ if (((crossP) * (viewvector)) < -0.1) {
+ // state changes
+ positive = false;
+ // creates and insert cusp
+ cusp = dynamic_cast<NonTVertex*>(ioViewMap->InsertViewVertex(fes->vertexA(), newVEdges));
+ if (cusp)
+ cusp->setNature(cusp->getNature()|Nature::CUSP);
+ }
+ }
+ else {
+ // If we're in a negative part, we need a stronger negative value to change
+ if (((crossP) * (viewvector)) > 0.1) {
+ positive = true;
+ cusp = dynamic_cast<NonTVertex*>(ioViewMap->InsertViewVertex(fes->vertexA(), newVEdges));
+ if (cusp)
+ cusp->setNature(cusp->getNature()|Nature::CUSP);
+ }
+ }
+ fe = fe->nextEdge();
+ } while (fe && fe != fefirst);
+ }
+ for (ve = newVEdges.begin(), veend = newVEdges.end(); ve != veend; ++ve) {
+ (*ve)->viewShape()->AddEdge(*ve);
+ vedges.push_back(*ve);
+ }
+}
+
+void ViewMapBuilder::ComputeCumulativeVisibility(ViewMap *ioViewMap, WingedEdge& we, const BBox<Vec3r>& bbox,
+ real epsilon, bool cull, GridDensityProviderFactory& factory)
+{
+ auto_ptr<GridHelpers::Transform> transform;
+ auto_ptr<OccluderSource> source;
+
+ if (_orthographicProjection) {
+ transform.reset(new BoxGrid::Transform);
+ }
+ else {
+ transform.reset(new SphericalGrid::Transform);
+ }
+
+ if (cull) {
+ source.reset(new CulledOccluderSource(*transform, we, *ioViewMap, true));
+ }
+ else {
+ source.reset(new OccluderSource(*transform, we));
+ }
+
+ auto_ptr<GridDensityProvider> density(factory.newGridDensityProvider(*source, bbox, *transform));
+
+ if (_orthographicProjection) {
+ BoxGrid grid(*source, *density, ioViewMap, _viewpoint, _EnableQI);
+ computeCumulativeVisibility<BoxGrid, BoxGrid::Iterator>(ioViewMap, grid, epsilon, _pRenderMonitor);
+ }
+ else {
+ SphericalGrid grid(*source, *density, ioViewMap, _viewpoint, _EnableQI);
+ computeCumulativeVisibility<SphericalGrid, SphericalGrid::Iterator>(ioViewMap, grid, epsilon, _pRenderMonitor);
+ }
+}
+
+void ViewMapBuilder::ComputeDetailedVisibility(ViewMap *ioViewMap, WingedEdge& we, const BBox<Vec3r>& bbox,
+ real epsilon, bool cull, GridDensityProviderFactory& factory)
+{
+ auto_ptr<GridHelpers::Transform> transform;
+ auto_ptr<OccluderSource> source;
+
+ if (_orthographicProjection) {
+ transform.reset(new BoxGrid::Transform);
+ }
+ else {
+ transform.reset(new SphericalGrid::Transform);
+ }
+
+ if (cull) {
+ source.reset(new CulledOccluderSource(*transform, we, *ioViewMap, true));
+ }
+ else {
+ source.reset(new OccluderSource(*transform, we));
+ }
+
+ auto_ptr<GridDensityProvider> density(factory.newGridDensityProvider(*source, bbox, *transform));
+
+ if (_orthographicProjection) {
+ BoxGrid grid(*source, *density, ioViewMap, _viewpoint, _EnableQI);
+ computeDetailedVisibility<BoxGrid, BoxGrid::Iterator>(ioViewMap, grid, epsilon, _pRenderMonitor);
+ }
+ else {
+ SphericalGrid grid(*source, *density, ioViewMap, _viewpoint, _EnableQI);
+ computeDetailedVisibility<SphericalGrid, SphericalGrid::Iterator>(ioViewMap, grid, epsilon, _pRenderMonitor);
+ }
+}
+
+void ViewMapBuilder::ComputeEdgesVisibility(ViewMap *ioViewMap, WingedEdge& we, const BBox<Vec3r>& bbox,
+ unsigned int sceneNumFaces, visibility_algo iAlgo, real epsilon)
+{
+ switch(iAlgo) {
+ case ray_casting:
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "Using ordinary ray casting" << endl;
+ }
+ BuildGrid(we, bbox, sceneNumFaces);
+ ComputeRayCastingVisibility(ioViewMap, epsilon);
+ break;
+ case ray_casting_fast:
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "Using fast ray casting" << endl;
+ }
+ BuildGrid(we, bbox, sceneNumFaces);
+ ComputeFastRayCastingVisibility(ioViewMap, epsilon);
+ break;
+ case ray_casting_very_fast:
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "Using very fast ray casting" << endl;
+ }
+ BuildGrid(we, bbox, sceneNumFaces);
+ ComputeVeryFastRayCastingVisibility(ioViewMap, epsilon);
+ break;
+ case ray_casting_culled_adaptive_traditional:
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "Using culled adaptive grid with heuristic density and traditional QI calculation" << endl;
+ }
+ try {
+ HeuristicGridDensityProviderFactory factory(0.5f, sceneNumFaces);
+ ComputeDetailedVisibility(ioViewMap, we, bbox, epsilon, true, factory);
+ }
+ catch (...) {
+ // Last resort catch to make sure RAII semantics hold for OptimizedGrid. Can be replaced with
+ // try...catch block around main() if the program as a whole is converted to RAII
+
+ // This is the little-mentioned caveat of RAII: RAII does not work unless destructors are always
+ // called, but destructors are only called if all exceptions are caught (or std::terminate() is
+ // replaced).
+
+ // We don't actually handle the exception here, so re-throw it now that our destructors have had a
+ // chance to run.
+ throw;
+ }
+ break;
+ case ray_casting_adaptive_traditional:
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "Using unculled adaptive grid with heuristic density and traditional QI calculation" << endl;
+ }
+ try {
+ HeuristicGridDensityProviderFactory factory(0.5f, sceneNumFaces);
+ ComputeDetailedVisibility(ioViewMap, we, bbox, epsilon, false, factory);
+ }
+ catch (...) {
+ throw;
+ }
+ break;
+ case ray_casting_culled_adaptive_cumulative:
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "Using culled adaptive grid with heuristic density and cumulative QI calculation" << endl;
+ }
+ try {
+ HeuristicGridDensityProviderFactory factory(0.5f, sceneNumFaces);
+ ComputeCumulativeVisibility(ioViewMap, we, bbox, epsilon, true, factory);
+ }
+ catch (...) {
+ throw;
+ }
+ break;
+ case ray_casting_adaptive_cumulative:
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "Using unculled adaptive grid with heuristic density and cumulative QI calculation" << endl;
+ }
+ try {
+ HeuristicGridDensityProviderFactory factory(0.5f, sceneNumFaces);
+ ComputeCumulativeVisibility(ioViewMap, we, bbox, epsilon, false, factory);
+ }
+ catch (...) {
+ throw;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static const unsigned gProgressBarMaxSteps = 10;
+static const unsigned gProgressBarMinSize = 2000;
+
+void ViewMapBuilder::ComputeRayCastingVisibility(ViewMap *ioViewMap, real epsilon)
+{
+ vector<ViewEdge*>& vedges = ioViewMap->ViewEdges();
+ bool progressBarDisplay = false;
+ unsigned progressBarStep = 0;
+ unsigned vEdgesSize = vedges.size();
+ unsigned fEdgesSize = ioViewMap->FEdges().size();
+
+ if (_pProgressBar != NULL && fEdgesSize > gProgressBarMinSize) {
+ unsigned progressBarSteps = min(gProgressBarMaxSteps, vEdgesSize);
+ progressBarStep = vEdgesSize / progressBarSteps;
+ _pProgressBar->reset();
+ _pProgressBar->setLabelText("Computing Ray casting Visibility");
+ _pProgressBar->setTotalSteps(progressBarSteps);
+ _pProgressBar->setProgress(0);
+ progressBarDisplay = true;
+ }
+
+ unsigned counter = progressBarStep;
+ FEdge *fe, *festart;
+ int nSamples = 0;
+ vector<Polygon3r*> aFaces;
+ Polygon3r *aFace = NULL;
+ unsigned tmpQI = 0;
+ unsigned qiClasses[256];
+ unsigned maxIndex, maxCard;
+ unsigned qiMajority;
+ static unsigned timestamp = 1;
+ for (vector<ViewEdge*>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
+ if (_pRenderMonitor && _pRenderMonitor->testBreak())
+ break;
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "Processing ViewEdge " << (*ve)->getId() << endl;
+ }
+ #endif
+ festart = (*ve)->fedgeA();
+ fe = (*ve)->fedgeA();
+ qiMajority = 1;
+ do {
+ qiMajority++;
+ fe = fe->nextEdge();
+ } while (fe && fe != festart);
+ qiMajority >>= 1;
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tqiMajority: " << qiMajority << endl;
+ }
+ #endif
+
+ tmpQI = 0;
+ maxIndex = 0;
+ maxCard = 0;
+ nSamples = 0;
+ fe = (*ve)->fedgeA();
+ memset(qiClasses, 0, 256 * sizeof(*qiClasses));
+ set<ViewShape*> occluders;
+ do {
+ if ((maxCard < qiMajority)) {
+ tmpQI = ComputeRayCastingVisibility(fe, _Grid, epsilon, occluders, &aFace, timestamp++);
+
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tFEdge: visibility " << tmpQI << endl;
+ }
+ #endif
+ //ARB: This is an error condition, not an alert condition.
+ // Some sort of recovery or abort is necessary.
+ if (tmpQI >= 256) {
+ cerr << "Warning: too many occluding levels" << endl;
+ //ARB: Wild guess: instead of aborting or corrupting memory, treat as tmpQI == 255
+ tmpQI = 255;
+ }
+
+ if (++qiClasses[tmpQI] > maxCard) {
+ maxCard = qiClasses[tmpQI];
+ maxIndex = tmpQI;
+ }
+ }
+ else {
+ //ARB: FindOccludee is redundant if ComputeRayCastingVisibility has been called
+ FindOccludee(fe, _Grid, epsilon, &aFace, timestamp++);
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tFEdge: occludee only (" << (aFace != NULL ? "found" : "not found") << ")" << endl;
+ }
+ #endif
+ }
+
+ if (aFace) {
+ fe->setaFace(*aFace);
+ aFaces.push_back(aFace);
+ fe->setOccludeeEmpty(false);
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tFound occludee" << endl;
+ }
+ #endif
+ }
+ else {
+ //ARB: We are arbitrarily using the last observed value for occludee (almost always the value observed
+ // for the edge before festart). Is that meaningful?
+ // ...in fact, _occludeeEmpty seems to be unused.
+ fe->setOccludeeEmpty(true);
+ }
+
+ ++nSamples;
+ fe = fe->nextEdge();
+ } while ((maxCard < qiMajority) && (fe) && (fe != festart));
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tFinished with " << nSamples << " samples, maxCard = " << maxCard << endl;
+ }
+ #endif
+
+ // ViewEdge
+ // qi --
+ (*ve)->setQI(maxIndex);
+ // occluders --
+ for (set<ViewShape*>::iterator o = occluders.begin(), oend = occluders.end(); o != oend; ++o)
+ (*ve)->AddOccluder((*o));
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\tConclusion: QI = " << maxIndex << ", " << (*ve)->occluders_size() << " occluders." << endl;
+ }
+ #endif
+ // occludee --
+ if (!aFaces.empty()) {
+ if (aFaces.size() <= (float)nSamples / 2.0f) {
+ (*ve)->setaShape(0);
+ }
+ else {
+ vector<Polygon3r*>::iterator p = aFaces.begin();
+ WFace *wface = (WFace*)((*p)->userdata);
+ ViewShape *vshape = ioViewMap->viewShape(wface->GetVertex(0)->shape()->GetId());
+ ++p;
+ (*ve)->setaShape(vshape);
+ }
+ }
+
+ if (progressBarDisplay) {
+ counter--;
+ if (counter <= 0) {
+ counter = progressBarStep;
+ _pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
+ }
+ }
+ aFaces.clear();
+ }
+}
+
+void ViewMapBuilder::ComputeFastRayCastingVisibility(ViewMap *ioViewMap, real epsilon)
+{
+ vector<ViewEdge*>& vedges = ioViewMap->ViewEdges();
+ bool progressBarDisplay = false;
+ unsigned progressBarStep = 0;
+ unsigned vEdgesSize = vedges.size();
+ unsigned fEdgesSize = ioViewMap->FEdges().size();
+
+ if (_pProgressBar != NULL && fEdgesSize > gProgressBarMinSize) {
+ unsigned progressBarSteps = min(gProgressBarMaxSteps, vEdgesSize);
+ progressBarStep = vEdgesSize / progressBarSteps;
+ _pProgressBar->reset();
+ _pProgressBar->setLabelText("Computing Ray casting Visibility");
+ _pProgressBar->setTotalSteps(progressBarSteps);
+ _pProgressBar->setProgress(0);
+ progressBarDisplay = true;
+ }
+
+ unsigned counter = progressBarStep;
+ FEdge *fe, *festart;
+ unsigned nSamples = 0;
+ vector<Polygon3r*> aFaces;
+ Polygon3r *aFace = NULL;
+ unsigned tmpQI = 0;
+ unsigned qiClasses[256];
+ unsigned maxIndex, maxCard;
+ unsigned qiMajority;
+ static unsigned timestamp = 1;
+ bool even_test;
+ for (vector<ViewEdge*>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
+ if (_pRenderMonitor && _pRenderMonitor->testBreak())
+ break;
+
+ festart = (*ve)->fedgeA();
+ fe = (*ve)->fedgeA();
+ qiMajority = 1;
+ do {
+ qiMajority++;
+ fe = fe->nextEdge();
+ } while (fe && fe != festart);
+ if (qiMajority >= 4)
+ qiMajority >>= 2;
+ else
+ qiMajority = 1;
+
+ set<ViewShape*> occluders;
+
+ even_test = true;
+ maxIndex = 0;
+ maxCard = 0;
+ nSamples = 0;
+ memset(qiClasses, 0, 256 * sizeof(*qiClasses));
+ fe = (*ve)->fedgeA();
+ do {
+ if (even_test) {
+ if ((maxCard < qiMajority)) {
+ tmpQI = ComputeRayCastingVisibility(fe, _Grid, epsilon, occluders, &aFace, timestamp++);
+
+ //ARB: This is an error condition, not an alert condition.
+ // Some sort of recovery or abort is necessary.
+ if (tmpQI >= 256) {
+ cerr << "Warning: too many occluding levels" << endl;
+ //ARB: Wild guess: instead of aborting or corrupting memory, treat as tmpQI == 255
+ tmpQI = 255;
+ }
+
+ if (++qiClasses[tmpQI] > maxCard) {
+ maxCard = qiClasses[tmpQI];
+ maxIndex = tmpQI;
+ }
+ }
+ else {
+ //ARB: FindOccludee is redundant if ComputeRayCastingVisibility has been called
+ FindOccludee(fe, _Grid, epsilon, &aFace, timestamp++);
+ }
+
+ if (aFace) {
+ fe->setaFace(*aFace);
+ aFaces.push_back(aFace);
+ }
+ ++nSamples;
+ even_test = false;
+ }
+ else {
+ even_test = true;
+ }
+ fe = fe->nextEdge();
+ } while ((maxCard < qiMajority) && (fe) && (fe != festart));
+
+ (*ve)->setQI(maxIndex);
+
+ if (!aFaces.empty()) {
+ if (aFaces.size() < nSamples / 2) {
+ (*ve)->setaShape(0);
+ }
+ else {
+ vector<Polygon3r*>::iterator p = aFaces.begin();
+ WFace *wface = (WFace*)((*p)->userdata);
+ ViewShape *vshape = ioViewMap->viewShape(wface->GetVertex(0)->shape()->GetId());
+ ++p;
+#if 0
+ for (; p != pend; ++p) {
+ WFace *f = (WFace*)((*p)->userdata);
+ ViewShape *vs = ioViewMap->viewShape(f->GetVertex(0)->shape()->GetId());
+ if (vs != vshape) {
+ sameShape = false;
+ break;
+ }
+ }
+ if (sameShape)
+#endif
+ (*ve)->setaShape(vshape);
+ }
+ }
+
+ //(*ve)->setaFace(aFace);
+
+ if (progressBarDisplay) {
+ counter--;
+ if (counter <= 0) {
+ counter = progressBarStep;
+ _pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
+ }
+ }
+ aFaces.clear();
+ }
+}
+
+void ViewMapBuilder::ComputeVeryFastRayCastingVisibility(ViewMap *ioViewMap, real epsilon)
+{
+ vector<ViewEdge*>& vedges = ioViewMap->ViewEdges();
+ bool progressBarDisplay = false;
+ unsigned progressBarStep = 0;
+ unsigned vEdgesSize = vedges.size();
+ unsigned fEdgesSize = ioViewMap->FEdges().size();
+
+ if (_pProgressBar != NULL && fEdgesSize > gProgressBarMinSize) {
+ unsigned progressBarSteps = min(gProgressBarMaxSteps, vEdgesSize);
+ progressBarStep = vEdgesSize / progressBarSteps;
+ _pProgressBar->reset();
+ _pProgressBar->setLabelText("Computing Ray casting Visibility");
+ _pProgressBar->setTotalSteps(progressBarSteps);
+ _pProgressBar->setProgress(0);
+ progressBarDisplay = true;
+ }
+
+ unsigned counter = progressBarStep;
+ FEdge *fe;
+ unsigned qi = 0;
+ Polygon3r *aFace = NULL;
+ static unsigned timestamp = 1;
+ for (vector<ViewEdge*>::iterator ve = vedges.begin(), veend = vedges.end(); ve != veend; ve++) {
+ if (_pRenderMonitor && _pRenderMonitor->testBreak())
+ break;
+
+ set<ViewShape*> occluders;
+
+ fe = (*ve)->fedgeA();
+ qi = ComputeRayCastingVisibility(fe, _Grid, epsilon, occluders, &aFace, timestamp++);
+ if (aFace) {
+ fe->setaFace(*aFace);
+ WFace *wface = (WFace*)(aFace->userdata);
+ ViewShape *vshape = ioViewMap->viewShape(wface->GetVertex(0)->shape()->GetId());
+ (*ve)->setaShape(vshape);
+ }
+ else {
+ (*ve)->setaShape(0);
+ }
+
+ (*ve)->setQI(qi);
+
+ if (progressBarDisplay) {
+ counter--;
+ if (counter <= 0) {
+ counter = progressBarStep;
+ _pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
+ }
+ }
+ }
+}
+
+void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp,
+ Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector<WVertex*>& faceVertices)
+{
+ WFace *face = NULL;
+ if (fe->isSmooth()) {
+ FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth*>(fe);
+ face = (WFace*)fes->face();
+ }
+ OccludersSet occluders;
+ WFace *oface;
+ bool skipFace;
+
+ WVertex::incoming_edge_iterator ie;
+ OccludersSet::iterator p, pend;
+
+ *oaPolygon = NULL;
+ if (((fe)->getNature() & Nature::SILHOUETTE) || ((fe)->getNature() & Nature::BORDER)) {
+ occluders.clear();
+ // we cast a ray from A in the same direction but looking behind
+ Vec3r v(-u[0], -u[1], -u[2]);
+ iGrid->castInfiniteRay(A, v, occluders, timestamp);
+
+ bool noIntersection = true;
+ real mint = FLT_MAX;
+ // we met some occluders, let us fill the aShape field with the first intersected occluder
+ for (p = occluders.begin(), pend = occluders.end(); p != pend; p++) {
+ // check whether the edge and the polygon plane are coincident:
+ //-------------------------------------------------------------
+ //first let us compute the plane equation.
+ oface = (WFace*)(*p)->userdata;
+ Vec3r v1(((*p)->getVertices())[0]);
+ Vec3r normal((*p)->getNormal());
+ real d = -(v1 * normal);
+ real t, t_u, t_v;
+
+ if (face) {
+ skipFace = false;
+
+ if (face == oface)
+ continue;
+
+ if (faceVertices.empty())
+ continue;
+
+ for (vector<WVertex*>::iterator fv = faceVertices.begin(), fvend = faceVertices.end();
+ fv != fvend;
+ ++fv)
+ {
+ if ((*fv)->isBoundary())
+ continue;
+ WVertex::incoming_edge_iterator iebegin = (*fv)->incoming_edges_begin();
+ WVertex::incoming_edge_iterator ieend = (*fv)->incoming_edges_end();
+ for (ie = iebegin; ie != ieend; ++ie) {
+ if ((*ie) == 0)
+ continue;
+
+ WFace *sface = (*ie)->GetbFace();
+ if (sface == oface) {
+ skipFace = true;
+ break;
+ }
+ }
+ if (skipFace)
+ break;
+ }
+ if (skipFace)
+ continue;
+ }
+ else {
+ if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, normal, d, t, epsilon))
+ continue;
+ }
+ if ((*p)->rayIntersect(A, v, t, t_u, t_v)) {
+ if (fabs(v * normal) > 0.0001) {
+ if (t > 0.0) { // && t < 1.0) {
+ if (t < mint) {
+ *oaPolygon = (*p);
+ mint = t;
+ noIntersection = false;
+ fe->setOccludeeIntersection(Vec3r(A + t * v));
+ }
+ }
+ }
+ }
+ }
+
+ if (noIntersection)
+ *oaPolygon = NULL;
+ }
+}
+
+void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp)
+{
+ OccludersSet occluders;
+
+ Vec3r A;
+ Vec3r edge;
+ Vec3r origin;
+ A = Vec3r(((fe)->vertexA()->point3D() + (fe)->vertexB()->point3D()) / 2.0);
+ edge = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D());
+ origin = Vec3r((fe)->vertexA()->point3D());
+ Vec3r u;
+ if (_orthographicProjection) {
+ u = Vec3r(0.0, 0.0, _viewpoint.z() - A.z());
+ }
+ else {
+ u = Vec3r(_viewpoint - A);
+ }
+ u.normalize();
+ if (A < iGrid->getOrigin())
+ cerr << "Warning: point is out of the grid for fedge " << fe->getId().getFirst() << "-"
+ << fe->getId().getSecond() << endl;
+
+ vector<WVertex*> faceVertices;
+
+ WFace *face = NULL;
+ if (fe->isSmooth()) {
+ FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth*>(fe);
+ face = (WFace*)fes->face();
+ }
+ if (face)
+ face->RetrieveVertexList(faceVertices);
+
+ return FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, A, origin, edge, faceVertices);
+}
+
+int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real epsilon, set<ViewShape*>& oOccluders,
+ Polygon3r **oaPolygon, unsigned timestamp)
+{
+ OccludersSet occluders;
+ int qi = 0;
+
+ Vec3r center;
+ Vec3r edge;
+ Vec3r origin;
+
+ center = fe->center3d();
+ edge = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D());
+ origin = Vec3r(fe->vertexA()->point3D());
+ // Is the edge outside the view frustum ?
+ Vec3r gridOrigin(iGrid->getOrigin());
+ Vec3r gridExtremity(iGrid->getOrigin() + iGrid->gridSize());
+
+ if ((center.x() < gridOrigin.x()) || (center.y() < gridOrigin.y()) || (center.z() < gridOrigin.z()) ||
+ (center.x() > gridExtremity.x()) || (center.y() > gridExtremity.y()) || (center.z() > gridExtremity.z())) {
+ cerr << "Warning: point is out of the grid for fedge " << fe->getId() << endl;
+ //return 0;
+ }
+
+#if 0
+ Vec3r A(fe->vertexA()->point2d());
+ Vec3r B(fe->vertexB()->point2d());
+ int viewport[4];
+ SilhouetteGeomEngine::retrieveViewport(viewport);
+ if ((A.x() < viewport[0]) || (A.x() > viewport[2]) || (A.y() < viewport[1]) || (A.y() > viewport[3]) ||
+ (B.x() < viewport[0]) || (B.x() > viewport[2]) || (B.y() < viewport[1]) || (B.y() > viewport[3])) {
+ cerr << "Warning: point is out of the grid for fedge " << fe->getId() << endl;
+ //return 0;
+ }
+#endif
+
+ Vec3r vp;
+ if (_orthographicProjection) {
+ vp = Vec3r(center.x(), center.y(), _viewpoint.z());
+ }
+ else {
+ vp = Vec3r(_viewpoint);
+ }
+ Vec3r u(vp - center);
+ real raylength = u.norm();
+ u.normalize();
+#if 0
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "grid origin " << iGrid->getOrigin().x() << "," << iGrid->getOrigin().y() << ","
+ << iGrid->getOrigin().z() << endl;
+ cout << "center " << center.x() << "," << center.y() << "," << center.z() << endl;
+ }
+#endif
+
+ iGrid->castRay(center, vp, occluders, timestamp);
+
+ WFace *face = NULL;
+ if (fe->isSmooth()) {
+ FEdgeSmooth *fes = dynamic_cast<FEdgeSmooth*>(fe);
+ face = (WFace*)fes->face();
+ }
+ vector<WVertex*> faceVertices;
+ WVertex::incoming_edge_iterator ie;
+
+ WFace *oface;
+ bool skipFace;
+ OccludersSet::iterator p, pend;
+ if (face)
+ face->RetrieveVertexList(faceVertices);
+
+ for (p = occluders.begin(), pend = occluders.end(); p != pend; p++) {
+ // If we're dealing with an exact silhouette, check whether we must take care of this occluder of not.
+ // (Indeed, we don't consider the occluders that share at least one vertex with the face containing this edge).
+ //-----------
+ oface = (WFace*)(*p)->userdata;
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tEvaluating intersection for occluder " << ((*p)->getVertices())[0] << ((*p)->getVertices())[1]
+ << ((*p)->getVertices())[2] << endl << "\t\t\tand ray " << vp << " * " << u << " (center " << center
+ << ")" << endl;
+ }
+ #endif
+ Vec3r v1(((*p)->getVertices())[0]);
+ Vec3r normal((*p)->getNormal());
+ real d = -(v1 * normal);
+ real t, t_u, t_v;
+
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tp: " << ((*p)->getVertices())[0] << ((*p)->getVertices())[1] << ((*p)->getVertices())[2]
+ << ", norm: " << (*p)->getNormal() << endl;
+ }
+ #endif
+
+ if (face) {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tDetermining face adjacency...";
+ }
+ #endif
+ skipFace = false;
+
+ if (face == oface) {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << " Rejecting occluder for face concurrency." << endl;
+ }
+ #endif
+ continue;
+ }
+
+ for (vector<WVertex*>::iterator fv = faceVertices.begin(), fvend = faceVertices.end();
+ fv != fvend;
+ ++fv)
+ {
+ if ((*fv)->isBoundary())
+ continue;
+
+ WVertex::incoming_edge_iterator iebegin = (*fv)->incoming_edges_begin();
+ WVertex::incoming_edge_iterator ieend = (*fv)->incoming_edges_end();
+ for (ie = iebegin; ie != ieend; ++ie) {
+ if ((*ie) == 0)
+ continue;
+
+ WFace *sface = (*ie)->GetbFace();
+ //WFace *sfacea = (*ie)->GetaFace();
+ //if ((sface == oface) || (sfacea == oface)) {
+ if (sface == oface) {
+ skipFace = true;
+ break;
+ }
+ }
+ if (skipFace)
+ break;
+ }
+ if (skipFace) {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << " Rejecting occluder for face adjacency." << endl;
+ }
+ #endif
+ continue;
+ }
+ }
+ else {
+ // check whether the edge and the polygon plane are coincident:
+ //-------------------------------------------------------------
+ //first let us compute the plane equation.
+
+ if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, normal, d, t, epsilon)) {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tRejecting occluder for target coincidence." << endl;
+ }
+ #endif
+ continue;
+ }
+ }
+
+ if ((*p)->rayIntersect(center, u, t, t_u, t_v)) {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tRay " << vp << " * " << u << " intersects at time " << t << " (raylength is "
+ << raylength << ")" << endl;
+ cout << "\t\t(u * normal) == " << (u * normal) << " for normal " << normal << endl;
+ }
+ #endif
+ if (fabs(u * normal) > 0.0001) {
+ if ((t>0.0) && (t<raylength)) {
+ #if LOGGING
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "\t\tIs occluder" << endl;
+ }
+ #endif
+ WFace *f = (WFace*)((*p)->userdata);
+ ViewShape *vshape = _ViewMap->viewShape(f->GetVertex(0)->shape()->GetId());
+ oOccluders.insert(vshape);
+ ++qi;
+ if (!_EnableQI)
+ break;
+ }
+ }
+ }
+ }
+
+ // Find occludee
+ FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, center, edge, origin, faceVertices);
+
+ return qi;
+}
+
+void ViewMapBuilder::ComputeIntersections(ViewMap *ioViewMap, intersection_algo iAlgo, real epsilon)
+{
+ switch (iAlgo) {
+ case sweep_line:
+ ComputeSweepLineIntersections(ioViewMap, epsilon);
+ break;
+ default:
+ break;
+ }
+ ViewMap::viewvertices_container& vvertices = ioViewMap->ViewVertices();
+ for (ViewMap::viewvertices_container::iterator vv = vvertices.begin(), vvend = vvertices.end();
+ vv != vvend;
+ ++vv)
+ {
+ if ((*vv)->getNature() == Nature::T_VERTEX) {
+ TVertex *tvertex = (TVertex*)(*vv);
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ cout << "TVertex " << tvertex->getId() << " has :" << endl;
+ cout << "FrontEdgeA: " << tvertex->frontEdgeA().first << endl;
+ cout << "FrontEdgeB: " << tvertex->frontEdgeB().first << endl;
+ cout << "BackEdgeA: " << tvertex->backEdgeA().first << endl;
+ cout << "BackEdgeB: " << tvertex->backEdgeB().first << endl << endl;
+ }
+ }
+ }
+}
+
+struct less_SVertex2D : public binary_function<SVertex*, SVertex*, bool>
+{
+ real epsilon;
+
+ less_SVertex2D(real eps) : binary_function<SVertex*, SVertex*, bool>()
+ {
+ epsilon = eps;
+ }
+
+ bool operator()(SVertex *x, SVertex *y)
+ {
+ Vec3r A = x->point2D();
+ Vec3r B = y->point2D();
+ for (unsigned int i = 0; i < 3; i++) {
+ if ((fabs(A[i] - B[i])) < epsilon)
+ continue;
+ if (A[i] < B[i])
+ return true;
+ if (A[i] > B[i])
+ return false;
+ }
+ return false;
+ }
+};
+
+typedef Segment<FEdge*, Vec3r> segment;
+typedef Intersection<segment> intersection;
+
+struct less_Intersection : public binary_function<intersection*, intersection*, bool>
+{
+ segment *edge;
+
+ less_Intersection(segment *iEdge) : binary_function<intersection*, intersection*, bool>()
+ {
+ edge = iEdge;
+ }
+
+ bool operator()(intersection *x, intersection *y)
+ {
+ real tx = x->getParameter(edge);
+ real ty = y->getParameter(edge);
+ if (tx > ty)
+ return true;
+ return false;
+ }
+};
+
+struct silhouette_binary_rule : public binary_rule<segment, segment>
+{
+ silhouette_binary_rule() : binary_rule<segment,segment>() {}
+
+ virtual bool operator()(segment& s1, segment& s2)
+ {
+ FEdge *f1 = s1.edge();
+ FEdge *f2 = s2.edge();
+
+ if ((!(((f1)->getNature() & Nature::SILHOUETTE) || ((f1)->getNature() & Nature::BORDER))) &&
+ (!(((f2)->getNature() & Nature::SILHOUETTE) || ((f2)->getNature() & Nature::BORDER))))
+ {
+ return false;
+ }
+
+ return true;
+ }
+};
+
+void ViewMapBuilder::ComputeSweepLineIntersections(ViewMap *ioViewMap, real epsilon)
+{
+ vector<SVertex*>& svertices = ioViewMap->SVertices();
+ bool progressBarDisplay = false;
+ unsigned sVerticesSize = svertices.size();
+ unsigned fEdgesSize = ioViewMap->FEdges().size();
+#if 0
+ if (_global.debug & G_DEBUG_FREESTYLE) {
+ ViewMap::fedges_container& fedges = ioViewMap->FEdges();
+ for (ViewMap::fedges_container::const_iterator f = fedges.begin(), end = fedges.end(); f != end; ++f) {
+ cout << (*f)->aMaterialIndex() << "-" << (*f)->bMaterialIndex() << endl;
+ }
+ }
+#endif
+ unsigned progressBarStep = 0;
+
+ if (_pProgressBar != NULL && fEdgesSize > gProgressBarMinSize) {
+ unsigned progressBarSteps = min(gProgressBarMaxSteps, sVerticesSize);
+ progressBarStep = sVerticesSize / progressBarSteps;
+ _pProgressBar->reset();
+ _pProgressBar->setLabelText("Computing Sweep Line Intersections");
+ _pProgressBar->setTotalSteps(progressBarSteps);
+ _pProgressBar->setProgress(0);
+ progressBarDisplay = true;
+ }
+
+ unsigned counter = progressBarStep;
+
+ sort(svertices.begin(), svertices.end(), less_SVertex2D(epsilon));
+
+ SweepLine<FEdge*, Vec3r> SL;
+
+ vector<FEdge*>& ioEdges = ioViewMap->FEdges();
+
+ vector<segment*> segments;
+
+ vector<FEdge*>::iterator fe, fend;
+
+ for (fe = ioEdges.begin(), fend = ioEdges.end(); fe != fend; fe++) {
+ segment *s = new segment((*fe), (*fe)->vertexA()->point2D(), (*fe)->vertexB()->point2D());
+ (*fe)->userdata = s;
+ segments.push_back(s);
+ }
+
+ vector<segment*> vsegments;
+ for (vector<SVertex*>::iterator sv = svertices.begin(), svend = svertices.end(); sv != svend; sv++) {
+ if (_pRenderMonitor && _pRenderMonitor->testBreak())
+ break;
+
+ const vector<FEdge*>& vedges = (*sv)->fedges();
+
+ for (vector<FEdge*>::const_iterator sve = vedges.begin(), sveend = vedges.end(); sve != sveend; sve++) {
+ vsegments.push_back((segment*)((*sve)->userdata));
+ }
+
+ Vec3r evt((*sv)->point2D());
+ silhouette_binary_rule sbr;
+ SL.process(evt, vsegments, sbr, epsilon);
+
+ if (progressBarDisplay) {
+ counter--;
+ if (counter <= 0) {
+ counter = progressBarStep;
+ _pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
+ }
+ }
+ vsegments.clear();
+ }
+
+ if (_pRenderMonitor && _pRenderMonitor->testBreak()) {
+ // delete segments
+ if (!segments.empty()) {
+ vector<segment*>::iterator s, send;
+ for (s = segments.begin(), send = segments.end(); s != send; s++) {
+ delete *s;
+ }
+ }
+ return;
+ }
+
+ // reset userdata:
+ for (fe = ioEdges.begin(), fend = ioEdges.end(); fe != fend; fe++)
+ (*fe)->userdata = NULL;
+
+ // list containing the new edges resulting from splitting operations.
+ vector<FEdge*> newEdges;
+
+ // retrieve the intersected edges:
+ vector<segment*>& iedges = SL.intersectedEdges();
+ // retrieve the intersections:
+ vector<intersection*>& intersections = SL.intersections();
+
+ int id = 0;
+ // create a view vertex for each intersection and linked this one with the intersection object
+ vector<intersection*>::iterator i, iend;
+ for (i = intersections.begin(), iend = intersections.end(); i != iend; i++) {
+ FEdge *fA = (*i)->EdgeA->edge();
+ FEdge *fB = (*i)->EdgeB->edge();
+
+ Vec3r A1 = fA->vertexA()->point3D();
+ Vec3r A2 = fA->vertexB()->point3D();
+ Vec3r B1 = fB->vertexA()->point3D();
+ Vec3r B2 = fB->vertexB()->point3D();
+
+ Vec3r a1 = fA->vertexA()->point2D();
+ Vec3r a2 = fA->vertexB()->point2D();
+ Vec3r b1 = fB->vertexA()->point2D();
+ Vec3r b2 = fB->vertexB()->point2D();
+
+ real ta = (*i)->tA;
+ real tb = (*i)->tB;
+
+ if ((ta < -epsilon) || (ta > 1+epsilon))
+ cerr << "Warning: 2D intersection out of range for edge " << fA->vertexA()->getId() << " - "
+ << fA->vertexB()->getId() << endl;
+
+ if ((tb < -epsilon) || (tb > 1+epsilon))
+ cerr << "Warning: 2D intersection out of range for edge " << fB->vertexA()->getId() << " - "
+ << fB->vertexB()->getId() << endl;
+
+ real Ta = SilhouetteGeomEngine::ImageToWorldParameter(fA, ta);
+ real Tb = SilhouetteGeomEngine::ImageToWorldParameter(fB, tb);
+
+ if ((Ta < -epsilon) || (Ta > 1 + epsilon))
+ cerr << "Warning: 3D intersection out of range for edge " << fA->vertexA()->getId() << " - "
+ << fA->vertexB()->getId() << endl;
+
+ if ((Tb < -epsilon) || (Tb > 1 + epsilon))
+ cerr << "Warning: 3D intersection out of range for edge " << fB->vertexA()->getId() << " - "
+ << fB->vertexB()->getId() << endl;
+
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ if ((Ta < -epsilon) || (Ta > 1 + epsilon) || (Tb < -epsilon) || (Tb > 1 + epsilon)) {
+ printf("ta %.12e\n", ta);
+ printf("tb %.12e\n", tb);
+ printf("a1 %e, %e -- b1 %e, %e\n", a1[0], a1[1], b1[0], b1[1]);
+ printf("a2 %e, %e -- b2 %e, %e\n", a2[0], a2[1], b2[0], b2[1]);
+ if ((Ta < -epsilon) || (Ta > 1 + epsilon))
+ printf("Ta %.12e\n", Ta);
+ if ((Tb < -epsilon) || (Tb > 1 + epsilon))
+ printf("Tb %.12e\n", Tb);
+ printf("A1 %e, %e, %e -- B1 %e, %e, %e\n", A1[0], A1[1], A1[2], B1[0], B1[1], B1[2]);
+ printf("A2 %e, %e, %e -- B2 %e, %e, %e\n", A2[0], A2[1], A2[2], B2[0], B2[1], B2[2]);
+ }
+ }
+#endif
+
+ TVertex *tvertex = ioViewMap->CreateTVertex(Vec3r(A1 + Ta * (A2 - A1)), Vec3r(a1 + ta * (a2 - a1)), fA,
+ Vec3r(B1 + Tb * (B2 - B1)), Vec3r(b1 + tb * (b2 - b1)), fB, id);
+
+ (*i)->userdata = tvertex;
+ ++id;
+ }
+
+ progressBarStep = 0;
+
+ if (progressBarDisplay) {
+ unsigned iEdgesSize = iedges.size();
+ unsigned progressBarSteps = min(gProgressBarMaxSteps, iEdgesSize);
+ progressBarStep = iEdgesSize / progressBarSteps;
+ _pProgressBar->reset();
+ _pProgressBar->setLabelText("Splitting intersected edges");
+ _pProgressBar->setTotalSteps(progressBarSteps);
+ _pProgressBar->setProgress(0);
+ }
+
+ counter = progressBarStep;
+
+ vector<TVertex*> edgeVVertices;
+ vector<ViewEdge*> newVEdges;
+ vector<segment*>::iterator s, send;
+ for (s = iedges.begin(), send = iedges.end(); s != send; s++) {
+ edgeVVertices.clear();
+ newEdges.clear();
+ newVEdges.clear();
+
+ FEdge *fedge = (*s)->edge();
+ ViewEdge *vEdge = fedge->viewedge();
+ ViewShape *shape = vEdge->viewShape();
+
+ vector<intersection*>& eIntersections = (*s)->intersections();
+ // we first need to sort these intersections from farther to closer to A
+ sort(eIntersections.begin(), eIntersections.end(), less_Intersection(*s));
+ for (i = eIntersections.begin(), iend = eIntersections.end(); i != iend; i++)
+ edgeVVertices.push_back((TVertex*)(*i)->userdata);
+
+ shape->SplitEdge(fedge, edgeVVertices, ioViewMap->FEdges(), ioViewMap->ViewEdges());
+
+ if (progressBarDisplay) {
+ counter--;
+ if (counter <= 0) {
+ counter = progressBarStep;
+ _pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
+ }
+ }
+ }
+
+ // reset userdata:
+ for (fe = ioEdges.begin(), fend = ioEdges.end(); fe != fend; fe++)
+ (*fe)->userdata = NULL;
+
+ // delete segments
+ if (!segments.empty()) {
+ for (s = segments.begin(), send = segments.end(); s != send; s++) {
+ delete *s;
+ }
+ }
+}
diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
new file mode 100644
index 00000000000..2d5d24a0ffe
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h
@@ -0,0 +1,257 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_VIEW_MAP_BUILDER_H__
+#define __FREESTYLE_VIEW_MAP_BUILDER_H__
+
+/** \file blender/freestyle/intern/view_map/ViewMapBuilder.h
+ * \ingroup freestyle
+ * \brief Class to build silhouette edges from a Winged-Edge structure
+ * \author Stephane Grabli
+ * \date 25/03/2002
+ */
+
+#include <vector>
+
+#include "GridDensityProvider.h"
+#include "Silhouette.h"
+#include "SilhouetteGeomEngine.h"
+#include "ViewEdgeXBuilder.h"
+#include "ViewMap.h"
+
+#include "../geometry/Geom.h"
+#include "../geometry/GeomUtils.h"
+#include "../geometry/Grid.h"
+#include "../geometry/SweepLine.h"
+
+#include "../scene_graph/NodeGroup.h"
+#include "../scene_graph/TriangleRep.h"
+
+#include "../system/FreestyleConfig.h"
+#include "../system/ProgressBar.h"
+#include "../system/RenderMonitor.h"
+#include "../system/TimeUtils.h"
+
+#include "../winged_edge/WEdge.h"
+#include "../winged_edge/WXEdge.h"
+
+using namespace Geometry;
+
+class LIB_VIEW_MAP_EXPORT ViewMapBuilder
+{
+private:
+ ViewMap *_ViewMap; // result
+ //SilhouetteGeomEngine _GeomEngine;
+ ProgressBar *_pProgressBar;
+ RenderMonitor *_pRenderMonitor;
+ Vec3r _viewpoint;
+ bool _orthographicProjection;
+ Grid *_Grid;
+ ViewEdgeXBuilder *_pViewEdgeBuilder;
+ bool _EnableQI;
+ double _epsilon;
+
+ // tmp values:
+ int _currentId;
+ int _currentFId;
+ int _currentSVertexId;
+
+public:
+ typedef enum {
+ sweep_line,
+ } intersection_algo;
+
+ typedef enum {
+ ray_casting,
+ ray_casting_fast,
+ ray_casting_very_fast,
+ ray_casting_culled_adaptive_traditional,
+ ray_casting_adaptive_traditional,
+ ray_casting_culled_adaptive_cumulative,
+ ray_casting_adaptive_cumulative,
+ } visibility_algo;
+
+ inline ViewMapBuilder()
+ {
+ _pProgressBar = NULL;
+ _pRenderMonitor = NULL;
+ _Grid = NULL;
+ _currentId = 1;
+ _currentFId = 0;
+ _currentSVertexId = 0;
+ _pViewEdgeBuilder = new ViewEdgeXBuilder;
+ _EnableQI = true;
+ }
+
+ inline ~ViewMapBuilder()
+ {
+ if (_pViewEdgeBuilder) {
+ delete _pViewEdgeBuilder;
+ _pViewEdgeBuilder = NULL;
+ }
+ }
+
+ /* Build Grid for ray casting */
+ /*! Build non-culled Grid in camera space for ray casting */
+ void BuildGrid(WingedEdge& we, const BBox<Vec3r>& bbox, unsigned int sceneNumFaces);
+
+ /*! Compute Shapes from a WingedEdge containing a list of WShapes */
+ void computeInitialViewEdges(WingedEdge&);
+
+ /*! Compute Cusps */
+ void computeCusps(ViewMap *ioViewMap);
+
+ /*! Detects cusps (for a single ViewEdge) among SVertices and builds a ViewVertex on top of each cusp SVertex
+ * We use a hysteresis approach to avoid noise.
+ */
+ void DetectCusps(ViewEdge *ioEdge);
+
+ /*! Sets the current viewpoint */
+ inline void setViewpoint(const Vec3r& ivp)
+ {
+ _viewpoint = ivp;
+ SilhouetteGeomEngine::setViewpoint(ivp);
+ }
+
+ /*! Sets the current transformation
+ * iModelViewMatrix
+ * The 4x4 model view matrix, in column major order (openGL like).
+ * iProjection matrix
+ * The 4x4 projection matrix, in column major order (openGL like).
+ * iViewport
+ * The viewport. 4 real array: origin.x, origin.y, width, length
+ */
+ inline void setTransform(const real iModelViewMatrix[4][4], const real iProjectionMatrix[4][4],
+ const int iViewport[4], real iFocalLength, real iAspect, real iFovy)
+ {
+ _orthographicProjection = (iProjectionMatrix[3][3] != 0.0);
+ SilhouetteGeomEngine::setTransform(iModelViewMatrix, iProjectionMatrix, iViewport, iFocalLength);
+ }
+
+ inline void setFrustum(real iZnear, real iZfar)
+ {
+ SilhouetteGeomEngine::setFrustum(iZnear, iZfar);
+ }
+
+ /*! Builds the scene view map returns the list the view map
+ * it is up to the caller to delete this ViewMap
+ * iWRoot
+ * The root group node containing the WEdge structured scene
+ */
+ ViewMap *BuildViewMap(WingedEdge& we, visibility_algo iAlgo, real epsilon, const BBox<Vec3r>& bbox,
+ unsigned int sceneNumFaces);
+
+ void CullViewEdges(ViewMap *ioViewMap, real viewProscenium[4], real occluderProscenium[4],
+ bool extensiveFEdgeSearch = true);
+
+ /*! computes the intersection between all 2D feature edges of the scene.
+ * ioViewMap
+ * The view map. It is modified by the method.
+ * The list of all features edges of the scene.
+ * Each time an intersection is found, the 2 intersecting edges are splitted (creating 2 new vertices)
+ * At the end, this list is updated with the adding of all new created edges (resulting from splitting).
+ * iAlgo
+ * The algo to use for computing the intersections
+ */
+ void ComputeIntersections(ViewMap *ioViewMap, intersection_algo iAlgo = sweep_line, real epsilon = 1.0e-06);
+
+ /*! Computes the 2D scene silhouette edges visibility
+ * iGrid
+ * For the Ray Casting algorithm.
+ */
+ void ComputeEdgesVisibility(ViewMap *ioViewMap, WingedEdge& we, const BBox<Vec3r>& bbox, unsigned int sceneNumFaces,
+ visibility_algo iAlgo = ray_casting, real epsilon = 1.0e-6);
+
+ void setGrid(Grid *iGrid)
+ {
+ _Grid = iGrid;
+ }
+
+ /*! accessors */
+
+ /*! Modifiers */
+ inline void setProgressBar(ProgressBar *iProgressBar)
+ {
+ _pProgressBar = iProgressBar;
+ }
+
+ inline void setRenderMonitor(RenderMonitor *iRenderMonitor)
+ {
+ _pRenderMonitor = iRenderMonitor;
+ }
+
+ inline void setEnableQI(bool iBool)
+ {
+ _EnableQI = iBool;
+ }
+
+protected:
+ /*! Computes intersections on all edges of the scene using a sweep line algorithm */
+ void ComputeSweepLineIntersections(ViewMap *ioViewMap, real epsilon = 1.0e-6);
+
+ /*! Computes the 2D scene silhouette edges visibility using a ray casting. On each edge, a ray is cast
+ * to check its quantitative invisibility. The list of occluders are each time stored in the tested edge.
+ * ioViewMap
+ * The view map.
+ * The 2D scene silhouette edges as FEdges.
+ * These edges have already been splitted at their intersections points.
+ * Thus, these edges do not intersect anymore.
+ * The visibility corresponding to each edge of ioScene is set is this edge.
+ */
+ void ComputeRayCastingVisibility(ViewMap *ioViewMap, real epsilon = 1.0e-6);
+ void ComputeFastRayCastingVisibility(ViewMap *ioViewMap, real epsilon = 1.0e-6);
+ void ComputeVeryFastRayCastingVisibility(ViewMap *ioViewMap, real epsilon = 1.0e-6);
+
+ void ComputeCumulativeVisibility(ViewMap *ioViewMap, WingedEdge& we, const BBox<Vec3r>& bbox, real epsilon,
+ bool cull, GridDensityProviderFactory& factory);
+ void ComputeDetailedVisibility(ViewMap *ioViewMap, WingedEdge& we, const BBox<Vec3r>& bbox, real epsilon,
+ bool cull, GridDensityProviderFactory& factory);
+
+ /*! Compute the visibility for the FEdge fe.
+ * The occluders are added to fe occluders list.
+ * fe
+ * The FEdge
+ * iGrid
+ * The grid used to compute the ray casting visibility
+ * epsilon
+ * The epsilon used for computation
+ * oShapeId
+ * fe is the border (in 2D) between 2 2D spaces.
+ * if fe is a silhouette, One of these 2D spaces is occupied by the shape to which fe belongs (on its left)
+ * and the other one is either occupied by another shape or empty or occupied by the same shape.
+ * We use this ray csating operation to determine which shape lies on fe's right.
+ * The result is the shape id stored in oShapeId
+ */
+ int ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real epsilon, set<ViewShape*>& oOccluders,
+ Polygon3r **oaPolygon, unsigned timestamp);
+ // FIXME
+ void FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp);
+ void FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp,
+ Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector<WVertex*>& faceVertices);
+};
+
+#endif // __FREESTYLE_VIEW_MAP_BUILDER_H__
diff --git a/source/blender/freestyle/intern/view_map/ViewMapIO.cpp b/source/blender/freestyle/intern/view_map/ViewMapIO.cpp
new file mode 100644
index 00000000000..0e0e02dcaee
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ViewMapIO.cpp
@@ -0,0 +1,1258 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/ViewMapIO.cpp
+ * \ingroup freestyle
+ * \brief Functions to manage I/O for the view map
+ * \author Emmanuel Turquin
+ * \date 09/01/2003
+ */
+
+#include "ViewMapIO.h"
+
+#ifdef IRIX
+# define WRITE(n) Internal::write<sizeof((n))>(out, (const char *)(&(n)))
+# define READ(n) Internal::read<sizeof((n))>(in, (char *)(&(n)))
+#else
+# define WRITE(n) out.write((const char *)(&(n)), sizeof((n)))
+# define READ(n) in.read((char *)(&(n)), sizeof((n)))
+#endif
+
+#define WRITE_IF_NON_NULL(ptr) \
+ if (ptr) { \
+ WRITE((ptr)->userdata); \
+ } \
+ else { \
+ WRITE(ZERO); \
+ } (void)0
+
+#define READ_IF_NON_NULL(ptr, array) \
+ READ(tmp); \
+ if (tmp) { \
+ (ptr) = (array)[tmp]; \
+ } \
+ else { \
+ (ptr) = NULL; \
+ } (void)0
+
+namespace ViewMapIO {
+
+namespace Internal {
+
+ViewMap* g_vm;
+
+//////////////////// 'load' Functions ////////////////////
+
+inline int load(istream& in, Vec3r& v)
+{
+ if (Options::getFlags() & Options::FLOAT_VECTORS) {
+ float tmp;
+ READ(tmp);
+ v[0] = tmp;
+ READ(tmp);
+ v[1] = tmp;
+ READ(tmp);
+ v[2] = tmp;
+ }
+ else {
+ Vec3r::value_type tmp;
+ READ(tmp);
+ v[0] = tmp;
+ READ(tmp);
+ v[1] = tmp;
+ READ(tmp);
+ v[2] = tmp;
+ }
+ return 0;
+}
+
+inline int load(istream& in, Polygon3r& p)
+{
+ unsigned tmp;
+
+ // Id
+ READ(tmp);
+ p.setId(tmp);
+
+ // vertices (List)
+ vector<Vec3r> tmp_vec;
+ Vec3r v;
+ READ(tmp);
+ for (unsigned int i = 0; i < tmp; i++) {
+ load(in, v);
+ tmp_vec.push_back(v);
+ }
+ p.setVertices(tmp_vec);
+
+ // min & max
+ // Already computed (in the SetVertices() method)
+
+ return 0;
+}
+
+inline int load(istream& in, FrsMaterial& m)
+{
+ float tmp_array[4];
+ int i;
+
+ // Diffuse
+ for (i = 0; i < 4; i++)
+ READ(tmp_array[i]);
+ m.setDiffuse(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]);
+
+ // Specular
+ for (i = 0; i < 4; i++)
+ READ(tmp_array[i]);
+ m.setSpecular(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]);
+
+ // Ambient
+ for (i = 0; i < 4; i++)
+ READ(tmp_array[i]);
+ m.setAmbient(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]);
+
+ // Emission
+ for (i = 0; i < 4; i++)
+ READ(tmp_array[i]);
+ m.setEmission(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]);
+
+ // Shininess
+ READ(tmp_array[0]);
+ m.setShininess(tmp_array[0]);
+
+ return 0;
+}
+
+static int load(istream& in, ViewShape *vs)
+{
+ if (!vs || !vs->sshape())
+ return 1;
+
+ // SShape
+
+ // -> Id
+ Id::id_type id1, id2;
+ READ(id1);
+ READ(id2);
+ vs->sshape()->setId(Id(id1, id2));
+
+ // -> Importance
+ float importance;
+ READ(importance);
+ vs->sshape()->setImportance(importance);
+
+ // -> BBox
+ // Not necessary (only used during view map computatiom)
+
+ unsigned i, size, tmp;
+
+ // -> Material
+ READ(size);
+ vector<FrsMaterial> frs_materials;
+ FrsMaterial m;
+ for (i = 0; i < size; ++i) {
+ load(in, m);
+ frs_materials.push_back(m);
+ }
+ vs->sshape()->setFrsMaterials(frs_materials);
+
+ // -> VerticesList (List)
+ READ(size);
+ for (i = 0; i < size; i++) {
+ SVertex *sv;
+ READ_IF_NON_NULL(sv, g_vm->SVertices());
+ vs->sshape()->AddNewVertex(sv);
+ }
+
+ // -> Chains (List)
+ READ(size);
+ for (i = 0; i < size; i++) {
+ FEdge *fe;
+ READ_IF_NON_NULL(fe, g_vm->FEdges());
+ vs->sshape()->AddChain(fe);
+ }
+
+ // -> EdgesList (List)
+ READ(size);
+ for (i = 0; i < size; i++) {
+ FEdge *fe;
+ READ_IF_NON_NULL(fe, g_vm->FEdges());
+ vs->sshape()->AddEdge(fe);
+ }
+
+ // ViewEdges (List)
+ READ(size);
+ for (i = 0; i < size; i++) {
+ ViewEdge *ve;
+ READ_IF_NON_NULL(ve, g_vm->ViewEdges());
+ vs->AddEdge(ve);
+ }
+
+ // ViewVertices (List)
+ READ(size);
+ for (i = 0; i < size; i++) {
+ ViewVertex *vv;
+ READ_IF_NON_NULL(vv, g_vm->ViewVertices());
+ vs->AddVertex(vv);
+ }
+
+ return 0;
+}
+
+
+static int load(istream& in, FEdge *fe)
+{
+ if (!fe)
+ return 1;
+
+ bool b;
+
+ FEdgeSmooth *fesmooth = NULL;
+ FEdgeSharp *fesharp = NULL;
+ if (fe->isSmooth()) {
+ fesmooth = dynamic_cast<FEdgeSmooth*>(fe);
+ }
+ else {
+ fesharp = dynamic_cast<FEdgeSharp*>(fe);
+ }
+
+ // Id
+ Id::id_type id1, id2;
+ READ(id1);
+ READ(id2);
+ fe->setId(Id(id1, id2));
+
+ // Nature
+ Nature::EdgeNature nature;
+ READ(nature);
+ fe->setNature(nature);
+
+#if 0 // hasVisibilityPoint
+ bool b;
+ READ(b);
+ fe->setHasVisibilityPoint(b);
+#endif
+
+ Vec3r v;
+ unsigned int matindex;
+
+#if 0
+ // VisibilityPointA
+ load(in, v);
+ fe->setVisibilityPointA(v);
+
+ // VisibilityPointB
+ load(in, v);
+ fe->setVisibilityPointB(v);
+#endif
+
+ if (fe->isSmooth()) {
+ // Normal
+ load(in, v);
+ fesmooth->setNormal(v);
+
+ // Material
+ READ(matindex);
+ fesmooth->setFrsMaterialIndex(matindex);
+ }
+ else {
+ // aNormal
+ load(in, v);
+ fesharp->setNormalA(v);
+
+ // bNormal
+ load(in, v);
+ fesharp->setNormalB(v);
+
+ // Materials
+ READ(matindex);
+ fesharp->setaFrsMaterialIndex(matindex);
+ READ(matindex);
+ fesharp->setbFrsMaterialIndex(matindex);
+ }
+
+ unsigned tmp;
+
+ // VertexA
+ SVertex *sva;
+ READ_IF_NON_NULL(sva, g_vm->SVertices());
+ fe->setVertexA(sva);
+
+ // VertexB
+ SVertex *svb;
+ READ_IF_NON_NULL(svb, g_vm->SVertices());
+ fe->setVertexB(svb);
+
+ // NextEdge
+ FEdge *nfe;
+ READ_IF_NON_NULL(nfe, g_vm->FEdges());
+ fe->setNextEdge(nfe);
+
+ // PreviousEdge
+ FEdge *pfe;
+ READ_IF_NON_NULL(pfe, g_vm->FEdges());
+ fe->setPreviousEdge(pfe);
+
+ // ViewEdge
+ ViewEdge *ve;
+ READ_IF_NON_NULL(ve, g_vm->ViewEdges());
+ fe->setViewEdge(ve);
+
+ // Face
+ // Not necessary (only used during view map computatiom)
+
+ Polygon3r p;
+
+ // aFace
+ load(in, p);
+ fe->setaFace(p);
+
+ // occludeeEmpty
+ READ(b);
+ fe->setOccludeeEmpty(b);
+
+ // occludeeIntersection
+ load(in, v);
+ fe->setOccludeeIntersection(v);
+
+ return 0;
+}
+
+static int load(istream& in, SVertex *sv)
+{
+ if (!sv)
+ return 1;
+
+ // Id
+ Id::id_type id1, id2;
+ READ(id1);
+ READ(id2);
+ sv->setId(Id(id1, id2));
+
+ Vec3r v;
+
+ // Point3D
+ load(in, v);
+ sv->setPoint3D(v);
+
+ // Point2D
+ load(in, v);
+ sv->setPoint2D(v);
+
+ unsigned tmp;
+
+ // Shape
+ ViewShape *vs;
+ READ_IF_NON_NULL(vs, g_vm->ViewShapes());
+ sv->setShape(vs->sshape());
+
+ // pViewVertex
+ ViewVertex *vv;
+ READ_IF_NON_NULL(vv, g_vm->ViewVertices());
+ sv->setViewVertex(vv);
+
+ unsigned i, size;
+
+ // Normals (List)
+ READ(size);
+ for (i = 0; i < size; i++) {
+ load(in, v);
+ sv->AddNormal(v);
+ }
+
+ // FEdges (List)
+ READ(size);
+ FEdge *fe;
+ for (i = 0; i < size; i++) {
+ READ_IF_NON_NULL(fe, g_vm->FEdges());
+ sv->AddFEdge(fe);
+ }
+
+ return 0;
+}
+
+
+static int load(istream& in, ViewEdge *ve)
+{
+ if (!ve)
+ return 1;
+
+ unsigned tmp;
+
+ // Id
+ Id::id_type id1, id2;
+ READ(id1);
+ READ(id2);
+ ve->setId(Id(id1, id2));
+
+ // Nature
+ Nature::EdgeNature nature;
+ READ(nature);
+ ve->setNature(nature);
+
+ // QI
+ READ(tmp);
+ ve->setQI(tmp);
+
+ // Shape
+ ViewShape *vs;
+ READ_IF_NON_NULL(vs, g_vm->ViewShapes());
+ ve->setShape(vs);
+
+ // aShape
+ ViewShape *avs;
+ READ_IF_NON_NULL(avs, g_vm->ViewShapes());
+ ve->setaShape(avs);
+
+ // FEdgeA
+ FEdge *fea;
+ READ_IF_NON_NULL(fea, g_vm->FEdges());
+ ve->setFEdgeA(fea);
+
+ // FEdgeB
+ FEdge *feb;
+ READ_IF_NON_NULL(feb, g_vm->FEdges());
+ ve->setFEdgeB(feb);
+
+ // A
+ ViewVertex *vva;
+ READ_IF_NON_NULL(vva, g_vm->ViewVertices());
+ ve->setA(vva);
+
+ // B
+ ViewVertex *vvb;
+ READ_IF_NON_NULL(vvb, g_vm->ViewVertices());
+ ve->setB(vvb);
+
+ // Occluders (List)
+ if (!(Options::getFlags() & Options::NO_OCCLUDERS)) {
+ unsigned size;
+ READ(size);
+ ViewShape *vso;
+ for (unsigned int i = 0; i < size; i++) {
+ READ_IF_NON_NULL(vso, g_vm->ViewShapes());
+ ve->AddOccluder(vso);
+ }
+ }
+
+ return 0;
+}
+
+
+static int load(istream& in, ViewVertex *vv)
+{
+ if (!vv)
+ return 1;
+
+ unsigned tmp;
+ bool b;
+
+ // Nature
+ Nature::VertexNature nature;
+ READ(nature);
+ vv->setNature(nature);
+
+ if (vv->getNature() & Nature::T_VERTEX) {
+ TVertex *tv = dynamic_cast<TVertex*>(vv);
+
+ // Id
+ Id::id_type id1, id2;
+ READ(id1);
+ READ(id2);
+ tv->setId(Id(id1, id2));
+
+ // FrontSVertex
+ SVertex *fsv;
+ READ_IF_NON_NULL(fsv, g_vm->SVertices());
+ tv->setFrontSVertex(fsv);
+
+ // BackSVertex
+ SVertex *bsv;
+ READ_IF_NON_NULL(bsv, g_vm->SVertices());
+ tv->setBackSVertex(bsv);
+
+ // FrontEdgeA
+ ViewEdge *fea;
+ READ_IF_NON_NULL(fea, g_vm->ViewEdges());
+ READ(b);
+ tv->setFrontEdgeA(fea, b);
+
+ // FrontEdgeB
+ ViewEdge *feb;
+ READ_IF_NON_NULL(feb, g_vm->ViewEdges());
+ READ(b);
+ tv->setFrontEdgeB(feb, b);
+
+ // BackEdgeA
+ ViewEdge *bea;
+ READ_IF_NON_NULL(bea, g_vm->ViewEdges());
+ READ(b);
+ tv->setBackEdgeA(bea, b);
+
+ // BackEdgeB
+ ViewEdge *beb;
+ READ_IF_NON_NULL(beb, g_vm->ViewEdges());
+ READ(b);
+ tv->setBackEdgeB(beb, b);
+ }
+ else if (vv->getNature() & Nature::NON_T_VERTEX) {
+ NonTVertex *ntv = dynamic_cast<NonTVertex*>(vv);
+
+ // SVertex
+ SVertex *sv;
+ READ_IF_NON_NULL(sv, g_vm->SVertices());
+ ntv->setSVertex(sv);
+
+ // ViewEdges (List)
+ unsigned size;
+ READ(size);
+ ViewEdge *ve;
+ for (unsigned int i = 0; i < size; i++) {
+ READ_IF_NON_NULL(ve, g_vm->ViewEdges());
+ READ(b);
+ ntv->AddViewEdge(ve, b);
+ }
+ }
+
+ return 0;
+}
+
+//////////////////// 'save' Functions ////////////////////
+
+inline int save(ostream& out, const Vec3r& v)
+{
+ if (Options::getFlags() & Options::FLOAT_VECTORS) {
+ float tmp;
+
+ tmp = v[0];
+ WRITE(tmp);
+ tmp = v[1];
+ WRITE(tmp);
+ tmp = v[2];
+ WRITE(tmp);
+ }
+ else {
+ Vec3r::value_type tmp;
+
+ tmp = v[0];
+ WRITE(tmp);
+ tmp = v[1];
+ WRITE(tmp);
+ tmp = v[2];
+ WRITE(tmp);
+ }
+ return 0;
+}
+
+
+inline int save(ostream& out, const Polygon3r& p)
+{
+ unsigned tmp;
+
+ // Id
+ tmp = p.getId();
+ WRITE(tmp);
+
+ // vertices (List)
+ tmp = p.getVertices().size();
+ WRITE(tmp);
+ for (vector<Vec3r>::const_iterator i = p.getVertices().begin(); i != p.getVertices().end(); i++) {
+ save(out, *i);
+ }
+
+ // min & max
+ // Do not need to be saved
+
+ return 0;
+}
+
+inline int save(ostream& out, const FrsMaterial& m)
+{
+ unsigned i;
+
+ // Diffuse
+ for (i = 0; i < 4; i++)
+ WRITE(m.diffuse()[i]);
+
+ // Specular
+ for (i = 0; i < 4; i++)
+ WRITE(m.specular()[i]);
+
+ // Ambient
+ for (i = 0; i < 4; i++)
+ WRITE(m.ambient()[i]);
+
+ // Emission
+ for (i = 0; i < 4; i++)
+ WRITE(m.emission()[i]);
+
+ // Shininess
+ float shininess = m.shininess();
+ WRITE(shininess);
+
+ return 0;
+}
+
+static int save(ostream& out, ViewShape *vs)
+{
+ if (!vs || !vs->sshape()) {
+ cerr << "Warning: null ViewShape" << endl;
+ return 1;
+ }
+
+ unsigned tmp;
+
+ // SShape
+
+ // -> Id
+ Id::id_type id = vs->sshape()->getId().getFirst();
+ WRITE(id);
+ id = vs->sshape()->getId().getSecond();
+ WRITE(id);
+
+ // -> Importance
+ float importance = vs->sshape()->importance();
+ WRITE(importance);
+
+ // -> BBox
+ // Not necessary (only used during view map computatiom)
+
+ // -> Material
+ unsigned int size = vs->sshape()->frs_materials().size();
+ WRITE(size);
+ for (unsigned int i = 0; i < size; ++i)
+ save(out, vs->sshape()->frs_material(i));
+
+ // -> VerticesList (List)
+ tmp = vs->sshape()->getVertexList().size();
+ WRITE(tmp);
+ for (vector<SVertex*>::const_iterator i1 = vs->sshape()->getVertexList().begin();
+ i1 != vs->sshape()->getVertexList().end();
+ i1++)
+ {
+ WRITE_IF_NON_NULL(*i1);
+ }
+
+ // -> Chains (List)
+ tmp = vs->sshape()->getChains().size();
+ WRITE(tmp);
+ for (vector<FEdge*>::const_iterator i2 = vs->sshape()->getChains().begin();
+ i2 != vs->sshape()->getChains().end();
+ i2++)
+ {
+ WRITE_IF_NON_NULL(*i2);
+ }
+
+ // -> EdgesList (List)
+ tmp = vs->sshape()->getEdgeList().size();
+ WRITE(tmp);
+ for (vector<FEdge*>::const_iterator i3 = vs->sshape()->getEdgeList().begin();
+ i3 != vs->sshape()->getEdgeList().end();
+ i3++)
+ {
+ WRITE_IF_NON_NULL(*i3);
+ }
+
+ // ViewEdges (List)
+ tmp = vs->edges().size();
+ WRITE(tmp);
+ for (vector<ViewEdge*>::const_iterator i4 = vs->edges().begin(); i4 != vs->edges().end(); i4++)
+ WRITE_IF_NON_NULL(*i4);
+
+ // ViewVertices (List)
+ tmp = vs->vertices().size();
+ WRITE(tmp);
+ for (vector<ViewVertex*>::const_iterator i5 = vs->vertices().begin(); i5 != vs->vertices().end(); i5++)
+ WRITE_IF_NON_NULL(*i5);
+
+ return 0;
+}
+
+
+static int save(ostream& out, FEdge *fe)
+{
+ if (!fe) {
+ cerr << "Warning: null FEdge" << endl;
+ return 1;
+ }
+
+ FEdgeSmooth *fesmooth = dynamic_cast<FEdgeSmooth*>(fe);
+ FEdgeSharp *fesharp = dynamic_cast<FEdgeSharp*>(fe);
+
+ // Id
+ Id::id_type id = fe->getId().getFirst();
+ WRITE(id);
+ id = fe->getId().getSecond();
+ WRITE(id);
+
+ // Nature
+ Nature::EdgeNature nature = fe->getNature();
+ WRITE(nature);
+
+ bool b;
+
+#if 0
+ // hasVisibilityPoint
+ b = fe->hasVisibilityPoint();
+ WRITE(b);
+
+ // VisibilityPointA
+ save(out, fe->visibilityPointA());
+
+ // VisibilityPointB
+ save(out, fe->visibilityPointB());
+#endif
+
+ unsigned index;
+ if (fe->isSmooth()) {
+ // normal
+ save(out, fesmooth->normal());
+ // material
+ index = fesmooth->frs_materialIndex();
+ WRITE(index);
+ }
+ else {
+ // aNormal
+ save(out, fesharp->normalA());
+ // bNormal
+ save(out, fesharp->normalB());
+ // aMaterial
+ index = fesharp->aFrsMaterialIndex();
+ WRITE(index);
+ // bMaterial
+ index = fesharp->bFrsMaterialIndex();
+ WRITE(index);
+ }
+
+ // VertexA
+ WRITE_IF_NON_NULL(fe->vertexA());
+
+ // VertexB
+ WRITE_IF_NON_NULL(fe->vertexB());
+
+ // NextEdge
+ WRITE_IF_NON_NULL(fe->nextEdge());
+
+ // PreviousEdge
+ WRITE_IF_NON_NULL(fe->previousEdge());
+
+ // ViewEdge
+ WRITE_IF_NON_NULL(fe->viewedge());
+
+ // Face
+ // Not necessary (only used during view map computatiom)
+
+ // aFace
+ save(out, (Polygon3r&)fe->aFace());
+
+ // occludeeEmpty
+ b = fe->getOccludeeEmpty();
+ WRITE(b);
+
+ // occludeeIntersection
+ save(out, fe->getOccludeeIntersection());
+
+ return 0;
+}
+
+static int save(ostream& out, SVertex *sv)
+{
+ if (!sv) {
+ cerr << "Warning: null SVertex" << endl;
+ return 1;
+ }
+
+ unsigned tmp;
+
+ // Id
+ Id::id_type id = sv->getId().getFirst();
+ WRITE(id);
+ id = sv->getId().getSecond();
+ WRITE(id);
+
+ Vec3r v;
+
+ // Point3D
+ v = sv->point3D();
+ save(out, sv->point3D());
+
+ // Point2D
+ v = sv->point2D();
+ save(out, v);
+
+ // Shape
+ WRITE_IF_NON_NULL(sv->shape());
+
+ // pViewVertex
+ WRITE_IF_NON_NULL(sv->viewvertex());
+
+ // Normals (List)
+ // Note: the 'size()' method of a set doesn't seem to return the actual size of the given set, so we have to
+ // hack it...
+ set<Vec3r>::const_iterator i;
+ for (i = sv->normals().begin(), tmp = 0; i != sv->normals().end(); i++, tmp++);
+ WRITE(tmp);
+ for (i = sv->normals().begin(); i != sv->normals().end(); i++)
+ save(out, *i);
+
+ // FEdges (List)
+ tmp = sv->fedges().size();
+ WRITE(tmp);
+ for (vector<FEdge*>::const_iterator j = sv->fedges_begin(); j != sv->fedges_end(); j++)
+ WRITE_IF_NON_NULL(*j);
+
+ return 0;
+}
+
+
+static int save(ostream& out, ViewEdge *ve)
+{
+ if (!ve) {
+ cerr << "Warning: null ViewEdge" << endl;
+ return 1;
+ }
+
+ unsigned tmp;
+
+ // Id
+ Id::id_type id = ve->getId().getFirst();
+ WRITE(id);
+ id = ve->getId().getSecond();
+ WRITE(id);
+
+ // Nature
+ Nature::EdgeNature nature = ve->getNature();
+ WRITE(nature);
+
+ // QI
+ unsigned qi = ve->qi();
+ WRITE(qi);
+
+ // Shape
+ WRITE_IF_NON_NULL(ve->shape());
+
+ // aShape
+ WRITE_IF_NON_NULL(ve->aShape());
+
+ // FEdgeA
+ WRITE_IF_NON_NULL(ve->fedgeA());
+
+ // FEdgeB
+ WRITE_IF_NON_NULL(ve->fedgeB());
+
+ // A
+ WRITE_IF_NON_NULL(ve->A());
+
+ // B
+ WRITE_IF_NON_NULL(ve->B());
+
+ // Occluders (List)
+ if (!(Options::getFlags() & Options::NO_OCCLUDERS)) {
+ tmp = ve->occluders().size();
+ WRITE(tmp);
+ for (vector<ViewShape*>::const_iterator i = ve->occluders().begin(); i != ve->occluders().end(); i++)
+ WRITE_IF_NON_NULL((*i));
+ }
+
+ return 0;
+}
+
+
+static int save(ostream& out, ViewVertex *vv)
+{
+ if (!vv) {
+ cerr << "Warning: null ViewVertex" << endl;
+ return 1;
+ }
+
+ // Nature
+ Nature::VertexNature nature = vv->getNature();
+ WRITE(nature);
+
+ if (vv->getNature() & Nature::T_VERTEX) {
+ TVertex *tv = dynamic_cast<TVertex*>(vv);
+
+ // Id
+ Id::id_type id = tv->getId().getFirst();
+ WRITE(id);
+ id = tv->getId().getSecond();
+ WRITE(id);
+
+ // FrontSVertex
+ WRITE_IF_NON_NULL(tv->frontSVertex());
+
+ // BackSVertex
+ WRITE_IF_NON_NULL(tv->backSVertex());
+
+ // FrontEdgeA
+ WRITE_IF_NON_NULL(tv->frontEdgeA().first);
+ WRITE(tv->frontEdgeA().second);
+
+ // FrontEdgeB
+ WRITE_IF_NON_NULL(tv->frontEdgeB().first);
+ WRITE(tv->frontEdgeB().second);
+
+ // BackEdgeA
+ WRITE_IF_NON_NULL(tv->backEdgeA().first);
+ WRITE(tv->backEdgeA().second);
+
+ // BackEdgeB
+ WRITE_IF_NON_NULL(tv->backEdgeB().first);
+ WRITE(tv->backEdgeB().second);
+ }
+ else if (vv->getNature() & Nature::NON_T_VERTEX) {
+ NonTVertex *ntv = dynamic_cast<NonTVertex*>(vv);
+
+ // SVertex
+ WRITE_IF_NON_NULL(ntv->svertex());
+
+ // ViewEdges (List)
+ unsigned size = ntv->viewedges().size();
+ WRITE(size);
+ vector<ViewVertex::directedViewEdge>::const_iterator i = ntv->viewedges().begin();
+ for (; i != ntv->viewedges().end(); i++) {
+ WRITE_IF_NON_NULL(i->first);
+ WRITE(i->second);
+ }
+ }
+ else {
+ cerr << "Warning: unexpected ViewVertex nature" << endl;
+ return 1;
+ }
+
+ return 0;
+}
+
+} // End of namespace Internal
+
+
+//////////////////// "Public" 'load' and 'save' functions ////////////////////
+
+#define SET_PROGRESS(n) \
+ if (pb) { \
+ pb->setProgress((n)); \
+ } (void)0
+
+int load(istream& in, ViewMap *vm, ProgressBar *pb)
+{
+ if (!vm)
+ return 1;
+
+ //soc unused - unsigned tmp;
+ int err = 0;
+ Internal::g_vm = vm;
+
+ // Management of the progress bar (if present)
+ if (pb) {
+ pb->reset();
+ pb->setLabelText("Loading View Map...");
+ pb->setTotalSteps(6);
+ pb->setProgress(0);
+ }
+
+ // Read and set the options
+ unsigned char flags;
+ READ(flags);
+ Options::setFlags(flags);
+
+ // Read the size of the five ViewMap's lists (with some extra informations for the ViewVertices)
+ // and instantiate them (with default costructors)
+ unsigned vs_s, fe_s, fe_rle1, fe_rle2, sv_s, ve_s, vv_s, vv_rle1, vv_rle2;
+ READ(vs_s);
+ READ(fe_s);
+
+ if (fe_s) {
+ bool b;
+ READ(b);
+ for (READ(fe_rle1), fe_rle2 = 0; fe_rle1 < fe_s + 1; fe_rle2 = fe_rle1, READ(fe_rle1)) {
+ if (b) {
+ for (unsigned int i = fe_rle2; i < fe_rle1; i++) {
+ FEdgeSmooth *fes = new FEdgeSmooth;
+ vm->AddFEdge(fes);
+ }
+ b = !b;
+ }
+ else if (!b) {
+ for (unsigned int i = fe_rle2; i < fe_rle1; i++) {
+ FEdgeSharp *fes = new FEdgeSharp;
+ vm->AddFEdge(fes);
+ }
+ b = !b;
+ }
+ }
+ }
+
+ READ(sv_s);
+ READ(ve_s);
+ READ(vv_s);
+
+ if (vv_s) {
+ Nature::VertexNature nature;
+ READ(nature);
+ for (READ(vv_rle1), vv_rle2 = 0; vv_rle1 < vv_s + 1; vv_rle2 = vv_rle1, READ(vv_rle1)) {
+ if (nature & Nature::T_VERTEX) {
+ for (unsigned int i = vv_rle2; i < vv_rle1; i++) {
+ TVertex *tv = new TVertex();
+ vm->AddViewVertex(tv);
+ }
+ nature = Nature::NON_T_VERTEX;
+ }
+ else if (nature & Nature::NON_T_VERTEX) {
+ for (unsigned int i = vv_rle2; i < vv_rle1; i++) {
+ NonTVertex *ntv = new NonTVertex();
+ vm->AddViewVertex(ntv);
+ }
+ nature = Nature::T_VERTEX;
+ }
+ }
+ }
+
+ for (unsigned int i0 = 0; i0 < vs_s; i0++) {
+ SShape *ss = new SShape();
+ ViewShape *vs = new ViewShape();
+ vs->setSShape(ss);
+ ss->setViewShape(vs);
+ vm->AddViewShape(vs);
+ }
+#if 0
+ for (unsigned int i1 = 0; i1 < fe_s; i1++) {
+ FEdge *fe = new FEdge();
+ vm->AddFEdge(fe);
+ }
+#endif
+ for (unsigned int i2 = 0; i2 < sv_s; i2++) {
+ SVertex *sv = new SVertex();
+ vm->AddSVertex(sv);
+ }
+ for (unsigned int i3 = 0; i3 < ve_s; i3++) {
+ ViewEdge *ve = new ViewEdge();
+ vm->AddViewEdge(ve);
+ }
+
+ // Read the values for all the objects created above
+ SET_PROGRESS(1);
+ for (vector<ViewShape*>::const_iterator i4 = vm->ViewShapes().begin(); i4 != vm->ViewShapes().end(); i4++)
+ err += Internal::load(in, *i4);
+ SET_PROGRESS(2);
+ for (vector<FEdge*>::const_iterator i5 = vm->FEdges().begin(); i5 != vm->FEdges().end(); i5++)
+ err += Internal::load(in, *i5);
+ SET_PROGRESS(3);
+ for (vector<SVertex*>::const_iterator i6 = vm->SVertices().begin(); i6 != vm->SVertices().end(); i6++)
+ err += Internal::load(in, *i6);
+ SET_PROGRESS(4);
+ for (vector<ViewEdge*>::const_iterator i7 = vm->ViewEdges().begin(); i7 != vm->ViewEdges().end(); i7++)
+ err += Internal::load(in, *i7);
+ SET_PROGRESS(5);
+ for (vector<ViewVertex*>::const_iterator i8 = vm->ViewVertices().begin(); i8 != vm->ViewVertices().end(); i8++)
+ err += Internal::load(in, *i8);
+ SET_PROGRESS(6);
+
+ // Read the shape id to index mapping
+ unsigned map_s;
+ READ(map_s);
+ unsigned id,index;
+ for (unsigned int i4 = 0; i4 < map_s; ++i4) {
+ READ(id);
+ READ(index);
+ vm->shapeIdToIndexMap()[id] = index;
+ }
+
+ return err;
+}
+
+
+int save(ostream& out, ViewMap *vm, ProgressBar *pb)
+{
+ if (!vm)
+ return 1;
+
+ int err = 0;
+
+ // Management of the progress bar (if present)
+ if (pb) {
+ pb->reset();
+ pb->setLabelText("Saving View Map...");
+ pb->setTotalSteps(6);
+ pb->setProgress(0);
+ }
+
+ // For every object, initialize its userdata member to its index in the ViewMap list
+ for (unsigned int i0 = 0; i0 < vm->ViewShapes().size(); i0++) {
+ vm->ViewShapes()[i0]->userdata = SET_UINT_IN_POINTER(i0);
+ vm->ViewShapes()[i0]->sshape()->userdata = SET_UINT_IN_POINTER(i0);
+ }
+ for (unsigned int i1 = 0; i1 < vm->FEdges().size(); i1++)
+ vm->FEdges()[i1]->userdata = SET_UINT_IN_POINTER(i1);
+ for (unsigned int i2 = 0; i2 < vm->SVertices().size(); i2++)
+ vm->SVertices()[i2]->userdata = SET_UINT_IN_POINTER(i2);
+ for (unsigned int i3 = 0; i3 < vm->ViewEdges().size(); i3++)
+ vm->ViewEdges()[i3]->userdata = SET_UINT_IN_POINTER(i3);
+ for (unsigned int i4 = 0; i4 < vm->ViewVertices().size(); i4++)
+ vm->ViewVertices()[i4]->userdata = SET_UINT_IN_POINTER(i4);
+
+ // Write the current options
+ unsigned char flags = Options::getFlags();
+ WRITE(flags);
+
+ // Write the size of the five lists (with some extra informations for the ViewVertices)
+ unsigned size;
+ size = vm->ViewShapes().size();
+ WRITE(size);
+ size = vm->FEdges().size();
+ WRITE(size);
+ if (size) {
+ bool b = vm->FEdges()[0]->isSmooth();
+ WRITE(b);
+ for (unsigned int i = 0; i < size; i++) {
+ while (i < size && (vm->FEdges()[i]->isSmooth() == b))
+ i++;
+ if (i < size) {
+ WRITE(i);
+ b = !b;
+ }
+ }
+ WRITE(size);
+ size++;
+ WRITE(size);
+ }
+ size = vm->SVertices().size();
+ WRITE(size);
+ size = vm->ViewEdges().size();
+ WRITE(size);
+ size = vm->ViewVertices().size();
+ WRITE(size);
+ if (size) {
+ Nature::VertexNature nature = vm->ViewVertices()[0]->getNature();
+ WRITE(nature);
+ nature &= ~Nature::VIEW_VERTEX;
+ for (unsigned int i = 0; i < size; i++) {
+ while (i < size && (vm->ViewVertices()[i]->getNature() & nature))
+ i++;
+ if (i < size) {
+ WRITE(i);
+ nature = vm->ViewVertices()[i]->getNature() & ~Nature::VIEW_VERTEX;
+ }
+ }
+ WRITE(size);
+ size++;
+ WRITE(size);
+ }
+
+ // Write all the elts of the ViewShapes List
+ SET_PROGRESS(1);
+ for (vector<ViewShape*>::const_iterator i5 = vm->ViewShapes().begin(); i5 != vm->ViewShapes().end(); i5++)
+ err += Internal::save(out, *i5);
+ SET_PROGRESS(2);
+ for (vector<FEdge*>::const_iterator i6 = vm->FEdges().begin(); i6 != vm->FEdges().end(); i6++)
+ err += Internal::save(out, *i6);
+ SET_PROGRESS(3);
+ for (vector<SVertex*>::const_iterator i7 = vm->SVertices().begin(); i7 != vm->SVertices().end(); i7++)
+ err += Internal::save(out, *i7);
+ SET_PROGRESS(4);
+ for (vector<ViewEdge*>::const_iterator i8 = vm->ViewEdges().begin(); i8 != vm->ViewEdges().end(); i8++)
+ err += Internal::save(out, *i8);
+ SET_PROGRESS(5);
+ for (vector<ViewVertex*>::const_iterator i9 = vm->ViewVertices().begin(); i9 != vm->ViewVertices().end(); i9++)
+ err += Internal::save(out, *i9);
+
+ // Write the shape id to index mapping
+ size = vm->shapeIdToIndexMap().size();
+ WRITE(size);
+ unsigned int id, index;
+ for (ViewMap::id_to_index_map::iterator mit = vm->shapeIdToIndexMap().begin(),
+ mitend = vm->shapeIdToIndexMap().end();
+ mit != mitend;
+ ++mit)
+ {
+ id = mit->first;
+ index = mit->second;
+ WRITE(id);
+ WRITE(index);
+ }
+
+ // Reset 'userdata' members
+ for (vector<ViewShape*>::const_iterator j0 = vm->ViewShapes().begin(); j0 != vm->ViewShapes().end(); j0++) {
+ (*j0)->userdata = NULL;
+ (*j0)->sshape()->userdata = NULL;
+ }
+ for (vector<FEdge*>::const_iterator j1 = vm->FEdges().begin(); j1 != vm->FEdges().end(); j1++)
+ (*j1)->userdata = NULL;
+ for (vector<SVertex*>::const_iterator j2 = vm->SVertices().begin(); j2 != vm->SVertices().end(); j2++)
+ (*j2)->userdata = NULL;
+ for (vector<ViewEdge*>::const_iterator j3 = vm->ViewEdges().begin(); j3 != vm->ViewEdges().end(); j3++)
+ (*j3)->userdata = NULL;
+ for (vector<ViewVertex*>::const_iterator j4 = vm->ViewVertices().begin(); j4 != vm->ViewVertices().end(); j4++)
+ (*j4)->userdata = NULL;
+ SET_PROGRESS(6);
+
+ return err;
+}
+
+
+//////////////////// Options ////////////////////
+
+namespace Options {
+
+namespace Internal {
+
+static unsigned char g_flags = 0;
+static string g_models_path;
+
+} // End of namespace Internal
+
+void setFlags(const unsigned char flags)
+{
+ Internal::g_flags = flags;
+}
+
+void addFlags(const unsigned char flags)
+{
+ Internal::g_flags |= flags;
+}
+
+void rmFlags(const unsigned char flags)
+{
+ Internal::g_flags &= ~flags;
+}
+
+unsigned char getFlags()
+{
+ return Internal::g_flags;
+}
+
+void setModelsPath(const string& path)
+{
+ Internal::g_models_path = path;
+}
+
+string getModelsPath()
+{
+ return Internal::g_models_path;
+}
+
+} // End of namepace Options
+
+} // End of namespace ViewMapIO
diff --git a/source/blender/freestyle/intern/view_map/ViewMapIO.h b/source/blender/freestyle/intern/view_map/ViewMapIO.h
new file mode 100644
index 00000000000..44521f03317
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ViewMapIO.h
@@ -0,0 +1,129 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_VIEW_MAP_IO_H__
+#define __FREESTYLE_VIEW_MAP_IO_H__
+
+/** \file blender/freestyle/intern/view_map/ViewMapIO.h
+ * \ingroup freestyle
+ * \brief Functions to manage I/O for the view map
+ * \author Emmanuel Turquin
+ * \date 09/01/2003
+ */
+
+#include <fstream>
+#include <string>
+
+#include "ViewMap.h"
+
+#include "../system/FreestyleConfig.h"
+#include "../system/ProgressBar.h"
+
+namespace ViewMapIO {
+
+static const unsigned ZERO = UINT_MAX;
+
+LIB_VIEW_MAP_EXPORT
+int load(istream& in, ViewMap *vm, ProgressBar *pb = NULL);
+
+LIB_VIEW_MAP_EXPORT
+int save(ostream& out, ViewMap *vm, ProgressBar *pb = NULL);
+
+namespace Options {
+
+static const unsigned char FLOAT_VECTORS = 1;
+static const unsigned char NO_OCCLUDERS = 2;
+
+LIB_VIEW_MAP_EXPORT
+void setFlags(const unsigned char flags);
+
+LIB_VIEW_MAP_EXPORT
+void addFlags(const unsigned char flags);
+
+LIB_VIEW_MAP_EXPORT
+void rmFlags(const unsigned char flags);
+
+LIB_VIEW_MAP_EXPORT
+unsigned char getFlags();
+
+LIB_VIEW_MAP_EXPORT
+void setModelsPath(const string& path);
+
+LIB_VIEW_MAP_EXPORT
+string getModelsPath();
+
+}; // End of namepace Options
+
+#ifdef IRIX
+
+namespace Internal {
+
+template <unsigned S>
+ostream& write(ostream& out, const char *str)
+{
+ out.put(str[S - 1]);
+ return write<S - 1>(out, str);
+}
+
+template<>
+ostream& write<1>(ostream& out, const char *str)
+{
+ return out.put(str[0]);
+}
+
+template<>
+ostream& write<0>(ostream& out, const char*)
+{
+ return out;
+}
+
+template <unsigned S>
+istream& read(istream& in, char *str)
+{
+ in.get(str[S - 1]);
+ return read<S - 1>(in, str);
+}
+
+template<>
+istream& read<1>(istream& in, char *str)
+{
+ return in.get(str[0]);
+}
+
+template<>
+istream& read<0>(istream& in, char*)
+{
+ return in;
+}
+
+} // End of namespace Internal
+
+#endif // IRIX
+
+} // End of namespace ViewMapIO
+
+#endif // __FREESTYLE_VIEW_MAP_IO_H__
diff --git a/source/blender/freestyle/intern/view_map/ViewMapIterators.h b/source/blender/freestyle/intern/view_map/ViewMapIterators.h
new file mode 100644
index 00000000000..78c09c863cc
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ViewMapIterators.h
@@ -0,0 +1,574 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_VIEW_MAP_ITERATORS_H__
+#define __FREESTYLE_VIEW_MAP_ITERATORS_H__
+
+/** \file blender/freestyle/intern/view_map/ViewMapIterators.h
+ * \ingroup freestyle
+ * \brief Iterators used to iterate over the various elements of the ViewMap
+ * \author Stephane Grabli
+ * \date 01/07/2003
+ */
+
+#include "ViewMap.h"
+
+#include "../system/Iterator.h" //soc
+
+
+/**********************************/
+/* */
+/* */
+/* ViewMap */
+/* */
+/* */
+/**********************************/
+
+/**********************************/
+/* */
+/* */
+/* ViewVertex */
+/* */
+/* */
+/**********************************/
+
+namespace ViewVertexInternal {
+
+/*! Class representing an iterator over oriented ViewEdges around a ViewVertex. This iterator allows a CCW iteration
+ * (in the image plane).
+ * An instance of an orientedViewEdgeIterator can only be obtained from a ViewVertex by calling edgesBegin()
+ * or edgesEnd().
+ */
+class orientedViewEdgeIterator : public Iterator
+{
+public:
+ friend class ViewVertex;
+ friend class TVertex;
+ friend class NonTVertex;
+ friend class ViewEdge;
+
+ // FIXME
+ typedef ::TVertex::edge_pointers_container edge_pointers_container;
+ typedef ::NonTVertex::edges_container edges_container;
+
+protected:
+ Nature::VertexNature _Nature; // the nature of the underlying vertex
+ // T vertex attributes
+ edge_pointers_container::iterator _tbegin;
+ edge_pointers_container::iterator _tend;
+ edge_pointers_container::iterator _tvertex_iter;
+
+ // Non TVertex attributes
+ edges_container::iterator _begin;
+ edges_container::iterator _end;
+ edges_container::iterator _nontvertex_iter;
+
+public:
+ /*! Default constructor */
+ inline orientedViewEdgeIterator() {}
+
+ inline orientedViewEdgeIterator(Nature::VertexNature iNature)
+ {
+ _Nature = iNature;
+ }
+
+ /*! Copy constructor */
+ orientedViewEdgeIterator(const orientedViewEdgeIterator& iBrother)
+ {
+ _Nature = iBrother._Nature;
+ if (_Nature & Nature::T_VERTEX) {
+ _tbegin = iBrother._tbegin;
+ _tend = iBrother._tend;
+ _tvertex_iter = iBrother._tvertex_iter;
+ }
+ else {
+ _begin = iBrother._begin;
+ _end = iBrother._end;
+ _nontvertex_iter = iBrother._nontvertex_iter;
+ }
+ }
+
+ virtual ~orientedViewEdgeIterator() {}
+
+public:
+ inline orientedViewEdgeIterator(edge_pointers_container::iterator begin, edge_pointers_container::iterator end,
+ edge_pointers_container::iterator iter)
+ {
+ _Nature = Nature::T_VERTEX;
+ _tbegin = begin;
+ _tend = end;
+ _tvertex_iter = iter;
+ }
+
+ inline orientedViewEdgeIterator(edges_container::iterator begin, edges_container::iterator end,
+ edges_container::iterator iter)
+ {
+ _Nature = Nature::NON_T_VERTEX;
+ _begin = begin;
+ _end = end;
+ _nontvertex_iter = iter;
+ }
+
+public:
+ /*! Tells whether the ViewEdge pointed by this iterator is the first one of the iteration list or not. */
+ virtual bool isBegin() const
+ {
+ if (_Nature & Nature::T_VERTEX)
+ return (_tvertex_iter == _tbegin);
+ else
+ return (_nontvertex_iter == _begin);
+ }
+
+ /*! Tells whether the ViewEdge pointed by this iterator is after the last one of the iteration list or not. */
+ virtual bool isEnd() const
+ {
+ if (_Nature & Nature::T_VERTEX)
+ return (_tvertex_iter == _tend);
+ else
+ return (_nontvertex_iter == _end);
+ }
+
+ // operators
+ /*! Increments. In the scripting language, call "increment()". */
+ // operator corresponding to ++i
+ virtual orientedViewEdgeIterator& operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ // operator corresponding to i++, i.e. which returns the value *and then* increments.
+ // That's why we store the value in a temp.
+ virtual orientedViewEdgeIterator operator++(int)
+ {
+ orientedViewEdgeIterator tmp = *this;
+ increment();
+ return tmp;
+ }
+
+ // comparibility
+ /*! operator != */
+ virtual bool operator!=(const orientedViewEdgeIterator& b) const
+ {
+ if (_Nature & Nature::T_VERTEX)
+ return (_tvertex_iter != b._tvertex_iter);
+ else
+ return (_nontvertex_iter != b._nontvertex_iter);
+ }
+
+ /*! operator == */
+ virtual bool operator==(const orientedViewEdgeIterator& b) const
+ {
+ return !(*this != b);
+ }
+
+ // dereferencing
+ /*! Returns a reference to the pointed orientedViewEdge.
+ * In the scripting language, you must call "getObject()" instead.
+ */
+ virtual ::ViewVertex::directedViewEdge& operator*() const
+ {
+ if (_Nature & Nature::T_VERTEX)
+ //return _tvertex_iter;
+ return **_tvertex_iter;
+ else
+ return (*_nontvertex_iter);
+ }
+ /*! Returns a pointer to the pointed orientedViewEdge.
+ * Can't be called in the scripting language.
+ */
+ virtual ::ViewVertex::directedViewEdge *operator->() const
+ {
+ return &(operator*());
+ }
+
+public:
+ /*! increments.*/
+ virtual inline int increment()
+ {
+ if (_Nature & Nature::T_VERTEX) {
+ ::ViewVertex::directedViewEdge tmp = (**_tvertex_iter);
+ ++_tvertex_iter;
+ if (_tvertex_iter != _tend) {
+ // FIXME : pquoi deja ?
+ ::ViewVertex::directedViewEdge tmp2 = (**_tvertex_iter);
+ if (tmp2.first == tmp.first)
+ ++_tvertex_iter;
+ }
+ }
+ else {
+ ++_nontvertex_iter;
+ }
+ return 0;
+ }
+};
+
+} // ViewVertexInternal namespace
+
+/**********************************/
+/* */
+/* */
+/* ViewEdge */
+/* */
+/* */
+/**********************************/
+
+namespace ViewEdgeInternal {
+
+//
+// SVertexIterator
+//
+/////////////////////////////////////////////////
+
+class SVertexIterator : public Interface0DIteratorNested
+{
+public:
+ SVertexIterator()
+ {
+ _vertex = NULL;
+ _begin = NULL;
+ _previous_edge = NULL;
+ _next_edge = NULL;
+ _t = 0;
+ }
+
+ SVertexIterator(const SVertexIterator& vi)
+ {
+ _vertex = vi._vertex;
+ _begin = vi._begin;
+ _previous_edge = vi._previous_edge;
+ _next_edge = vi._next_edge;
+ _t = vi._t;
+ }
+
+ SVertexIterator(SVertex *v, SVertex *begin, FEdge *prev, FEdge *next, float t)
+ {
+ _vertex = v;
+ _begin = begin;
+ _previous_edge = prev;
+ _next_edge = next;
+ _t = t;
+ }
+
+ SVertexIterator& operator=(const SVertexIterator& vi)
+ {
+ _vertex = vi._vertex;
+ _begin = vi._begin;
+ _previous_edge = vi._previous_edge;
+ _next_edge = vi._next_edge;
+ _t = vi._t;
+ return *this;
+ }
+
+ virtual ~SVertexIterator() {}
+
+ virtual string getExactTypeName() const
+ {
+ return "SVertexIterator";
+ }
+
+ virtual SVertex& operator*()
+ {
+ return *_vertex;
+ }
+
+ virtual SVertex *operator->()
+ {
+ return &(operator*());
+ }
+
+ virtual SVertexIterator& operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ virtual SVertexIterator operator++(int)
+ {
+ SVertexIterator ret(*this);
+ increment();
+ return ret;
+ }
+
+ virtual SVertexIterator& operator--()
+ {
+ decrement();
+ return *this;
+ }
+
+ virtual SVertexIterator operator--(int)
+ {
+ SVertexIterator ret(*this);
+ decrement();
+ return ret;
+ }
+
+ virtual int increment()
+ {
+ if (!_next_edge) {
+ _vertex = NULL;
+ return 0;
+ }
+ _t += (float)_next_edge->getLength2D();
+ _vertex = _next_edge->vertexB();
+ _previous_edge = _next_edge;
+ _next_edge = _next_edge->nextEdge();
+ return 0;
+ }
+
+ virtual int decrement()
+ {
+ if (!_previous_edge) {
+ _vertex = NULL;
+ return 0;
+ }
+ if ((!_next_edge) && (!_vertex)) {
+ _vertex = _previous_edge->vertexB();
+ return 0;
+ }
+ _t -= (float)_previous_edge->getLength2D();
+ _vertex = _previous_edge->vertexA();
+ _next_edge = _previous_edge;
+ _previous_edge = _previous_edge->previousEdge();
+ return 0;
+ }
+
+ virtual bool isBegin() const
+ {
+ return _vertex == _begin;
+ }
+
+ virtual bool isEnd() const
+ {
+ return (!_vertex) || (_vertex == _begin && _previous_edge);
+ }
+
+ virtual float t() const
+ {
+ return _t;
+ }
+
+ virtual float u() const
+ {
+ return _t / (float)_next_edge->viewedge()->getLength2D();
+ }
+
+ virtual bool operator==(const Interface0DIteratorNested& it) const
+ {
+ const SVertexIterator *it_exact = dynamic_cast<const SVertexIterator*>(&it);
+ if (!it_exact)
+ return false;
+ return (_vertex == it_exact->_vertex);
+ }
+
+ virtual SVertexIterator *copy() const
+ {
+ return new SVertexIterator(*this);
+ }
+
+private:
+ SVertex *_vertex;
+ SVertex *_begin;
+ FEdge *_previous_edge;
+ FEdge *_next_edge;
+ float _t; // curvilinear abscissa
+};
+
+
+//
+// ViewEdgeIterator (base class)
+//
+///////////////////////////////////////////////////////////
+
+/*! Base class for iterators over ViewEdges of the ViewMap Graph.
+ * Basically the "increment()" operator of this class should be able to take the decision of "where" (on which
+ * ViewEdge) to go when pointing on a given ViewEdge.
+ * ::Caution::: the dereferencing operator returns a *pointer* to the pointed ViewEdge.
+ */
+class ViewEdgeIterator : public Iterator
+{
+public:
+ /*! Builds a ViewEdgeIterator from a starting ViewEdge and its orientation.
+ * \param begin
+ * The ViewEdge from where to start the iteration.
+ * \param orientation
+ * If true, we'll look for the next ViewEdge among the ViewEdges that surround the ending ViewVertex of begin.
+ * If false, we'll search over the ViewEdges surrounding the ending ViewVertex of begin.
+ */
+ ViewEdgeIterator(ViewEdge *begin = NULL, bool orientation = true)
+ {
+ _orientation = orientation;
+ _edge = begin;
+ _begin = begin;
+ }
+
+ /*! Copy constructor */
+ ViewEdgeIterator(const ViewEdgeIterator& it)
+ {
+ _orientation = it._orientation;
+ _edge = it._edge;
+ _begin = it._begin;
+ }
+
+ virtual ~ViewEdgeIterator() {}
+
+ /*! Returns the string "ViewEdgeIterator" */
+ virtual string getExactTypeName() const
+ {
+ return "ViewEdgeIterator";
+ }
+
+ /*! Returns the current pointed ViewEdge. */
+ ViewEdge *getCurrentEdge()
+ {
+ return _edge;
+ }
+
+ /*! Sets the current pointed ViewEdge. */
+ void setCurrentEdge(ViewEdge *edge)
+ {
+ _edge = edge;
+ }
+
+ /*! Returns the first ViewEdge used for the iteration. */
+ ViewEdge *getBegin()
+ {
+ return _begin;
+ }
+
+ /*! Sets the first ViewEdge used for the iteration. */
+ void setBegin(ViewEdge *begin)
+ {
+ _begin = begin;
+ }
+
+ /*! Gets the orientation of the pointed ViewEdge in the iteration. */
+ bool getOrientation() const
+ {
+ return _orientation;
+ }
+
+ /*! Sets the orientation of the pointed ViewEdge in the iteration. */
+ void setOrientation(bool orientation)
+ {
+ _orientation = orientation;
+ }
+
+ /*! Changes the current orientation. */
+ void changeOrientation()
+ {
+ _orientation = !_orientation;
+ }
+
+ /*! Returns a *pointer* to the pointed ViewEdge. */
+ virtual ViewEdge *operator*()
+ {
+ return _edge;
+ }
+
+ virtual ViewEdge *operator->()
+ {
+ return operator*();
+ }
+
+ /*! Increments. In the scripting language, call "increment()". */
+ virtual ViewEdgeIterator& operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ /*! Increments. In the scripting language, call "increment()". */
+ virtual ViewEdgeIterator operator++(int)
+ {
+ ViewEdgeIterator tmp(*this);
+ increment();
+ return tmp;
+ }
+
+ /*! increments. */
+ virtual int increment()
+ {
+ cerr << "Warning: method increment() not implemented" << endl;
+ return 0;
+ }
+
+ /*! Decrements. In the scripting language, call "decrement()". */
+ virtual ViewEdgeIterator& operator--()
+ {
+ decrement();
+ return *this;
+ }
+
+ /*! Decrements. In the scripting language, call "decrement()". */
+ virtual ViewEdgeIterator operator--(int)
+ {
+ ViewEdgeIterator tmp(*this);
+ decrement();
+ return tmp;
+ }
+
+ /*! decrements. */
+ virtual int decrement()
+ {
+ cerr << "Warning: method decrement() not implemented" << endl;
+ return 0;
+ }
+
+ /*! Returns true if the pointed ViewEdge is the first one used for the iteration. */
+ virtual bool isBegin() const
+ {
+ return _edge == _begin;
+ }
+
+ /*! Returns true if the pointed ViewEdge* equals 0. */
+ virtual bool isEnd() const
+ {
+ return !_edge;
+ }
+
+ /*! operator == */
+ virtual bool operator==(ViewEdgeIterator& it) const
+ {
+ return _edge == it._edge;
+ }
+
+ /*! operator != */
+ virtual bool operator!=(ViewEdgeIterator& it) const
+ {
+ return !(*this == it);
+ }
+
+protected:
+ bool _orientation;
+ ViewEdge *_edge;
+ ViewEdge *_begin;
+};
+
+} // end of namespace ViewEdgeInternal
+
+#endif // __FREESTYLE_VIEW_MAP_ITERATORS_H__
diff --git a/source/blender/freestyle/intern/view_map/ViewMapTesselator.cpp b/source/blender/freestyle/intern/view_map/ViewMapTesselator.cpp
new file mode 100644
index 00000000000..d1adc55d3ac
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ViewMapTesselator.cpp
@@ -0,0 +1,49 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/view_map/ViewMapTesselator.cpp
+ * \ingroup freestyle
+ * \brief Class to build a Node Tree designed to be displayed from a Silhouette View Map structure.
+ * \author Stephane Grabli
+ * \date 26/03/2002
+ */
+
+#include "ViewMapTesselator.h"
+
+NodeGroup *ViewMapTesselator::Tesselate(ViewMap *iViewMap)
+{
+ if (0 == iViewMap->ViewEdges().size())
+ return NULL;
+
+ const vector<ViewEdge*>& viewedges = iViewMap->ViewEdges();
+ return Tesselate(viewedges.begin(), viewedges.end());
+}
+
+NodeGroup *ViewMapTesselator::Tesselate(WShape *)
+{
+ return NULL;
+}
diff --git a/source/blender/freestyle/intern/view_map/ViewMapTesselator.h b/source/blender/freestyle/intern/view_map/ViewMapTesselator.h
new file mode 100644
index 00000000000..c1ed7e3926a
--- /dev/null
+++ b/source/blender/freestyle/intern/view_map/ViewMapTesselator.h
@@ -0,0 +1,211 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_VIEW_MAP_TESSELATOR_H__
+#define __FREESTYLE_VIEW_MAP_TESSELATOR_H__
+
+/** \file blender/freestyle/intern/view_map/ViewMapTesselator.h
+ * \ingroup freestyle
+ * \brief Class to build a Node Tree designed to be displayed from a Silhouette View Map structure.
+ * \author Stephane Grabli
+ * \date 26/03/2002
+ */
+
+#include "Silhouette.h"
+#include "ViewMap.h"
+
+#include "../scene_graph/LineRep.h"
+#include "../scene_graph/NodeShape.h"
+#include "../scene_graph/NodeGroup.h"
+#include "../scene_graph/OrientedLineRep.h"
+#include "../scene_graph/VertexRep.h"
+
+#include "../winged_edge/WEdge.h"
+
+class NodeShape;
+class NodeGroup;
+class SShape;
+class WShape;
+
+class LIB_VIEW_MAP_EXPORT ViewMapTesselator
+{
+public:
+ inline ViewMapTesselator()
+ {
+ _nature = Nature::SILHOUETTE | Nature::BORDER | Nature::CREASE;
+ _FrsMaterial.setDiffuse(0, 0, 0, 1);
+ _overloadFrsMaterial = false;
+ }
+
+ virtual ~ViewMapTesselator() {}
+
+ /*! Builds a set of lines rep contained under a a NodeShape, itself contained under a NodeGroup from a ViewMap */
+ NodeGroup *Tesselate(ViewMap *iViewMap);
+
+ /*! Builds a set of lines rep contained under a a NodeShape, itself contained under a NodeGroup from a set of
+ * view edges
+ */
+ template<class ViewEdgesIterator>
+ NodeGroup *Tesselate(ViewEdgesIterator begin, ViewEdgesIterator end);
+
+ /*! Builds a set of lines rep contained among a NodeShape, from a WShape */
+ NodeGroup *Tesselate(WShape *iWShape);
+
+ inline void setNature(Nature::EdgeNature iNature)
+ {
+ _nature = iNature;
+ }
+
+ inline void setFrsMaterial(const FrsMaterial& iMaterial)
+ {
+ _FrsMaterial = iMaterial;
+ _overloadFrsMaterial = true;
+ }
+
+ inline Nature::EdgeNature nature()
+ {
+ return _nature;
+ }
+
+ inline const FrsMaterial& frs_material() const
+ {
+ return _FrsMaterial;
+ }
+
+protected:
+ virtual void AddVertexToLine(LineRep *iLine, SVertex *v) = 0;
+
+private:
+ Nature::EdgeNature _nature;
+ FrsMaterial _FrsMaterial;
+ bool _overloadFrsMaterial;
+};
+
+/*! Class to tesselate the 2D projected silhouette */
+class ViewMapTesselator2D : public ViewMapTesselator
+{
+public:
+ inline ViewMapTesselator2D() : ViewMapTesselator() {}
+ virtual ~ViewMapTesselator2D() {}
+
+protected:
+ virtual void AddVertexToLine(LineRep *iLine, SVertex *v)
+ {
+ iLine->AddVertex(v->point2D());
+ }
+};
+
+/*! Class to tesselate the 3D silhouette */
+class ViewMapTesselator3D : public ViewMapTesselator
+{
+public:
+ inline ViewMapTesselator3D() : ViewMapTesselator() {}
+ virtual ~ViewMapTesselator3D() {}
+
+protected:
+ virtual void AddVertexToLine(LineRep *iLine, SVertex *v)
+ {
+ iLine->AddVertex(v->point3D());
+ }
+};
+
+//
+// Implementation
+//
+///////////////////////////////////////////////
+
+template<class ViewEdgesIterator>
+NodeGroup *ViewMapTesselator::Tesselate(ViewEdgesIterator begin, ViewEdgesIterator end)
+{
+ NodeGroup *group = new NodeGroup;
+ NodeShape *tshape = new NodeShape;
+ group->AddChild(tshape);
+ //tshape->frs_material().setDiffuse(0.0f, 0.0f, 0.0f, 1.0f);
+ tshape->setFrsMaterial(_FrsMaterial);
+
+ LineRep *line;
+
+ FEdge *firstEdge;
+ FEdge *nextFEdge, *currentEdge;
+
+ int id = 0;
+ //for (vector<ViewEdge*>::const_iterator c = viewedges.begin(), cend = viewedges.end(); c != cend; c++)
+ for (ViewEdgesIterator c = begin, cend = end; c != cend; c++) {
+#if 0
+ if ((*c)->qi() > 0) {
+ continue;
+ }
+ if (!((*c)->nature() & (_nature))) {
+ continue;
+ }
+#endif
+ firstEdge = (*c)->fedgeA();
+
+#if 0
+ if (firstEdge->invisibility() > 0)
+ continue;
+#endif
+
+ line = new OrientedLineRep();
+ if (_overloadFrsMaterial)
+ line->setFrsMaterial(_FrsMaterial);
+
+ // there might be chains containing a single element
+ if (0 == (firstEdge)->nextEdge()) {
+ line->setStyle(LineRep::LINES);
+ //line->AddVertex((*c)->vertexA()->point3D());
+ //line->AddVertex((*c)->vertexB()->point3D());
+ AddVertexToLine(line, firstEdge->vertexA());
+ AddVertexToLine(line, firstEdge->vertexB());
+ }
+ else {
+ line->setStyle(LineRep::LINE_STRIP);
+
+ //firstEdge = (*c);
+ nextFEdge = firstEdge;
+ currentEdge = firstEdge;
+ do {
+ //line->AddVertex(nextFEdge->vertexA()->point3D());
+ AddVertexToLine(line, nextFEdge->vertexA());
+ currentEdge = nextFEdge;
+ nextFEdge = nextFEdge->nextEdge();
+ } while ((nextFEdge != NULL) && (nextFEdge != firstEdge));
+ // Add the last vertex
+ //line->AddVertex(currentEdge->vertexB()->point3D());
+ AddVertexToLine(line, currentEdge->vertexB());
+ }
+
+ line->setId((*c)->getId().getFirst());
+ line->ComputeBBox();
+ tshape->AddRep(line);
+ id++;
+ }
+
+ return group;
+}
+
+#endif // __FREESTYLE_VIEW_MAP_TESSELATOR_H__
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
new file mode 100644
index 00000000000..64b897c5596
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
@@ -0,0 +1,642 @@
+/*
+ * ***** 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.
+ *
+ * This Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is:
+ * GTS - Library for the manipulation of triangulated surfaces
+ * Copyright (C) 1999 Stephane Popinet
+ * and:
+ * OGF/Graphite: Geometry and Graphics Programming Library + Utilities
+ * Copyright (C) 2000-2003 Bruno Levy
+ * Contact: Bruno Levy levy@loria.fr
+ * ISA Project
+ * LORIA, INRIA Lorraine,
+ * Campus Scientifique, BP 239
+ * 54506 VANDOEUVRE LES NANCY CEDEX
+ * FRANCE
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/winged_edge/Curvature.cpp
+ * \ingroup freestyle
+ * \brief GTS - Library for the manipulation of triangulated surfaces
+ * \author Stephane Popinet
+ * \date 1999
+ * \brief OGF/Graphite: Geometry and Graphics Programming Library + Utilities
+ * \author Bruno Levy
+ * \date 2000-2003
+ */
+
+#include <assert.h>
+#include <cstdlib> // for malloc and free
+#include <math.h>
+#include <set>
+#include <stack>
+
+#include "Curvature.h"
+#include "WEdge.h"
+
+#include "../geometry/normal_cycle.h"
+
+#include "../system/FreestyleConfig.h"
+
+static bool angle_obtuse(WVertex *v, WFace *f)
+{
+ WOEdge *e;
+ f->getOppositeEdge(v, e);
+
+ Vec3r vec1(e->GetaVertex()->GetVertex()-v->GetVertex());
+ Vec3r vec2(e->GetbVertex()->GetVertex()-v->GetVertex());
+ return ((vec1 * vec2) < 0);
+}
+
+// FIXME
+// WVvertex is useless but kept for history reasons
+static bool triangle_obtuse(WVertex *, WFace *f)
+{
+ bool b = false;
+ for (int i = 0; i < 3; i++)
+ b = b || ((f->getEdgeList()[i]->GetVec() * f->getEdgeList()[(i + 1) % 3]->GetVec()) < 0);
+ return b;
+}
+
+static real cotan(WVertex *vo, WVertex *v1, WVertex *v2)
+{
+ /* cf. Appendix B of [Meyer et al 2002] */
+ real udotv, denom;
+
+ Vec3r u(v1->GetVertex() - vo->GetVertex());
+ Vec3r v(v2->GetVertex() - vo->GetVertex());
+
+ udotv = u * v;
+ denom = sqrt(u.squareNorm() * v.squareNorm() - udotv * udotv);
+
+ /* denom can be zero if u==v. Returning 0 is acceptable, based on the callers of this function below. */
+ if (denom == 0.0)
+ return 0.0;
+ return (udotv / denom);
+}
+
+static real angle_from_cotan(WVertex *vo, WVertex *v1, WVertex *v2)
+{
+ /* cf. Appendix B and the caption of Table 1 from [Meyer et al 2002] */
+ real udotv, denom;
+
+ Vec3r u (v1->GetVertex() - vo->GetVertex());
+ Vec3r v(v2->GetVertex() - vo->GetVertex());
+
+ udotv = u * v;
+ denom = sqrt(u.squareNorm() * v.squareNorm() - udotv * udotv);
+
+ /* Note: I assume this is what they mean by using atan2(). -Ray Jones */
+
+ /* tan = denom/udotv = y/x (see man page for atan2) */
+ return (fabs(atan2(denom, udotv)));
+}
+
+/*! gts_vertex_mean_curvature_normal:
+ * @v: a #WVertex.
+ * @s: a #GtsSurface.
+ * @Kh: the Mean Curvature Normal at @v.
+ *
+ * Computes the Discrete Mean Curvature Normal approximation at @v.
+ * The mean curvature at @v is half the magnitude of the vector @Kh.
+ *
+ * Note: the normal computed is not unit length, and may point either into or out of the surface, depending on
+ * the curvature at @v. It is the responsibility of the caller of the function to use the mean curvature normal
+ * appropriately.
+ *
+ * This approximation is from the paper:
+ * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
+ * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
+ * VisMath '02, Berlin (Germany)
+ * http://www-grail.usc.edu/pubs.html
+ *
+ * Returns: %TRUE if the operator could be evaluated, %FALSE if the evaluation failed for some reason (@v is
+ * boundary or is the endpoint of a non-manifold edge.)
+ */
+bool gts_vertex_mean_curvature_normal(WVertex *v, Vec3r &Kh)
+{
+ real area = 0.0;
+
+ if (!v)
+ return false;
+
+ /* this operator is not defined for boundary edges */
+ if (v->isBoundary())
+ return false;
+
+ WVertex::incoming_edge_iterator itE;
+
+ for (itE=v->incoming_edges_begin(); itE != v->incoming_edges_end(); itE++)
+ area += (*itE)->GetaFace()->getArea();
+
+ Kh = Vec3r(0.0, 0.0, 0.0);
+
+ for (itE=v->incoming_edges_begin(); itE != v->incoming_edges_end(); itE++) {
+ WOEdge *e = (*itE)->getPrevOnFace();
+#if 0
+ if ((e->GetaVertex() == v) || (e->GetbVertex() == v))
+ cerr<< "BUG ";
+#endif
+ WVertex *v1 = e->GetaVertex();
+ WVertex *v2 = e->GetbVertex();
+ real temp;
+
+ temp = cotan(v1, v, v2);
+ Kh = Vec3r(Kh + temp * (v2->GetVertex() - v->GetVertex()));
+
+ temp = cotan(v2, v, v1);
+ Kh = Vec3r(Kh + temp * (v1->GetVertex() - v->GetVertex()));
+ }
+ if (area > 0.0) {
+ Kh[0] /= 2 * area;
+ Kh[1] /= 2 * area;
+ Kh[2] /= 2 * area;
+ }
+ else {
+ return false;
+ }
+
+ return true;
+}
+
+/*! gts_vertex_gaussian_curvature:
+ * @v: a #WVertex.
+ * @s: a #GtsSurface.
+ * @Kg: the Discrete Gaussian Curvature approximation at @v.
+ *
+ * Computes the Discrete Gaussian Curvature approximation at @v.
+ *
+ * This approximation is from the paper:
+ * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
+ * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
+ * VisMath '02, Berlin (Germany)
+ * http://www-grail.usc.edu/pubs.html
+ *
+ * Returns: %TRUE if the operator could be evaluated, %FALSE if the evaluation failed for some reason (@v is
+ * boundary or is the endpoint of a non-manifold edge.)
+ */
+bool gts_vertex_gaussian_curvature(WVertex *v, real *Kg)
+{
+ real area = 0.0;
+ real angle_sum = 0.0;
+
+ if (!v)
+ return false;
+ if (!Kg)
+ return false;
+
+ /* this operator is not defined for boundary edges */
+ if (v->isBoundary()) {
+ *Kg = 0.0;
+ return false;
+ }
+
+ WVertex::incoming_edge_iterator itE;
+ for (itE = v->incoming_edges_begin(); itE != v->incoming_edges_end(); itE++)
+ area += (*itE)->GetaFace()->getArea();
+
+ for (itE = v->incoming_edges_begin(); itE != v->incoming_edges_end(); itE++) {
+ WOEdge *e = (*itE)->getPrevOnFace();
+ WVertex *v1 = e->GetaVertex();
+ WVertex *v2 = e->GetbVertex();
+ angle_sum += angle_from_cotan(v, v1, v2);
+ }
+
+ *Kg = (2.0 * M_PI - angle_sum) / area;
+
+ return true;
+}
+
+/*! gts_vertex_principal_curvatures:
+ * @Kh: mean curvature.
+ * @Kg: Gaussian curvature.
+ * @K1: first principal curvature.
+ * @K2: second principal curvature.
+ *
+ * Computes the principal curvatures at a point given the mean and Gaussian curvatures at that point.
+ *
+ * The mean curvature can be computed as one-half the magnitude of the vector computed by
+ * gts_vertex_mean_curvature_normal().
+ *
+ * The Gaussian curvature can be computed with gts_vertex_gaussian_curvature().
+ */
+void gts_vertex_principal_curvatures (real Kh, real Kg, real *K1, real *K2)
+{
+ real temp = Kh * Kh - Kg;
+
+ if (!K1 || !K2)
+ return;
+
+ if (temp < 0.0)
+ temp = 0.0;
+ temp = sqrt (temp);
+ *K1 = Kh + temp;
+ *K2 = Kh - temp;
+}
+
+/* from Maple */
+static void linsolve(real m11, real m12, real b1, real m21, real m22, real b2, real *x1, real *x2)
+{
+ real temp;
+
+ temp = 1.0 / (m21 * m12 - m11 * m22);
+ *x1 = (m12 * b2 - m22 * b1) * temp;
+ *x2 = (m11 * b2 - m21 * b1) * temp;
+}
+
+/* from Maple - largest eigenvector of [a b; b c] */
+static void eigenvector(real a, real b, real c, Vec3r e)
+{
+ if (b == 0.0) {
+ e[0] = 0.0;
+ }
+ else {
+ e[0] = -(c - a - sqrt(c * c - 2 * a * c + a * a + 4 * b * b)) / (2 * b);
+ }
+ e[1] = 1.0;
+ e[2] = 0.0;
+}
+
+/*! gts_vertex_principal_directions:
+ * @v: a #WVertex.
+ * @s: a #GtsSurface.
+ * @Kh: mean curvature normal (a #Vec3r).
+ * @Kg: Gaussian curvature (a real).
+ * @e1: first principal curvature direction (direction of largest curvature).
+ * @e2: second principal curvature direction.
+ *
+ * Computes the principal curvature directions at a point given @Kh and @Kg, the mean curvature normal and
+ * Gaussian curvatures at that point, computed with gts_vertex_mean_curvature_normal() and
+ * gts_vertex_gaussian_curvature(), respectively.
+ *
+ * Note that this computation is very approximate and tends to be unstable. Smoothing of the surface or the principal
+ * directions may be necessary to achieve reasonable results.
+ */
+void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, Vec3r &e2)
+{
+ Vec3r N;
+ real normKh;
+
+ Vec3r basis1, basis2, d, eig;
+ real ve2, vdotN;
+ real aterm_da, bterm_da, cterm_da, const_da;
+ real aterm_db, bterm_db, cterm_db, const_db;
+ real a, b, c;
+ real K1, K2;
+ real *weights, *kappas, *d1s, *d2s;
+ int edge_count;
+ real err_e1, err_e2;
+ int e;
+ WVertex::incoming_edge_iterator itE;
+
+ /* compute unit normal */
+ normKh = Kh.norm();
+
+ if (normKh > 0.0) {
+ Kh.normalize();
+ }
+ else {
+ /* This vertex is a point of zero mean curvature (flat or saddle point). Compute a normal by averaging
+ * the adjacent triangles
+ */
+ N[0] = N[1] = N[2] = 0.0;
+
+ for (itE = v->incoming_edges_begin(); itE != v->incoming_edges_end(); itE++)
+ N = Vec3r(N + (*itE)->GetaFace()->GetNormal());
+ real normN = N.norm();
+ if (normN <= 0.0)
+ return;
+ N.normalize();
+ }
+
+ /* construct a basis from N: */
+ /* set basis1 to any component not the largest of N */
+ basis1[0] = basis1[1] = basis1[2] = 0.0;
+ if (fabs (N[0]) > fabs (N[1]))
+ basis1[1] = 1.0;
+ else
+ basis1[0] = 1.0;
+
+ /* make basis2 orthogonal to N */
+ basis2 = (N ^ basis1);
+ basis2.normalize();
+
+ /* make basis1 orthogonal to N and basis2 */
+ basis1 = (N ^ basis2);
+ basis1.normalize();
+
+ aterm_da = bterm_da = cterm_da = const_da = 0.0;
+ aterm_db = bterm_db = cterm_db = const_db = 0.0;
+ int nb_edges=v->GetEdges().size();
+
+ weights = (real *)malloc(sizeof (real) * nb_edges);
+ kappas = (real *)malloc(sizeof (real) * nb_edges);
+ d1s = (real *)malloc(sizeof (real) * nb_edges);
+ d2s = (real *)malloc(sizeof (real) * nb_edges);
+ edge_count = 0;
+
+ for (itE = v->incoming_edges_begin(); itE != v->incoming_edges_end(); itE++) {
+ WOEdge *e;
+ WFace *f1, *f2;
+ real weight, kappa, d1, d2;
+ Vec3r vec_edge;
+ if (!*itE)
+ continue;
+ e = *itE;
+
+ /* since this vertex passed the tests in gts_vertex_mean_curvature_normal(), this should be true. */
+ //g_assert(gts_edge_face_number (e, s) == 2);
+
+ /* identify the two triangles bordering e in s */
+ f1 = e->GetaFace();
+ f2 = e->GetbFace();
+
+ /* We are solving for the values of the curvature tensor
+ * B = [ a b ; b c ].
+ * The computations here are from section 5 of [Meyer et al 2002].
+ *
+ * The first step is to calculate the linear equations governing the values of (a,b,c). These can be computed
+ * by setting the derivatives of the error E to zero (section 5.3).
+ *
+ * Since a + c = norm(Kh), we only compute the linear equations for dE/da and dE/db. (NB: [Meyer et al 2002]
+ * has the equation a + b = norm(Kh), but I'm almost positive this is incorrect).
+ *
+ * Note that the w_ij (defined in section 5.2) are all scaled by (1/8*A_mixed). We drop this uniform scale
+ * factor because the solution of the linear equations doesn't rely on it.
+ *
+ * The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are also const_dy
+ * terms that are the constant factors in the equations.
+ */
+
+ /* find the vector from v along edge e */
+ vec_edge = Vec3r(-1 * e->GetVec());
+
+ ve2 = vec_edge.squareNorm();
+ vdotN = vec_edge * N;
+
+ /* section 5.2 - There is a typo in the computation of kappa. The edges should be x_j-x_i. */
+ kappa = 2.0 * vdotN / ve2;
+
+ /* section 5.2 */
+
+ /* I don't like performing a minimization where some of the weights can be negative (as can be the case
+ * if f1 or f2 are obtuse). To ensure all-positive weights, we check for obtuseness. */
+ weight = 0.0;
+ if (!triangle_obtuse(v, f1)) {
+ weight += ve2 * cotan(f1->GetNextOEdge(e->twin())->GetbVertex(), e->GetaVertex(), e->GetbVertex()) / 8.0;
+ }
+ else {
+ if (angle_obtuse(v, f1)) {
+ weight += ve2 * f1->getArea() / 4.0;
+ }
+ else {
+ weight += ve2 * f1->getArea() / 8.0;
+ }
+ }
+
+ if (!triangle_obtuse(v, f2)) {
+ weight += ve2 * cotan (f2->GetNextOEdge(e)->GetbVertex(), e->GetaVertex(), e->GetbVertex()) / 8.0;
+ }
+ else {
+ if (angle_obtuse(v, f2)) {
+ weight += ve2 * f1->getArea() / 4.0;
+ }
+ else {
+ weight += ve2 * f1->getArea() / 8.0;
+ }
+ }
+
+ /* projection of edge perpendicular to N (section 5.3) */
+ d[0] = vec_edge[0] - vdotN * N[0];
+ d[1] = vec_edge[1] - vdotN * N[1];
+ d[2] = vec_edge[2] - vdotN * N[2];
+ d.normalize();
+
+ /* not explicit in the paper, but necessary. Move d to 2D basis. */
+ d1 = d * basis1;
+ d2 = d * basis2;
+
+ /* store off the curvature, direction of edge, and weights for later use */
+ weights[edge_count] = weight;
+ kappas[edge_count] = kappa;
+ d1s[edge_count] = d1;
+ d2s[edge_count] = d2;
+ edge_count++;
+
+ /* Finally, update the linear equations */
+ aterm_da += weight * d1 * d1 * d1 * d1;
+ bterm_da += weight * d1 * d1 * 2 * d1 * d2;
+ cterm_da += weight * d1 * d1 * d2 * d2;
+ const_da += weight * d1 * d1 * (-kappa);
+
+ aterm_db += weight * d1 * d2 * d1 * d1;
+ bterm_db += weight * d1 * d2 * 2 * d1 * d2;
+ cterm_db += weight * d1 * d2 * d2 * d2;
+ const_db += weight * d1 * d2 * (-kappa);
+ }
+
+ /* now use the identity (Section 5.3) a + c = |Kh| = 2 * kappa_h */
+ aterm_da -= cterm_da;
+ const_da += cterm_da * normKh;
+
+ aterm_db -= cterm_db;
+ const_db += cterm_db * normKh;
+
+ /* check for solvability of the linear system */
+ if (((aterm_da * bterm_db - aterm_db * bterm_da) != 0.0) && ((const_da != 0.0) || (const_db != 0.0))) {
+ linsolve(aterm_da, bterm_da, -const_da, aterm_db, bterm_db, -const_db, &a, &b);
+
+ c = normKh - a;
+
+ eigenvector(a, b, c, eig);
+ }
+ else {
+ /* region of v is planar */
+ eig[0] = 1.0;
+ eig[1] = 0.0;
+ }
+
+ /* Although the eigenvectors of B are good estimates of the principal directions, it seems that which one is
+ * attached to which curvature direction is a bit arbitrary. This may be a bug in my implementation, or just
+ * a side-effect of the inaccuracy of B due to the discrete nature of the sampling.
+ *
+ * To overcome this behavior, we'll evaluate which assignment best matches the given eigenvectors by comparing
+ * the curvature estimates computed above and the curvatures calculated from the discrete differential operators.
+ */
+
+ gts_vertex_principal_curvatures(0.5 * normKh, Kg, &K1, &K2);
+
+ err_e1 = err_e2 = 0.0;
+ /* loop through the values previously saved */
+ for (e = 0; e < edge_count; e++) {
+ real weight, kappa, d1, d2;
+ real temp1, temp2;
+ real delta;
+
+ weight = weights[e];
+ kappa = kappas[e];
+ d1 = d1s[e];
+ d2 = d2s[e];
+
+ temp1 = fabs (eig[0] * d1 + eig[1] * d2);
+ temp1 = temp1 * temp1;
+ temp2 = fabs (eig[1] * d1 - eig[0] * d2);
+ temp2 = temp2 * temp2;
+
+ /* err_e1 is for K1 associated with e1 */
+ delta = K1 * temp1 + K2 * temp2 - kappa;
+ err_e1 += weight * delta * delta;
+
+ /* err_e2 is for K1 associated with e2 */
+ delta = K2 * temp1 + K1 * temp2 - kappa;
+ err_e2 += weight * delta * delta;
+ }
+ free (weights);
+ free (kappas);
+ free (d1s);
+ free (d2s);
+
+ /* rotate eig by a right angle if that would decrease the error */
+ if (err_e2 < err_e1) {
+ real temp = eig[0];
+
+ eig[0] = eig[1];
+ eig[1] = -temp;
+ }
+
+ e1[0] = eig[0] * basis1[0] + eig[1] * basis2[0];
+ e1[1] = eig[0] * basis1[1] + eig[1] * basis2[1];
+ e1[2] = eig[0] * basis1[2] + eig[1] * basis2[2];
+ e1.normalize();
+
+ /* make N,e1,e2 a right handed coordinate sytem */
+ e2 = N ^ e1;
+ e2.normalize();
+}
+
+namespace OGF {
+
+inline static real angle(WOEdge *h)
+{
+ const Vec3r& n1 = h->GetbFace()->GetNormal();
+ const Vec3r& n2 = h->GetaFace()->GetNormal();
+ const Vec3r v = h->getVec3r();
+ real sine = (n1 ^ n2) * v / v.norm();
+ if (sine >= 1.0) {
+ return M_PI / 2.0;
+ }
+ if (sine <= -1.0) {
+ return -M_PI / 2.0;
+ }
+ return ::asin(sine);
+}
+
+// precondition1: P is inside the sphere
+// precondition2: P,V points to the outside of the sphere (i.e. OP.V > 0)
+static bool sphere_clip_vector(const Vec3r& O, real r, const Vec3r& P, Vec3r& V)
+{
+ Vec3r W = P - O;
+ real a = V.squareNorm();
+ real b = 2.0 * V * W;
+ real c = W.squareNorm() - r * r;
+ real delta = b * b - 4 * a * c;
+ if (delta < 0) {
+ // Should not happen, but happens sometimes (numerical precision)
+ return true;
+ }
+ real t = - b + ::sqrt(delta) / (2.0 * a);
+ if (t < 0.0) {
+ // Should not happen, but happens sometimes (numerical precision)
+ return true;
+ }
+ if (t >= 1.0) {
+ // Inside the sphere
+ return false;
+ }
+
+ V[0] = (t * V.x());
+ V[1] = (t * V.y());
+ V[2] = (t * V.z());
+
+ return true;
+}
+
+// TODO: check optimizations:
+// use marking ? (measure *timings* ...)
+void compute_curvature_tensor(WVertex *start, real radius, NormalCycle& nc)
+{
+ // in case we have a non-manifold vertex, skip it...
+ if (start->isBoundary())
+ return;
+
+ std::set<WVertex*> vertices;
+ const Vec3r& O = start->GetVertex();
+ std::stack<WVertex*> S;
+ S.push(start);
+ vertices.insert(start);
+ while (!S.empty()) {
+ WVertex *v = S.top();
+ S.pop();
+ if (v->isBoundary())
+ continue;
+ const Vec3r& P = v->GetVertex();
+ WVertex::incoming_edge_iterator woeit = v->incoming_edges_begin();
+ WVertex::incoming_edge_iterator woeitend = v->incoming_edges_end();
+ for (; woeit != woeitend; ++woeit) {
+ WOEdge *h = *woeit;
+ if ((v == start) || h->GetVec() * (O - P) > 0.0) {
+ Vec3r V(-1 * h->GetVec());
+ bool isect = sphere_clip_vector(O, radius, P, V);
+ assert (h->GetOwner()->GetNumberOfOEdges() == 2); // Because otherwise v->isBoundary() would be true
+ nc.accumulate_dihedral_angle(V, h->GetAngle());
+
+ if (!isect) {
+ WVertex *w = h->GetaVertex();
+ if (vertices.find(w) == vertices.end()) {
+ vertices.insert(w);
+ S.push(w);
+ }
+ }
+ }
+ }
+ }
+}
+
+void compute_curvature_tensor_one_ring(WVertex *start, NormalCycle& nc)
+{
+ // in case we have a non-manifold vertex, skip it...
+ if (start->isBoundary())
+ return;
+
+ WVertex::incoming_edge_iterator woeit = start->incoming_edges_begin();
+ WVertex::incoming_edge_iterator woeitend = start->incoming_edges_end();
+ for (; woeit != woeitend; ++woeit) {
+ WOEdge *h = (*woeit)->twin();
+ nc.accumulate_dihedral_angle(h->GetVec(), h->GetAngle());
+ WOEdge *hprev = h->getPrevOnFace();
+ nc.accumulate_dihedral_angle(hprev->GetVec(), hprev->GetAngle());
+ }
+}
+
+} // OGF namespace
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.h b/source/blender/freestyle/intern/winged_edge/Curvature.h
new file mode 100644
index 00000000000..20450dbdb38
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.h
@@ -0,0 +1,143 @@
+/*
+ * ***** 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.
+ *
+ * This Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is:
+ * GTS - Library for the manipulation of triangulated surfaces
+ * Copyright (C) 1999 Stephane Popinet
+ * and:
+ * OGF/Graphite: Geometry and Graphics Programming Library + Utilities
+ * Copyright (C) 2000-2003 Bruno Levy
+ * Contact: Bruno Levy levy@loria.fr
+ * ISA Project
+ * LORIA, INRIA Lorraine,
+ * Campus Scientifique, BP 239
+ * 54506 VANDOEUVRE LES NANCY CEDEX
+ * FRANCE
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_CURVATURE_H__
+#define __FREESTYLE_CURVATURE_H__
+
+/** \file blender/freestyle/intern/winged_edge/Curvature.h
+ * \ingroup freestyle
+ * \brief GTS - Library for the manipulation of triangulated surfaces
+ * \author Stephane Popinet
+ * \date 1999
+ * \brief OGF/Graphite: Geometry and Graphics Programming Library + Utilities
+ * \author Bruno Levy
+ * \date 2000-2003
+ */
+
+#include "../geometry/Geom.h"
+
+#include "../system/FreestyleConfig.h"
+#include "../system/Precision.h"
+
+using namespace Geometry;
+
+class WVertex;
+
+class LIB_WINGED_EDGE_EXPORT CurvatureInfo
+{
+public:
+ CurvatureInfo()
+ {
+ K1 = 0.0;
+ K2 = 0.0;
+ e1 = Vec3r(0.0, 0.0, 0.0);
+ e2 = Vec3r(0.0, 0.0, 0.0);
+ Kr = 0.0;
+ dKr = 0.0;
+ er = Vec3r(0.0, 0.0, 0.0);
+ }
+
+ CurvatureInfo(const CurvatureInfo& iBrother)
+ {
+ K1 = iBrother.K1;
+ K2 = iBrother.K2;
+ e1 = iBrother.e1;
+ e2 = iBrother.e2;
+ Kr = iBrother.Kr;
+ dKr = iBrother.dKr;
+ er = iBrother.er;
+ }
+
+ CurvatureInfo(const CurvatureInfo& ca, const CurvatureInfo& cb, real t)
+ {
+ K1 = ca.K1 + t * (cb.K1 - ca.K1);
+ K2 = ca.K2 + t * (cb.K2 - ca.K2);
+ e1 = ca.e1 + t * (cb.e1 - ca.e1);
+ e2 = ca.e2 + t * (cb.e2 - ca.e2);
+ Kr = ca.Kr + t * (cb.Kr - ca.Kr);
+ dKr = ca.dKr + t * (cb.dKr - ca.dKr);
+ er = ca.er + t * (cb.er - ca.er);
+ }
+
+ real K1; // maximum curvature
+ real K2; // minimum curvature
+ Vec3r e1; // maximum curvature direction
+ Vec3r e2; // minimum curvature direction
+ real Kr; // radial curvature
+ real dKr; // radial curvature
+ Vec3r er; // radial curvature direction
+};
+
+class Face_Curvature_Info
+{
+public:
+ Face_Curvature_Info() {}
+
+ ~Face_Curvature_Info()
+ {
+ for (vector<CurvatureInfo*>::iterator ci = vec_curvature_info.begin(), ciend = vec_curvature_info.end();
+ ci != ciend;
+ ++ci)
+ {
+ delete (*ci);
+ }
+ vec_curvature_info.clear();
+ }
+
+ vector<CurvatureInfo *> vec_curvature_info;
+};
+
+bool LIB_WINGED_EDGE_EXPORT gts_vertex_mean_curvature_normal(WVertex *v, Vec3r &n);
+
+bool LIB_WINGED_EDGE_EXPORT gts_vertex_gaussian_curvature(WVertex *v, real *Kg);
+
+void LIB_WINGED_EDGE_EXPORT gts_vertex_principal_curvatures(real Kh, real Kg, real *K1, real *K2);
+
+void LIB_WINGED_EDGE_EXPORT gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, Vec3r &e2);
+
+namespace OGF {
+
+class NormalCycle ;
+
+void LIB_WINGED_EDGE_EXPORT compute_curvature_tensor( WVertex *start, double radius, NormalCycle& nc);
+
+void LIB_WINGED_EDGE_EXPORT compute_curvature_tensor_one_ring(WVertex *start, NormalCycle& nc);
+
+} // OGF namespace
+
+#endif /* __FREESTYLE_CURVATURE_H__ */
diff --git a/source/blender/freestyle/intern/winged_edge/Nature.h b/source/blender/freestyle/intern/winged_edge/Nature.h
new file mode 100644
index 00000000000..0ce64f3f1cb
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/Nature.h
@@ -0,0 +1,79 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_NATURE_H__
+#define __FREESTYLE_NATURE_H__
+
+/** \file blender/freestyle/intern/winged_edge/Nature.h
+ * \ingroup freestyle
+ * \brief Different natures for both vertices and edges
+ * \author Emmanuel Turquin
+ * \date 01/07/2003
+ */
+
+/*! Namespace gathering the different possible natures of 0D and 1D elements of the ViewMap */
+namespace Nature {
+
+/* XXX Why not using enums??? */
+
+typedef unsigned short VertexNature;
+/*! true for any 0D element */
+static const VertexNature POINT = 0; // 0
+/*! true for SVertex */
+static const VertexNature S_VERTEX = (1 << 0); // 1
+/*! true for ViewVertex */
+static const VertexNature VIEW_VERTEX = (1 << 1); // 2
+/*! true for NonTVertex */
+static const VertexNature NON_T_VERTEX = (1 << 2); // 4
+/*! true for TVertex */
+static const VertexNature T_VERTEX = (1 << 3); // 8
+/*! true for CUSP */
+static const VertexNature CUSP = (1 << 4); // 16
+
+typedef unsigned short EdgeNature;
+/*! true for non feature edges (always false for 1D elements of the ViewMap) */
+static const EdgeNature NO_FEATURE = 0; // 0
+/*! true for silhouettes */
+static const EdgeNature SILHOUETTE = (1 << 0); // 1
+/*! true for borders */
+static const EdgeNature BORDER = (1 << 1); // 2
+/*! true for creases */
+static const EdgeNature CREASE = (1 << 2); // 4
+/*! true for ridges */
+static const EdgeNature RIDGE = (1 << 3); // 8
+/*! true for valleys */
+static const EdgeNature VALLEY = (1 << 4); // 16
+/*! true for suggestive contours */
+static const EdgeNature SUGGESTIVE_CONTOUR = (1 << 5); // 32
+/*! true for material boundaries */
+static const EdgeNature MATERIAL_BOUNDARY = (1 << 6); // 64
+/*! true for user-defined edge marks */
+static const EdgeNature EDGE_MARK = (1 << 7); // 128
+
+} // end of namespace Nature
+
+#endif // __FREESTYLE_NATURE_H__
diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.cpp b/source/blender/freestyle/intern/winged_edge/WEdge.cpp
new file mode 100644
index 00000000000..6201d23f9bf
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/WEdge.cpp
@@ -0,0 +1,713 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/winged_edge/WEdge.cpp
+ * \ingroup freestyle
+ * \brief Classes to define a Winged Edge data structure.
+ * \author Stephane Grabli
+ * \date 18/02/2002
+ */
+
+#include <iostream>
+
+#include "WEdge.h"
+
+/*! Temporary structures */
+class vertexdata
+{
+public:
+ WVertex *_copy;
+};
+
+class oedgedata
+{
+public:
+ WOEdge *_copy;
+};
+
+class edgedata
+{
+public:
+ WEdge *_copy;
+};
+
+class facedata
+{
+public:
+ WFace *_copy;
+};
+
+
+/**********************************
+ * *
+ * *
+ * WVertex *
+ * *
+ * *
+ **********************************/
+
+WVertex::WVertex(WVertex& iBrother)
+{
+ _Id = iBrother._Id;
+ _Vertex = iBrother._Vertex;
+ _EdgeList = iBrother._EdgeList;
+
+ _Shape = iBrother._Shape;
+ _Smooth = iBrother._Smooth;
+ _Border = iBrother._Border;
+ userdata = NULL;
+ iBrother.userdata = new vertexdata;
+ ((vertexdata *)(iBrother.userdata))->_copy = this;
+}
+
+WVertex *WVertex::duplicate()
+{
+ WVertex *clone = new WVertex(*this);
+ return clone;
+}
+
+WOEdge *WVertex::incoming_edge_iterator::operator*()
+{
+ return _current;
+}
+
+void WVertex::incoming_edge_iterator::increment()
+{
+ WOEdge *twin = _current->twin();
+ if (!twin) {
+ // we reached a hole
+ _current = 0;
+ return;
+ }
+ WOEdge *next = twin->getPrevOnFace();
+ if (next == _begin) {
+ next = NULL;
+ }
+ _current = next;
+}
+
+WFace *WVertex::face_iterator::operator*()
+{
+ WOEdge *woedge = *_edge_it;
+ if (!woedge)
+ return NULL;
+ return (woedge)->GetbFace();
+}
+
+#if 0
+bool WVertex::isBoundary () const
+{
+ return _Border;
+}
+#endif
+bool WVertex::isBoundary ()
+{
+ if (_Border == 1)
+ return true;
+ else if (_Border == 0)
+ return false;
+
+ vector<WEdge *>::const_iterator it;
+ for (it = _EdgeList.begin(); it != _EdgeList.end(); it++) {
+ if ((*it)->GetNumberOfOEdges() == 1) {
+ _Border = 1;
+ return true;
+ }
+ }
+#if 0
+ if (!(*it)->GetaOEdge()->GetaFace())
+ return true;
+#endif
+ _Border = 0;
+ return false;
+}
+
+void WVertex::AddEdge(WEdge *iEdge)
+{
+ _EdgeList.push_back(iEdge);
+}
+
+WVertex::incoming_edge_iterator WVertex::incoming_edges_begin()
+{
+ WOEdge *begin;
+ WEdge *wedge = _EdgeList.front();
+ WOEdge *aOEdge = wedge->GetaOEdge();
+ if (aOEdge->GetbVertex() == this)
+ begin = aOEdge;
+ else
+ begin = _EdgeList.front()->GetbOEdge();
+ return incoming_edge_iterator(this, begin, begin);
+}
+
+WVertex::incoming_edge_iterator WVertex::incoming_edges_end()
+{
+ WOEdge *begin;
+ WOEdge *aOEdge = _EdgeList.front()->GetaOEdge();
+ if (aOEdge->GetbVertex() == this)
+ begin = aOEdge;
+ else
+ begin = _EdgeList.front()->GetbOEdge();
+ return incoming_edge_iterator(this, begin, 0);
+}
+#if 0
+WOEdge **WVertex::incoming_edge_iterator::operator->()
+{
+ WOEdge **ppaOEdge = (*_iter)->GetaOEdge();
+ if (aOEdge->GetbVertex() == _vertex) {
+ return ppaOEdge;
+ }
+ else {
+ WOEdge *bOEdge = (*_iter)->GetbOEdge();
+ return &bOEdge;
+ }
+}
+#endif
+
+/**********************************
+ * *
+ * *
+ * WOEdge *
+ * *
+ * *
+ **********************************/
+
+WOEdge::WOEdge(WOEdge& iBrother)
+{
+ _paVertex = iBrother.GetaVertex();
+ _pbVertex = iBrother.GetbVertex();
+ _paFace = iBrother.GetaFace();
+ _pbFace = iBrother.GetbFace();
+ _pOwner = iBrother.GetOwner();
+ userdata = NULL;
+ iBrother.userdata = new oedgedata;
+ ((oedgedata *)(iBrother.userdata))->_copy = this;
+
+ _vec = iBrother._vec;
+ _angle = iBrother._angle;
+}
+
+WOEdge *WOEdge::duplicate()
+{
+ WOEdge *clone = new WOEdge(*this);
+ return clone;
+}
+
+Vec3r WOEdge::getVec3r ()
+{
+ return Vec3r(_pbVertex->GetVertex() - _paVertex->GetVertex());
+}
+
+WOEdge *WOEdge::twin ()
+{
+ return GetOwner()->GetOtherOEdge(this);
+}
+
+WOEdge *WOEdge::getPrevOnFace()
+{
+ return _pbFace->GetPrevOEdge(this);
+}
+
+/**********************************
+ * *
+ * *
+ * WEdge *
+ * *
+ * *
+ **********************************/
+
+WEdge::WEdge(WEdge& iBrother)
+{
+ _paOEdge = NULL;
+ _pbOEdge = NULL;
+ WOEdge *aoedge = iBrother.GetaOEdge();
+ WOEdge *boedge = iBrother.GetbOEdge();
+ userdata = NULL;
+
+ if (aoedge)
+ //_paOEdge = new WOEdge(*aoedge);
+ _paOEdge = aoedge->duplicate();
+ if (boedge)
+ //_pbOEdge = new WOEdge(*boedge);
+ _pbOEdge = boedge->duplicate();
+
+ _nOEdges = iBrother.GetNumberOfOEdges();
+ _Id = iBrother.GetId();
+ iBrother.userdata = new edgedata;
+ ((edgedata *)(iBrother.userdata))->_copy = this;
+}
+
+WEdge *WEdge::duplicate()
+{
+ WEdge *clone = new WEdge(*this);
+ return clone;
+}
+
+/**********************************
+ * *
+ * *
+ * WFace *
+ * *
+ * *
+ **********************************/
+
+WFace::WFace(WFace& iBrother)
+{
+ _OEdgeList = iBrother.getEdgeList();
+ _Normal = iBrother.GetNormal();
+ _VerticesNormals = iBrother._VerticesNormals;
+ _VerticesTexCoords = iBrother._VerticesTexCoords;
+ _Id = iBrother.GetId();
+ _FrsMaterialIndex = iBrother._FrsMaterialIndex;
+ _Mark = iBrother._Mark;
+ userdata = NULL;
+ iBrother.userdata = new facedata;
+ ((facedata *)(iBrother.userdata))->_copy = this;
+}
+
+WFace *WFace::duplicate()
+{
+ WFace *clone = new WFace(*this);
+ return clone;
+}
+
+const FrsMaterial& WFace::frs_material()
+{
+ return getShape()->frs_material(_FrsMaterialIndex);
+}
+
+WOEdge *WFace::MakeEdge(WVertex *v1, WVertex *v2)
+{
+ // First check whether the same oriented edge already exists or not:
+ vector<WEdge *>& v1Edges = v1->GetEdges();
+ for (vector<WEdge*>::iterator it1 = v1Edges.begin(), end = v1Edges.end(); it1 != end; it1++) {
+ WEdge *we = (*it1);
+ WOEdge *woea = we->GetaOEdge();
+
+ //if ((*it1)->GetbVertex() == v2) {
+ if ((woea->GetaVertex() == v1) && (woea->GetbVertex() == v2)) {
+ // The oriented edge already exists
+ cerr << "Warning: edge " << v1->GetId() << " - " << v2->GetId() << " appears twice, correcting" << endl;
+ // Adds the edge to the face
+ //AddEdge((*it1)->GetaOEdge());
+ AddEdge(woea);
+ (*it1)->setNumberOfOEdges((*it1)->GetNumberOfOEdges()+1);
+ //sets these vertices as border:
+ v1->setBorder(true);
+ v2->setBorder(true);
+ //return (*it1)->GetaOEdge();
+ return woea;
+ }
+
+ WOEdge *woeb = we->GetbOEdge();
+ //if ((*it1)->GetbVertex() == v2)
+ if (woeb && (woeb->GetaVertex() == v1) && (woeb->GetbVertex() == v2)) {
+ // The oriented edge already exists
+ cerr << "Warning: edge " << v1->GetId() << " - " << v2->GetId() << " appears twice, correcting" << endl;
+ // Adds the edge to the face
+ //AddEdge((*it1)->GetaOEdge());
+ AddEdge(woeb);
+ (*it1)->setNumberOfOEdges((*it1)->GetNumberOfOEdges()+1);
+ //sets these vertices as border:
+ v1->setBorder(true);
+ v2->setBorder(true);
+ //return (*it1)->GetaOEdge();
+ return woeb;
+ }
+ }
+
+ // the oriented edge we're about to build
+ WOEdge *pOEdge = new WOEdge;
+ // The edge containing the oriented edge.
+ WEdge *edge;
+
+ // checks whether this edge already exists or not
+ // If it exists, it points outward v2
+ bool exist = false;
+ WOEdge *pInvertEdge = NULL; // The inverted edge if it exists
+ vector<WEdge *>& v2Edges = v2->GetEdges();
+ vector<WEdge *>::iterator it;
+ for (it = v2Edges.begin(); it != v2Edges.end(); it++) {
+ if ((*it)->GetbVertex() == v1) {
+ // The invert edge already exists
+ exist = true;
+ pInvertEdge = (*it)->GetaOEdge();
+ break;
+ }
+ }
+
+ //DEBUG:
+ if (true == exist) { // The invert edge already exists
+ // Retrieves the corresponding edge
+ edge = pInvertEdge->GetOwner();
+
+ // Sets the a Face (retrieved from pInvertEdge
+ pOEdge->setaFace(pInvertEdge->GetbFace());
+
+ // Updates the invert edge:
+ pInvertEdge->setaFace(this);
+ }
+ else { // The invert edge does not exist yet
+ // we must create a new edge
+ //edge = new WEdge;
+ edge = instanciateEdge();
+
+ // updates the a,b vertex edges list:
+ v1->AddEdge(edge);
+ v2->AddEdge(edge);
+ }
+
+ pOEdge->setOwner(edge);
+ // Add the vertices:
+ pOEdge->setaVertex(v1);
+ pOEdge->setbVertex(v2);
+
+ // Debug:
+ if (v1->GetId() == v2->GetId())
+ cerr << "Warning: edge " << this << " null with vertex " << v1->GetId() << endl;
+
+ edge->AddOEdge(pOEdge);
+ //edge->setNumberOfOEdges(edge->GetNumberOfOEdges() + 1);
+
+ // Add this face (the b face)
+ pOEdge->setbFace(this);
+
+ // Adds the edge to the face
+ AddEdge(pOEdge);
+
+ return pOEdge;
+}
+
+
+bool WFace::getOppositeEdge (const WVertex *v, WOEdge *&e)
+{
+ if (_OEdgeList.size() != 3)
+ return false;
+
+ vector<WOEdge *>::iterator it;
+ e = NULL;
+ for (it = _OEdgeList.begin(); it != _OEdgeList.end(); it++) {
+ if ((*it)->GetaVertex() == v)
+ e = *it;
+ }
+ if (!e)
+ return false;
+ e = NULL;
+ for (it = _OEdgeList.begin(); it != _OEdgeList.end(); it++) {
+ if (((*it)->GetaVertex() != v) && ((*it)->GetbVertex() != v))
+ e = *it;
+ }
+ if (!e)
+ return false;
+ else
+ return true;
+}
+
+real WFace::getArea ()
+{
+ vector<WOEdge *>::iterator it;
+ Vec3r origin = (*(_OEdgeList.begin()))->GetaVertex()->GetVertex();
+ it = _OEdgeList.begin();
+ real a = 0;
+ for (it = it++; it != _OEdgeList.end(); it++) {
+ Vec3r v1 = Vec3r((*it)->GetaVertex()->GetVertex() - origin);
+ Vec3r v2 = Vec3r((*it)->GetbVertex()->GetVertex() - origin);
+ a += (v1 ^ v2).norm() / 2.0;
+ }
+ return a;
+}
+
+
+WOEdge *WFace::GetPrevOEdge(WOEdge* iOEdge)
+{
+ vector<WOEdge *>::iterator woe, woend, woefirst;
+ woefirst = _OEdgeList.begin();
+ woend = _OEdgeList.end();
+ WOEdge *prev = *woefirst;
+ woe = woefirst;
+ ++woe;
+ for (; woe != woend; woe++) {
+ if ((*woe) == iOEdge)
+ return prev;
+ prev = *woe;
+ }
+ // We left the loop. That means that the first OEdge was the good one:
+ if ((*woefirst) == iOEdge)
+ return prev;
+
+ return NULL;
+}
+
+WShape *WFace::getShape()
+{
+ return GetVertex(0)->shape();
+}
+
+
+/**********************************
+ * *
+ * *
+ * WShape *
+ * *
+ * *
+ **********************************/
+
+LIB_WINGED_EDGE_EXPORT
+unsigned WShape::_SceneCurrentId = 0;
+
+WShape *WShape::duplicate()
+{
+ WShape *clone = new WShape(*this);
+ return clone;
+}
+
+WShape::WShape(WShape& iBrother)
+{
+ _Id = iBrother.GetId();
+ _Name = iBrother._Name;
+ _FrsMaterials = iBrother._FrsMaterials;
+ _meanEdgeSize = iBrother._meanEdgeSize;
+ iBrother.bbox(_min, _max);
+ vector<WVertex *>& vertexList = iBrother.getVertexList();
+ vector<WVertex *>::iterator v = vertexList.begin(), vend = vertexList.end();
+ for (; v != vend; ++v) {
+ //WVertex *newVertex = new WVertex(*(*v));
+ WVertex *newVertex = (*v)->duplicate();
+
+ newVertex->setShape(this);
+ AddVertex(newVertex);
+ }
+
+ vector<WEdge *>& edgeList = iBrother.getEdgeList();
+ vector<WEdge *>::iterator e = edgeList.begin(), eend = edgeList.end();
+ for (; e != eend; ++e) {
+ //WEdge *newEdge = new WEdge(*(*e));
+ WEdge *newEdge = (*e)->duplicate();
+ AddEdge(newEdge);
+ }
+
+ vector<WFace *>& faceList = iBrother.GetFaceList();
+ vector<WFace *>::iterator f = faceList.begin(), fend = faceList.end();
+ for (; f != fend; ++f) {
+ //WFace *newFace = new WFace(*(*f));
+ WFace *newFace = (*f)->duplicate();
+ AddFace(newFace);
+ }
+
+ // update all pointed addresses thanks to the newly created objects:
+ vend = _VertexList.end();
+ for (v = _VertexList.begin(); v != vend; ++v) {
+ const vector<WEdge *>& vedgeList = (*v)->GetEdges();
+ vector<WEdge *> newvedgelist;
+ unsigned int i;
+ for (i = 0; i < vedgeList.size(); i++) {
+ WEdge *current = vedgeList[i];
+ edgedata *currentvedata = (edgedata *)current->userdata;
+ newvedgelist.push_back(currentvedata->_copy);
+ }
+ (*v)->setEdges(newvedgelist);
+ }
+
+ eend = _EdgeList.end();
+ for (e = _EdgeList.begin(); e != eend; ++e) {
+ // update aOedge:
+ WOEdge *aoEdge = (*e)->GetaOEdge();
+ aoEdge->setaVertex(((vertexdata *)(aoEdge->GetaVertex()->userdata))->_copy);
+ aoEdge->setbVertex(((vertexdata *)(aoEdge->GetbVertex()->userdata))->_copy);
+ if (aoEdge->GetaFace())
+ aoEdge->setaFace(((facedata *)(aoEdge->GetaFace()->userdata))->_copy);
+ aoEdge->setbFace(((facedata *)(aoEdge->GetbFace()->userdata))->_copy);
+ aoEdge->setOwner(((edgedata *)(aoEdge->GetOwner()->userdata))->_copy);
+
+ // update bOedge:
+ WOEdge *boEdge = (*e)->GetbOEdge();
+ if (boEdge) {
+ boEdge->setaVertex(((vertexdata *)(boEdge->GetaVertex()->userdata))->_copy);
+ boEdge->setbVertex(((vertexdata *)(boEdge->GetbVertex()->userdata))->_copy);
+ if (boEdge->GetaFace())
+ boEdge->setaFace(((facedata *)(boEdge->GetaFace()->userdata))->_copy);
+ boEdge->setbFace(((facedata *)(boEdge->GetbFace()->userdata))->_copy);
+ boEdge->setOwner(((edgedata *)(boEdge->GetOwner()->userdata))->_copy);
+ }
+ }
+
+ fend = _FaceList.end();
+ for (f = _FaceList.begin(); f != fend; ++f) {
+ unsigned int i;
+ const vector<WOEdge *>& oedgeList = (*f)->getEdgeList();
+ vector<WOEdge *> newoedgelist;
+
+ unsigned int n = oedgeList.size();
+ for (i = 0; i < n; i++) {
+ WOEdge *current = oedgeList[i];
+ oedgedata *currentoedata = (oedgedata *)current->userdata;
+ newoedgelist.push_back(currentoedata->_copy);
+ //oedgeList[i] = currentoedata->_copy;
+ //oedgeList[i] = ((oedgedata *)(oedgeList[i]->userdata))->_copy;
+ }
+ (*f)->setEdgeList(newoedgelist);
+ }
+
+ // Free all memory (arghh!)
+ // Vertex
+ vend = iBrother.getVertexList().end();
+ for (v = iBrother.getVertexList().begin(); v != vend; ++v) {
+ delete (vertexdata *)((*v)->userdata);
+ (*v)->userdata = NULL;
+ }
+
+ // Edges and OEdges:
+ eend = iBrother.getEdgeList().end();
+ for (e = iBrother.getEdgeList().begin(); e != eend; ++e) {
+ delete (edgedata *)((*e)->userdata);
+ (*e)->userdata = NULL;
+ // OEdge a:
+ delete (oedgedata *)((*e)->GetaOEdge()->userdata);
+ (*e)->GetaOEdge()->userdata = NULL;
+ // OEdge b:
+ WOEdge *oedgeb = (*e)->GetbOEdge();
+ if (oedgeb) {
+ delete (oedgedata *)(oedgeb->userdata);
+ oedgeb->userdata = NULL;
+ }
+ }
+
+ // Faces
+ fend = iBrother.GetFaceList().end();
+ for (f = iBrother.GetFaceList().begin(); f != fend; ++f) {
+ delete (facedata *)((*f)->userdata);
+ (*f)->userdata = NULL;
+ }
+}
+
+WFace *WShape::MakeFace(vector<WVertex *>& iVertexList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterial)
+{
+ // allocate the new face
+ WFace *face = instanciateFace();
+
+ WFace *result = MakeFace(iVertexList, iFaceEdgeMarksList, iMaterial, face);
+ if (!result)
+ delete face;
+ return result;
+}
+
+WFace *WShape::MakeFace(vector<WVertex *>& iVertexList, vector<Vec3r>& iNormalsList, vector<Vec2r>& iTexCoordsList,
+ vector<bool>& iFaceEdgeMarksList, unsigned iMaterial)
+{
+ // allocate the new face
+ WFace *face = MakeFace(iVertexList, iFaceEdgeMarksList, iMaterial);
+
+ if (!face)
+ return NULL;
+
+ // set the list of per-vertex normals
+ face->setNormalList(iNormalsList);
+ // set the list of per-vertex tex coords
+ face->setTexCoordsList(iTexCoordsList);
+
+ return face;
+}
+
+WFace *WShape::MakeFace(vector<WVertex *>& iVertexList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterial,
+ WFace *face)
+{
+ int id = _FaceList.size();
+
+ face->setFrsMaterialIndex(iMaterial);
+
+ // Check whether we have a degenerated face:
+
+ // LET'S HACK IT FOR THE TRIANGLE CASE:
+
+ if (3 == iVertexList.size()) {
+ if ((iVertexList[0] == iVertexList[1]) ||
+ (iVertexList[0] == iVertexList[2]) ||
+ (iVertexList[2] == iVertexList[1])) {
+ cerr << "Warning: degenerated triangle detected, correcting" << endl;
+ return NULL;
+ }
+ }
+
+ vector<WVertex *>::iterator it;
+
+ // compute the face normal (v1v2 ^ v1v3)
+ WVertex *v1, *v2, *v3;
+ it = iVertexList.begin();
+ v1 = *it;
+ it++;
+ v2 = *it;
+ it++;
+ v3 = *it;
+
+ Vec3r vector1(v2->GetVertex() - v1->GetVertex());
+ Vec3r vector2(v3->GetVertex() - v1->GetVertex());
+
+ Vec3r normal(vector1 ^ vector2);
+ normal.normalize();
+ face->setNormal(normal);
+
+ vector<bool>::iterator mit = iFaceEdgeMarksList.begin();
+ face->setMark(*mit);
+ mit++;
+
+ // vertex pointers used to build each edge
+ vector<WVertex *>::iterator va, vb;
+
+ va = iVertexList.begin();
+ vb = va;
+ for (; va != iVertexList.end(); va = vb) {
+ ++vb;
+ // Adds va to the vertex list:
+ //face->AddVertex(*va);
+
+ WOEdge *oedge;
+ if (*va == iVertexList.back())
+ oedge = face->MakeEdge(*va, iVertexList.front()); //for the last (closing) edge
+ else
+ oedge = face->MakeEdge(*va, *vb);
+
+ if (!oedge)
+ return NULL;
+
+ WEdge *edge = oedge->GetOwner();
+ if (1 == edge->GetNumberOfOEdges()) {
+ // means that we just created a new edge and that we must add it to the shape's edges list
+ edge->setId(_EdgeList.size());
+ AddEdge(edge);
+ // compute the mean edge value:
+ _meanEdgeSize += edge->GetaOEdge()->GetVec().norm();
+ }
+
+ edge->setMark(*mit);
+ ++mit;
+ }
+
+ // Add the face to the shape's faces list:
+ face->setId(id);
+ AddFace(face);
+
+ return face;
+} \ No newline at end of file
diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.h b/source/blender/freestyle/intern/winged_edge/WEdge.h
new file mode 100644
index 00000000000..be9181329d6
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/WEdge.h
@@ -0,0 +1,1344 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_W_EDGE_H__
+#define __FREESTYLE_W_EDGE_H__
+
+/** \file blender/freestyle/intern/winged_edge/WEdge.h
+ * \ingroup freestyle
+ * \brief Classes to define a Winged Edge data structure.
+ * \author Stephane Grabli
+ * \date 18/02/2002
+ */
+
+#include <iterator>
+#include <math.h>
+#include <vector>
+
+#include "../geometry/Geom.h"
+
+#include "../scene_graph/FrsMaterial.h"
+
+#include "../system/FreestyleConfig.h"
+
+using namespace std;
+using namespace Geometry;
+
+
+/**********************************
+ * *
+ * *
+ * WVertex *
+ * *
+ * *
+ **********************************/
+
+
+class WOEdge;
+class WEdge;
+class WShape;
+class WFace;
+
+class LIB_WINGED_EDGE_EXPORT WVertex
+{
+protected:
+ int _Id; // an identificator
+ Vec3r _Vertex;
+ vector<WEdge*> _EdgeList;
+ WShape *_Shape; // the shape to which the vertex belongs
+ bool _Smooth; // flag to indicate whether the Vertex belongs to a smooth edge or not
+ int _Border; // 1 -> border, 0 -> no border, -1 -> not set
+
+public:
+ void *userdata; // designed to store specific user data
+ inline WVertex(const Vec3r &v)
+ {
+ _Id = 0;
+ _Vertex = v;
+ userdata = NULL;
+ _Shape = NULL;
+ _Smooth = true;
+ _Border = -1;
+ }
+
+ /*! Copy constructor */
+ WVertex(WVertex& iBrother);
+ virtual WVertex *duplicate();
+ virtual ~WVertex() {}
+
+ /*! accessors */
+ inline Vec3r& GetVertex()
+ {
+ return _Vertex;
+ }
+
+ inline vector<WEdge*>& GetEdges()
+ {
+ return _EdgeList;
+ }
+
+ inline int GetId()
+ {
+ return _Id;
+ }
+
+ inline WShape *shape() const
+ {
+ return _Shape;
+ }
+
+ inline bool isSmooth() const
+ {
+ return _Smooth;
+ }
+
+ bool isBoundary();
+
+ /*! modifiers */
+ inline void setVertex(const Vec3r& v)
+ {
+ _Vertex = v;
+ }
+
+ inline void setEdges(const vector<WEdge *>& iEdgeList)
+ {
+ _EdgeList = iEdgeList;
+ }
+
+ inline void setId(int id)
+ {
+ _Id = id;
+ }
+
+ inline void setShape(WShape *iShape)
+ {
+ _Shape = iShape;
+ }
+
+ inline void setSmooth(bool b)
+ {
+ _Smooth = b;
+ }
+
+ inline void setBorder(bool b)
+ {
+ if (b)
+ _Border = 1;
+ else
+ _Border = 0;
+ }
+
+ /*! Adds an edge to the edges list */
+ void AddEdge(WEdge *iEdge);
+
+ virtual void ResetUserData()
+ {
+ userdata = NULL;
+ }
+
+public:
+ /*! Iterator to iterate over a vertex incoming edges in the CCW order*/
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ class incoming_edge_iterator : public input_iterator<WOEdge *, ptrdiff_t>
+#else
+ class LIB_WINGED_EDGE_EXPORT incoming_edge_iterator
+ : public iterator<input_iterator_tag, WOEdge *, ptrdiff_t>
+#endif
+ {
+ private:
+ WVertex *_vertex;
+ //
+ WOEdge *_begin;
+ WOEdge *_current;
+
+ public:
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ inline incoming_edge_iterator() : input_iterator<WOEdge *, ptrdiff_t>() {}
+#else
+ inline incoming_edge_iterator() : iterator<input_iterator_tag, WOEdge *, ptrdiff_t>() {}
+#endif
+ virtual ~incoming_edge_iterator() {}; //soc
+
+ protected:
+ friend class WVertex;
+ inline incoming_edge_iterator(WVertex *iVertex, WOEdge *iBegin, WOEdge *iCurrent)
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ : input_iterator<WOEdge *, ptrdiff_t>()
+#else
+ : iterator<input_iterator_tag, WOEdge *, ptrdiff_t>()
+#endif
+ {
+ _vertex = iVertex;
+ _begin = iBegin;
+ _current = iCurrent;
+ }
+
+ public:
+ inline incoming_edge_iterator(const incoming_edge_iterator& iBrother)
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ : input_iterator<WOEdge *, ptrdiff_t>(iBrother)
+#else
+ : iterator<input_iterator_tag, WOEdge *, ptrdiff_t>(iBrother)
+#endif
+ {
+ _vertex = iBrother._vertex;
+ _begin = iBrother._begin;
+ _current = iBrother._current;
+ }
+
+ public:
+ // operators
+ // operator corresponding to ++i
+ virtual incoming_edge_iterator& operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ // operator corresponding to i++
+ virtual incoming_edge_iterator operator++(int)
+ {
+ incoming_edge_iterator tmp = *this;
+ increment();
+ return tmp;
+ }
+
+ // comparibility
+ virtual bool operator!=(const incoming_edge_iterator& b) const
+ {
+ return ((_current) != (b._current));
+ }
+
+ virtual bool operator==(const incoming_edge_iterator& b) const
+ {
+ return ((_current)== (b._current));
+ }
+
+ // dereferencing
+ virtual WOEdge *operator*();
+ //virtual WOEdge **operator->();
+ protected:
+ virtual void increment();
+ };
+
+ /*! Iterator to iterate over a vertex faces in the CCW order */
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ class face_iterator : public input_iterator<WFace *, ptrdiff_t>
+#else
+ class LIB_WINGED_EDGE_EXPORT face_iterator : public iterator<input_iterator_tag, WFace *, ptrdiff_t>
+#endif
+ {
+ private:
+ incoming_edge_iterator _edge_it;
+
+ public:
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ inline face_iterator() : input_iterator<WFace *, ptrdiff_t>() {}
+#else
+ inline face_iterator() : iterator<input_iterator_tag, WFace *, ptrdiff_t>() {}
+#endif
+ virtual ~face_iterator() {}; //soc
+
+ protected:
+ friend class WVertex;
+ inline face_iterator(incoming_edge_iterator it)
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ : input_iterator<WFace *, ptrdiff_t>()
+#else
+ : iterator<input_iterator_tag, WFace *, ptrdiff_t>()
+#endif
+ {
+ _edge_it = it;
+ }
+
+ public:
+ inline face_iterator(const face_iterator& iBrother)
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ : input_iterator<WFace *, ptrdiff_t>(iBrother)
+#else
+ : iterator<input_iterator_tag, WFace *, ptrdiff_t>(iBrother)
+#endif
+ {
+ _edge_it = iBrother._edge_it;
+ }
+
+ public:
+ // operators
+ // operator corresponding to ++i
+ virtual face_iterator& operator++()
+ {
+ increment();
+ return *this;
+ }
+
+ // operator corresponding to i++
+ virtual face_iterator operator++(int)
+ {
+ face_iterator tmp = *this;
+ increment();
+ return tmp;
+ }
+
+ // comparibility
+ virtual bool operator!=(const face_iterator& b) const
+ {
+ return ((_edge_it) != (b._edge_it));
+ }
+
+ virtual bool operator==(const face_iterator& b) const
+ {
+ return ((_edge_it)== (b._edge_it));
+ }
+
+ // dereferencing
+ virtual WFace *operator*();
+ //virtual WOEdge **operator->();
+
+ protected:
+ inline void increment()
+ {
+ ++_edge_it;
+ }
+ };
+
+public:
+ /*! iterators access */
+ virtual incoming_edge_iterator incoming_edges_begin();
+ virtual incoming_edge_iterator incoming_edges_end();
+
+ virtual face_iterator faces_begin()
+ {
+ return face_iterator(incoming_edges_begin());
+ }
+
+ virtual face_iterator faces_end()
+ {
+ return face_iterator(incoming_edges_end());
+ }
+};
+
+
+/**********************************
+ * *
+ * *
+ * WOEdge *
+ * *
+ * *
+ **********************************/
+
+class WFace;
+class WEdge;
+
+class LIB_WINGED_EDGE_EXPORT WOEdge
+{
+protected:
+#if 0
+ WOEdge *_paCWEdge; // edge reached when traveling clockwise on aFace from the edge
+ WOEdge *_pbCWEdge; // edge reached when traveling clockwise on bFace from the edge
+ WOEdge *_paCCWEdge; // edge reached when traveling counterclockwise on aFace from the edge
+ WOEdge *_pbCCWEdge; // edge reached when traveling counterclockwise on bFace from the edge
+#endif
+ WVertex *_paVertex; // starting vertex
+ WVertex *_pbVertex; // ending vertex
+ WFace *_paFace; // when following the edge, face on the right
+ WFace *_pbFace; // when following the edge, face on the left
+ WEdge *_pOwner; // Edge
+
+ Vec3r _vec;
+ real _angle;
+
+public:
+ void *userdata;
+
+ inline WOEdge()
+ {
+#if 0
+ _paCWEdge = NULL;
+ _pbCWEdge = NULL;
+ _paCCWEdge = NULL;
+ _pbCCWEdge = NULL;
+#endif
+ _paVertex = NULL;
+ _pbVertex = NULL;
+ _paFace = NULL;
+ _pbFace = NULL;
+ _pOwner = NULL;
+ userdata = NULL;
+ }
+
+ virtual ~WOEdge() {}; //soc
+
+ /*! copy constructor */
+ WOEdge(WOEdge& iBrother);
+ virtual WOEdge *duplicate();
+
+ /*! accessors */
+#if 0
+ inline WOEdge *GetaCWEdge()
+ {
+ return _paCWEdge;
+ }
+
+ inline WOEdge *GetbCWEdge()
+ {
+ return _pbCWEdge;
+ }
+
+ inline WOEdge *GetaCCWEdge()
+ {
+ return _paCCWEdge;
+ }
+
+ inline WOEdge *GetbCCWEdge()
+ {
+ return _pbCCWEdge;
+ }
+#endif
+
+ inline WVertex *GetaVertex()
+ {
+ return _paVertex;
+ }
+
+ inline WVertex *GetbVertex()
+ {
+ return _pbVertex;
+ }
+
+ inline WFace *GetaFace()
+ {
+ return _paFace;
+ }
+
+ inline WFace *GetbFace()
+ {
+ return _pbFace;
+ }
+
+ inline WEdge *GetOwner()
+ {
+ return _pOwner;
+ }
+
+ inline const Vec3r& GetVec()
+ {
+ return _vec;
+ }
+
+ inline const real GetAngle()
+ {
+ return _angle;
+ }
+
+
+ /*! modifiers */
+#if 0
+ inline void SetaCWEdge(WOEdge *pe)
+ {
+ _paCWEdge = pe;
+ }
+
+ inline void SetbCWEdge(WOEdge *pe)
+ {
+ _pbCWEdge = pe;
+ }
+
+ inline void SetaCCWEdge(WOEdge *pe)
+ {
+ _paCCWEdge = pe;
+ }
+
+ inline void SetbCCCWEdge(WOEdge *pe)
+ {
+ _pbCCWEdge = pe;
+ }
+#endif
+
+ inline void setVecAndAngle();
+
+ inline void setaVertex(WVertex *pv)
+ {
+ _paVertex = pv;
+ setVecAndAngle();
+ }
+
+ inline void setbVertex(WVertex *pv)
+ {
+ _pbVertex = pv;
+ setVecAndAngle();
+ }
+
+ inline void setaFace(WFace *pf)
+ {
+ _paFace = pf;
+ setVecAndAngle();
+ }
+
+ inline void setbFace(WFace *pf)
+ {
+ _pbFace = pf;
+ setVecAndAngle();
+ }
+
+ inline void setOwner(WEdge *pe)
+ {
+ _pOwner = pe;
+ }
+
+ /*! Retrieves the list of edges in CW order */
+ inline void RetrieveCWOrderedEdges(vector<WEdge*>& oEdges);
+
+ /*! returns the vector between the two vertices */
+ Vec3r getVec3r ();
+ WOEdge *twin ();
+ WOEdge *getPrevOnFace();
+
+ virtual void ResetUserData()
+ {
+ userdata = NULL;
+ }
+};
+
+
+/**********************************
+ * *
+ * *
+ * WEdge *
+ * *
+ * *
+ **********************************/
+
+class LIB_WINGED_EDGE_EXPORT WEdge
+{
+protected:
+ WOEdge *_paOEdge; // first oriented edge
+ WOEdge *_pbOEdge; // second oriented edge
+ int _nOEdges; // number of oriented edges associated with this edge. (1 means border edge)
+ bool _Mark; // user-specified edge mark for feature edge detection
+ int _Id; // Identifier for the edge
+
+public:
+ void *userdata; // designed to store specific user data
+
+ inline WEdge()
+ {
+ _paOEdge = NULL;
+ _pbOEdge = NULL;
+ _nOEdges = 0;
+ userdata = NULL;
+ }
+
+ inline WEdge(WOEdge *iOEdge)
+ {
+ _paOEdge = iOEdge;
+ _pbOEdge = NULL;
+ _nOEdges = 1;
+ userdata = NULL;
+ }
+
+ inline WEdge(WOEdge *iaOEdge, WOEdge *ibOEdge)
+ {
+ _paOEdge = iaOEdge;
+ _pbOEdge = ibOEdge;
+ _nOEdges = 2;
+ userdata = NULL;
+ }
+
+ /*! Copy constructor */
+ WEdge(WEdge& iBrother);
+ virtual WEdge *duplicate();
+
+ virtual ~WEdge()
+ {
+ if (_paOEdge) {
+ delete _paOEdge;
+ _paOEdge = NULL;
+ }
+
+ if (_pbOEdge) {
+ delete _pbOEdge;
+ _pbOEdge = NULL;
+ }
+ }
+
+ /*! checks whether two WEdge have a common vertex.
+ * Returns a pointer on the common vertex if it exists, NULL otherwise.
+ */
+ static inline WVertex *CommonVertex(WEdge *iEdge1, WEdge *iEdge2)
+ {
+ if (!iEdge1 || !iEdge2)
+ return NULL;
+
+ WVertex *wv1 = iEdge1->GetaOEdge()->GetaVertex();
+ WVertex *wv2 = iEdge1->GetaOEdge()->GetbVertex();
+ WVertex *wv3 = iEdge2->GetaOEdge()->GetaVertex();
+ WVertex *wv4 = iEdge2->GetaOEdge()->GetbVertex();
+
+ if ((wv1 == wv3) || (wv1 == wv4)) {
+ return wv1;
+ }
+ else if ((wv2 == wv3) || (wv2 == wv4)) {
+ return wv2;
+ }
+ return NULL;
+ }
+
+ /*! accessors */
+ inline WOEdge *GetaOEdge()
+ {
+ return _paOEdge;
+ }
+
+ inline WOEdge *GetbOEdge()
+ {
+ return _pbOEdge;
+ }
+
+ inline int GetNumberOfOEdges()
+ {
+ return _nOEdges;
+ }
+
+ inline bool GetMark()
+ {
+ return _Mark;
+ }
+
+ inline int GetId()
+ {
+ return _Id;
+ }
+
+ inline WVertex *GetaVertex()
+ {
+ return _paOEdge->GetaVertex();
+ }
+
+ inline WVertex *GetbVertex()
+ {
+ return _paOEdge->GetbVertex();
+ }
+
+ inline WFace *GetaFace()
+ {
+ return _paOEdge->GetaFace();
+ }
+
+ inline WFace *GetbFace()
+ {
+ return _paOEdge->GetbFace();
+ }
+
+ inline WOEdge *GetOtherOEdge(WOEdge *iOEdge) {
+ if (iOEdge == _paOEdge)
+ return _pbOEdge;
+ else
+ return _paOEdge;
+ }
+
+ /*! modifiers */
+ inline void setaOEdge(WOEdge *iEdge)
+ {
+ _paOEdge = iEdge;
+ }
+
+ inline void setbOEdge(WOEdge *iEdge)
+ {
+ _pbOEdge = iEdge;
+ }
+
+ inline void AddOEdge(WOEdge *iEdge)
+ {
+ if (!_paOEdge) {
+ _paOEdge = iEdge;
+ _nOEdges++;
+ return;
+ }
+ if (!_pbOEdge) {
+ _pbOEdge = iEdge;
+ _nOEdges++;
+ return;
+ }
+ }
+
+ inline void setNumberOfOEdges(int n)
+ {
+ _nOEdges = n;
+ }
+
+ inline void setMark(bool mark)
+ {
+ _Mark = mark;
+ }
+
+ inline void setId(int id)
+ {
+ _Id = id;
+ }
+
+ virtual void ResetUserData()
+ {
+ userdata = NULL;
+ }
+};
+
+
+/**********************************
+ * *
+ * *
+ * WFace *
+ * *
+ * *
+ **********************************/
+
+
+class LIB_WINGED_EDGE_EXPORT WFace
+{
+protected:
+ vector<WOEdge *> _OEdgeList; // list of oriented edges of bording the face
+ Vec3r _Normal; // normal to the face
+ // in case there is a normal per vertex.
+ // The normal number i corresponds to the aVertex of the oedge number i, for that face
+ vector<Vec3r> _VerticesNormals;
+ vector<Vec2r> _VerticesTexCoords;
+
+ int _Id;
+ unsigned _FrsMaterialIndex;
+ bool _Mark; // Freestyle face mark (if true, feature edges on this face are ignored)
+
+public:
+ void *userdata;
+ inline WFace()
+ {
+ userdata = NULL;
+ _FrsMaterialIndex = 0;
+ }
+
+ /*! copy constructor */
+ WFace(WFace& iBrother);
+ virtual WFace *duplicate();
+ virtual ~WFace() {}
+
+ /*! accessors */
+ inline const vector<WOEdge*>& getEdgeList()
+ {
+ return _OEdgeList;
+ }
+
+ inline WOEdge *GetOEdge(int i)
+ {
+ return _OEdgeList[i];
+ }
+
+ inline Vec3r& GetNormal()
+ {
+ return _Normal;
+ }
+
+ inline int GetId()
+ {
+ return _Id;
+ }
+
+ inline unsigned frs_materialIndex() const
+ {
+ return _FrsMaterialIndex;
+ }
+
+ inline bool GetMark() const
+ {
+ return _Mark;
+ }
+
+ const FrsMaterial& frs_material();
+
+ /*! The vertex of index i corresponds to the a vertex of the edge of index i */
+ inline WVertex *GetVertex(unsigned int index)
+ {
+#if 0
+ if (index >= _OEdgeList.size())
+ return NULL;
+#endif
+ return _OEdgeList[index]->GetaVertex();
+ }
+
+ /*! returns the index at which iVertex is stored in the array.
+ * returns -1 if iVertex doesn't belong to the face.
+ */
+ inline int GetIndex(WVertex *iVertex)
+ {
+ int index = 0;
+ for (vector<WOEdge*>::iterator woe = _OEdgeList.begin(), woend = _OEdgeList.end(); woe != woend; woe++) {
+ if ((*woe)->GetaVertex() == iVertex)
+ return index;
+ ++index;
+ }
+ return -1;
+ }
+
+ inline void RetrieveVertexList(vector<WVertex *>& oVertices)
+ {
+ for (vector<WOEdge *>::iterator woe = _OEdgeList.begin(), woend = _OEdgeList.end(); woe != woend; woe++) {
+ oVertices.push_back((*woe)->GetaVertex());
+ }
+ }
+
+ inline void RetrieveBorderFaces(vector<const WFace *>& oWFaces)
+ {
+ for (vector<WOEdge *>::iterator woe = _OEdgeList.begin(), woend = _OEdgeList.end(); woe != woend; woe++) {
+ WFace *af;
+ if ((af = (*woe)->GetaFace()))
+ oWFaces.push_back(af);
+ }
+ }
+
+ inline WFace *GetBordingFace(int index)
+ {
+#if 0
+ if (index >= _OEdgeList.size())
+ return NULL;
+#endif
+ return _OEdgeList[index]->GetaFace();
+ }
+
+ inline WFace *GetBordingFace(WOEdge *iOEdge)
+ {
+ return iOEdge->GetaFace();
+ }
+
+ inline vector<Vec3r>& GetPerVertexNormals()
+ {
+ return _VerticesNormals;
+ }
+
+ inline vector<Vec2r>& GetPerVertexTexCoords()
+ {
+ return _VerticesTexCoords;
+ }
+
+ /*! Returns the normal of the vertex of index index */
+ inline Vec3r& GetVertexNormal(int index)
+ {
+ return _VerticesNormals[index];
+ }
+
+ /*! Returns the tex coords of the vertex of index index */
+ inline Vec2r& GetVertexTexCoords(int index)
+ {
+ return _VerticesTexCoords[index];
+ }
+
+ /*! Returns the normal of the vertex iVertex for that face */
+ inline Vec3r& GetVertexNormal(WVertex *iVertex)
+ {
+ int i = 0;
+ int index = 0;
+ for (vector<WOEdge *>::const_iterator woe = _OEdgeList.begin(), woend = _OEdgeList.end(); woe != woend; woe++) {
+ if ((*woe)->GetaVertex() == iVertex) {
+ index = i;
+ break;
+ }
+ ++i;
+ }
+
+ return _VerticesNormals[index];
+ }
+
+ inline WOEdge *GetNextOEdge(WOEdge *iOEdge)
+ {
+ bool found = false;
+ vector<WOEdge *>::iterator woe, woend, woefirst;
+ woefirst = _OEdgeList.begin();
+ for (woe = woefirst, woend = _OEdgeList.end(); woe != woend; ++woe) {
+ if (found)
+ return (*woe);
+
+ if ((*woe) == iOEdge) {
+ found = true;
+ }
+ }
+
+ // We left the loop. That means that the first OEdge was the good one:
+ if (found)
+ return (*woefirst);
+
+ return NULL;
+ }
+
+ WOEdge *GetPrevOEdge(WOEdge *iOEdge);
+
+ inline int numberOfEdges() const
+ {
+ return _OEdgeList.size();
+ }
+
+ inline int numberOfVertices() const
+ {
+ return _OEdgeList.size();
+ }
+
+ /*! Returns true if the face has one ot its edge which is a border edge */
+ inline bool isBorder() const
+ {
+ for (vector<WOEdge*>::const_iterator woe = _OEdgeList.begin(), woeend = _OEdgeList.end();
+ woe != woeend;
+ ++woe)
+ {
+ if ((*woe)->GetOwner()->GetbOEdge() == 0)
+ return true;
+ }
+ return false;
+ }
+
+ /*! modifiers */
+ inline void setEdgeList(const vector<WOEdge *>& iEdgeList)
+ {
+ _OEdgeList = iEdgeList;
+ }
+
+ inline void setNormal(const Vec3r& iNormal)
+ {
+ _Normal = iNormal;
+ }
+
+ inline void setNormalList(const vector<Vec3r>& iNormalsList)
+ {
+ _VerticesNormals = iNormalsList;
+ }
+
+ inline void setTexCoordsList(const vector<Vec2r>& iTexCoordsList)
+ {
+ _VerticesTexCoords = iTexCoordsList;
+ }
+
+ inline void setId(int id)
+ {
+ _Id = id;
+ }
+
+ inline void setFrsMaterialIndex(unsigned iMaterialIndex)
+ {
+ _FrsMaterialIndex = iMaterialIndex;
+ }
+
+ inline void setMark(bool iMark)
+ {
+ _Mark = iMark;
+ }
+
+ /*! designed to build a specialized WEdge for use in MakeEdge */
+ virtual WEdge *instanciateEdge() const
+ {
+ return new WEdge;
+ }
+
+ /*! Builds an oriented edge
+ * Returns the built edge.
+ * v1, v2
+ * Vertices at the edge's extremities
+ * The edge is oriented from v1 to v2.
+ */
+ virtual WOEdge *MakeEdge(WVertex *v1, WVertex *v2);
+
+ /*! Adds an edge to the edges list */
+ inline void AddEdge(WOEdge *iEdge)
+ {
+ _OEdgeList.push_back(iEdge);
+ }
+
+ /*! For triangles, returns the edge opposite to the vertex in e.
+ * returns flase if the face is not a triangle or if the vertex is not found
+ */
+ bool getOppositeEdge (const WVertex *v, WOEdge* &e);
+
+ /*! compute the area of the face */
+ real getArea ();
+
+ WShape *getShape();
+ virtual void ResetUserData()
+ {
+ userdata = NULL;
+ }
+};
+
+
+/**********************************
+ * *
+ * *
+ * WShape *
+ * *
+ * *
+ **********************************/
+
+
+class LIB_WINGED_EDGE_EXPORT WShape
+{
+protected:
+ vector<WVertex *> _VertexList;
+ vector<WEdge *> _EdgeList;
+ vector<WFace *> _FaceList;
+ int _Id;
+ string _Name;
+ static unsigned _SceneCurrentId;
+ Vec3r _min;
+ Vec3r _max;
+ vector<FrsMaterial> _FrsMaterials;
+ real _meanEdgeSize;
+
+public:
+ inline WShape()
+ {
+ _meanEdgeSize = 0;
+ _Id = _SceneCurrentId;
+ _SceneCurrentId++;
+ }
+
+ /*! copy constructor */
+ WShape(WShape& iBrother);
+ virtual WShape *duplicate();
+
+ virtual ~WShape()
+ {
+ if (_EdgeList.size() != 0) {
+ vector<WEdge *>::iterator e;
+ for (e = _EdgeList.begin(); e != _EdgeList.end(); ++e) {
+ delete (*e);
+ }
+ _EdgeList.clear();
+ }
+
+ if (_VertexList.size() != 0) {
+ vector<WVertex *>::iterator v;
+ for (v = _VertexList.begin(); v != _VertexList.end(); ++v) {
+ delete (*v);
+ }
+ _VertexList.clear();
+ }
+
+ if (_FaceList.size() != 0) {
+ vector<WFace *>::iterator f;
+ for (f = _FaceList.begin(); f != _FaceList.end(); ++f) {
+ delete (*f);
+ }
+ _FaceList.clear();
+ }
+ }
+
+ /*! accessors */
+ inline vector<WEdge *>& getEdgeList()
+ {
+ return _EdgeList;
+ }
+
+ inline vector<WVertex *>& getVertexList()
+ {
+ return _VertexList;
+ }
+
+ inline vector<WFace *>& GetFaceList()
+ {
+ return _FaceList;
+ }
+
+ inline unsigned GetId()
+ {
+ return _Id;
+ }
+
+ inline void bbox(Vec3r& min, Vec3r& max)
+ {
+ min = _min;
+ max = _max;
+ }
+
+ inline const FrsMaterial& frs_material(unsigned i) const
+ {
+ return _FrsMaterials[i];
+ }
+
+ inline const vector<FrsMaterial>& frs_materials() const
+ {
+ return _FrsMaterials;
+ }
+
+ inline const real getMeanEdgeSize() const
+ {
+ return _meanEdgeSize;
+ }
+
+ inline const string& getName() const
+ {
+ return _Name;
+ }
+
+ /*! modifiers */
+ static inline void setCurrentId(const unsigned id)
+ {
+ _SceneCurrentId = id;
+ }
+
+ inline void setEdgeList(const vector<WEdge *>& iEdgeList)
+ {
+ _EdgeList = iEdgeList;
+ }
+
+ inline void setVertexList(const vector<WVertex *>& iVertexList)
+ {
+ _VertexList = iVertexList;
+ }
+
+ inline void setFaceList(const vector<WFace *>& iFaceList)
+ {
+ _FaceList = iFaceList;
+ }
+
+ inline void setId(int id)
+ {
+ _Id = id;
+ }
+
+ inline void setBBox(const Vec3r& min, const Vec3r& max)
+ {
+ _min = min;
+ _max = max;
+ }
+
+ inline void setFrsMaterial(const FrsMaterial& frs_material, unsigned i)
+ {
+ _FrsMaterials[i] = frs_material;
+ }
+
+ inline void setFrsMaterials(const vector<FrsMaterial>& iMaterials)
+ {
+ _FrsMaterials = iMaterials;
+ }
+
+ inline void setName(const string& name)
+ {
+ _Name = name;
+ }
+
+ /*! designed to build a specialized WFace for use in MakeFace */
+ virtual WFace *instanciateFace() const
+ {
+ return new WFace;
+ }
+
+ /*! adds a new face to the shape
+ * returns the built face.
+ * iVertexList
+ * List of face's vertices. These vertices are not added to the WShape vertex list; they are supposed to be
+ * already stored when calling MakeFace.
+ * The order in which the vertices are stored in the list determines the face's edges orientation and (so) the
+ * face orientation.
+ * iMaterialIndex
+ * The material index for this face
+ */
+ virtual WFace *MakeFace(vector<WVertex *>& iVertexList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex);
+
+ /*! adds a new face to the shape. The difference with the previous method is that this one is designed
+ * to build a WingedEdge structure for which there are per vertex normals, opposed to per face normals.
+ * returns the built face.
+ * iVertexList
+ * List of face's vertices. These vertices are not added to the WShape vertex list; they are supposed to be
+ * already stored when calling MakeFace.
+ * The order in which the vertices are stored in the list determines the face's edges orientation and (so) the
+ * face orientation.
+ * iMaterialIndex
+ * The materialIndex for this face
+ * iNormalsList
+ * The list of normals, iNormalsList[i] corresponding to the normal of the vertex iVertexList[i] for that face.
+ * iTexCoordsList
+ * The list of tex coords, iTexCoordsList[i] corresponding to the normal of the vertex iVertexList[i] for
+ * that face.
+ */
+ virtual WFace *MakeFace(vector<WVertex *>& iVertexList, vector<Vec3r>& iNormalsList, vector<Vec2r>& iTexCoordsList,
+ vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex);
+
+ inline void AddEdge(WEdge *iEdge)
+ {
+ _EdgeList.push_back(iEdge);
+ }
+
+ inline void AddFace(WFace *iFace)
+ {
+ _FaceList.push_back(iFace);
+ }
+
+ inline void AddVertex(WVertex *iVertex)
+ {
+ iVertex->setShape(this);
+ _VertexList.push_back(iVertex);
+ }
+
+ inline void ResetUserData()
+ {
+ for (vector<WVertex *>::iterator v = _VertexList.begin(), vend = _VertexList.end(); v != vend; v++) {
+ (*v)->ResetUserData();
+ }
+
+ for (vector<WEdge *>::iterator e = _EdgeList.begin(), eend = _EdgeList.end(); e != eend; e++) {
+ (*e)->ResetUserData();
+ // manages WOEdge:
+ WOEdge *oe = (*e)->GetaOEdge();
+ if (oe)
+ oe->ResetUserData();
+ oe = (*e)->GetbOEdge();
+ if (oe)
+ oe->ResetUserData();
+ }
+
+ for (vector<WFace *>::iterator f = _FaceList.begin(), fend = _FaceList.end(); f != fend; f++) {
+ (*f)->ResetUserData();
+ }
+ }
+
+ inline void ComputeBBox()
+ {
+ _min = _VertexList[0]->GetVertex();
+ _max = _VertexList[0]->GetVertex();
+
+ Vec3r v;
+ for (vector<WVertex *>::iterator wv = _VertexList.begin(), wvend = _VertexList.end(); wv != wvend; wv++) {
+ for (unsigned int i = 0; i < 3; i++) {
+ v = (*wv)->GetVertex();
+ if (v[i] < _min[i])
+ _min[i] = v[i];
+ if (v[i] > _max[i])
+ _max[i] = v[i];
+ }
+ }
+ }
+
+ inline real ComputeMeanEdgeSize()
+ {
+ _meanEdgeSize = _meanEdgeSize / _EdgeList.size();
+ return _meanEdgeSize;
+ }
+
+protected:
+ /*! Builds the face passed as argument (which as already been allocated)
+ * iVertexList
+ * List of face's vertices. These vertices are not added to the WShape vertex list; they are supposed to be
+ * already stored when calling MakeFace.
+ * The order in which the vertices are stored in the list determines the face's edges orientation and (so) the
+ * face orientation.
+ * iMaterialIndex
+ * The material index for this face
+ * face
+ * The Face that is filled in
+ */
+ virtual WFace *MakeFace(vector<WVertex *>& iVertexList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex,
+ WFace *face);
+};
+
+
+/**********************************
+ * *
+ * *
+ * WingedEdge *
+ * *
+ * *
+ **********************************/
+
+class WingedEdge
+{
+public:
+ WingedEdge() {}
+
+ ~WingedEdge()
+ {
+ clear();
+ }
+
+ void clear()
+ {
+ for (vector<WShape *>::iterator it = _wshapes.begin(); it != _wshapes.end(); it++)
+ delete *it;
+ _wshapes.clear();
+ }
+
+ void addWShape(WShape *wshape)
+ {
+ _wshapes.push_back(wshape);
+ }
+
+ vector<WShape *>& getWShapes()
+ {
+ return _wshapes;
+ }
+
+private:
+ vector<WShape *> _wshapes;
+};
+
+
+
+/*
+
+#############################################
+#############################################
+#############################################
+###### ######
+###### I M P L E M E N T A T I O N ######
+###### ######
+#############################################
+#############################################
+#############################################
+
+*/
+/* for inline functions */
+void WOEdge::RetrieveCWOrderedEdges(vector<WEdge *>& oEdges)
+{
+ WOEdge *currentOEdge = this;
+ do {
+ WOEdge *nextOEdge = currentOEdge->GetbFace()->GetNextOEdge(currentOEdge);
+ oEdges.push_back(nextOEdge->GetOwner());
+ currentOEdge = nextOEdge->GetOwner()->GetOtherOEdge(nextOEdge);
+ } while (currentOEdge && (currentOEdge->GetOwner() != GetOwner()));
+}
+
+inline void WOEdge::setVecAndAngle()
+{
+ if (_paVertex && _pbVertex) {
+ _vec = _pbVertex->GetVertex() - _paVertex->GetVertex();
+ if (_paFace && _pbFace) {
+ real sine = (_pbFace->GetNormal() ^ _paFace->GetNormal()) * _vec / _vec.norm();
+ if (sine >= 1.0) {
+ _angle = M_PI / 2.0;
+ return;
+ }
+ if (sine <= -1.0) {
+ _angle = -M_PI / 2.0;
+ return;
+ }
+ _angle = ::asin(sine);
+ }
+ }
+}
+
+#endif // __FREESTYLE_W_EDGE_H__ \ No newline at end of file
diff --git a/source/blender/freestyle/intern/winged_edge/WFillGrid.cpp b/source/blender/freestyle/intern/winged_edge/WFillGrid.cpp
new file mode 100644
index 00000000000..8b446791efc
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/WFillGrid.cpp
@@ -0,0 +1,68 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/winged_edge/WFillGrid.cpp
+ * \ingroup freestyle
+ * \brief Class to fill in a grid from a SceneGraph (uses only the WingedEdge structures)
+ * \author Emmanuel Turquin
+ * \author Stephane Grabli
+ * \date 03/05/2003
+ */
+
+#include "WEdge.h"
+#include "WFillGrid.h"
+
+void WFillGrid::fillGrid()
+{
+ if (!_winged_edge || !_grid)
+ return;
+
+ vector<WShape *> wshapes = _winged_edge->getWShapes();
+ vector<WVertex *> fvertices;
+ vector<Vec3r> vectors;
+ vector<WFace *> faces;
+
+ for (vector<WShape *>::const_iterator it = wshapes.begin(); it != wshapes.end(); ++it) {
+ faces = (*it)->GetFaceList();
+
+ for (vector<WFace *>::const_iterator f = faces.begin(); f != faces.end(); ++f) {
+ (*f)->RetrieveVertexList(fvertices);
+
+ for (vector<WVertex*>::const_iterator wv = fvertices.begin(); wv != fvertices.end(); ++wv)
+ vectors.push_back(Vec3r((*wv)->GetVertex()));
+
+ // occluder will be deleted by the grid
+ Polygon3r *occluder = new Polygon3r(vectors, (*f)->GetNormal());
+ occluder->setId(_polygon_id++);
+ occluder->userdata = (void *)(*f);
+ _grid->insertOccluder(occluder);
+ vectors.clear();
+ fvertices.clear();
+ }
+ faces.clear();
+ }
+} \ No newline at end of file
diff --git a/source/blender/freestyle/intern/winged_edge/WFillGrid.h b/source/blender/freestyle/intern/winged_edge/WFillGrid.h
new file mode 100644
index 00000000000..223c5a786d8
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/WFillGrid.h
@@ -0,0 +1,88 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_W_FILL_GRID_H__
+#define __FREESTYLE_W_FILL_GRID_H__
+
+/** \file blender/freestyle/intern/winged_edge/WFillGrid.h
+ * \ingroup freestyle
+ * \brief Class to fill in a grid from a SceneGraph (uses only the WingedEdge structures)
+ * \author Emmanuel Turquin
+ * \author Stephane Grabli
+ * \date 03/05/2003
+ */
+
+#include "WEdge.h"
+
+#include "../geometry/Grid.h"
+#include "../geometry/Polygon.h"
+
+class LIB_WINGED_EDGE_EXPORT WFillGrid
+{
+public:
+ inline WFillGrid(Grid *grid = NULL, WingedEdge *winged_edge = NULL)
+ {
+ _winged_edge = winged_edge;
+ _grid = grid;
+ _polygon_id = 0;
+ }
+
+ virtual ~WFillGrid() {}
+
+ void fillGrid();
+
+ /*! Accessors */
+ WingedEdge *getWingedEdge()
+ {
+ return _winged_edge;
+ }
+
+ Grid *getGrid()
+ {
+ return _grid;
+ }
+
+ /*! Modifiers */
+ void setWingedEdge(WingedEdge *winged_edge)
+ {
+ if (winged_edge)
+ _winged_edge = winged_edge;
+ }
+
+ void setGrid(Grid *grid)
+ {
+ if (grid)
+ _grid = grid;
+ }
+
+private:
+ Grid *_grid;
+ WingedEdge *_winged_edge;
+ unsigned _polygon_id;
+};
+
+#endif // __FREESTYLE_W_FILL_GRID_H__ \ No newline at end of file
diff --git a/source/blender/freestyle/intern/winged_edge/WSFillGrid.cpp b/source/blender/freestyle/intern/winged_edge/WSFillGrid.cpp
new file mode 100644
index 00000000000..3504a8ab179
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/WSFillGrid.cpp
@@ -0,0 +1,67 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/winged_edge/WSFillGrid.cpp
+ * \ingroup freestyle
+ * \brief Class to fill in a grid from a SceneGraph (uses only the WingedEdge structures)
+ * \author Stephane Grabli
+ * \date 03/05/2003
+ */
+
+#include "WEdge.h"
+#include "WSFillGrid.h"
+
+void WSFillGrid::fillGrid()
+{
+ if (!_winged_edge || !_grid)
+ return;
+
+ vector<WShape *> wshapes = _winged_edge->getWShapes();
+ vector<WVertex *> fvertices;
+ vector<Vec3r> vectors;
+ vector<WFace *> faces;
+
+ for (vector<WShape *>::const_iterator it = wshapes.begin(); it != wshapes.end(); ++it) {
+ faces = (*it)->GetFaceList();
+
+ for (vector<WFace *>::const_iterator f = faces.begin(); f != faces.end(); ++f) {
+ (*f)->RetrieveVertexList(fvertices);
+
+ for (vector<WVertex*>::const_iterator wv = fvertices.begin(); wv != fvertices.end(); ++wv)
+ vectors.push_back(Vec3r((*wv)->GetVertex()));
+
+ // occluder will be deleted by the grid
+ Polygon3r *occluder = new Polygon3r(vectors, (*f)->GetNormal());
+ occluder->setId(_polygon_id++);
+ occluder->userdata = (void *)(*f);
+ _grid->insertOccluder(occluder);
+ vectors.clear();
+ fvertices.clear();
+ }
+ faces.clear();
+ }
+} \ No newline at end of file
diff --git a/source/blender/freestyle/intern/winged_edge/WSFillGrid.h b/source/blender/freestyle/intern/winged_edge/WSFillGrid.h
new file mode 100644
index 00000000000..55bedd83cce
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/WSFillGrid.h
@@ -0,0 +1,87 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_WS_FILL_GRID_H__
+#define __FREESTYLE_WS_FILL_GRID_H__
+
+/** \file blender/freestyle/intern/winged_edge/WSFillGrid.h
+ * \ingroup freestyle
+ * \brief Class to fill in a grid from a SceneGraph (uses only the WingedEdge structures)
+ * \author Stephane Grabli
+ * \date 03/05/2003
+ */
+
+#include "WEdge.h"
+
+#include "../geometry/Grid.h"
+#include "../geometry/Polygon.h"
+
+class LIB_WINGED_EDGE_EXPORT WSFillGrid
+{
+public:
+ inline WSFillGrid(Grid *grid = NULL, WingedEdge *winged_edge = NULL)
+ {
+ _winged_edge = winged_edge;
+ _grid = grid;
+ _polygon_id = 0;
+ }
+
+ virtual ~WSFillGrid() {}
+
+ void fillGrid();
+
+ /*! Accessors */
+ WingedEdge *getWingedEdge()
+ {
+ return _winged_edge;
+ }
+
+ Grid *getGrid()
+ {
+ return _grid;
+ }
+
+ /*! Modifiers */
+ void setWingedEdge(WingedEdge *winged_edge)
+ {
+ if (winged_edge)
+ _winged_edge = winged_edge;
+ }
+
+ void setGrid(Grid *grid)
+ {
+ if (grid)
+ _grid = grid;
+ }
+
+private:
+ Grid *_grid;
+ WingedEdge *_winged_edge;
+ unsigned _polygon_id;
+};
+
+#endif // __FREESTYLE_WS_FILL_GRID_H__ \ No newline at end of file
diff --git a/source/blender/freestyle/intern/winged_edge/WXEdge.cpp b/source/blender/freestyle/intern/winged_edge/WXEdge.cpp
new file mode 100644
index 00000000000..719ed10925d
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/WXEdge.cpp
@@ -0,0 +1,301 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/winged_edge/WXEdge.cpp
+ * \ingroup freestyle
+ * \brief Classes to define an Extended Winged Edge data structure.
+ * \author Stephane Grabli
+ * \date 26/10/2003
+ */
+
+#include "WXEdge.h"
+#include "BKE_global.h"
+
+/**********************************
+ * *
+ * *
+ * WXFace *
+ * *
+ * *
+ **********************************/
+
+unsigned int WXFaceLayer::Get0VertexIndex() const
+{
+ int i = 0;
+ int nEdges = _pWXFace->numberOfEdges();
+ for (i = 0; i < nEdges; ++i) {
+ if (_DotP[i] == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+unsigned int WXFaceLayer::GetSmoothEdgeIndex() const
+{
+ int i = 0;
+ int nEdges = _pWXFace->numberOfEdges();
+ for (i = 0; i < nEdges; ++i) {
+ if ((_DotP[i] == 0) && (_DotP[(i+1)%nEdges] == 0)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void WXFaceLayer::RetrieveCuspEdgesIndices(vector<int>& oCuspEdges)
+{
+ int i = 0;
+ int nEdges = _pWXFace->numberOfEdges();
+ for (i = 0; i < nEdges; ++i) {
+ if (_DotP[i] * _DotP[(i + 1) % nEdges] < 0) {
+ // we got one
+ oCuspEdges.push_back(i);
+ }
+ }
+}
+
+WXSmoothEdge *WXFaceLayer::BuildSmoothEdge()
+{
+ // if the smooth edge has already been built: exit
+ if (_pSmoothEdge)
+ return _pSmoothEdge;
+ real ta, tb;
+ WOEdge *woea(0), *woeb(0);
+ bool ok = false;
+ vector<int> cuspEdgesIndices;
+ int indexStart, indexEnd;
+ unsigned nedges = _pWXFace->numberOfEdges();
+ if (_nNullDotP == nedges) {
+ _pSmoothEdge = NULL;
+ return _pSmoothEdge;
+ }
+ if ((_nPosDotP != 0) && (_nPosDotP != _DotP.size()) && (_nNullDotP == 0)) {
+ // that means that we have a smooth edge that starts from an edge and ends at an edge
+ //-----------------------------
+ // We retrieve the 2 edges for which we have opposite signs for each extremity
+ RetrieveCuspEdgesIndices(cuspEdgesIndices);
+ if (cuspEdgesIndices.size() != 2) // we necessarly have 2 cusp edges
+ return 0;
+
+ // let us determine which cusp edge corresponds to the starting:
+ // We can do that because we defined that a silhouette edge had the back facing part on its right.
+ // So if the WOEdge woea is such that woea[0].dotp > 0 and woea[1].dotp < 0, it is the starting edge.
+ //-------------------------------------------
+
+ if (_DotP[cuspEdgesIndices[0]] > 0) {
+ woea = _pWXFace->GetOEdge(cuspEdgesIndices[0]);
+ woeb = _pWXFace->GetOEdge(cuspEdgesIndices[1]);
+ indexStart = cuspEdgesIndices[0];
+ indexEnd = cuspEdgesIndices[1];
+ }
+ else {
+ woea = _pWXFace->GetOEdge(cuspEdgesIndices[1]);
+ woeb = _pWXFace->GetOEdge(cuspEdgesIndices[0]);
+ indexStart = cuspEdgesIndices[1];
+ indexEnd = cuspEdgesIndices[0];
+ }
+
+ // Compute the interpolation:
+ ta = _DotP[indexStart] / (_DotP[indexStart] - _DotP[(indexStart + 1) % nedges]);
+ tb = _DotP[indexEnd] / (_DotP[indexEnd] - _DotP[(indexEnd + 1) % nedges]);
+ ok = true;
+ }
+ else if (_nNullDotP == 1) {
+ // that means that we have exactly one of the 2 extremities of our silhouette edge is a vertex of the mesh
+ if ((_nPosDotP == 2) || (_nPosDotP == 0)) {
+ _pSmoothEdge = NULL;
+ return _pSmoothEdge;
+ }
+ RetrieveCuspEdgesIndices(cuspEdgesIndices);
+ // We should have only one EdgeCusp:
+ if (cuspEdgesIndices.size() != 1) {
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ cout << "Warning in BuildSmoothEdge: weird WXFace configuration" << endl;
+ }
+ _pSmoothEdge = NULL;
+ return NULL;
+ }
+ unsigned index0 = Get0VertexIndex(); // retrieve the 0 vertex index
+ unsigned nedges = _pWXFace->numberOfEdges();
+ if (_DotP[cuspEdgesIndices[0]] > 0) {
+ woea = _pWXFace->GetOEdge(cuspEdgesIndices[0]);
+ woeb = _pWXFace->GetOEdge(index0);
+ indexStart = cuspEdgesIndices[0];
+ ta = _DotP[indexStart] / (_DotP[indexStart] - _DotP[(indexStart + 1) % nedges]);
+ tb = 0.0;
+ }
+ else {
+ woea = _pWXFace->GetOEdge(index0);
+ woeb = _pWXFace->GetOEdge(cuspEdgesIndices[0]);
+ indexEnd = cuspEdgesIndices[0];
+ ta = 0.0;
+ tb = _DotP[indexEnd] / (_DotP[indexEnd] - _DotP[(indexEnd + 1) % nedges]);
+ }
+ ok = true;
+ }
+ else if (_nNullDotP == 2) {
+ // that means that the silhouette edge is an edge of the mesh
+ int index = GetSmoothEdgeIndex();
+ if (!_pWXFace->front()) { // is it in the right order ?
+ // the order of the WOEdge index is wrong
+ woea = _pWXFace->GetOEdge((index + 1) % nedges);
+ woeb = _pWXFace->GetOEdge((index - 1) % nedges);
+ ta = 0;
+ tb = 1;
+ ok = true;
+ }
+ else {
+ // here it's not good, our edge is a single point -> skip that face
+ ok = false;
+#if 0
+ // the order of the WOEdge index is good
+ woea = _pWXFace->GetOEdge((index - 1) % nedges);
+ woeb = _pWXFace->GetOEdge((index + 1) % nedges);
+ ta = 1;
+ tb = 0;
+#endif
+ }
+ }
+ if (ok) {
+ _pSmoothEdge = new WXSmoothEdge;
+ _pSmoothEdge->setWOeA(woea);
+ _pSmoothEdge->setWOeB(woeb);
+ _pSmoothEdge->setTa(ta);
+ _pSmoothEdge->setTb(tb);
+ if (_Nature & Nature::SILHOUETTE) {
+ if (_nNullDotP != 2) {
+ if (_DotP[_ClosestPointIndex] + 0.01 > 0)
+ _pSmoothEdge->setFront(true);
+ else
+ _pSmoothEdge->setFront(false);
+ }
+ }
+ }
+
+#if 0
+ // check bording edges to see if they have different dotp values in bording faces.
+ for (int i = 0; i < numberOfEdges(); i++) {
+ WSFace *bface = (WSFace *)GetBordingFace(i);
+ if (bface) {
+ if ((front()) ^ (bface->front())) { // fA->front XOR fB->front (true if one is 0 and the other is 1)
+ // that means that the edge i of the face is a silhouette edge
+ // CHECK FIRST WHETHER THE EXACTSILHOUETTEEDGE HAS NOT YET BEEN BUILT ON THE OTHER FACE (1 is enough).
+ if (((WSExactFace *)bface)->exactSilhouetteEdge()) {
+ // that means that this silhouette edge has already been built
+ return ((WSExactFace *)bface)->exactSilhouetteEdge();
+ }
+ // Else we must build it
+ WOEdge *woea, *woeb;
+ real ta, tb;
+ if (!front()) { // is it in the right order ?
+ // the order of the WOEdge index is wrong
+ woea = _OEdgeList[(i + 1) % numberOfEdges()];
+ if (0 == i)
+ woeb = _OEdgeList[numberOfEdges() - 1];
+ else
+ woeb = _OEdgeList[(i - 1)];
+ ta = 0;
+ tb = 1;
+ }
+ else {
+ // the order of the WOEdge index is good
+ if (0 == i)
+ woea = _OEdgeList[numberOfEdges() - 1];
+ else
+ woea = _OEdgeList[(i - 1)];
+ woeb = _OEdgeList[(i + 1) % numberOfEdges()];
+ ta = 1;
+ tb = 0;
+ }
+
+ _pSmoothEdge = new ExactSilhouetteEdge(ExactSilhouetteEdge::VERTEX_VERTEX);
+ _pSmoothEdge->setWOeA(woea);
+ _pSmoothEdge->setWOeA(woeb);
+ _pSmoothEdge->setTa(ta);
+ _pSmoothEdge->setTb(tb);
+
+ return _pSmoothEdge;
+ }
+ }
+ }
+#endif
+ return _pSmoothEdge;
+}
+
+
+void WXFace::ComputeCenter()
+{
+ vector<WVertex *> iVertexList;
+ RetrieveVertexList(iVertexList);
+ Vec3r center;
+ for (vector<WVertex *>::iterator wv = iVertexList.begin(), wvend = iVertexList.end(); wv != wvend; ++wv) {
+ center += (*wv)->GetVertex();
+ }
+ center /= (real)iVertexList.size();
+ setCenter(center);
+}
+
+/**********************************
+ * *
+ * *
+ * WXShape *
+ * *
+ * *
+ **********************************/
+
+WFace *WXShape::MakeFace(vector<WVertex *>& iVertexList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex)
+{
+ WFace *face = WShape::MakeFace(iVertexList, iFaceEdgeMarksList, iMaterialIndex);
+ if (!face)
+ return NULL;
+
+ Vec3r center;
+ for (vector<WVertex *>::iterator wv = iVertexList.begin(), wvend = iVertexList.end(); wv != wvend; ++wv) {
+ center += (*wv)->GetVertex();
+ }
+ center /= (real)iVertexList.size();
+ ((WXFace *)face)->setCenter(center);
+
+ return face;
+}
+
+WFace *WXShape::MakeFace(vector<WVertex *>& iVertexList, vector<Vec3r>& iNormalsList, vector<Vec2r>& iTexCoordsList,
+ vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex)
+{
+ WFace *face = WShape::MakeFace(iVertexList, iNormalsList, iTexCoordsList, iFaceEdgeMarksList, iMaterialIndex);
+
+#if 0
+ Vec3r center;
+ for (vector<WVertex *>::iterator wv = iVertexList.begin(), wvend = iVertexList.end(); wv != wvend; ++wv) {
+ center += (*wv)->GetVertex();
+ }
+ center /= (real)iVertexList.size();
+ ((WSFace *)face)->setCenter(center);
+#endif
+
+ return face;
+} \ No newline at end of file
diff --git a/source/blender/freestyle/intern/winged_edge/WXEdge.h b/source/blender/freestyle/intern/winged_edge/WXEdge.h
new file mode 100644
index 00000000000..9f3522e4e70
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/WXEdge.h
@@ -0,0 +1,809 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_WX_EDGE_H__
+#define __FREESTYLE_WX_EDGE_H__
+
+/** \file blender/freestyle/intern/winged_edge/WXEdge.h
+ * \ingroup freestyle
+ * \brief Classes to define an Extended Winged Edge data structure.
+ * \author Stephane Grabli
+ * \date 26/10/2003
+ */
+
+#include "Curvature.h"
+#include "Nature.h"
+#include "WEdge.h"
+
+typedef Nature::EdgeNature WXNature;
+
+/**********************************
+ * *
+ * *
+ * WXVertex *
+ * *
+ * *
+ **********************************/
+
+class WXVertex : public WVertex
+{
+private:
+ // Curvature info
+ CurvatureInfo *_curvatures;
+
+public:
+ inline WXVertex(const Vec3r &v) : WVertex(v)
+ {
+ _curvatures = NULL;
+ }
+
+ /*! Copy constructor */
+ WXVertex(WXVertex& iBrother) : WVertex(iBrother)
+ {
+ _curvatures = new CurvatureInfo(*iBrother._curvatures);
+ }
+
+ virtual WVertex *duplicate()
+ {
+ WXVertex *clone = new WXVertex(*this);
+ return clone;
+ }
+
+ virtual ~WXVertex()
+ {
+ if (_curvatures)
+ delete _curvatures;
+ }
+
+ virtual void Reset()
+ {
+ if (_curvatures)
+ _curvatures->Kr = 0.0;
+ }
+
+ inline void setCurvatures(CurvatureInfo *ci)
+ {
+ _curvatures = ci;
+ }
+
+ inline bool isFeature();
+
+ inline CurvatureInfo *curvatures()
+ {
+ return _curvatures;
+ }
+};
+
+
+/**********************************
+ * *
+ * *
+ * WXEdge *
+ * *
+ * *
+ **********************************/
+
+class WXEdge : public WEdge
+{
+private:
+ // flag to indicate whether the edge is a silhouette edge or not
+ WXNature _nature;
+ // 0: the order doesn't matter. 1: the order is the orginal one. -1: the order is not good
+ int _order;
+ // A front facing edge is an edge for which the bording face which is the nearest from the viewpoint is front.
+ // A back facing edge is the opposite.
+ bool _front;
+
+public:
+ inline WXEdge() : WEdge()
+ {
+ _nature = Nature::NO_FEATURE;
+ _front = false;
+ _order = 0;
+ }
+
+ inline WXEdge(WOEdge *iOEdge) : WEdge(iOEdge)
+ {
+ _nature = Nature::NO_FEATURE;
+ _front = false;
+ _order = 0;
+ }
+
+ inline WXEdge(WOEdge *iaOEdge, WOEdge *ibOEdge) : WEdge(iaOEdge, ibOEdge)
+ {
+ _nature = Nature::NO_FEATURE;
+ _front = false;
+ _order = 0;
+ }
+
+ /*! Copy constructor */
+ inline WXEdge(WXEdge& iBrother) : WEdge(iBrother)
+ {
+ _nature = iBrother.nature();
+ _front = iBrother._front;
+ _order = iBrother._order;
+ }
+
+ virtual WEdge *duplicate()
+ {
+ WXEdge *clone = new WXEdge(*this);
+ return clone;
+ }
+
+ virtual ~WXEdge() {}
+
+ virtual void Reset()
+ {
+ _nature = _nature & ~Nature::SILHOUETTE;
+ _nature = _nature & ~Nature::SUGGESTIVE_CONTOUR;
+ }
+
+ /*! accessors */
+ inline WXNature nature()
+ {
+ return _nature;
+ }
+
+ inline bool front()
+ {
+ return _front;
+ }
+
+ inline int order() const
+ {
+ return _order;
+ }
+
+ /*! modifiers */
+ inline void setFront(bool iFront)
+ {
+ _front = iFront;
+ }
+
+ inline void setNature(WXNature iNature)
+ {
+ _nature = iNature;
+ }
+
+ inline void AddNature(WXNature iNature)
+ {
+ _nature = _nature | iNature;
+ }
+
+ inline void setOrder(int i)
+ {
+ _order = i;
+ }
+};
+
+/**********************************
+ * *
+ * *
+ * WXFace *
+ * *
+ * *
+ **********************************/
+
+/*! Class to store a smooth edge (i.e Hertzman & Zorin smooth silhouette edges) */
+class WXSmoothEdge
+{
+public:
+ typedef enum {
+ EDGE_EDGE,
+ VERTEX_EDGE,
+ EDGE_VERTEX,
+ } Configuration;
+
+ WOEdge *_woea; // Oriented edge from which the silhouette edge starts
+ WOEdge *_woeb; // Oriented edge where the silhouette edge ends
+ real _ta; // The silhouette starting point's coordinates are : _woea[0]+ta*(_woea[1]-_woea[0])
+ real _tb; // The silhouette ending point's coordinates are : _woeb[0]+ta*(_woeb[1]-_woeb[0])
+ bool _front;
+ Configuration _config;
+
+ WXSmoothEdge()
+ {
+ _woea = NULL;
+ _woeb = NULL;
+ _ta = 0;
+ _tb = 0;
+ _front = false;
+ _config = EDGE_EDGE;
+ }
+
+ WXSmoothEdge(const WXSmoothEdge& iBrother)
+ {
+ _woea = iBrother._woea;
+ _woeb = iBrother._woeb;
+ _ta = iBrother._ta;
+ _tb = iBrother._tb;
+ _config = iBrother._config;
+ _front = iBrother._front;
+ }
+
+ ~WXSmoothEdge() {}
+
+ inline WOEdge *woea()
+ {
+ return _woea;
+ }
+
+ inline WOEdge *woeb()
+ {
+ return _woeb;
+ }
+
+ inline real ta() const
+ {
+ return _ta;
+ }
+
+ inline real tb() const
+ {
+ return _tb;
+ }
+
+ inline bool front() const
+ {
+ return _front;
+ }
+
+ inline Configuration configuration() const
+ {
+ return _config;
+ }
+
+ /*! modifiers */
+ inline void setWOeA(WOEdge *iwoea)
+ {
+ _woea = iwoea;
+ }
+
+ inline void setWOeB(WOEdge *iwoeb)
+ {
+ _woeb = iwoeb;
+ }
+
+ inline void setTa(real ta)
+ {
+ _ta = ta;
+ }
+
+ inline void setTb(real tb)
+ {
+ _tb = tb;
+ }
+
+ inline void setFront(bool iFront)
+ {
+ _front = iFront;
+ }
+
+ inline void setConfiguration(Configuration iConf)
+ {
+ _config = iConf;
+ }
+};
+
+/* Class to store a value per vertex and a smooth edge.
+ * The WXFace stores a list of these
+ */
+class WXFace;
+
+class LIB_WINGED_EDGE_EXPORT WXFaceLayer
+{
+public:
+ void *userdata;
+ WXFace *_pWXFace;
+ // in case of silhouette: the values obtained when computing the normal-view direction dot product. _DotP[i] is
+ // this value for the vertex i for that face.
+ vector<real> _DotP;
+ WXSmoothEdge *_pSmoothEdge;
+ WXNature _Nature;
+
+ //oldtmp values
+ // count the number of positive dot products for vertices.
+ // if this number is != 0 and !=_DotP.size() -> it is a silhouette fac
+ unsigned _nPosDotP;
+
+ unsigned _nNullDotP; // count the number of null dot products for vertices.
+ unsigned _ClosestPointIndex;
+ bool _viewDependant;
+
+ WXFaceLayer(WXFace *iFace, WXNature iNature, bool viewDependant)
+ {
+ _pWXFace = iFace;
+ _pSmoothEdge = NULL;
+ _nPosDotP = 0;
+ _nNullDotP = 0;
+ _Nature = iNature;
+ _viewDependant = viewDependant;
+ userdata = NULL;
+ }
+
+ WXFaceLayer(const WXFaceLayer& iBrother)
+ {
+ _pWXFace = iBrother._pWXFace;
+ _pSmoothEdge = NULL;
+ _DotP = iBrother._DotP;
+ _nPosDotP = iBrother._nPosDotP;
+ _nNullDotP = iBrother._nNullDotP;
+ _Nature = iBrother._Nature;
+ if (iBrother._pSmoothEdge) { // XXX ? It's set to null a few lines above!
+ _pSmoothEdge = new WXSmoothEdge(*(iBrother._pSmoothEdge));
+ }
+ _viewDependant = iBrother._viewDependant;
+ userdata = NULL;
+ }
+
+ virtual ~WXFaceLayer()
+ {
+ if (!_DotP.empty())
+ _DotP.clear();
+ if (_pSmoothEdge) {
+ delete _pSmoothEdge;
+ _pSmoothEdge = NULL;
+ }
+ }
+
+ inline const real dotP(int i) const
+ {
+ return _DotP[i];
+ }
+
+ inline unsigned nPosDotP() const
+ {
+ return _nPosDotP;
+ }
+
+ inline unsigned nNullDotP() const
+ {
+ return _nNullDotP;
+ }
+
+ inline int closestPointIndex() const
+ {
+ return _ClosestPointIndex;
+ }
+
+ inline Nature::EdgeNature nature() const
+ {
+ return _Nature;
+ }
+
+ inline bool hasSmoothEdge() const
+ {
+ if (_pSmoothEdge)
+ return true;
+ return false;
+ }
+
+ inline WXFace *getFace()
+ {
+ return _pWXFace;
+ }
+
+ inline WXSmoothEdge *getSmoothEdge()
+ {
+ return _pSmoothEdge;
+ }
+
+ inline bool isViewDependant() const
+ {
+ return _viewDependant;
+ }
+
+ inline void setClosestPointIndex(int iIndex)
+ {
+ _ClosestPointIndex = iIndex;
+ }
+
+ inline void removeSmoothEdge()
+ {
+ if (!_DotP.empty())
+ _DotP.clear();
+ if (_pSmoothEdge) {
+ delete _pSmoothEdge;
+ _pSmoothEdge = NULL;
+ }
+ }
+
+ /*! If one of the face layer vertex has a DotP equal to 0, this method returns the vertex where it happens */
+ unsigned int Get0VertexIndex() const;
+
+ /*! In case one of the edge of the triangle is a smooth edge, this method allows to retrieve the concerned edge */
+ unsigned int GetSmoothEdgeIndex() const;
+
+ /*! retrieves the edges of the triangle for which the signs are different (a null value is not considered) for
+ * the dotp values at each edge extrimity
+ */
+ void RetrieveCuspEdgesIndices(vector<int>& oCuspEdges);
+
+ WXSmoothEdge *BuildSmoothEdge();
+
+ inline void setDotP(const vector<real>& iDotP)
+ {
+ _DotP = iDotP;
+ }
+
+ inline void PushDotP(real iDotP)
+ {
+ _DotP.push_back(iDotP);
+ if (iDotP > 0)
+ ++_nPosDotP;
+ if (iDotP == 0)
+ ++_nNullDotP;
+ }
+
+ inline void ReplaceDotP(unsigned int index, real newDotP)
+ {
+ _DotP[index] = newDotP;
+ updateDotPInfos();
+ }
+
+ inline void updateDotPInfos()
+ {
+ _nPosDotP = 0;
+ _nNullDotP = 0;
+ for (vector<real>::iterator d = _DotP.begin(), dend = _DotP.end(); d != dend; ++d) {
+ if ((*d) > 0)
+ ++_nPosDotP;
+ if ((*d) == 0)
+ ++_nNullDotP;
+ }
+ }
+};
+
+class WXFace : public WFace
+{
+protected:
+ Vec3r _center; // center of the face
+ real _Z; // distance from viewpoint to the center of the face
+ bool _front; // flag to tell whether the face is front facing or back facing
+ real _dotp; // value obtained when computing the normal-viewpoint dot product
+
+ vector<WXFaceLayer *> _SmoothLayers; // The data needed to store one or several smooth edges that traverse the face
+
+public:
+ inline WXFace() : WFace()
+ {
+ _Z = 0.0;
+ _front = false;
+ }
+
+ /*! Copy constructor */
+ WXFace(WXFace& iBrother) : WFace(iBrother)
+ {
+ _center = iBrother.center();
+ _Z = iBrother.Z();
+ _front = iBrother.front();
+ for (vector<WXFaceLayer*>::iterator wxf = iBrother._SmoothLayers.begin(), wxfend = iBrother._SmoothLayers.end();
+ wxf != wxfend;
+ ++wxf)
+ {
+ _SmoothLayers.push_back(new WXFaceLayer(**wxf));
+ }
+ }
+
+ virtual WFace *duplicate()
+ {
+ WXFace *clone = new WXFace(*this);
+ return clone;
+ }
+
+ virtual ~WXFace()
+ {
+ if (!_SmoothLayers.empty()) {
+ for (vector<WXFaceLayer*>::iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
+ wxf != wxfend;
+ ++wxf)
+ {
+ delete (*wxf);
+ }
+ _SmoothLayers.clear();
+ }
+ }
+
+ /*! designed to build a specialized WEdge for use in MakeEdge */
+ virtual WEdge *instanciateEdge() const
+ {
+ return new WXEdge;
+ }
+
+ /*! accessors */
+ inline Vec3r& center()
+ {
+ return _center;
+ }
+
+ inline real Z()
+ {
+ return _Z;
+ }
+
+ inline bool front()
+ {
+ return _front;
+ }
+
+ inline real dotp()
+ {
+ return _dotp;
+ }
+
+ inline bool hasSmoothEdges() const
+ {
+ for (vector<WXFaceLayer*>::const_iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
+ wxf != wxfend;
+ ++wxf)
+ {
+ if ((*wxf)->hasSmoothEdge()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ vector<WXFaceLayer*>& getSmoothLayers()
+ {
+ return _SmoothLayers;
+ }
+
+ /*! retrieve the smooth edges that match the Nature given as argument */
+ void retrieveSmoothEdges(WXNature iNature, vector<WXSmoothEdge *>& oSmoothEdges)
+ {
+ for (vector<WXFaceLayer *>::iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
+ wxf != wxfend;
+ ++wxf)
+ {
+ if ((*wxf)->hasSmoothEdge() && ((*wxf)->_Nature & iNature)) {
+ oSmoothEdges.push_back((*wxf)->_pSmoothEdge);
+ }
+ }
+ }
+
+ void retrieveSmoothEdgesLayers(WXNature iNature, vector<WXFaceLayer *>& oSmoothEdgesLayers)
+ {
+ for (vector<WXFaceLayer *>::iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
+ wxf != wxfend;
+ ++wxf)
+ {
+ if ((*wxf)->hasSmoothEdge() && ((*wxf)->_Nature & iNature)) {
+ oSmoothEdgesLayers.push_back((*wxf));
+ }
+ }
+ }
+
+ void retrieveSmoothLayers(WXNature iNature, vector<WXFaceLayer *>& oSmoothLayers)
+ {
+ for (vector<WXFaceLayer *>::iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
+ wxf != wxfend;
+ ++wxf)
+ {
+ if ((*wxf)->_Nature & iNature) {
+ oSmoothLayers.push_back(*wxf);
+ }
+ }
+ }
+
+ /*! modifiers */
+ inline void setCenter(const Vec3r& iCenter)
+ {
+ _center = iCenter;
+ }
+
+ void ComputeCenter();
+
+ inline void setZ(real z)
+ {
+ _Z = z;
+ }
+
+ inline void setFront(bool iFront)
+ {
+ _front = iFront;
+ }
+
+ inline void setDotP(real iDotP)
+ {
+ _dotp = iDotP;
+ if (_dotp > 0)
+ _front = true;
+ else
+ _front = false;
+ }
+
+ inline void AddSmoothLayer(WXFaceLayer *iLayer)
+ {
+ _SmoothLayers.push_back(iLayer);
+ }
+
+ inline void Reset()
+ {
+ vector<WXFaceLayer *> layersToKeep;
+ for (vector<WXFaceLayer *>::iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
+ wxf != wxfend;
+ ++wxf)
+ {
+ if ((*wxf)->isViewDependant())
+ delete (*wxf);
+ else
+ layersToKeep.push_back(*wxf);
+ }
+ _SmoothLayers = layersToKeep;
+ }
+
+ /*! Clears everything */
+ inline void Clear()
+ {
+ for (vector<WXFaceLayer *>::iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
+ wxf != wxfend;
+ ++wxf)
+ {
+ delete (*wxf);
+ }
+ _SmoothLayers.clear();
+ }
+
+ virtual void ResetUserData()
+ {
+ WFace::ResetUserData();
+ for (vector<WXFaceLayer *>::iterator wxf = _SmoothLayers.begin(), wxfend = _SmoothLayers.end();
+ wxf != wxfend;
+ ++wxf)
+ {
+ (*wxf)->userdata = NULL;
+ }
+ }
+};
+
+
+/**********************************
+ * *
+ * *
+ * WXShape *
+ * *
+ * *
+ **********************************/
+
+class WXShape : public WShape
+{
+public:
+ typedef WXShape type_name;
+
+protected:
+ bool _computeViewIndependant; // flag to indicate whether the view independant stuff must be computed or not
+
+public:
+ inline WXShape() : WShape()
+ {
+ _computeViewIndependant = true;
+ }
+
+ /*! copy constructor */
+ inline WXShape(WXShape& iBrother) : WShape(iBrother)
+ {
+ _computeViewIndependant = iBrother._computeViewIndependant;
+ }
+
+ virtual WShape *duplicate()
+ {
+ WXShape *clone = new WXShape(*this);
+ return clone;
+ }
+
+ virtual ~WXShape() {}
+
+ inline bool getComputeViewIndependantFlag() const
+ {
+ return _computeViewIndependant;
+ }
+
+ inline void setComputeViewIndependantFlag(bool iFlag)
+ {
+ _computeViewIndependant = iFlag;
+ }
+
+ /*! designed to build a specialized WFace for use in MakeFace */
+ virtual WFace *instanciateFace() const
+ {
+ return new WXFace;
+ }
+
+ /*! adds a new face to the shape returns the built face.
+ * iVertexList
+ * List of face's vertices. These vertices are not added to the WShape vertex list; they are supposed
+ * to be already stored when calling MakeFace. The order in which the vertices are stored in the list
+ * determines the face's edges orientation and (so) the face orientation.
+ */
+ virtual WFace *MakeFace(vector<WVertex *>& iVertexList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex);
+
+ /*! adds a new face to the shape. The difference with the previous method is that this one is designed to build
+ * a WingedEdge structure for which there are per vertex normals, opposed to per face normals.
+ * returns the built face.
+ * iVertexList
+ * List of face's vertices. These vertices are not added to the WShape vertex list; they are supposed to be
+ * already stored when calling MakeFace.
+ * The order in which the vertices are stored in the list determines the face's edges orientation and (so) the
+ * face orientation.
+ * iNormalsList
+ * The list of normals, iNormalsList[i] corresponding to the normal of the vertex iVertexList[i] for that face.
+ * iTexCoordsList
+ * The list of tex coords, iTexCoordsList[i] corresponding to the normal of the vertex iVertexList[i] for
+ * that face.
+ */
+ virtual WFace *MakeFace(vector<WVertex *>& iVertexList, vector<Vec3r>& iNormalsList, vector<Vec2r>& iTexCoordsList,
+ vector<bool>& iFaceEdgeMarksList, unsigned iMaterialIndex);
+
+ /*! Reset all edges and vertices flags (which might have been set up on a previous pass) */
+ virtual void Reset()
+ {
+ // Reset Edges
+ vector<WEdge *>& wedges = getEdgeList();
+ for (vector<WEdge *>::iterator we = wedges.begin(), weend = wedges.end(); we != weend; ++we) {
+ ((WXEdge*)(*we))->Reset();
+ }
+
+ //Reset faces:
+ vector<WFace *>& wfaces = GetFaceList();
+ for (vector<WFace *>::iterator wf = wfaces.begin(), wfend = wfaces.end(); wf != wfend; ++wf) {
+ ((WXFace*)(*wf))->Reset();
+ }
+ }
+ /*! accessors */
+};
+
+/*
+
+#############################################
+#############################################
+#############################################
+###### ######
+###### I M P L E M E N T A T I O N ######
+###### ######
+#############################################
+#############################################
+#############################################
+
+*/
+/* for inline functions */
+
+bool WXVertex::isFeature()
+{
+ int counter = 0;
+ vector<WEdge *>& vedges = GetEdges();
+ for (vector<WEdge *>::iterator ve = vedges.begin(), vend = vedges.end(); ve != vend; ++ve) {
+ if (((WXEdge *)(*ve))->nature() != Nature::NO_FEATURE)
+ counter++;
+ }
+
+ if ((counter == 1) || (counter > 2))
+ return true;
+ return false;
+}
+
+#endif // __FREESTYLE_WX_EDGE_H__ \ No newline at end of file
diff --git a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
new file mode 100644
index 00000000000..51e93f34fa3
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
@@ -0,0 +1,58 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/winged_edge/WSBuilder.cpp
+ * \ingroup freestyle
+ * \brief Class inherited from WingedEdgeBuilder and designed to build a WX (WingedEdge + extended info
+ * (silhouette etc...)) structure from a polygonal model
+ * \author Stephane Grabli
+ * \date 28/05/2003
+ */
+
+#include "WXEdge.h"
+#include "WXEdgeBuilder.h"
+
+void WXEdgeBuilder::visitIndexedFaceSet(IndexedFaceSet& ifs)
+{
+ if (_pRenderMonitor && _pRenderMonitor->testBreak())
+ return;
+ WXShape *shape = new WXShape;
+ buildWShape(*shape, ifs);
+ shape->setId(ifs.getId().getFirst());
+ shape->setName(ifs.getName());
+ //ifs.setId(shape->GetId());
+}
+
+void WXEdgeBuilder::buildWVertices(WShape& shape, const real *vertices, unsigned vsize)
+{
+ WXVertex *vertex;
+ for (unsigned int i = 0; i < vsize; i += 3) {
+ vertex = new WXVertex(Vec3r(vertices[i], vertices[i + 1], vertices[i + 2]));
+ vertex->setId(i / 3);
+ shape.AddVertex(vertex);
+ }
+} \ No newline at end of file
diff --git a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.h b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.h
new file mode 100644
index 00000000000..91e9b389f7c
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.h
@@ -0,0 +1,54 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_WX_EDGE_BUILDER_H__
+#define __FREESTYLE_WX_EDGE_BUILDER_H__
+
+/** \file blender/freestyle/intern/winged_edge/WSBuilder.h
+ * \ingroup freestyle
+ * \brief Class inherited from WingedEdgeBuilder and designed to build a WX (WingedEdge + extended info
+ * (silhouette etc...)) structure from a polygonal model
+ * \author Stephane Grabli
+ * \date 28/05/2003
+ */
+
+#include "WingedEdgeBuilder.h"
+
+#include "../scene_graph/IndexedFaceSet.h"
+
+class LIB_WINGED_EDGE_EXPORT WXEdgeBuilder : public WingedEdgeBuilder
+{
+public:
+ WXEdgeBuilder() : WingedEdgeBuilder() {}
+ virtual ~WXEdgeBuilder() {}
+ VISIT_DECL(IndexedFaceSet)
+
+protected:
+ virtual void buildWVertices(WShape& shape, const real *vertices, unsigned vsize);
+};
+
+#endif // __FREESTYLE_WX_EDGE_BUILDER_H__ \ No newline at end of file
diff --git a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp
new file mode 100644
index 00000000000..4ef34bbe3ee
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp
@@ -0,0 +1,373 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp
+ * \ingroup freestyle
+ * \brief Class to render a WingedEdge data structure from a polyhedral data structure organized in nodes
+ * of a scene graph
+ * \author Stephane Grabli
+ * \date 28/05/2003
+ */
+
+#include <set>
+
+#include "WingedEdgeBuilder.h"
+
+#include "../geometry/GeomUtils.h"
+
+#include "../scene_graph/NodeShape.h"
+
+using namespace std;
+
+void WingedEdgeBuilder::visitIndexedFaceSet(IndexedFaceSet& ifs)
+{
+ if (_pRenderMonitor && _pRenderMonitor->testBreak())
+ return;
+ WShape *shape = new WShape;
+ buildWShape(*shape, ifs);
+ shape->setId(ifs.getId().getFirst());
+ //ifs.setId(shape->GetId());
+}
+
+void WingedEdgeBuilder::visitNodeShape(NodeShape& ns)
+{
+ //Sets the current material to iShapeode->material:
+ _current_frs_material = &(ns.frs_material());
+}
+
+void WingedEdgeBuilder::visitNodeTransform(NodeTransform& tn)
+{
+ if (!_current_matrix) {
+ _current_matrix = new Matrix44r(tn.matrix());
+ return;
+ }
+
+ _matrices_stack.push_back(_current_matrix);
+ Matrix44r *new_matrix = new Matrix44r(*_current_matrix * tn.matrix());
+ _current_matrix = new_matrix;
+}
+
+void WingedEdgeBuilder::visitNodeTransformAfter(NodeTransform&)
+{
+ if (_current_matrix)
+ delete _current_matrix;
+
+ if (_matrices_stack.empty()) {
+ _current_matrix = NULL;
+ return;
+ }
+
+ _current_matrix = _matrices_stack.back();
+ _matrices_stack.pop_back();
+}
+
+void WingedEdgeBuilder::buildWShape(WShape& shape, IndexedFaceSet& ifs)
+{
+ unsigned int vsize = ifs.vsize();
+ unsigned int nsize = ifs.nsize();
+ //soc unused - unsigned tsize = ifs.tsize();
+
+ const real *vertices = ifs.vertices();
+ const real *normals = ifs.normals();
+ const real *texCoords = ifs.texCoords();
+
+ real *new_vertices;
+ real *new_normals;
+
+ new_vertices = new real[vsize];
+ new_normals = new real[nsize];
+
+ // transform coordinates from local to world system
+ if (_current_matrix) {
+ transformVertices(vertices, vsize, *_current_matrix, new_vertices);
+ transformNormals(normals, nsize, *_current_matrix, new_normals);
+ }
+ else {
+ memcpy(new_vertices, vertices, vsize * sizeof(*new_vertices));
+ memcpy(new_normals, normals, nsize * sizeof(*new_normals));
+ }
+
+ const IndexedFaceSet::TRIANGLES_STYLE *faceStyle = ifs.trianglesStyle();
+
+ vector<FrsMaterial> frs_materials;
+ if (ifs.msize()) {
+ const FrsMaterial *const *mats = ifs.frs_materials();
+ for (unsigned i = 0; i < ifs.msize(); ++i)
+ frs_materials.push_back(*(mats[i]));
+ shape.setFrsMaterials(frs_materials);
+ }
+
+#if 0
+ const FrsMaterial *mat = (ifs.frs_material());
+ if (mat)
+ shape.setFrsMaterial(*mat);
+ else if (_current_frs_material)
+ shape.setFrsMaterial(*_current_frs_material);
+#endif
+ const IndexedFaceSet::FaceEdgeMark *faceEdgeMarks = ifs.faceEdgeMarks();
+
+ // sets the current WShape to shape
+ _current_wshape = &shape;
+
+ // create a WVertex for each vertex
+ buildWVertices(shape, new_vertices, vsize);
+
+ const unsigned int *vindices = ifs.vindices();
+ const unsigned int *nindices = ifs.nindices();
+ const unsigned int *tindices = NULL;
+ if (ifs.tsize()) {
+ tindices = ifs.tindices();
+ }
+
+ const unsigned int *mindices = NULL;
+ if (ifs.msize())
+ mindices = ifs.mindices();
+ const unsigned int *numVertexPerFace = ifs.numVertexPerFaces();
+ const unsigned int numfaces = ifs.numFaces();
+
+ for (unsigned int index = 0; index < numfaces; index++) {
+ switch (faceStyle[index]) {
+ case IndexedFaceSet::TRIANGLE_STRIP:
+ buildTriangleStrip(new_vertices, new_normals, frs_materials, texCoords, faceEdgeMarks, vindices,
+ nindices, mindices, tindices, numVertexPerFace[index]);
+ break;
+ case IndexedFaceSet::TRIANGLE_FAN:
+ buildTriangleFan(new_vertices, new_normals, frs_materials, texCoords, faceEdgeMarks, vindices,
+ nindices, mindices, tindices, numVertexPerFace[index]);
+ break;
+ case IndexedFaceSet::TRIANGLES:
+ buildTriangles(new_vertices, new_normals, frs_materials, texCoords, faceEdgeMarks, vindices,
+ nindices, mindices, tindices, numVertexPerFace[index]);
+ break;
+ }
+ vindices += numVertexPerFace[index];
+ nindices += numVertexPerFace[index];
+ if (mindices)
+ mindices += numVertexPerFace[index];
+ if (tindices)
+ tindices += numVertexPerFace[index];
+ faceEdgeMarks++;
+ }
+
+ delete[] new_vertices;
+ delete[] new_normals;
+
+ // compute bbox
+ shape.ComputeBBox();
+ // compute mean edge size:
+ shape.ComputeMeanEdgeSize();
+
+ // Parse the built winged-edge shape to update post-flags
+ set<Vec3r> normalsSet;
+ vector<WVertex *>& wvertices = shape.getVertexList();
+ for (vector<WVertex *>::iterator wv = wvertices.begin(), wvend = wvertices.end(); wv != wvend; ++wv) {
+ if ((*wv)->isBoundary())
+ continue;
+ if ((*wv)->GetEdges().size() == 0) // This means that the WVertex has no incoming edges... (12-Sep-2011 T.K.)
+ continue;
+ normalsSet.clear();
+ WVertex::face_iterator fit = (*wv)->faces_begin();
+ WVertex::face_iterator fitend = (*wv)->faces_end();
+ for (; fit != fitend; ++fit) {
+ WFace *face = *fit;
+ normalsSet.insert(face->GetVertexNormal(*wv));
+ if (normalsSet.size() != 1) {
+ break;
+ }
+ }
+ if (normalsSet.size() !=1 ) {
+ (*wv)->setSmooth(false);
+ }
+ }
+ // Adds the new WShape to the WingedEdge structure
+ _winged_edge->addWShape(&shape);
+}
+
+void WingedEdgeBuilder::buildWVertices(WShape& shape, const real *vertices, unsigned vsize)
+{
+ WVertex *vertex;
+ for (unsigned int i = 0; i < vsize; i += 3) {
+ vertex = new WVertex(Vec3r(vertices[i], vertices[i + 1], vertices[i + 2]));
+ vertex->setId(i / 3);
+ shape.AddVertex(vertex);
+ }
+}
+
+void WingedEdgeBuilder::buildTriangleStrip(const real *vertices, const real *normals, vector<FrsMaterial>& iMaterials,
+ const real *texCoords, const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
+ const unsigned *vindices, const unsigned *nindices, const unsigned *mindices,
+ const unsigned *tindices, const unsigned nvertices)
+{
+ unsigned nDoneVertices = 2; // number of vertices already treated
+ unsigned nTriangle = 0; // number of the triangle currently being treated
+ //int nVertex = 0; // vertex number
+
+ WShape *currentShape = _current_wshape; // the current shape being built
+ vector<WVertex *> triangleVertices;
+ vector<Vec3r> triangleNormals;
+ vector<Vec2r> triangleTexCoords;
+ vector<bool> triangleFaceEdgeMarks;
+
+ while (nDoneVertices < nvertices) {
+ //clear the vertices list:
+ triangleVertices.clear();
+ //Then rebuild it:
+ if (0 == nTriangle % 2) { // if nTriangle is even
+ triangleVertices.push_back(currentShape->getVertexList()[vindices[nTriangle] / 3]);
+ triangleVertices.push_back(currentShape->getVertexList()[vindices[nTriangle + 1] / 3]);
+ triangleVertices.push_back(currentShape->getVertexList()[vindices[nTriangle + 2] / 3]);
+
+ triangleNormals.push_back(Vec3r(normals[nindices[nTriangle]], normals[nindices[nTriangle] + 1],
+ normals[nindices[nTriangle] + 2]));
+ triangleNormals.push_back(Vec3r(normals[nindices[nTriangle + 1]], normals[nindices[nTriangle + 1] + 1],
+ normals[nindices[nTriangle + 1] + 2]));
+ triangleNormals.push_back(Vec3r(normals[nindices[nTriangle + 2]], normals[nindices[nTriangle + 2] + 1],
+ normals[nindices[nTriangle + 2] + 2]));
+
+ if (texCoords) {
+ triangleTexCoords.push_back(Vec2r(texCoords[tindices[nTriangle]], texCoords[tindices[nTriangle] + 1]));
+ triangleTexCoords.push_back(Vec2r(texCoords[tindices[nTriangle + 1]],
+ texCoords[tindices[nTriangle + 1] + 1]));
+ triangleTexCoords.push_back(Vec2r(texCoords[tindices[nTriangle + 2]],
+ texCoords[tindices[nTriangle + 2] + 1]));
+ }
+ }
+ else { // if nTriangle is odd
+ triangleVertices.push_back(currentShape->getVertexList()[vindices[nTriangle] / 3]);
+ triangleVertices.push_back(currentShape->getVertexList()[vindices[nTriangle + 2] / 3]);
+ triangleVertices.push_back(currentShape->getVertexList()[vindices[nTriangle + 1] / 3]);
+
+ triangleNormals.push_back(Vec3r(normals[nindices[nTriangle]], normals[nindices[nTriangle] + 1],
+ normals[nindices[nTriangle] + 2]));
+ triangleNormals.push_back(Vec3r(normals[nindices[nTriangle + 2]], normals[nindices[nTriangle + 2] + 1],
+ normals[nindices[nTriangle + 2] + 2]));
+ triangleNormals.push_back(Vec3r(normals[nindices[nTriangle + 1]], normals[nindices[nTriangle + 1] + 1],
+ normals[nindices[nTriangle + 1] + 2]));
+
+ if (texCoords) {
+ triangleTexCoords.push_back(Vec2r(texCoords[tindices[nTriangle]], texCoords[tindices[nTriangle] + 1]));
+ triangleTexCoords.push_back(Vec2r(texCoords[tindices[nTriangle + 2]],
+ texCoords[tindices[nTriangle + 2] + 1]));
+ triangleTexCoords.push_back(Vec2r(texCoords[tindices[nTriangle + 1]],
+ texCoords[tindices[nTriangle + 1] + 1]));
+ }
+ }
+ triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[nTriangle / 3] & IndexedFaceSet::FACE_MARK) != 0);
+ triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[nTriangle / 3] & IndexedFaceSet::EDGE_MARK_V1V2) != 0);
+ triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[nTriangle / 3] & IndexedFaceSet::EDGE_MARK_V2V3) != 0);
+ triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[nTriangle / 3] & IndexedFaceSet::EDGE_MARK_V3V1) != 0);
+ if (mindices) {
+ currentShape->MakeFace(triangleVertices, triangleNormals, triangleTexCoords, triangleFaceEdgeMarks,
+ mindices[nTriangle / 3]);
+ }
+ else {
+ currentShape->MakeFace(triangleVertices, triangleNormals, triangleTexCoords, triangleFaceEdgeMarks, 0);
+ }
+ nDoneVertices++; // with a strip, each triangle is one vertex more
+ nTriangle++;
+ }
+}
+
+void WingedEdgeBuilder::buildTriangleFan(const real *vertices, const real *normals, vector<FrsMaterial>& iMaterials,
+ const real *texCoords, const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
+ const unsigned *vindices, const unsigned *nindices, const unsigned *mindices,
+ const unsigned *tindices, const unsigned nvertices)
+{
+ // Nothing to be done
+}
+
+void WingedEdgeBuilder::buildTriangles(const real *vertices, const real *normals, vector<FrsMaterial>& iMaterials,
+ const real *texCoords, const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
+ const unsigned *vindices, const unsigned *nindices, const unsigned *mindices,
+ const unsigned *tindices, const unsigned nvertices)
+{
+ WShape *currentShape = _current_wshape; // the current shape begin built
+ vector<WVertex *> triangleVertices;
+ vector<Vec3r> triangleNormals;
+ vector<Vec2r> triangleTexCoords;
+ vector<bool> triangleFaceEdgeMarks;
+
+ // Each triplet of vertices is considered as an independent triangle
+ for (unsigned int i = 0; i < nvertices / 3; i++) {
+ triangleVertices.push_back(currentShape->getVertexList()[vindices[3 * i] / 3]);
+ triangleVertices.push_back(currentShape->getVertexList()[vindices[3 * i + 1] / 3]);
+ triangleVertices.push_back(currentShape->getVertexList()[vindices[3 * i + 2] / 3]);
+
+ triangleNormals.push_back(Vec3r(normals[nindices[3 * i]], normals[nindices[3 * i] + 1],
+ normals[nindices[3 * i] + 2]));
+ triangleNormals.push_back(Vec3r(normals[nindices[3 * i + 1]], normals[nindices[3 * i + 1] + 1],
+ normals[nindices[3 * i + 1] + 2]));
+ triangleNormals.push_back(Vec3r(normals[nindices[3 * i + 2]], normals[nindices[3 * i + 2] + 1],
+ normals[nindices[3 * i + 2] + 2]));
+
+ if (texCoords) {
+ triangleTexCoords.push_back(Vec2r(texCoords[tindices[3 * i]], texCoords[tindices[3 * i] + 1]));
+ triangleTexCoords.push_back(Vec2r(texCoords[tindices[3 * i + 1]], texCoords[tindices[3 * i + 1] + 1]));
+ triangleTexCoords.push_back(Vec2r(texCoords[tindices[3 * i + 2]], texCoords[tindices[3 * i + 2] + 1]));
+ }
+
+ triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[i] & IndexedFaceSet::FACE_MARK) != 0);
+ triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[i] & IndexedFaceSet::EDGE_MARK_V1V2) != 0);
+ triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[i] & IndexedFaceSet::EDGE_MARK_V2V3) != 0);
+ triangleFaceEdgeMarks.push_back((iFaceEdgeMarks[i] & IndexedFaceSet::EDGE_MARK_V3V1) != 0);
+ }
+ if (mindices)
+ currentShape->MakeFace(triangleVertices, triangleNormals, triangleTexCoords, triangleFaceEdgeMarks,
+ mindices[0]);
+ else
+ currentShape->MakeFace(triangleVertices, triangleNormals, triangleTexCoords, triangleFaceEdgeMarks, 0);
+}
+
+void WingedEdgeBuilder::transformVertices(const real *vertices, unsigned vsize, const Matrix44r& transform, real *res)
+{
+ const real *v = vertices;
+ real *pv = res;
+
+ for (unsigned int i = 0; i < vsize / 3; i++) {
+ HVec3r hv_tmp(v[0], v[1], v[2]);
+ HVec3r hv(transform * hv_tmp);
+ for (unsigned int j = 0; j < 3; j++)
+ pv[j] = hv[j] / hv[3];
+ v += 3;
+ pv += 3;
+ }
+}
+
+void WingedEdgeBuilder::transformNormals(const real *normals, unsigned nsize, const Matrix44r& transform, real *res)
+{
+ const real *n = normals;
+ real *pn = res;
+
+ for (unsigned int i = 0; i < nsize / 3; i++) {
+ Vec3r hn(n[0], n[1], n[2]);
+ hn = GeomUtils::rotateVector(transform, hn);
+ for (unsigned int j = 0; j < 3; j++)
+ pn[j] = hn[j];
+ n += 3;
+ pn += 3;
+ }
+} \ No newline at end of file
diff --git a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.h b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.h
new file mode 100644
index 00000000000..cf32c1191b2
--- /dev/null
+++ b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.h
@@ -0,0 +1,157 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2010 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __FREESTYLE_WINGED_EDGE_BUILDER_H__
+#define __FREESTYLE_WINGED_EDGE_BUILDER_H__
+
+/** \file blender/freestyle/intern/winged_edge/WingedEdgeBuilder.h
+ * \ingroup freestyle
+ * \brief Class to render a WingedEdge data structure from a polyhedral data structure organized in nodes
+ * of a scene graph
+ * \author Stephane Grabli
+ * \date 28/05/2003
+ */
+
+#include "WEdge.h"
+
+#include "../scene_graph/IndexedFaceSet.h"
+#include "../scene_graph/NodeTransform.h"
+#include "../scene_graph/SceneVisitor.h"
+
+#include "../system/FreestyleConfig.h"
+#include "../system/RenderMonitor.h"
+
+class LIB_WINGED_EDGE_EXPORT WingedEdgeBuilder : public SceneVisitor
+{
+public:
+ inline WingedEdgeBuilder() : SceneVisitor()
+ {
+ _current_wshape = NULL;
+ _current_frs_material = NULL;
+ _current_matrix = NULL;
+ _winged_edge = new WingedEdge; // Not deleted by the destructor
+ _pRenderMonitor = NULL;
+ }
+
+ virtual ~WingedEdgeBuilder()
+ {
+ for (vector<Matrix44r*>::iterator it = _matrices_stack.begin(); it != _matrices_stack.end(); ++it)
+ delete *it;
+ _matrices_stack.clear();
+ }
+
+ VISIT_DECL(IndexedFaceSet)
+ VISIT_DECL(NodeShape)
+ VISIT_DECL(NodeTransform)
+
+ virtual void visitNodeTransformAfter(NodeTransform&);
+
+ //
+ // Accessors
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ inline WingedEdge *getWingedEdge()
+ {
+ return _winged_edge;
+ }
+
+ inline WShape *getCurrentWShape()
+ {
+ return _current_wshape;
+ }
+
+ inline FrsMaterial *getCurrentFrsMaterial()
+ {
+ return _current_frs_material;
+ }
+
+ inline Matrix44r *getCurrentMatrix()
+ {
+ return _current_matrix;
+ }
+
+ //
+ // Modifiers
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ inline void setCurrentWShape(WShape *wshape)
+ {
+ _current_wshape = wshape;
+ }
+
+ inline void setCurrentFrsMaterial(FrsMaterial *mat)
+ {
+ _current_frs_material = mat;
+ }
+
+#if 0
+ inline void setCurrentMatrix(Matrix44r *matrix)
+ {
+ _current_matrix = matrix;
+ }
+#endif
+
+ inline void setRenderMonitor(RenderMonitor *iRenderMonitor) {
+ _pRenderMonitor = iRenderMonitor;
+ }
+
+protected:
+ virtual void buildWShape(WShape& shape, IndexedFaceSet& ifs);
+ virtual void buildWVertices(WShape& shape, const real *vertices, unsigned vsize);
+
+ RenderMonitor *_pRenderMonitor;
+
+private:
+ void buildTriangleStrip(const real *vertices, const real *normals, vector<FrsMaterial>& iMaterials,
+ const real *texCoords, const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
+ const unsigned *vindices, const unsigned *nindices, const unsigned *mindices,
+ const unsigned *tindices, const unsigned nvertices);
+
+ void buildTriangleFan(const real *vertices, const real *normals, vector<FrsMaterial>& iMaterials,
+ const real *texCoords, const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
+ const unsigned *vindices, const unsigned *nindices, const unsigned *mindices,
+ const unsigned *tindices, const unsigned nvertices);
+
+ void buildTriangles(const real *vertices, const real *normals, vector<FrsMaterial>& iMaterials,
+ const real *texCoords, const IndexedFaceSet::FaceEdgeMark *iFaceEdgeMarks,
+ const unsigned *vindices, const unsigned *nindices, const unsigned *mindices,
+ const unsigned *tindices, const unsigned nvertices);
+
+ void transformVertices(const real *vertices, unsigned vsize, const Matrix44r& transform, real *res);
+
+ void transformNormals(const real *normals, unsigned nsize, const Matrix44r& transform, real *res);
+
+ WShape *_current_wshape;
+ FrsMaterial *_current_frs_material;
+ WingedEdge *_winged_edge;
+ Matrix44r *_current_matrix;
+ vector<Matrix44r *> _matrices_stack;
+};
+
+#endif // __FREESTYLE_WINGED_EDGE_BUILDER_H__ \ No newline at end of file