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:
-rw-r--r--CMakeLists.txt3
-rw-r--r--SConstruct5
-rw-r--r--build_files/scons/config/darwin-config.py3
-rw-r--r--build_files/scons/config/freebsd7-config.py3
-rw-r--r--build_files/scons/config/freebsd8-config.py3
-rw-r--r--build_files/scons/config/freebsd9-config.py3
-rw-r--r--build_files/scons/config/linux-config.py3
-rw-r--r--build_files/scons/config/linuxcross-config.py3
-rw-r--r--build_files/scons/config/win32-mingw-config.py3
-rw-r--r--build_files/scons/config/win32-vc-config.py3
-rw-r--r--build_files/scons/config/win64-mingw-config.py3
-rw-r--r--build_files/scons/config/win64-vc-config.py3
-rw-r--r--build_files/scons/tools/Blender.py4
-rw-r--r--build_files/scons/tools/btools.py3
-rw-r--r--doc/python_api/sphinx_doc_gen.py11
-rw-r--r--[-rwxr-xr-x]extern/libmv/third_party/ceres/mkfiles.sh0
-rw-r--r--intern/cycles/blender/addon/ui.py152
-rw-r--r--[-rwxr-xr-x]release/bin/blender-softwaregl50
-rw-r--r--release/datafiles/startup.blendbin407724 -> 414132 bytes
-rw-r--r--release/scripts/freestyle/data/env_map/brown00.pngbin0 -> 22195 bytes
-rw-r--r--release/scripts/freestyle/data/env_map/gray00.pngbin0 -> 18513 bytes
-rw-r--r--release/scripts/freestyle/data/env_map/gray01.pngbin0 -> 9915 bytes
-rw-r--r--release/scripts/freestyle/data/env_map/gray02.pngbin0 -> 7197 bytes
-rw-r--r--release/scripts/freestyle/data/env_map/gray03.pngbin0 -> 16109 bytes
-rw-r--r--release/scripts/freestyle/style_modules/ChainingIterators.py731
-rw-r--r--release/scripts/freestyle/style_modules/Functions0D.py92
-rw-r--r--release/scripts/freestyle/style_modules/Functions1D.py45
-rw-r--r--release/scripts/freestyle/style_modules/PredicatesB1D.py70
-rw-r--r--release/scripts/freestyle/style_modules/PredicatesU0D.py103
-rw-r--r--release/scripts/freestyle/style_modules/PredicatesU1D.py381
-rw-r--r--release/scripts/freestyle/style_modules/anisotropic_diffusion.py74
-rw-r--r--release/scripts/freestyle/style_modules/apriori_and_causal_density.py45
-rw-r--r--release/scripts/freestyle/style_modules/apriori_density.py43
-rw-r--r--release/scripts/freestyle/style_modules/backbone_stretcher.py36
-rw-r--r--release/scripts/freestyle/style_modules/blueprint_circles.py46
-rw-r--r--release/scripts/freestyle/style_modules/blueprint_ellipses.py46
-rw-r--r--release/scripts/freestyle/style_modules/blueprint_squares.py45
-rw-r--r--release/scripts/freestyle/style_modules/cartoon.py42
-rw-r--r--release/scripts/freestyle/style_modules/contour.py42
-rw-r--r--release/scripts/freestyle/style_modules/curvature2d.py60
-rw-r--r--release/scripts/freestyle/style_modules/external_contour.py43
-rw-r--r--release/scripts/freestyle/style_modules/external_contour_sketchy.py48
-rw-r--r--release/scripts/freestyle/style_modules/external_contour_smooth.py44
-rw-r--r--release/scripts/freestyle/style_modules/extra-lines.sml3
-rw-r--r--release/scripts/freestyle/style_modules/freestyle_init.py2
-rw-r--r--release/scripts/freestyle/style_modules/haloing.py50
-rw-r--r--release/scripts/freestyle/style_modules/ignore_small_occlusions.py41
-rw-r--r--release/scripts/freestyle/style_modules/invisible_lines.py42
-rw-r--r--release/scripts/freestyle/style_modules/japanese_bigbrush.py60
-rw-r--r--release/scripts/freestyle/style_modules/logical_operators.py36
-rw-r--r--release/scripts/freestyle/style_modules/long_anisotropically_dense.py81
-rw-r--r--release/scripts/freestyle/style_modules/multiple_parameterization.py51
-rw-r--r--release/scripts/freestyle/style_modules/nature.py43
-rw-r--r--release/scripts/freestyle/style_modules/near_lines.py44
-rw-r--r--release/scripts/freestyle/style_modules/occluded_by_specific_object.py45
-rw-r--r--release/scripts/freestyle/style_modules/parameter_editor.py1317
-rw-r--r--release/scripts/freestyle/style_modules/polygonalize.py40
-rw-r--r--release/scripts/freestyle/style_modules/qi0.py41
-rw-r--r--release/scripts/freestyle/style_modules/qi0_not_external_contour.py43
-rw-r--r--release/scripts/freestyle/style_modules/qi1.py42
-rw-r--r--release/scripts/freestyle/style_modules/qi2.py42
-rw-r--r--release/scripts/freestyle/style_modules/sequentialsplit_sketchy.py68
-rw-r--r--release/scripts/freestyle/style_modules/shaders.py1344
-rw-r--r--release/scripts/freestyle/style_modules/sketchy_multiple_parameterization.py48
-rw-r--r--release/scripts/freestyle/style_modules/sketchy_topology_broken.py89
-rw-r--r--release/scripts/freestyle/style_modules/sketchy_topology_preserved.py49
-rw-r--r--release/scripts/freestyle/style_modules/split_at_highest_2d_curvatures.py41
-rw-r--r--release/scripts/freestyle/style_modules/split_at_tvertices.py42
-rw-r--r--release/scripts/freestyle/style_modules/stroke_texture.py43
-rw-r--r--release/scripts/freestyle/style_modules/suggestive.py43
-rw-r--r--release/scripts/freestyle/style_modules/thickness_fof_depth_discontinuity.py62
-rw-r--r--release/scripts/freestyle/style_modules/tipremover.py42
-rw-r--r--release/scripts/freestyle/style_modules/tvertex_remover.py42
-rw-r--r--release/scripts/freestyle/style_modules/uniformpruning_zsort.py40
-rw-r--r--release/scripts/startup/bl_operators/__init__.py14
-rw-r--r--release/scripts/startup/bl_operators/freestyle.py134
-rw-r--r--release/scripts/startup/bl_ui/__init__.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py160
-rw-r--r--release/scripts/startup/bl_ui/properties_render_layer.py782
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py15
-rw-r--r--source/blender/CMakeLists.txt8
-rw-r--r--source/blender/SConscript3
-rw-r--r--source/blender/blenfont/BLF_translation.h3
-rw-r--r--source/blender/blenfont/CMakeLists.txt4
-rw-r--r--source/blender/blenfont/SConscript3
-rw-r--r--source/blender/blenkernel/BKE_global.h6
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h79
-rw-r--r--source/blender/blenkernel/BKE_main.h3
-rw-r--r--source/blender/blenkernel/CMakeLists.txt13
-rw-r--r--source/blender/blenkernel/SConscript6
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c20
-rw-r--r--source/blender/blenkernel/intern/bpath.c15
-rw-r--r--source/blender/blenkernel/intern/group.c10
-rw-r--r--source/blender/blenkernel/intern/idcode.c3
-rw-r--r--source/blender/blenkernel/intern/library.c29
-rw-r--r--source/blender/blenkernel/intern/linestyle.c1022
-rw-r--r--source/blender/blenkernel/intern/material.c3
-rw-r--r--source/blender/blenkernel/intern/object.c14
-rw-r--r--source/blender/blenkernel/intern/scene.c17
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c10
-rw-r--r--source/blender/blenlib/CMakeLists.txt4
-rw-r--r--source/blender/blenlib/SConscript3
-rw-r--r--source/blender/blenloader/CMakeLists.txt4
-rw-r--r--source/blender/blenloader/SConscript3
-rw-r--r--source/blender/blenloader/intern/readfile.c334
-rw-r--r--source/blender/blenloader/intern/writefile.c228
-rw-r--r--source/blender/bmesh/CMakeLists.txt4
-rw-r--r--source/blender/bmesh/SConscript3
-rw-r--r--source/blender/bmesh/bmesh_class.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c52
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.h10
-rw-r--r--source/blender/bmesh/operators/bmo_similar.c16
-rw-r--r--source/blender/editors/animation/CMakeLists.txt4
-rw-r--r--source/blender/editors/animation/SConscript3
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c85
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c15
-rw-r--r--source/blender/editors/animation/anim_filter.c75
-rw-r--r--source/blender/editors/include/ED_anim_api.h6
-rw-r--r--source/blender/editors/include/UI_resources.h5
-rw-r--r--source/blender/editors/interface/CMakeLists.txt4
-rw-r--r--source/blender/editors/interface/SConscript3
-rw-r--r--source/blender/editors/interface/interface_templates.c22
-rw-r--r--source/blender/editors/interface/resources.c25
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt4
-rw-r--r--source/blender/editors/mesh/SConscript3
-rw-r--r--source/blender/editors/mesh/editmesh_select.c24
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c106
-rw-r--r--source/blender/editors/mesh/mesh_intern.h6
-rw-r--r--source/blender/editors/mesh/mesh_ops.c6
-rw-r--r--source/blender/editors/render/CMakeLists.txt7
-rw-r--r--source/blender/editors/render/SConscript3
-rw-r--r--source/blender/editors/render/render_intern.h19
-rw-r--r--source/blender/editors/render/render_ops.c19
-rw-r--r--source/blender/editors/render/render_shading.c622
-rw-r--r--source/blender/editors/space_buttons/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_buttons/SConscript3
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c3
-rw-r--r--source/blender/editors/space_buttons/buttons_header.c1
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c9
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_file/SConscript3
-rw-r--r--source/blender/editors/space_file/filelist.c7
-rw-r--r--source/blender/editors/space_nla/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_nla/SConscript3
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c3
-rw-r--r--source/blender/editors/space_nla/nla_channels.c3
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_view3d/SConscript3
-rw-r--r--source/blender/editors/space_view3d/drawobject.c72
-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
-rw-r--r--source/blender/makesdna/CMakeLists.txt4
-rw-r--r--source/blender/makesdna/DNA_ID.h3
-rw-r--r--source/blender/makesdna/DNA_action_types.h3
-rw-r--r--source/blender/makesdna/DNA_freestyle_types.h128
-rw-r--r--source/blender/makesdna/DNA_linestyle_types.h410
-rw-r--r--source/blender/makesdna/DNA_material_types.h5
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h5
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h6
-rw-r--r--source/blender/makesdna/DNA_scene_types.h27
-rw-r--r--source/blender/makesdna/DNA_space_types.h1
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h3
-rw-r--r--source/blender/makesdna/SConscript6
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt3
-rw-r--r--source/blender/makesdna/intern/SConscript3
-rw-r--r--source/blender/makesdna/intern/makesdna.c8
-rw-r--r--source/blender/makesrna/RNA_access.h39
-rw-r--r--source/blender/makesrna/RNA_enum_types.h7
-rw-r--r--source/blender/makesrna/SConscript4
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt13
-rw-r--r--source/blender/makesrna/intern/SConscript6
-rw-r--r--source/blender/makesrna/intern/makesrna.c3
-rw-r--r--source/blender/makesrna/intern/rna_ID.c9
-rw-r--r--source/blender/makesrna/intern/rna_action.c8
-rw-r--r--source/blender/makesrna/intern/rna_color.c38
-rw-r--r--source/blender/makesrna/intern/rna_internal.h6
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c1146
-rw-r--r--source/blender/makesrna/intern/rna_main.c11
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c53
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c33
-rw-r--r--source/blender/makesrna/intern/rna_scene.c518
-rw-r--r--source/blender/makesrna/intern/rna_space.c1
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c14
-rw-r--r--source/blender/python/SConscript4
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c25
-rw-r--r--source/blender/python/intern/CMakeLists.txt7
-rw-r--r--source/blender/python/intern/bpy.c7
-rw-r--r--source/blender/python/intern/bpy_app.c13
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c7
-rw-r--r--source/blender/render/CMakeLists.txt7
-rw-r--r--source/blender/render/SConscript4
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h3
-rw-r--r--source/blender/render/intern/include/render_types.h16
-rw-r--r--source/blender/render/intern/source/convertblender.c88
-rw-r--r--source/blender/render/intern/source/pipeline.c103
-rw-r--r--source/blender/render/intern/source/render_result.c7
-rw-r--r--source/blender/render/intern/source/shadeoutput.c8
-rw-r--r--source/blender/windowmanager/CMakeLists.txt7
-rw-r--r--source/blender/windowmanager/SConscript4
-rw-r--r--source/blender/windowmanager/WM_types.h3
-rw-r--r--source/blender/windowmanager/intern/wm_files.c7
-rw-r--r--source/blenderplayer/bad_level_call_stubs/CMakeLists.txt4
-rw-r--r--source/blenderplayer/bad_level_call_stubs/SConscript3
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c16
-rw-r--r--source/creator/CMakeLists.txt15
-rw-r--r--source/creator/creator.c15
733 files changed, 100918 insertions, 287 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 59dbeaed36b..e623cfe290e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -233,6 +233,9 @@ option(WITH_LZMA "Enable best LZMA compression, (used for pointcache)"
# Camera/motion tracking
option(WITH_LIBMV "Enable libmv structure from motion library" ON)
+# Freestyle
+option(WITH_FREESTYLE "Enable Freestyle (advanced edges rendering)" ON)
+
# Misc
option(WITH_INPUT_NDOF "Enable NDOF input devices (SpaceNavigator and friends)" ON)
option(WITH_RAYOPTIMIZATION "Enable use of SIMD (SSE) optimizations for the raytracer" ON)
diff --git a/SConstruct b/SConstruct
index b7665d14228..e3e58270cdd 100644
--- a/SConstruct
+++ b/SConstruct
@@ -269,6 +269,7 @@ if 'blenderlite' in B.targets:
target_env_defs['WITH_BF_PYTHON'] = False
target_env_defs['WITH_BF_3DMOUSE'] = False
target_env_defs['WITH_BF_LIBMV'] = False
+ target_env_defs['WITH_BF_FREESTYLE'] = False
# Merge blenderlite, let command line to override
for k,v in target_env_defs.iteritems():
@@ -700,6 +701,10 @@ if env['OURPLATFORM']!='darwin':
if VERSION_RELEASE_CYCLE == "release" and "addons_contrib" in dn:
dn.remove('addons_contrib')
+ # do not install freestyle if disabled
+ if not env['WITH_BF_FREESTYLE'] and "freestyle" in dn:
+ dn.remove("freestyle")
+
dir = os.path.join(env['BF_INSTALLDIR'], VERSION)
dir += os.sep + os.path.basename(scriptpath) + dp[len(scriptpath):]
diff --git a/build_files/scons/config/darwin-config.py b/build_files/scons/config/darwin-config.py
index 207ddd3579b..ee1b7bfa38c 100644
--- a/build_files/scons/config/darwin-config.py
+++ b/build_files/scons/config/darwin-config.py
@@ -317,6 +317,9 @@ WITH_BF_CYCLES_CUDA_BINARIES = False
BF_CYCLES_CUDA_NVCC = '/usr/local/cuda/bin/nvcc'
BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_13', 'sm_20', 'sm_21']
+#Freestyle
+WITH_BF_FREESTYLE = True
+
#Ray trace optimization
if MACOSX_ARCHITECTURE == 'x86_64' or MACOSX_ARCHITECTURE == 'i386':
WITH_BF_RAYOPTIMIZATION = True
diff --git a/build_files/scons/config/freebsd7-config.py b/build_files/scons/config/freebsd7-config.py
index 02c9093567a..6c39039c4fb 100644
--- a/build_files/scons/config/freebsd7-config.py
+++ b/build_files/scons/config/freebsd7-config.py
@@ -162,6 +162,9 @@ WITH_GHOST_XDND = False
WITH_BF_OPENMP = True
+#Freestyle
+WITH_BF_FREESTYLE = True
+
#Ray trace optimization
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-pthread']
diff --git a/build_files/scons/config/freebsd8-config.py b/build_files/scons/config/freebsd8-config.py
index 5d3308c50d4..3318e21bf1d 100644
--- a/build_files/scons/config/freebsd8-config.py
+++ b/build_files/scons/config/freebsd8-config.py
@@ -162,6 +162,9 @@ WITH_BF_OPENMP = True
WITH_GHOST_XDND = False
+#Freestyle
+WITH_BF_FREESTYLE = True
+
#Ray trace optimization
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-pthread']
diff --git a/build_files/scons/config/freebsd9-config.py b/build_files/scons/config/freebsd9-config.py
index 98c2c8fa500..b6c5c0d45eb 100644
--- a/build_files/scons/config/freebsd9-config.py
+++ b/build_files/scons/config/freebsd9-config.py
@@ -162,6 +162,9 @@ WITH_BF_OPENMP = True
WITH_GHOST_XDND = False
+#Freestyle
+WITH_BF_FREESTYLE = True
+
#Ray trace optimization
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-pthread']
diff --git a/build_files/scons/config/linux-config.py b/build_files/scons/config/linux-config.py
index 068273e35ef..22e82662ae7 100644
--- a/build_files/scons/config/linux-config.py
+++ b/build_files/scons/config/linux-config.py
@@ -226,6 +226,9 @@ BF_3DMOUSE_LIBPATH = '${BF_3DMOUSE}/lib'
BF_3DMOUSE_LIB = 'spnav'
BF_3DMOUSE_LIB_STATIC = '${BF_3DMOUSE_LIBPATH}/libspnav.a'
+#Freestyle
+WITH_BF_FREESTYLE = True
+
##
CC = 'gcc'
CXX = 'g++'
diff --git a/build_files/scons/config/linuxcross-config.py b/build_files/scons/config/linuxcross-config.py
index 54faf59b2a4..925ca5bb889 100644
--- a/build_files/scons/config/linuxcross-config.py
+++ b/build_files/scons/config/linuxcross-config.py
@@ -160,6 +160,9 @@ BF_OPENCOLLADA_INC = '${BF_OPENCOLLADA}/include'
BF_OPENCOLLADA_LIB = 'OpenCOLLADAStreamWriter OpenCOLLADASaxFrameworkLoader OpenCOLLADAFramework OpenCOLLADABaseUtils GeneratedSaxParser UTF MathMLSolver expat pcre buffer ftoa'
BF_OPENCOLLADA_LIBPATH = '${BF_OPENCOLLADA}/lib ${BF_ICONV_LIBPATH}'
+#Freestyle
+WITH_BF_FREESTYLE = True
+
#Ray trace optimization
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse']
diff --git a/build_files/scons/config/win32-mingw-config.py b/build_files/scons/config/win32-mingw-config.py
index 391421609d2..5362e35878e 100644
--- a/build_files/scons/config/win32-mingw-config.py
+++ b/build_files/scons/config/win32-mingw-config.py
@@ -176,6 +176,9 @@ WITH_BF_CYCLES_CUDA_BINARIES = False
#BF_CYCLES_CUDA_NVCC = "" # Path to the nvidia compiler
BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_13', 'sm_20', 'sm_21', 'sm_30']
+#Freestyle
+WITH_BF_FREESTYLE = True
+
##
CC = 'gcc'
CXX = 'g++'
diff --git a/build_files/scons/config/win32-vc-config.py b/build_files/scons/config/win32-vc-config.py
index 21488e75f7e..cf0afec0ee1 100644
--- a/build_files/scons/config/win32-vc-config.py
+++ b/build_files/scons/config/win32-vc-config.py
@@ -195,6 +195,9 @@ BF_CYCLES_CUDA_BINARIES_ARCH = ['sm_13', 'sm_20', 'sm_21', 'sm_30']
WITH_BF_RAYOPTIMIZATION = True
BF_RAYOPTIMIZATION_SSE_FLAGS = ['/arch:SSE']
+#Freestyle
+WITH_BF_FREESTYLE = True
+
WITH_BF_STATICOPENGL = False
BF_OPENGL_INC = '${BF_OPENGL}/include'
BF_OPENGL_LIBINC = '${BF_OPENGL}/lib'
diff --git a/build_files/scons/config/win64-mingw-config.py b/build_files/scons/config/win64-mingw-config.py
index d00e7a3ffa7..5e6e16b1771 100644
--- a/build_files/scons/config/win64-mingw-config.py
+++ b/build_files/scons/config/win64-mingw-config.py
@@ -174,6 +174,9 @@ BF_RAYOPTIMIZATION_SSE_FLAGS = ['-mmmx', '-msse', '-msse2']
#May produce errors with unsupported MinGW-w64 builds
WITH_BF_OPENMP = False
+#Freestyle
+WITH_BF_FREESTYLE = True
+
##
CC = 'gcc'
CXX = 'g++'
diff --git a/build_files/scons/config/win64-vc-config.py b/build_files/scons/config/win64-vc-config.py
index c0ea7972aeb..33f01616579 100644
--- a/build_files/scons/config/win64-vc-config.py
+++ b/build_files/scons/config/win64-vc-config.py
@@ -192,6 +192,9 @@ WITH_BF_RAYOPTIMIZATION = True
# No need to manually specify SSE/SSE2 on x64 systems.
BF_RAYOPTIMIZATION_SSE_FLAGS = ['']
+#Freestyle
+WITH_BF_FREESTYLE = True
+
WITH_BF_STATICOPENGL = False
BF_OPENGL_INC = '${BF_OPENGL}/include'
BF_OPENGL_LIBINC = '${BF_OPENGL}/lib'
diff --git a/build_files/scons/tools/Blender.py b/build_files/scons/tools/Blender.py
index 94a9f1d9c24..eac26c1a50b 100644
--- a/build_files/scons/tools/Blender.py
+++ b/build_files/scons/tools/Blender.py
@@ -388,6 +388,10 @@ def creator(env):
if env['BF_DEBUG']:
defs.append('_DEBUG')
+ if env['WITH_BF_FREESTYLE']:
+ incs.append('#/source/blender/freestyle')
+ defs.append('WITH_FREESTYLE')
+
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs.append(env['BF_PTHREADS_INC'])
incs.append('#/intern/utfconv')
diff --git a/build_files/scons/tools/btools.py b/build_files/scons/tools/btools.py
index ee6dd20ecc0..9a31ba650f5 100644
--- a/build_files/scons/tools/btools.py
+++ b/build_files/scons/tools/btools.py
@@ -116,6 +116,7 @@ def validate_arguments(args, bc):
'WITH_BF_TIFF', 'BF_TIFF', 'BF_TIFF_INC', 'BF_TIFF_LIB', 'BF_TIFF_LIBPATH', 'WITH_BF_STATICTIFF', 'BF_TIFF_LIB_STATIC',
'WITH_BF_ZLIB', 'BF_ZLIB', 'BF_ZLIB_INC', 'BF_ZLIB_LIB', 'BF_ZLIB_LIBPATH', 'WITH_BF_STATICZLIB', 'BF_ZLIB_LIB_STATIC',
'WITH_BF_INTERNATIONAL',
+ 'WITH_BF_FREESTYLE',
'WITH_BF_ICONV', 'BF_ICONV', 'BF_ICONV_INC', 'BF_ICONV_LIB', 'BF_ICONV_LIBPATH',
'WITH_BF_GAMEENGINE',
'WITH_BF_BULLET', 'BF_BULLET', 'BF_BULLET_INC', 'BF_BULLET_LIB',
@@ -386,6 +387,8 @@ def read_opts(env, cfg, args):
(BoolVariable('WITH_BF_INTERNATIONAL', 'Use Boost::locale if true', True)),
+ (BoolVariable('WITH_BF_FREESTYLE', 'Build advanced edge renderer', True)),
+
(BoolVariable('WITH_BF_ICONV', 'Use iconv if true', True)),
('BF_ICONV', 'iconv base path', ''),
('BF_ICONV_INC', 'iconv include path', ''),
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index 7457ae02d6c..4311ae56f8e 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -262,6 +262,7 @@ else:
"mathutils",
"mathutils.geometry",
"mathutils.noise",
+ "Freestyle",
]
# ------
@@ -449,6 +450,7 @@ if ARGS.sphinx_build_pdf:
ClassMethodDescriptorType = type(dict.__dict__['fromkeys'])
MethodDescriptorType = type(dict.get)
GetSetDescriptorType = type(int.real)
+StaticMethodType = type(staticmethod(lambda: None))
from types import MemberDescriptorType
_BPY_STRUCT_FAKE = "bpy_struct"
@@ -913,6 +915,12 @@ def pymodule2sphinx(basepath, module_name, module, title):
if type(descr) == GetSetDescriptorType:
py_descr2sphinx(" ", fw, descr, module_name, type_name, key)
+ for key, descr in descr_items:
+ if type(descr) == StaticMethodType:
+ descr = getattr(value, key)
+ write_indented_lines(" ", fw, descr.__doc__ or "Undocumented", False)
+ fw("\n")
+
fw("\n\n")
file.close()
@@ -1543,7 +1551,7 @@ def write_rst_contents(basepath):
# mathutils
"mathutils", "mathutils.geometry", "mathutils.noise",
# misc
- "bgl", "blf", "gpu", "aud", "bpy_extras",
+ "Freestyle", "bgl", "blf", "gpu", "aud", "bpy_extras",
# bmesh, submodules are in own page
"bmesh",
)
@@ -1691,6 +1699,7 @@ def write_rst_importable_modules(basepath):
"mathutils" : "Math Types & Utilities",
"mathutils.geometry": "Geometry Utilities",
"mathutils.noise" : "Noise Utilities",
+ "Freestyle" : "Freestyle Data Types & Operators",
}
for mod_name, mod_descr in importable_modules.items():
if mod_name not in EXCLUDE_MODULES:
diff --git a/extern/libmv/third_party/ceres/mkfiles.sh b/extern/libmv/third_party/ceres/mkfiles.sh
index d335829aa2c..d335829aa2c 100755..100644
--- a/extern/libmv/third_party/ceres/mkfiles.sh
+++ b/extern/libmv/third_party/ceres/mkfiles.sh
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index fded07ab227..ccc2a0ecbda 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -220,10 +220,69 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
sub.prop(rd, "use_persistent_data", text="Persistent Images")
+class Cycles_PT_post_processing(CyclesButtonsPanel, Panel):
+ bl_label = "Post Processing"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ rd = context.scene.render
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(rd, "use_compositing")
+ col.prop(rd, "use_sequencer")
+
+ col = split.column()
+ col.prop(rd, "dither_intensity", text="Dither", slider=True)
+
+
+class CyclesCamera_PT_dof(CyclesButtonsPanel, Panel):
+ bl_label = "Depth of Field"
+ bl_context = "data"
+
+ @classmethod
+ def poll(cls, context):
+ return context.camera and CyclesButtonsPanel.poll(context)
+
+ def draw(self, context):
+ layout = self.layout
+
+ cam = context.camera
+ ccam = cam.cycles
+
+ split = layout.split()
+
+ col = split.column()
+ col.label("Focus:")
+ col.prop(cam, "dof_object", text="")
+
+ sub = col.row()
+ sub.active = cam.dof_object is None
+ sub.prop(cam, "dof_distance", text="Distance")
+
+ col = split.column()
+
+ col.label("Aperture:")
+ sub = col.column(align=True)
+ sub.prop(ccam, "aperture_type", text="")
+ if ccam.aperture_type == 'RADIUS':
+ sub.prop(ccam, "aperture_size", text="Size")
+ elif ccam.aperture_type == 'FSTOP':
+ sub.prop(ccam, "aperture_fstop", text="Number")
+
+ sub = col.column(align=True)
+ sub.prop(ccam, "aperture_blades", text="Blades")
+ sub.prop(ccam, "aperture_rotation", text="Rotation")
+
+
class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
bl_label = "Layers"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ bl_options = {'HIDE_HEADER'}
+ bl_context = "render_layer"
+ COMPAT_ENGINES = {'CYCLES'}
def draw(self, context):
layout = self.layout
@@ -240,9 +299,24 @@ class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
row = layout.row()
rl = rd.layers.active
- row.prop(rl, "name")
+ if rl:
+ row.prop(rl, "name")
row.prop(rd, "use_single_layer", text="", icon_only=True)
+
+class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel):
+ bl_label = "Layer"
+ bl_options = {'DEFAULT_CLOSED'}
+ bl_context = "render_layer"
+ COMPAT_ENGINES = {'CYCLES'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+ rd = scene.render
+ rl = rd.layers.active
+
split = layout.split()
col = split.column()
@@ -264,6 +338,20 @@ class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
col.prop(rl, "samples")
col.prop(rl, "use_sky", "Use Environment")
+
+class CyclesRender_PT_layer_passes(CyclesButtonsPanel, Panel):
+ bl_label = "Layer"
+ bl_options = {'DEFAULT_CLOSED'}
+ bl_context = "render_layer"
+ COMPAT_ENGINES = {'CYCLES'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+ rd = scene.render
+ rl = rd.layers.active
+
split = layout.split()
col = split.column()
@@ -300,64 +388,6 @@ class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
col.prop(rl, "use_pass_environment")
-class Cycles_PT_post_processing(CyclesButtonsPanel, Panel):
- bl_label = "Post Processing"
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw(self, context):
- layout = self.layout
-
- rd = context.scene.render
-
- split = layout.split()
-
- col = split.column()
- col.prop(rd, "use_compositing")
- col.prop(rd, "use_sequencer")
-
- col = split.column()
- col.prop(rd, "dither_intensity", text="Dither", slider=True)
-
-
-class CyclesCamera_PT_dof(CyclesButtonsPanel, Panel):
- bl_label = "Depth of Field"
- bl_context = "data"
-
- @classmethod
- def poll(cls, context):
- return context.camera and CyclesButtonsPanel.poll(context)
-
- def draw(self, context):
- layout = self.layout
-
- cam = context.camera
- ccam = cam.cycles
-
- split = layout.split()
-
- col = split.column()
- col.label("Focus:")
- col.prop(cam, "dof_object", text="")
-
- sub = col.row()
- sub.active = cam.dof_object is None
- sub.prop(cam, "dof_distance", text="Distance")
-
- col = split.column()
-
- col.label("Aperture:")
- sub = col.column(align=True)
- sub.prop(ccam, "aperture_type", text="")
- if ccam.aperture_type == 'RADIUS':
- sub.prop(ccam, "aperture_size", text="Size")
- elif ccam.aperture_type == 'FSTOP':
- sub.prop(ccam, "aperture_fstop", text="Number")
-
- sub = col.column(align=True)
- sub.prop(ccam, "aperture_blades", text="Blades")
- sub.prop(ccam, "aperture_rotation", text="Rotation")
-
-
class Cycles_PT_context_material(CyclesButtonsPanel, Panel):
bl_label = ""
bl_context = "material"
diff --git a/release/bin/blender-softwaregl b/release/bin/blender-softwaregl
index 970a7870760..63e6d9a9658 100755..100644
--- a/release/bin/blender-softwaregl
+++ b/release/bin/blender-softwaregl
@@ -1,25 +1,25 @@
-#!/bin/sh
-BF_DIST_BIN=`dirname "$0"`
-BF_PROGRAM="blender" # BF_PROGRAM=`basename "$0"`-bin
-exitcode=0
-
-LD_LIBRARY_PATH=${BF_DIST_BIN}/lib:${LD_LIBRARY_PATH}
-
-if [ -n "$LD_LIBRARYN32_PATH" ]; then
- LD_LIBRARYN32_PATH=${BF_DIST_BIN}/lib:${LD_LIBRARYN32_PATH}
-fi
-if [ -n "$LD_LIBRARYN64_PATH" ]; then
- LD_LIBRARYN64_PATH=${BF_DIST_BIN}/lib:${LD_LIBRARYN64_PATH}
-fi
-if [ -n "$LD_LIBRARY_PATH_64" ]; then
- LD_LIBRARY_PATH_64=${BF_DIST_BIN}/lib:${LD_LIBRARY_PATH_64}
-fi
-
-# Workaround for half-transparent windows when compiz is enabled
-XLIB_SKIP_ARGB_VISUALS=1
-
-export LD_LIBRARY_PATH LD_LIBRARYN32_PATH LD_LIBRARYN64_PATH LD_LIBRARY_PATH_64 LD_PRELOAD XLIB_SKIP_ARGB_VISUALS
-
-"$BF_DIST_BIN/$BF_PROGRAM" ${1+"$@"}
-exitcode=$?
-exit $exitcode
+#!/bin/sh
+BF_DIST_BIN=`dirname "$0"`
+BF_PROGRAM="blender" # BF_PROGRAM=`basename "$0"`-bin
+exitcode=0
+
+LD_LIBRARY_PATH=${BF_DIST_BIN}/lib:${LD_LIBRARY_PATH}
+
+if [ -n "$LD_LIBRARYN32_PATH" ]; then
+ LD_LIBRARYN32_PATH=${BF_DIST_BIN}/lib:${LD_LIBRARYN32_PATH}
+fi
+if [ -n "$LD_LIBRARYN64_PATH" ]; then
+ LD_LIBRARYN64_PATH=${BF_DIST_BIN}/lib:${LD_LIBRARYN64_PATH}
+fi
+if [ -n "$LD_LIBRARY_PATH_64" ]; then
+ LD_LIBRARY_PATH_64=${BF_DIST_BIN}/lib:${LD_LIBRARY_PATH_64}
+fi
+
+# Workaround for half-transparent windows when compiz is enabled
+XLIB_SKIP_ARGB_VISUALS=1
+
+export LD_LIBRARY_PATH LD_LIBRARYN32_PATH LD_LIBRARYN64_PATH LD_LIBRARY_PATH_64 LD_PRELOAD XLIB_SKIP_ARGB_VISUALS
+
+"$BF_DIST_BIN/$BF_PROGRAM" ${1+"$@"}
+exitcode=$?
+exit $exitcode
diff --git a/release/datafiles/startup.blend b/release/datafiles/startup.blend
index 599bfb50d6e..dc684178f40 100644
--- a/release/datafiles/startup.blend
+++ b/release/datafiles/startup.blend
Binary files differ
diff --git a/release/scripts/freestyle/data/env_map/brown00.png b/release/scripts/freestyle/data/env_map/brown00.png
new file mode 100644
index 00000000000..855f06f4fb9
--- /dev/null
+++ b/release/scripts/freestyle/data/env_map/brown00.png
Binary files differ
diff --git a/release/scripts/freestyle/data/env_map/gray00.png b/release/scripts/freestyle/data/env_map/gray00.png
new file mode 100644
index 00000000000..7c9b1a8149e
--- /dev/null
+++ b/release/scripts/freestyle/data/env_map/gray00.png
Binary files differ
diff --git a/release/scripts/freestyle/data/env_map/gray01.png b/release/scripts/freestyle/data/env_map/gray01.png
new file mode 100644
index 00000000000..06542908e6b
--- /dev/null
+++ b/release/scripts/freestyle/data/env_map/gray01.png
Binary files differ
diff --git a/release/scripts/freestyle/data/env_map/gray02.png b/release/scripts/freestyle/data/env_map/gray02.png
new file mode 100644
index 00000000000..0208f4920d9
--- /dev/null
+++ b/release/scripts/freestyle/data/env_map/gray02.png
Binary files differ
diff --git a/release/scripts/freestyle/data/env_map/gray03.png b/release/scripts/freestyle/data/env_map/gray03.png
new file mode 100644
index 00000000000..aab9b957c21
--- /dev/null
+++ b/release/scripts/freestyle/data/env_map/gray03.png
Binary files differ
diff --git a/release/scripts/freestyle/style_modules/ChainingIterators.py b/release/scripts/freestyle/style_modules/ChainingIterators.py
new file mode 100644
index 00000000000..f2d953ddc14
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/ChainingIterators.py
@@ -0,0 +1,731 @@
+#
+# Filename : ChainingIterators.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Chaining Iterators to be used with chaining operators
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+
+## the natural chaining iterator
+## It follows the edges of same nature following the topology of
+## objects with preseance on silhouettes, then borders,
+## then suggestive contours, then everything else. It doesn't chain the same ViewEdge twice
+## You can specify whether to stay in the selection or not.
+class pyChainSilhouetteIterator(ChainingIterator):
+ def __init__(self, stayInSelection=1):
+ ChainingIterator.__init__(self, stayInSelection, 1,None,1)
+ def getExactTypeName(self):
+ return "pyChainSilhouetteIterator"
+ def init(self):
+ pass
+ def traverse(self, iter):
+ winner = None
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for i in range(len(natures)):
+ currentNature = self.getCurrentEdge().getNature()
+ if(natures[i] & currentNature):
+ count=0
+ while(it.isEnd() == 0):
+ visitNext = 0
+ oNature = it.getObject().getNature()
+ if(oNature & natures[i] != 0):
+ if(natures[i] != oNature):
+ for j in range(i):
+ if(natures[j] & oNature != 0):
+ visitNext = 1
+ break
+ if(visitNext != 0):
+ break
+ count = count+1
+ winner = it.getObject()
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ return winner
+
+## the natural chaining iterator
+## It follows the edges of same nature on the same
+## objects with preseance on silhouettes, then borders,
+## then suggestive contours, then everything else. It doesn't chain the same ViewEdge twice
+## You can specify whether to stay in the selection or not.
+## You can specify whether to chain iterate over edges that were
+## already visited or not.
+class pyChainSilhouetteGenericIterator(ChainingIterator):
+ def __init__(self, stayInSelection=1, stayInUnvisited=1):
+ ChainingIterator.__init__(self, stayInSelection, stayInUnvisited,None,1)
+ def getExactTypeName(self):
+ return "pyChainSilhouetteGenericIterator"
+ def init(self):
+ pass
+ def traverse(self, iter):
+ winner = None
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for i in range(len(natures)):
+ currentNature = self.getCurrentEdge().getNature()
+ if(natures[i] & currentNature):
+ count=0
+ while(it.isEnd() == 0):
+ visitNext = 0
+ oNature = it.getObject().getNature()
+ ve = it.getObject()
+ if(ve.getId() == self.getCurrentEdge().getId()):
+ it.increment()
+ continue
+ if(oNature & natures[i] != 0):
+ if(natures[i] != oNature):
+ for j in range(i):
+ if(natures[j] & oNature != 0):
+ visitNext = 1
+ break
+ if(visitNext != 0):
+ break
+ count = count+1
+ winner = ve
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ return winner
+
+class pyExternalContourChainingIterator(ChainingIterator):
+ def __init__(self):
+ ChainingIterator.__init__(self, 0, 1,None,1)
+ self._isExternalContour = ExternalContourUP1D()
+
+ def getExactTypeName(self):
+ return "pyExternalContourIterator"
+
+ def init(self):
+ self._nEdges = 0
+ self._isInSelection = 1
+
+ def checkViewEdge(self, ve, orientation):
+ if(orientation != 0):
+ vertex = ve.B()
+ else:
+ vertex = ve.A()
+ it = AdjacencyIterator(vertex,1,1)
+ while(it.isEnd() == 0):
+ ave = it.getObject()
+ if(self._isExternalContour(ave)):
+ return 1
+ it.increment()
+ print("pyExternlContourChainingIterator : didn't find next edge")
+ return 0
+ def traverse(self, iter):
+ winner = None
+ it = AdjacencyIterator(iter)
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(self._isExternalContour(ve)):
+ if (ve.getTimeStamp() == GetTimeStampCF()):
+ winner = ve
+ it.increment()
+
+ self._nEdges = self._nEdges+1
+ if(winner == None):
+ orient = 1
+ it = AdjacencyIterator(iter)
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(it.isIncoming() != 0):
+ orient = 0
+ good = self.checkViewEdge(ve,orient)
+ if(good != 0):
+ winner = ve
+ it.increment()
+ return winner
+
+## the natural chaining iterator
+## with a sketchy multiple touch
+class pySketchyChainSilhouetteIterator(ChainingIterator):
+ def __init__(self, nRounds=3,stayInSelection=1):
+ ChainingIterator.__init__(self, stayInSelection, 0,None,1)
+ self._timeStamp = GetTimeStampCF()+nRounds
+ self._nRounds = nRounds
+ def getExactTypeName(self):
+ return "pySketchyChainSilhouetteIterator"
+ def init(self):
+ self._timeStamp = GetTimeStampCF()+self._nRounds
+ def traverse(self, iter):
+ winner = None
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for i in range(len(natures)):
+ currentNature = self.getCurrentEdge().getNature()
+ if(natures[i] & currentNature):
+ count=0
+ while(it.isEnd() == 0):
+ visitNext = 0
+ oNature = it.getObject().getNature()
+ ve = it.getObject()
+ if(ve.getId() == self.getCurrentEdge().getId()):
+ it.increment()
+ continue
+ if(oNature & natures[i] != 0):
+ if(natures[i] != oNature):
+ for j in range(i):
+ if(natures[j] & oNature != 0):
+ visitNext = 1
+ break
+ if(visitNext != 0):
+ break
+ count = count+1
+ winner = ve
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ if(winner == None):
+ winner = self.getCurrentEdge()
+ if(winner.getChainingTimeStamp() == self._timeStamp):
+ winner = None
+ return winner
+
+
+# Chaining iterator designed for sketchy style.
+# can chain several times the same ViewEdge
+# in order to produce multiple strokes per ViewEdge.
+class pySketchyChainingIterator(ChainingIterator):
+ def __init__(self, nRounds=3, stayInSelection=1):
+ ChainingIterator.__init__(self, stayInSelection, 0,None,1)
+ self._timeStamp = GetTimeStampCF()+nRounds
+ self._nRounds = nRounds
+ def getExactTypeName(self):
+ return "pySketchyChainingIterator"
+
+ def init(self):
+ self._timeStamp = GetTimeStampCF()+self._nRounds
+
+ def traverse(self, iter):
+ winner = None
+ it = AdjacencyIterator(iter)
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == self.getCurrentEdge().getId()):
+ it.increment()
+ continue
+ winner = ve
+ it.increment()
+ if(winner == None):
+ winner = self.getCurrentEdge()
+ if(winner.getChainingTimeStamp() == self._timeStamp):
+ return None
+ return winner
+
+
+## Chaining iterator that fills small occlusions
+## percent
+## The max length of the occluded part
+## expressed in % of the total chain length
+class pyFillOcclusionsRelativeChainingIterator(ChainingIterator):
+ def __init__(self, percent):
+ ChainingIterator.__init__(self, 0, 1,None,1)
+ self._length = 0
+ self._percent = float(percent)
+ def getExactTypeName(self):
+ return "pyFillOcclusionsChainingIterator"
+ def init(self):
+ # each time we're evaluating a chain length
+ # we try to do it once. Thus we reinit
+ # the chain length here:
+ self._length = 0
+ def traverse(self, iter):
+ winner = None
+ winnerOrientation = 0
+ print(self.getCurrentEdge().getId().getFirst(), self.getCurrentEdge().getId().getSecond())
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for nat in natures:
+ if(self.getCurrentEdge().getNature() & nat != 0):
+ count=0
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getNature() & nat != 0):
+ count = count+1
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ if(winner != None):
+ # check whether this edge was part of the selection
+ if(winner.getTimeStamp() != GetTimeStampCF()):
+ #print("---", winner.getId().getFirst(), winner.getId().getSecond())
+ # if not, let's check whether it's short enough with
+ # respect to the chain made without staying in the selection
+ #------------------------------------------------------------
+ # Did we compute the prospective chain length already ?
+ if(self._length == 0):
+ #if not, let's do it
+ _it = pyChainSilhouetteGenericIterator(0,0)
+ _it.setBegin(winner)
+ _it.setCurrentEdge(winner)
+ _it.setOrientation(winnerOrientation)
+ _it.init()
+ while(_it.isEnd() == 0):
+ ve = _it.getObject()
+ #print("--------", ve.getId().getFirst(), ve.getId().getSecond())
+ self._length = self._length + ve.getLength2D()
+ _it.increment()
+ if(_it.isBegin() != 0):
+ break;
+ _it.setBegin(winner)
+ _it.setCurrentEdge(winner)
+ _it.setOrientation(winnerOrientation)
+ if(_it.isBegin() == 0):
+ _it.decrement()
+ while ((_it.isEnd() == 0) and (_it.isBegin() == 0)):
+ ve = _it.getObject()
+ #print("--------", ve.getId().getFirst(), ve.getId().getSecond())
+ self._length = self._length + ve.getLength2D()
+ _it.decrement()
+
+ # let's do the comparison:
+ # nw let's compute the length of this connex non selected part:
+ connexl = 0
+ _cit = pyChainSilhouetteGenericIterator(0,0)
+ _cit.setBegin(winner)
+ _cit.setCurrentEdge(winner)
+ _cit.setOrientation(winnerOrientation)
+ _cit.init()
+ while((_cit.isEnd() == 0) and (_cit.getObject().getTimeStamp() != GetTimeStampCF())):
+ ve = _cit.getObject()
+ #print("-------- --------", ve.getId().getFirst(), ve.getId().getSecond())
+ connexl = connexl + ve.getLength2D()
+ _cit.increment()
+ if(connexl > self._percent * self._length):
+ winner = None
+ return winner
+
+## Chaining iterator that fills small occlusions
+## size
+## The max length of the occluded part
+## expressed in pixels
+class pyFillOcclusionsAbsoluteChainingIterator(ChainingIterator):
+ def __init__(self, length):
+ ChainingIterator.__init__(self, 0, 1,None,1)
+ self._length = float(length)
+ def getExactTypeName(self):
+ return "pySmallFillOcclusionsChainingIterator"
+ def init(self):
+ pass
+ def traverse(self, iter):
+ winner = None
+ winnerOrientation = 0
+ #print(self.getCurrentEdge().getId().getFirst(), self.getCurrentEdge().getId().getSecond())
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for nat in natures:
+ if(self.getCurrentEdge().getNature() & nat != 0):
+ count=0
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getNature() & nat != 0):
+ count = count+1
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ if(winner != None):
+ # check whether this edge was part of the selection
+ if(winner.getTimeStamp() != GetTimeStampCF()):
+ #print("---", winner.getId().getFirst(), winner.getId().getSecond())
+ # nw let's compute the length of this connex non selected part:
+ connexl = 0
+ _cit = pyChainSilhouetteGenericIterator(0,0)
+ _cit.setBegin(winner)
+ _cit.setCurrentEdge(winner)
+ _cit.setOrientation(winnerOrientation)
+ _cit.init()
+ while((_cit.isEnd() == 0) and (_cit.getObject().getTimeStamp() != GetTimeStampCF())):
+ ve = _cit.getObject()
+ #print("-------- --------", ve.getId().getFirst(), ve.getId().getSecond())
+ connexl = connexl + ve.getLength2D()
+ _cit.increment()
+ if(connexl > self._length):
+ winner = None
+ return winner
+
+
+## Chaining iterator that fills small occlusions
+## percent
+## The max length of the occluded part
+## expressed in % of the total chain length
+class pyFillOcclusionsAbsoluteAndRelativeChainingIterator(ChainingIterator):
+ def __init__(self, percent, l):
+ ChainingIterator.__init__(self, 0, 1,None,1)
+ self._length = 0
+ self._absLength = l
+ self._percent = float(percent)
+ def getExactTypeName(self):
+ return "pyFillOcclusionsChainingIterator"
+ def init(self):
+ # each time we're evaluating a chain length
+ # we try to do it once. Thus we reinit
+ # the chain length here:
+ self._length = 0
+ def traverse(self, iter):
+ winner = None
+ winnerOrientation = 0
+ print(self.getCurrentEdge().getId().getFirst(), self.getCurrentEdge().getId().getSecond())
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for nat in natures:
+ if(self.getCurrentEdge().getNature() & nat != 0):
+ count=0
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getNature() & nat != 0):
+ count = count+1
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ if(winner != None):
+ # check whether this edge was part of the selection
+ if(winner.getTimeStamp() != GetTimeStampCF()):
+ #print("---", winner.getId().getFirst(), winner.getId().getSecond())
+ # if not, let's check whether it's short enough with
+ # respect to the chain made without staying in the selection
+ #------------------------------------------------------------
+ # Did we compute the prospective chain length already ?
+ if(self._length == 0):
+ #if not, let's do it
+ _it = pyChainSilhouetteGenericIterator(0,0)
+ _it.setBegin(winner)
+ _it.setCurrentEdge(winner)
+ _it.setOrientation(winnerOrientation)
+ _it.init()
+ while(_it.isEnd() == 0):
+ ve = _it.getObject()
+ #print("--------", ve.getId().getFirst(), ve.getId().getSecond())
+ self._length = self._length + ve.getLength2D()
+ _it.increment()
+ if(_it.isBegin() != 0):
+ break;
+ _it.setBegin(winner)
+ _it.setCurrentEdge(winner)
+ _it.setOrientation(winnerOrientation)
+ if(_it.isBegin() == 0):
+ _it.decrement()
+ while ((_it.isEnd() == 0) and (_it.isBegin() == 0)):
+ ve = _it.getObject()
+ #print("--------", ve.getId().getFirst(), ve.getId().getSecond())
+ self._length = self._length + ve.getLength2D()
+ _it.decrement()
+
+ # let's do the comparison:
+ # nw let's compute the length of this connex non selected part:
+ connexl = 0
+ _cit = pyChainSilhouetteGenericIterator(0,0)
+ _cit.setBegin(winner)
+ _cit.setCurrentEdge(winner)
+ _cit.setOrientation(winnerOrientation)
+ _cit.init()
+ while((_cit.isEnd() == 0) and (_cit.getObject().getTimeStamp() != GetTimeStampCF())):
+ ve = _cit.getObject()
+ #print("-------- --------", ve.getId().getFirst(), ve.getId().getSecond())
+ connexl = connexl + ve.getLength2D()
+ _cit.increment()
+ if((connexl > self._percent * self._length) or (connexl > self._absLength)):
+ winner = None
+ return winner
+
+## Chaining iterator that fills small occlusions without caring about the
+## actual selection
+## percent
+## The max length of the occluded part
+## expressed in % of the total chain length
+class pyFillQi0AbsoluteAndRelativeChainingIterator(ChainingIterator):
+ def __init__(self, percent, l):
+ ChainingIterator.__init__(self, 0, 1,None,1)
+ self._length = 0
+ self._absLength = l
+ self._percent = float(percent)
+ def getExactTypeName(self):
+ return "pyFillOcclusionsChainingIterator"
+ def init(self):
+ # each time we're evaluating a chain length
+ # we try to do it once. Thus we reinit
+ # the chain length here:
+ self._length = 0
+ def traverse(self, iter):
+ winner = None
+ winnerOrientation = 0
+ print(self.getCurrentEdge().getId().getFirst(), self.getCurrentEdge().getId().getSecond())
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getId() == mateVE.getId() ):
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for nat in natures:
+ if(self.getCurrentEdge().getNature() & nat != 0):
+ count=0
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ if(ve.getNature() & nat != 0):
+ count = count+1
+ winner = ve
+ if(it.isIncoming() == 0):
+ winnerOrientation = 1
+ else:
+ winnerOrientation = 0
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ if(winner != None):
+ # check whether this edge was part of the selection
+ if(winner.qi() != 0):
+ #print("---", winner.getId().getFirst(), winner.getId().getSecond())
+ # if not, let's check whether it's short enough with
+ # respect to the chain made without staying in the selection
+ #------------------------------------------------------------
+ # Did we compute the prospective chain length already ?
+ if(self._length == 0):
+ #if not, let's do it
+ _it = pyChainSilhouetteGenericIterator(0,0)
+ _it.setBegin(winner)
+ _it.setCurrentEdge(winner)
+ _it.setOrientation(winnerOrientation)
+ _it.init()
+ while(_it.isEnd() == 0):
+ ve = _it.getObject()
+ #print("--------", ve.getId().getFirst(), ve.getId().getSecond())
+ self._length = self._length + ve.getLength2D()
+ _it.increment()
+ if(_it.isBegin() != 0):
+ break;
+ _it.setBegin(winner)
+ _it.setCurrentEdge(winner)
+ _it.setOrientation(winnerOrientation)
+ if(_it.isBegin() == 0):
+ _it.decrement()
+ while ((_it.isEnd() == 0) and (_it.isBegin() == 0)):
+ ve = _it.getObject()
+ #print("--------", ve.getId().getFirst(), ve.getId().getSecond())
+ self._length = self._length + ve.getLength2D()
+ _it.decrement()
+
+ # let's do the comparison:
+ # nw let's compute the length of this connex non selected part:
+ connexl = 0
+ _cit = pyChainSilhouetteGenericIterator(0,0)
+ _cit.setBegin(winner)
+ _cit.setCurrentEdge(winner)
+ _cit.setOrientation(winnerOrientation)
+ _cit.init()
+ while((_cit.isEnd() == 0) and (_cit.getObject().qi() != 0)):
+ ve = _cit.getObject()
+ #print("-------- --------", ve.getId().getFirst(), ve.getId().getSecond())
+ connexl = connexl + ve.getLength2D()
+ _cit.increment()
+ if((connexl > self._percent * self._length) or (connexl > self._absLength)):
+ winner = None
+ return winner
+
+
+## the natural chaining iterator
+## It follows the edges of same nature on the same
+## objects with preseance on silhouettes, then borders,
+## then suggestive contours, then everything else. It doesn't chain the same ViewEdge twice
+## You can specify whether to stay in the selection or not.
+class pyNoIdChainSilhouetteIterator(ChainingIterator):
+ def __init__(self, stayInSelection=1):
+ ChainingIterator.__init__(self, stayInSelection, 1,None,1)
+ def getExactTypeName(self):
+ return "pyChainSilhouetteIterator"
+ def init(self):
+ pass
+ def traverse(self, iter):
+ winner = None
+ it = AdjacencyIterator(iter)
+ tvertex = self.getVertex()
+ if type(tvertex) is TVertex:
+ mateVE = tvertex.mate(self.getCurrentEdge())
+ while(it.isEnd() == 0):
+ ve = it.getObject()
+ feB = self.getCurrentEdge().fedgeB()
+ feA = ve.fedgeA()
+ vB = feB.vertexB()
+ vA = feA.vertexA()
+ if vA.getId().getFirst() == vB.getId().getFirst():
+ winner = ve
+ break
+ feA = self.getCurrentEdge().fedgeA()
+ feB = ve.fedgeB()
+ vB = feB.vertexB()
+ vA = feA.vertexA()
+ if vA.getId().getFirst() == vB.getId().getFirst():
+ winner = ve
+ break
+ feA = self.getCurrentEdge().fedgeB()
+ feB = ve.fedgeB()
+ vB = feB.vertexB()
+ vA = feA.vertexB()
+ if vA.getId().getFirst() == vB.getId().getFirst():
+ winner = ve
+ break
+ feA = self.getCurrentEdge().fedgeA()
+ feB = ve.fedgeA()
+ vB = feB.vertexA()
+ vA = feA.vertexA()
+ if vA.getId().getFirst() == vB.getId().getFirst():
+ winner = ve
+ break
+ it.increment()
+ else:
+ ## case of NonTVertex
+ natures = [Nature.SILHOUETTE,Nature.BORDER,Nature.CREASE,Nature.SUGGESTIVE_CONTOUR,Nature.VALLEY,Nature.RIDGE]
+ for i in range(len(natures)):
+ currentNature = self.getCurrentEdge().getNature()
+ if(natures[i] & currentNature):
+ count=0
+ while(it.isEnd() == 0):
+ visitNext = 0
+ oNature = it.getObject().getNature()
+ if(oNature & natures[i] != 0):
+ if(natures[i] != oNature):
+ for j in range(i):
+ if(natures[j] & oNature != 0):
+ visitNext = 1
+ break
+ if(visitNext != 0):
+ break
+ count = count+1
+ winner = it.getObject()
+ it.increment()
+ if(count != 1):
+ winner = None
+ break
+ return winner
+
diff --git a/release/scripts/freestyle/style_modules/Functions0D.py b/release/scripts/freestyle/style_modules/Functions0D.py
new file mode 100644
index 00000000000..38dd4b770a6
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/Functions0D.py
@@ -0,0 +1,92 @@
+from freestyle_init import *
+
+class CurveMaterialF0D(UnaryFunction0DMaterial):
+ # A replacement of the built-in MaterialF0D for stroke creation.
+ # MaterialF0D does not work with Curves and Strokes.
+ def getName(self):
+ return "CurveMaterialF0D"
+ def __call__(self, inter):
+ cp = inter.getObject()
+ assert(isinstance(cp, CurvePoint))
+ fe = cp.A().getFEdge(cp.B())
+ assert(fe is not None)
+ return fe.material() if fe.isSmooth() else fe.bMaterial()
+
+class pyInverseCurvature2DAngleF0D(UnaryFunction0DDouble):
+ def getName(self):
+ return "InverseCurvature2DAngleF0D"
+
+ def __call__(self, inter):
+ func = Curvature2DAngleF0D()
+ c = func(inter)
+ return (3.1415 - c)
+
+class pyCurvilinearLengthF0D(UnaryFunction0DDouble):
+ def getName(self):
+ return "CurvilinearLengthF0D"
+
+ def __call__(self, inter):
+ i0d = inter.getObject()
+ s = i0d.getExactTypeName()
+ if (string.find(s, "CurvePoint") == -1):
+ print("CurvilinearLengthF0D: not implemented yet for", s)
+ return -1
+ cp = castToCurvePoint(i0d)
+ return cp.t2d()
+
+## estimate anisotropy of density
+class pyDensityAnisotropyF0D(UnaryFunction0DDouble):
+ def __init__(self,level):
+ UnaryFunction0DDouble.__init__(self)
+ self.IsoDensity = ReadCompleteViewMapPixelF0D(level)
+ self.d0Density = ReadSteerableViewMapPixelF0D(0, level)
+ self.d1Density = ReadSteerableViewMapPixelF0D(1, level)
+ self.d2Density = ReadSteerableViewMapPixelF0D(2, level)
+ self.d3Density = ReadSteerableViewMapPixelF0D(3, level)
+ def getName(self):
+ return "pyDensityAnisotropyF0D"
+ def __call__(self, inter):
+ c_iso = self.IsoDensity(inter)
+ c_0 = self.d0Density(inter)
+ c_1 = self.d1Density(inter)
+ c_2 = self.d2Density(inter)
+ c_3 = self.d3Density(inter)
+ cMax = max( max(c_0,c_1), max(c_2,c_3))
+ cMin = min( min(c_0,c_1), min(c_2,c_3))
+ if ( c_iso == 0 ):
+ v = 0
+ else:
+ v = (cMax-cMin)/c_iso
+ return (v)
+
+## Returns the gradient vector for a pixel
+## l
+## the level at which one wants to compute the gradient
+class pyViewMapGradientVectorF0D(UnaryFunction0DVec2f):
+ def __init__(self, l):
+ UnaryFunction0DVec2f.__init__(self)
+ self._l = l
+ self._step = pow(2,self._l)
+ def getName(self):
+ return "pyViewMapGradientVectorF0D"
+ def __call__(self, iter):
+ p = iter.getObject().getPoint2D()
+ gx = ReadCompleteViewMapPixelCF(self._l, int(p.x()+self._step), int(p.y()))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()))
+ gy = ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()+self._step))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()))
+ return Vector([gx, gy])
+
+class pyViewMapGradientNormF0D(UnaryFunction0DDouble):
+ def __init__(self, l):
+ UnaryFunction0DDouble.__init__(self)
+ self._l = l
+ self._step = pow(2,self._l)
+ def getName(self):
+ return "pyViewMapGradientNormF0D"
+ def __call__(self, iter):
+ p = iter.getObject().getPoint2D()
+ gx = ReadCompleteViewMapPixelCF(self._l, int(p.x()+self._step), int(p.y()))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()))
+ gy = ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()+self._step))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()))
+ grad = Vector([gx, gy])
+ return grad.length
+
+
diff --git a/release/scripts/freestyle/style_modules/Functions1D.py b/release/scripts/freestyle/style_modules/Functions1D.py
new file mode 100644
index 00000000000..aaf115356cb
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/Functions1D.py
@@ -0,0 +1,45 @@
+from freestyle_init import *
+from Functions0D import *
+import string
+
+class pyGetInverseProjectedZF1D(UnaryFunction1DDouble):
+ def getName(self):
+ return "pyGetInverseProjectedZF1D"
+
+ def __call__(self, inter):
+ func = GetProjectedZF1D()
+ z = func(inter)
+ return (1.0 - z)
+
+class pyGetSquareInverseProjectedZF1D(UnaryFunction1DDouble):
+ def getName(self):
+ return "pyGetInverseProjectedZF1D"
+
+ def __call__(self, inter):
+ func = GetProjectedZF1D()
+ z = func(inter)
+ return (1.0 - z*z)
+
+class pyDensityAnisotropyF1D(UnaryFunction1DDouble):
+ def __init__(self,level, integrationType=IntegrationType.MEAN, sampling=2.0):
+ UnaryFunction1DDouble.__init__(self, integrationType)
+ self._func = pyDensityAnisotropyF0D(level)
+ self._integration = integrationType
+ self._sampling = sampling
+ def getName(self):
+ return "pyDensityAnisotropyF1D"
+ def __call__(self, inter):
+ v = integrate(self._func, inter.pointsBegin(self._sampling), inter.pointsEnd(self._sampling), self._integration)
+ return v
+
+class pyViewMapGradientNormF1D(UnaryFunction1DDouble):
+ def __init__(self,l, integrationType, sampling=2.0):
+ UnaryFunction1DDouble.__init__(self, integrationType)
+ self._func = pyViewMapGradientNormF0D(l)
+ self._integration = integrationType
+ self._sampling = sampling
+ def getName(self):
+ return "pyViewMapGradientNormF1D"
+ def __call__(self, inter):
+ v = integrate(self._func, inter.pointsBegin(self._sampling), inter.pointsEnd(self._sampling), self._integration)
+ return v
diff --git a/release/scripts/freestyle/style_modules/PredicatesB1D.py b/release/scripts/freestyle/style_modules/PredicatesB1D.py
new file mode 100644
index 00000000000..3b7d21039df
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/PredicatesB1D.py
@@ -0,0 +1,70 @@
+from freestyle_init import *
+from Functions1D import *
+from random import *
+
+class pyZBP1D(BinaryPredicate1D):
+ def getName(self):
+ return "pyZBP1D"
+
+ def __call__(self, i1, i2):
+ func = GetZF1D()
+ return (func(i1) > func(i2))
+
+class pyZDiscontinuityBP1D(BinaryPredicate1D):
+ def __init__(self, iType = IntegrationType.MEAN):
+ BinaryPredicate1D.__init__(self)
+ self._GetZDiscontinuity = ZDiscontinuityF1D(iType)
+
+ def getName(self):
+ return "pyZDiscontinuityBP1D"
+
+ def __call__(self, i1, i2):
+ return (self._GetZDiscontinuity(i1) > self._GetZDiscontinuity(i2))
+
+class pyLengthBP1D(BinaryPredicate1D):
+ def getName(self):
+ return "LengthBP1D"
+
+ def __call__(self, i1, i2):
+ return (i1.getLength2D() > i2.getLength2D())
+
+class pySilhouetteFirstBP1D(BinaryPredicate1D):
+ def getName(self):
+ return "SilhouetteFirstBP1D"
+
+ def __call__(self, inter1, inter2):
+ bpred = SameShapeIdBP1D()
+ if (bpred(inter1, inter2) != 1):
+ return 0
+ if (inter1.getNature() & Nature.SILHOUETTE):
+ return (inter2.getNature() & Nature.SILHOUETTE)
+ return (inter1.getNature() == inter2.getNature())
+
+class pyNatureBP1D(BinaryPredicate1D):
+ def getName(self):
+ return "NatureBP1D"
+
+ def __call__(self, inter1, inter2):
+ return (inter1.getNature() & inter2.getNature())
+
+class pyViewMapGradientNormBP1D(BinaryPredicate1D):
+ def __init__(self,l, sampling=2.0):
+ BinaryPredicate1D.__init__(self)
+ self._GetGradient = pyViewMapGradientNormF1D(l, IntegrationType.MEAN)
+ def getName(self):
+ return "pyViewMapGradientNormBP1D"
+ def __call__(self, i1,i2):
+ print("compare gradient")
+ return (self._GetGradient(i1) > self._GetGradient(i2))
+
+class pyShuffleBP1D(BinaryPredicate1D):
+ def __init__(self):
+ BinaryPredicate1D.__init__(self)
+ seed(1)
+ def getName(self):
+ return "pyNearAndContourFirstBP1D"
+
+ def __call__(self, inter1, inter2):
+ r1 = uniform(0,1)
+ r2 = uniform(0,1)
+ return (r1<r2)
diff --git a/release/scripts/freestyle/style_modules/PredicatesU0D.py b/release/scripts/freestyle/style_modules/PredicatesU0D.py
new file mode 100644
index 00000000000..162254f17ed
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/PredicatesU0D.py
@@ -0,0 +1,103 @@
+from freestyle_init import *
+from Functions0D import *
+
+class pyHigherCurvature2DAngleUP0D(UnaryPredicate0D):
+ def __init__(self,a):
+ UnaryPredicate0D.__init__(self)
+ self._a = a
+
+ def getName(self):
+ return "HigherCurvature2DAngleUP0D"
+
+ def __call__(self, inter):
+ func = Curvature2DAngleF0D()
+ a = func(inter)
+ return ( a > self._a)
+
+class pyUEqualsUP0D(UnaryPredicate0D):
+ def __init__(self,u, w):
+ UnaryPredicate0D.__init__(self)
+ self._u = u
+ self._w = w
+
+ def getName(self):
+ return "UEqualsUP0D"
+
+ def __call__(self, inter):
+ func = pyCurvilinearLengthF0D()
+ u = func(inter)
+ return ( ( u > (self._u-self._w) ) and ( u < (self._u+self._w) ) )
+
+class pyVertexNatureUP0D(UnaryPredicate0D):
+ def __init__(self,nature):
+ UnaryPredicate0D.__init__(self)
+ self._nature = nature
+
+ def getName(self):
+ return "pyVertexNatureUP0D"
+
+ def __call__(self, inter):
+ v = inter.getObject()
+ nat = v.getNature()
+ if(nat & self._nature):
+ return 1;
+ return 0
+
+## check whether an Interface0DIterator
+## is a TVertex and is the one that is
+## hidden (inferred from the context)
+class pyBackTVertexUP0D(UnaryPredicate0D):
+ def __init__(self):
+ UnaryPredicate0D.__init__(self)
+ self._getQI = QuantitativeInvisibilityF0D()
+ def getName(self):
+ return "pyBackTVertexUP0D"
+ def __call__(self, iter):
+ v = iter.getObject()
+ nat = v.getNature()
+ if(nat & Nature.T_VERTEX == 0):
+ return 0
+ next = iter
+ if(next.isEnd()):
+ return 0
+ if(self._getQI(next) != 0):
+ return 1
+ return 0
+
+class pyParameterUP0DGoodOne(UnaryPredicate0D):
+ def __init__(self,pmin,pmax):
+ UnaryPredicate0D.__init__(self)
+ self._m = pmin
+ self._M = pmax
+ #self.getCurvilinearAbscissa = GetCurvilinearAbscissaF0D()
+
+ def getName(self):
+ return "pyCurvilinearAbscissaHigherThanUP0D"
+
+ def __call__(self, inter):
+ #s = self.getCurvilinearAbscissa(inter)
+ u = inter.u()
+ #print(u)
+ return ((u>=self._m) and (u<=self._M))
+
+class pyParameterUP0D(UnaryPredicate0D):
+ def __init__(self,pmin,pmax):
+ UnaryPredicate0D.__init__(self)
+ self._m = pmin
+ self._M = pmax
+ #self.getCurvilinearAbscissa = GetCurvilinearAbscissaF0D()
+
+ def getName(self):
+ return "pyCurvilinearAbscissaHigherThanUP0D"
+
+ def __call__(self, inter):
+ func = Curvature2DAngleF0D()
+ c = func(inter)
+ b1 = (c>0.1)
+ #s = self.getCurvilinearAbscissa(inter)
+ u = inter.u()
+ #print(u)
+ b = ((u>=self._m) and (u<=self._M))
+ return b and b1
+
+
diff --git a/release/scripts/freestyle/style_modules/PredicatesU1D.py b/release/scripts/freestyle/style_modules/PredicatesU1D.py
new file mode 100644
index 00000000000..3529ca8b4e3
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/PredicatesU1D.py
@@ -0,0 +1,381 @@
+from freestyle_init import *
+from Functions1D import *
+
+count = 0
+class pyNFirstUP1D(UnaryPredicate1D):
+ def __init__(self, n):
+ UnaryPredicate1D.__init__(self)
+ self.__n = n
+ def __call__(self, inter):
+ global count
+ count = count + 1
+ if count <= self.__n:
+ return 1
+ return 0
+
+class pyHigherLengthUP1D(UnaryPredicate1D):
+ def __init__(self,l):
+ UnaryPredicate1D.__init__(self)
+ self._l = l
+
+ def getName(self):
+ return "HigherLengthUP1D"
+
+ def __call__(self, inter):
+ return (inter.getLength2D() > self._l)
+
+class pyNatureUP1D(UnaryPredicate1D):
+ def __init__(self,nature):
+ UnaryPredicate1D.__init__(self)
+ self._nature = nature
+ self._getNature = CurveNatureF1D()
+
+ def getName(self):
+ return "pyNatureUP1D"
+
+ def __call__(self, inter):
+ if(self._getNature(inter) & self._nature):
+ return 1
+ return 0
+
+class pyHigherNumberOfTurnsUP1D(UnaryPredicate1D):
+ def __init__(self,n,a):
+ UnaryPredicate1D.__init__(self)
+ self._n = n
+ self._a = a
+
+ def getName(self):
+ return "HigherNumberOfTurnsUP1D"
+
+ def __call__(self, inter):
+ count = 0
+ func = Curvature2DAngleF0D()
+ it = inter.verticesBegin()
+ while(it.isEnd() == 0):
+ if(func(it) > self._a):
+ count = count+1
+ if(count > self._n):
+ return 1
+ it.increment()
+ return 0
+
+class pyDensityUP1D(UnaryPredicate1D):
+ def __init__(self,wsize,threshold, integration = IntegrationType.MEAN, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._wsize = wsize
+ self._threshold = threshold
+ self._integration = integration
+ self._func = DensityF1D(self._wsize, self._integration, sampling)
+
+ def getName(self):
+ return "pyDensityUP1D"
+
+ def __call__(self, inter):
+ if(self._func(inter) < self._threshold):
+ return 1
+ return 0
+
+class pyLowSteerableViewMapDensityUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, level,integration = IntegrationType.MEAN):
+ UnaryPredicate1D.__init__(self)
+ self._threshold = threshold
+ self._level = level
+ self._integration = integration
+
+ def getName(self):
+ return "pyLowSteerableViewMapDensityUP1D"
+
+ def __call__(self, inter):
+ func = GetSteerableViewMapDensityF1D(self._level, self._integration)
+ v = func(inter)
+ print(v)
+ if(v < self._threshold):
+ return 1
+ return 0
+
+class pyLowDirectionalViewMapDensityUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, orientation, level,integration = IntegrationType.MEAN):
+ UnaryPredicate1D.__init__(self)
+ self._threshold = threshold
+ self._orientation = orientation
+ self._level = level
+ self._integration = integration
+
+ def getName(self):
+ return "pyLowDirectionalViewMapDensityUP1D"
+
+ def __call__(self, inter):
+ func = GetDirectionalViewMapDensityF1D(self._orientation, self._level, self._integration)
+ v = func(inter)
+ #print(v)
+ if(v < self._threshold):
+ return 1
+ return 0
+
+class pyHighSteerableViewMapDensityUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, level,integration = IntegrationType.MEAN):
+ UnaryPredicate1D.__init__(self)
+ self._threshold = threshold
+ self._level = level
+ self._integration = integration
+ self._func = GetSteerableViewMapDensityF1D(self._level, self._integration)
+ def getName(self):
+ return "pyHighSteerableViewMapDensityUP1D"
+
+ def __call__(self, inter):
+
+ v = self._func(inter)
+ if(v > self._threshold):
+ return 1
+ return 0
+
+class pyHighDirectionalViewMapDensityUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, orientation, level,integration = IntegrationType.MEAN, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._threshold = threshold
+ self._orientation = orientation
+ self._level = level
+ self._integration = integration
+ self._sampling = sampling
+ def getName(self):
+ return "pyLowDirectionalViewMapDensityUP1D"
+
+ def __call__(self, inter):
+ func = GetDirectionalViewMapDensityF1D(self._orientation, self._level, self._integration, self._sampling)
+ v = func(inter)
+ if(v > self._threshold):
+ return 1
+ return 0
+
+class pyHighViewMapDensityUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, level,integration = IntegrationType.MEAN, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._threshold = threshold
+ self._level = level
+ self._integration = integration
+ self._sampling = sampling
+ self._func = GetCompleteViewMapDensityF1D(self._level, self._integration, self._sampling) # 2.0 is the smpling
+
+ def getName(self):
+ return "pyHighViewMapDensityUP1D"
+
+ def __call__(self, inter):
+ #print("toto")
+ #print(func.getName())
+ #print(inter.getExactTypeName())
+ v= self._func(inter)
+ if(v > self._threshold):
+ return 1
+ return 0
+
+class pyDensityFunctorUP1D(UnaryPredicate1D):
+ def __init__(self,wsize,threshold, functor, funcmin=0.0, funcmax=1.0, integration = IntegrationType.MEAN):
+ UnaryPredicate1D.__init__(self)
+ self._wsize = wsize
+ self._threshold = float(threshold)
+ self._functor = functor
+ self._funcmin = float(funcmin)
+ self._funcmax = float(funcmax)
+ self._integration = integration
+
+ def getName(self):
+ return "pyDensityFunctorUP1D"
+
+ def __call__(self, inter):
+ func = DensityF1D(self._wsize, self._integration)
+ res = self._functor(inter)
+ k = (res-self._funcmin)/(self._funcmax-self._funcmin)
+ if(func(inter) < self._threshold*k):
+ return 1
+ return 0
+
+class pyZSmallerUP1D(UnaryPredicate1D):
+ def __init__(self,z, integration=IntegrationType.MEAN):
+ UnaryPredicate1D.__init__(self)
+ self._z = z
+ self._integration = integration
+ def getName(self):
+ return "pyZSmallerUP1D"
+
+ def __call__(self, inter):
+ func = GetProjectedZF1D(self._integration)
+ if(func(inter) < self._z):
+ return 1
+ return 0
+
+class pyIsOccludedByUP1D(UnaryPredicate1D):
+ def __init__(self,id):
+ UnaryPredicate1D.__init__(self)
+ self._id = id
+ def getName(self):
+ return "pyIsOccludedByUP1D"
+ def __call__(self, inter):
+ func = GetShapeF1D()
+ shapes = func(inter)
+ for s in shapes:
+ if(s.getId() == self._id):
+ return 0
+ it = inter.verticesBegin()
+ itlast = inter.verticesEnd()
+ itlast.decrement()
+ v = it.getObject()
+ vlast = itlast.getObject()
+ tvertex = v.viewvertex()
+ if type(tvertex) is TVertex:
+ print("TVertex: [ ", tvertex.getId().getFirst(), ",", tvertex.getId().getSecond()," ]")
+ eit = tvertex.edgesBegin()
+ while(eit.isEnd() == 0):
+ ve, incoming = eit.getObject()
+ if(ve.getId() == self._id):
+ return 1
+ print("-------", ve.getId().getFirst(), "-", ve.getId().getSecond())
+ eit.increment()
+ tvertex = vlast.viewvertex()
+ if type(tvertex) is TVertex:
+ print("TVertex: [ ", tvertex.getId().getFirst(), ",", tvertex.getId().getSecond()," ]")
+ eit = tvertex.edgesBegin()
+ while(eit.isEnd() == 0):
+ ve, incoming = eit.getObject()
+ if(ve.getId() == self._id):
+ return 1
+ print("-------", ve.getId().getFirst(), "-", ve.getId().getSecond())
+ eit.increment()
+ return 0
+
+class pyIsInOccludersListUP1D(UnaryPredicate1D):
+ def __init__(self,id):
+ UnaryPredicate1D.__init__(self)
+ self._id = id
+ def getName(self):
+ return "pyIsInOccludersListUP1D"
+ def __call__(self, inter):
+ func = GetOccludersF1D()
+ occluders = func(inter)
+ for a in occluders:
+ if(a.getId() == self._id):
+ return 1
+ return 0
+
+class pyIsOccludedByItselfUP1D(UnaryPredicate1D):
+ def __init__(self):
+ UnaryPredicate1D.__init__(self)
+ self.__func1 = GetOccludersF1D()
+ self.__func2 = GetShapeF1D()
+ def getName(self):
+ return "pyIsOccludedByItselfUP1D"
+ def __call__(self, inter):
+ lst1 = self.__func1(inter)
+ lst2 = self.__func2(inter)
+ for vs1 in lst1:
+ for vs2 in lst2:
+ if vs1.getId() == vs2.getId():
+ return 1
+ return 0
+
+class pyIsOccludedByIdListUP1D(UnaryPredicate1D):
+ def __init__(self, idlist):
+ UnaryPredicate1D.__init__(self)
+ self._idlist = idlist
+ self.__func1 = GetOccludersF1D()
+ def getName(self):
+ return "pyIsOccludedByIdListUP1D"
+ def __call__(self, inter):
+ lst1 = self.__func1(inter)
+ for vs1 in lst1:
+ for id in self._idlist:
+ if vs1.getId() == id:
+ return 1
+ return 0
+
+class pyShapeIdListUP1D(UnaryPredicate1D):
+ def __init__(self,idlist):
+ UnaryPredicate1D.__init__(self)
+ self._idlist = idlist
+ self._funcs = []
+ for id in idlist :
+ self._funcs.append(ShapeUP1D(id.getFirst(), id.getSecond()))
+
+ def getName(self):
+ return "pyShapeIdUP1D"
+ def __call__(self, inter):
+ for func in self._funcs :
+ if(func(inter) == 1) :
+ return 1
+ return 0
+
+## deprecated
+class pyShapeIdUP1D(UnaryPredicate1D):
+ def __init__(self,id):
+ UnaryPredicate1D.__init__(self)
+ self._id = id
+ def getName(self):
+ return "pyShapeIdUP1D"
+ def __call__(self, inter):
+ func = GetShapeF1D()
+ shapes = func(inter)
+ for a in shapes:
+ if(a.getId() == self._id):
+ return 1
+ return 0
+
+class pyHighDensityAnisotropyUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, level, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._l = threshold
+ self.func = pyDensityAnisotropyF1D(level, IntegrationType.MEAN, sampling)
+ def getName(self):
+ return "pyHighDensityAnisotropyUP1D"
+ def __call__(self, inter):
+ return (self.func(inter) > self._l)
+
+class pyHighViewMapGradientNormUP1D(UnaryPredicate1D):
+ def __init__(self,threshold, l, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._threshold = threshold
+ self._GetGradient = pyViewMapGradientNormF1D(l, IntegrationType.MEAN)
+ def getName(self):
+ return "pyHighViewMapGradientNormUP1D"
+ def __call__(self, inter):
+ gn = self._GetGradient(inter)
+ #print(gn)
+ return (gn > self._threshold)
+
+class pyDensityVariableSigmaUP1D(UnaryPredicate1D):
+ def __init__(self,functor, sigmaMin,sigmaMax, lmin, lmax, tmin, tmax, integration = IntegrationType.MEAN, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._functor = functor
+ self._sigmaMin = float(sigmaMin)
+ self._sigmaMax = float(sigmaMax)
+ self._lmin = float(lmin)
+ self._lmax = float(lmax)
+ self._tmin = tmin
+ self._tmax = tmax
+ self._integration = integration
+ self._sampling = sampling
+
+ def getName(self):
+ return "pyDensityUP1D"
+
+ def __call__(self, inter):
+ sigma = (self._sigmaMax-self._sigmaMin)/(self._lmax-self._lmin)*(self._functor(inter)-self._lmin) + self._sigmaMin
+ t = (self._tmax-self._tmin)/(self._lmax-self._lmin)*(self._functor(inter)-self._lmin) + self._tmin
+ if(sigma<self._sigmaMin):
+ sigma = self._sigmaMin
+ self._func = DensityF1D(sigma, self._integration, self._sampling)
+ d = self._func(inter)
+ if(d<t):
+ return 1
+ return 0
+
+class pyClosedCurveUP1D(UnaryPredicate1D):
+ def __call__(self, inter):
+ it = inter.verticesBegin()
+ itlast = inter.verticesEnd()
+ itlast.decrement()
+ vlast = itlast.getObject()
+ v = it.getObject()
+ print(v.getId().getFirst(), v.getId().getSecond())
+ print(vlast.getId().getFirst(), vlast.getId().getSecond())
+ if(v.getId() == vlast.getId()):
+ return 1
+ return 0
diff --git a/release/scripts/freestyle/style_modules/anisotropic_diffusion.py b/release/scripts/freestyle/style_modules/anisotropic_diffusion.py
new file mode 100644
index 00000000000..7e7ebf647bd
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/anisotropic_diffusion.py
@@ -0,0 +1,74 @@
+#
+# Filename : anisotropic_diffusion.py
+# Author : Fredo Durand
+# Date : 12/08/2004
+# Purpose : Smoothes lines using an anisotropic diffusion scheme
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+from PredicatesU0D import *
+from math import *
+
+## thickness modifiers
+
+normalInfo=Normal2DF0D()
+curvatureInfo=Curvature2DAngleF0D()
+
+def edgestopping(x, sigma):
+ return exp(- x*x/(2*sigma*sigma))
+
+class pyDiffusion2Shader(StrokeShader):
+ def __init__(self, lambda1, nbIter):
+ StrokeShader.__init__(self)
+ self._lambda = lambda1
+ self._nbIter = nbIter
+ def getName(self):
+ return "pyDiffusionShader"
+ def shade(self, stroke):
+ for i in range (1, self._nbIter):
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v=it.getObject()
+ p1 = v.getPoint()
+ p2 = normalInfo(it.castToInterface0DIterator())*self._lambda*curvatureInfo(it.castToInterface0DIterator())
+ v.setPoint(p1+p2)
+ it.increment()
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D())
+Operators.select( upred )
+bpred = TrueBP1D();
+Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(upred) )
+shaders_list = [
+ ConstantThicknessShader(4),
+ StrokeTextureShader("smoothAlpha.bmp", Stroke.OPAQUE_MEDIUM, 0),
+ SamplingShader(2),
+ pyDiffusion2Shader(-0.03, 30),
+ IncreasingColorShader(1.0,0.0,0.0,1, 0, 1, 0, 1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
+
+
+
diff --git a/release/scripts/freestyle/style_modules/apriori_and_causal_density.py b/release/scripts/freestyle/style_modules/apriori_and_causal_density.py
new file mode 100644
index 00000000000..7cdd4b2fd66
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/apriori_and_causal_density.py
@@ -0,0 +1,45 @@
+#
+# Filename : apriori_and_causal_density.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Selects the lines with high a priori density and
+# subjects them to the causal density so as to avoid
+# cluttering
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), pyHighViewMapDensityUP1D(0.3, IntegrationType.LAST))
+Operators.select(upred)
+bpred = TrueBP1D()
+Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ ConstantThicknessShader(2),
+ ConstantColorShader(0.0, 0.0, 0.0,1)
+ ]
+Operators.create(pyDensityUP1D(1,0.1, IntegrationType.MEAN), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/apriori_density.py b/release/scripts/freestyle/style_modules/apriori_density.py
new file mode 100644
index 00000000000..5ff6c58e77f
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/apriori_density.py
@@ -0,0 +1,43 @@
+#
+# Filename : apriori_density.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws lines having a high a priori density
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+Operators.select(AndUP1D(QuantitativeInvisibilityUP1D(0), pyHighViewMapDensityUP1D(0.1,5)))
+bpred = TrueBP1D()
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), pyHighViewMapDensityUP1D(0.0007,5))
+Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ ConstantThicknessShader(2),
+ ConstantColorShader(0.0, 0.0, 0.0,1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/backbone_stretcher.py b/release/scripts/freestyle/style_modules/backbone_stretcher.py
new file mode 100644
index 00000000000..8a6b9d71a66
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/backbone_stretcher.py
@@ -0,0 +1,36 @@
+#
+# Filename : backbone_stretcher.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Stretches the geometry of visible lines
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [TextureAssignerShader(4), ConstantColorShader(0.5, 0.5, 0.5), BackboneStretcherShader(20)]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/blueprint_circles.py b/release/scripts/freestyle/style_modules/blueprint_circles.py
new file mode 100644
index 00000000000..7f3a7564cfe
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/blueprint_circles.py
@@ -0,0 +1,46 @@
+#
+# Filename : blueprint_circles.py
+# Author : Emmanuel Turquin
+# Date : 04/08/2005
+# Purpose : Produces a blueprint using circular contour strokes
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D())
+bpred = SameShapeIdBP1D()
+Operators.select(upred)
+Operators.bidirectionalChain(ChainPredicateIterator(upred,bpred), NotUP1D(upred))
+Operators.select(pyHigherLengthUP1D(200))
+shaders_list = [
+ ConstantThicknessShader(5),
+ pyBluePrintCirclesShader(3),
+ pyPerlinNoise1DShader(0.1, 15, 8),
+ TextureAssignerShader(4),
+ IncreasingColorShader(0.8, 0.8, 0.3, 0.4, 0.3, 0.3, 0.3, 0.1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/blueprint_ellipses.py b/release/scripts/freestyle/style_modules/blueprint_ellipses.py
new file mode 100644
index 00000000000..a5cfe4ec30b
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/blueprint_ellipses.py
@@ -0,0 +1,46 @@
+#
+# Filename : blueprint_ellipses.py
+# Author : Emmanuel Turquin
+# Date : 04/08/2005
+# Purpose : Produces a blueprint using elliptic contour strokes
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D())
+bpred = SameShapeIdBP1D()
+Operators.select(upred)
+Operators.bidirectionalChain(ChainPredicateIterator(upred,bpred), NotUP1D(upred))
+Operators.select(pyHigherLengthUP1D(200))
+shaders_list = [
+ ConstantThicknessShader(5),
+ pyBluePrintEllipsesShader(3),
+ pyPerlinNoise1DShader(0.1, 10, 8),
+ TextureAssignerShader(4),
+ IncreasingColorShader(0.6, 0.3, 0.3, 0.7, 0.3, 0.3, 0.3, 0.1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/blueprint_squares.py b/release/scripts/freestyle/style_modules/blueprint_squares.py
new file mode 100644
index 00000000000..7798acc7d47
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/blueprint_squares.py
@@ -0,0 +1,45 @@
+# Filename : blueprint_squares.py
+# Author : Emmanuel Turquin
+# Date : 04/08/2005
+# Purpose : Produces a blueprint using square contour strokes
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D())
+bpred = SameShapeIdBP1D()
+Operators.select(upred)
+Operators.bidirectionalChain(ChainPredicateIterator(upred,bpred), NotUP1D(upred))
+Operators.select(pyHigherLengthUP1D(200))
+shaders_list = [
+ ConstantThicknessShader(8),
+ pyBluePrintSquaresShader(2, 20),
+ pyPerlinNoise1DShader(0.07, 10, 8),
+ TextureAssignerShader(4),
+ IncreasingColorShader(0.6, 0.3, 0.3, 0.7, 0.6, 0.3, 0.3, 0.3),
+ ConstantThicknessShader(4)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/cartoon.py b/release/scripts/freestyle/style_modules/cartoon.py
new file mode 100644
index 00000000000..6ace7e0585a
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/cartoon.py
@@ -0,0 +1,42 @@
+#
+# Filename : cartoon.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws colored lines. The color is automatically
+# infered from each object's material in a cartoon-like
+# fashion.
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ BezierCurveShader(3),
+ ConstantThicknessShader(4),
+ pyMaterialColorShader(0.8)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/contour.py b/release/scripts/freestyle/style_modules/contour.py
new file mode 100644
index 00000000000..c4b3a0f0827
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/contour.py
@@ -0,0 +1,42 @@
+#
+# Filename : contour.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws each object's visible contour
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+Operators.select(AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D() ) )
+bpred = SameShapeIdBP1D();
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ContourUP1D())
+Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ ConstantThicknessShader(5.0),
+ IncreasingColorShader(0.8,0,0,1,0.1,0,0,1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/curvature2d.py b/release/scripts/freestyle/style_modules/curvature2d.py
new file mode 100644
index 00000000000..fc2bcab4946
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/curvature2d.py
@@ -0,0 +1,60 @@
+#
+# Filename : curvature2d.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : The stroke points are colored in gray levels and depending
+# on the 2d curvature value
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+class py2DCurvatureColorShader(StrokeShader):
+ def getName(self):
+ return "py2DCurvatureColorShader"
+
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ func = Curvature2DAngleF0D()
+ while it.isEnd() == 0:
+ it0D = it.castToInterface0DIterator()
+ sv = it.getObject()
+ att = sv.attribute()
+ c = func(it0D)
+ if (c<0):
+ print("negative 2D curvature")
+ color = 10.0 * c/3.1415
+ att.setColor(color,color,color);
+ it.increment()
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ StrokeTextureShader("smoothAlpha.bmp", Stroke.OPAQUE_MEDIUM, 0),
+ ConstantThicknessShader(5),
+ py2DCurvatureColorShader()
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/external_contour.py b/release/scripts/freestyle/style_modules/external_contour.py
new file mode 100644
index 00000000000..2a39b79a410
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/external_contour.py
@@ -0,0 +1,43 @@
+#
+# Filename : external_contour.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the external contour of the scene
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from ChainingIterators import *
+from shaders import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D())
+Operators.select(upred )
+bpred = TrueBP1D();
+Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(upred))
+shaders_list = [
+ ConstantThicknessShader(3),
+ ConstantColorShader(0.0, 0.0, 0.0,1)
+ ]
+Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file
diff --git a/release/scripts/freestyle/style_modules/external_contour_sketchy.py b/release/scripts/freestyle/style_modules/external_contour_sketchy.py
new file mode 100644
index 00000000000..8a4c570b279
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/external_contour_sketchy.py
@@ -0,0 +1,48 @@
+#
+# Filename : external_contour_sketchy.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the external contour of the scene using a sketchy
+# chaining iterator (in particular each ViewEdge can be drawn
+# several times
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D())
+Operators.select(upred)
+Operators.bidirectionalChain(pySketchyChainingIterator(), NotUP1D(upred))
+shaders_list = [
+ SamplingShader(4),
+ SpatialNoiseShader(10, 150, 2, 1, 1),
+ IncreasingThicknessShader(4, 10),
+ SmoothingShader(400, 0.1, 0, 0.2, 0, 0, 0, 1),
+ IncreasingColorShader(1,0,0,1,0,1,0,1),
+ TextureAssignerShader(4)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/external_contour_smooth.py b/release/scripts/freestyle/style_modules/external_contour_smooth.py
new file mode 100644
index 00000000000..201dc271388
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/external_contour_smooth.py
@@ -0,0 +1,44 @@
+#
+# Filename : external_contour_smooth.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws a smooth external contour
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+from ChainingIterators import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D())
+Operators.select(upred)
+bpred = TrueBP1D();
+Operators.bidirectionalChain(ChainPredicateIterator(upred, bpred), NotUP1D(upred))
+shaders_list = [
+ SamplingShader(2),
+ IncreasingThicknessShader(4,20),
+ IncreasingColorShader(1.0, 0.0, 0.5,1, 0.5,1, 0.3, 1),
+ SmoothingShader(100, 0.05, 0, 0.2, 0, 0, 0, 1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/extra-lines.sml b/release/scripts/freestyle/style_modules/extra-lines.sml
new file mode 100644
index 00000000000..c63cd40945d
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/extra-lines.sml
@@ -0,0 +1,3 @@
+1suggestive.py
+1ridges.py
+1nor_suggestive_or_ridges.py
diff --git a/release/scripts/freestyle/style_modules/freestyle_init.py b/release/scripts/freestyle/style_modules/freestyle_init.py
new file mode 100644
index 00000000000..9eb8b2d6340
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/freestyle_init.py
@@ -0,0 +1,2 @@
+from Freestyle import *
+from mathutils import Vector
diff --git a/release/scripts/freestyle/style_modules/haloing.py b/release/scripts/freestyle/style_modules/haloing.py
new file mode 100644
index 00000000000..afa46173d54
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/haloing.py
@@ -0,0 +1,50 @@
+#
+# Filename : haloing.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : This style module selects the lines that
+# are connected (in the image) to a specific
+# object and trims them in order to produce
+# a haloing effect around the target shape
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from PredicatesB1D import *
+from shaders import *
+
+# id corresponds to the id of the target object
+# (accessed by SHIFT+click)
+id = Id(3,0)
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0) , pyIsOccludedByUP1D(id))
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+shaders_list = [
+ IncreasingThicknessShader(3, 5),
+ IncreasingColorShader(1,0,0, 1,0,1,0,1),
+ SamplingShader(1.0),
+ pyTVertexRemoverShader(),
+ TipRemoverShader(3.0)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/ignore_small_occlusions.py b/release/scripts/freestyle/style_modules/ignore_small_occlusions.py
new file mode 100644
index 00000000000..ff6efa89ade
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/ignore_small_occlusions.py
@@ -0,0 +1,41 @@
+#
+# Filename : ignore_small_oclusions.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : The strokes are drawn through small occlusions
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+#Operators.bidirectionalChain(pyFillOcclusionsChainingIterator(0.1))
+Operators.bidirectionalChain(pyFillOcclusionsAbsoluteChainingIterator(12))
+shaders_list = [
+ SamplingShader(5.0),
+ ConstantThicknessShader(3),
+ ConstantColorShader(0.0,0.0,0.0),
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/invisible_lines.py b/release/scripts/freestyle/style_modules/invisible_lines.py
new file mode 100644
index 00000000000..ea509463bfd
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/invisible_lines.py
@@ -0,0 +1,42 @@
+#
+# Filename : invisible_lines.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws all lines whose Quantitative Invisibility
+# is different from 0
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+upred = NotUP1D(QuantitativeInvisibilityUP1D(0))
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+shaders_list = [
+ SamplingShader(5.0),
+ ConstantThicknessShader(3.0),
+ ConstantColorShader(0.7,0.7,0.7)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/japanese_bigbrush.py b/release/scripts/freestyle/style_modules/japanese_bigbrush.py
new file mode 100644
index 00000000000..7f109598aaa
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/japanese_bigbrush.py
@@ -0,0 +1,60 @@
+#
+# Filename : japanese_bigbrush.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Simulates a big brush fr oriental painting
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from PredicatesB1D import *
+from Functions0D import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0)))
+## Splits strokes at points of highest 2D curavture
+## when there are too many abrupt turns in it
+func = pyInverseCurvature2DAngleF0D()
+Operators.recursiveSplit(func, pyParameterUP0D(0.2,0.8), NotUP1D(pyHigherNumberOfTurnsUP1D(3, 0.5)), 2)
+## Keeps only long enough strokes
+Operators.select(pyHigherLengthUP1D(100))
+## Sorts so as to draw the longest strokes first
+## (this will be done using the causal density)
+Operators.sort(pyLengthBP1D())
+shaders_list = [
+ pySamplingShader(10),
+ BezierCurveShader(30),
+ SamplingShader(50),
+ ConstantThicknessShader(10),
+ pyNonLinearVaryingThicknessShader(4,25, 0.6),
+ TextureAssignerShader(6),
+ ConstantColorShader(0.2, 0.2, 0.2,1.0),
+ TipRemoverShader(10)
+ ]
+
+## Use the causal density to avoid cluttering
+Operators.create(pyDensityUP1D(8,0.4, IntegrationType.MEAN), shaders_list)
+
+
diff --git a/release/scripts/freestyle/style_modules/logical_operators.py b/release/scripts/freestyle/style_modules/logical_operators.py
new file mode 100644
index 00000000000..0ecf6623697
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/logical_operators.py
@@ -0,0 +1,36 @@
+from freestyle_init import *
+
+class AndUP1D(UnaryPredicate1D):
+ def __init__(self, pred1, pred2):
+ UnaryPredicate1D.__init__(self)
+ self.__pred1 = pred1
+ self.__pred2 = pred2
+
+ def getName(self):
+ return "AndUP1D"
+
+ def __call__(self, inter):
+ return self.__pred1(inter) and self.__pred2(inter)
+
+class OrUP1D(UnaryPredicate1D):
+ def __init__(self, pred1, pred2):
+ UnaryPredicate1D.__init__(self)
+ self.__pred1 = pred1
+ self.__pred2 = pred2
+
+ def getName(self):
+ return "OrUP1D"
+
+ def __call__(self, inter):
+ return self.__pred1(inter) or self.__pred2(inter)
+
+class NotUP1D(UnaryPredicate1D):
+ def __init__(self, pred):
+ UnaryPredicate1D.__init__(self)
+ self.__pred = pred
+
+ def getName(self):
+ return "NotUP1D"
+
+ def __call__(self, inter):
+ return self.__pred(inter) == 0
diff --git a/release/scripts/freestyle/style_modules/long_anisotropically_dense.py b/release/scripts/freestyle/style_modules/long_anisotropically_dense.py
new file mode 100644
index 00000000000..155ee489680
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/long_anisotropically_dense.py
@@ -0,0 +1,81 @@
+#
+# Filename : long_anisotropically_dense.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Selects the lines that are long and have a high anisotropic
+# a priori density and uses causal density
+# to draw without cluttering. Ideally, half of the
+# selected lines are culled using the causal density.
+#
+# ********************* WARNING *************************************
+# ******** The Directional a priori density maps must ******
+# ******** have been computed prior to using this style module ******
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from PredicatesU0D import *
+from PredicatesB1D import *
+from Functions0D import *
+from Functions1D import *
+from shaders import *
+
+## custom density predicate
+class pyDensityUP1D(UnaryPredicate1D):
+ def __init__(self,wsize,threshold, integration = IntegrationType.MEAN, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._wsize = wsize
+ self._threshold = threshold
+ self._integration = integration
+ self._func = DensityF1D(self._wsize, self._integration, sampling)
+ self._func2 = DensityF1D(self._wsize, IntegrationType.MAX, sampling)
+
+ def getName(self):
+ return "pyDensityUP1D"
+
+ def __call__(self, inter):
+ c = self._func(inter)
+ m = self._func2(inter)
+ if(c < self._threshold):
+ return 1
+ if( m > 4* c ):
+ if ( c < 1.5*self._threshold ):
+ return 1
+ return 0
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0)))
+Operators.select(pyHigherLengthUP1D(40))
+## selects lines having a high anisotropic a priori density
+Operators.select(pyHighDensityAnisotropyUP1D(0.3,4))
+Operators.sort(pyLengthBP1D())
+shaders_list = [
+ SamplingShader(2.0),
+ ConstantThicknessShader(2),
+ ConstantColorShader(0.2,0.2,0.25,1),
+ ]
+## uniform culling
+Operators.create(pyDensityUP1D(3.0,2.0e-2, IntegrationType.MEAN, 0.1), shaders_list)
+
+
diff --git a/release/scripts/freestyle/style_modules/multiple_parameterization.py b/release/scripts/freestyle/style_modules/multiple_parameterization.py
new file mode 100644
index 00000000000..3f0409db5fa
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/multiple_parameterization.py
@@ -0,0 +1,51 @@
+#
+# Filename : multiple_parameterization.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : The thickness and the color of the strokes vary continuously
+# independently from occlusions although only
+# visible lines are actually drawn. This is equivalent
+# to assigning the thickness using a parameterization covering
+# the complete silhouette (visible+invisible) and drawing
+# the strokes using a second parameterization that only
+# covers the visible portions.
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+## Chain following the same nature, but without the restriction
+## of staying inside the selection (0).
+Operators.bidirectionalChain(ChainSilhouetteIterator(0))
+shaders_list = [
+ SamplingShader(20),
+ IncreasingThicknessShader(1.5, 30),
+ ConstantColorShader(0.0,0.0,0.0),
+ IncreasingColorShader(1,0,0,1,0,1,0,1),
+ TextureAssignerShader(-1),
+ pyHLRShader() ## this shader draws only visible portions
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/nature.py b/release/scripts/freestyle/style_modules/nature.py
new file mode 100644
index 00000000000..b5481a8e519
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/nature.py
@@ -0,0 +1,43 @@
+#
+# Filename : nature.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Uses the NatureUP1D predicate to select the lines
+# of a given type (among Nature.SILHOUETTE, Nature.CREASE, Nature.SUGGESTIVE_CONTOURS,
+# Nature.BORDERS).
+# The suggestive contours must have been enabled in the
+# options dialog to appear in the View Map.
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+Operators.select(pyNatureUP1D(Nature.SILHOUETTE))
+Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D( pyNatureUP1D( Nature.SILHOUETTE) ) )
+shaders_list = [
+ IncreasingThicknessShader(3, 10),
+ IncreasingColorShader(0.0,0.0,0.0, 1, 0.8,0,0,1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/near_lines.py b/release/scripts/freestyle/style_modules/near_lines.py
new file mode 100644
index 00000000000..565bca1fe1f
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/near_lines.py
@@ -0,0 +1,44 @@
+#
+# Filename : near_lines.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the lines that are "closer" than a threshold
+# (between 0 and 1)
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), pyZSmallerUP1D(0.5, IntegrationType.MEAN))
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+shaders_list = [
+ TextureAssignerShader(-1),
+ ConstantThicknessShader(5),
+ ConstantColorShader(0.0, 0.0, 0.0)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/occluded_by_specific_object.py b/release/scripts/freestyle/style_modules/occluded_by_specific_object.py
new file mode 100644
index 00000000000..09ce39d5dd6
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/occluded_by_specific_object.py
@@ -0,0 +1,45 @@
+#
+# Filename : occluded_by_specific_object.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws only the lines that are occluded by a given object
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from shaders import *
+
+## the id of the occluder (use SHIFT+click on the ViewMap to
+## retrieve ids)
+id = Id(3,0)
+upred = AndUP1D(NotUP1D(QuantitativeInvisibilityUP1D(0)),
+pyIsInOccludersListUP1D(id))
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+shaders_list = [
+ SamplingShader(5),
+ ConstantThicknessShader(3),
+ ConstantColorShader(0.3,0.3,0.3,1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/parameter_editor.py b/release/scripts/freestyle/style_modules/parameter_editor.py
new file mode 100644
index 00000000000..76ca49adaa6
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/parameter_editor.py
@@ -0,0 +1,1317 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import Freestyle
+import math
+import mathutils
+import time
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+class ColorRampModifier(StrokeShader):
+ def __init__(self, blend, influence, ramp):
+ StrokeShader.__init__(self)
+ self.__blend = blend
+ self.__influence = influence
+ self.__ramp = ramp
+ def evaluate(self, t):
+ col = Freestyle.evaluateColorRamp(self.__ramp, t)
+ col = col.xyz # omit alpha
+ return col
+ def blend_ramp(self, a, b):
+ return Freestyle.blendRamp(self.__blend, a, self.__influence, b)
+
+class ScalarBlendModifier(StrokeShader):
+ def __init__(self, blend, influence):
+ StrokeShader.__init__(self)
+ self.__blend = blend
+ self.__influence = influence
+ def blend(self, v1, v2):
+ fac = self.__influence
+ facm = 1.0 - fac
+ if self.__blend == "MIX":
+ v1 = facm * v1 + fac * v2
+ elif self.__blend == "ADD":
+ v1 += fac * v2
+ elif self.__blend == "MULTIPLY":
+ v1 *= facm + fac * v2;
+ elif self.__blend == "SUBTRACT":
+ v1 -= fac * v2
+ elif self.__blend == "DIVIDE":
+ if v2 != 0.0:
+ v1 = facm * v1 + fac * v1 / v2
+ elif self.__blend == "DIFFERENCE":
+ v1 = facm * v1 + fac * abs(v1 - v2)
+ elif self.__blend == "MININUM":
+ tmp = fac * v1
+ if v1 > tmp:
+ v1 = tmp
+ elif self.__blend == "MAXIMUM":
+ tmp = fac * v1
+ if v1 < tmp:
+ v1 = tmp
+ else:
+ raise ValueError("unknown curve blend type: " + self.__blend)
+ return v1
+
+class CurveMappingModifier(ScalarBlendModifier):
+ def __init__(self, blend, influence, mapping, invert, curve):
+ ScalarBlendModifier.__init__(self, blend, influence)
+ assert mapping in ("LINEAR", "CURVE")
+ self.__mapping = getattr(self, mapping)
+ self.__invert = invert
+ self.__curve = curve
+ def LINEAR(self, t):
+ if self.__invert:
+ return 1.0 - t
+ return t
+ def CURVE(self, t):
+ return Freestyle.evaluateCurveMappingF(self.__curve, 0, t)
+ def evaluate(self, t):
+ return self.__mapping(t)
+
+class ThicknessModifierMixIn:
+ def __init__(self):
+ scene = Freestyle.getCurrentScene()
+ self.__persp_camera = (scene.camera.data.type == "PERSP")
+ def set_thickness(self, sv, outer, inner):
+ fe = sv.A().getFEdge(sv.B())
+ nature = fe.getNature()
+ if (nature & Nature.BORDER):
+ if self.__persp_camera:
+ point = -sv.getPoint3D()
+ point.normalize()
+ dir = point.dot(fe.normalB())
+ else:
+ dir = fe.normalB().z
+ if dir < 0.0: # the back side is visible
+ outer, inner = inner, outer
+ elif (nature & Nature.SILHOUETTE):
+ if fe.isSmooth(): # TODO more tests needed
+ outer, inner = inner, outer
+ else:
+ outer = inner = (outer + inner) / 2
+ sv.attribute().setThickness(outer, inner)
+
+class ThicknessBlenderMixIn(ThicknessModifierMixIn):
+ def __init__(self, position, ratio):
+ ThicknessModifierMixIn.__init__(self)
+ self.__position = position
+ self.__ratio = ratio
+ def blend_thickness(self, outer, inner, v):
+ if self.__position == "CENTER":
+ outer = self.blend(outer, v / 2)
+ inner = self.blend(inner, v / 2)
+ elif self.__position == "INSIDE":
+ outer = self.blend(outer, 0)
+ inner = self.blend(inner, v)
+ elif self.__position == "OUTSIDE":
+ outer = self.blend(outer, v)
+ inner = self.blend(inner, 0)
+ elif self.__position == "RELATIVE":
+ outer = self.blend(outer, v * self.__ratio)
+ inner = self.blend(inner, v * (1 - self.__ratio))
+ else:
+ raise ValueError("unknown thickness position: " + self.__position)
+ return outer, inner
+
+class BaseColorShader(ConstantColorShader):
+ def getName(self):
+ return "BaseColorShader"
+
+class BaseThicknessShader(StrokeShader, ThicknessModifierMixIn):
+ def __init__(self, thickness, position, ratio):
+ StrokeShader.__init__(self)
+ ThicknessModifierMixIn.__init__(self)
+ if position == "CENTER":
+ self.__outer = thickness / 2
+ self.__inner = thickness / 2
+ elif position == "INSIDE":
+ self.__outer = 0
+ self.__inner = thickness
+ elif position == "OUTSIDE":
+ self.__outer = thickness
+ self.__inner = 0
+ elif position == "RELATIVE":
+ self.__outer = thickness * ratio
+ self.__inner = thickness * (1 - ratio)
+ else:
+ raise ValueError("unknown thickness position: " + self.position)
+ def getName(self):
+ return "BaseThicknessShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ sv = it.getObject()
+ self.set_thickness(sv, self.__outer, self.__inner)
+ it.increment()
+
+# Along Stroke modifiers
+
+def iter_t2d_along_stroke(stroke):
+ total = stroke.getLength2D()
+ distance = 0.0
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ p = it.getObject().getPoint()
+ if not it.isBegin():
+ distance += (prev - p).length
+ prev = p
+ t = min(distance / total, 1.0)
+ yield it, t
+ it.increment()
+
+class ColorAlongStrokeShader(ColorRampModifier):
+ def getName(self):
+ return "ColorAlongStrokeShader"
+ def shade(self, stroke):
+ for it, t in iter_t2d_along_stroke(stroke):
+ attr = it.getObject().attribute()
+ a = attr.getColorRGB()
+ b = self.evaluate(t)
+ c = self.blend_ramp(a, b)
+ attr.setColor(c)
+
+class AlphaAlongStrokeShader(CurveMappingModifier):
+ def getName(self):
+ return "AlphaAlongStrokeShader"
+ def shade(self, stroke):
+ for it, t in iter_t2d_along_stroke(stroke):
+ attr = it.getObject().attribute()
+ a = attr.getAlpha()
+ b = self.evaluate(t)
+ c = self.blend(a, b)
+ attr.setAlpha(c)
+
+class ThicknessAlongStrokeShader(ThicknessBlenderMixIn, CurveMappingModifier):
+ def __init__(self, thickness_position, thickness_ratio,
+ blend, influence, mapping, invert, curve, value_min, value_max):
+ ThicknessBlenderMixIn.__init__(self, thickness_position, thickness_ratio)
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__value_min = value_min
+ self.__value_max = value_max
+ def getName(self):
+ return "ThicknessAlongStrokeShader"
+ def shade(self, stroke):
+ for it, t in iter_t2d_along_stroke(stroke):
+ sv = it.getObject()
+ a = sv.attribute().getThicknessRL()
+ b = self.__value_min + self.evaluate(t) * (self.__value_max - self.__value_min)
+ c = self.blend_thickness(a[0], a[1], b)
+ self.set_thickness(sv, c[0], c[1])
+
+# Distance from Camera modifiers
+
+def iter_distance_from_camera(stroke, range_min, range_max):
+ normfac = range_max - range_min # normalization factor
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ p = it.getObject().getPoint3D() # in the camera coordinate
+ distance = p.length
+ if distance < range_min:
+ t = 0.0
+ elif distance > range_max:
+ t = 1.0
+ else:
+ t = (distance - range_min) / normfac
+ yield it, t
+ it.increment()
+
+class ColorDistanceFromCameraShader(ColorRampModifier):
+ def __init__(self, blend, influence, ramp, range_min, range_max):
+ ColorRampModifier.__init__(self, blend, influence, ramp)
+ self.__range_min = range_min
+ self.__range_max = range_max
+ def getName(self):
+ return "ColorDistanceFromCameraShader"
+ def shade(self, stroke):
+ for it, t in iter_distance_from_camera(stroke, self.__range_min, self.__range_max):
+ attr = it.getObject().attribute()
+ a = attr.getColorRGB()
+ b = self.evaluate(t)
+ c = self.blend_ramp(a, b)
+ attr.setColor(c)
+
+class AlphaDistanceFromCameraShader(CurveMappingModifier):
+ def __init__(self, blend, influence, mapping, invert, curve, range_min, range_max):
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__range_min = range_min
+ self.__range_max = range_max
+ def getName(self):
+ return "AlphaDistanceFromCameraShader"
+ def shade(self, stroke):
+ for it, t in iter_distance_from_camera(stroke, self.__range_min, self.__range_max):
+ attr = it.getObject().attribute()
+ a = attr.getAlpha()
+ b = self.evaluate(t)
+ c = self.blend(a, b)
+ attr.setAlpha(c)
+
+class ThicknessDistanceFromCameraShader(ThicknessBlenderMixIn, CurveMappingModifier):
+ def __init__(self, thickness_position, thickness_ratio,
+ blend, influence, mapping, invert, curve, range_min, range_max, value_min, value_max):
+ ThicknessBlenderMixIn.__init__(self, thickness_position, thickness_ratio)
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__range_min = range_min
+ self.__range_max = range_max
+ self.__value_min = value_min
+ self.__value_max = value_max
+ def getName(self):
+ return "ThicknessDistanceFromCameraShader"
+ def shade(self, stroke):
+ for it, t in iter_distance_from_camera(stroke, self.__range_min, self.__range_max):
+ sv = it.getObject()
+ a = sv.attribute().getThicknessRL()
+ b = self.__value_min + self.evaluate(t) * (self.__value_max - self.__value_min)
+ c = self.blend_thickness(a[0], a[1], b)
+ self.set_thickness(sv, c[0], c[1])
+
+# Distance from Object modifiers
+
+def iter_distance_from_object(stroke, object, range_min, range_max):
+ scene = Freestyle.getCurrentScene()
+ mv = scene.camera.matrix_world.copy() # model-view matrix
+ mv.invert()
+ loc = mv * object.location # loc in the camera coordinate
+ normfac = range_max - range_min # normalization factor
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ p = it.getObject().getPoint3D() # in the camera coordinate
+ distance = (p - loc).length
+ if distance < range_min:
+ t = 0.0
+ elif distance > range_max:
+ t = 1.0
+ else:
+ t = (distance - range_min) / normfac
+ yield it, t
+ it.increment()
+
+class ColorDistanceFromObjectShader(ColorRampModifier):
+ def __init__(self, blend, influence, ramp, target, range_min, range_max):
+ ColorRampModifier.__init__(self, blend, influence, ramp)
+ self.__target = target
+ self.__range_min = range_min
+ self.__range_max = range_max
+ def getName(self):
+ return "ColorDistanceFromObjectShader"
+ def shade(self, stroke):
+ if self.__target is None:
+ return
+ for it, t in iter_distance_from_object(stroke, self.__target, self.__range_min, self.__range_max):
+ attr = it.getObject().attribute()
+ a = attr.getColorRGB()
+ b = self.evaluate(t)
+ c = self.blend_ramp(a, b)
+ attr.setColor(c)
+
+class AlphaDistanceFromObjectShader(CurveMappingModifier):
+ def __init__(self, blend, influence, mapping, invert, curve, target, range_min, range_max):
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__target = target
+ self.__range_min = range_min
+ self.__range_max = range_max
+ def getName(self):
+ return "AlphaDistanceFromObjectShader"
+ def shade(self, stroke):
+ if self.__target is None:
+ return
+ for it, t in iter_distance_from_object(stroke, self.__target, self.__range_min, self.__range_max):
+ attr = it.getObject().attribute()
+ a = attr.getAlpha()
+ b = self.evaluate(t)
+ c = self.blend(a, b)
+ attr.setAlpha(c)
+
+class ThicknessDistanceFromObjectShader(ThicknessBlenderMixIn, CurveMappingModifier):
+ def __init__(self, thickness_position, thickness_ratio,
+ blend, influence, mapping, invert, curve, target, range_min, range_max, value_min, value_max):
+ ThicknessBlenderMixIn.__init__(self, thickness_position, thickness_ratio)
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__target = target
+ self.__range_min = range_min
+ self.__range_max = range_max
+ self.__value_min = value_min
+ self.__value_max = value_max
+ def getName(self):
+ return "ThicknessDistanceFromObjectShader"
+ def shade(self, stroke):
+ if self.__target is None:
+ return
+ for it, t in iter_distance_from_object(stroke, self.__target, self.__range_min, self.__range_max):
+ sv = it.getObject()
+ a = sv.attribute().getThicknessRL()
+ b = self.__value_min + self.evaluate(t) * (self.__value_max - self.__value_min)
+ c = self.blend_thickness(a[0], a[1], b)
+ self.set_thickness(sv, c[0], c[1])
+
+# Material modifiers
+
+def iter_material_color(stroke, material_attr):
+ func = CurveMaterialF0D()
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ material = func(it.castToInterface0DIterator())
+ if material_attr == "DIFF":
+ color = (material.diffuseR(),
+ material.diffuseG(),
+ material.diffuseB())
+ elif material_attr == "SPEC":
+ color = (material.specularR(),
+ material.specularG(),
+ material.specularB())
+ else:
+ raise ValueError("unexpected material attribute: " + material_attr)
+ yield it, color
+ it.increment()
+
+def iter_material_value(stroke, material_attr):
+ func = CurveMaterialF0D()
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ material = func(it.castToInterface0DIterator())
+ if material_attr == "DIFF":
+ r = material.diffuseR()
+ g = material.diffuseG()
+ b = material.diffuseB()
+ t = 0.35 * r + 0.45 * r + 0.2 * b
+ elif material_attr == "DIFF_R":
+ t = material.diffuseR()
+ elif material_attr == "DIFF_G":
+ t = material.diffuseG()
+ elif material_attr == "DIFF_B":
+ t = material.diffuseB()
+ elif material_attr == "SPEC":
+ r = material.specularR()
+ g = material.specularG()
+ b = material.specularB()
+ t = 0.35 * r + 0.45 * r + 0.2 * b
+ elif material_attr == "SPEC_R":
+ t = material.specularR()
+ elif material_attr == "SPEC_G":
+ t = material.specularG()
+ elif material_attr == "SPEC_B":
+ t = material.specularB()
+ elif material_attr == "SPEC_HARDNESS":
+ t = material.shininess()
+ elif material_attr == "ALPHA":
+ t = material.diffuseA()
+ else:
+ raise ValueError("unexpected material attribute: " + material_attr)
+ yield it, t
+ it.increment()
+
+class ColorMaterialShader(ColorRampModifier):
+ def __init__(self, blend, influence, ramp, material_attr, use_ramp):
+ ColorRampModifier.__init__(self, blend, influence, ramp)
+ self.__material_attr = material_attr
+ self.__use_ramp = use_ramp
+ def getName(self):
+ return "ColorMaterialShader"
+ def shade(self, stroke):
+ if self.__material_attr in ["DIFF", "SPEC"] and not self.__use_ramp:
+ for it, b in iter_material_color(stroke, self.__material_attr):
+ attr = it.getObject().attribute()
+ a = attr.getColorRGB()
+ c = self.blend_ramp(a, b)
+ attr.setColor(c)
+ else:
+ for it, t in iter_material_value(stroke, self.__material_attr):
+ attr = it.getObject().attribute()
+ a = attr.getColorRGB()
+ b = self.evaluate(t)
+ c = self.blend_ramp(a, b)
+ attr.setColor(c)
+
+class AlphaMaterialShader(CurveMappingModifier):
+ def __init__(self, blend, influence, mapping, invert, curve, material_attr):
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__material_attr = material_attr
+ def getName(self):
+ return "AlphaMaterialShader"
+ def shade(self, stroke):
+ for it, t in iter_material_value(stroke, self.__material_attr):
+ attr = it.getObject().attribute()
+ a = attr.getAlpha()
+ b = self.evaluate(t)
+ c = self.blend(a, b)
+ attr.setAlpha(c)
+
+class ThicknessMaterialShader(ThicknessBlenderMixIn, CurveMappingModifier):
+ def __init__(self, thickness_position, thickness_ratio,
+ blend, influence, mapping, invert, curve, material_attr, value_min, value_max):
+ ThicknessBlenderMixIn.__init__(self, thickness_position, thickness_ratio)
+ CurveMappingModifier.__init__(self, blend, influence, mapping, invert, curve)
+ self.__material_attr = material_attr
+ self.__value_min = value_min
+ self.__value_max = value_max
+ def getName(self):
+ return "ThicknessMaterialShader"
+ def shade(self, stroke):
+ for it, t in iter_material_value(stroke, self.__material_attr):
+ sv = it.getObject()
+ a = sv.attribute().getThicknessRL()
+ b = self.__value_min + self.evaluate(t) * (self.__value_max - self.__value_min)
+ c = self.blend_thickness(a[0], a[1], b)
+ self.set_thickness(sv, c[0], c[1])
+
+# Calligraphic thickness modifier
+
+class CalligraphicThicknessShader(ThicknessBlenderMixIn, ScalarBlendModifier):
+ def __init__(self, thickness_position, thickness_ratio,
+ blend, influence, orientation, min_thickness, max_thickness):
+ ThicknessBlenderMixIn.__init__(self, thickness_position, thickness_ratio)
+ ScalarBlendModifier.__init__(self, blend, influence)
+ self.__orientation = mathutils.Vector((math.cos(orientation), math.sin(orientation)))
+ self.__min_thickness = min_thickness
+ self.__max_thickness = max_thickness
+ def shade(self, stroke):
+ func = VertexOrientation2DF0D()
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ dir = func(it.castToInterface0DIterator())
+ orthDir = mathutils.Vector((-dir.y, dir.x))
+ orthDir.normalize()
+ fac = abs(orthDir * self.__orientation)
+ sv = it.getObject()
+ a = sv.attribute().getThicknessRL()
+ b = self.__min_thickness + fac * (self.__max_thickness - self.__min_thickness)
+ b = max(b, 0.0)
+ c = self.blend_thickness(a[0], a[1], b)
+ self.set_thickness(sv, c[0], c[1])
+ it.increment()
+
+# Geometry modifiers
+
+def iter_distance_along_stroke(stroke):
+ distance = 0.0
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ p = it.getObject().getPoint()
+ if not it.isBegin():
+ distance += (prev - p).length
+ prev = p
+ yield it, distance
+ it.increment()
+
+class SinusDisplacementShader(StrokeShader):
+ def __init__(self, wavelength, amplitude, phase):
+ StrokeShader.__init__(self)
+ self._wavelength = wavelength
+ self._amplitude = amplitude
+ self._phase = phase / wavelength * 2 * math.pi
+ self._getNormal = Normal2DF0D()
+ def getName(self):
+ return "SinusDisplacementShader"
+ def shade(self, stroke):
+ for it, distance in iter_distance_along_stroke(stroke):
+ v = it.getObject()
+ n = self._getNormal(it.castToInterface0DIterator())
+ p = v.getPoint()
+ u = v.u()
+ n = n * self._amplitude * math.cos(distance / self._wavelength * 2 * math.pi + self._phase)
+ v.setPoint(p + n)
+ stroke.UpdateLength()
+
+class PerlinNoise1DShader(StrokeShader):
+ def __init__(self, freq = 10, amp = 10, oct = 4, angle = math.radians(45), seed = -1):
+ StrokeShader.__init__(self)
+ self.__noise = Noise(seed)
+ self.__freq = freq
+ self.__amp = amp
+ self.__oct = oct
+ self.__dir = Vector([cos(angle), sin(angle)])
+ def getName(self):
+ return "PerlinNoise1DShader"
+ def shade(self, stroke):
+ length = stroke.getLength2D()
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ v = it.getObject()
+ nres = self.__noise.turbulence1(length * v.u(), self.__freq, self.__amp, self.__oct)
+ v.setPoint(v.getPoint() + nres * self.__dir)
+ it.increment()
+ stroke.UpdateLength()
+
+class PerlinNoise2DShader(StrokeShader):
+ def __init__(self, freq = 10, amp = 10, oct = 4, angle = math.radians(45), seed = -1):
+ StrokeShader.__init__(self)
+ self.__noise = Noise(seed)
+ self.__freq = freq
+ self.__amp = amp
+ self.__oct = oct
+ self.__dir = Vector([cos(angle), sin(angle)])
+ def getName(self):
+ return "PerlinNoise2DShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ v = it.getObject()
+ vec = Vector([v.getProjectedX(), v.getProjectedY()])
+ nres = self.__noise.turbulence2(vec, self.__freq, self.__amp, self.__oct)
+ v.setPoint(v.getPoint() + nres * self.__dir)
+ it.increment()
+ stroke.UpdateLength()
+
+class Offset2DShader(StrokeShader):
+ def __init__(self, start, end, x, y):
+ StrokeShader.__init__(self)
+ self.__start = start
+ self.__end = end
+ self.__xy = Vector([x, y])
+ self.__getNormal = Normal2DF0D()
+ def getName(self):
+ return "Offset2DShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ v = it.getObject()
+ u = v.u()
+ a = self.__start + u * (self.__end - self.__start)
+ n = self.__getNormal(it.castToInterface0DIterator())
+ n = n * a
+ p = v.getPoint()
+ v.setPoint(p + n + self.__xy)
+ it.increment()
+ stroke.UpdateLength()
+
+class Transform2DShader(StrokeShader):
+ def __init__(self, pivot, scale_x, scale_y, angle, pivot_u, pivot_x, pivot_y):
+ StrokeShader.__init__(self)
+ self.__pivot = pivot
+ self.__scale_x = scale_x
+ self.__scale_y = scale_y
+ self.__angle = angle
+ self.__pivot_u = pivot_u
+ self.__pivot_x = pivot_x
+ self.__pivot_y = pivot_y
+ def getName(self):
+ return "Transform2DShader"
+ def shade(self, stroke):
+ # determine the pivot of scaling and rotation operations
+ if self.__pivot == "START":
+ it = stroke.strokeVerticesBegin()
+ pivot = it.getObject().getPoint()
+ elif self.__pivot == "END":
+ it = stroke.strokeVerticesEnd()
+ it.decrement()
+ pivot = it.getObject().getPoint()
+ elif self.__pivot == "PARAM":
+ p = None
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ prev = p
+ v = it.getObject()
+ p = v.getPoint()
+ u = v.u()
+ if self.__pivot_u < u:
+ break
+ it.increment()
+ if prev is None:
+ pivot = p
+ else:
+ delta = u - self.__pivot_u
+ pivot = p + delta * (prev - p)
+ elif self.__pivot == "CENTER":
+ pivot = Vector([0.0, 0.0])
+ n = 0
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ p = it.getObject().getPoint()
+ pivot = pivot + p
+ n = n + 1
+ it.increment()
+ pivot.x = pivot.x / n
+ pivot.y = pivot.y / n
+ elif self.__pivot == "ABSOLUTE":
+ pivot = Vector([self.__pivot_x, self.__pivot_y])
+ # apply scaling and rotation operations
+ cos_theta = math.cos(self.__angle)
+ sin_theta = math.sin(self.__angle)
+ it = stroke.strokeVerticesBegin()
+ while not it.isEnd():
+ v = it.getObject()
+ p = v.getPoint()
+ p = p - pivot
+ x = p.x * self.__scale_x
+ y = p.y * self.__scale_y
+ p.x = x * cos_theta - y * sin_theta
+ p.y = x * sin_theta + y * cos_theta
+ v.setPoint(p + pivot)
+ it.increment()
+ stroke.UpdateLength()
+
+# Predicates and helper functions
+
+class QuantitativeInvisibilityRangeUP1D(UnaryPredicate1D):
+ def __init__(self, qi_start, qi_end):
+ UnaryPredicate1D.__init__(self)
+ self.__getQI = QuantitativeInvisibilityF1D()
+ self.__qi_start = qi_start
+ self.__qi_end = qi_end
+ def getName(self):
+ return "QuantitativeInvisibilityRangeUP1D"
+ def __call__(self, inter):
+ qi = self.__getQI(inter)
+ return self.__qi_start <= qi <= self.__qi_end
+
+def join_unary_predicates(upred_list, bpred):
+ if not upred_list:
+ return None
+ upred = upred_list[0]
+ for p in upred_list[1:]:
+ upred = bpred(upred, p)
+ return upred
+
+class ObjectNamesUP1D(UnaryPredicate1D):
+ def __init__(self, names, negative):
+ UnaryPredicate1D.__init__(self)
+ self._names = names
+ self._negative = negative
+ def getName(self):
+ return "ObjectNamesUP1D"
+ def __call__(self, viewEdge):
+ found = viewEdge.viewShape().getName() in self._names
+ if self._negative:
+ return not found
+ return found
+
+# Stroke caps
+
+def iter_stroke_vertices(stroke):
+ it = stroke.strokeVerticesBegin()
+ prev_p = None
+ while not it.isEnd():
+ sv = it.getObject()
+ p = sv.getPoint()
+ if prev_p is None or (prev_p - p).length > 1e-6:
+ yield sv
+ prev_p = p
+ it.increment()
+
+class RoundCapShader(StrokeShader):
+ def round_cap_thickness(self, x):
+ x = max(0.0, min(x, 1.0))
+ return math.sqrt(1.0 - (x ** 2))
+ def shade(self, stroke):
+ # save the location and attribute of stroke vertices
+ buffer = []
+ for sv in iter_stroke_vertices(stroke):
+ buffer.append((sv.getPoint(), sv.attribute()))
+ nverts = len(buffer)
+ if nverts < 2:
+ return
+ # calculate the number of additional vertices to form caps
+ R, L = stroke[0].attribute().getThicknessRL()
+ caplen_beg = (R + L) / 2.0
+ nverts_beg = max(5, int(R + L))
+ R, L = stroke[-1].attribute().getThicknessRL()
+ caplen_end = (R + L) / 2.0
+ nverts_end = max(5, int(R + L))
+ # adjust the total number of stroke vertices
+ stroke.Resample(nverts + nverts_beg + nverts_end)
+ # restore the location and attribute of the original vertices
+ for i in range(nverts):
+ p, attr = buffer[i]
+ stroke[nverts_beg + i].setPoint(p)
+ stroke[nverts_beg + i].setAttribute(attr)
+ # reshape the cap at the beginning of the stroke
+ q, attr = buffer[1]
+ p, attr = buffer[0]
+ d = p - q
+ d = d / d.length * caplen_beg
+ n = 1.0 / nverts_beg
+ R, L = attr.getThicknessRL()
+ for i in range(nverts_beg):
+ t = (nverts_beg - i) * n
+ stroke[i].setPoint(p + d * t)
+ r = self.round_cap_thickness((nverts_beg - i + 1) * n)
+ stroke[i].setAttribute(attr)
+ stroke[i].attribute().setThickness(R * r, L * r)
+ # reshape the cap at the end of the stroke
+ q, attr = buffer[-2]
+ p, attr = buffer[-1]
+ d = p - q
+ d = d / d.length * caplen_end
+ n = 1.0 / nverts_end
+ R, L = attr.getThicknessRL()
+ for i in range(nverts_end):
+ t = (nverts_end - i) * n
+ stroke[-i-1].setPoint(p + d * t)
+ r = self.round_cap_thickness((nverts_end - i + 1) * n)
+ stroke[-i-1].setAttribute(attr)
+ stroke[-i-1].attribute().setThickness(R * r, L * r)
+ # update the curvilinear 2D length of each vertex
+ stroke.UpdateLength()
+
+class SquareCapShader(StrokeShader):
+ def shade(self, stroke):
+ # save the location and attribute of stroke vertices
+ buffer = []
+ for sv in iter_stroke_vertices(stroke):
+ buffer.append((sv.getPoint(), sv.attribute()))
+ nverts = len(buffer)
+ if nverts < 2:
+ return
+ # calculate the number of additional vertices to form caps
+ R, L = stroke[0].attribute().getThicknessRL()
+ caplen_beg = (R + L) / 2.0
+ nverts_beg = 1
+ R, L = stroke[-1].attribute().getThicknessRL()
+ caplen_end = (R + L) / 2.0
+ nverts_end = 1
+ # adjust the total number of stroke vertices
+ stroke.Resample(nverts + nverts_beg + nverts_end)
+ # restore the location and attribute of the original vertices
+ for i in range(nverts):
+ p, attr = buffer[i]
+ stroke[nverts_beg + i].setPoint(p)
+ stroke[nverts_beg + i].setAttribute(attr)
+ # reshape the cap at the beginning of the stroke
+ q, attr = buffer[1]
+ p, attr = buffer[0]
+ d = p - q
+ stroke[0].setPoint(p + d / d.length * caplen_beg)
+ stroke[0].setAttribute(attr)
+ # reshape the cap at the end of the stroke
+ q, attr = buffer[-2]
+ p, attr = buffer[-1]
+ d = p - q
+ stroke[-1].setPoint(p + d / d.length * caplen_beg)
+ stroke[-1].setAttribute(attr)
+ # update the curvilinear 2D length of each vertex
+ stroke.UpdateLength()
+
+# Split by dashed line pattern
+
+class SplitPatternStartingUP0D(UnaryPredicate0D):
+ def __init__(self, controller):
+ UnaryPredicate0D.__init__(self)
+ self._controller = controller
+ def __call__(self, inter):
+ return self._controller.start()
+
+class SplitPatternStoppingUP0D(UnaryPredicate0D):
+ def __init__(self, controller):
+ UnaryPredicate0D.__init__(self)
+ self._controller = controller
+ def __call__(self, inter):
+ return self._controller.stop()
+
+class SplitPatternController:
+ def __init__(self, pattern, sampling):
+ self.sampling = float(sampling)
+ k = len(pattern) // 2
+ n = k * 2
+ self.start_pos = [pattern[i] + pattern[i+1] for i in range(0, n, 2)]
+ self.stop_pos = [pattern[i] for i in range(0, n, 2)]
+ self.init()
+ def init(self):
+ self.start_len = 0.0
+ self.start_idx = 0
+ self.stop_len = self.sampling
+ self.stop_idx = 0
+ def start(self):
+ self.start_len += self.sampling
+ if abs(self.start_len - self.start_pos[self.start_idx]) < self.sampling / 2.0:
+ self.start_len = 0.0
+ self.start_idx = (self.start_idx + 1) % len(self.start_pos)
+ return True
+ return False
+ def stop(self):
+ if self.start_len > 0.0:
+ self.init()
+ self.stop_len += self.sampling
+ if abs(self.stop_len - self.stop_pos[self.stop_idx]) < self.sampling / 2.0:
+ self.stop_len = self.sampling
+ self.stop_idx = (self.stop_idx + 1) % len(self.stop_pos)
+ return True
+ return False
+
+# Dashed line
+
+class DashedLineShader(StrokeShader):
+ def __init__(self, pattern):
+ StrokeShader.__init__(self)
+ self._pattern = pattern
+ def getName(self):
+ return "DashedLineShader"
+ def shade(self, stroke):
+ index = 0 # pattern index
+ start = 0.0 # 2D curvilinear length
+ visible = True
+ sampling = 1.0
+ it = stroke.strokeVerticesBegin(sampling)
+ while not it.isEnd():
+ pos = it.t()
+ # The extra 'sampling' term is added below, because the
+ # visibility attribute of the i-th vertex refers to the
+ # visibility of the stroke segment between the i-th and
+ # (i+1)-th vertices.
+ if pos - start + sampling > self._pattern[index]:
+ start = pos
+ index += 1
+ if index == len(self._pattern):
+ index = 0
+ visible = not visible
+ it.getObject().attribute().setVisible(visible)
+ it.increment()
+
+# predicates for chaining
+
+class AngleLargerThanBP1D(BinaryPredicate1D):
+ def __init__(self, angle):
+ BinaryPredicate1D.__init__(self)
+ self._angle = angle
+ def getName(self):
+ return "AngleLargerThanBP1D"
+ def __call__(self, i1, i2):
+ fe1a = i1.fedgeA()
+ fe1b = i1.fedgeB()
+ fe2a = i2.fedgeA()
+ fe2b = i2.fedgeB()
+ sv1a = fe1a.vertexA().getPoint2D()
+ sv1b = fe1b.vertexB().getPoint2D()
+ sv2a = fe2a.vertexA().getPoint2D()
+ sv2b = fe2b.vertexB().getPoint2D()
+ if (sv1a - sv2a).length < 1e-6:
+ dir1 = sv1a - sv1b
+ dir2 = sv2b - sv2a
+ elif (sv1b - sv2b).length < 1e-6:
+ dir1 = sv1b - sv1a
+ dir2 = sv2a - sv2b
+ elif (sv1a - sv2b).length < 1e-6:
+ dir1 = sv1a - sv1b
+ dir2 = sv2a - sv2b
+ elif (sv1b - sv2a).length < 1e-6:
+ dir1 = sv1b - sv1a
+ dir2 = sv2b - sv2a
+ else:
+ return False
+ denom = dir1.length * dir2.length
+ if denom < 1e-6:
+ return False
+ x = (dir1 * dir2) / denom
+ return math.acos(min(max(x, -1.0), 1.0)) > self._angle
+
+class AndBP1D(BinaryPredicate1D):
+ def __init__(self, pred1, pred2):
+ BinaryPredicate1D.__init__(self)
+ self.__pred1 = pred1
+ self.__pred2 = pred2
+ def getName(self):
+ return "AndBP1D"
+ def __call__(self, i1, i2):
+ return self.__pred1(i1, i2) and self.__pred2(i1, i2)
+
+# predicates for selection
+
+class LengthThresholdUP1D(UnaryPredicate1D):
+ def __init__(self, min_length=None, max_length=None):
+ UnaryPredicate1D.__init__(self)
+ self._min_length = min_length
+ self._max_length = max_length
+ def getName(self):
+ return "LengthThresholdUP1D"
+ def __call__(self, inter):
+ length = inter.getLength2D()
+ if self._min_length is not None and length < self._min_length:
+ return False
+ if self._max_length is not None and length > self._max_length:
+ return False
+ return True
+
+class FaceMarkBothUP1D(UnaryPredicate1D):
+ def __call__(self, inter): # ViewEdge
+ fe = inter.fedgeA()
+ while fe is not None:
+ if fe.isSmooth():
+ if fe.faceMark():
+ return True
+ else:
+ if fe.aFaceMark() and fe.bFaceMark():
+ return True
+ fe = fe.nextEdge()
+ return False
+
+class FaceMarkOneUP1D(UnaryPredicate1D):
+ def __call__(self, inter): # ViewEdge
+ fe = inter.fedgeA()
+ while fe is not None:
+ if fe.isSmooth():
+ if fe.faceMark():
+ return True
+ else:
+ if fe.aFaceMark() or fe.bFaceMark():
+ return True
+ fe = fe.nextEdge()
+ return False
+
+# predicates for splitting
+
+class MaterialBoundaryUP0D(UnaryPredicate0D):
+ def getName(self):
+ return "MaterialBoundaryUP0D"
+ def __call__(self, it):
+ if it.isBegin():
+ return False
+ it_prev = Interface0DIterator(it)
+ it_prev.decrement()
+ v = it.getObject()
+ it.increment()
+ if it.isEnd():
+ return False
+ fe = v.getFEdge(it_prev.getObject())
+ idx1 = fe.materialIndex() if fe.isSmooth() else fe.bMaterialIndex()
+ fe = v.getFEdge(it.getObject())
+ idx2 = fe.materialIndex() if fe.isSmooth() else fe.bMaterialIndex()
+ return idx1 != idx2
+
+class Curvature2DAngleThresholdUP0D(UnaryPredicate0D):
+ def __init__(self, min_angle=None, max_angle=None):
+ UnaryPredicate0D.__init__(self)
+ self._min_angle = min_angle
+ self._max_angle = max_angle
+ self._func = Curvature2DAngleF0D()
+ def getName(self):
+ return "Curvature2DAngleThresholdUP0D"
+ def __call__(self, inter):
+ angle = math.pi - self._func(inter)
+ if self._min_angle is not None and angle < self._min_angle:
+ return True
+ if self._max_angle is not None and angle > self._max_angle:
+ return True
+ return False
+
+class Length2DThresholdUP0D(UnaryPredicate0D):
+ def __init__(self, length_limit):
+ UnaryPredicate0D.__init__(self)
+ self._length_limit = length_limit
+ self._t = 0.0
+ def getName(self):
+ return "Length2DThresholdUP0D"
+ def __call__(self, inter):
+ t = inter.t() # curvilinear abscissa
+ if t < self._t:
+ self._t = 0.0
+ return False
+ if t - self._t < self._length_limit:
+ return False
+ self._t = t
+ return True
+
+# Seed for random number generation
+
+class Seed:
+ def __init__(self):
+ self.t_max = 2 ** 15
+ self.t = int(time.time()) % self.t_max
+ def get(self, seed):
+ if seed < 0:
+ self.t = (self.t + 1) % self.t_max
+ return self.t
+ return seed
+
+_seed = Seed()
+
+# main function for parameter processing
+
+def process(layer_name, lineset_name):
+ scene = Freestyle.getCurrentScene()
+ layer = scene.render.layers[layer_name]
+ lineset = layer.freestyle_settings.linesets[lineset_name]
+ linestyle = lineset.linestyle
+
+ selection_criteria = []
+ # prepare selection criteria by visibility
+ if lineset.select_by_visibility:
+ if lineset.visibility == "VISIBLE":
+ selection_criteria.append(
+ QuantitativeInvisibilityUP1D(0))
+ elif lineset.visibility == "HIDDEN":
+ selection_criteria.append(
+ NotUP1D(QuantitativeInvisibilityUP1D(0)))
+ elif lineset.visibility == "RANGE":
+ selection_criteria.append(
+ QuantitativeInvisibilityRangeUP1D(lineset.qi_start, lineset.qi_end))
+ # prepare selection criteria by edge types
+ if lineset.select_by_edge_types:
+ edge_type_criteria = []
+ if lineset.select_silhouette:
+ upred = pyNatureUP1D(Nature.SILHOUETTE)
+ edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_silhouette else upred)
+ if lineset.select_border:
+ upred = pyNatureUP1D(Nature.BORDER)
+ edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_border else upred)
+ if lineset.select_crease:
+ upred = pyNatureUP1D(Nature.CREASE)
+ edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_crease else upred)
+ if lineset.select_ridge_valley:
+ upred = pyNatureUP1D(Nature.RIDGE)
+ edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_ridge_valley else upred)
+ if lineset.select_suggestive_contour:
+ upred = pyNatureUP1D(Nature.SUGGESTIVE_CONTOUR)
+ edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_suggestive_contour else upred)
+ if lineset.select_material_boundary:
+ upred = pyNatureUP1D(Nature.MATERIAL_BOUNDARY)
+ edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_material_boundary else upred)
+ if lineset.select_edge_mark:
+ upred = pyNatureUP1D(Nature.EDGE_MARK)
+ edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_edge_mark else upred)
+ if lineset.select_contour:
+ upred = ContourUP1D()
+ edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_contour else upred)
+ if lineset.select_external_contour:
+ upred = ExternalContourUP1D()
+ edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_external_contour else upred)
+ if lineset.edge_type_combination == "OR":
+ upred = join_unary_predicates(edge_type_criteria, OrUP1D)
+ else:
+ upred = join_unary_predicates(edge_type_criteria, AndUP1D)
+ if upred is not None:
+ if lineset.edge_type_negation == "EXCLUSIVE":
+ upred = NotUP1D(upred)
+ selection_criteria.append(upred)
+ # prepare selection criteria by face marks
+ if lineset.select_by_face_marks:
+ if lineset.face_mark_condition == "BOTH":
+ upred = FaceMarkBothUP1D()
+ else:
+ upred = FaceMarkOneUP1D()
+ if lineset.face_mark_negation == "EXCLUSIVE":
+ upred = NotUP1D(upred)
+ selection_criteria.append(upred)
+ # prepare selection criteria by group of objects
+ if lineset.select_by_group:
+ if lineset.group is not None:
+ names = dict((ob.name, True) for ob in lineset.group.objects)
+ upred = ObjectNamesUP1D(names, lineset.group_negation == 'EXCLUSIVE')
+ selection_criteria.append(upred)
+ # prepare selection criteria by image border
+ if lineset.select_by_image_border:
+ w = scene.render.resolution_x
+ h = scene.render.resolution_y
+ if scene.render.use_border:
+ xmin = scene.render.border_min_x * w
+ xmax = scene.render.border_max_x * w
+ ymin = scene.render.border_min_y * h
+ ymax = scene.render.border_max_y * h
+ else:
+ xmin, xmax = 0.0, float(w)
+ ymin, ymax = 0.0, float(h)
+ upred = WithinImageBoundaryUP1D(xmin, ymin, xmax, ymax)
+ selection_criteria.append(upred)
+ # select feature edges
+ upred = join_unary_predicates(selection_criteria, AndUP1D)
+ if upred is None:
+ upred = TrueUP1D()
+ Operators.select(upred)
+ # join feature edges to form chains
+ if linestyle.use_chaining:
+ if linestyle.chaining == "PLAIN":
+ if linestyle.same_object:
+ Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+ else:
+ Operators.bidirectionalChain(ChainPredicateIterator(upred, TrueBP1D()), NotUP1D(upred))
+ elif linestyle.chaining == "SKETCHY":
+ if linestyle.same_object:
+ Operators.bidirectionalChain(pySketchyChainSilhouetteIterator(linestyle.rounds))
+ else:
+ Operators.bidirectionalChain(pySketchyChainingIterator(linestyle.rounds))
+ else:
+ Operators.chain(ChainPredicateIterator(FalseUP1D(), FalseBP1D()), NotUP1D(upred))
+ # split chains
+ if linestyle.material_boundary:
+ Operators.sequentialSplit(MaterialBoundaryUP0D())
+ if linestyle.use_min_angle or linestyle.use_max_angle:
+ min_angle = linestyle.min_angle if linestyle.use_min_angle else None
+ max_angle = linestyle.max_angle if linestyle.use_max_angle else None
+ Operators.sequentialSplit(Curvature2DAngleThresholdUP0D(min_angle, max_angle))
+ if linestyle.use_split_length:
+ Operators.sequentialSplit(Length2DThresholdUP0D(linestyle.split_length), 1.0)
+ if linestyle.use_split_pattern:
+ pattern = []
+ if linestyle.split_dash1 > 0 and linestyle.split_gap1 > 0:
+ pattern.append(linestyle.split_dash1)
+ pattern.append(linestyle.split_gap1)
+ if linestyle.split_dash2 > 0 and linestyle.split_gap2 > 0:
+ pattern.append(linestyle.split_dash2)
+ pattern.append(linestyle.split_gap2)
+ if linestyle.split_dash3 > 0 and linestyle.split_gap3 > 0:
+ pattern.append(linestyle.split_dash3)
+ pattern.append(linestyle.split_gap3)
+ if len(pattern) > 0:
+ sampling = 1.0
+ controller = SplitPatternController(pattern, sampling)
+ Operators.sequentialSplit(SplitPatternStartingUP0D(controller),
+ SplitPatternStoppingUP0D(controller),
+ sampling)
+ # select chains
+ if linestyle.use_min_length or linestyle.use_max_length:
+ min_length = linestyle.min_length if linestyle.use_min_length else None
+ max_length = linestyle.max_length if linestyle.use_max_length else None
+ Operators.select(LengthThresholdUP1D(min_length, max_length))
+ # prepare a list of stroke shaders
+ shaders_list = []
+ for m in linestyle.geometry_modifiers:
+ if not m.use:
+ continue
+ if m.type == "SAMPLING":
+ shaders_list.append(SamplingShader(
+ m.sampling))
+ elif m.type == "BEZIER_CURVE":
+ shaders_list.append(BezierCurveShader(
+ m.error))
+ elif m.type == "SINUS_DISPLACEMENT":
+ shaders_list.append(SinusDisplacementShader(
+ m.wavelength, m.amplitude, m.phase))
+ elif m.type == "SPATIAL_NOISE":
+ shaders_list.append(SpatialNoiseShader(
+ m.amplitude, m.scale, m.octaves, m.smooth, m.pure_random))
+ elif m.type == "PERLIN_NOISE_1D":
+ shaders_list.append(PerlinNoise1DShader(
+ m.frequency, m.amplitude, m.octaves, m.angle, _seed.get(m.seed)))
+ elif m.type == "PERLIN_NOISE_2D":
+ shaders_list.append(PerlinNoise2DShader(
+ m.frequency, m.amplitude, m.octaves, m.angle, _seed.get(m.seed)))
+ elif m.type == "BACKBONE_STRETCHER":
+ shaders_list.append(BackboneStretcherShader(
+ m.backbone_length))
+ elif m.type == "TIP_REMOVER":
+ shaders_list.append(TipRemoverShader(
+ m.tip_length))
+ elif m.type == "POLYGONIZATION":
+ shaders_list.append(PolygonalizationShader(
+ m.error))
+ elif m.type == "GUIDING_LINES":
+ shaders_list.append(GuidingLinesShader(
+ m.offset))
+ elif m.type == "BLUEPRINT":
+ if m.shape == "CIRCLES":
+ shaders_list.append(pyBluePrintCirclesShader(
+ m.rounds, m.random_radius, m.random_center))
+ elif m.shape == "ELLIPSES":
+ shaders_list.append(pyBluePrintEllipsesShader(
+ m.rounds, m.random_radius, m.random_center))
+ elif m.shape == "SQUARES":
+ shaders_list.append(pyBluePrintSquaresShader(
+ m.rounds, m.backbone_length, m.random_backbone))
+ elif m.type == "2D_OFFSET":
+ shaders_list.append(Offset2DShader(
+ m.start, m.end, m.x, m.y))
+ elif m.type == "2D_TRANSFORM":
+ shaders_list.append(Transform2DShader(
+ m.pivot, m.scale_x, m.scale_y, m.angle, m.pivot_u, m.pivot_x, m.pivot_y))
+ color = linestyle.color
+ if (not linestyle.use_chaining) or (linestyle.chaining == "PLAIN" and linestyle.same_object):
+ thickness_position = linestyle.thickness_position
+ else:
+ thickness_position = "CENTER"
+ import bpy
+ if bpy.app.debug_freestyle:
+ print("Warning: Thickness position options are applied when chaining is disabled")
+ print(" or the Plain chaining is used with the Same Object option enabled.")
+ shaders_list.append(BaseColorShader(color.r, color.g, color.b, linestyle.alpha))
+ shaders_list.append(BaseThicknessShader(linestyle.thickness, thickness_position,
+ linestyle.thickness_ratio))
+ for m in linestyle.color_modifiers:
+ if not m.use:
+ continue
+ if m.type == "ALONG_STROKE":
+ shaders_list.append(ColorAlongStrokeShader(
+ m.blend, m.influence, m.color_ramp))
+ elif m.type == "DISTANCE_FROM_CAMERA":
+ shaders_list.append(ColorDistanceFromCameraShader(
+ m.blend, m.influence, m.color_ramp,
+ m.range_min, m.range_max))
+ elif m.type == "DISTANCE_FROM_OBJECT":
+ shaders_list.append(ColorDistanceFromObjectShader(
+ m.blend, m.influence, m.color_ramp, m.target,
+ m.range_min, m.range_max))
+ elif m.type == "MATERIAL":
+ shaders_list.append(ColorMaterialShader(
+ m.blend, m.influence, m.color_ramp, m.material_attr,
+ m.use_ramp))
+ for m in linestyle.alpha_modifiers:
+ if not m.use:
+ continue
+ if m.type == "ALONG_STROKE":
+ shaders_list.append(AlphaAlongStrokeShader(
+ m.blend, m.influence, m.mapping, m.invert, m.curve))
+ elif m.type == "DISTANCE_FROM_CAMERA":
+ shaders_list.append(AlphaDistanceFromCameraShader(
+ m.blend, m.influence, m.mapping, m.invert, m.curve,
+ m.range_min, m.range_max))
+ elif m.type == "DISTANCE_FROM_OBJECT":
+ shaders_list.append(AlphaDistanceFromObjectShader(
+ m.blend, m.influence, m.mapping, m.invert, m.curve, m.target,
+ m.range_min, m.range_max))
+ elif m.type == "MATERIAL":
+ shaders_list.append(AlphaMaterialShader(
+ m.blend, m.influence, m.mapping, m.invert, m.curve,
+ m.material_attr))
+ for m in linestyle.thickness_modifiers:
+ if not m.use:
+ continue
+ if m.type == "ALONG_STROKE":
+ shaders_list.append(ThicknessAlongStrokeShader(
+ thickness_position, linestyle.thickness_ratio,
+ m.blend, m.influence, m.mapping, m.invert, m.curve,
+ m.value_min, m.value_max))
+ elif m.type == "DISTANCE_FROM_CAMERA":
+ shaders_list.append(ThicknessDistanceFromCameraShader(
+ thickness_position, linestyle.thickness_ratio,
+ m.blend, m.influence, m.mapping, m.invert, m.curve,
+ m.range_min, m.range_max, m.value_min, m.value_max))
+ elif m.type == "DISTANCE_FROM_OBJECT":
+ shaders_list.append(ThicknessDistanceFromObjectShader(
+ thickness_position, linestyle.thickness_ratio,
+ m.blend, m.influence, m.mapping, m.invert, m.curve, m.target,
+ m.range_min, m.range_max, m.value_min, m.value_max))
+ elif m.type == "MATERIAL":
+ shaders_list.append(ThicknessMaterialShader(
+ thickness_position, linestyle.thickness_ratio,
+ m.blend, m.influence, m.mapping, m.invert, m.curve,
+ m.material_attr, m.value_min, m.value_max))
+ elif m.type == "CALLIGRAPHY":
+ shaders_list.append(CalligraphicThicknessShader(
+ thickness_position, linestyle.thickness_ratio,
+ m.blend, m.influence,
+ m.orientation, m.min_thickness, m.max_thickness))
+ if linestyle.caps == "ROUND":
+ shaders_list.append(RoundCapShader())
+ elif linestyle.caps == "SQUARE":
+ shaders_list.append(SquareCapShader())
+ if linestyle.use_dashed_line:
+ pattern = []
+ if linestyle.dash1 > 0 and linestyle.gap1 > 0:
+ pattern.append(linestyle.dash1)
+ pattern.append(linestyle.gap1)
+ if linestyle.dash2 > 0 and linestyle.gap2 > 0:
+ pattern.append(linestyle.dash2)
+ pattern.append(linestyle.gap2)
+ if linestyle.dash3 > 0 and linestyle.gap3 > 0:
+ pattern.append(linestyle.dash3)
+ pattern.append(linestyle.gap3)
+ if len(pattern) > 0:
+ shaders_list.append(DashedLineShader(pattern))
+ # create strokes using the shaders list
+ Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/polygonalize.py b/release/scripts/freestyle/style_modules/polygonalize.py
new file mode 100644
index 00000000000..4446c4c1dcc
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/polygonalize.py
@@ -0,0 +1,40 @@
+#
+# Filename : polygonalize.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Make the strokes more "polygonal"
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(),NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ SamplingShader(2.0),
+ ConstantThicknessShader(3),
+ ConstantColorShader(0.0,0.0,0.0),
+ PolygonalizationShader(8)
+ ]
+Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file
diff --git a/release/scripts/freestyle/style_modules/qi0.py b/release/scripts/freestyle/style_modules/qi0.py
new file mode 100644
index 00000000000..d35d23cb7c3
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/qi0.py
@@ -0,0 +1,41 @@
+#
+# Filename : qi0.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the visible lines (chaining follows same nature lines)
+# (most basic style module)
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ SamplingShader(5.0),
+ ConstantThicknessShader(4.0),
+ ConstantColorShader(0.0,0.0,0.0)
+ ]
+Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file
diff --git a/release/scripts/freestyle/style_modules/qi0_not_external_contour.py b/release/scripts/freestyle/style_modules/qi0_not_external_contour.py
new file mode 100644
index 00000000000..eed41af32b4
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/qi0_not_external_contour.py
@@ -0,0 +1,43 @@
+#
+# Filename : qi0_not_external_contour.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the visible lines (chaining follows same nature lines)
+# that do not belong to the external contour of the scene
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+
+upred = AndUP1D(QuantitativeInvisibilityUP1D(0), ExternalContourUP1D())
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+shaders_list = [
+ SamplingShader(4),
+ SpatialNoiseShader(4, 150, 2, True, True),
+ IncreasingThicknessShader(2, 5),
+ BackboneStretcherShader(20),
+ IncreasingColorShader(1,0,0,1,0,1,0,1),
+ TextureAssignerShader(4)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/qi1.py b/release/scripts/freestyle/style_modules/qi1.py
new file mode 100644
index 00000000000..8d248376138
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/qi1.py
@@ -0,0 +1,42 @@
+#
+# Filename : qi1.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws lines hidden by one surface.
+# *** Quantitative Invisibility must have been
+# enabled in the options dialog to use this style module ****
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(1))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(1)))
+shaders_list = [
+ SamplingShader(5.0),
+ ConstantThicknessShader(3),
+ ConstantColorShader(0.5,0.5,0.5, 1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/qi2.py b/release/scripts/freestyle/style_modules/qi2.py
new file mode 100644
index 00000000000..ba5e97b6982
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/qi2.py
@@ -0,0 +1,42 @@
+#
+# Filename : qi2.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws lines hidden by two surfaces.
+# *** Quantitative Invisibility must have been
+# enabled in the options dialog to use this style module ****
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(2))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(2)))
+shaders_list = [
+ SamplingShader(10),
+ ConstantThicknessShader(1.5),
+ ConstantColorShader(0.7,0.7,0.7, 1)
+ ]
+Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file
diff --git a/release/scripts/freestyle/style_modules/sequentialsplit_sketchy.py b/release/scripts/freestyle/style_modules/sequentialsplit_sketchy.py
new file mode 100644
index 00000000000..53fa03103aa
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/sequentialsplit_sketchy.py
@@ -0,0 +1,68 @@
+#
+# Filename : sequentialsplit_sketchy.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Use the sequential split with two different
+# predicates to specify respectively the starting and
+# the stopping extremities for strokes
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from PredicatesU0D import *
+from Functions0D import *
+
+## Predicate to tell whether a TVertex
+## corresponds to a change from 0 to 1 or not.
+class pyBackTVertexUP0D(UnaryPredicate0D):
+ def __init__(self):
+ UnaryPredicate0D.__init__(self)
+ self._getQI = QuantitativeInvisibilityF0D()
+ def getName(self):
+ return "pyBackTVertexUP0D"
+ def __call__(self, iter):
+ v = iter.getObject()
+ nat = v.getNature()
+ if(nat & Nature.T_VERTEX == 0):
+ return 0
+ if(self._getQI(iter) != 0):
+ return 1
+ return 0
+
+
+upred = QuantitativeInvisibilityUP1D(0)
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+## starting and stopping predicates:
+start = pyVertexNatureUP0D(Nature.NON_T_VERTEX)
+stop = pyBackTVertexUP0D()
+Operators.sequentialSplit(start, stop, 10)
+shaders_list = [
+ SpatialNoiseShader(7, 120, 2, True, True),
+ IncreasingThicknessShader(5, 8),
+ ConstantColorShader(0.2, 0.2, 0.2, 1),
+ TextureAssignerShader(4)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
+
diff --git a/release/scripts/freestyle/style_modules/shaders.py b/release/scripts/freestyle/style_modules/shaders.py
new file mode 100644
index 00000000000..f05042f8332
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/shaders.py
@@ -0,0 +1,1344 @@
+from freestyle_init import *
+from PredicatesU0D import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from logical_operators import *
+from ChainingIterators import *
+from random import *
+from math import *
+
+## thickness modifiers
+######################
+
+class pyDepthDiscontinuityThicknessShader(StrokeShader):
+ def __init__(self, min, max):
+ StrokeShader.__init__(self)
+ self.__min = float(min)
+ self.__max = float(max)
+ self.__func = ZDiscontinuityF0D()
+ def getName(self):
+ return "pyDepthDiscontinuityThicknessShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ z_min=0.0
+ z_max=1.0
+ a = (self.__max - self.__min)/(z_max-z_min)
+ b = (self.__min*z_max-self.__max*z_min)/(z_max-z_min)
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ z = self.__func(it.castToInterface0DIterator())
+ thickness = a*z+b
+ it.getObject().attribute().setThickness(thickness, thickness)
+ it.increment()
+
+class pyConstantThicknessShader(StrokeShader):
+ def __init__(self, thickness):
+ StrokeShader.__init__(self)
+ self._thickness = thickness
+
+ def getName(self):
+ return "pyConstantThicknessShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ t = self._thickness/2.0
+ att.setThickness(t, t)
+ it.increment()
+
+class pyFXSThicknessShader(StrokeShader):
+ def __init__(self, thickness):
+ StrokeShader.__init__(self)
+ self._thickness = thickness
+
+ def getName(self):
+ return "pyFXSThicknessShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ t = self._thickness/2.0
+ att.setThickness(t, t)
+ it.increment()
+
+class pyFXSVaryingThicknessWithDensityShader(StrokeShader):
+ def __init__(self, wsize, threshold_min, threshold_max, thicknessMin, thicknessMax):
+ StrokeShader.__init__(self)
+ self.wsize= wsize
+ self.threshold_min= threshold_min
+ self.threshold_max= threshold_max
+ self._thicknessMin = thicknessMin
+ self._thicknessMax = thicknessMax
+
+ def getName(self):
+ return "pyVaryingThicknessWithDensityShader"
+ def shade(self, stroke):
+ n = stroke.strokeVerticesSize()
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ func = DensityF0D(self.wsize)
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ toto = it.castToInterface0DIterator()
+ c= func(toto)
+ if (c < self.threshold_min ):
+ c = self.threshold_min
+ if (c > self.threshold_max ):
+ c = self.threshold_max
+## t = (c - self.threshold_min)/(self.threshold_max - self.threshold_min)*(self._thicknessMax-self._thicknessMin) + self._thicknessMin
+ t = (self.threshold_max - c )/(self.threshold_max - self.threshold_min)*(self._thicknessMax-self._thicknessMin) + self._thicknessMin
+ att.setThickness(t/2.0, t/2.0)
+ i = i+1
+ it.increment()
+class pyIncreasingThicknessShader(StrokeShader):
+ def __init__(self, thicknessMin, thicknessMax):
+ StrokeShader.__init__(self)
+ self._thicknessMin = thicknessMin
+ self._thicknessMax = thicknessMax
+
+ def getName(self):
+ return "pyIncreasingThicknessShader"
+ def shade(self, stroke):
+ n = stroke.strokeVerticesSize()
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ c = float(i)/float(n)
+ if(i < float(n)/2.0):
+ t = (1.0 - c)*self._thicknessMin + c * self._thicknessMax
+ else:
+ t = (1.0 - c)*self._thicknessMax + c * self._thicknessMin
+ att.setThickness(t/2.0, t/2.0)
+ i = i+1
+ it.increment()
+
+class pyConstrainedIncreasingThicknessShader(StrokeShader):
+ def __init__(self, thicknessMin, thicknessMax, ratio):
+ StrokeShader.__init__(self)
+ self._thicknessMin = thicknessMin
+ self._thicknessMax = thicknessMax
+ self._ratio = ratio
+
+ def getName(self):
+ return "pyConstrainedIncreasingThicknessShader"
+ def shade(self, stroke):
+ slength = stroke.getLength2D()
+ tmp = self._ratio*slength
+ maxT = 0.0
+ if(tmp < self._thicknessMax):
+ maxT = tmp
+ else:
+ maxT = self._thicknessMax
+ n = stroke.strokeVerticesSize()
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ c = float(i)/float(n)
+ if(i < float(n)/2.0):
+ t = (1.0 - c)*self._thicknessMin + c * maxT
+ else:
+ t = (1.0 - c)*maxT + c * self._thicknessMin
+ att.setThickness(t/2.0, t/2.0)
+ if(i == n-1):
+ att.setThickness(self._thicknessMin/2.0, self._thicknessMin/2.0)
+ i = i+1
+ it.increment()
+
+class pyDecreasingThicknessShader(StrokeShader):
+ def __init__(self, thicknessMax, thicknessMin):
+ StrokeShader.__init__(self)
+ self._thicknessMin = thicknessMin
+ self._thicknessMax = thicknessMax
+
+ def getName(self):
+ return "pyDecreasingThicknessShader"
+ def shade(self, stroke):
+ l = stroke.getLength2D()
+ tMax = self._thicknessMax
+ if(self._thicknessMax > 0.33*l):
+ tMax = 0.33*l
+ tMin = self._thicknessMin
+ if(self._thicknessMin > 0.1*l):
+ tMin = 0.1*l
+ n = stroke.strokeVerticesSize()
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ c = float(i)/float(n)
+ t = (1.0 - c)*tMax +c*tMin
+ att.setThickness(t/2.0, t/2.0)
+ i = i+1
+ it.increment()
+
+def smoothC( a, exp ):
+ c = pow(float(a),exp)*pow(2.0,exp)
+ return c
+
+class pyNonLinearVaryingThicknessShader(StrokeShader):
+ def __init__(self, thicknessExtremity, thicknessMiddle, exponent):
+ StrokeShader.__init__(self)
+ self._thicknessMin = thicknessMiddle
+ self._thicknessMax = thicknessExtremity
+ self._exponent = exponent
+
+ def getName(self):
+ return "pyNonLinearVaryingThicknessShader"
+ def shade(self, stroke):
+ n = stroke.strokeVerticesSize()
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ if(i < float(n)/2.0):
+ c = float(i)/float(n)
+ else:
+ c = float(n-i)/float(n)
+ c = smoothC(c, self._exponent)
+ t = (1.0 - c)*self._thicknessMax + c * self._thicknessMin
+ att.setThickness(t/2.0, t/2.0)
+ i = i+1
+ it.increment()
+
+## Spherical linear interpolation (cos)
+class pySLERPThicknessShader(StrokeShader):
+ def __init__(self, thicknessMin, thicknessMax, omega=1.2):
+ StrokeShader.__init__(self)
+ self._thicknessMin = thicknessMin
+ self._thicknessMax = thicknessMax
+ self._omega = omega
+
+ def getName(self):
+ return "pySLERPThicknessShader"
+ def shade(self, stroke):
+ slength = stroke.getLength2D()
+ tmp = 0.33*slength
+ maxT = self._thicknessMax
+ if(tmp < self._thicknessMax):
+ maxT = tmp
+
+ n = stroke.strokeVerticesSize()
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ c = float(i)/float(n)
+ if(i < float(n)/2.0):
+ t = sin((1-c)*self._omega)/sinh(self._omega)*self._thicknessMin + sin(c*self._omega)/sinh(self._omega) * maxT
+ else:
+ t = sin((1-c)*self._omega)/sinh(self._omega)*maxT + sin(c*self._omega)/sinh(self._omega) * self._thicknessMin
+ att.setThickness(t/2.0, t/2.0)
+ i = i+1
+ it.increment()
+
+class pyTVertexThickenerShader(StrokeShader): ## FIXME
+ def __init__(self, a=1.5, n=3):
+ StrokeShader.__init__(self)
+ self._a = a
+ self._n = n
+
+ def getName(self):
+ return "pyTVertexThickenerShader"
+
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ predTVertex = pyVertexNatureUP0D(Nature.T_VERTEX)
+ while it.isEnd() == 0:
+ if(predTVertex(it) == 1):
+ it2 = StrokeVertexIterator(it)
+ it2.increment()
+ if not(it.isBegin() or it2.isEnd()):
+ it.increment()
+ continue
+ n = self._n
+ a = self._a
+ if(it.isBegin()):
+ it3 = StrokeVertexIterator(it)
+ count = 0
+ while (it3.isEnd() == 0 and count < n):
+ att = it3.getObject().attribute()
+ tr = att.getThicknessR();
+ tl = att.getThicknessL();
+ r = (a-1.0)/float(n-1)*(float(n)/float(count+1) - 1) + 1
+ #r = (1.0-a)/float(n-1)*count + a
+ att.setThickness(r*tr, r*tl)
+ it3.increment()
+ count = count + 1
+ if(it2.isEnd()):
+ it4 = StrokeVertexIterator(it)
+ count = 0
+ while (it4.isBegin() == 0 and count < n):
+ att = it4.getObject().attribute()
+ tr = att.getThicknessR();
+ tl = att.getThicknessL();
+ r = (a-1.0)/float(n-1)*(float(n)/float(count+1) - 1) + 1
+ #r = (1.0-a)/float(n-1)*count + a
+ att.setThickness(r*tr, r*tl)
+ it4.decrement()
+ count = count + 1
+ if ((it4.isBegin() == 1)):
+ att = it4.getObject().attribute()
+ tr = att.getThicknessR();
+ tl = att.getThicknessL();
+ r = (a-1.0)/float(n-1)*(float(n)/float(count+1) - 1) + 1
+ #r = (1.0-a)/float(n-1)*count + a
+ att.setThickness(r*tr, r*tl)
+ it.increment()
+
+class pyImportance2DThicknessShader(StrokeShader):
+ def __init__(self, x, y, w, kmin, kmax):
+ StrokeShader.__init__(self)
+ self._x = x
+ self._y = y
+ self._w = float(w)
+ self._kmin = float(kmin)
+ self._kmax = float(kmax)
+
+ def getName(self):
+ return "pyImportanceThicknessShader"
+ def shade(self, stroke):
+ origin = Vector([self._x, self._y])
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v = it.getObject()
+ p = Vector([v.getProjectedX(), v.getProjectedY()])
+ d = (p-origin).length
+ if(d>self._w):
+ k = self._kmin
+ else:
+ k = (self._kmax*(self._w-d) + self._kmin*d)/self._w
+ att = v.attribute()
+ tr = att.getThicknessR()
+ tl = att.getThicknessL()
+ att.setThickness(k*tr/2.0, k*tl/2.0)
+ it.increment()
+
+class pyImportance3DThicknessShader(StrokeShader):
+ def __init__(self, x, y, z, w, kmin, kmax):
+ StrokeShader.__init__(self)
+ self._x = x
+ self._y = y
+ self._z = z
+ self._w = float(w)
+ self._kmin = float(kmin)
+ self._kmax = float(kmax)
+
+ def getName(self):
+ return "pyImportance3DThicknessShader"
+ def shade(self, stroke):
+ origin = Vector([self._x, self._y, self._z])
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v = it.getObject()
+ p = Vector([v.getX(), v.getY(), v.getZ()])
+ d = (p-origin).length
+ if(d>self._w):
+ k = self._kmin
+ else:
+ k = (self._kmax*(self._w-d) + self._kmin*d)/self._w
+ att = v.attribute()
+ tr = att.getThicknessR()
+ tl = att.getThicknessL()
+ att.setThickness(k*tr/2.0, k*tl/2.0)
+ it.increment()
+
+class pyZDependingThicknessShader(StrokeShader):
+ def __init__(self, min, max):
+ StrokeShader.__init__(self)
+ self.__min = min
+ self.__max = max
+ self.__func = GetProjectedZF0D()
+ def getName(self):
+ return "pyZDependingThicknessShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ z_min = 1
+ z_max = 0
+ while it.isEnd() == 0:
+ z = self.__func(it.castToInterface0DIterator())
+ if z < z_min:
+ z_min = z
+ if z > z_max:
+ z_max = z
+ it.increment()
+ z_diff = 1 / (z_max - z_min)
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ z = (self.__func(it.castToInterface0DIterator()) - z_min) * z_diff
+ thickness = (1 - z) * self.__max + z * self.__min
+ it.getObject().attribute().setThickness(thickness, thickness)
+ it.increment()
+
+
+## color modifiers
+##################
+
+class pyConstantColorShader(StrokeShader):
+ def __init__(self,r,g,b, a = 1):
+ StrokeShader.__init__(self)
+ self._r = r
+ self._g = g
+ self._b = b
+ self._a = a
+ def getName(self):
+ return "pyConstantColorShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ att.setColor(self._r, self._g, self._b)
+ att.setAlpha(self._a)
+ it.increment()
+
+#c1->c2
+class pyIncreasingColorShader(StrokeShader):
+ def __init__(self,r1,g1,b1,a1, r2,g2,b2,a2):
+ StrokeShader.__init__(self)
+ self._c1 = [r1,g1,b1,a1]
+ self._c2 = [r2,g2,b2,a2]
+ def getName(self):
+ return "pyIncreasingColorShader"
+ def shade(self, stroke):
+ n = stroke.strokeVerticesSize() - 1
+ inc = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ c = float(inc)/float(n)
+
+ att.setColor( (1-c)*self._c1[0] + c*self._c2[0],
+ (1-c)*self._c1[1] + c*self._c2[1],
+ (1-c)*self._c1[2] + c*self._c2[2],)
+ att.setAlpha((1-c)*self._c1[3] + c*self._c2[3],)
+ inc = inc+1
+ it.increment()
+
+# c1->c2->c1
+class pyInterpolateColorShader(StrokeShader):
+ def __init__(self,r1,g1,b1,a1, r2,g2,b2,a2):
+ StrokeShader.__init__(self)
+ self._c1 = [r1,g1,b1,a1]
+ self._c2 = [r2,g2,b2,a2]
+ def getName(self):
+ return "pyInterpolateColorShader"
+ def shade(self, stroke):
+ n = stroke.strokeVerticesSize() - 1
+ inc = 0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ u = float(inc)/float(n)
+ c = 1-2*(fabs(u-0.5))
+ att.setColor( (1-c)*self._c1[0] + c*self._c2[0],
+ (1-c)*self._c1[1] + c*self._c2[1],
+ (1-c)*self._c1[2] + c*self._c2[2],)
+ att.setAlpha((1-c)*self._c1[3] + c*self._c2[3],)
+ inc = inc+1
+ it.increment()
+
+class pyMaterialColorShader(StrokeShader):
+ def __init__(self, threshold=50):
+ StrokeShader.__init__(self)
+ self._threshold = threshold
+
+ def getName(self):
+ return "pyMaterialColorShader"
+
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ func = MaterialF0D()
+ xn = 0.312713
+ yn = 0.329016
+ Yn = 1.0
+ un = 4.* xn/ ( -2.*xn + 12.*yn + 3. )
+ vn= 9.* yn/ ( -2.*xn + 12.*yn +3. )
+ while it.isEnd() == 0:
+ toto = it.castToInterface0DIterator()
+ mat = func(toto)
+
+ r = mat.diffuseR()
+ g = mat.diffuseG()
+ b = mat.diffuseB()
+
+ X = 0.412453*r + 0.35758 *g + 0.180423*b
+ Y = 0.212671*r + 0.71516 *g + 0.072169*b
+ Z = 0.019334*r + 0.119193*g + 0.950227*b
+
+ if((X == 0) and (Y == 0) and (Z == 0)):
+ X = 0.01
+ Y = 0.01
+ Z = 0.01
+ u = 4.*X / (X + 15.*Y + 3.*Z)
+ v = 9.*Y / (X + 15.*Y + 3.*Z)
+
+ L= 116. * pow((Y/Yn),(1./3.)) -16
+ U = 13. * L * (u - un)
+ V = 13. * L * (v - vn)
+
+ if (L > self._threshold):
+ L = L/1.3
+ U = U+10
+ else:
+ L = L +2.5*(100-L)/5.
+ U = U/3.0
+ V = V/3.0
+ u = U / (13. * L) + un
+ v = V / (13. * L) + vn
+
+ Y = Yn * pow( ((L+16.)/116.), 3.)
+ X = -9. * Y * u / ((u - 4.)* v - u * v)
+ Z = (9. * Y - 15*v*Y - v*X) /( 3. * v)
+
+ r = 3.240479 * X - 1.53715 * Y - 0.498535 * Z
+ g = -0.969256 * X + 1.875991 * Y + 0.041556 * Z
+ b = 0.055648 * X - 0.204043 * Y + 1.057311 * Z
+
+ r = max(0,r)
+ g = max(0,g)
+ b = max(0,b)
+
+ att = it.getObject().attribute()
+ att.setColor(r, g, b)
+ it.increment()
+
+class pyRandomColorShader(StrokeShader):
+ def getName(self):
+ return "pyRandomColorShader"
+ def __init__(self, s=1):
+ StrokeShader.__init__(self)
+ seed(s)
+ def shade(self, stroke):
+ ## pick a random color
+ c0 = float(uniform(15,75))/100.0
+ c1 = float(uniform(15,75))/100.0
+ c2 = float(uniform(15,75))/100.0
+ print(c0, c1, c2)
+ it = stroke.strokeVerticesBegin()
+ while(it.isEnd() == 0):
+ it.getObject().attribute().setColor(c0,c1,c2)
+ it.increment()
+
+class py2DCurvatureColorShader(StrokeShader):
+ def getName(self):
+ return "py2DCurvatureColorShader"
+
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ func = Curvature2DAngleF0D()
+ while it.isEnd() == 0:
+ toto = it.castToInterface0DIterator()
+ sv = it.getObject()
+ att = sv.attribute()
+ c = func(toto)
+ if (c<0):
+ print("negative 2D curvature")
+ color = 10.0 * c/3.1415
+ print(color)
+ att.setColor(color,color,color);
+ it.increment()
+
+class pyTimeColorShader(StrokeShader):
+ def __init__(self, step=0.01):
+ StrokeShader.__init__(self)
+ self._t = 0
+ self._step = step
+ def shade(self, stroke):
+ c = self._t*1.0
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ att = it.getObject().attribute()
+ att.setColor(c,c,c)
+ it.increment()
+ self._t = self._t+self._step
+
+## geometry modifiers
+
+class pySamplingShader(StrokeShader):
+ def __init__(self, sampling):
+ StrokeShader.__init__(self)
+ self._sampling = sampling
+ def getName(self):
+ return "pySamplingShader"
+ def shade(self, stroke):
+ stroke.Resample(float(self._sampling))
+ stroke.UpdateLength()
+
+class pyBackboneStretcherShader(StrokeShader):
+ def __init__(self, l):
+ StrokeShader.__init__(self)
+ self._l = l
+ def getName(self):
+ return "pyBackboneStretcherShader"
+ def shade(self, stroke):
+ it0 = stroke.strokeVerticesBegin()
+ it1 = StrokeVertexIterator(it0)
+ it1.increment()
+ itn = stroke.strokeVerticesEnd()
+ itn.decrement()
+ itn_1 = StrokeVertexIterator(itn)
+ itn_1.decrement()
+ v0 = it0.getObject()
+ v1 = it1.getObject()
+ vn_1 = itn_1.getObject()
+ vn = itn.getObject()
+ p0 = Vector([v0.getProjectedX(), v0.getProjectedY()])
+ pn = Vector([vn.getProjectedX(), vn.getProjectedY()])
+ p1 = Vector([v1.getProjectedX(), v1.getProjectedY()])
+ pn_1 = Vector([vn_1.getProjectedX(), vn_1.getProjectedY()])
+ d1 = p0-p1
+ d1.normalize()
+ dn = pn-pn_1
+ dn.normalize()
+ newFirst = p0+d1*float(self._l)
+ newLast = pn+dn*float(self._l)
+ v0.setPoint(newFirst)
+ vn.setPoint(newLast)
+ stroke.UpdateLength()
+
+class pyLengthDependingBackboneStretcherShader(StrokeShader):
+ def __init__(self, l):
+ StrokeShader.__init__(self)
+ self._l = l
+ def getName(self):
+ return "pyBackboneStretcherShader"
+ def shade(self, stroke):
+ l = stroke.getLength2D()
+ stretch = self._l*l
+ it0 = stroke.strokeVerticesBegin()
+ it1 = StrokeVertexIterator(it0)
+ it1.increment()
+ itn = stroke.strokeVerticesEnd()
+ itn.decrement()
+ itn_1 = StrokeVertexIterator(itn)
+ itn_1.decrement()
+ v0 = it0.getObject()
+ v1 = it1.getObject()
+ vn_1 = itn_1.getObject()
+ vn = itn.getObject()
+ p0 = Vector([v0.getProjectedX(), v0.getProjectedY()])
+ pn = Vector([vn.getProjectedX(), vn.getProjectedY()])
+ p1 = Vector([v1.getProjectedX(), v1.getProjectedY()])
+ pn_1 = Vector([vn_1.getProjectedX(), vn_1.getProjectedY()])
+ d1 = p0-p1
+ d1.normalize()
+ dn = pn-pn_1
+ dn.normalize()
+ newFirst = p0+d1*float(stretch)
+ newLast = pn+dn*float(stretch)
+ v0.setPoint(newFirst)
+ vn.setPoint(newLast)
+ stroke.UpdateLength()
+
+
+## Shader to replace a stroke by its corresponding tangent
+class pyGuidingLineShader(StrokeShader):
+ def getName(self):
+ return "pyGuidingLineShader"
+ ## shading method
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin() ## get the first vertex
+ itlast = stroke.strokeVerticesEnd() ##
+ itlast.decrement() ## get the last one
+ t = itlast.getObject().getPoint() - it.getObject().getPoint() ## tangent direction
+ itmiddle = StrokeVertexIterator(it) ##
+ while(itmiddle.getObject().u()<0.5): ## look for the stroke middle vertex
+ itmiddle.increment() ##
+ it = StrokeVertexIterator(itmiddle)
+ it.increment()
+ while(it.isEnd() == 0): ## position all the vertices along the tangent for the right part
+ it.getObject().setPoint(itmiddle.getObject().getPoint() \
+ +t*(it.getObject().u()-itmiddle.getObject().u()))
+ it.increment()
+ it = StrokeVertexIterator(itmiddle)
+ it.decrement()
+ while(it.isBegin() == 0): ## position all the vertices along the tangent for the left part
+ it.getObject().setPoint(itmiddle.getObject().getPoint() \
+ -t*(itmiddle.getObject().u()-it.getObject().u()))
+ it.decrement()
+ it.getObject().setPoint(itmiddle.getObject().getPoint()-t*(itmiddle.getObject().u())) ## first vertex
+ stroke.UpdateLength()
+
+
+class pyBackboneStretcherNoCuspShader(StrokeShader):
+ def __init__(self, l):
+ StrokeShader.__init__(self)
+ self._l = l
+ def getName(self):
+ return "pyBackboneStretcherNoCuspShader"
+ def shade(self, stroke):
+ it0 = stroke.strokeVerticesBegin()
+ it1 = StrokeVertexIterator(it0)
+ it1.increment()
+ itn = stroke.strokeVerticesEnd()
+ itn.decrement()
+ itn_1 = StrokeVertexIterator(itn)
+ itn_1.decrement()
+ v0 = it0.getObject()
+ v1 = it1.getObject()
+ if((v0.getNature() & Nature.CUSP == 0) and (v1.getNature() & Nature.CUSP == 0)):
+ p0 = v0.getPoint()
+ p1 = v1.getPoint()
+ d1 = p0-p1
+ d1.normalize()
+ newFirst = p0+d1*float(self._l)
+ v0.setPoint(newFirst)
+ vn_1 = itn_1.getObject()
+ vn = itn.getObject()
+ if((vn.getNature() & Nature.CUSP == 0) and (vn_1.getNature() & Nature.CUSP == 0)):
+ pn = vn.getPoint()
+ pn_1 = vn_1.getPoint()
+ dn = pn-pn_1
+ dn.normalize()
+ newLast = pn+dn*float(self._l)
+ vn.setPoint(newLast)
+ stroke.UpdateLength()
+
+normalInfo=Normal2DF0D()
+curvatureInfo=Curvature2DAngleF0D()
+
+def edgestopping(x, sigma):
+ return exp(- x*x/(2*sigma*sigma))
+
+class pyDiffusion2Shader(StrokeShader):
+ def __init__(self, lambda1, nbIter):
+ StrokeShader.__init__(self)
+ self._lambda = lambda1
+ self._nbIter = nbIter
+ self._normalInfo = Normal2DF0D()
+ self._curvatureInfo = Curvature2DAngleF0D()
+ def getName(self):
+ return "pyDiffusionShader"
+ def shade(self, stroke):
+ for i in range (1, self._nbIter):
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v=it.getObject()
+ p1 = v.getPoint()
+ p2 = self._normalInfo(it.castToInterface0DIterator())*self._lambda*self._curvatureInfo(it.castToInterface0DIterator())
+ v.setPoint(p1+p2)
+ it.increment()
+ stroke.UpdateLength()
+
+class pyTipRemoverShader(StrokeShader):
+ def __init__(self, l):
+ StrokeShader.__init__(self)
+ self._l = l
+ def getName(self):
+ return "pyTipRemoverShader"
+ def shade(self, stroke):
+ originalSize = stroke.strokeVerticesSize()
+ if(originalSize<4):
+ return
+ verticesToRemove = []
+ oldAttributes = []
+ it = stroke.strokeVerticesBegin()
+ while(it.isEnd() == 0):
+ v = it.getObject()
+ if((v.curvilinearAbscissa() < self._l) or (v.strokeLength()-v.curvilinearAbscissa() < self._l)):
+ verticesToRemove.append(v)
+ oldAttributes.append(StrokeAttribute(v.attribute()))
+ it.increment()
+ if(originalSize-len(verticesToRemove) < 2):
+ return
+ for sv in verticesToRemove:
+ stroke.RemoveVertex(sv)
+ stroke.Resample(originalSize)
+ if(stroke.strokeVerticesSize() != originalSize):
+ print("pyTipRemover: Warning: resampling problem")
+ it = stroke.strokeVerticesBegin()
+ for a in oldAttributes:
+ if(it.isEnd() == 1):
+ break
+ v = it.getObject()
+ v.setAttribute(a)
+ it.increment()
+ stroke.UpdateLength()
+
+class pyTVertexRemoverShader(StrokeShader):
+ def getName(self):
+ return "pyTVertexRemoverShader"
+ def shade(self, stroke):
+ if(stroke.strokeVerticesSize() <= 3 ):
+ return
+ predTVertex = pyVertexNatureUP0D(Nature.T_VERTEX)
+ it = stroke.strokeVerticesBegin()
+ itlast = stroke.strokeVerticesEnd()
+ itlast.decrement()
+ if(predTVertex(it) == 1):
+ stroke.RemoveVertex(it.getObject())
+ if(predTVertex(itlast) == 1):
+ stroke.RemoveVertex(itlast.getObject())
+ stroke.UpdateLength()
+
+class pyExtremitiesOrientationShader(StrokeShader):
+ def __init__(self, x1,y1,x2=0,y2=0):
+ StrokeShader.__init__(self)
+ self._v1 = Vector([x1,y1])
+ self._v2 = Vector([x2,y2])
+ def getName(self):
+ return "pyExtremitiesOrientationShader"
+ def shade(self, stroke):
+ print(self._v1.x,self._v1.y)
+ stroke.setBeginningOrientation(self._v1.x,self._v1.y)
+ stroke.setEndingOrientation(self._v2.x,self._v2.y)
+
+def getFEdge(it1, it2):
+ return it1.getFEdge(it2)
+
+class pyHLRShader(StrokeShader):
+ def getName(self):
+ return "pyHLRShader"
+ def shade(self, stroke):
+ originalSize = stroke.strokeVerticesSize()
+ if(originalSize<4):
+ return
+ it = stroke.strokeVerticesBegin()
+ invisible = 0
+ it2 = StrokeVertexIterator(it)
+ it2.increment()
+ fe = getFEdge(it.getObject(), it2.getObject())
+ if(fe.viewedge().qi() != 0):
+ invisible = 1
+ while(it2.isEnd() == 0):
+ v = it.getObject()
+ vnext = it2.getObject()
+ if(v.getNature() & Nature.VIEW_VERTEX):
+ #if(v.getNature() & Nature.T_VERTEX):
+ fe = getFEdge(v,vnext)
+ qi = fe.viewedge().qi()
+ if(qi != 0):
+ invisible = 1
+ else:
+ invisible = 0
+ if(invisible == 1):
+ v.attribute().setVisible(0)
+ it.increment()
+ it2.increment()
+
+class pyTVertexOrientationShader(StrokeShader):
+ def __init__(self):
+ StrokeShader.__init__(self)
+ self._Get2dDirection = Orientation2DF1D()
+ def getName(self):
+ return "pyTVertexOrientationShader"
+ ## finds the TVertex orientation from the TVertex and
+ ## the previous or next edge
+ def findOrientation(self, tv, ve):
+ mateVE = tv.mate(ve)
+ if((ve.qi() != 0) or (mateVE.qi() != 0)):
+ ait = AdjacencyIterator(tv,1,0)
+ winner = None
+ incoming = 1
+ while(ait.isEnd() == 0):
+ ave = ait.getObject()
+ if((ave.getId() != ve.getId()) and (ave.getId() != mateVE.getId())):
+ winner = ait.getObject()
+ if(ait.isIncoming() == 0):
+ incoming = 0
+ break
+ ait.increment()
+ if(winner != None):
+ if(incoming != 0):
+ direction = self._Get2dDirection(winner.fedgeB())
+ else:
+ direction = self._Get2dDirection(winner.fedgeA())
+ return direction
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it2 = StrokeVertexIterator(it)
+ it2.increment()
+ ## case where the first vertex is a TVertex
+ v = it.getObject()
+ if(v.getNature() & Nature.T_VERTEX):
+ tv = v.castToTVertex()
+ ve = getFEdge(v, it2.getObject()).viewedge()
+ if(tv != None):
+ dir = self.findOrientation(tv, ve)
+ #print(dir.x, dir.y)
+ v.attribute().setAttributeVec2f("orientation", dir)
+ while(it2.isEnd() == 0):
+ vprevious = it.getObject()
+ v = it2.getObject()
+ if(v.getNature() & Nature.T_VERTEX):
+ tv = v.castToTVertex()
+ ve = getFEdge(vprevious, v).viewedge()
+ if(tv != None):
+ dir = self.findOrientation(tv, ve)
+ #print(dir.x, dir.y)
+ v.attribute().setAttributeVec2f("orientation", dir)
+ it.increment()
+ it2.increment()
+ ## case where the last vertex is a TVertex
+ v = it.getObject()
+ if(v.getNature() & Nature.T_VERTEX):
+ itPrevious = StrokeVertexIterator(it)
+ itPrevious.decrement()
+ tv = v.castToTVertex()
+ ve = getFEdge(itPrevious.getObject(), v).viewedge()
+ if(tv != None):
+ dir = self.findOrientation(tv, ve)
+ #print(dir.x, dir.y)
+ v.attribute().setAttributeVec2f("orientation", dir)
+
+class pySinusDisplacementShader(StrokeShader):
+ def __init__(self, f, a):
+ StrokeShader.__init__(self)
+ self._f = f
+ self._a = a
+ self._getNormal = Normal2DF0D()
+
+ def getName(self):
+ return "pySinusDisplacementShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v = it.getObject()
+ #print(self._getNormal.getName())
+ n = self._getNormal(it.castToInterface0DIterator())
+ p = v.getPoint()
+ u = v.u()
+ a = self._a*(1-2*(fabs(u-0.5)))
+ n = n*a*cos(self._f*u*6.28)
+ #print(n.x, n.y)
+ v.setPoint(p+n)
+ #v.setPoint(v.getPoint()+n*a*cos(f*v.u()))
+ it.increment()
+ stroke.UpdateLength()
+
+class pyPerlinNoise1DShader(StrokeShader):
+ def __init__(self, freq = 10, amp = 10, oct = 4, seed = -1):
+ StrokeShader.__init__(self)
+ self.__noise = Noise(seed)
+ self.__freq = freq
+ self.__amp = amp
+ self.__oct = oct
+ def getName(self):
+ return "pyPerlinNoise1DShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v = it.getObject()
+ i = v.getProjectedX() + v.getProjectedY()
+ nres = self.__noise.turbulence1(i, self.__freq, self.__amp, self.__oct)
+ v.setPoint(v.getProjectedX() + nres, v.getProjectedY() + nres)
+ it.increment()
+ stroke.UpdateLength()
+
+class pyPerlinNoise2DShader(StrokeShader):
+ def __init__(self, freq = 10, amp = 10, oct = 4, seed = -1):
+ StrokeShader.__init__(self)
+ self.__noise = Noise(seed)
+ self.__freq = freq
+ self.__amp = amp
+ self.__oct = oct
+ def getName(self):
+ return "pyPerlinNoise2DShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ v = it.getObject()
+ vec = Vector([v.getProjectedX(), v.getProjectedY()])
+ nres = self.__noise.turbulence2(vec, self.__freq, self.__amp, self.__oct)
+ v.setPoint(v.getProjectedX() + nres, v.getProjectedY() + nres)
+ it.increment()
+ stroke.UpdateLength()
+
+class pyBluePrintCirclesShader(StrokeShader):
+ def __init__(self, turns = 1, random_radius = 3, random_center = 5):
+ StrokeShader.__init__(self)
+ self.__turns = turns
+ self.__random_center = random_center
+ self.__random_radius = random_radius
+ def getName(self):
+ return "pyBluePrintCirclesShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ if it.isEnd():
+ return
+ p_min = it.getObject().getPoint()
+ p_max = it.getObject().getPoint()
+ while it.isEnd() == 0:
+ p = it.getObject().getPoint()
+ if (p.x < p_min.x):
+ p_min.x = p.x
+ if (p.x > p_max.x):
+ p_max.x = p.x
+ if (p.y < p_min.y):
+ p_min.y = p.y
+ if (p.y > p_max.y):
+ p_max.y = p.y
+ it.increment()
+ stroke.Resample(32 * self.__turns)
+ sv_nb = stroke.strokeVerticesSize()
+# print("min :", p_min.x, p_min.y) # DEBUG
+# print("mean :", p_sum.x, p_sum.y) # DEBUG
+# print("max :", p_max.x, p_max.y) # DEBUG
+# print("----------------------") # DEBUG
+#######################################################
+ sv_nb = sv_nb // self.__turns
+ center = (p_min + p_max) / 2
+ radius = (center.x - p_min.x + center.y - p_min.y) / 2
+ p_new = Vector([0, 0])
+#######################################################
+ R = self.__random_radius
+ C = self.__random_center
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ for j in range(self.__turns):
+ prev_radius = radius
+ prev_center = center
+ radius = radius + randint(-R, R)
+ center = center + Vector([randint(-C, C), randint(-C, C)])
+ while i < sv_nb and it.isEnd() == 0:
+ t = float(i) / float(sv_nb - 1)
+ r = prev_radius + (radius - prev_radius) * t
+ c = prev_center + (center - prev_center) * t
+ p_new.x = c.x + r * cos(2 * pi * t)
+ p_new.y = c.y + r * sin(2 * pi * t)
+ it.getObject().setPoint(p_new)
+ i = i + 1
+ it.increment()
+ i = 1
+ verticesToRemove = []
+ while it.isEnd() == 0:
+ verticesToRemove.append(it.getObject())
+ it.increment()
+ for sv in verticesToRemove:
+ stroke.RemoveVertex(sv)
+ stroke.UpdateLength()
+
+class pyBluePrintEllipsesShader(StrokeShader):
+ def __init__(self, turns = 1, random_radius = 3, random_center = 5):
+ StrokeShader.__init__(self)
+ self.__turns = turns
+ self.__random_center = random_center
+ self.__random_radius = random_radius
+ def getName(self):
+ return "pyBluePrintEllipsesShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ if it.isEnd():
+ return
+ p_min = it.getObject().getPoint()
+ p_max = it.getObject().getPoint()
+ while it.isEnd() == 0:
+ p = it.getObject().getPoint()
+ if (p.x < p_min.x):
+ p_min.x = p.x
+ if (p.x > p_max.x):
+ p_max.x = p.x
+ if (p.y < p_min.y):
+ p_min.y = p.y
+ if (p.y > p_max.y):
+ p_max.y = p.y
+ it.increment()
+ stroke.Resample(32 * self.__turns)
+ sv_nb = stroke.strokeVerticesSize()
+ sv_nb = sv_nb // self.__turns
+ center = (p_min + p_max) / 2
+ radius = center - p_min
+ p_new = Vector([0, 0])
+#######################################################
+ R = self.__random_radius
+ C = self.__random_center
+ i = 0
+ it = stroke.strokeVerticesBegin()
+ for j in range(self.__turns):
+ prev_radius = radius
+ prev_center = center
+ radius = radius + Vector([randint(-R, R), randint(-R, R)])
+ center = center + Vector([randint(-C, C), randint(-C, C)])
+ while i < sv_nb and it.isEnd() == 0:
+ t = float(i) / float(sv_nb - 1)
+ r = prev_radius + (radius - prev_radius) * t
+ c = prev_center + (center - prev_center) * t
+ p_new.x = c.x + r.x * cos(2 * pi * t)
+ p_new.y = c.y + r.y * sin(2 * pi * t)
+ it.getObject().setPoint(p_new)
+ i = i + 1
+ it.increment()
+ i = 1
+ verticesToRemove = []
+ while it.isEnd() == 0:
+ verticesToRemove.append(it.getObject())
+ it.increment()
+ for sv in verticesToRemove:
+ stroke.RemoveVertex(sv)
+ stroke.UpdateLength()
+
+
+class pyBluePrintSquaresShader(StrokeShader):
+ def __init__(self, turns = 1, bb_len = 10, bb_rand = 0):
+ StrokeShader.__init__(self)
+ self.__turns = turns
+ self.__bb_len = bb_len
+ self.__bb_rand = bb_rand
+
+ def getName(self):
+ return "pyBluePrintSquaresShader"
+
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ if it.isEnd():
+ return
+ p_min = it.getObject().getPoint()
+ p_max = it.getObject().getPoint()
+ while it.isEnd() == 0:
+ p = it.getObject().getPoint()
+ if (p.x < p_min.x):
+ p_min.x = p.x
+ if (p.x > p_max.x):
+ p_max.x = p.x
+ if (p.y < p_min.y):
+ p_min.y = p.y
+ if (p.y > p_max.y):
+ p_max.y = p.y
+ it.increment()
+ stroke.Resample(32 * self.__turns)
+ sv_nb = stroke.strokeVerticesSize()
+#######################################################
+ sv_nb = sv_nb // self.__turns
+ first = sv_nb // 4
+ second = 2 * first
+ third = 3 * first
+ fourth = sv_nb
+ p_first = Vector([p_min.x - self.__bb_len, p_min.y])
+ p_first_end = Vector([p_max.x + self.__bb_len, p_min.y])
+ p_second = Vector([p_max.x, p_min.y - self.__bb_len])
+ p_second_end = Vector([p_max.x, p_max.y + self.__bb_len])
+ p_third = Vector([p_max.x + self.__bb_len, p_max.y])
+ p_third_end = Vector([p_min.x - self.__bb_len, p_max.y])
+ p_fourth = Vector([p_min.x, p_max.y + self.__bb_len])
+ p_fourth_end = Vector([p_min.x, p_min.y - self.__bb_len])
+#######################################################
+ R = self.__bb_rand
+ r = self.__bb_rand // 2
+ it = stroke.strokeVerticesBegin()
+ visible = 1
+ for j in range(self.__turns):
+ p_first = p_first + Vector([randint(-R, R), randint(-r, r)])
+ p_first_end = p_first_end + Vector([randint(-R, R), randint(-r, r)])
+ p_second = p_second + Vector([randint(-r, r), randint(-R, R)])
+ p_second_end = p_second_end + Vector([randint(-r, r), randint(-R, R)])
+ p_third = p_third + Vector([randint(-R, R), randint(-r, r)])
+ p_third_end = p_third_end + Vector([randint(-R, R), randint(-r, r)])
+ p_fourth = p_fourth + Vector([randint(-r, r), randint(-R, R)])
+ p_fourth_end = p_fourth_end + Vector([randint(-r, r), randint(-R, R)])
+ vec_first = p_first_end - p_first
+ vec_second = p_second_end - p_second
+ vec_third = p_third_end - p_third
+ vec_fourth = p_fourth_end - p_fourth
+ i = 0
+ while i < sv_nb and it.isEnd() == 0:
+ if i < first:
+ p_new = p_first + vec_first * float(i)/float(first - 1)
+ if i == first - 1:
+ visible = 0
+ elif i < second:
+ p_new = p_second + vec_second * float(i - first)/float(second - first - 1)
+ if i == second - 1:
+ visible = 0
+ elif i < third:
+ p_new = p_third + vec_third * float(i - second)/float(third - second - 1)
+ if i == third - 1:
+ visible = 0
+ else:
+ p_new = p_fourth + vec_fourth * float(i - third)/float(fourth - third - 1)
+ if i == fourth - 1:
+ visible = 0
+ if it.getObject() == None:
+ i = i + 1
+ it.increment()
+ if visible == 0:
+ visible = 1
+ continue
+ it.getObject().setPoint(p_new)
+ it.getObject().attribute().setVisible(visible)
+ if visible == 0:
+ visible = 1
+ i = i + 1
+ it.increment()
+ verticesToRemove = []
+ while it.isEnd() == 0:
+ verticesToRemove.append(it.getObject())
+ it.increment()
+ for sv in verticesToRemove:
+ stroke.RemoveVertex(sv)
+ stroke.UpdateLength()
+
+
+class pyBluePrintDirectedSquaresShader(StrokeShader):
+ def __init__(self, turns = 1, bb_len = 10, mult = 1):
+ StrokeShader.__init__(self)
+ self.__mult = mult
+ self.__turns = turns
+ self.__bb_len = 1 + float(bb_len) / 100
+ def getName(self):
+ return "pyBluePrintDirectedSquaresShader"
+ def shade(self, stroke):
+ stroke.Resample(32 * self.__turns)
+ p_mean = Vector([0, 0])
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ p = it.getObject().getPoint()
+ p_mean = p_mean + p
+ it.increment()
+ sv_nb = stroke.strokeVerticesSize()
+ p_mean = p_mean / sv_nb
+ p_var_xx = 0
+ p_var_yy = 0
+ p_var_xy = 0
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ p = it.getObject().getPoint()
+ p_var_xx = p_var_xx + pow(p.x - p_mean.x, 2)
+ p_var_yy = p_var_yy + pow(p.y - p_mean.y, 2)
+ p_var_xy = p_var_xy + (p.x - p_mean.x) * (p.y - p_mean.y)
+ it.increment()
+ p_var_xx = p_var_xx / sv_nb
+ p_var_yy = p_var_yy / sv_nb
+ p_var_xy = p_var_xy / sv_nb
+## print(p_var_xx, p_var_yy, p_var_xy)
+ trace = p_var_xx + p_var_yy
+ det = p_var_xx * p_var_yy - p_var_xy * p_var_xy
+ sqrt_coeff = sqrt(trace * trace - 4 * det)
+ lambda1 = (trace + sqrt_coeff) / 2
+ lambda2 = (trace - sqrt_coeff) / 2
+## print(lambda1, lambda2)
+ theta = atan(2 * p_var_xy / (p_var_xx - p_var_yy)) / 2
+## print(theta)
+ if p_var_yy > p_var_xx:
+ e1 = Vector([cos(theta + pi / 2), sin(theta + pi / 2)]) * sqrt(lambda1) * self.__mult
+ e2 = Vector([cos(theta + pi), sin(theta + pi)]) * sqrt(lambda2) * self.__mult
+ else:
+ e1 = Vector([cos(theta), sin(theta)]) * sqrt(lambda1) * self.__mult
+ e2 = Vector([cos(theta + pi / 2), sin(theta + pi / 2)]) * sqrt(lambda2) * self.__mult
+#######################################################
+ sv_nb = sv_nb // self.__turns
+ first = sv_nb // 4
+ second = 2 * first
+ third = 3 * first
+ fourth = sv_nb
+ bb_len1 = self.__bb_len
+ bb_len2 = 1 + (bb_len1 - 1) * sqrt(lambda1 / lambda2)
+ p_first = p_mean - e1 - e2 * bb_len2
+ p_second = p_mean - e1 * bb_len1 + e2
+ p_third = p_mean + e1 + e2 * bb_len2
+ p_fourth = p_mean + e1 * bb_len1 - e2
+ vec_first = e2 * bb_len2 * 2
+ vec_second = e1 * bb_len1 * 2
+ vec_third = vec_first * -1
+ vec_fourth = vec_second * -1
+#######################################################
+ it = stroke.strokeVerticesBegin()
+ visible = 1
+ for j in range(self.__turns):
+ i = 0
+ while i < sv_nb:
+ if i < first:
+ p_new = p_first + vec_first * float(i)/float(first - 1)
+ if i == first - 1:
+ visible = 0
+ elif i < second:
+ p_new = p_second + vec_second * float(i - first)/float(second - first - 1)
+ if i == second - 1:
+ visible = 0
+ elif i < third:
+ p_new = p_third + vec_third * float(i - second)/float(third - second - 1)
+ if i == third - 1:
+ visible = 0
+ else:
+ p_new = p_fourth + vec_fourth * float(i - third)/float(fourth - third - 1)
+ if i == fourth - 1:
+ visible = 0
+ it.getObject().setPoint(p_new)
+ it.getObject().attribute().setVisible(visible)
+ if visible == 0:
+ visible = 1
+ i = i + 1
+ it.increment()
+ verticesToRemove = []
+ while it.isEnd() == 0:
+ verticesToRemove.append(it.getObject())
+ it.increment()
+ for sv in verticesToRemove:
+ stroke.RemoveVertex(sv)
+ stroke.UpdateLength()
+
+class pyModulateAlphaShader(StrokeShader):
+ def __init__(self, min = 0, max = 1):
+ StrokeShader.__init__(self)
+ self.__min = min
+ self.__max = max
+ def getName(self):
+ return "pyModulateAlphaShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ alpha = it.getObject().attribute().getAlpha()
+ p = it.getObject().getPoint()
+ alpha = alpha * p.y / 400
+ if alpha < self.__min:
+ alpha = self.__min
+ elif alpha > self.__max:
+ alpha = self.__max
+ it.getObject().attribute().setAlpha(alpha)
+ it.increment()
+
+
+## various
+class pyDummyShader(StrokeShader):
+ def getName(self):
+ return "pyDummyShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ it_end = stroke.strokeVerticesEnd()
+ while it.isEnd() == 0:
+ toto = it.castToInterface0DIterator()
+ att = it.getObject().attribute()
+ att.setColor(0.3, 0.4, 0.4)
+ att.setThickness(0, 5)
+ it.increment()
+
+class pyDebugShader(StrokeShader):
+ def getName(self):
+ return "pyDebugShader"
+
+ def shade(self, stroke):
+ fe = GetSelectedFEdgeCF()
+ id1=fe.vertexA().getId()
+ id2=fe.vertexB().getId()
+ #print(id1.getFirst(), id1.getSecond())
+ #print(id2.getFirst(), id2.getSecond())
+ it = stroke.strokeVerticesBegin()
+ found = 0
+ foundfirst = 0
+ foundsecond = 0
+ while it.isEnd() == 0:
+ cp = it.getObject()
+ if((cp.A().getId() == id1) or (cp.B().getId() == id1)):
+ foundfirst = 1
+ if((cp.A().getId() == id2) or (cp.B().getId() == id2)):
+ foundsecond = 1
+ if((foundfirst != 0) and (foundsecond != 0)):
+ found = 1
+ break
+ it.increment()
+ if(found != 0):
+ print("The selected Stroke id is: ", stroke.getId().getFirst(), stroke.getId().getSecond())
diff --git a/release/scripts/freestyle/style_modules/sketchy_multiple_parameterization.py b/release/scripts/freestyle/style_modules/sketchy_multiple_parameterization.py
new file mode 100644
index 00000000000..163c891fa90
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/sketchy_multiple_parameterization.py
@@ -0,0 +1,48 @@
+#
+# Filename : sketchy_multiple_parameterization.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Builds sketchy strokes whose topology relies on a
+# parameterization that covers the complete lines (visible+invisible)
+# whereas only the visible portions are actually drawn
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+## 0: don't restrict to selection
+Operators.bidirectionalChain(pySketchyChainSilhouetteIterator(3,0))
+shaders_list = [
+ SamplingShader(2),
+ SpatialNoiseShader(15, 120, 2, 1, 1),
+ IncreasingThicknessShader(5, 30),
+ SmoothingShader(100, 0.05, 0, 0.2, 0, 0, 0, 1),
+ IncreasingColorShader(0,0.2,0,1,0.2,0.7,0.2,1),
+ TextureAssignerShader(6),
+ pyHLRShader()
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/sketchy_topology_broken.py b/release/scripts/freestyle/style_modules/sketchy_topology_broken.py
new file mode 100644
index 00000000000..9ec0cffcfec
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/sketchy_topology_broken.py
@@ -0,0 +1,89 @@
+#
+# Filename : sketchy_topology_broken.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : The topology of the strokes is, first, built
+# independantly from the 3D topology of objects,
+# and, second, so as to chain several times the same ViewEdge.
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+## Backbone stretcher that leaves cusps intact to avoid cracks
+class pyBackboneStretcherNoCuspShader(StrokeShader):
+ def __init__(self, l):
+ StrokeShader.__init__(self)
+ self._l = l
+ def getName(self):
+ return "pyBackboneStretcherNoCuspShader"
+ def shade(self, stroke):
+ it0 = stroke.strokeVerticesBegin()
+ it1 = StrokeVertexIterator(it0)
+ it1.increment()
+ itn = stroke.strokeVerticesEnd()
+ itn.decrement()
+ itn_1 = StrokeVertexIterator(itn)
+ itn_1.decrement()
+ v0 = it0.getObject()
+ v1 = it1.getObject()
+ if((v0.getNature() & Nature.CUSP == 0) and (v1.getNature() & Nature.CUSP == 0)):
+ p0 = v0.getPoint()
+ p1 = v1.getPoint()
+ d1 = p0-p1
+ d1.normalize()
+ newFirst = p0+d1*float(self._l)
+ v0.setPoint(newFirst)
+ else:
+ print("got a v0 cusp")
+ vn_1 = itn_1.getObject()
+ vn = itn.getObject()
+ if((vn.getNature() & Nature.CUSP == 0) and (vn_1.getNature() & Nature.CUSP == 0)):
+ pn = vn.getPoint()
+ pn_1 = vn_1.getPoint()
+ dn = pn-pn_1
+ dn.normalize()
+ newLast = pn+dn*float(self._l)
+ vn.setPoint(newLast)
+ else:
+ print("got a vn cusp")
+
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+## Chain 3 times each ViewEdge indpendantly from the
+## initial objects topology
+Operators.bidirectionalChain(pySketchyChainingIterator(3))
+shaders_list = [
+ SamplingShader(4),
+ SpatialNoiseShader(6, 120, 2, 1, 1),
+ IncreasingThicknessShader(4, 10),
+ SmoothingShader(100, 0.1, 0, 0.2, 0, 0, 0, 1),
+ pyBackboneStretcherNoCuspShader(20),
+ #ConstantColorShader(0.0,0.0,0.0)
+ IncreasingColorShader(0.2,0.2,0.2,1,0.5,0.5,0.5,1),
+ #IncreasingColorShader(1,0,0,1,0,1,0,1),
+ TextureAssignerShader(4)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/sketchy_topology_preserved.py b/release/scripts/freestyle/style_modules/sketchy_topology_preserved.py
new file mode 100644
index 00000000000..85e11af38b9
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/sketchy_topology_preserved.py
@@ -0,0 +1,49 @@
+#
+# Filename : sketchy_topology_preserved.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : The topology of the strokes is built
+# so as to chain several times the same ViewEdge.
+# The topology of the objects is preserved
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = QuantitativeInvisibilityUP1D(0)
+Operators.select(upred)
+Operators.bidirectionalChain(pySketchyChainSilhouetteIterator(3,1))
+shaders_list = [
+ SamplingShader(4),
+ SpatialNoiseShader(20, 220, 2, 1, 1),
+ IncreasingThicknessShader(4, 8),
+ SmoothingShader(300, 0.05, 0, 0.2, 0, 0, 0, 0.5),
+ ConstantColorShader(0.6,0.2,0.0),
+ TextureAssignerShader(4),
+ ]
+
+Operators.create(TrueUP1D(), shaders_list)
+
diff --git a/release/scripts/freestyle/style_modules/split_at_highest_2d_curvatures.py b/release/scripts/freestyle/style_modules/split_at_highest_2d_curvatures.py
new file mode 100644
index 00000000000..52cc10a9c60
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/split_at_highest_2d_curvatures.py
@@ -0,0 +1,41 @@
+#
+# Filename : split_at_highest_2d_curvature.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the visible lines (chaining follows same nature lines)
+# (most basic style module)
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU0D import *
+from PredicatesU1D import *
+from Functions0D import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+func = pyInverseCurvature2DAngleF0D()
+Operators.recursiveSplit(func, pyParameterUP0D(0.4,0.6), NotUP1D(pyHigherLengthUP1D(100)), 2)
+shaders_list = [ConstantThicknessShader(10), IncreasingColorShader(1,0,0,1,0,1,0,1), TextureAssignerShader(3)]
+Operators.create(TrueUP1D(), shaders_list)
+
diff --git a/release/scripts/freestyle/style_modules/split_at_tvertices.py b/release/scripts/freestyle/style_modules/split_at_tvertices.py
new file mode 100644
index 00000000000..78f781dd290
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/split_at_tvertices.py
@@ -0,0 +1,42 @@
+#
+# Filename : split_at_tvertices.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws strokes that starts and stops at Tvertices (visible or not)
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from PredicatesU0D import *
+from Functions0D import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+start = pyVertexNatureUP0D(Nature.T_VERTEX)
+## use the same predicate to decide where to start and where to stop
+## the strokes:
+Operators.sequentialSplit(start, start, 10)
+shaders_list = [ConstantThicknessShader(5), IncreasingColorShader(1,0,0,1,0,1,0,1), TextureAssignerShader(3)]
+Operators.create(TrueUP1D(), shaders_list)
+
diff --git a/release/scripts/freestyle/style_modules/stroke_texture.py b/release/scripts/freestyle/style_modules/stroke_texture.py
new file mode 100644
index 00000000000..afebbe30a90
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/stroke_texture.py
@@ -0,0 +1,43 @@
+#
+# Filename : stroke_texture.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws textured strokes (illustrate the StrokeTextureShader shader)
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+from ChainingIterators import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ SamplingShader(3),
+ BezierCurveShader(4),
+ StrokeTextureShader("washbrushAlpha.bmp", Stroke.DRY_MEDIUM, 1),
+ ConstantThicknessShader(40),
+ ConstantColorShader(0,0,0,1),
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/suggestive.py b/release/scripts/freestyle/style_modules/suggestive.py
new file mode 100644
index 00000000000..39d8515ed6c
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/suggestive.py
@@ -0,0 +1,43 @@
+#
+# Filename : suggestive.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Draws the suggestive contours.
+# ***** The suggestive contours must be enabled
+# in the options dialog *****
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from PredicatesU1D import *
+from shaders import *
+
+upred = AndUP1D(pyNatureUP1D(Nature.SUGGESTIVE_CONTOUR), QuantitativeInvisibilityUP1D(0))
+Operators.select(upred)
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(upred))
+shaders_list = [
+ IncreasingThicknessShader(1, 3),
+ ConstantColorShader(0.2,0.2,0.2, 1)
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/thickness_fof_depth_discontinuity.py b/release/scripts/freestyle/style_modules/thickness_fof_depth_discontinuity.py
new file mode 100644
index 00000000000..21f6c7bdf35
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/thickness_fof_depth_discontinuity.py
@@ -0,0 +1,62 @@
+#
+# Filename : thickness_fof_depth_discontinuity.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Assigns to strokes a thickness that depends on the depth discontinuity
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+class pyDepthDiscontinuityThicknessShader(StrokeShader):
+ def __init__(self, min, max):
+ StrokeShader.__init__(self)
+ self.__min = float(min)
+ self.__max = float(max)
+ self.__func = ZDiscontinuityF0D()
+ def getName(self):
+ return "pyDepthDiscontinuityThicknessShader"
+ def shade(self, stroke):
+ it = stroke.strokeVerticesBegin()
+ z_min=0.0
+ z_max=1.0
+ a = (self.__max - self.__min)/(z_max-z_min)
+ b = (self.__min*z_max-self.__max*z_min)/(z_max-z_min)
+ it = stroke.strokeVerticesBegin()
+ while it.isEnd() == 0:
+ z = self.__func(it.castToInterface0DIterator())
+ thickness = a*z+b
+ it.getObject().attribute().setThickness(thickness, thickness)
+ it.increment()
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ SamplingShader(1),
+ ConstantThicknessShader(3),
+ ConstantColorShader(0.0,0.0,0.0),
+ pyDepthDiscontinuityThicknessShader(0.8, 6)
+ ]
+Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file
diff --git a/release/scripts/freestyle/style_modules/tipremover.py b/release/scripts/freestyle/style_modules/tipremover.py
new file mode 100644
index 00000000000..3e495b7d332
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/tipremover.py
@@ -0,0 +1,42 @@
+#
+# Filename : tipremover.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Removes strokes extremities
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+
+from freestyle_init import *
+from logical_operators import *
+from ChainingIterators import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ SamplingShader(5),
+ ConstantThicknessShader(3),
+ ConstantColorShader(0,0,0),
+ TipRemoverShader(20)
+ ]
+Operators.create(TrueUP1D(), shaders_list) \ No newline at end of file
diff --git a/release/scripts/freestyle/style_modules/tvertex_remover.py b/release/scripts/freestyle/style_modules/tvertex_remover.py
new file mode 100644
index 00000000000..c328f4c98ec
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/tvertex_remover.py
@@ -0,0 +1,42 @@
+#
+# Filename : tvertex_remover.py
+# Author : Stephane Grabli
+# Date : 04/08/2005
+# Purpose : Removes TVertices
+#
+#############################################################################
+#
+# Copyright (C) : Please refer to the COPYRIGHT file distributed
+# with this source distribution.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#############################################################################
+
+
+from freestyle_init import *
+from logical_operators import *
+from PredicatesB1D import *
+from shaders import *
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator(), NotUP1D(QuantitativeInvisibilityUP1D(0)))
+shaders_list = [
+ IncreasingThicknessShader(3, 5),
+ ConstantColorShader(0.2,0.2,0.2, 1),
+ SamplingShader(10.0),
+ pyTVertexRemoverShader()
+ ]
+Operators.create(TrueUP1D(), shaders_list)
diff --git a/release/scripts/freestyle/style_modules/uniformpruning_zsort.py b/release/scripts/freestyle/style_modules/uniformpruning_zsort.py
new file mode 100644
index 00000000000..50a2f6423fd
--- /dev/null
+++ b/release/scripts/freestyle/style_modules/uniformpruning_zsort.py
@@ -0,0 +1,40 @@
+from freestyle_init import *
+from logical_operators import *
+from PredicatesU1D import *
+from PredicatesU0D import *
+from PredicatesB1D import *
+from Functions0D import *
+from Functions1D import *
+from shaders import *
+
+class pyDensityUP1D(UnaryPredicate1D):
+ def __init__(self,wsize,threshold, integration = IntegrationType.MEAN, sampling=2.0):
+ UnaryPredicate1D.__init__(self)
+ self._wsize = wsize
+ self._threshold = threshold
+ self._integration = integration
+ self._func = DensityF1D(self._wsize, self._integration, sampling)
+
+ def getName(self):
+ return "pyDensityUP1D"
+
+ def __call__(self, inter):
+ d = self._func(inter)
+ print("For Chain ", inter.getId().getFirst(), inter.getId().getSecond(), "density is ", d)
+ if(d < self._threshold):
+ return 1
+ return 0
+
+Operators.select(QuantitativeInvisibilityUP1D(0))
+Operators.bidirectionalChain(ChainSilhouetteIterator())
+#Operators.sequentialSplit(pyVertexNatureUP0D(Nature.VIEW_VERTEX), 2)
+Operators.sort(pyZBP1D())
+shaders_list = [
+ StrokeTextureShader("smoothAlpha.bmp", Stroke.OPAQUE_MEDIUM, 0),
+ ConstantThicknessShader(3),
+ SamplingShader(5.0),
+ ConstantColorShader(0,0,0,1)
+ ]
+Operators.create(pyDensityUP1D(2,0.05, IntegrationType.MEAN,4), shaders_list)
+#Operators.create(pyDensityFunctorUP1D(8,0.03, pyGetInverseProjectedZF1D(), 0,1, IntegrationType.MEAN), shaders_list)
+
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index 3ff02420bbd..64851a3a4c1 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -22,7 +22,7 @@ if "bpy" in locals():
from imp import reload as _reload
for val in _modules_loaded.values():
_reload(val)
-_modules = (
+_modules = [
"add_mesh_torus",
"anim",
"clip",
@@ -44,16 +44,18 @@ _modules = (
"vertexpaint_dirt",
"view3d",
"wm",
-)
+]
+
+import bpy
+
+if bpy.app.build_options.freestyle:
+ _modules.append("freestyle")
__import__(name=__name__, fromlist=_modules)
_namespace = globals()
-_modules_loaded = {name: _namespace[name] for name in _modules}
+_modules_loaded = {name: _namespace[name] for name in _modules if name != 'bpy'}
del _namespace
-import bpy
-
-
def register():
bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_operators/freestyle.py b/release/scripts/startup/bl_operators/freestyle.py
new file mode 100644
index 00000000000..985676aa86c
--- /dev/null
+++ b/release/scripts/startup/bl_operators/freestyle.py
@@ -0,0 +1,134 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+
+from bpy.props import (EnumProperty, StringProperty)
+
+
+class SCENE_OT_freestyle_fill_range_by_selection(bpy.types.Operator):
+ '''Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object
+ (either a user-specified object or the active camera)'''
+ bl_idname = "scene.freestyle_fill_range_by_selection"
+ bl_label = "Fill Range by Selection"
+
+ type = EnumProperty(name="Type", description="Type of the modifier to work on",
+ items=(("COLOR", "Color", "Color modifier type"),
+ ("ALPHA", "Alpha", "Alpha modifier type"),
+ ("THICKNESS", "Thickness", "Thickness modifier type")))
+ name = StringProperty(name="Name", description="Name of the modifier to work on")
+
+ def execute(self, context):
+ rl = context.scene.render.layers.active
+ lineset = rl.freestyle_settings.linesets.active
+ linestyle = lineset.linestyle
+ # Find the modifier to work on
+ if self.type == 'COLOR':
+ m = linestyle.color_modifiers[self.name]
+ elif self.type == 'ALPHA':
+ m = linestyle.alpha_modifiers[self.name]
+ else:
+ m = linestyle.thickness_modifiers[self.name]
+ # Find the source object
+ if m.type == 'DISTANCE_FROM_CAMERA':
+ source = context.scene.camera
+ elif m.type == 'DISTANCE_FROM_OBJECT':
+ if m.target is None:
+ self.report({'ERROR'}, "Target object not specified")
+ return {'CANCELLED'}
+ source = m.target
+ else:
+ self.report({'ERROR'}, "Unexpected modifier type: " + m.type)
+ return {'CANCELLED'}
+ # Find selected mesh objects
+ selection = [ob for ob in context.scene.objects if ob.select and ob.type == 'MESH' and ob.name != source.name]
+ if len(selection) > 0:
+ # Compute the min/max distance between selected mesh objects and the source
+ min_dist = float('inf')
+ max_dist = -min_dist
+ for ob in selection:
+ for vert in ob.data.vertices:
+ dist = (ob.matrix_world * vert.co - source.location).length
+ min_dist = min(dist, min_dist)
+ max_dist = max(dist, max_dist)
+ # Fill the Range Min/Max entries with the computed distances
+ m.range_min = min_dist
+ m.range_max = max_dist
+ return {'FINISHED'}
+
+
+class SCENE_OT_freestyle_add_edge_marks_to_keying_set(bpy.types.Operator):
+ '''Add the data paths to the Freestyle Edge Mark property of selected edges to the active keying set'''
+ bl_idname = "scene.freestyle_add_edge_marks_to_keying_set"
+ bl_label = "Add Edge Marks to Keying Set"
+ bl_options = {'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.active_object
+ return (ob and ob.type == 'MESH')
+
+ def execute(self, context):
+ # active keying set
+ scene = context.scene
+ ks = scene.keying_sets.active
+ if ks is None:
+ ks = scene.keying_sets.new(idname="FreestyleEdgeMarkKeyingSet", name="Freestyle Edge Mark Keying Set")
+ ks.bl_description = ""
+ # add data paths to the keying set
+ ob = context.active_object
+ ob_mode = ob.mode
+ mesh = ob.data
+ bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+ for i, edge in enumerate(mesh.edges):
+ if not edge.hide and edge.select:
+ path = 'edges[%d].use_freestyle_edge_mark' % i
+ ks.paths.add(mesh, path, index=0)
+ bpy.ops.object.mode_set(mode=ob_mode, toggle=False)
+ return {'FINISHED'}
+
+
+class SCENE_OT_freestyle_add_face_marks_to_keying_set(bpy.types.Operator):
+ '''Add the data paths to the Freestyle Face Mark property of selected polygons to the active keying set'''
+ bl_idname = "scene.freestyle_add_face_marks_to_keying_set"
+ bl_label = "Add Face Marks to Keying Set"
+ bl_options = {'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ ob = context.active_object
+ return (ob and ob.type == 'MESH')
+
+ def execute(self, context):
+ # active keying set
+ scene = context.scene
+ ks = scene.keying_sets.active
+ if ks is None:
+ ks = scene.keying_sets.new(idname="FreestyleFaceMarkKeyingSet", name="Freestyle Face Mark Keying Set")
+ ks.bl_description = ""
+ # add data paths to the keying set
+ ob = context.active_object
+ ob_mode = ob.mode
+ mesh = ob.data
+ bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+ for i, polygon in enumerate(mesh.polygons):
+ if not polygon.hide and polygon.select:
+ path = 'polygons[%d].use_freestyle_face_mark' % i
+ ks.paths.add(mesh, path, index=0)
+ bpy.ops.object.mode_set(mode=ob_mode, toggle=False)
+ return {'FINISHED'}
diff --git a/release/scripts/startup/bl_ui/__init__.py b/release/scripts/startup/bl_ui/__init__.py
index 982c723f08e..94f324d62d0 100644
--- a/release/scripts/startup/bl_ui/__init__.py
+++ b/release/scripts/startup/bl_ui/__init__.py
@@ -53,6 +53,7 @@ _modules = (
"properties_physics_smoke",
"properties_physics_softbody",
"properties_render",
+ "properties_render_layer",
"properties_scene",
"properties_texture",
"properties_world",
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 29e32401d2b..cb5a473dba1 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
-from bpy.types import Menu, Panel, UIList
+from bpy.types import Menu, Panel
class RENDER_MT_presets(Menu):
@@ -43,23 +43,6 @@ class RENDER_MT_framerate_presets(Menu):
draw = Menu.draw_preset
-class RENDER_UL_renderlayers(UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
- # assert(isinstance(item, bpy.types.SceneRenderLayer)
- layer = item
- if self.layout_type in {'DEFAULT', 'COMPACT'}:
- layout.label(layer.name, icon_value=icon)
- layout.prop(layer, "use", text="", index=index)
- elif self.layout_type in {'GRID'}:
- layout.alignment = 'CENTER'
- layout.label("", icon_value=icon)
-
-# else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
-# uiItemL(sub, name, icon);
-# uiBlockSetEmboss(block, UI_EMBOSS);
-# uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0, NULL);
-# }
-
class RenderButtonsPanel():
bl_space_type = 'PROPERTIES'
@@ -69,8 +52,18 @@ class RenderButtonsPanel():
@classmethod
def poll(cls, context):
- rd = context.scene.render
- return context.scene and (rd.engine in cls.COMPAT_ENGINES)
+ scene = context.scene
+ return scene and (scene.render.engine in cls.COMPAT_ENGINES)
+
+
+class RenderFreestyleButtonsPanel(RenderButtonsPanel):
+ # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
+
+ @classmethod
+ def poll(cls, context):
+ if not super().poll(context):
+ return False
+ return bpy.app.build_options.freestyle
class RENDER_PT_render(RenderButtonsPanel, Panel):
@@ -90,110 +83,6 @@ class RENDER_PT_render(RenderButtonsPanel, Panel):
layout.prop(rd, "display_mode", text="Display")
-class RENDER_PT_layers(RenderButtonsPanel, Panel):
- bl_label = "Layers"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER'}
-
- def draw(self, context):
- layout = self.layout
-
- scene = context.scene
- rd = scene.render
-
- row = layout.row()
- row.template_list("RENDER_UL_renderlayers", "", rd, "layers", rd.layers, "active_index", rows=2)
-
- col = row.column(align=True)
- col.operator("scene.render_layer_add", icon='ZOOMIN', text="")
- col.operator("scene.render_layer_remove", icon='ZOOMOUT', text="")
-
- row = layout.row()
- rl = rd.layers.active
- if rl:
- row.prop(rl, "name")
- row.prop(rd, "use_single_layer", text="", icon_only=True)
-
- split = layout.split()
-
- col = split.column()
- col.prop(scene, "layers", text="Scene")
- col.label(text="")
- col.prop(rl, "light_override", text="Light")
- col.prop(rl, "material_override", text="Material")
-
- col = split.column()
- col.prop(rl, "layers", text="Layer")
- col.label(text="Mask Layers:")
- col.prop(rl, "layers_zmask", text="")
-
- layout.separator()
- layout.label(text="Include:")
-
- split = layout.split()
-
- col = split.column()
- col.prop(rl, "use_zmask")
- row = col.row()
- row.prop(rl, "invert_zmask", text="Negate")
- row.active = rl.use_zmask
- col.prop(rl, "use_all_z")
-
- col = split.column()
- col.prop(rl, "use_solid")
- col.prop(rl, "use_halo")
- col.prop(rl, "use_ztransp")
-
- col = split.column()
- col.prop(rl, "use_sky")
- col.prop(rl, "use_edge_enhance")
- col.prop(rl, "use_strand")
-
- layout.separator()
-
- split = layout.split()
-
- col = split.column()
- col.label(text="Passes:")
- col.prop(rl, "use_pass_combined")
- col.prop(rl, "use_pass_z")
- col.prop(rl, "use_pass_vector")
- col.prop(rl, "use_pass_normal")
- col.prop(rl, "use_pass_uv")
- col.prop(rl, "use_pass_mist")
- col.prop(rl, "use_pass_object_index")
- col.prop(rl, "use_pass_material_index")
- col.prop(rl, "use_pass_color")
-
- col = split.column()
- col.label()
- col.prop(rl, "use_pass_diffuse")
- row = col.row()
- row.prop(rl, "use_pass_specular")
- row.prop(rl, "exclude_specular", text="")
- row = col.row()
- row.prop(rl, "use_pass_shadow")
- row.prop(rl, "exclude_shadow", text="")
- row = col.row()
- row.prop(rl, "use_pass_emit")
- row.prop(rl, "exclude_emit", text="")
- row = col.row()
- row.prop(rl, "use_pass_ambient_occlusion")
- row.prop(rl, "exclude_ambient_occlusion", text="")
- row = col.row()
- row.prop(rl, "use_pass_environment")
- row.prop(rl, "exclude_environment", text="")
- row = col.row()
- row.prop(rl, "use_pass_indirect")
- row.prop(rl, "exclude_indirect", text="")
- row = col.row()
- row.prop(rl, "use_pass_reflection")
- row.prop(rl, "exclude_reflection", text="")
- row = col.row()
- row.prop(rl, "use_pass_refraction")
- row.prop(rl, "exclude_refraction", text="")
-
-
class RENDER_PT_dimensions(RenderButtonsPanel, Panel):
bl_label = "Dimensions"
COMPAT_ENGINES = {'BLENDER_RENDER'}
@@ -420,6 +309,29 @@ class RENDER_PT_post_processing(RenderButtonsPanel, Panel):
sub.prop(rd, "edge_color", text="")
+class RENDER_PT_freestyle(RenderFreestyleButtonsPanel, Panel):
+ bl_label = "Freestyle"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ def draw_header(self, context):
+ rd = context.scene.render
+ self.layout.prop(rd, "use_freestyle", text="")
+
+ def draw(self, context):
+ rd = context.scene.render
+
+ layout = self.layout
+ layout.active = rd.use_freestyle
+
+ row = layout.row()
+ row.label(text="Line Thickness:")
+ row.prop(rd, "line_thickness_mode", expand=True)
+ row = layout.row()
+ row.active = (rd.line_thickness_mode == 'ABSOLUTE')
+ row.prop(rd, "unit_line_thickness")
+
+
class RENDER_PT_stamp(RenderButtonsPanel, Panel):
bl_label = "Stamp"
bl_options = {'DEFAULT_CLOSED'}
diff --git a/release/scripts/startup/bl_ui/properties_render_layer.py b/release/scripts/startup/bl_ui/properties_render_layer.py
new file mode 100644
index 00000000000..61750f6e89f
--- /dev/null
+++ b/release/scripts/startup/bl_ui/properties_render_layer.py
@@ -0,0 +1,782 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import bpy
+from bpy.types import Menu, Panel, UIList
+
+
+class RenderLayerButtonsPanel():
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "render_layer"
+ # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
+
+ @classmethod
+ def poll(cls, context):
+ scene = context.scene
+ return scene and (scene.render.engine in cls.COMPAT_ENGINES)
+
+
+class RenderLayerFreestyleButtonsPanel(RenderLayerButtonsPanel):
+ # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
+
+ @classmethod
+ def poll(cls, context):
+ if not super().poll(context):
+ return False
+ rd = context.scene.render
+ return bpy.app.build_options.freestyle and rd.use_freestyle and rd.layers.active
+
+
+class RenderLayerFreestyleEditorButtonsPanel(RenderLayerFreestyleButtonsPanel):
+ # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
+
+ @classmethod
+ def poll(cls, context):
+ if not super().poll(context):
+ return False
+ rl = context.scene.render.layers.active
+ return rl and rl.freestyle_settings.mode == 'EDITOR'
+
+
+class RENDERLAYER_UL_renderlayers(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ # assert(isinstance(item, bpy.types.SceneRenderLayer)
+ layer = item
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ layout.label(layer.name, icon_value=icon)
+ layout.prop(layer, "use", text="", index=index)
+ elif self.layout_type in {'GRID'}:
+ layout.alignment = 'CENTER'
+ layout.label("", icon_value=icon)
+
+# else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
+# uiItemL(sub, name, icon);
+# uiBlockSetEmboss(block, UI_EMBOSS);
+# uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0, NULL);
+# }
+
+
+class RENDERLAYER_UL_linesets(UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ lineset = item
+ if self.layout_type in {'DEFAULT', 'COMPACT'}:
+ layout.label(lineset.name, icon_value=icon)
+ layout.prop(lineset, "use", text="", index=index)
+ elif self.layout_type in {'GRID'}:
+ layout.alignment = 'CENTER'
+ layout.label("", icon_value=icon)
+
+##ifdef WITH_FREESTYLE
+# else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer) ||
+# RNA_struct_is_a(itemptr->type, &RNA_FreestyleLineSet)) {
+##else
+# else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
+##endif
+# uiItemL(sub, name, icon);
+# uiBlockSetEmboss(block, UI_EMBOSS);
+# uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0, NULL);
+# }
+
+
+class RENDERLAYER_PT_layers(RenderLayerButtonsPanel, Panel):
+ bl_label = "Layers"
+ bl_options = {'HIDE_HEADER'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+ rd = scene.render
+
+ row = layout.row()
+ row.template_list("RENDERLAYER_UL_renderlayers", "", rd, "layers", rd.layers, "active_index", rows=2)
+
+ col = row.column(align=True)
+ col.operator("scene.render_layer_add", icon='ZOOMIN', text="")
+ col.operator("scene.render_layer_remove", icon='ZOOMOUT', text="")
+
+ row = layout.row()
+ rl = rd.layers.active
+ if rl:
+ row.prop(rl, "name")
+ row.prop(rd, "use_single_layer", text="", icon_only=True)
+
+
+class RENDERLAYER_PT_layer_options(RenderLayerButtonsPanel, Panel):
+ bl_label = "Layer"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+ rd = scene.render
+ rl = rd.layers.active
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(scene, "layers", text="Scene")
+ col.label(text="")
+ col.prop(rl, "light_override", text="Light")
+ col.prop(rl, "material_override", text="Material")
+
+ col = split.column()
+ col.prop(rl, "layers", text="Layer")
+ col.label(text="Mask Layers:")
+ col.prop(rl, "layers_zmask", text="")
+
+ layout.separator()
+ layout.label(text="Include:")
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(rl, "use_zmask")
+ row = col.row()
+ row.prop(rl, "invert_zmask", text="Negate")
+ row.active = rl.use_zmask
+ col.prop(rl, "use_all_z")
+
+ col = split.column()
+ col.prop(rl, "use_solid")
+ col.prop(rl, "use_halo")
+ col.prop(rl, "use_ztransp")
+
+ col = split.column()
+ col.prop(rl, "use_sky")
+ col.prop(rl, "use_edge_enhance")
+ col.prop(rl, "use_strand")
+ if bpy.app.build_options.freestyle:
+ row = col.row()
+ row.prop(rl, "use_freestyle")
+ row.active = rd.use_freestyle
+
+
+class RENDERLAYER_PT_layer_passes(RenderLayerButtonsPanel, Panel):
+ bl_label = "Render Passes"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ def draw_pass_type_buttons(self, box, rl, pass_type):
+ # property names
+ use_pass_type = "use_pass_" + pass_type
+ exclude_pass_type = "exclude_" + pass_type
+ # draw pass type buttons
+ row = box.row()
+ row.prop(rl, use_pass_type)
+ row.prop(rl, exclude_pass_type, text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
+ rd = scene.render
+ rl = rd.layers.active
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(rl, "use_pass_combined")
+ col.prop(rl, "use_pass_z")
+ col.prop(rl, "use_pass_vector")
+ col.prop(rl, "use_pass_normal")
+ col.prop(rl, "use_pass_uv")
+ col.prop(rl, "use_pass_mist")
+ col.prop(rl, "use_pass_object_index")
+ col.prop(rl, "use_pass_material_index")
+ col.prop(rl, "use_pass_color")
+
+ col = split.column()
+ col.prop(rl, "use_pass_diffuse")
+ self.draw_pass_type_buttons(col, rl, "specular")
+ self.draw_pass_type_buttons(col, rl, "shadow")
+ self.draw_pass_type_buttons(col, rl, "emit")
+ self.draw_pass_type_buttons(col, rl, "ambient_occlusion")
+ self.draw_pass_type_buttons(col, rl, "environment")
+ self.draw_pass_type_buttons(col, rl, "indirect")
+ self.draw_pass_type_buttons(col, rl, "reflection")
+ self.draw_pass_type_buttons(col, rl, "refraction")
+
+
+class RENDER_MT_lineset_specials(Menu):
+ bl_label = "Lineset Specials"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator("scene.freestyle_lineset_copy", icon='COPYDOWN')
+ layout.operator("scene.freestyle_lineset_paste", icon='PASTEDOWN')
+
+
+class RENDERLAYER_PT_freestyle(RenderLayerFreestyleButtonsPanel, Panel):
+ bl_label = "Freestyle"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ def draw(self, context):
+ rd = context.scene.render
+ rl = rd.layers.active
+ freestyle = rl.freestyle_settings
+
+ layout = self.layout
+ layout.active = rl.use_freestyle
+ layout.prop(freestyle, "mode", text="Control mode")
+
+ col = layout.column()
+ col.label(text="Edge Detection Options:")
+ split = col.split()
+ sub = split.column()
+ sub.prop(freestyle, "crease_angle")
+ sub.prop(freestyle, "use_culling")
+ sub = split.column()
+ sub.prop(freestyle, "use_smoothness")
+ sub.prop(freestyle, "use_material_boundaries")
+ col.prop(freestyle, "use_advanced_options")
+ # Advanced options are hidden by default to warn new users
+ if freestyle.use_advanced_options:
+ split = col.split()
+ sub = split.column()
+ sub.active = freestyle.use_advanced_options
+ if freestyle.mode == 'SCRIPT':
+ sub.prop(freestyle, "use_ridges_and_valleys")
+ sub.prop(freestyle, "sphere_radius")
+ sub = split.column()
+ sub.active = freestyle.use_advanced_options
+ if freestyle.mode == 'SCRIPT':
+ sub.prop(freestyle, "use_suggestive_contours")
+ sub.prop(freestyle, "kr_derivative_epsilon")
+
+ if freestyle.mode == 'SCRIPT':
+ split = layout.split()
+ split.label("Style modules:")
+ split.operator("scene.freestyle_module_add", text="Add")
+ for i, module in enumerate(freestyle.modules):
+ box = layout.box()
+ box.context_pointer_set("freestyle_module", module)
+ row = box.row(align=True)
+ row.prop(module, "use", text="")
+ row.prop(module, "module_path", text="")
+ row.operator("scene.freestyle_module_remove", icon='X', text="")
+ row.operator("scene.freestyle_module_move", icon='TRIA_UP', text="").direction = 'UP'
+ row.operator("scene.freestyle_module_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+
+
+class RENDERLAYER_PT_freestyle_lineset(RenderLayerFreestyleEditorButtonsPanel, Panel):
+ bl_label = "Freestyle Line Set"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ def draw_edge_type_buttons(self, box, lineset, edge_type):
+ # property names
+ select_edge_type = "select_" + edge_type
+ exclude_edge_type = "exclude_" + edge_type
+ # draw edge type buttons
+ row = box.row(align=True)
+ row.prop(lineset, select_edge_type)
+ sub = row.column()
+ sub.prop(lineset, exclude_edge_type, text="")
+ sub.active = getattr(lineset, select_edge_type)
+
+ def draw(self, context):
+ rd = context.scene.render
+ rl = rd.layers.active
+ freestyle = rl.freestyle_settings
+ lineset = freestyle.linesets.active
+
+ layout = self.layout
+ layout.active = rl.use_freestyle
+
+ col = layout.column()
+ row = col.row()
+ rows = 5 if lineset else 2
+ row.template_list("RENDERLAYER_UL_linesets", "", freestyle, "linesets", freestyle.linesets, "active_index", rows=rows)
+
+ sub = row.column()
+ subsub = sub.column(align=True)
+ subsub.operator("scene.freestyle_lineset_add", icon='ZOOMIN', text="")
+ subsub.operator("scene.freestyle_lineset_remove", icon='ZOOMOUT', text="")
+ subsub.menu("RENDER_MT_lineset_specials", icon='DOWNARROW_HLT', text="")
+ if lineset:
+ sub.separator()
+ subsub = sub.column(align=True)
+ subsub.operator("scene.freestyle_lineset_move", icon='TRIA_UP', text="").direction = 'UP'
+ subsub.operator("scene.freestyle_lineset_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+
+ col.prop(lineset, "name")
+
+ col = layout.column()
+ col.label(text="Selection By:")
+ row = col.row(align=True)
+ row.prop(lineset, "select_by_visibility", text="Visibility", toggle=True)
+ row.prop(lineset, "select_by_edge_types", text="Edge Types", toggle=True)
+ row.prop(lineset, "select_by_face_marks", text="Face Marks", toggle=True)
+ row.prop(lineset, "select_by_group", text="Group", toggle=True)
+ row.prop(lineset, "select_by_image_border", text="Image Border", toggle=True)
+
+ if lineset.select_by_visibility:
+ col.label(text="Visibility:")
+ row = col.row(align=True)
+ row.prop(lineset, "visibility", expand=True)
+ if lineset.visibility == 'RANGE':
+ row = col.row(align=True)
+ row.prop(lineset, "qi_start")
+ row.prop(lineset, "qi_end")
+
+ if lineset.select_by_edge_types:
+ col.label(text="Edge Types:")
+ row = col.row()
+ row.prop(lineset, "edge_type_negation", expand=True)
+ row.prop(lineset, "edge_type_combination", expand=True)
+
+ split = col.split()
+ sub = split.column()
+ self.draw_edge_type_buttons(sub, lineset, "silhouette")
+ self.draw_edge_type_buttons(sub, lineset, "border")
+ self.draw_edge_type_buttons(sub, lineset, "contour")
+ self.draw_edge_type_buttons(sub, lineset, "suggestive_contour")
+ self.draw_edge_type_buttons(sub, lineset, "ridge_valley")
+ sub = split.column()
+ self.draw_edge_type_buttons(sub, lineset, "crease")
+ self.draw_edge_type_buttons(sub, lineset, "edge_mark")
+ self.draw_edge_type_buttons(sub, lineset, "external_contour")
+ self.draw_edge_type_buttons(sub, lineset, "material_boundary")
+
+ if lineset.select_by_face_marks:
+ col.label(text="Face Marks:")
+ row = col.row()
+ row.prop(lineset, "face_mark_negation", expand=True)
+ row.prop(lineset, "face_mark_condition", expand=True)
+
+ if lineset.select_by_group:
+ col.label(text="Group:")
+ row = col.row()
+ row.prop(lineset, "group", text="")
+ row.prop(lineset, "group_negation", expand=True)
+
+
+class RENDERLAYER_PT_freestyle_linestyle(RenderLayerFreestyleEditorButtonsPanel, Panel):
+ bl_label = "Freestyle Line Style"
+ bl_options = {'DEFAULT_CLOSED'}
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
+
+ def draw_modifier_box_header(self, box, modifier):
+ row = box.row()
+ row.context_pointer_set("modifier", modifier)
+ if modifier.expanded:
+ icon = 'TRIA_DOWN'
+ else:
+ icon = 'TRIA_RIGHT'
+ row.prop(modifier, "expanded", text="", icon=icon, emboss=False)
+ # TODO: Use icons rather than text label, would save some room!
+ row.label(text=modifier.rna_type.name)
+ row.prop(modifier, "name", text="")
+ if modifier.use:
+ icon = 'RESTRICT_RENDER_OFF'
+ else:
+ icon = 'RESTRICT_RENDER_ON'
+ row.prop(modifier, "use", text="", icon=icon)
+ sub = row.row(align=True)
+ sub.operator("scene.freestyle_modifier_copy", icon='NONE', text="Copy")
+ sub.operator("scene.freestyle_modifier_move", icon='TRIA_UP', text="").direction = 'UP'
+ sub.operator("scene.freestyle_modifier_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
+ sub.operator("scene.freestyle_modifier_remove", icon='X', text="")
+
+ def draw_modifier_common(self, box, modifier):
+ row = box.row()
+ row.prop(modifier, "blend", text="")
+ row.prop(modifier, "influence")
+
+ def draw_modifier_color_ramp_common(self, box, modifier, has_range):
+ box.template_color_ramp(modifier, "color_ramp", expand=True)
+ if has_range:
+ row = box.row(align=True)
+ row.prop(modifier, "range_min")
+ row.prop(modifier, "range_max")
+
+ def draw_modifier_curve_common(self, box, modifier, has_range, has_value):
+ row = box.row()
+ row.prop(modifier, "mapping", text="")
+ sub = row.column()
+ sub.prop(modifier, "invert")
+ if modifier.mapping == 'CURVE':
+ sub.active = False
+ box.template_curve_mapping(modifier, "curve")
+ if has_range:
+ row = box.row(align=True)
+ row.prop(modifier, "range_min")
+ row.prop(modifier, "range_max")
+ if has_value:
+ row = box.row(align=True)
+ row.prop(modifier, "value_min")
+ row.prop(modifier, "value_max")
+
+ def draw_color_modifier(self, context, modifier):
+ layout = self.layout
+
+ col = layout.column(align=True)
+ self.draw_modifier_box_header(col.box(), modifier)
+ if modifier.expanded:
+ box = col.box()
+ self.draw_modifier_common(box, modifier)
+
+ if modifier.type == 'ALONG_STROKE':
+ self.draw_modifier_color_ramp_common(box, modifier, False)
+
+ elif modifier.type == 'DISTANCE_FROM_OBJECT':
+ box.prop(modifier, "target")
+ self.draw_modifier_color_ramp_common(box, modifier, True)
+ prop = box.operator("scene.freestyle_fill_range_by_selection")
+ prop.type = 'COLOR'
+ prop.name = modifier.name
+
+ elif modifier.type == 'DISTANCE_FROM_CAMERA':
+ self.draw_modifier_color_ramp_common(box, modifier, True)
+ prop = box.operator("scene.freestyle_fill_range_by_selection")
+ prop.type = 'COLOR'
+ prop.name = modifier.name
+
+ elif modifier.type == 'MATERIAL':
+ row = box.row()
+ row.prop(modifier, "material_attr", text="")
+ sub = row.column()
+ sub.prop(modifier, "use_ramp")
+ if modifier.material_attr in {'DIFF', 'SPEC'}:
+ sub.active = True
+ show_ramp = modifier.use_ramp
+ else:
+ sub.active = False
+ show_ramp = True
+ if show_ramp:
+ self.draw_modifier_color_ramp_common(box, modifier, False)
+
+ def draw_alpha_modifier(self, context, modifier):
+ layout = self.layout
+
+ col = layout.column(align=True)
+ self.draw_modifier_box_header(col.box(), modifier)
+ if modifier.expanded:
+ box = col.box()
+ self.draw_modifier_common(box, modifier)
+
+ if modifier.type == 'ALONG_STROKE':
+ self.draw_modifier_curve_common(box, modifier, False, False)
+
+ elif modifier.type == 'DISTANCE_FROM_OBJECT':
+ box.prop(modifier, "target")
+ self.draw_modifier_curve_common(box, modifier, True, False)
+ prop = box.operator("scene.freestyle_fill_range_by_selection")
+ prop.type = 'ALPHA'
+ prop.name = modifier.name
+
+ elif modifier.type == 'DISTANCE_FROM_CAMERA':
+ self.draw_modifier_curve_common(box, modifier, True, False)
+ prop = box.operator("scene.freestyle_fill_range_by_selection")
+ prop.type = 'ALPHA'
+ prop.name = modifier.name
+
+ elif modifier.type == 'MATERIAL':
+ box.prop(modifier, "material_attr", text="")
+ self.draw_modifier_curve_common(box, modifier, False, False)
+
+ def draw_thickness_modifier(self, context, modifier):
+ layout = self.layout
+
+ col = layout.column(align=True)
+ self.draw_modifier_box_header(col.box(), modifier)
+ if modifier.expanded:
+ box = col.box()
+ self.draw_modifier_common(box, modifier)
+
+ if modifier.type == 'ALONG_STROKE':
+ self.draw_modifier_curve_common(box, modifier, False, True)
+
+ elif modifier.type == 'DISTANCE_FROM_OBJECT':
+ box.prop(modifier, "target")
+ self.draw_modifier_curve_common(box, modifier, True, True)
+ prop = box.operator("scene.freestyle_fill_range_by_selection")
+ prop.type = 'THICKNESS'
+ prop.name = modifier.name
+
+ elif modifier.type == 'DISTANCE_FROM_CAMERA':
+ self.draw_modifier_curve_common(box, modifier, True, True)
+ prop = box.operator("scene.freestyle_fill_range_by_selection")
+ prop.type = 'THICKNESS'
+ prop.name = modifier.name
+
+ elif modifier.type == 'MATERIAL':
+ box.prop(modifier, "material_attr", text="")
+ self.draw_modifier_curve_common(box, modifier, False, True)
+
+ elif modifier.type == 'CALLIGRAPHY':
+ box.prop(modifier, "orientation")
+ row = box.row(align=True)
+ row.prop(modifier, "min_thickness")
+ row.prop(modifier, "max_thickness")
+
+ def draw_geometry_modifier(self, context, modifier):
+ layout = self.layout
+
+ col = layout.column(align=True)
+ self.draw_modifier_box_header(col.box(), modifier)
+ if modifier.expanded:
+ box = col.box()
+
+ if modifier.type == 'SAMPLING':
+ box.prop(modifier, "sampling")
+
+ elif modifier.type == 'BEZIER_CURVE':
+ box.prop(modifier, "error")
+
+ elif modifier.type == 'SINUS_DISPLACEMENT':
+ split = box.split()
+ col = split.column()
+ col.prop(modifier, "wavelength")
+ col.prop(modifier, "amplitude")
+ col = split.column()
+ col.prop(modifier, "phase")
+
+ elif modifier.type == 'SPATIAL_NOISE':
+ split = box.split()
+ col = split.column()
+ col.prop(modifier, "amplitude")
+ col.prop(modifier, "scale")
+ col.prop(modifier, "octaves")
+ col = split.column()
+ col.prop(modifier, "smooth")
+ col.prop(modifier, "pure_random")
+
+ elif modifier.type == 'PERLIN_NOISE_1D':
+ split = box.split()
+ col = split.column()
+ col.prop(modifier, "frequency")
+ col.prop(modifier, "amplitude")
+ col.prop(modifier, "seed")
+ col = split.column()
+ col.prop(modifier, "octaves")
+ col.prop(modifier, "angle")
+
+ elif modifier.type == 'PERLIN_NOISE_2D':
+ split = box.split()
+ col = split.column()
+ col.prop(modifier, "frequency")
+ col.prop(modifier, "amplitude")
+ col.prop(modifier, "seed")
+ col = split.column()
+ col.prop(modifier, "octaves")
+ col.prop(modifier, "angle")
+
+ elif modifier.type == 'BACKBONE_STRETCHER':
+ box.prop(modifier, "backbone_length")
+
+ elif modifier.type == 'TIP_REMOVER':
+ box.prop(modifier, "tip_length")
+
+ elif modifier.type == 'POLYGONIZATION':
+ box.prop(modifier, "error")
+
+ elif modifier.type == 'GUIDING_LINES':
+ box.prop(modifier, "offset")
+
+ elif modifier.type == 'BLUEPRINT':
+ row = box.row()
+ row.prop(modifier, "shape", expand=True)
+ box.prop(modifier, "rounds")
+ row = box.row()
+ if modifier.shape in {'CIRCLES', 'ELLIPSES'}:
+ row.prop(modifier, "random_radius")
+ row.prop(modifier, "random_center")
+ elif modifier.shape == 'SQUARES':
+ row.prop(modifier, "backbone_length")
+ row.prop(modifier, "random_backbone")
+
+ elif modifier.type == '2D_OFFSET':
+ row = box.row(align=True)
+ row.prop(modifier, "start")
+ row.prop(modifier, "end")
+ row = box.row(align=True)
+ row.prop(modifier, "x")
+ row.prop(modifier, "y")
+
+ elif modifier.type == '2D_TRANSFORM':
+ box.prop(modifier, "pivot")
+ if modifier.pivot == 'PARAM':
+ box.prop(modifier, "pivot_u")
+ elif modifier.pivot == 'ABSOLUTE':
+ row = box.row(align=True)
+ row.prop(modifier, "pivot_x")
+ row.prop(modifier, "pivot_y")
+ row = box.row(align=True)
+ row.prop(modifier, "scale_x")
+ row.prop(modifier, "scale_y")
+ box.prop(modifier, "angle")
+
+ def draw(self, context):
+ rd = context.scene.render
+ rl = rd.layers.active
+ lineset = rl.freestyle_settings.linesets.active
+
+ layout = self.layout
+ layout.active = rl.use_freestyle
+
+ if lineset is None:
+ return
+ linestyle = lineset.linestyle
+
+ layout.template_ID(lineset, "linestyle", new="scene.freestyle_linestyle_new")
+ row = layout.row(align=True)
+ row.prop(linestyle, "panel", expand=True)
+ if linestyle.panel == 'STROKES':
+ ## Chaining
+ layout.label(text="Chaining:")
+ split = layout.split(align=True)
+ # First column
+ col = split.column()
+ col.prop(linestyle, "use_chaining", text="Enable Chaining")
+ sub = col.row()
+ sub.active = linestyle.use_chaining
+ sub.prop(linestyle, "same_object")
+ # Second column
+ col = split.column()
+ col.active = linestyle.use_chaining
+ col.prop(linestyle, "chaining", text="")
+ if linestyle.chaining == 'SKETCHY':
+ col.prop(linestyle, "rounds")
+
+ ## Splitting
+ layout.label(text="Splitting:")
+ split = layout.split(align=True)
+ # First column
+ col = split.column()
+ row = col.row(align=True)
+ row.prop(linestyle, "use_min_angle", text="")
+ sub = row.row()
+ sub.active = linestyle.use_min_angle
+ sub.prop(linestyle, "min_angle")
+ row = col.row(align=True)
+ row.prop(linestyle, "use_max_angle", text="")
+ sub = row.row()
+ sub.active = linestyle.use_max_angle
+ sub.prop(linestyle, "max_angle")
+ # Second column
+ col = split.column()
+ row = col.row(align=True)
+ row.prop(linestyle, "use_split_length", text="")
+ sub = row.row()
+ sub.active = linestyle.use_split_length
+ sub.prop(linestyle, "split_length", text="2D Length")
+ row = col.row(align=True)
+ row.prop(linestyle, "material_boundary")
+ # End of columns
+ row = layout.row(align=True)
+ row.prop(linestyle, "use_split_pattern", text="")
+ sub = row.row()
+ sub.active = linestyle.use_split_pattern
+ sub.prop(linestyle, "split_dash1", text="D1")
+ sub.prop(linestyle, "split_gap1", text="G1")
+ sub.prop(linestyle, "split_dash2", text="D2")
+ sub.prop(linestyle, "split_gap2", text="G2")
+ sub.prop(linestyle, "split_dash3", text="D3")
+ sub.prop(linestyle, "split_gap3", text="G3")
+
+ ## Selection
+ layout.label(text="Selection:")
+ split = layout.split(align=True)
+ # First column
+ col = split.column()
+ row = col.row(align=True)
+ row.prop(linestyle, "use_min_length", text="")
+ sub = row.row()
+ sub.active = linestyle.use_min_length
+ sub.prop(linestyle, "min_length")
+ # Second column
+ col = split.column()
+ row = col.row(align=True)
+ row.prop(linestyle, "use_max_length", text="")
+ sub = row.row()
+ sub.active = linestyle.use_max_length
+ sub.prop(linestyle, "max_length")
+
+ ## Caps
+ layout.label(text="Caps:")
+ row = layout.row(align=True)
+ row.prop(linestyle, "caps", expand=True)
+
+ ## Dashed lines
+ layout.label(text="Dashed Line:")
+ row = layout.row(align=True)
+ row.prop(linestyle, "use_dashed_line", text="")
+ sub = row.row()
+ sub.active = linestyle.use_dashed_line
+ sub.prop(linestyle, "dash1", text="D1")
+ sub.prop(linestyle, "gap1", text="G1")
+ sub.prop(linestyle, "dash2", text="D2")
+ sub.prop(linestyle, "gap2", text="G2")
+ sub.prop(linestyle, "dash3", text="D3")
+ sub.prop(linestyle, "gap3", text="G3")
+
+ elif linestyle.panel == 'COLOR':
+ col = layout.column()
+ row = col.row()
+ row.label(text="Base Color:")
+ row.prop(linestyle, "color", text="")
+ col.label(text="Modifiers:")
+ col.operator_menu_enum("scene.freestyle_color_modifier_add", "type", text="Add Modifier")
+ for modifier in linestyle.color_modifiers:
+ self.draw_color_modifier(context, modifier)
+
+ elif linestyle.panel == 'ALPHA':
+ col = layout.column()
+ row = col.row()
+ row.label(text="Base Transparency:")
+ row.prop(linestyle, "alpha")
+ col.label(text="Modifiers:")
+ col.operator_menu_enum("scene.freestyle_alpha_modifier_add", "type", text="Add Modifier")
+ for modifier in linestyle.alpha_modifiers:
+ self.draw_alpha_modifier(context, modifier)
+
+ elif linestyle.panel == 'THICKNESS':
+ col = layout.column()
+ row = col.row()
+ row.label(text="Base Thickness:")
+ row.prop(linestyle, "thickness")
+ row = col.row()
+ row.prop(linestyle, "thickness_position", expand=True)
+ row = col.row()
+ row.prop(linestyle, "thickness_ratio")
+ row.active = (linestyle.thickness_position == 'RELATIVE')
+ col = layout.column()
+ col.label(text="Modifiers:")
+ col.operator_menu_enum("scene.freestyle_thickness_modifier_add", "type", text="Add Modifier")
+ for modifier in linestyle.thickness_modifiers:
+ self.draw_thickness_modifier(context, modifier)
+
+ elif linestyle.panel == 'GEOMETRY':
+ col = layout.column()
+ col.label(text="Modifiers:")
+ col.operator_menu_enum("scene.freestyle_geometry_modifier_add", "type", text="Add Modifier")
+ for modifier in linestyle.geometry_modifiers:
+ self.draw_geometry_modifier(context, modifier)
+
+ elif linestyle.panel == 'MISC':
+ pass
+
+
+if __name__ == "__main__": # only for live edit.
+ bpy.utils.register_module(__name__)
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index d1f9ea58654..6c5cc93947b 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -1860,6 +1860,12 @@ class VIEW3D_MT_edit_mesh_edges(Menu):
layout.separator()
+ if context.scene and bpy.app.build_options.freestyle:
+ layout.operator("mesh.mark_freestyle_edge").clear = False
+ layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
+
+ layout.separator()
+
layout.operator("mesh.edge_rotate", text="Rotate Edge CW").use_ccw = False
layout.operator("mesh.edge_rotate", text="Rotate Edge CCW").use_ccw = True
@@ -1900,6 +1906,12 @@ class VIEW3D_MT_edit_mesh_faces(Menu):
layout.separator()
+ if context.scene and bpy.app.build_options.freestyle:
+ layout.operator("mesh.mark_freestyle_face").clear = False
+ layout.operator("mesh.mark_freestyle_face", text="Clear Freestyle Face").clear = True
+
+ layout.separator()
+
layout.operator("mesh.quads_convert_to_tris")
layout.operator("mesh.tris_convert_to_quads")
@@ -2503,6 +2515,9 @@ class VIEW3D_PT_view3d_meshdisplay(Panel):
col.prop(mesh, "show_edge_bevel_weight", text="Bevel Weights")
col.prop(mesh, "show_edge_seams", text="Seams")
col.prop(mesh, "show_edge_sharp", text="Sharp")
+ if context.scene and bpy.app.build_options.freestyle:
+ col.prop(mesh, "show_freestyle_edge_marks", text="Freestyle Edge Marks")
+ col.prop(mesh, "show_freestyle_face_marks", text="Freestyle Face Marks")
col.separator()
col.label(text="Normals:")
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index 36b05fd31f4..ddfc7c06fb6 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -143,3 +143,11 @@ endif()
if(WITH_OPENCOLLADA)
add_subdirectory(collada)
endif()
+
+if(WITH_FREESTYLE)
+ list(APPEND SRC_DNA_INC
+ ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_linestyle_types.h
+ )
+ add_subdirectory(freestyle)
+endif()
+
diff --git a/source/blender/SConscript b/source/blender/SConscript
index 80457c739b6..e103aaf8bef 100644
--- a/source/blender/SConscript
+++ b/source/blender/SConscript
@@ -70,3 +70,6 @@ if env['WITH_BF_COLLADA']:
if env['WITH_BF_COMPOSITOR']:
SConscript (['compositor/SConscript',
'opencl/SConscript'])
+
+if env['WITH_BF_FREESTYLE']:
+ SConscript (['freestyle/SConscript'])
diff --git a/source/blender/blenfont/BLF_translation.h b/source/blender/blenfont/BLF_translation.h
index 35ca5f19bdc..5b2c4e87165 100644
--- a/source/blender/blenfont/BLF_translation.h
+++ b/source/blender/blenfont/BLF_translation.h
@@ -126,6 +126,9 @@ const char *BLF_translate_do_tooltip(const char *msgctxt, const char *msgid);
#define BLF_I18NCONTEXT_ID_BRUSH "Brush"
#define BLF_I18NCONTEXT_ID_CAMERA "Camera"
#define BLF_I18NCONTEXT_ID_CURVE "Curve"
+#ifdef WITH_FREESTYLE
+# define BLF_I18NCONTEXT_ID_FREESTYLELINESTYLE "FreestyleLineStyle"
+#endif
#define BLF_I18NCONTEXT_ID_GPENCIL "GPencil"
#define BLF_I18NCONTEXT_ID_GROUP "Group"
#define BLF_I18NCONTEXT_ID_ID "ID"
diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt
index 7bb80c34323..42298133d7d 100644
--- a/source/blender/blenfont/CMakeLists.txt
+++ b/source/blender/blenfont/CMakeLists.txt
@@ -59,6 +59,10 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
add_definitions(-DGLEW_STATIC)
blender_add_lib(bf_blenfont "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/blenfont/SConscript b/source/blender/blenfont/SConscript
index 3529330a308..8273ddf1e40 100644
--- a/source/blender/blenfont/SConscript
+++ b/source/blender/blenfont/SConscript
@@ -43,4 +43,7 @@ if sys.platform == 'win32' or env['OURPLATFORM'] == 'linuxcross':
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+
env.BlenderLib ( 'bf_blenfont', sources, Split(incs), defines=defs, libtype=['core','player'], priority=[210,210] )
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 5458568433d..5d8b6983aad 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -132,10 +132,12 @@ enum {
G_DEBUG_EVENTS = (1 << 3), /* input/window/screen events */
G_DEBUG_HANDLERS = (1 << 4), /* events handling */
G_DEBUG_WM = (1 << 5), /* operator, undo */
- G_DEBUG_JOBS = (1 << 6) /* jobs time profiling */
+ G_DEBUG_JOBS = (1 << 6), /* jobs time profiling */
+ G_DEBUG_FREESTYLE = (1 << 7), /* freestyle messages */
};
-#define G_DEBUG_ALL (G_DEBUG | G_DEBUG_FFMPEG | G_DEBUG_PYTHON | G_DEBUG_EVENTS | G_DEBUG_WM | G_DEBUG_JOBS)
+#define G_DEBUG_ALL (G_DEBUG | G_DEBUG_FFMPEG | G_DEBUG_PYTHON | G_DEBUG_EVENTS | G_DEBUG_WM | G_DEBUG_JOBS | \
+ G_DEBUG_FREESTYLE)
/* G.fileflags */
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
new file mode 100644
index 00000000000..e077cd998c9
--- /dev/null
+++ b/source/blender/blenkernel/BKE_linestyle.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 __BKE_LINESTYLE_H__
+#define __BKE_LINESTYLE_H__
+
+/** \file BKE_linestyle.h
+ * \ingroup bke
+ * \brief Blender kernel freestyle line style functionality.
+ */
+
+#ifdef WITH_FREESTYLE
+
+#include "DNA_linestyle_types.h"
+
+#define LS_MODIFIER_TYPE_COLOR 1
+#define LS_MODIFIER_TYPE_ALPHA 2
+#define LS_MODIFIER_TYPE_THICKNESS 3
+#define LS_MODIFIER_TYPE_GEOMETRY 4
+
+struct Main;
+struct Object;
+
+FreestyleLineStyle *FRS_new_linestyle(const char *name, struct Main *main);
+void FRS_free_linestyle(FreestyleLineStyle *linestyle);
+FreestyleLineStyle *FRS_copy_linestyle(FreestyleLineStyle *linestyle);
+
+LineStyleModifier *FRS_add_linestyle_color_modifier(FreestyleLineStyle *linestyle, int type);
+LineStyleModifier *FRS_add_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, int type);
+LineStyleModifier *FRS_add_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, int type);
+LineStyleModifier *FRS_add_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, int type);
+
+LineStyleModifier *FRS_copy_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m);
+LineStyleModifier *FRS_copy_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m);
+LineStyleModifier *FRS_copy_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m);
+LineStyleModifier *FRS_copy_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m);
+
+void FRS_remove_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
+void FRS_remove_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
+void FRS_remove_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
+void FRS_remove_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
+
+void FRS_move_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+void FRS_move_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+void FRS_move_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+void FRS_move_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+
+void FRS_list_modifier_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase);
+char *FRS_path_from_ID_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand *color_ramp);
+
+void FRS_unlink_linestyle_target_object(FreestyleLineStyle *linestyle, struct Object *ob);
+
+#endif /* WITH_FREESTYLE */
+
+#endif /* __BKE_LINESTYLE_H__ */
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 8e4d370e8a0..7c36ff07da5 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -88,6 +88,9 @@ typedef struct Main {
ListBase gpencil;
ListBase movieclip;
ListBase mask;
+#ifdef WITH_FREESTYLE
+ ListBase linestyle;
+#endif
char id_tag_update[256];
} Main;
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index fefd4c89fbe..2eeecefe231 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -152,7 +152,7 @@ set(SRC
intern/world.c
intern/writeavi.c
intern/writeframeserver.c
-
+
BKE_DerivedMesh.h
BKE_action.h
BKE_addon.h
@@ -424,6 +424,17 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_FREESTYLE)
+ list(APPEND SRC
+ intern/linestyle.c
+ BKE_linestyle.h
+ )
+ list(APPEND INC
+ ../freestyle
+ )
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
## Warnings as errors, this is too strict!
#if(MSVC)
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index e53e4724071..bcdf37da104 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -148,6 +148,12 @@ if env['WITH_BF_FFTW3']:
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+ incs += ' ../freestyle'
+else:
+ sources.remove(os.path.join('intern', 'linestyle.c'))
+
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 40b883e3f4e..aecf6e5e437 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -86,6 +86,9 @@ short id_type_can_have_animdata(ID *id)
case ID_PA:
case ID_MA: case ID_TE: case ID_NT:
case ID_LA: case ID_CA: case ID_WO:
+#ifdef WITH_FREESTYLE
+ case ID_LS:
+#endif
case ID_SPK:
case ID_SCE:
case ID_MC:
@@ -827,7 +830,12 @@ void BKE_animdata_main_cb(Main *mainptr, ID_AnimData_Edit_Callback func, void *u
/* scenes */
ANIMDATA_NODETREE_IDS_CB(mainptr->scene.first, Scene);
-}
+
+#ifdef WITH_FREESTYLE
+ /* line styles */
+ ANIMDATA_IDS_CB(mainptr->linestyle.first);
+#endif
+ }
/* Fix all RNA-Paths throughout the database (directly access the Global.main version)
* NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
@@ -912,6 +920,11 @@ void BKE_all_animdata_fix_paths_rename(ID *ref_id, const char *prefix, const cha
/* worlds */
RENAMEFIX_ANIM_NODETREE_IDS(mainptr->world.first, World);
+#ifdef WITH_FREESTYLE
+ /* linestyles */
+ RENAMEFIX_ANIM_IDS(mainptr->linestyle.first);
+#endif
+
/* scenes */
RENAMEFIX_ANIM_NODETREE_IDS(mainptr->scene.first, Scene);
}
@@ -2397,6 +2410,11 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime)
/* movie clips */
EVAL_ANIM_IDS(main->movieclip.first, ADT_RECALC_ANIM);
+#ifdef WITH_FREESTYLE
+ /* linestyles */
+ EVAL_ANIM_IDS(main->linestyle.first, ADT_RECALC_ANIM);
+#endif
+
/* objects */
/* ADT_RECALC_ANIM doesn't need to be supplied here, since object AnimData gets
* this tagged by Depsgraph on framechange. This optimization means that objects
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index b0021050e8f..624e86d5787 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -70,6 +70,9 @@
#include "DNA_vfont_types.h"
#include "DNA_scene_types.h"
#include "DNA_smoke_types.h"
+#ifdef WITH_FREESTYLE
+# include "DNA_freestyle_types.h"
+#endif
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -579,6 +582,18 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
}
SEQ_END
}
+#ifdef WITH_FREESTYLE
+ {
+ SceneRenderLayer *srl = scene->r.layers.first;
+
+ for(; srl; srl = srl->next) {
+ FreestyleModuleConfig* module = srl->freestyleConfig.modules.first;
+ for (; module; module = module->next) {
+ rewrite_path_fixed(module->module_path, visit_cb, absbase, bpath_user_data);
+ }
+ }
+ }
+#endif
break;
}
case ID_ME:
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index 20d874e7243..fda7dfb046e 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -103,6 +103,16 @@ void BKE_group_unlink(Group *group)
for (srl = sce->r.layers.first; srl; srl = srl->next) {
if (srl->light_override == group)
srl->light_override = NULL;
+
+#ifdef WITH_FREESTYLE
+ {
+ FreestyleLineSet *lineset;
+ for(lineset = srl->freestyleConfig.linesets.first; lineset; lineset= lineset->next) {
+ if (lineset->group == group)
+ lineset->group = NULL;
+ }
+ }
+#endif
}
}
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index c3008d17bd1..8fab0f2d4df 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -62,6 +62,9 @@ static IDType idtypes[] = {
{ ID_KE, "Key", "shape_keys", 0 },
{ ID_LA, "Lamp", "lamps", IDTYPE_FLAGS_ISLINKABLE },
{ ID_LI, "Library", "libraries", 0 },
+#ifdef WITH_FREESTYLE
+ { ID_LS, "FreestyleLineStyle", "linestyles", IDTYPE_FLAGS_ISLINKABLE },
+#endif
{ ID_LT, "Lattice", "lattices", IDTYPE_FLAGS_ISLINKABLE },
{ ID_MA, "Material", "materials", IDTYPE_FLAGS_ISLINKABLE },
{ ID_MB, "Metaball", "metaballs", IDTYPE_FLAGS_ISLINKABLE },
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 817068ae41e..610237abcdd 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -110,6 +110,9 @@
#include "BKE_text.h"
#include "BKE_texture.h"
#include "BKE_world.h"
+#ifdef WITH_FREESTYLE
+# include "BKE_linestyle.h"
+#endif
#include "RNA_access.h"
@@ -276,6 +279,10 @@ int id_make_local(ID *id, int test)
return 0; /* can't be linked */
case ID_GD:
return 0; /* not implemented */
+#ifdef WITH_FREESTYLE
+ case ID_LS:
+ return 0; /* not implemented */
+#endif
}
return 0;
@@ -370,6 +377,11 @@ int id_copy(ID *id, ID **newid, int test)
case ID_MSK:
if (!test) *newid = (ID *)BKE_mask_copy((Mask *)id);
return 1;
+#ifdef WITH_FREESTYLE
+ case ID_LS:
+ if(!test) *newid= (ID*)FRS_copy_linestyle((FreestyleLineStyle*)id);
+ return 1;
+#endif
}
return 0;
@@ -500,6 +512,10 @@ ListBase *which_libbase(Main *mainlib, short type)
return &(mainlib->movieclip);
case ID_MSK:
return &(mainlib->mask);
+#ifdef WITH_FREESTYLE
+ case ID_LS:
+ return &(mainlib->linestyle);
+#endif
}
return NULL;
}
@@ -584,6 +600,9 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[a++] = &(main->wm);
lb[a++] = &(main->movieclip);
lb[a++] = &(main->mask);
+#ifdef WITH_FREESTYLE
+ lb[a++] = &(main->linestyle);
+#endif
lb[a] = NULL;
@@ -698,6 +717,11 @@ static ID *alloc_libblock_notest(short type)
case ID_MSK:
id = MEM_callocN(sizeof(Mask), "Mask");
break;
+#ifdef WITH_FREESTYLE
+ case ID_LS:
+ id = MEM_callocN(sizeof(FreestyleLineStyle), "Freestyle Line Style");
+ break;
+#endif
}
return id;
}
@@ -923,6 +947,11 @@ void BKE_libblock_free(ListBase *lb, void *idv)
case ID_MSK:
BKE_mask_free(bmain, (Mask *)id);
break;
+#ifdef WITH_FREESTYLE
+ case ID_LS:
+ FRS_free_linestyle((FreestyleLineStyle *)id);
+ break;
+#endif
}
BLI_remlink(lb, id);
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
new file mode 100644
index 00000000000..aa9200adef4
--- /dev/null
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -0,0 +1,1022 @@
+/*
+ * ***** 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/blenkernel/intern/linestyle.c
+ * \ingroup bke
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_object_types.h"
+#include "DNA_material_types.h" /* for ramp blend */
+#include "DNA_texture_types.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_linestyle.h"
+#include "BKE_main.h"
+#include "BKE_texture.h"
+#include "BKE_colortools.h"
+#include "BKE_animsys.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+
+static const char *modifier_name[LS_MODIFIER_NUM] = {
+ NULL,
+ "Along Stroke",
+ "Distance from Camera",
+ "Distance from Object",
+ "Material",
+ "Sampling",
+ "Bezier Curve",
+ "Sinus Displacement",
+ "Spatial Noise",
+ "Perlin Noise 1D",
+ "Perlin Noise 2D",
+ "Backbone Stretcher",
+ "Tip Remover",
+ "Calligraphy",
+ "Polygonalization",
+ "Guiding Lines",
+ "Blueprint",
+ "2D Offset",
+ "2D Transform",
+};
+
+static void default_linestyle_settings(FreestyleLineStyle *linestyle)
+{
+ linestyle->panel = LS_PANEL_STROKES;
+ linestyle->r = linestyle->g = linestyle->b = 0.0f;
+ linestyle->alpha = 1.0f;
+ linestyle->thickness = 1.0f;
+ linestyle->thickness_position = LS_THICKNESS_CENTER;
+ linestyle->thickness_ratio = 0.5f;
+ linestyle->chaining = LS_CHAINING_PLAIN;
+ linestyle->rounds = 3;
+ linestyle->min_angle = DEG2RADF(0.0f);
+ linestyle->max_angle = DEG2RADF(0.0f);
+ linestyle->min_length = 0.0f;
+ linestyle->max_length = 10000.0f;
+ linestyle->split_length = 100;
+
+ linestyle->color_modifiers.first = linestyle->color_modifiers.last = NULL;
+ linestyle->alpha_modifiers.first = linestyle->alpha_modifiers.last = NULL;
+ linestyle->thickness_modifiers.first = linestyle->thickness_modifiers.last = NULL;
+ linestyle->geometry_modifiers.first = linestyle->geometry_modifiers.last = NULL;
+
+ FRS_add_linestyle_geometry_modifier(linestyle, LS_MODIFIER_SAMPLING);
+
+ linestyle->caps = LS_CAPS_BUTT;
+}
+
+FreestyleLineStyle *FRS_new_linestyle(const char *name, struct Main *main)
+{
+ FreestyleLineStyle *linestyle;
+
+ if (!main)
+ main = G.main;
+
+ linestyle = (FreestyleLineStyle *)BKE_libblock_alloc(&main->linestyle, ID_LS, name);
+
+ default_linestyle_settings(linestyle);
+
+ return linestyle;
+}
+
+void FRS_free_linestyle(FreestyleLineStyle *linestyle)
+{
+ LineStyleModifier *m;
+
+ BKE_free_animdata(&linestyle->id);
+ while ((m = (LineStyleModifier *)linestyle->color_modifiers.first))
+ FRS_remove_linestyle_color_modifier(linestyle, m);
+ while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first))
+ FRS_remove_linestyle_alpha_modifier(linestyle, m);
+ while ((m = (LineStyleModifier *)linestyle->thickness_modifiers.first))
+ FRS_remove_linestyle_thickness_modifier(linestyle, m);
+ while ((m = (LineStyleModifier *)linestyle->geometry_modifiers.first))
+ FRS_remove_linestyle_geometry_modifier(linestyle, m);
+}
+
+FreestyleLineStyle *FRS_copy_linestyle(FreestyleLineStyle *linestyle)
+{
+ FreestyleLineStyle *new_linestyle;
+ LineStyleModifier *m;
+
+ new_linestyle = FRS_new_linestyle(linestyle->id.name + 2, NULL);
+ FRS_free_linestyle(new_linestyle);
+
+ new_linestyle->r = linestyle->r;
+ new_linestyle->g = linestyle->g;
+ new_linestyle->b = linestyle->b;
+ new_linestyle->alpha = linestyle->alpha;
+ new_linestyle->thickness = linestyle->thickness;
+ new_linestyle->thickness_position = linestyle->thickness_position;
+ new_linestyle->thickness_ratio = linestyle->thickness_ratio;
+ new_linestyle->flag = linestyle->flag;
+ new_linestyle->caps = linestyle->caps;
+ new_linestyle->chaining = linestyle->chaining;
+ new_linestyle->rounds = linestyle->rounds;
+ new_linestyle->min_angle = linestyle->min_angle;
+ new_linestyle->max_angle = linestyle->max_angle;
+ new_linestyle->min_length = linestyle->min_length;
+ new_linestyle->max_length = linestyle->max_length;
+ new_linestyle->split_length = linestyle->split_length;
+ new_linestyle->dash1 = linestyle->dash1;
+ new_linestyle->gap1 = linestyle->gap1;
+ new_linestyle->dash2 = linestyle->dash2;
+ new_linestyle->gap2 = linestyle->gap2;
+ new_linestyle->dash3 = linestyle->dash3;
+ new_linestyle->gap3 = linestyle->gap3;
+ new_linestyle->panel = linestyle->panel;
+ for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next)
+ FRS_copy_linestyle_color_modifier(new_linestyle, m);
+ for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next)
+ FRS_copy_linestyle_alpha_modifier(new_linestyle, m);
+ for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next)
+ FRS_copy_linestyle_thickness_modifier(new_linestyle, m);
+ for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next)
+ FRS_copy_linestyle_geometry_modifier(new_linestyle, m);
+
+ return new_linestyle;
+}
+
+static LineStyleModifier *new_modifier(int type, size_t size)
+{
+ LineStyleModifier *m;
+
+ m = (LineStyleModifier *)MEM_callocN(size, "line style modifier");
+ if (m) {
+ m->type = type;
+ strcpy(m->name, modifier_name[type]);
+ m->influence = 1.0f;
+ m->flags = LS_MODIFIER_ENABLED | LS_MODIFIER_EXPANDED;
+ }
+
+ return m;
+}
+
+static void add_to_modifier_list(ListBase *lb, LineStyleModifier *m)
+{
+ BLI_addtail(lb, (void *)m);
+ BLI_uniquename(lb, m, modifier_name[m->type], '.', offsetof(LineStyleModifier, name), sizeof(m->name));
+}
+
+static LineStyleModifier *alloc_color_modifier(int type)
+{
+ size_t size;
+
+ switch (type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ size = sizeof(LineStyleColorModifier_AlongStroke);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ size = sizeof(LineStyleColorModifier_DistanceFromCamera);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ size = sizeof(LineStyleColorModifier_DistanceFromObject);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ size = sizeof(LineStyleColorModifier_Material);
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+
+ return new_modifier(type, size);
+}
+
+LineStyleModifier *FRS_add_linestyle_color_modifier(FreestyleLineStyle *linestyle, int type)
+{
+ LineStyleModifier *m;
+
+ m = alloc_color_modifier(type);
+ if (!m)
+ return NULL;
+ m->blend = MA_RAMP_BLEND;
+
+ switch (type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ ((LineStyleColorModifier_AlongStroke *)m)->color_ramp = add_colorband(1);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp = add_colorband(1);
+ ((LineStyleColorModifier_DistanceFromCamera *)m)->range_min = 0.0f;
+ ((LineStyleColorModifier_DistanceFromCamera *)m)->range_max = 10000.0f;
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ ((LineStyleColorModifier_DistanceFromObject *)m)->target = NULL;
+ ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp = add_colorband(1);
+ ((LineStyleColorModifier_DistanceFromObject *)m)->range_min = 0.0f;
+ ((LineStyleColorModifier_DistanceFromObject *)m)->range_max = 10000.0f;
+ break;
+ case LS_MODIFIER_MATERIAL:
+ ((LineStyleColorModifier_Material *)m)->color_ramp = add_colorband(1);
+ ((LineStyleColorModifier_Material *)m)->mat_attr = LS_MODIFIER_MATERIAL_DIFF;
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->color_modifiers, m);
+
+ return m;
+}
+
+LineStyleModifier *FRS_copy_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+{
+ LineStyleModifier *new_m;
+
+ new_m = alloc_color_modifier(m->type);
+ if (!new_m)
+ return NULL;
+ new_m->influence = m->influence;
+ new_m->flags = m->flags;
+ new_m->blend = m->blend;
+
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ {
+ LineStyleColorModifier_AlongStroke *p = (LineStyleColorModifier_AlongStroke *)m;
+ ((LineStyleColorModifier_AlongStroke *)new_m)->color_ramp = MEM_dupallocN(p->color_ramp);
+ }
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ {
+ LineStyleColorModifier_DistanceFromCamera *p = (LineStyleColorModifier_DistanceFromCamera *)m;
+ ((LineStyleColorModifier_DistanceFromCamera *)new_m)->color_ramp = MEM_dupallocN(p->color_ramp);
+ ((LineStyleColorModifier_DistanceFromCamera *)new_m)->range_min = p->range_min;
+ ((LineStyleColorModifier_DistanceFromCamera *)new_m)->range_max = p->range_max;
+ }
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ {
+ LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)m;
+ if (p->target)
+ p->target->id.us++;
+ ((LineStyleColorModifier_DistanceFromObject *)new_m)->target = p->target;
+ ((LineStyleColorModifier_DistanceFromObject *)new_m)->color_ramp = MEM_dupallocN(p->color_ramp);
+ ((LineStyleColorModifier_DistanceFromObject *)new_m)->range_min = p->range_min;
+ ((LineStyleColorModifier_DistanceFromObject *)new_m)->range_max = p->range_max;
+ }
+ break;
+ case LS_MODIFIER_MATERIAL:
+ {
+ LineStyleColorModifier_Material *p = (LineStyleColorModifier_Material *)m;
+ ((LineStyleColorModifier_Material *)new_m)->color_ramp = MEM_dupallocN(p->color_ramp);
+ ((LineStyleColorModifier_Material *)new_m)->mat_attr = p->mat_attr;
+ }
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->color_modifiers, new_m);
+
+ return new_m;
+}
+
+void FRS_remove_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+{
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ MEM_freeN(((LineStyleColorModifier_AlongStroke *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ MEM_freeN(((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ MEM_freeN(((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ MEM_freeN(((LineStyleColorModifier_Material *)m)->color_ramp);
+ break;
+ }
+ BLI_freelinkN(&linestyle->color_modifiers, m);
+}
+
+static LineStyleModifier *alloc_alpha_modifier(int type)
+{
+ size_t size;
+
+ switch (type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ size = sizeof(LineStyleAlphaModifier_AlongStroke);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ size = sizeof(LineStyleAlphaModifier_DistanceFromCamera);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ size = sizeof(LineStyleAlphaModifier_DistanceFromObject);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ size = sizeof(LineStyleAlphaModifier_Material);
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ return new_modifier(type, size);
+}
+
+LineStyleModifier *FRS_add_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, int type)
+{
+ LineStyleModifier *m;
+
+ m = alloc_alpha_modifier(type);
+ if (!m)
+ return NULL;
+ m->blend = LS_VALUE_BLEND;
+
+ switch (type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ ((LineStyleAlphaModifier_AlongStroke *)m)->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ ((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ ((LineStyleAlphaModifier_DistanceFromCamera *)m)->range_min = 0.0f;
+ ((LineStyleAlphaModifier_DistanceFromCamera *)m)->range_max = 10000.0f;
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ ((LineStyleAlphaModifier_DistanceFromObject *)m)->target = NULL;
+ ((LineStyleAlphaModifier_DistanceFromObject *)m)->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ ((LineStyleAlphaModifier_DistanceFromObject *)m)->range_min = 0.0f;
+ ((LineStyleAlphaModifier_DistanceFromObject *)m)->range_max = 10000.0f;
+ break;
+ case LS_MODIFIER_MATERIAL:
+ ((LineStyleAlphaModifier_Material *)m)->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ ((LineStyleAlphaModifier_Material *)m)->mat_attr = LS_MODIFIER_MATERIAL_DIFF;
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->alpha_modifiers, m);
+
+ return m;
+}
+
+LineStyleModifier *FRS_copy_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+{
+ LineStyleModifier *new_m;
+
+ new_m = alloc_alpha_modifier(m->type);
+ if (!new_m)
+ return NULL;
+ new_m->influence = m->influence;
+ new_m->flags = m->flags;
+ new_m->blend = m->blend;
+
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ {
+ LineStyleAlphaModifier_AlongStroke *p = (LineStyleAlphaModifier_AlongStroke *)m;
+ ((LineStyleAlphaModifier_AlongStroke *)new_m)->curve = curvemapping_copy(p->curve);
+ }
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ {
+ LineStyleAlphaModifier_DistanceFromCamera *p = (LineStyleAlphaModifier_DistanceFromCamera *)m;
+ ((LineStyleAlphaModifier_DistanceFromCamera *)new_m)->curve = curvemapping_copy(p->curve);
+ ((LineStyleAlphaModifier_DistanceFromCamera *)new_m)->range_min = p->range_min;
+ ((LineStyleAlphaModifier_DistanceFromCamera *)new_m)->range_max = p->range_max;
+ }
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ {
+ LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)m;
+ if (p->target)
+ p->target->id.us++;
+ ((LineStyleAlphaModifier_DistanceFromObject *)new_m)->target = p->target;
+ ((LineStyleAlphaModifier_DistanceFromObject *)new_m)->curve = curvemapping_copy(p->curve);
+ ((LineStyleAlphaModifier_DistanceFromObject *)new_m)->range_min = p->range_min;
+ ((LineStyleAlphaModifier_DistanceFromObject *)new_m)->range_max = p->range_max;
+ }
+ break;
+ case LS_MODIFIER_MATERIAL:
+ {
+ LineStyleAlphaModifier_Material *p = (LineStyleAlphaModifier_Material *)m;
+ ((LineStyleAlphaModifier_Material *)new_m)->curve = curvemapping_copy(p->curve);
+ ((LineStyleAlphaModifier_Material *)new_m)->mat_attr = p->mat_attr;
+ }
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->alpha_modifiers, new_m);
+
+ return new_m;
+}
+
+void FRS_remove_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+{
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ curvemapping_free(((LineStyleAlphaModifier_AlongStroke *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ curvemapping_free(((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ curvemapping_free(((LineStyleAlphaModifier_DistanceFromObject *)m)->curve);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ curvemapping_free(((LineStyleAlphaModifier_Material *)m)->curve);
+ break;
+ }
+ BLI_freelinkN(&linestyle->alpha_modifiers, m);
+}
+
+static LineStyleModifier *alloc_thickness_modifier(int type)
+{
+ size_t size;
+
+ switch (type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ size = sizeof(LineStyleThicknessModifier_AlongStroke);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ size = sizeof(LineStyleThicknessModifier_DistanceFromCamera);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ size = sizeof(LineStyleThicknessModifier_DistanceFromObject);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ size = sizeof(LineStyleThicknessModifier_Material);
+ break;
+ case LS_MODIFIER_CALLIGRAPHY:
+ size = sizeof(LineStyleThicknessModifier_Calligraphy);
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+
+ return new_modifier(type, size);
+}
+
+LineStyleModifier *FRS_add_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, int type)
+{
+ LineStyleModifier *m;
+
+ m = alloc_thickness_modifier(type);
+ if (!m)
+ return NULL;
+ m->blend = LS_VALUE_BLEND;
+
+ switch (type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ ((LineStyleThicknessModifier_AlongStroke *)m)->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ ((LineStyleThicknessModifier_AlongStroke *)m)->value_min = 0.0f;
+ ((LineStyleThicknessModifier_AlongStroke *)m)->value_max = 1.0f;
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ ((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ ((LineStyleThicknessModifier_DistanceFromCamera *)m)->range_min = 0.0f;
+ ((LineStyleThicknessModifier_DistanceFromCamera *)m)->range_max = 1000.0f;
+ ((LineStyleThicknessModifier_DistanceFromCamera *)m)->value_min = 0.0f;
+ ((LineStyleThicknessModifier_DistanceFromCamera *)m)->value_max = 1.0f;
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ ((LineStyleThicknessModifier_DistanceFromObject *)m)->target = NULL;
+ ((LineStyleThicknessModifier_DistanceFromObject *)m)->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ ((LineStyleThicknessModifier_DistanceFromObject *)m)->range_min = 0.0f;
+ ((LineStyleThicknessModifier_DistanceFromObject *)m)->range_max = 1000.0f;
+ ((LineStyleThicknessModifier_DistanceFromObject *)m)->value_min = 0.0f;
+ ((LineStyleThicknessModifier_DistanceFromObject *)m)->value_max = 1.0f;
+ break;
+ case LS_MODIFIER_MATERIAL:
+ ((LineStyleThicknessModifier_Material *)m)->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ ((LineStyleThicknessModifier_Material *)m)->mat_attr = LS_MODIFIER_MATERIAL_DIFF;
+ ((LineStyleThicknessModifier_Material *)m)->value_min = 0.0f;
+ ((LineStyleThicknessModifier_Material *)m)->value_max = 1.0f;
+ break;
+ case LS_MODIFIER_CALLIGRAPHY:
+ ((LineStyleThicknessModifier_Calligraphy *)m)->min_thickness = 1.0f;
+ ((LineStyleThicknessModifier_Calligraphy *)m)->max_thickness = 10.0f;
+ ((LineStyleThicknessModifier_Calligraphy *)m)->orientation = DEG2RADF(60.0f);
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->thickness_modifiers, m);
+
+ return m;
+}
+
+LineStyleModifier *FRS_copy_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+{
+ LineStyleModifier *new_m;
+
+ new_m = alloc_thickness_modifier(m->type);
+ if (!new_m)
+ return NULL;
+ new_m->influence = m->influence;
+ new_m->flags = m->flags;
+ new_m->blend = m->blend;
+
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ {
+ LineStyleThicknessModifier_AlongStroke *p = (LineStyleThicknessModifier_AlongStroke *)m;
+ ((LineStyleThicknessModifier_AlongStroke *)new_m)->curve = curvemapping_copy(p->curve);
+ ((LineStyleThicknessModifier_AlongStroke *)new_m)->value_min = p->value_min;
+ ((LineStyleThicknessModifier_AlongStroke *)new_m)->value_max = p->value_max;
+ }
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ {
+ LineStyleThicknessModifier_DistanceFromCamera *p = (LineStyleThicknessModifier_DistanceFromCamera *)m;
+ ((LineStyleThicknessModifier_DistanceFromCamera *)new_m)->curve = curvemapping_copy(p->curve);
+ ((LineStyleThicknessModifier_DistanceFromCamera *)new_m)->range_min = p->range_min;
+ ((LineStyleThicknessModifier_DistanceFromCamera *)new_m)->range_max = p->range_max;
+ ((LineStyleThicknessModifier_DistanceFromCamera *)new_m)->value_min = p->value_min;
+ ((LineStyleThicknessModifier_DistanceFromCamera *)new_m)->value_max = p->value_max;
+ }
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ {
+ LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)m;
+ if (p->target)
+ p->target->id.us++;
+ ((LineStyleThicknessModifier_DistanceFromObject *)new_m)->target = p->target;
+ ((LineStyleThicknessModifier_DistanceFromObject *)new_m)->curve = curvemapping_copy(p->curve);
+ ((LineStyleThicknessModifier_DistanceFromObject *)new_m)->range_min = p->range_min;
+ ((LineStyleThicknessModifier_DistanceFromObject *)new_m)->range_max = p->range_max;
+ ((LineStyleThicknessModifier_DistanceFromObject *)new_m)->value_min = p->value_min;
+ ((LineStyleThicknessModifier_DistanceFromObject *)new_m)->value_max = p->value_max;
+ }
+ break;
+ case LS_MODIFIER_MATERIAL:
+ {
+ LineStyleThicknessModifier_Material *p = (LineStyleThicknessModifier_Material *)m;
+ ((LineStyleThicknessModifier_Material *)new_m)->curve = curvemapping_copy(p->curve);
+ ((LineStyleThicknessModifier_Material *)new_m)->mat_attr = p->mat_attr;
+ ((LineStyleThicknessModifier_Material *)new_m)->value_min = p->value_min;
+ ((LineStyleThicknessModifier_Material *)new_m)->value_max = p->value_max;
+ }
+ break;
+ case LS_MODIFIER_CALLIGRAPHY:
+ {
+ LineStyleThicknessModifier_Calligraphy *p = (LineStyleThicknessModifier_Calligraphy *)m;
+ ((LineStyleThicknessModifier_Calligraphy *)new_m)->min_thickness = p->min_thickness;
+ ((LineStyleThicknessModifier_Calligraphy *)new_m)->max_thickness = p->max_thickness;
+ ((LineStyleThicknessModifier_Calligraphy *)new_m)->orientation = p->orientation;
+ }
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->thickness_modifiers, new_m);
+
+ return new_m;
+}
+
+void FRS_remove_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+{
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ curvemapping_free(((LineStyleThicknessModifier_AlongStroke *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ curvemapping_free(((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ curvemapping_free(((LineStyleThicknessModifier_DistanceFromObject *)m)->curve);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ curvemapping_free(((LineStyleThicknessModifier_Material *)m)->curve);
+ break;
+ case LS_MODIFIER_CALLIGRAPHY:
+ break;
+ }
+ BLI_freelinkN(&linestyle->thickness_modifiers, m);
+}
+
+static LineStyleModifier *alloc_geometry_modifier(int type)
+{
+ size_t size;
+
+ switch (type) {
+ case LS_MODIFIER_SAMPLING:
+ size = sizeof(LineStyleGeometryModifier_Sampling);
+ break;
+ case LS_MODIFIER_BEZIER_CURVE:
+ size = sizeof(LineStyleGeometryModifier_BezierCurve);
+ break;
+ case LS_MODIFIER_SINUS_DISPLACEMENT:
+ size = sizeof(LineStyleGeometryModifier_SinusDisplacement);
+ break;
+ case LS_MODIFIER_SPATIAL_NOISE:
+ size = sizeof(LineStyleGeometryModifier_SpatialNoise);
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_1D:
+ size = sizeof(LineStyleGeometryModifier_PerlinNoise1D);
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_2D:
+ size = sizeof(LineStyleGeometryModifier_PerlinNoise2D);
+ break;
+ case LS_MODIFIER_BACKBONE_STRETCHER:
+ size = sizeof(LineStyleGeometryModifier_BackboneStretcher);
+ break;
+ case LS_MODIFIER_TIP_REMOVER:
+ size = sizeof(LineStyleGeometryModifier_TipRemover);
+ break;
+ case LS_MODIFIER_POLYGONIZATION:
+ size = sizeof(LineStyleGeometryModifier_Polygonalization);
+ break;
+ case LS_MODIFIER_GUIDING_LINES:
+ size = sizeof(LineStyleGeometryModifier_GuidingLines);
+ break;
+ case LS_MODIFIER_BLUEPRINT:
+ size = sizeof(LineStyleGeometryModifier_Blueprint);
+ break;
+ case LS_MODIFIER_2D_OFFSET:
+ size = sizeof(LineStyleGeometryModifier_2DOffset);
+ break;
+ case LS_MODIFIER_2D_TRANSFORM:
+ size = sizeof(LineStyleGeometryModifier_2DTransform);
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+
+ return new_modifier(type, size);
+}
+
+LineStyleModifier *FRS_add_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, int type)
+{
+ LineStyleModifier *m;
+
+ m = alloc_geometry_modifier(type);
+ if (!m)
+ return NULL;
+
+ switch (type) {
+ case LS_MODIFIER_SAMPLING:
+ ((LineStyleGeometryModifier_Sampling *)m)->sampling = 10.0f;
+ break;
+ case LS_MODIFIER_BEZIER_CURVE:
+ ((LineStyleGeometryModifier_BezierCurve *)m)->error = 10.0f;
+ break;
+ case LS_MODIFIER_SINUS_DISPLACEMENT:
+ ((LineStyleGeometryModifier_SinusDisplacement *)m)->wavelength = 20.0f;
+ ((LineStyleGeometryModifier_SinusDisplacement *)m)->amplitude = 5.0f;
+ ((LineStyleGeometryModifier_SinusDisplacement *)m)->phase = 0.0f;
+ break;
+ case LS_MODIFIER_SPATIAL_NOISE:
+ ((LineStyleGeometryModifier_SpatialNoise *)m)->amplitude = 5.0f;
+ ((LineStyleGeometryModifier_SpatialNoise *)m)->scale = 20.0f;
+ ((LineStyleGeometryModifier_SpatialNoise *)m)->octaves = 4;
+ ((LineStyleGeometryModifier_SpatialNoise *)m)->flags = LS_MODIFIER_SPATIAL_NOISE_SMOOTH | LS_MODIFIER_SPATIAL_NOISE_PURERANDOM;
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_1D:
+ ((LineStyleGeometryModifier_PerlinNoise1D *)m)->frequency = 10.0f;
+ ((LineStyleGeometryModifier_PerlinNoise1D *)m)->amplitude = 10.0f;
+ ((LineStyleGeometryModifier_PerlinNoise1D *)m)->octaves = 4;
+ ((LineStyleGeometryModifier_PerlinNoise1D *)m)->angle = DEG2RADF(45.0f);
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_2D:
+ ((LineStyleGeometryModifier_PerlinNoise2D *)m)->frequency = 10.0f;
+ ((LineStyleGeometryModifier_PerlinNoise2D *)m)->amplitude = 10.0f;
+ ((LineStyleGeometryModifier_PerlinNoise2D *)m)->octaves = 4;
+ ((LineStyleGeometryModifier_PerlinNoise2D *)m)->angle = DEG2RADF(45.0f);
+ break;
+ case LS_MODIFIER_BACKBONE_STRETCHER:
+ ((LineStyleGeometryModifier_BackboneStretcher *)m)->backbone_length = 10.0f;
+ break;
+ case LS_MODIFIER_TIP_REMOVER:
+ ((LineStyleGeometryModifier_TipRemover *)m)->tip_length = 10.0f;
+ break;
+ case LS_MODIFIER_POLYGONIZATION:
+ ((LineStyleGeometryModifier_Polygonalization *)m)->error = 10.0f;
+ break;
+ case LS_MODIFIER_GUIDING_LINES:
+ ((LineStyleGeometryModifier_GuidingLines *)m)->offset = 0.0f;
+ break;
+ case LS_MODIFIER_BLUEPRINT:
+ ((LineStyleGeometryModifier_Blueprint *)m)->flags = LS_MODIFIER_BLUEPRINT_CIRCLES;
+ ((LineStyleGeometryModifier_Blueprint *)m)->rounds = 1;
+ ((LineStyleGeometryModifier_Blueprint *)m)->backbone_length = 10.0f;
+ ((LineStyleGeometryModifier_Blueprint *)m)->random_radius = 3;
+ ((LineStyleGeometryModifier_Blueprint *)m)->random_center = 5;
+ ((LineStyleGeometryModifier_Blueprint *)m)->random_backbone = 5;
+ break;
+ case LS_MODIFIER_2D_OFFSET:
+ ((LineStyleGeometryModifier_2DOffset *)m)->start = 0.0f;
+ ((LineStyleGeometryModifier_2DOffset *)m)->end = 0.0f;
+ ((LineStyleGeometryModifier_2DOffset *)m)->x = 0.0f;
+ ((LineStyleGeometryModifier_2DOffset *)m)->y = 0.0f;
+ break;
+ case LS_MODIFIER_2D_TRANSFORM:
+ ((LineStyleGeometryModifier_2DTransform *)m)->pivot = LS_MODIFIER_2D_TRANSFORM_PIVOT_CENTER;
+ ((LineStyleGeometryModifier_2DTransform *)m)->scale_x = 1.0f;
+ ((LineStyleGeometryModifier_2DTransform *)m)->scale_y = 1.0f;
+ ((LineStyleGeometryModifier_2DTransform *)m)->angle = DEG2RADF(0.0f);
+ ((LineStyleGeometryModifier_2DTransform *)m)->pivot_u = 0.5f;
+ ((LineStyleGeometryModifier_2DTransform *)m)->pivot_x = 0.0f;
+ ((LineStyleGeometryModifier_2DTransform *)m)->pivot_y = 0.0f;
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->geometry_modifiers, m);
+
+ return m;
+}
+
+LineStyleModifier *FRS_copy_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+{
+ LineStyleModifier *new_m;
+
+ new_m = alloc_geometry_modifier(m->type);
+ if (!new_m)
+ return NULL;
+ new_m->flags = m->flags;
+
+ switch (m->type) {
+ case LS_MODIFIER_SAMPLING:
+ {
+ LineStyleGeometryModifier_Sampling *p = (LineStyleGeometryModifier_Sampling *)m;
+ ((LineStyleGeometryModifier_Sampling *)new_m)->sampling = p->sampling;
+ }
+ break;
+ case LS_MODIFIER_BEZIER_CURVE:
+ {
+ LineStyleGeometryModifier_BezierCurve *p = (LineStyleGeometryModifier_BezierCurve *)m;
+ ((LineStyleGeometryModifier_BezierCurve *)new_m)->error = p->error;
+ }
+ break;
+ case LS_MODIFIER_SINUS_DISPLACEMENT:
+ {
+ LineStyleGeometryModifier_SinusDisplacement *p = (LineStyleGeometryModifier_SinusDisplacement *)m;
+ ((LineStyleGeometryModifier_SinusDisplacement *)new_m)->wavelength = p->wavelength;
+ ((LineStyleGeometryModifier_SinusDisplacement *)new_m)->amplitude = p->amplitude;
+ ((LineStyleGeometryModifier_SinusDisplacement *)new_m)->phase = p->phase;
+ }
+ break;
+ case LS_MODIFIER_SPATIAL_NOISE:
+ {
+ LineStyleGeometryModifier_SpatialNoise *p = (LineStyleGeometryModifier_SpatialNoise *)m;
+ ((LineStyleGeometryModifier_SpatialNoise *)new_m)->amplitude = p->amplitude;
+ ((LineStyleGeometryModifier_SpatialNoise *)new_m)->scale = p->scale;
+ ((LineStyleGeometryModifier_SpatialNoise *)new_m)->octaves = p->octaves;
+ ((LineStyleGeometryModifier_SpatialNoise *)new_m)->flags = p->flags;
+ }
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_1D:
+ {
+ LineStyleGeometryModifier_PerlinNoise1D *p = (LineStyleGeometryModifier_PerlinNoise1D *)m;
+ ((LineStyleGeometryModifier_PerlinNoise1D *)new_m)->frequency = p->frequency;
+ ((LineStyleGeometryModifier_PerlinNoise1D *)new_m)->amplitude = p->amplitude;
+ ((LineStyleGeometryModifier_PerlinNoise1D *)new_m)->octaves = p->octaves;
+ ((LineStyleGeometryModifier_PerlinNoise1D *)new_m)->angle = p->angle;
+ }
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_2D:
+ {
+ LineStyleGeometryModifier_PerlinNoise2D *p = (LineStyleGeometryModifier_PerlinNoise2D *)m;
+ ((LineStyleGeometryModifier_PerlinNoise2D *)new_m)->frequency = p->frequency;
+ ((LineStyleGeometryModifier_PerlinNoise2D *)new_m)->amplitude = p->amplitude;
+ ((LineStyleGeometryModifier_PerlinNoise2D *)new_m)->octaves = p->octaves;
+ ((LineStyleGeometryModifier_PerlinNoise2D *)new_m)->angle = p->angle;
+ }
+ break;
+ case LS_MODIFIER_BACKBONE_STRETCHER:
+ {
+ LineStyleGeometryModifier_BackboneStretcher *p = (LineStyleGeometryModifier_BackboneStretcher *)m;
+ ((LineStyleGeometryModifier_BackboneStretcher *)new_m)->backbone_length = p->backbone_length;
+ }
+ break;
+ case LS_MODIFIER_TIP_REMOVER:
+ {
+ LineStyleGeometryModifier_TipRemover *p = (LineStyleGeometryModifier_TipRemover *)m;
+ ((LineStyleGeometryModifier_TipRemover *)new_m)->tip_length = p->tip_length;
+ }
+ break;
+ case LS_MODIFIER_POLYGONIZATION:
+ {
+ LineStyleGeometryModifier_Polygonalization *p = (LineStyleGeometryModifier_Polygonalization *)m;
+ ((LineStyleGeometryModifier_Polygonalization *)new_m)->error = p->error;
+ }
+ break;
+ case LS_MODIFIER_GUIDING_LINES:
+ {
+ LineStyleGeometryModifier_GuidingLines *p = (LineStyleGeometryModifier_GuidingLines *)m;
+ ((LineStyleGeometryModifier_GuidingLines *)new_m)->offset = p->offset;
+ }
+ break;
+ case LS_MODIFIER_BLUEPRINT:
+ {
+ LineStyleGeometryModifier_Blueprint *p = (LineStyleGeometryModifier_Blueprint *)m;
+ ((LineStyleGeometryModifier_Blueprint *)new_m)->flags = p->flags;
+ ((LineStyleGeometryModifier_Blueprint *)new_m)->rounds = p->rounds;
+ ((LineStyleGeometryModifier_Blueprint *)new_m)->backbone_length = p->backbone_length;
+ ((LineStyleGeometryModifier_Blueprint *)new_m)->random_radius = p->random_radius;
+ ((LineStyleGeometryModifier_Blueprint *)new_m)->random_center = p->random_center;
+ ((LineStyleGeometryModifier_Blueprint *)new_m)->random_backbone = p->random_backbone;
+ }
+ break;
+ case LS_MODIFIER_2D_OFFSET:
+ {
+ LineStyleGeometryModifier_2DOffset *p = (LineStyleGeometryModifier_2DOffset *)m;
+ ((LineStyleGeometryModifier_2DOffset *)new_m)->start = p->start;
+ ((LineStyleGeometryModifier_2DOffset *)new_m)->end = p->end;
+ ((LineStyleGeometryModifier_2DOffset *)new_m)->x = p->x;
+ ((LineStyleGeometryModifier_2DOffset *)new_m)->y = p->y;
+ }
+ break;
+ case LS_MODIFIER_2D_TRANSFORM:
+ {
+ LineStyleGeometryModifier_2DTransform *p = (LineStyleGeometryModifier_2DTransform *)m;
+ ((LineStyleGeometryModifier_2DTransform *)new_m)->pivot = p->pivot;
+ ((LineStyleGeometryModifier_2DTransform *)new_m)->scale_x = p->scale_x;
+ ((LineStyleGeometryModifier_2DTransform *)new_m)->scale_y = p->scale_y;
+ ((LineStyleGeometryModifier_2DTransform *)new_m)->angle = p->angle;
+ ((LineStyleGeometryModifier_2DTransform *)new_m)->pivot_u = p->pivot_u;
+ ((LineStyleGeometryModifier_2DTransform *)new_m)->pivot_x = p->pivot_x;
+ ((LineStyleGeometryModifier_2DTransform *)new_m)->pivot_y = p->pivot_y;
+ }
+ break;
+ default:
+ return NULL; /* unknown modifier type */
+ }
+ add_to_modifier_list(&linestyle->geometry_modifiers, new_m);
+
+ return new_m;
+}
+
+void FRS_remove_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+{
+ switch (m->type) {
+ case LS_MODIFIER_SAMPLING:
+ break;
+ case LS_MODIFIER_BEZIER_CURVE:
+ break;
+ case LS_MODIFIER_SINUS_DISPLACEMENT:
+ break;
+ case LS_MODIFIER_SPATIAL_NOISE:
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_1D:
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_2D:
+ break;
+ case LS_MODIFIER_BACKBONE_STRETCHER:
+ break;
+ case LS_MODIFIER_TIP_REMOVER:
+ break;
+ case LS_MODIFIER_POLYGONIZATION:
+ break;
+ case LS_MODIFIER_GUIDING_LINES:
+ break;
+ case LS_MODIFIER_BLUEPRINT:
+ break;
+ case LS_MODIFIER_2D_OFFSET:
+ break;
+ case LS_MODIFIER_2D_TRANSFORM:
+ break;
+ }
+ BLI_freelinkN(&linestyle->geometry_modifiers, m);
+}
+
+static void move_modifier(ListBase *lb, LineStyleModifier *modifier, int direction)
+{
+ BLI_remlink(lb, modifier);
+ if (direction > 0)
+ BLI_insertlinkbefore(lb, modifier->prev, modifier);
+ else
+ BLI_insertlinkafter(lb, modifier->next, modifier);
+}
+
+void FRS_move_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+{
+ move_modifier(&linestyle->color_modifiers, modifier, direction);
+}
+
+void FRS_move_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+{
+ move_modifier(&linestyle->alpha_modifiers, modifier, direction);
+}
+
+void FRS_move_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+{
+ move_modifier(&linestyle->thickness_modifiers, modifier, direction);
+}
+
+void FRS_move_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+{
+ move_modifier(&linestyle->geometry_modifiers, modifier, direction);
+}
+
+void FRS_list_modifier_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase)
+{
+ LineStyleModifier *m;
+ ColorBand *color_ramp;
+ LinkData *link;
+
+ listbase->first = listbase->last = NULL;
+ for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) {
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ color_ramp = ((LineStyleColorModifier_AlongStroke *)m)->color_ramp;
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ color_ramp = ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp;
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ color_ramp = ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp;
+ break;
+ case LS_MODIFIER_MATERIAL:
+ color_ramp = ((LineStyleColorModifier_Material *)m)->color_ramp;
+ break;
+ default:
+ continue;
+ }
+ link = (LinkData *) MEM_callocN( sizeof(LinkData), "link to color ramp");
+ link->data = color_ramp;
+ BLI_addtail(listbase, link);
+ }
+}
+
+/* XXX Do we want to keep that goto? Or use a boolean var? */
+char *FRS_path_from_ID_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand *color_ramp)
+{
+ LineStyleModifier *m;
+
+ for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) {
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ if (color_ramp == ((LineStyleColorModifier_AlongStroke *)m)->color_ramp)
+ goto found;
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ if (color_ramp == ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp)
+ goto found;
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ if (color_ramp == ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp)
+ goto found;
+ break;
+ case LS_MODIFIER_MATERIAL:
+ if (color_ramp == ((LineStyleColorModifier_Material *)m)->color_ramp)
+ goto found;
+ break;
+ }
+ }
+ printf("FRS_path_from_ID_to_color_ramp: No color ramps correspond to the given pointer.\n");
+ return NULL;
+
+found:
+ return BLI_sprintfN("color_modifiers[\"%s\"].color_ramp", m->name);
+}
+
+void FRS_unlink_linestyle_target_object(FreestyleLineStyle *linestyle, struct Object *ob)
+{
+ LineStyleModifier *m;
+
+ for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) {
+ if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ if (((LineStyleColorModifier_DistanceFromObject *)m)->target == ob) {
+ ((LineStyleColorModifier_DistanceFromObject *)m)->target = NULL;
+ }
+ }
+ }
+ for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next) {
+ if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ if (((LineStyleAlphaModifier_DistanceFromObject *)m)->target == ob) {
+ ((LineStyleAlphaModifier_DistanceFromObject *)m)->target = NULL;
+ }
+ }
+ }
+ for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next) {
+ if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ if (((LineStyleThicknessModifier_DistanceFromObject *)m)->target == ob) {
+ ((LineStyleThicknessModifier_DistanceFromObject *)m)->target = NULL;
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index f19dc93198d..ad0a149a42c 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -153,6 +153,9 @@ void init_material(Material *ma)
ma->tx_limit = 0.0;
ma->tx_falloff = 1.0;
ma->shad_alpha = 1.0f;
+#ifdef WITH_FREESTYLE
+ ma->vcol_alpha = 0;
+#endif
ma->gloss_mir = ma->gloss_tra = 1.0;
ma->samp_gloss_mir = ma->samp_gloss_tra = 18;
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index b5e82586f5a..8a6309593f1 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -117,6 +117,10 @@
#include "GPU_material.h"
+#ifdef WITH_FREESTYLE
+# include "FRS_freestyle.h"
+#endif
+
/* Local function protos */
float originmat[3][3]; /* after BKE_object_where_is_calc(), can be used in other functions (bad!) */
@@ -669,6 +673,16 @@ void BKE_object_unlink(Object *ob)
}
SEQ_END
}
+
+#ifdef WITH_FREESTYLE
+ {
+ SceneRenderLayer *srl;
+
+ for (srl= sce->r.layers.first; srl; srl= srl->next) {
+ FRS_unlink_target_object(&srl->freestyleConfig, ob);
+ }
+ }
+#endif
}
sce = sce->id.next;
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 9e8cf985f71..285646191f7 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -87,6 +87,10 @@
//XXX #include "BIF_previewrender.h"
//XXX #include "BIF_editseq.h"
+#ifdef WITH_FREESTYLE
+# include "FRS_freestyle_config.h"
+#endif
+
#ifdef WIN32
#else
#include <sys/time.h>
@@ -331,6 +335,16 @@ void BKE_scene_free(Scene *sce)
sce->r.ffcodecdata.properties = NULL;
}
+#ifdef WITH_FREESTYLE
+ {
+ SceneRenderLayer *srl;
+
+ for (srl = sce->r.layers.first; srl; srl = srl->next) {
+ FRS_free_freestyle_config(srl);
+ }
+ }
+#endif
+
BLI_freelistN(&sce->markers);
BLI_freelistN(&sce->transform_spaces);
BLI_freelistN(&sce->r.layers);
@@ -1252,6 +1266,9 @@ SceneRenderLayer *BKE_scene_add_render_layer(Scene *sce, const char *name)
srl->lay = (1 << 20) - 1;
srl->layflag = 0x7FFF; /* solid ztra halo edge strand */
srl->passflag = SCE_PASS_COMBINED | SCE_PASS_Z;
+#ifdef WITH_FREESTYLE
+ FRS_add_freestyle_config(srl);
+#endif
return srl;
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 2e10407bee8..ce6e158b6d9 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -964,7 +964,11 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
edgeFlag = (ccgdm->edgeFlags) ? &ccgdm->edgeFlags[i] : NULL;
if (edgeFlag)
+#ifdef WITH_FREESTYLE
+ flags |= (*edgeFlag & (ME_SEAM | ME_SHARP | ME_FREESTYLE_EDGE)) | ME_EDGEDRAW | ME_EDGERENDER;
+#else
flags |= (*edgeFlag & (ME_SEAM | ME_SHARP)) | ME_EDGEDRAW | ME_EDGERENDER;
+#endif
else
flags |= ME_EDGEDRAW | ME_EDGERENDER;
@@ -1015,7 +1019,7 @@ static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf)
}
else {
mf->flag = ME_SMOOTH;
- }
+}
mf->edcode = 0;
}
@@ -1232,7 +1236,11 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
if (edgeFlags) {
if (edgeIdx != -1) {
+#ifdef WITH_FREESTYLE
+ ed_flag |= ((edgeFlags[index] & (ME_SEAM | ME_SHARP | ME_FREESTYLE_EDGE)) | ME_EDGEDRAW | ME_EDGERENDER);
+#else
ed_flag |= ((edgeFlags[index] & (ME_SEAM | ME_SHARP)) | ME_EDGEDRAW | ME_EDGERENDER);
+#endif
}
}
else {
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index e5851109d87..82ff09b5999 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -165,6 +165,10 @@ if(WITH_OPENMP)
add_definitions(-DPARALLEL=1)
endif()
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
if(WIN32)
list(APPEND INC
../../../intern/utfconv
diff --git a/source/blender/blenlib/SConscript b/source/blender/blenlib/SConscript
index 2be06f7311d..19216442aa0 100644
--- a/source/blender/blenlib/SConscript
+++ b/source/blender/blenlib/SConscript
@@ -37,6 +37,9 @@ incs += ' ' + env['BF_FREETYPE_INC']
incs += ' ' + env['BF_ZLIB_INC']
defs = []
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+
if env['WITH_BF_BINRELOC']:
cflags='-pthread'
incs += ' ../../../extern/binreloc/include'
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 5b929195aea..b55d6b679d2 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -66,4 +66,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
blender_add_lib(bf_blenloader "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/blenloader/SConscript b/source/blender/blenloader/SConscript
index 8950c4f7702..f85ae8c112b 100644
--- a/source/blender/blenloader/SConscript
+++ b/source/blender/blenloader/SConscript
@@ -40,6 +40,9 @@ defs = []
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
env.BlenderLib ( 'bf_blenloader', sources, Split(incs), defs, libtype=['core','player'], priority = [167,30]) #, cc_compileflags=['/WX'] )
else:
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 070cb4676a1..fdf23458c76 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -70,6 +70,9 @@
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
#include "DNA_lamp_types.h"
+#ifdef WITH_FREESTYLE
+# include "DNA_linestyle_types.h"
+#endif
#include "DNA_meta_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
@@ -1070,10 +1073,10 @@ FileData *blo_openblendermemory(void *mem, int memsize, ReportList *reports)
}
}
else
- fd->read = fd_read_from_memory;
+ fd->read = fd_read_from_memory;
fd->flags |= FD_FLAGS_NOT_MY_BUFFER;
-
+
return blo_decode_and_check(fd, reports);
}
}
@@ -1203,19 +1206,19 @@ static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */
return oldnewmap_lookup_and_inc(fd->datamap, adr);
}
-static void *newglobadr(FileData *fd, void *adr) /* direct datablocks with global linking */
+static void *newglobadr(FileData *fd, void *adr) /* direct datablocks with global linking */
{
return oldnewmap_lookup_and_inc(fd->globmap, adr);
}
-static void *newimaadr(FileData *fd, void *adr) /* used to restore image data after undo */
+static void *newimaadr(FileData *fd, void *adr) /* used to restore image data after undo */
{
if (fd->imamap && adr)
return oldnewmap_lookup_and_inc(fd->imamap, adr);
return NULL;
}
-static void *newmclipadr(FileData *fd, void *adr) /* used to restore movie clip data after undo */
+static void *newmclipadr(FileData *fd, void *adr) /* used to restore movie clip data after undo */
{
if (fd->movieclipmap && adr)
return oldnewmap_lookup_and_inc(fd->movieclipmap, adr);
@@ -1226,7 +1229,7 @@ static void *newpackedadr(FileData *fd, void *adr) /* used to restore packe
{
if (fd->packedmap && adr)
return oldnewmap_lookup_and_inc(fd->packedmap, adr);
-
+
return oldnewmap_lookup_and_inc(fd->datamap, adr);
}
@@ -3331,7 +3334,7 @@ static void direct_link_texture(FileData *fd, Tex *tex)
tex->env = newdataadr(fd, tex->env);
if (tex->env) {
tex->env->ima = NULL;
- memset(tex->env->cube, 0, 6 * sizeof(void *));
+ memset(tex->env->cube, 0, 6*sizeof(void *));
tex->env->ok= 0;
}
tex->pd = newdataadr(fd, tex->pd);
@@ -5043,6 +5046,16 @@ static void lib_link_scene(FileData *fd, Main *main)
for (srl = sce->r.layers.first; srl; srl = srl->next) {
srl->mat_override = newlibadr_us(fd, sce->id.lib, srl->mat_override);
srl->light_override = newlibadr_us(fd, sce->id.lib, srl->light_override);
+#ifdef WITH_FREESTYLE
+ {
+ FreestyleLineSet *fls;
+
+ for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
+ fls->linestyle = newlibadr_us(fd, sce->id.lib, fls->linestyle);
+ fls->group = newlibadr_us(fd, sce->id.lib, fls->group);
+ }
+ }
+#endif
}
/*Game Settings: Dome Warp Text*/
sce->gm.dome.warptext = newlibadr(fd, sce->id.lib, sce->gm.dome.warptext);
@@ -5150,7 +5163,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
if (sce->toolsettings->vpaint) {
sce->toolsettings->vpaint->vpaint_prev = NULL;
sce->toolsettings->vpaint->tot = 0;
- }
+ }
if (sce->toolsettings->wpaint) {
sce->toolsettings->wpaint->wpaint_prev = NULL;
sce->toolsettings->wpaint->tot = 0;
@@ -5290,6 +5303,19 @@ static void direct_link_scene(FileData *fd, Scene *sce)
link_list(fd, &(sce->markers));
link_list(fd, &(sce->transform_spaces));
link_list(fd, &(sce->r.layers));
+
+#ifdef WITH_FREESTYLE
+ {
+ SceneRenderLayer *srl;
+
+ for(srl = sce->r.layers.first; srl; srl = srl->next) {
+ link_list(fd, &(srl->freestyleConfig.modules));
+ }
+ for(srl = sce->r.layers.first; srl; srl = srl->next) {
+ link_list(fd, &(srl->freestyleConfig.linesets));
+ }
+ }
+#endif
sce->nodetree = newdataadr(fd, sce->nodetree);
if (sce->nodetree) {
@@ -5902,7 +5928,7 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
pa->activedata = NULL;
pa->type = NULL;
}
-
+
link_list(fd, &ar->ui_lists);
for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) {
@@ -6213,7 +6239,7 @@ static void direct_link_screen(FileData *fd, bScreen *sc)
sclip->scopes.track_preview = NULL;
sclip->draw_context = NULL;
sclip->scopes.ok = 0;
- }
+ }
}
sa->actionzones.first = sa->actionzones.last = NULL;
@@ -6581,6 +6607,181 @@ static void lib_link_mask(FileData *fd, Main *main)
}
}
+#ifdef WITH_FREESTYLE
+/* ************ READ LINE STYLE ***************** */
+
+static void lib_link_linestyle(FileData *fd, Main *main)
+{
+ FreestyleLineStyle *linestyle;
+ LineStyleModifier *m;
+
+ linestyle = main->linestyle.first;
+ while (linestyle) {
+ if (linestyle->id.flag & LIB_NEED_LINK) {
+ linestyle->id.flag -= LIB_NEED_LINK;
+
+ if (linestyle->id.properties)
+ IDP_LibLinkProperty(linestyle->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ if (linestyle->adt)
+ lib_link_animdata(fd, &linestyle->id, linestyle->adt);
+ for (m = linestyle->color_modifiers.first; m; m = m->next) {
+ switch (m->type) {
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ {
+ LineStyleColorModifier_DistanceFromObject *cm = (LineStyleColorModifier_DistanceFromObject *)m;
+ cm->target = newlibadr(fd, linestyle->id.lib, cm->target);
+ }
+ break;
+ }
+ }
+ for (m = linestyle->alpha_modifiers.first; m; m = m->next){
+ switch (m->type) {
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ {
+ LineStyleAlphaModifier_DistanceFromObject *am = (LineStyleAlphaModifier_DistanceFromObject *)m;
+ am->target = newlibadr(fd, linestyle->id.lib, am->target);
+ }
+ break;
+ }
+ }
+ for (m = linestyle->thickness_modifiers.first; m; m = m->next){
+ switch (m->type) {
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ {
+ LineStyleThicknessModifier_DistanceFromObject *tm = (LineStyleThicknessModifier_DistanceFromObject *)m;
+ tm->target = newlibadr(fd, linestyle->id.lib, tm->target);
+ }
+ break;
+ }
+ }
+ }
+ linestyle = linestyle->id.next;
+ }
+}
+
+static void direct_link_linestyle_color_modifier(FileData *fd, LineStyleModifier *modifier)
+{
+ switch (modifier->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ {
+ LineStyleColorModifier_AlongStroke *m = (LineStyleColorModifier_AlongStroke *)modifier;
+ m->color_ramp = newdataadr(fd, m->color_ramp);
+ }
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ {
+ LineStyleColorModifier_DistanceFromCamera *m = (LineStyleColorModifier_DistanceFromCamera *)modifier;
+ m->color_ramp = newdataadr(fd, m->color_ramp);
+ }
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ {
+ LineStyleColorModifier_DistanceFromObject *m = (LineStyleColorModifier_DistanceFromObject *)modifier;
+ m->color_ramp = newdataadr(fd, m->color_ramp);
+ }
+ break;
+ case LS_MODIFIER_MATERIAL:
+ {
+ LineStyleColorModifier_Material *m = (LineStyleColorModifier_Material *)modifier;
+ m->color_ramp = newdataadr(fd, m->color_ramp);
+ }
+ break;
+ }
+}
+
+static void direct_link_linestyle_alpha_modifier(FileData *fd, LineStyleModifier *modifier)
+{
+ switch (modifier->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ {
+ LineStyleAlphaModifier_AlongStroke *m = (LineStyleAlphaModifier_AlongStroke *)modifier;
+ m->curve = newdataadr(fd, m->curve);
+ direct_link_curvemapping(fd, m->curve);
+ }
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ {
+ LineStyleAlphaModifier_DistanceFromCamera *m = (LineStyleAlphaModifier_DistanceFromCamera *)modifier;
+ m->curve = newdataadr(fd, m->curve);
+ direct_link_curvemapping(fd, m->curve);
+ }
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ {
+ LineStyleAlphaModifier_DistanceFromObject *m = (LineStyleAlphaModifier_DistanceFromObject *)modifier;
+ m->curve = newdataadr(fd, m->curve);
+ direct_link_curvemapping(fd, m->curve);
+ }
+ break;
+ case LS_MODIFIER_MATERIAL:
+ {
+ LineStyleAlphaModifier_Material *m = (LineStyleAlphaModifier_Material *)modifier;
+ m->curve = newdataadr(fd, m->curve);
+ direct_link_curvemapping(fd, m->curve);
+ }
+ break;
+ }
+}
+
+static void direct_link_linestyle_thickness_modifier(FileData *fd, LineStyleModifier *modifier)
+{
+ switch (modifier->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ {
+ LineStyleThicknessModifier_AlongStroke *m = (LineStyleThicknessModifier_AlongStroke *)modifier;
+ m->curve = newdataadr(fd, m->curve);
+ direct_link_curvemapping(fd, m->curve);
+ }
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ {
+ LineStyleThicknessModifier_DistanceFromCamera *m = (LineStyleThicknessModifier_DistanceFromCamera *)modifier;
+ m->curve = newdataadr(fd, m->curve);
+ direct_link_curvemapping(fd, m->curve);
+ }
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ {
+ LineStyleThicknessModifier_DistanceFromObject *m = (LineStyleThicknessModifier_DistanceFromObject *)modifier;
+ m->curve = newdataadr(fd, m->curve);
+ direct_link_curvemapping(fd, m->curve);
+ }
+ break;
+ case LS_MODIFIER_MATERIAL:
+ {
+ LineStyleThicknessModifier_Material *m = (LineStyleThicknessModifier_Material *)modifier;
+ m->curve = newdataadr(fd, m->curve);
+ direct_link_curvemapping(fd, m->curve);
+ }
+ break;
+ }
+}
+
+static void direct_link_linestyle_geometry_modifier(FileData *UNUSED(fd), LineStyleModifier *UNUSED(modifier))
+{
+}
+
+static void direct_link_linestyle(FileData *fd, FreestyleLineStyle *linestyle)
+{
+ LineStyleModifier *modifier;
+
+ linestyle->adt= newdataadr(fd, linestyle->adt);
+ direct_link_animdata(fd, linestyle->adt);
+ link_list(fd, &linestyle->color_modifiers);
+ for(modifier = linestyle->color_modifiers.first; modifier; modifier = modifier->next)
+ direct_link_linestyle_color_modifier(fd, modifier);
+ link_list(fd, &linestyle->alpha_modifiers);
+ for(modifier = linestyle->alpha_modifiers.first; modifier; modifier = modifier->next)
+ direct_link_linestyle_alpha_modifier(fd, modifier);
+ link_list(fd, &linestyle->thickness_modifiers);
+ for(modifier = linestyle->thickness_modifiers.first; modifier; modifier = modifier->next)
+ direct_link_linestyle_thickness_modifier(fd, modifier);
+ link_list(fd, &linestyle->geometry_modifiers);
+ for(modifier = linestyle->geometry_modifiers.first; modifier; modifier = modifier->next)
+ direct_link_linestyle_geometry_modifier(fd, modifier);
+}
+#endif
+
/* ************** GENERAL & MAIN ******************** */
@@ -6615,6 +6816,9 @@ static const char *dataname(short id_code)
case ID_PA: return "Data from PA";
case ID_GD: return "Data from GD";
case ID_MC: return "Data from MC";
+#ifdef WITH_FREESTYLE
+ case ID_LS: return "Data from LS";
+#endif
}
return "Data from Lib Block";
@@ -6791,6 +6995,11 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
case ID_MSK:
direct_link_mask(fd, (Mask *)id);
break;
+#ifdef WITH_FREESTYLE
+ case ID_LS:
+ direct_link_linestyle(fd, (FreestyleLineStyle *)id);
+ break;
+#endif
}
oldnewmap_free_unused(fd->datamap);
@@ -6923,7 +7132,7 @@ static void do_versions_nodetree_convert_angle(bNodeTree *ntree)
/* Convert degrees to radians. */
NodeDefocus *nqd = node->storage;
/* XXX DNA char to float conversion seems to map the char value into the [0.0f, 1.0f] range... */
- nqd->rotation = DEG2RADF(nqd->rotation * 255.0f);
+ nqd->rotation = DEG2RADF(nqd->rotation*255.0f);
}
else if (node->type == CMP_NODE_CHROMA_MATTE) {
/* Convert degrees to radians. */
@@ -6935,7 +7144,7 @@ static void do_versions_nodetree_convert_angle(bNodeTree *ntree)
/* Convert degrees to radians. */
NodeGlare *ndg = node->storage;
/* XXX DNA char to float conversion seems to map the char value into the [0.0f, 1.0f] range... */
- ndg->angle_ofs = DEG2RADF(ndg->angle_ofs * 255.0f);
+ ndg->angle_ofs = DEG2RADF(ndg->angle_ofs*255.0f);
}
/* XXX TexMapping struct is used by other nodes too (at least node_composite_mapValue),
* but not the rot part...
@@ -8645,13 +8854,13 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
SEQ_END
if (scene->r.bake_samples == 0)
- scene->r.bake_samples = 256;
+ scene->r.bake_samples = 256;
}
for (image = main->image.first; image; image = image->id.next) {
if (image->flag & IMA_DO_PREMUL)
image->alpha_mode = IMA_ALPHA_STRAIGHT;
- }
+ }
for (tex = main->tex.first; tex; tex = tex->id.next) {
if (tex->type == TEX_IMAGE && (tex->imaflag & TEX_USEALPHA) == 0) {
@@ -8716,6 +8925,47 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
// if (main->versionfile < 265 || (main->versionfile == 265 && main->subversionfile < 7)) {
+#ifdef WITH_FREESTYLE
+ /* default values in Freestyle settings */
+ {
+ Scene *sce;
+ SceneRenderLayer *srl;
+ FreestyleLineStyle *linestyle;
+
+ for(sce = main->scene.first; sce; sce = sce->id.next) {
+ if (sce->r.line_thickness_mode == 0) {
+ sce->r.line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE;
+ sce->r.unit_line_thickness = 1.0f;
+ }
+ for(srl = sce->r.layers.first; srl; srl = srl->next) {
+ if (srl->freestyleConfig.mode == 0)
+ srl->freestyleConfig.mode = FREESTYLE_CONTROL_EDITOR_MODE;
+ if (srl->freestyleConfig.raycasting_algorithm == FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE ||
+ srl->freestyleConfig.raycasting_algorithm == FREESTYLE_ALGO_CULLED_ADAPTIVE_TRADITIONAL) {
+ srl->freestyleConfig.raycasting_algorithm = 0; /* deprecated */
+ srl->freestyleConfig.flags |= FREESTYLE_CULLING;
+ }
+ }
+ }
+ for(linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) {
+#if 1
+ /* disable the Misc panel for now */
+ if (linestyle->panel == LS_PANEL_MISC) {
+ linestyle->panel = LS_PANEL_STROKES;
+ }
+#endif
+ if (linestyle->thickness_position == 0) {
+ linestyle->thickness_position = LS_THICKNESS_CENTER;
+ linestyle->thickness_ratio = 0.5f;
+ }
+ if (linestyle->chaining == 0)
+ linestyle->chaining = LS_CHAINING_PLAIN;
+ if (linestyle->rounds == 0)
+ linestyle->rounds = 3;
+ }
+ }
+#endif
+
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */
@@ -8737,8 +8987,8 @@ static void lib_link_all(FileData *fd, Main *main)
/* No load UI for undo memfiles */
if (fd->memfile == NULL) {
- lib_link_windowmanager(fd, main);
- lib_link_screen(fd, main);
+ lib_link_windowmanager(fd, main);
+ lib_link_screen(fd, main);
}
lib_link_scene(fd, main);
lib_link_object(fd, main);
@@ -8765,6 +9015,9 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_particlesettings(fd, main);
lib_link_movieclip(fd, main);
lib_link_mask(fd, main);
+#ifdef WITH_FREESTYLE
+ lib_link_linestyle(fd, main);
+#endif
lib_link_mesh(fd, main); /* as last: tpage images with users at zero */
@@ -8824,7 +9077,7 @@ static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
for (kmi=keymap->items.first; kmi; kmi=kmi->next)
direct_link_keymapitem(fd, kmi);
}
-
+
for (addon = user->addons.first; addon; addon = addon->next) {
addon->prop = newdataadr(fd, addon->prop);
if (addon->prop) {
@@ -9044,7 +9297,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old)
return;
}
else
- id = is_yet_read(fd, ptr, bhead);
+ id = is_yet_read(fd, ptr, bhead);
if (id == NULL) {
read_libblock(fd, ptr, bhead, LIB_READ+LIB_INDIRECT, NULL);
@@ -9721,6 +9974,18 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
for (srl = sce->r.layers.first; srl; srl = srl->next) {
expand_doit(fd, mainvar, srl->mat_override);
expand_doit(fd, mainvar, srl->light_override);
+
+#ifdef WITH_FREESTYLE
+ {
+ FreestyleLineSet *lineset;
+
+ for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ if (lineset->group)
+ expand_doit(fd, mainvar, lineset->group);
+ expand_doit(fd, mainvar, lineset->linestyle);
+ }
+ }
+#endif
}
if (sce->r.dometext)
@@ -9819,6 +10084,28 @@ static void expand_mask(FileData *fd, Main *mainvar, Mask *mask)
}
}
+#ifdef WITH_FREESTYLE
+static void expand_linestyle(FileData *fd, Main *mainvar, FreestyleLineStyle *linestyle)
+{
+ LineStyleModifier *m;
+
+ if (linestyle->adt)
+ expand_animdata(fd, mainvar, linestyle->adt);
+ for (m = linestyle->color_modifiers.first; m; m = m->next) {
+ if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT)
+ expand_doit(fd, mainvar, ((LineStyleColorModifier_DistanceFromObject *)m)->target);
+ }
+ for (m = linestyle->alpha_modifiers.first; m; m = m->next){
+ if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT)
+ expand_doit(fd, mainvar, ((LineStyleAlphaModifier_DistanceFromObject *)m)->target);
+ }
+ for (m = linestyle->thickness_modifiers.first; m; m = m->next){
+ if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT)
+ expand_doit(fd, mainvar, ((LineStyleThicknessModifier_DistanceFromObject *)m)->target);
+ }
+}
+#endif
+
void BLO_main_expander(void (*expand_doit_func)(void *, Main *, void *))
{
expand_doit = expand_doit_func;
@@ -9909,6 +10196,11 @@ void BLO_expand_main(void *fdhandle, Main *mainvar)
case ID_MSK:
expand_mask(fd, mainvar, (Mask *)id);
break;
+#ifdef WITH_FREESTYLE
+ case ID_LS:
+ expand_linestyle(fd, mainvar, (FreestyleLineStyle *)id);
+ break;
+#endif
}
do_it = TRUE;
@@ -10329,9 +10621,9 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
BLI_strncpy(fd->relabase, mainptr->curlib->filepath, sizeof(fd->relabase));
}
else {
- BKE_reportf_wrap(basefd->reports, RPT_INFO, TIP_("Read library: '%s', '%s'"),
- mainptr->curlib->filepath, mainptr->curlib->name);
- fd = blo_openblenderfile(mainptr->curlib->filepath, basefd->reports);
+ BKE_reportf_wrap(basefd->reports, RPT_INFO, TIP_("Read library: '%s', '%s'"),
+ mainptr->curlib->filepath, mainptr->curlib->name);
+ fd = blo_openblenderfile(mainptr->curlib->filepath, basefd->reports);
}
/* allow typing in a new lib path */
if (G.debug_value == -666) {
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index e7a53670849..475d96fd709 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -108,6 +108,9 @@
#include "DNA_key_types.h"
#include "DNA_lattice_types.h"
#include "DNA_lamp_types.h"
+#ifdef WITH_FREESTYLE
+# include "DNA_linestyle_types.h"
+#endif
#include "DNA_meta_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -2296,8 +2299,25 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
for (ts = sce->transform_spaces.first; ts; ts = ts->next)
writestruct(wd, DATA, "TransformOrientation", 1, ts);
- for (srl= sce->r.layers.first; srl; srl= srl->next)
+ for (srl = sce->r.layers.first; srl; srl = srl->next) {
writestruct(wd, DATA, "SceneRenderLayer", 1, srl);
+
+#ifdef WITH_FREESTYLE
+ {
+ FreestyleModuleConfig *fmc;
+ FreestyleLineSet *fls;
+
+ for(fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
+ writestruct(wd, DATA, "FreestyleModuleConfig", 1, fmc);
+ }
+
+ for(fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
+ writestruct(wd, DATA, "FreestyleLineSet", 1, fls);
+ }
+
+ }
+#endif
+ }
if (sce->nodetree) {
writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree);
@@ -2902,6 +2922,209 @@ static void write_masks(WriteData *wd, ListBase *idbase)
mywrite(wd, MYWRITE_FLUSH, 0);
}
+#ifdef WITH_FREESTYLE
+static void write_linestyle_color_modifiers(WriteData *wd, ListBase *modifiers)
+{
+ LineStyleModifier *m;
+ const char *struct_name;
+
+ for (m = modifiers->first; m; m = m->next) {
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ struct_name = "LineStyleColorModifier_AlongStroke";
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ struct_name = "LineStyleColorModifier_DistanceFromCamera";
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ struct_name = "LineStyleColorModifier_DistanceFromObject";
+ break;
+ case LS_MODIFIER_MATERIAL:
+ struct_name = "LineStyleColorModifier_Material";
+ break;
+ default:
+ struct_name = "LineStyleColorModifier"; /* this should not happen */
+ }
+ writestruct(wd, DATA, struct_name, 1, m);
+ }
+ for (m = modifiers->first; m; m = m->next) {
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_AlongStroke *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Material *)m)->color_ramp);
+ break;
+ }
+ }
+}
+
+static void write_linestyle_alpha_modifiers(WriteData *wd, ListBase *modifiers)
+{
+ LineStyleModifier *m;
+ const char *struct_name;
+
+ for (m = modifiers->first; m; m = m->next) {
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ struct_name = "LineStyleAlphaModifier_AlongStroke";
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ struct_name = "LineStyleAlphaModifier_DistanceFromCamera";
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ struct_name = "LineStyleAlphaModifier_DistanceFromObject";
+ break;
+ case LS_MODIFIER_MATERIAL:
+ struct_name = "LineStyleAlphaModifier_Material";
+ break;
+ default:
+ struct_name = "LineStyleAlphaModifier"; /* this should not happen */
+ }
+ writestruct(wd, DATA, struct_name, 1, m);
+ }
+ for (m = modifiers->first; m; m = m->next) {
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_AlongStroke *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromObject *)m)->curve);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ write_curvemapping(wd, ((LineStyleAlphaModifier_Material *)m)->curve);
+ break;
+ }
+ }
+}
+
+static void write_linestyle_thickness_modifiers(WriteData *wd, ListBase *modifiers)
+{
+ LineStyleModifier *m;
+ const char *struct_name;
+
+ for (m = modifiers->first; m; m = m->next) {
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ struct_name = "LineStyleThicknessModifier_AlongStroke";
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ struct_name = "LineStyleThicknessModifier_DistanceFromCamera";
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ struct_name = "LineStyleThicknessModifier_DistanceFromObject";
+ break;
+ case LS_MODIFIER_MATERIAL:
+ struct_name = "LineStyleThicknessModifier_Material";
+ break;
+ case LS_MODIFIER_CALLIGRAPHY:
+ struct_name = "LineStyleThicknessModifier_Calligraphy";
+ break;
+ default:
+ struct_name = "LineStyleThicknessModifier"; /* this should not happen */
+ }
+ writestruct(wd, DATA, struct_name, 1, m);
+ }
+ for (m = modifiers->first; m; m = m->next) {
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_AlongStroke *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve);
+ break;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromObject *)m)->curve);
+ break;
+ case LS_MODIFIER_MATERIAL:
+ write_curvemapping(wd, ((LineStyleThicknessModifier_Material *)m)->curve);
+ break;
+ }
+ }
+}
+
+static void write_linestyle_geometry_modifiers(WriteData *wd, ListBase *modifiers)
+{
+ LineStyleModifier *m;
+ const char *struct_name;
+
+ for (m = modifiers->first; m; m = m->next) {
+ switch (m->type) {
+ case LS_MODIFIER_SAMPLING:
+ struct_name = "LineStyleGeometryModifier_Sampling";
+ break;
+ case LS_MODIFIER_BEZIER_CURVE:
+ struct_name = "LineStyleGeometryModifier_BezierCurve";
+ break;
+ case LS_MODIFIER_SINUS_DISPLACEMENT:
+ struct_name = "LineStyleGeometryModifier_SinusDisplacement";
+ break;
+ case LS_MODIFIER_SPATIAL_NOISE:
+ struct_name = "LineStyleGeometryModifier_SpatialNoise";
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_1D:
+ struct_name = "LineStyleGeometryModifier_PerlinNoise1D";
+ break;
+ case LS_MODIFIER_PERLIN_NOISE_2D:
+ struct_name = "LineStyleGeometryModifier_PerlinNoise2D";
+ break;
+ case LS_MODIFIER_BACKBONE_STRETCHER:
+ struct_name = "LineStyleGeometryModifier_BackboneStretcher";
+ break;
+ case LS_MODIFIER_TIP_REMOVER:
+ struct_name = "LineStyleGeometryModifier_TipRemover";
+ break;
+ case LS_MODIFIER_POLYGONIZATION:
+ struct_name = "LineStyleGeometryModifier_Polygonalization";
+ break;
+ case LS_MODIFIER_GUIDING_LINES:
+ struct_name = "LineStyleGeometryModifier_GuidingLines";
+ break;
+ case LS_MODIFIER_BLUEPRINT:
+ struct_name = "LineStyleGeometryModifier_Blueprint";
+ break;
+ case LS_MODIFIER_2D_OFFSET:
+ struct_name = "LineStyleGeometryModifier_2DOffset";
+ break;
+ case LS_MODIFIER_2D_TRANSFORM:
+ struct_name = "LineStyleGeometryModifier_2DTransform";
+ break;
+ default:
+ struct_name = "LineStyleGeometryModifier"; /* this should not happen */
+ }
+ writestruct(wd, DATA, struct_name, 1, m);
+ }
+}
+
+static void write_linestyles(WriteData *wd, ListBase *idbase)
+{
+ FreestyleLineStyle *linestyle;
+
+ for (linestyle = idbase->first; linestyle; linestyle = linestyle->id.next) {
+ if (linestyle->id.us>0 || wd->current) {
+ writestruct(wd, ID_LS, "FreestyleLineStyle", 1, linestyle);
+ if (linestyle->id.properties)
+ IDP_WriteProperty(linestyle->id.properties, wd);
+ if (linestyle->adt)
+ write_animdata(wd, linestyle->adt);
+ write_linestyle_color_modifiers(wd, &linestyle->color_modifiers);
+ write_linestyle_alpha_modifiers(wd, &linestyle->alpha_modifiers);
+ write_linestyle_thickness_modifiers(wd, &linestyle->thickness_modifiers);
+ write_linestyle_geometry_modifiers(wd, &linestyle->geometry_modifiers);
+ }
+ }
+}
+#endif
+
/* context is usually defined by WM, two cases where no WM is available:
* - for forward compatibility, curscreen has to be saved
* - for undofile, curscene needs to be saved */
@@ -3008,6 +3231,9 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil
write_brushes (wd, &mainvar->brush);
write_scripts (wd, &mainvar->script);
write_gpencils (wd, &mainvar->gpencil);
+#ifdef WITH_FREESTYLE
+ write_linestyles(wd, &mainvar->linestyle);
+#endif
write_libraries(wd, mainvar->next);
if (write_user_block) {
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 42a1a5e0f3e..d49686f204a 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -134,4 +134,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
blender_add_lib(bf_bmesh "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/bmesh/SConscript b/source/blender/bmesh/SConscript
index a8ca514297e..fa6bdbcf26f 100644
--- a/source/blender/bmesh/SConscript
+++ b/source/blender/bmesh/SConscript
@@ -53,4 +53,7 @@ if env['WITH_BF_BULLET']:
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+
env.BlenderLib ( libname = 'bf_bmesh', sources = sources, includes = Split(incs), libtype = ['core','player'], defines=defs, priority=[100, 100], compileflags=cflags )
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 4fa3a69356f..4461a7afdd7 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -246,6 +246,9 @@ enum {
/* spare tag, assumed dirty, use define in each function to name based on use */
// _BM_ELEM_TAG_ALT = (1 << 6), // UNUSED
+#ifdef WITH_FREESTYLE
+ BM_ELEM_FREESTYLE = (1 << 6), /* used for Freestyle faces and edges */
+#endif
BM_ELEM_INTERNAL_TAG = (1 << 7) /* for low level internal API tagging,
* since tools may want to tag verts and
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index fddb7b4bf2c..fa58ccd98bc 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -1002,18 +1002,28 @@ char BM_vert_flag_from_mflag(const char meflag)
}
char BM_edge_flag_from_mflag(const short meflag)
{
- return ( ((meflag & SELECT) ? BM_ELEM_SELECT : 0) |
- ((meflag & ME_SEAM) ? BM_ELEM_SEAM : 0) |
- ((meflag & ME_EDGEDRAW) ? BM_ELEM_DRAW : 0) |
- ((meflag & ME_SHARP) == 0 ? BM_ELEM_SMOOTH : 0) | /* invert */
- ((meflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0)
+ return ( ((meflag & SELECT) ? BM_ELEM_SELECT : 0) |
+ ((meflag & ME_SEAM) ? BM_ELEM_SEAM : 0) |
+ ((meflag & ME_EDGEDRAW) ? BM_ELEM_DRAW : 0) |
+ ((meflag & ME_SHARP) == 0 ? BM_ELEM_SMOOTH : 0) | /* invert */
+ ((meflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0) |
+#ifdef WITH_FREESTYLE
+ ((meflag & ME_FREESTYLE_EDGE) ? BM_ELEM_FREESTYLE : 0)
+#else
+ 0
+#endif
);
}
char BM_face_flag_from_mflag(const char meflag)
{
- return ( ((meflag & ME_FACE_SEL) ? BM_ELEM_SELECT : 0) |
- ((meflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0) |
- ((meflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0)
+ return ( ((meflag & ME_FACE_SEL) ? BM_ELEM_SELECT : 0) |
+ ((meflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0) |
+ ((meflag & ME_HIDE) ? BM_ELEM_HIDDEN : 0) |
+#ifdef WITH_FREESTYLE
+ ((meflag & ME_FREESTYLE_FACE) ? BM_ELEM_FREESTYLE : 0)
+#else
+ 0
+#endif
);
}
@@ -1031,12 +1041,15 @@ short BM_edge_flag_to_mflag(BMEdge *eed)
{
const char hflag = eed->head.hflag;
- return ( ((hflag & BM_ELEM_SELECT) ? SELECT : 0) |
- ((hflag & BM_ELEM_SEAM) ? ME_SEAM : 0) |
- ((hflag & BM_ELEM_DRAW) ? ME_EDGEDRAW : 0) |
- ((hflag & BM_ELEM_SMOOTH) == 0 ? ME_SHARP : 0) |
- ((hflag & BM_ELEM_HIDDEN) ? ME_HIDE : 0) |
- ((BM_edge_is_wire(eed)) ? ME_LOOSEEDGE : 0) | /* not typical */
+ return ( ((hflag & BM_ELEM_SELECT) ? SELECT : 0) |
+ ((hflag & BM_ELEM_SEAM) ? ME_SEAM : 0) |
+ ((hflag & BM_ELEM_DRAW) ? ME_EDGEDRAW : 0) |
+ ((hflag & BM_ELEM_SMOOTH) == 0 ? ME_SHARP : 0) |
+ ((hflag & BM_ELEM_HIDDEN) ? ME_HIDE : 0) |
+#ifdef WITH_FREESTYLE
+ ((hflag & BM_ELEM_FREESTYLE) ? ME_FREESTYLE_EDGE : 0) |
+#endif
+ ((BM_edge_is_wire(eed)) ? ME_LOOSEEDGE : 0) | /* not typical */
ME_EDGERENDER
);
}
@@ -1044,8 +1057,13 @@ char BM_face_flag_to_mflag(BMFace *efa)
{
const char hflag = efa->head.hflag;
- return ( ((hflag & BM_ELEM_SELECT) ? ME_FACE_SEL : 0) |
- ((hflag & BM_ELEM_SMOOTH) ? ME_SMOOTH : 0) |
- ((hflag & BM_ELEM_HIDDEN) ? ME_HIDE : 0)
+ return ( ((hflag & BM_ELEM_SELECT) ? ME_FACE_SEL : 0) |
+ ((hflag & BM_ELEM_SMOOTH) ? ME_SMOOTH : 0) |
+ ((hflag & BM_ELEM_HIDDEN) ? ME_HIDE : 0) |
+#ifdef WITH_FREESTYLE
+ ((hflag & BM_ELEM_FREESTYLE) ? ME_FREESTYLE_FACE : 0)
+#else
+ 0
+#endif
);
}
diff --git a/source/blender/bmesh/intern/bmesh_operators.h b/source/blender/bmesh/intern/bmesh_operators.h
index d02b0dce728..16b38c340ff 100644
--- a/source/blender/bmesh/intern/bmesh_operators.h
+++ b/source/blender/bmesh/intern/bmesh_operators.h
@@ -60,7 +60,10 @@ enum {
SIMFACE_SIDES,
SIMFACE_PERIMETER,
SIMFACE_NORMAL,
- SIMFACE_COPLANAR
+ SIMFACE_COPLANAR,
+#ifdef WITH_FREESTYLE
+ SIMFACE_FREESTYLE
+#endif
};
/* similar edge selection slot values */
@@ -72,7 +75,10 @@ enum {
SIMEDGE_CREASE,
SIMEDGE_BEVEL,
SIMEDGE_SEAM,
- SIMEDGE_SHARP
+ SIMEDGE_SHARP,
+#ifdef WITH_FREESTYLE
+ SIMEDGE_FREESTYLE
+#endif
};
/* similar vertex selection slot values */
diff --git a/source/blender/bmesh/operators/bmo_similar.c b/source/blender/bmesh/operators/bmo_similar.c
index baabcffd162..454f9ab2ad3 100644
--- a/source/blender/bmesh/operators/bmo_similar.c
+++ b/source/blender/bmesh/operators/bmo_similar.c
@@ -245,6 +245,14 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op)
cont = false;
}
break;
+#ifdef WITH_FREESTYLE
+ case SIMFACE_FREESTYLE:
+ if (BM_elem_flag_test(fm, BM_ELEM_FREESTYLE) == BM_elem_flag_test(fs, BM_ELEM_FREESTYLE)) {
+ BMO_elem_flag_enable(bm, fm, FACE_MARK);
+ cont = FALSE;
+ }
+ break;
+#endif
default:
BLI_assert(0);
}
@@ -463,6 +471,14 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
cont = false;
}
break;
+#ifdef WITH_FREESTYLE
+ case SIMEDGE_FREESTYLE:
+ if (BM_elem_flag_test(e, BM_ELEM_FREESTYLE) == BM_elem_flag_test(es, BM_ELEM_FREESTYLE)) {
+ BMO_elem_flag_enable(bm, e, EDGE_MARK);
+ cont = FALSE;
+ }
+ break;
+#endif
default:
BLI_assert(0);
}
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt
index 9e1e44e411d..58e38e55fa3 100644
--- a/source/blender/editors/animation/CMakeLists.txt
+++ b/source/blender/editors/animation/CMakeLists.txt
@@ -58,4 +58,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
blender_add_lib(bf_editor_animation "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/animation/SConscript b/source/blender/editors/animation/SConscript
index 2a6b381ba66..a4ccf1f6c3c 100644
--- a/source/blender/editors/animation/SConscript
+++ b/source/blender/editors/animation/SConscript
@@ -37,4 +37,7 @@ defs = []
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+
env.BlenderLib ( 'bf_editors_animation', sources, Split(incs), defs, libtype=['core'], priority=[125] )
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index f5c9bfb4cf5..7362935b4cc 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -47,6 +47,9 @@
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
#include "DNA_lattice_types.h"
+#ifdef WITH_FREESTYLE
+# include "DNA_linestyle_types.h"
+#endif
#include "DNA_mesh_types.h"
#include "DNA_material_types.h"
#include "DNA_meta_types.h"
@@ -2010,6 +2013,85 @@ static bAnimChannelType ACF_DSNTREE =
acf_dsntree_setting_ptr /* pointer for setting */
};
+#ifdef WITH_FREESTYLE
+/* LineStyle Expander ------------------------------------------- */
+
+/* TODO: just get this from RNA? */
+static int acf_dslinestyle_icon(bAnimListElem *UNUSED(ale))
+{
+ return ICON_BRUSH_DATA; /* FIXME */
+}
+
+/* get the appropriate flag(s) for the setting when it is valid */
+static int acf_dslinestyle_setting_flag(bAnimContext *UNUSED(ac), int setting, short *neg)
+{
+ /* clear extra return data first */
+ *neg = 0;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return LS_DS_EXPAND;
+
+ case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
+ return ADT_NLA_EVAL_OFF;
+
+ case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
+ *neg = 1;
+ return ADT_CURVES_NOT_VISIBLE;
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return ADT_UI_SELECTED;
+
+ default: /* unsupported */
+ return 0;
+ }
+}
+
+/* get pointer to the setting */
+static void *acf_dslinestyle_setting_ptr(bAnimListElem *ale, int setting, short *type)
+{
+ FreestyleLineStyle *linestyle = (FreestyleLineStyle *)ale->data;
+
+ /* clear extra return data first */
+ *type = 0;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return GET_ACF_FLAG_PTR(linestyle->flag, type);
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
+ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
+ if (linestyle->adt)
+ return GET_ACF_FLAG_PTR(linestyle->adt->flag, type);
+ else
+ return NULL;
+
+ default: /* unsupported */
+ return NULL;
+ }
+}
+
+/* node tree expander type define */
+static bAnimChannelType ACF_DSLINESTYLE=
+{
+ "Line Style Expander", /* type name */
+
+ acf_generic_dataexpand_color, /* backdrop color */
+ acf_generic_dataexpand_backdrop,/* backdrop */
+ acf_generic_indention_1, /* indent level */
+ acf_generic_basic_offset, /* offset */
+
+ acf_generic_idblock_name, /* name */
+ acf_generic_idblock_nameprop, /* name prop */
+ acf_dslinestyle_icon, /* icon */
+
+ acf_generic_dataexpand_setting_valid, /* has setting */
+ acf_dslinestyle_setting_flag, /* flag for setting */
+ acf_dslinestyle_setting_ptr /* pointer for setting */
+};
+#endif
+
/* Mesh Expander ------------------------------------------- */
// TODO: just get this from RNA?
@@ -2722,6 +2804,9 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_DSTEX; /* Texture Channel */
animchannelTypeInfo[type++] = &ACF_DSLAT; /* Lattice Channel */
animchannelTypeInfo[type++] = &ACF_DSSPK; /* Speaker Channel */
+#ifdef WITH_FREESTYLE
+ animchannelTypeInfo[type++] = &ACF_DSLINESTYLE; /* LineStyle Channel */
+#endif
animchannelTypeInfo[type++] = &ACF_SHAPEKEY; /* ShapeKey */
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 458054c9d7f..275cf723dcd 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -124,6 +124,9 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
case ANIMTYPE_DSMESH:
case ANIMTYPE_DSTEX:
case ANIMTYPE_DSLAT:
+#ifdef WITH_FREESTYLE
+ case ANIMTYPE_DSLINESTYLE:
+#endif
case ANIMTYPE_DSSPK:
{
/* need to verify that this data is valid for now */
@@ -169,6 +172,9 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
case ANIMTYPE_DSARM:
case ANIMTYPE_DSMESH:
case ANIMTYPE_DSLAT:
+#ifdef WITH_FREESTYLE
+ case ANIMTYPE_DSLINESTYLE:
+#endif
case ANIMTYPE_DSSPK:
{
/* need to verify that this data is valid for now */
@@ -249,6 +255,9 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
case ANIMTYPE_DSNTREE:
case ANIMTYPE_DSTEX:
case ANIMTYPE_DSLAT:
+#ifdef WITH_FREESTYLE
+ case ANIMTYPE_DSLINESTYLE:
+#endif
case ANIMTYPE_DSSPK:
{
if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
@@ -343,6 +352,9 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
case ANIMTYPE_DSNTREE:
case ANIMTYPE_DSTEX:
case ANIMTYPE_DSLAT:
+#ifdef WITH_FREESTYLE
+ case ANIMTYPE_DSLINESTYLE:
+#endif
case ANIMTYPE_DSSPK:
{
/* need to verify that this data is valid for now */
@@ -2207,6 +2219,9 @@ static int mouse_anim_channels(bAnimContext *ac, float UNUSED(x), int channel_in
case ANIMTYPE_DSNTREE:
case ANIMTYPE_DSTEX:
case ANIMTYPE_DSLAT:
+#ifdef WITH_FREESTYLE
+ case ANIMTYPE_DSLINESTYLE:
+#endif
case ANIMTYPE_DSSPK:
{
/* sanity checking... */
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 655ab2bfb15..37fd05f75a5 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -55,6 +55,9 @@
#include "DNA_camera_types.h"
#include "DNA_lamp_types.h"
#include "DNA_lattice_types.h"
+#ifdef WITH_FREESTYLE
+# include "DNA_linestyle_types.h"
+#endif
#include "DNA_key_types.h"
#include "DNA_mask_types.h"
#include "DNA_material_types.h"
@@ -734,6 +737,21 @@ static bAnimListElem *make_new_animlistelem(void *data, short datatype, ID *owne
ale->adt = BKE_animdata_from_id(data);
}
break;
+#ifdef WITH_FREESTYLE
+ case ANIMTYPE_DSLINESTYLE:
+ {
+ FreestyleLineStyle *linestyle = (FreestyleLineStyle *)data;
+ AnimData *adt = linestyle->adt;
+
+ ale->flag = FILTER_LS_SCED(linestyle);
+
+ ale->key_data = (adt) ? adt->action : NULL;
+ ale->datatype = ALE_ACT;
+
+ ale->adt = BKE_animdata_from_id(data);
+ }
+ break;
+#endif
case ANIMTYPE_DSPART:
{
ParticleSettings *part = (ParticleSettings *)ale->data;
@@ -1511,6 +1529,56 @@ static size_t animdata_filter_ds_nodetree(bAnimContext *ac, ListBase *anim_data,
return items;
}
+#ifdef WITH_FREESTYLE
+static size_t animdata_filter_ds_linestyle (bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
+{
+ SceneRenderLayer *srl;
+ size_t items = 0;
+
+ for (srl = sce->r.layers.first; srl; srl = srl->next) {
+ FreestyleLineSet *lineset;
+
+ /* skip render layers without Freestyle enabled */
+ if (!(srl->layflag & SCE_LAY_FRS))
+ continue;
+
+ /* loop over linesets defined in the render layer */
+ for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) {
+ FreestyleLineStyle *linestyle = lineset->linestyle;
+ ListBase tmp_data = {NULL, NULL};
+ size_t tmp_items = 0;
+
+ /* add scene-level animation channels */
+ BEGIN_ANIMFILTER_SUBCHANNELS(FILTER_LS_SCED(linestyle))
+ {
+ /* animation data filtering */
+ tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)linestyle, filter_mode);
+ }
+ END_ANIMFILTER_SUBCHANNELS;
+
+ /* did we find anything? */
+ if (tmp_items) {
+ /* include anim-expand widget first */
+ if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
+ /* check if filtering by active status */
+ if ANIMCHANNEL_ACTIVEOK(linestyle) {
+ ANIMCHANNEL_NEW_CHANNEL(linestyle, ANIMTYPE_DSLINESTYLE, sce);
+ }
+ }
+
+ /* now add the list of collected channels */
+ BLI_movelisttolist(anim_data, &tmp_data);
+ BLI_assert((tmp_data.first == tmp_data.last) && (tmp_data.first == NULL));
+ items += tmp_items;
+ }
+ }
+ }
+
+ /* return the number of items added to the list */
+ return items;
+}
+#endif
+
/* NOTE: owner_id is either material, lamp, or world block, which is the direct owner of the texture stack in question */
static size_t animdata_filter_ds_textures(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, int filter_mode)
{
@@ -2145,6 +2213,13 @@ static size_t animdata_filter_dopesheet_scene(bAnimContext *ac, ListBase *anim_d
tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)sce, ntree, filter_mode);
}
+#ifdef WITH_FREESTYLE
+ /* line styles */
+ if ((ads->filterflag & ADS_FILTER_NOLINESTYLE) == 0) {
+ tmp_items += animdata_filter_ds_linestyle(ac, &tmp_data, ads, sce, filter_mode);
+ }
+#endif
+
/* TODO: one day, when sequencer becomes its own datatype, perhaps it should be included here */
}
END_ANIMFILTER_SUBCHANNELS;
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 551d3041398..7ce25b11f93 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -155,6 +155,9 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_DSMESH,
ANIMTYPE_DSTEX,
ANIMTYPE_DSLAT,
+#ifdef WITH_FREESTYLE
+ ANIMTYPE_DSLINESTYLE,
+#endif
ANIMTYPE_DSSPK,
ANIMTYPE_SHAPEKEY,
@@ -236,6 +239,9 @@ typedef enum eAnimFilter_Flags {
#define EXPANDED_SCEC(sce) (CHECK_TYPE_INLINE(sce, Scene), ((sce->flag & SCE_DS_COLLAPSED) == 0))
/* 'Sub-Scene' channels (flags stored in Data block) */
#define FILTER_WOR_SCED(wo) (CHECK_TYPE_INLINE(wo, World), (wo->flag & WO_DS_EXPAND))
+#ifdef WITH_FREESTYLE
+# define FILTER_LS_SCED(linestyle) ((linestyle->flag & LS_DS_EXPAND))
+#endif
/* 'Object' channels */
#define SEL_OBJC(base) (CHECK_TYPE_INLINE(base, Base), ((base->flag & SELECT)))
#define EXPANDED_OBJC(ob) (CHECK_TYPE_INLINE(ob, Object), ((ob->nlaflag & OB_ADS_COLLAPSED) == 0))
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index f8eae840471..df07e05ec06 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -205,6 +205,11 @@ enum {
TH_STITCH_PREVIEW_UNSTITCHABLE,
TH_STITCH_PREVIEW_ACTIVE,
+/* #ifdef WITH_FREESTYLE */
+ TH_FREESTYLE_EDGE_MARK,
+ TH_FREESTYLE_FACE_MARK,
+/* #endif */
+
TH_MATCH, /* highlight color for search matches */
TH_SELECT_HIGHLIGHT, /* highlight color for selected outliner item */
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 8ba86673f87..267e7c05737 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -62,6 +62,10 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
if(WITH_HEADLESS)
add_definitions(-DWITH_HEADLESS)
endif()
diff --git a/source/blender/editors/interface/SConscript b/source/blender/editors/interface/SConscript
index 8d277d6cd35..16e4e6cb9c0 100644
--- a/source/blender/editors/interface/SConscript
+++ b/source/blender/editors/interface/SConscript
@@ -42,6 +42,9 @@ defs = []
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+
if env['WITH_BF_PYTHON']:
defs.append('WITH_PYTHON')
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 3385d334b71..ec2b4f5adf0 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -329,6 +329,9 @@ static const char *template_id_browse_tip(StructRNA *type)
case ID_MA: return N_("Browse Material to be linked");
case ID_TE: return N_("Browse Texture to be linked");
case ID_IM: return N_("Browse Image to be linked");
+#ifdef WITH_FREESTYLE
+ case ID_LS: return N_("Browse Line Style Data to be linked");
+#endif
case ID_LT: return N_("Browse Lattice Data to be linked");
case ID_LA: return N_("Browse Lamp Data to be linked");
case ID_CA: return N_("Browse Camera Data to be linked");
@@ -364,6 +367,9 @@ static const char *template_id_context(StructRNA *type)
case ID_MA: return BLF_I18NCONTEXT_ID_MATERIAL;
case ID_TE: return BLF_I18NCONTEXT_ID_TEXTURE;
case ID_IM: return BLF_I18NCONTEXT_ID_IMAGE;
+#ifdef WITH_FREESTYLE
+ case ID_LS: return BLF_I18NCONTEXT_ID_FREESTYLELINESTYLE;
+#endif
case ID_LT: return BLF_I18NCONTEXT_ID_LATTICE;
case ID_LA: return BLF_I18NCONTEXT_ID_LAMP;
case ID_CA: return BLF_I18NCONTEXT_ID_CAMERA;
@@ -519,7 +525,11 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
BLF_I18NCONTEXT_ID_NODETREE,
BLF_I18NCONTEXT_ID_BRUSH,
BLF_I18NCONTEXT_ID_PARTICLESETTINGS,
- BLF_I18NCONTEXT_ID_GPENCIL);
+ BLF_I18NCONTEXT_ID_GPENCIL,
+#ifdef WITH_FREESTYLE
+ BLF_I18NCONTEXT_ID_FREESTYLELINESTYLE
+#endif
+ );
if (newop) {
but = uiDefIconTextButO(block, BUT, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN,
@@ -2430,7 +2440,7 @@ static void uilist_draw_item_default(struct uiList *ui_list, struct bContext *UN
uiItemL(layout, name, icon);
break;
}
-
+
/* free name */
if (namebuf) {
MEM_freeN(namebuf);
@@ -2513,7 +2523,7 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
if (ui_list_type == NULL) {
RNA_warning("List type %s not found", listtype_name);
return;
- }
+ }
draw_item = ui_list_type->draw_item ? ui_list_type->draw_item : uilist_draw_item_default;
@@ -2528,7 +2538,7 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
ui_list = MEM_callocN(sizeof(uiList), __func__);
BLI_strncpy(ui_list->list_id, ui_list_id, sizeof(ui_list->list_id));
BLI_addtail(&ar->ui_lists, ui_list);
- }
+ }
/* Because we can't actually pass type across save&load... */
ui_list->type = ui_list_type;
@@ -2622,10 +2632,10 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
if (icon == ICON_DOT)
icon = ICON_NONE;
draw_item(ui_list, C, row, dataptr, &itemptr, icon, active_dataptr, active_propname, i);
- }
+ }
i++;
- }
+}
RNA_PROP_END;
}
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index e3fbbc26d0d..7efda2f56c3 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -359,6 +359,12 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->handle_sel_vect; break;
case TH_HANDLE_SEL_ALIGN:
cp = ts->handle_sel_align; break;
+#ifdef WITH_FREESTYLE
+ case TH_FREESTYLE_EDGE_MARK:
+ cp = ts->freestyle_edge_mark; break;
+ case TH_FREESTYLE_FACE_MARK:
+ cp = ts->freestyle_face_mark; break;
+#endif
case TH_SYNTAX_B:
cp = ts->syntaxb; break;
@@ -751,6 +757,10 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tv3d.button_text_hi, 255, 255, 255, 255);
rgba_char_args_set(btheme->tv3d.button_title, 0, 0, 0, 255);
rgba_char_args_set(btheme->tv3d.title, 0, 0, 0, 255);
+#ifdef WITH_FREESTYLE
+ rgba_char_args_set(btheme->tv3d.freestyle_edge_mark, 0x7f, 0xff, 0x7f, 255);
+ rgba_char_args_set(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51);
+#endif
btheme->tv3d.facedot_size = 4;
@@ -2008,6 +2018,21 @@ void init_userdef_do_versions(void)
}
}
+#ifdef WITH_FREESTYLE
+ /* Freestyle color settings */
+ {
+ bTheme *btheme;
+
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ /* check for alpha == 0 is safe, then color was never set */
+ if (btheme->tv3d.freestyle_edge_mark[3] == 0) {
+ rgba_char_args_set(btheme->tv3d.freestyle_edge_mark, 0x7f, 0xff, 0x7f, 255);
+ rgba_char_args_set(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51);
+ }
+ }
+ }
+#endif
+
/* GL Texture Garbage Collection (variable abused above!) */
if (U.textimeout == 0) {
U.texcollectrate = 60;
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 169e7a60fb1..b51d55aaf0e 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -72,6 +72,10 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
if(WITH_BULLET)
add_definitions(-DWITH_BULLET)
endif()
diff --git a/source/blender/editors/mesh/SConscript b/source/blender/editors/mesh/SConscript
index 11c90a4a922..55ad14a50fc 100644
--- a/source/blender/editors/mesh/SConscript
+++ b/source/blender/editors/mesh/SConscript
@@ -53,6 +53,9 @@ else:
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+
if env['WITH_BF_BULLET']:
defs.append('WITH_BULLET')
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index e85649831f2..88d826c2f98 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -681,6 +681,9 @@ static EnumPropertyItem prop_similar_types[] = {
{SIMEDGE_BEVEL, "BEVEL", 0, "Bevel", ""},
{SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
{SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
+#ifdef WITH_FREESTYLE
+ {SIMEDGE_FREESTYLE, "FREESTYLE_EDGE", 0, "Freestyle Edge Marks", ""},
+#endif
{SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
{SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
@@ -689,6 +692,9 @@ static EnumPropertyItem prop_similar_types[] = {
{SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
{SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
{SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
+#ifdef WITH_FREESTYLE
+ {SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""},
+#endif
{0, NULL, 0, NULL, NULL}
};
@@ -863,7 +869,11 @@ static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUS
}
}
else if (em->selectmode & SCE_SELECT_FACE) {
+#ifdef WITH_FREESTYLE
+ for (a = SIMFACE_MATERIAL; a <= SIMFACE_FREESTYLE; a++) {
+#else
for (a = SIMFACE_MATERIAL; a <= SIMFACE_COPLANAR; a++) {
+#endif
RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
}
}
@@ -1313,6 +1323,11 @@ static void edgetag_context_set(BMesh *bm, Scene *scene, BMEdge *e, int val)
case EDGE_MODE_TAG_SHARP:
BM_elem_flag_set(e, BM_ELEM_SMOOTH, !val);
break;
+#ifdef WITH_FREESTYLE
+ case EDGE_MODE_TAG_FREESTYLE:
+ BM_elem_flag_set(e, BM_ELEM_FREESTYLE, val);
+ break;
+#endif
case EDGE_MODE_TAG_CREASE:
BM_elem_float_data_set(&bm->edata, e, CD_CREASE, (val) ? 1.0f : 0.0f);
break;
@@ -1331,6 +1346,10 @@ static int edgetag_context_check(Scene *scene, BMesh *bm, BMEdge *e)
return BM_elem_flag_test(e, BM_ELEM_SEAM);
case EDGE_MODE_TAG_SHARP:
return !BM_elem_flag_test(e, BM_ELEM_SMOOTH);
+#ifdef WITH_FREESTYLE
+ case EDGE_MODE_TAG_FREESTYLE:
+ return !BM_elem_flag_test(e, BM_ELEM_FREESTYLE);
+#endif
case EDGE_MODE_TAG_CREASE:
return BM_elem_float_data_get(&bm->edata, e, CD_CREASE) ? TRUE : FALSE;
case EDGE_MODE_TAG_BEVEL:
@@ -1496,6 +1515,11 @@ static int mouse_mesh_shortest_path_edge(ViewContext *vc)
case EDGE_MODE_TAG_BEVEL:
me->drawflag |= ME_DRAWBWEIGHTS;
break;
+#ifdef WITH_FREESTYLE
+ case EDGE_MODE_TAG_FREESTYLE:
+ me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
+ break;
+#endif
}
EDBM_update_generic(em, FALSE, FALSE);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 3e8219bfd1c..b411cd2bd27 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -5759,3 +5759,109 @@ void MESH_OT_symmetrize(struct wmOperatorType *ot)
BMO_SYMMETRIZE_NEGATIVE_X,
"Direction", "Which sides to copy from and to");
}
+
+#ifdef WITH_FREESTYLE
+static int edbm_mark_freestyle_edge(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Mesh *me = ((Mesh *)obedit->data);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMEdge *eed;
+ BMIter iter;
+ int clear = RNA_boolean_get(op->ptr, "clear");
+
+ if (em == NULL)
+ return OPERATOR_FINISHED;
+
+ /* auto-enable seams drawing */
+ if (clear == 0) {
+ me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
+ }
+
+ if (clear) {
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
+ BM_elem_flag_disable(eed, BM_ELEM_FREESTYLE);
+ }
+ }
+ else {
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
+ BM_elem_flag_enable(eed, BM_ELEM_FREESTYLE);
+ }
+ }
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_mark_freestyle_edge(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Mark Freestyle Edge";
+ ot->description = "(un)mark selected edges as Freestyle feature edges";
+ ot->idname = "MESH_OT_mark_freestyle_edge";
+
+ /* api callbacks */
+ ot->exec = edbm_mark_freestyle_edge;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+}
+
+static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ Mesh *me = ((Mesh *)obedit->data);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ BMFace *efa;
+ BMIter iter;
+ int clear = RNA_boolean_get(op->ptr, "clear");
+
+ if (em == NULL) return OPERATOR_FINISHED;
+
+ /* auto-enable Freestyle face mark drawing */
+ if(!clear) {
+ me->drawflag |= ME_DRAW_FREESTYLE_FACE;
+ }
+
+ if(clear) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
+ BM_elem_flag_disable(efa, BM_ELEM_FREESTYLE);
+ }
+ } else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
+ BM_elem_flag_enable(efa, BM_ELEM_FREESTYLE);
+ }
+ }
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_mark_freestyle_face(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Mark Freestyle Face";
+ ot->description = "(un)mark selected faces for exclusion from Freestyle feature edge detection";
+ ot->idname = "MESH_OT_mark_freestyle_face";
+
+ /* api callbacks */
+ ot->exec = edbm_mark_freestyle_face_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+}
+#endif \ No newline at end of file
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 9ea15f93250..fe4917acdac 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -131,6 +131,9 @@ void MESH_OT_select_random(struct wmOperatorType *ot);
void MESH_OT_loop_multi_select(struct wmOperatorType *ot);
void MESH_OT_mark_seam(struct wmOperatorType *ot);
void MESH_OT_mark_sharp(struct wmOperatorType *ot);
+#ifdef WITH_FREESTYLE
+void MESH_OT_mark_freestyle_edge(struct wmOperatorType *ot);
+#endif
void MESH_OT_vertices_smooth(struct wmOperatorType *ot);
void MESH_OT_vertices_smooth_laplacian(struct wmOperatorType *ot);
void MESH_OT_noise(struct wmOperatorType *ot);
@@ -180,6 +183,9 @@ void MESH_OT_rip(struct wmOperatorType *ot);
void MESH_OT_shape_propagate_to_all(struct wmOperatorType *ot);
void MESH_OT_blend_from_shape(struct wmOperatorType *ot);
void MESH_OT_sort_elements(struct wmOperatorType *ot);
+#ifdef WITH_FREESTYLE
+void MESH_OT_mark_freestyle_face(struct wmOperatorType *ot);
+#endif
/* ******************* mesh_data.c */
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 4fdbb9310b0..9403299b0cd 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -111,6 +111,9 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_faces_shade_smooth);
WM_operatortype_append(MESH_OT_faces_shade_flat);
WM_operatortype_append(MESH_OT_sort_elements);
+#ifdef WITH_FREESTYLE
+ WM_operatortype_append(MESH_OT_mark_freestyle_face);
+#endif
WM_operatortype_append(MESH_OT_delete);
WM_operatortype_append(MESH_OT_edge_collapse);
@@ -126,6 +129,9 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_loop_multi_select);
WM_operatortype_append(MESH_OT_mark_seam);
WM_operatortype_append(MESH_OT_mark_sharp);
+#ifdef WITH_FREESTYLE
+ WM_operatortype_append(MESH_OT_mark_freestyle_edge);
+#endif
WM_operatortype_append(MESH_OT_vertices_smooth);
WM_operatortype_append(MESH_OT_vertices_smooth_laplacian);
WM_operatortype_append(MESH_OT_noise);
diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt
index 3c5fd0b4ef7..b858d715cfe 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -68,4 +68,11 @@ if(WITH_HEADLESS)
add_definitions(-DWITH_HEADLESS)
endif()
+if(WITH_FREESTYLE)
+ list(APPEND INC
+ ../../freestyle
+ )
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
blender_add_lib(bf_editor_render "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/render/SConscript b/source/blender/editors/render/SConscript
index c05b542aea8..9d1de2fc700 100644
--- a/source/blender/editors/render/SConscript
+++ b/source/blender/editors/render/SConscript
@@ -42,6 +42,9 @@ if env['OURPLATFORM'] == 'linux':
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
+if env['WITH_BF_FREESTYLE']:
+ incs += ' ../../freestyle'
+ env.Append(CFLAGS=['-DWITH_FREESTYLE'])
if env['WITH_BF_QUICKTIME']:
incs += ' ../../quicktime'
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h
index 18ba2b5abf9..88c00601933 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.h
@@ -54,6 +54,25 @@ void MATERIAL_OT_paste(struct wmOperatorType *ot);
void SCENE_OT_render_layer_add(struct wmOperatorType *ot);
void SCENE_OT_render_layer_remove(struct wmOperatorType *ot);
+#ifdef WITH_FREESTYLE
+void SCENE_OT_freestyle_module_add(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_module_remove(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_module_move(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_lineset_add(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_lineset_copy(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_lineset_paste(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_lineset_remove(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_lineset_move(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_linestyle_new(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_color_modifier_add(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_alpha_modifier_add(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_thickness_modifier_add(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_geometry_modifier_add(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_modifier_remove(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_modifier_move(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_modifier_copy(struct wmOperatorType *ot);
+#endif
+
void TEXTURE_OT_slot_copy(struct wmOperatorType *ot);
void TEXTURE_OT_slot_paste(struct wmOperatorType *ot);
diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c
index c9e6dc90515..ebd2cc941d0 100644
--- a/source/blender/editors/render/render_ops.c
+++ b/source/blender/editors/render/render_ops.c
@@ -62,6 +62,25 @@ void ED_operatortypes_render(void)
WM_operatortype_append(SCENE_OT_render_layer_add);
WM_operatortype_append(SCENE_OT_render_layer_remove);
+#ifdef WITH_FREESTYLE
+ WM_operatortype_append(SCENE_OT_freestyle_module_add);
+ WM_operatortype_append(SCENE_OT_freestyle_module_remove);
+ WM_operatortype_append(SCENE_OT_freestyle_module_move);
+ WM_operatortype_append(SCENE_OT_freestyle_lineset_add);
+ WM_operatortype_append(SCENE_OT_freestyle_lineset_copy);
+ WM_operatortype_append(SCENE_OT_freestyle_lineset_paste);
+ WM_operatortype_append(SCENE_OT_freestyle_lineset_remove);
+ WM_operatortype_append(SCENE_OT_freestyle_lineset_move);
+ WM_operatortype_append(SCENE_OT_freestyle_linestyle_new);
+ WM_operatortype_append(SCENE_OT_freestyle_color_modifier_add);
+ WM_operatortype_append(SCENE_OT_freestyle_alpha_modifier_add);
+ WM_operatortype_append(SCENE_OT_freestyle_thickness_modifier_add);
+ WM_operatortype_append(SCENE_OT_freestyle_geometry_modifier_add);
+ WM_operatortype_append(SCENE_OT_freestyle_modifier_remove);
+ WM_operatortype_append(SCENE_OT_freestyle_modifier_move);
+ WM_operatortype_append(SCENE_OT_freestyle_modifier_copy);
+#endif
+
#if (defined(WITH_QUICKTIME) && !defined(USE_QTKIT))
WM_operatortype_append(SCENE_OT_render_data_set_quicktime_codec);
#endif
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 53e1f49d544..dfc53d0b195 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -69,7 +69,13 @@
#include "GPU_material.h"
+#ifdef WITH_FREESTYLE
+# include "BKE_linestyle.h"
+# include "FRS_freestyle.h"
+#endif
+
#include "RNA_access.h"
+#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -570,6 +576,622 @@ void SCENE_OT_render_layer_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+#ifdef WITH_FREESTYLE
+static int freestyle_module_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+
+ FRS_add_module(&srl->freestyleConfig);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_module_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Freestyle Module";
+ ot->idname = "SCENE_OT_freestyle_module_add";
+ ot->description = "Add a style module into the list of modules";
+
+ /* api callbacks */
+ ot->exec = freestyle_module_add_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int freestyle_module_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
+ FreestyleModuleConfig *module = ptr.data;
+
+ FRS_delete_module(&srl->freestyleConfig, module);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_module_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Freestyle Module";
+ ot->idname = "SCENE_OT_freestyle_module_remove";
+ ot->description = "Remove the style module from the stack";
+
+ /* api callbacks */
+ ot->exec = freestyle_module_remove_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int freestyle_module_move_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings);
+ FreestyleModuleConfig *module = ptr.data;
+ int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (dir == 1) {
+ FRS_move_module_up(&srl->freestyleConfig, module);
+ }
+ else {
+ FRS_move_module_down(&srl->freestyleConfig, module);
+ }
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_module_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem direction_items[] = {
+ {1, "UP", 0, "Up", ""},
+ {-1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Move Freestyle Module";
+ ot->idname = "SCENE_OT_freestyle_module_move";
+ ot->description = "Change the position of the style module within in the list of style modules";
+
+ /* api callbacks */
+ ot->exec = freestyle_module_move_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move, UP or DOWN");
+}
+
+static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+
+ FRS_add_lineset(&srl->freestyleConfig);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_lineset_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Line Set";
+ ot->idname = "SCENE_OT_freestyle_lineset_add";
+ ot->description = "Add a line set into the list of line sets";
+
+ /* api callbacks */
+ ot->exec = freestyle_lineset_add_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int freestyle_active_lineset_poll(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+
+ return FRS_get_active_lineset(&srl->freestyleConfig) != NULL;
+}
+
+static int freestyle_lineset_copy_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+
+ FRS_copy_active_lineset(&srl->freestyleConfig);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_lineset_copy(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy Line Set";
+ ot->idname = "SCENE_OT_freestyle_lineset_copy";
+ ot->description = "Copy the active line set to a buffer";
+
+ /* api callbacks */
+ ot->exec = freestyle_lineset_copy_exec;
+ ot->poll = freestyle_active_lineset_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int freestyle_lineset_paste_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+
+ FRS_paste_active_lineset(&srl->freestyleConfig);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_lineset_paste(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Paste Line Set";
+ ot->idname = "SCENE_OT_freestyle_lineset_paste";
+ ot->description = "Paste the buffer content to the active line set";
+
+ /* api callbacks */
+ ot->exec = freestyle_lineset_paste_exec;
+ ot->poll = freestyle_active_lineset_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int freestyle_lineset_remove_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+
+ FRS_delete_active_lineset(&srl->freestyleConfig);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_lineset_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Line Set";
+ ot->idname = "SCENE_OT_freestyle_lineset_remove";
+ ot->description = "Remove the active line set from the list of line sets";
+
+ /* api callbacks */
+ ot->exec = freestyle_lineset_remove_exec;
+ ot->poll = freestyle_active_lineset_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int freestyle_lineset_move_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (dir == 1) {
+ FRS_move_active_lineset_up(&srl->freestyleConfig);
+ }
+ else {
+ FRS_move_active_lineset_down(&srl->freestyleConfig);
+ }
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem direction_items[] = {
+ {1, "UP", 0, "Up", ""},
+ {-1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Move Line Set";
+ ot->idname = "SCENE_OT_freestyle_lineset_move";
+ ot->description = "Change the position of the active line set within the list of line sets";
+
+ /* api callbacks */
+ ot->exec = freestyle_lineset_move_exec;
+ ot->poll = freestyle_active_lineset_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move, UP or DOWN");
+}
+
+static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ FreestyleLineSet *lineset = FRS_get_active_lineset(&srl->freestyleConfig);
+
+ if (!lineset) {
+ BKE_report(op->reports, RPT_ERROR, "No active lineset to add a new line style to");
+ return OPERATOR_CANCELLED;
+ }
+ lineset->linestyle->id.us--;
+ lineset->linestyle = FRS_copy_linestyle(lineset->linestyle);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_linestyle_new(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Line Style";
+ ot->idname = "SCENE_OT_freestyle_linestyle_new";
+ ot->description = "Create a new line style, reusable by multiple line sets";
+
+ /* api callbacks */
+ ot->exec = freestyle_linestyle_new_exec;
+ ot->poll = freestyle_active_lineset_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int freestyle_color_modifier_add_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ FreestyleLineSet *lineset = FRS_get_active_lineset(&srl->freestyleConfig);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ if (!lineset) {
+ BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style to add the modifier to");
+ return OPERATOR_CANCELLED;
+ }
+ if (FRS_add_linestyle_color_modifier(lineset->linestyle, type) < 0) {
+ BKE_report(op->reports, RPT_ERROR, "Unknown line color modifier type.");
+ return OPERATOR_CANCELLED;
+ }
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_color_modifier_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Line Color Modifier";
+ ot->idname = "SCENE_OT_freestyle_color_modifier_add";
+ ot->description = "Add a line color modifier to the line style associated with the active lineset";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = freestyle_color_modifier_add_exec;
+ ot->poll = freestyle_active_lineset_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", linestyle_color_modifier_type_items, 0, "Type", "");
+}
+
+static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ FreestyleLineSet *lineset = FRS_get_active_lineset(&srl->freestyleConfig);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ if (!lineset) {
+ BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style to add the modifier to");
+ return OPERATOR_CANCELLED;
+ }
+ if (FRS_add_linestyle_alpha_modifier(lineset->linestyle, type) < 0) {
+ BKE_report(op->reports, RPT_ERROR, "Unknown alpha transparency modifier type");
+ return OPERATOR_CANCELLED;
+ }
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_alpha_modifier_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Alpha Transparency Modifier";
+ ot->idname = "SCENE_OT_freestyle_alpha_modifier_add";
+ ot->description = "Add an alpha transparency modifier to the line style associated with the active lineset";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = freestyle_alpha_modifier_add_exec;
+ ot->poll = freestyle_active_lineset_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", linestyle_alpha_modifier_type_items, 0, "Type", "");
+}
+
+static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ FreestyleLineSet *lineset = FRS_get_active_lineset(&srl->freestyleConfig);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ if (!lineset) {
+ BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style to add the modifier to");
+ return OPERATOR_CANCELLED;
+ }
+ if (FRS_add_linestyle_thickness_modifier(lineset->linestyle, type) < 0) {
+ BKE_report(op->reports, RPT_ERROR, "Unknown line thickness modifier type");
+ return OPERATOR_CANCELLED;
+ }
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_thickness_modifier_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Line Thickness Modifier";
+ ot->idname = "SCENE_OT_freestyle_thickness_modifier_add";
+ ot->description = "Add a line thickness modifier to the line style associated with the active lineset";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = freestyle_thickness_modifier_add_exec;
+ ot->poll = freestyle_active_lineset_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", linestyle_thickness_modifier_type_items, 0, "Type", "");
+}
+
+static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ FreestyleLineSet *lineset = FRS_get_active_lineset(&srl->freestyleConfig);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ if (!lineset) {
+ BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style to add the modifier to");
+ return OPERATOR_CANCELLED;
+ }
+ if (FRS_add_linestyle_geometry_modifier(lineset->linestyle, type) < 0) {
+ BKE_report(op->reports, RPT_ERROR, "Unknown stroke geometry modifier type");
+ return OPERATOR_CANCELLED;
+ }
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_geometry_modifier_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Stroke Geometry Modifier";
+ ot->idname = "SCENE_OT_freestyle_geometry_modifier_add";
+ ot->description = "Add a stroke geometry modifier to the line style associated with the active lineset";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = freestyle_geometry_modifier_add_exec;
+ ot->poll = freestyle_active_lineset_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", linestyle_geometry_modifier_type_items, 0, "Type", "");
+}
+
+static int freestyle_get_modifier_type(PointerRNA *ptr)
+{
+ if (RNA_struct_is_a(ptr->type, &RNA_LineStyleColorModifier))
+ return LS_MODIFIER_TYPE_COLOR;
+ else if (RNA_struct_is_a(ptr->type, &RNA_LineStyleAlphaModifier))
+ return LS_MODIFIER_TYPE_ALPHA;
+ else if (RNA_struct_is_a(ptr->type, &RNA_LineStyleThicknessModifier))
+ return LS_MODIFIER_TYPE_THICKNESS;
+ else if (RNA_struct_is_a(ptr->type, &RNA_LineStyleGeometryModifier))
+ return LS_MODIFIER_TYPE_GEOMETRY;
+ return -1;
+}
+
+static int freestyle_modifier_remove_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ FreestyleLineSet *lineset = FRS_get_active_lineset(&srl->freestyleConfig);
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
+ LineStyleModifier *modifier = ptr.data;
+
+ if (!lineset) {
+ BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style the modifier belongs to");
+ return OPERATOR_CANCELLED;
+ }
+
+ switch (freestyle_get_modifier_type(&ptr)) {
+ case LS_MODIFIER_TYPE_COLOR:
+ FRS_remove_linestyle_color_modifier(lineset->linestyle, modifier);
+ break;
+ case LS_MODIFIER_TYPE_ALPHA:
+ FRS_remove_linestyle_alpha_modifier(lineset->linestyle, modifier);
+ break;
+ case LS_MODIFIER_TYPE_THICKNESS:
+ FRS_remove_linestyle_thickness_modifier(lineset->linestyle, modifier);
+ break;
+ case LS_MODIFIER_TYPE_GEOMETRY:
+ FRS_remove_linestyle_geometry_modifier(lineset->linestyle, modifier);
+ break;
+ default:
+ BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier");
+ return OPERATOR_CANCELLED;
+ }
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_modifier_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Modifier";
+ ot->idname = "SCENE_OT_freestyle_modifier_remove";
+ ot->description = "Remove the modifier from the list of modifiers";
+
+ /* api callbacks */
+ ot->exec = freestyle_modifier_remove_exec;
+ ot->poll = freestyle_active_lineset_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ FreestyleLineSet *lineset = FRS_get_active_lineset(&srl->freestyleConfig);
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
+ LineStyleModifier *modifier = ptr.data;
+
+ if (!lineset) {
+ BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style the modifier belongs to");
+ return OPERATOR_CANCELLED;
+ }
+
+ switch (freestyle_get_modifier_type(&ptr)) {
+ case LS_MODIFIER_TYPE_COLOR:
+ FRS_copy_linestyle_color_modifier(lineset->linestyle, modifier);
+ break;
+ case LS_MODIFIER_TYPE_ALPHA:
+ FRS_copy_linestyle_alpha_modifier(lineset->linestyle, modifier);
+ break;
+ case LS_MODIFIER_TYPE_THICKNESS:
+ FRS_copy_linestyle_thickness_modifier(lineset->linestyle, modifier);
+ break;
+ case LS_MODIFIER_TYPE_GEOMETRY:
+ FRS_copy_linestyle_geometry_modifier(lineset->linestyle, modifier);
+ break;
+ default:
+ BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier");
+ return OPERATOR_CANCELLED;
+ }
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_modifier_copy(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Copy Modifier";
+ ot->idname = "SCENE_OT_freestyle_modifier_copy";
+ ot->description = "Duplicate the modifier within the list of modifiers";
+
+ /* api callbacks */
+ ot->exec = freestyle_modifier_copy_exec;
+ ot->poll = freestyle_active_lineset_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ FreestyleLineSet *lineset = FRS_get_active_lineset(&srl->freestyleConfig);
+ PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier);
+ LineStyleModifier *modifier = ptr.data;
+ int dir = RNA_enum_get(op->ptr, "direction");
+
+ if (!lineset) {
+ BKE_report(op->reports, RPT_ERROR, "No active lineset and associated line style the modifier belongs to");
+ return OPERATOR_CANCELLED;
+ }
+
+ switch (freestyle_get_modifier_type(&ptr)) {
+ case LS_MODIFIER_TYPE_COLOR:
+ FRS_move_linestyle_color_modifier(lineset->linestyle, modifier, dir);
+ break;
+ case LS_MODIFIER_TYPE_ALPHA:
+ FRS_move_linestyle_alpha_modifier(lineset->linestyle, modifier, dir);
+ break;
+ case LS_MODIFIER_TYPE_THICKNESS:
+ FRS_move_linestyle_thickness_modifier(lineset->linestyle, modifier, dir);
+ break;
+ case LS_MODIFIER_TYPE_GEOMETRY:
+ FRS_move_linestyle_geometry_modifier(lineset->linestyle, modifier, dir);
+ break;
+ default:
+ BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier");
+ return OPERATOR_CANCELLED;
+ }
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot)
+{
+ static EnumPropertyItem direction_items[] = {
+ {1, "UP", 0, "Up", ""},
+ {-1, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Move Modifier";
+ ot->idname = "SCENE_OT_freestyle_modifier_move";
+ ot->description = "Move the modifier within the list of modifiers";
+
+ /* api callbacks */
+ ot->exec = freestyle_modifier_move_exec;
+ ot->poll = freestyle_active_lineset_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move, UP or DOWN");
+}
+#endif
+
static int texture_slot_move(bContext *C, wmOperator *op)
{
ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).id.data;
diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt
index 7233d4623d1..10080c62594 100644
--- a/source/blender/editors/space_buttons/CMakeLists.txt
+++ b/source/blender/editors/space_buttons/CMakeLists.txt
@@ -48,4 +48,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
blender_add_lib(bf_editor_space_buttons "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_buttons/SConscript b/source/blender/editors/space_buttons/SConscript
index 5250a1264a4..1f7939598c8 100644
--- a/source/blender/editors/space_buttons/SConscript
+++ b/source/blender/editors/space_buttons/SConscript
@@ -38,4 +38,7 @@ defs = []
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+
env.BlenderLib ( 'bf_editors_space_buttons', sources, Split(incs), defs, libtype=['core'], priority=[120] )
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 2a5b64cd6ed..91f069d16de 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -538,6 +538,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
switch (mainb) {
case BCONTEXT_SCENE:
case BCONTEXT_RENDER:
+ case BCONTEXT_RENDER_LAYER:
found = buttons_context_path_scene(path);
break;
case BCONTEXT_WORLD:
@@ -1043,7 +1044,7 @@ void buttons_context_draw(const bContext *C, uiLayout *layout)
name = RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf), NULL);
if (name) {
- if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE) && ptr->type == &RNA_Scene)
+ if (!ELEM3(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_RENDER_LAYER) && ptr->type == &RNA_Scene)
uiItemLDrag(row, ptr, "", icon); /* save some space */
else
uiItemLDrag(row, ptr, name, icon);
diff --git a/source/blender/editors/space_buttons/buttons_header.c b/source/blender/editors/space_buttons/buttons_header.c
index ebba7d92819..3c2d9ac2eee 100644
--- a/source/blender/editors/space_buttons/buttons_header.c
+++ b/source/blender/editors/space_buttons/buttons_header.c
@@ -128,6 +128,7 @@ void buttons_header_buttons(const bContext *C, ARegion *ar)
} (void)0
BUTTON_HEADER_CTX(BCONTEXT_RENDER, ICON_SCENE, N_("Render"));
+ BUTTON_HEADER_CTX(BCONTEXT_RENDER_LAYER, ICON_RENDERLAYERS, N_("Render Layers"));
BUTTON_HEADER_CTX(BCONTEXT_SCENE, ICON_SCENE_DATA, N_("Scene"));
BUTTON_HEADER_CTX(BCONTEXT_WORLD, ICON_WORLD, N_("World"));
BUTTON_HEADER_CTX(BCONTEXT_OBJECT, ICON_OBJECT_DATA, N_("Object"));
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index c98d213e949..6367ca893d1 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -155,6 +155,8 @@ static void buttons_main_area_draw(const bContext *C, ARegion *ar)
ED_region_panels(C, ar, vertical, "scene", sbuts->mainb);
else if (sbuts->mainb == BCONTEXT_RENDER)
ED_region_panels(C, ar, vertical, "render", sbuts->mainb);
+ else if (sbuts->mainb == BCONTEXT_RENDER_LAYER)
+ ED_region_panels(C, ar, vertical, "render_layer", sbuts->mainb);
else if (sbuts->mainb == BCONTEXT_WORLD)
ED_region_panels(C, ar, vertical, "world", sbuts->mainb);
else if (sbuts->mainb == BCONTEXT_OBJECT)
@@ -239,6 +241,7 @@ static void buttons_area_listener(ScrArea *sa, wmNotifier *wmn)
switch (wmn->data) {
case ND_RENDER_OPTIONS:
buttons_area_redraw(sa, BCONTEXT_RENDER);
+ buttons_area_redraw(sa, BCONTEXT_RENDER_LAYER);
break;
case ND_FRAME:
/* any buttons area can have animated properties so redraw all */
@@ -375,6 +378,12 @@ static void buttons_area_listener(ScrArea *sa, wmNotifier *wmn)
ED_area_tag_redraw(sa);
sbuts->preview = 1;
break;
+#ifdef WITH_FREESTYLE
+ case NC_LINESTYLE:
+ ED_area_tag_redraw(sa);
+ sbuts->preview = 1;
+ break;
+#endif
}
if (wmn->data == ND_KEYS)
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index 98e147413ff..b30f008e1bf 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -82,4 +82,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
blender_add_lib(bf_editor_space_file "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_file/SConscript b/source/blender/editors/space_file/SConscript
index c3f8c6667f7..6459f880bc4 100644
--- a/source/blender/editors/space_file/SConscript
+++ b/source/blender/editors/space_file/SConscript
@@ -48,6 +48,9 @@ if env['WITH_BF_TIFF']:
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+
if env['OURPLATFORM'] == 'linux':
cflags='-pthread'
incs += ' ../../../extern/binreloc/include'
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index a49b75477e4..142eb2214a1 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -1162,7 +1162,11 @@ void filelist_from_main(struct FileList *filelist)
if (filelist->dir[0] == 0) {
/* make directories */
+#ifdef WITH_FREESTYLE
+ filelist->numfiles = 25;
+#else
filelist->numfiles = 24;
+#endif
filelist->filelist = (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry));
for (a = 0; a < filelist->numfiles; a++) {
@@ -1193,6 +1197,9 @@ void filelist_from_main(struct FileList *filelist)
filelist->filelist[21].relname = BLI_strdup("Action");
filelist->filelist[22].relname = BLI_strdup("NodeTree");
filelist->filelist[23].relname = BLI_strdup("Speaker");
+#ifdef WITH_FREESTYLE
+ filelist->filelist[24].relname = BLI_strdup("FreestyleLineStyle");
+#endif
filelist_sort(filelist, FILE_SORT_ALPHA);
}
else {
diff --git a/source/blender/editors/space_nla/CMakeLists.txt b/source/blender/editors/space_nla/CMakeLists.txt
index aa3598e8e1f..32fb3850cee 100644
--- a/source/blender/editors/space_nla/CMakeLists.txt
+++ b/source/blender/editors/space_nla/CMakeLists.txt
@@ -50,4 +50,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
blender_add_lib(bf_editor_space_nla "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_nla/SConscript b/source/blender/editors/space_nla/SConscript
index 18c6392eee9..2316f37e661 100644
--- a/source/blender/editors/space_nla/SConscript
+++ b/source/blender/editors/space_nla/SConscript
@@ -37,4 +37,7 @@ defs = []
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+
env.BlenderLib ( 'bf_editors_space_nla', sources, Split(incs), defs, libtype=['core'], priority=[85] )
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index d75946c4317..e2eb1f030b3 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -142,6 +142,9 @@ static int nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA
case ANIMTYPE_DSPART:
case ANIMTYPE_DSMBALL:
case ANIMTYPE_DSARM:
+#ifdef WITH_FREESTYLE
+ case ANIMTYPE_DSLINESTYLE:
+#endif
case ANIMTYPE_DSSPK:
{
/* for these channels, we only do AnimData */
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 95e75d0e4fc..97581cefc2b 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -178,6 +178,9 @@ static int mouse_nla_channels(bAnimContext *ac, float x, int channel_index, shor
case ANIMTYPE_DSMESH:
case ANIMTYPE_DSTEX:
case ANIMTYPE_DSLAT:
+#ifdef WITH_FREESTYLE
+ case ANIMTYPE_DSLINESTYLE:
+#endif
case ANIMTYPE_DSSPK:
{
/* sanity checking... */
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index 35dd88c3209..462619a7e8b 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -75,4 +75,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
blender_add_lib(bf_editor_space_view3d "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript
index 578f06ada16..b775c5bba59 100644
--- a/source/blender/editors/space_view3d/SConscript
+++ b/source/blender/editors/space_view3d/SConscript
@@ -45,4 +45,7 @@ if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', '
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+
env.BlenderLib ( 'bf_editors_space_view3d', sources, Split(incs), defines = defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 6dd3ecca244..fc8d5d26455 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -127,7 +127,11 @@ typedef struct drawDMEdgesSel_userData {
} drawDMEdgesSel_userData;
typedef struct drawDMFacesSel_userData {
+#ifdef WITH_FREESTYLE
+ unsigned char *cols[4];
+#else
unsigned char *cols[3];
+#endif
DerivedMesh *dm;
BMEditMesh *em;
@@ -2301,6 +2305,23 @@ static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em);
}
+#ifdef WITH_FREESTYLE
+/* Draw only Freestyle feature edges */
+static DMDrawOption draw_dm_edges_freestyle__setDrawOptions(void *userData, int index)
+{
+ BMEdge *eed = EDBM_edge_at_index(userData, index);
+
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_FREESTYLE))
+ return DM_DRAW_OPTION_NORMAL;
+ else
+ return DM_DRAW_OPTION_SKIP;
+}
+
+static void draw_dm_edges_freestyle(BMEditMesh *em, DerivedMesh *dm)
+{
+ dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, em);
+}
+#endif
/* Draw faces with color set based on selection
* return 2 for the active face so it renders with stipple enabled */
@@ -2319,7 +2340,11 @@ static DMDrawOption draw_dm_faces_sel__setDrawOptions(void *userData, int index)
return DM_DRAW_OPTION_STIPPLE;
}
else {
+#ifdef WITH_FREESTYLE
+ col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : BM_elem_flag_test(efa, BM_ELEM_FREESTYLE) ? 3 : 0];
+#else
col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
+#endif
if (col[3] == 0)
return DM_DRAW_OPTION_SKIP;
glColor4ubv(col);
@@ -2350,8 +2375,13 @@ static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int
if (efa == data->efa_act || next_efa == data->efa_act)
return 0;
+#ifdef WITH_FREESTYLE
+ col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : BM_elem_flag_test(efa, BM_ELEM_FREESTYLE) ? 3 : 0];
+ next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : BM_elem_flag_test(next_efa, BM_ELEM_FREESTYLE) ? 3 : 0];
+#else
col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT) ? 1 : 0];
next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT) ? 1 : 0];
+#endif
if (col[3] == 0 || next_col[3] == 0)
return 0;
@@ -2360,8 +2390,13 @@ static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int
}
/* also draws the active face */
+#ifdef WITH_FREESTYLE
+static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
+ unsigned char *selCol, unsigned char *actCol, unsigned char *markCol, BMFace *efa_act)
+#else
static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol,
unsigned char *selCol, unsigned char *actCol, BMFace *efa_act)
+#endif
{
drawDMFacesSel_userData data;
data.dm = dm;
@@ -2369,6 +2404,9 @@ static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *ba
data.em = em;
data.cols[1] = selCol;
data.cols[2] = actCol;
+#ifdef WITH_FREESTYLE
+ data.cols[3] = markCol;
+#endif
data.efa_act = efa_act;
/* double lookup */
data.orig_index_mf_to_mpoly = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
@@ -2911,10 +2949,16 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
if (me->drawflag & ME_DRAWFACES) { /* transp faces */
unsigned char col1[4], col2[4], col3[4];
+#ifdef WITH_FREESTYLE
+ unsigned char col4[4];
+#endif
UI_GetThemeColor4ubv(TH_FACE, col1);
UI_GetThemeColor4ubv(TH_FACE_SELECT, col2);
UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
+#ifdef WITH_FREESTYLE
+ UI_GetThemeColor4ubv(TH_FREESTYLE_FACE_MARK, col4);
+#endif
glEnable(GL_BLEND);
glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
@@ -2923,7 +2967,14 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
if (check_object_draw_texture(scene, v3d, dt))
col1[3] = 0;
+#ifdef WITH_FREESTYLE
+ if (!(me->drawflag & ME_DRAW_FREESTYLE_FACE))
+ col4[3] = 0;
+
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
+#else
draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
+#endif
glDisable(GL_BLEND);
glDepthMask(1); /* restore write in zbuffer */
@@ -2932,14 +2983,19 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
/* even if draw faces is off it would be nice to draw the stipple face
* Make all other faces zero alpha except for the active
* */
- unsigned char col1[4], col2[4], col3[4];
- col1[3] = col2[3] = 0; /* don't draw */
+ /* col4 is only used by WITH_FREESTYLE, but keeping it here spares some #ifdef's... */
+ unsigned char col1[4], col2[4], col3[4], col4[4];
+ col1[3] = col2[3] = col4[3] = 0; /* don't draw */
UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, col3);
glEnable(GL_BLEND);
glDepthMask(0); /* disable write in zbuffer, needed for nice transp */
+#ifdef WITH_FREESTYLE
+ draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act);
+#else
draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act);
+#endif
glDisable(GL_BLEND);
glDepthMask(1); /* restore write in zbuffer */
@@ -2975,6 +3031,18 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d,
glLineWidth(1);
}
+#ifdef WITH_FREESTYLE
+ if(me->drawflag & ME_DRAW_FREESTYLE_EDGE) {
+ UI_ThemeColor(TH_FREESTYLE_EDGE_MARK);
+ glLineWidth(2);
+
+ draw_dm_edges_freestyle(em, cageDM);
+
+ glColor3ub(0,0,0);
+ glLineWidth(1);
+ }
+#endif
+
if (me->drawflag & ME_DRAWCREASES && CustomData_has_layer(&em->bm->edata, CD_CREASE)) {
draw_dm_creases(em, cageDM);
}
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
diff --git a/source/blender/makesdna/CMakeLists.txt b/source/blender/makesdna/CMakeLists.txt
index 638d618d785..c60907060f7 100644
--- a/source/blender/makesdna/CMakeLists.txt
+++ b/source/blender/makesdna/CMakeLists.txt
@@ -23,4 +23,8 @@
#
# ***** END GPL LICENSE BLOCK *****
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
add_subdirectory(intern)
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index 91e98181ab9..a3a3d80133f 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -212,6 +212,9 @@ typedef struct PreviewImage {
#define ID_WM MAKE_ID2('W', 'M') /* WindowManager */
#define ID_MC MAKE_ID2('M', 'C') /* MovieClip */
#define ID_MSK MAKE_ID2('M', 'S') /* Mask */
+/* #ifdef WITH_FREESTYLE */
+# define ID_LS MAKE_ID2('L', 'S') /* FreestyleLineStyle */
+/* #endif */
/* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */
#define ID_SEQ MAKE_ID2('S', 'Q')
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index f227af78dab..3f6e6c59137 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -556,6 +556,9 @@ typedef enum eDopeSheet_FilterFlag {
ADS_FILTER_NONTREE = (1 << 19),
ADS_FILTER_NOTEX = (1 << 20),
ADS_FILTER_NOSPK = (1 << 21),
+/* #ifdef WITH_FREESTYLE */
+ ADS_FILTER_NOLINESTYLE = (1 << 22),
+/* #endif */
/* NLA-specific filters */
ADS_FILTER_NLA_NOACT = (1 << 25), /* if the AnimData block has no NLA data, don't include to just show Action-line */
diff --git a/source/blender/makesdna/DNA_freestyle_types.h b/source/blender/makesdna/DNA_freestyle_types.h
new file mode 100644
index 00000000000..b5fe7ead936
--- /dev/null
+++ b/source/blender/makesdna/DNA_freestyle_types.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 __DNA_FREESTYLE_TYPES_H__
+#define __DNA_FREESTYLE_TYPES_H__
+
+#include "DNA_listBase.h"
+
+struct FreestyleLineStyle;
+
+/* FreestyleConfig::flags */
+#define FREESTYLE_SUGGESTIVE_CONTOURS_FLAG (1 << 0)
+#define FREESTYLE_RIDGES_AND_VALLEYS_FLAG (1 << 1)
+#define FREESTYLE_MATERIAL_BOUNDARIES_FLAG (1 << 2)
+#define FREESTYLE_FACE_SMOOTHNESS_FLAG (1 << 3)
+#define FREESTYLE_ADVANCED_OPTIONS_FLAG (1 << 4)
+#define FREESTYLE_CULLING (1 << 5)
+
+/* FreestyleConfig::mode */
+#define FREESTYLE_CONTROL_SCRIPT_MODE 1
+#define FREESTYLE_CONTROL_EDITOR_MODE 2
+
+/* FreestyleLineSet::flags */
+#define FREESTYLE_LINESET_CURRENT (1 << 0)
+#define FREESTYLE_LINESET_ENABLED (1 << 1)
+#define FREESTYLE_LINESET_FE_NOT (1 << 2)
+#define FREESTYLE_LINESET_FE_AND (1 << 3)
+#define FREESTYLE_LINESET_GR_NOT (1 << 4)
+#define FREESTYLE_LINESET_FM_NOT (1 << 5)
+#define FREESTYLE_LINESET_FM_BOTH (1 << 6)
+
+/* FreestyleLineSet::selection */
+#define FREESTYLE_SEL_VISIBILITY (1 << 0)
+#define FREESTYLE_SEL_EDGE_TYPES (1 << 1)
+#define FREESTYLE_SEL_GROUP (1 << 2)
+#define FREESTYLE_SEL_IMAGE_BORDER (1 << 3)
+#define FREESTYLE_SEL_FACE_MARK (1 << 4)
+
+/* FreestyleLineSet::edge_types, exclude_edge_types */
+#define FREESTYLE_FE_SILHOUETTE (1 << 0)
+#define FREESTYLE_FE_BORDER (1 << 1)
+#define FREESTYLE_FE_CREASE (1 << 2)
+#define FREESTYLE_FE_RIDGE_VALLEY (1 << 3)
+/* Note: FREESTYLE_FE_VALLEY = (1 << 4) is no longer used */
+#define FREESTYLE_FE_SUGGESTIVE_CONTOUR (1 << 5)
+#define FREESTYLE_FE_MATERIAL_BOUNDARY (1 << 6)
+#define FREESTYLE_FE_CONTOUR (1 << 7)
+#define FREESTYLE_FE_EXTERNAL_CONTOUR (1 << 8)
+#define FREESTYLE_FE_EDGE_MARK (1 << 9)
+
+/* FreestyleLineSet::qi */
+#define FREESTYLE_QI_VISIBLE 1
+#define FREESTYLE_QI_HIDDEN 2
+#define FREESTYLE_QI_RANGE 3
+
+/* FreestyleConfig::raycasting_algorithm */
+/* Defines should be replaced with ViewMapBuilder::visibility_algo */
+#define FREESTYLE_ALGO_REGULAR 1
+#define FREESTYLE_ALGO_FAST 2
+#define FREESTYLE_ALGO_VERYFAST 3
+#define FREESTYLE_ALGO_CULLED_ADAPTIVE_TRADITIONAL 4
+#define FREESTYLE_ALGO_ADAPTIVE_TRADITIONAL 5
+#define FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE 6
+#define FREESTYLE_ALGO_ADAPTIVE_CUMULATIVE 7
+
+typedef struct FreestyleLineSet {
+ struct FreestyleLineSet *next, *prev;
+
+ char name[32]; /* line set name */
+ int flags;
+
+ int selection; /* selection criteria */
+ short qi; /* quantitative invisibility */
+ short pad1;
+ int qi_start, qi_end;
+ int edge_types, exclude_edge_types; /* feature edge types */
+ int pad2;
+ struct Group *group; /* group of target objects */
+
+ struct FreestyleLineStyle *linestyle;
+} FreestyleLineSet;
+
+typedef struct FreestyleModuleConfig {
+ struct FreestyleModuleConfig *next, *prev;
+
+ char module_path[256];
+ short is_displayed;
+ short pad[3];
+} FreestyleModuleConfig;
+
+typedef struct FreestyleConfig {
+ ListBase modules;
+
+ int mode; /* scripting, editor */
+ int raycasting_algorithm; /* XXX deprecated */
+ int flags; /* suggestive contours, ridges/valleys, material boundaries */
+ float sphere_radius;
+ float dkr_epsilon;
+ float crease_angle; /* in radians! */
+
+ ListBase linesets;
+} FreestyleConfig;
+
+#endif
diff --git a/source/blender/makesdna/DNA_linestyle_types.h b/source/blender/makesdna/DNA_linestyle_types.h
new file mode 100644
index 00000000000..9a42c79c098
--- /dev/null
+++ b/source/blender/makesdna/DNA_linestyle_types.h
@@ -0,0 +1,410 @@
+/*
+ * ***** 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 __DNA_LINESTYLE_TYPES_H__
+#define __DNA_LINESTYLE_TYPES_H__
+
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+
+struct ColorBand;
+struct CurveMapping;
+
+typedef struct LineStyleModifier {
+ struct LineStyleModifier *next, *prev;
+
+ char name[32];
+ int type;
+ float influence;
+ int flags;
+ int blend;
+
+} LineStyleModifier;
+
+/* LineStyleModifier::type */
+#define LS_MODIFIER_ALONG_STROKE 1
+#define LS_MODIFIER_DISTANCE_FROM_CAMERA 2
+#define LS_MODIFIER_DISTANCE_FROM_OBJECT 3
+#define LS_MODIFIER_MATERIAL 4
+#define LS_MODIFIER_SAMPLING 5
+#define LS_MODIFIER_BEZIER_CURVE 6
+#define LS_MODIFIER_SINUS_DISPLACEMENT 7
+#define LS_MODIFIER_SPATIAL_NOISE 8
+#define LS_MODIFIER_PERLIN_NOISE_1D 9
+#define LS_MODIFIER_PERLIN_NOISE_2D 10
+#define LS_MODIFIER_BACKBONE_STRETCHER 11
+#define LS_MODIFIER_TIP_REMOVER 12
+#define LS_MODIFIER_CALLIGRAPHY 13
+#define LS_MODIFIER_POLYGONIZATION 14
+#define LS_MODIFIER_GUIDING_LINES 15
+#define LS_MODIFIER_BLUEPRINT 16
+#define LS_MODIFIER_2D_OFFSET 17
+#define LS_MODIFIER_2D_TRANSFORM 18
+#define LS_MODIFIER_NUM 19
+
+/* LineStyleModifier::flags */
+#define LS_MODIFIER_ENABLED 1
+#define LS_MODIFIER_EXPANDED 2
+
+/* flags (for color) */
+#define LS_MODIFIER_USE_RAMP 1
+
+/* flags (for alpha & thickness) */
+#define LS_MODIFIER_USE_CURVE 1
+#define LS_MODIFIER_INVERT 2
+
+/* blend (for alpha & thickness) */
+#define LS_VALUE_BLEND 0
+#define LS_VALUE_ADD 1
+#define LS_VALUE_MULT 2
+#define LS_VALUE_SUB 3
+#define LS_VALUE_DIV 4
+#define LS_VALUE_DIFF 5
+#define LS_VALUE_MIN 6
+#define LS_VALUE_MAX 7
+
+/* Along Stroke modifiers */
+
+typedef struct LineStyleColorModifier_AlongStroke {
+ struct LineStyleModifier modifier;
+
+ struct ColorBand *color_ramp;
+} LineStyleColorModifier_AlongStroke;
+
+typedef struct LineStyleAlphaModifier_AlongStroke {
+ struct LineStyleModifier modifier;
+
+ struct CurveMapping *curve;
+ int flags;
+ int pad;
+} LineStyleAlphaModifier_AlongStroke;
+
+typedef struct LineStyleThicknessModifier_AlongStroke {
+ struct LineStyleModifier modifier;
+
+ struct CurveMapping *curve;
+ int flags;
+ float value_min, value_max;
+ int pad;
+} LineStyleThicknessModifier_AlongStroke;
+
+/* Distance from Camera modifiers */
+
+typedef struct LineStyleColorModifier_DistanceFromCamera {
+ struct LineStyleModifier modifier;
+
+ struct ColorBand *color_ramp;
+ float range_min, range_max;
+} LineStyleColorModifier_DistanceFromCamera;
+
+typedef struct LineStyleAlphaModifier_DistanceFromCamera {
+ struct LineStyleModifier modifier;
+
+ struct CurveMapping *curve;
+ int flags;
+ float range_min, range_max;
+ int pad;
+} LineStyleAlphaModifier_DistanceFromCamera;
+
+typedef struct LineStyleThicknessModifier_DistanceFromCamera {
+ struct LineStyleModifier modifier;
+
+ struct CurveMapping *curve;
+ int flags;
+ float range_min, range_max;
+ float value_min, value_max;
+ int pad;
+} LineStyleThicknessModifier_DistanceFromCamera;
+
+/* Distance from Object modifiers */
+
+typedef struct LineStyleColorModifier_DistanceFromObject {
+ struct LineStyleModifier modifier;
+
+ struct Object *target;
+ struct ColorBand *color_ramp;
+ float range_min, range_max;
+} LineStyleColorModifier_DistanceFromObject;
+
+typedef struct LineStyleAlphaModifier_DistanceFromObject {
+ struct LineStyleModifier modifier;
+
+ struct Object *target;
+ struct CurveMapping *curve;
+ int flags;
+ float range_min, range_max;
+ int pad;
+} LineStyleAlphaModifier_DistanceFromObject;
+
+typedef struct LineStyleThicknessModifier_DistanceFromObject {
+ struct LineStyleModifier modifier;
+
+ struct Object *target;
+ struct CurveMapping *curve;
+ int flags;
+ float range_min, range_max;
+ float value_min, value_max;
+ int pad;
+} LineStyleThicknessModifier_DistanceFromObject;
+
+/* Material modifiers */
+
+/* mat_attr */
+#define LS_MODIFIER_MATERIAL_DIFF 1
+#define LS_MODIFIER_MATERIAL_DIFF_R 2
+#define LS_MODIFIER_MATERIAL_DIFF_G 3
+#define LS_MODIFIER_MATERIAL_DIFF_B 4
+#define LS_MODIFIER_MATERIAL_SPEC 5
+#define LS_MODIFIER_MATERIAL_SPEC_R 6
+#define LS_MODIFIER_MATERIAL_SPEC_G 7
+#define LS_MODIFIER_MATERIAL_SPEC_B 8
+#define LS_MODIFIER_MATERIAL_SPEC_HARD 9
+#define LS_MODIFIER_MATERIAL_ALPHA 10
+
+typedef struct LineStyleColorModifier_Material {
+ struct LineStyleModifier modifier;
+
+ struct ColorBand *color_ramp;
+ int flags;
+ int mat_attr;
+} LineStyleColorModifier_Material;
+
+typedef struct LineStyleAlphaModifier_Material {
+ struct LineStyleModifier modifier;
+
+ struct CurveMapping *curve;
+ int flags;
+ int mat_attr;
+} LineStyleAlphaModifier_Material;
+
+typedef struct LineStyleThicknessModifier_Material {
+ struct LineStyleModifier modifier;
+
+ struct CurveMapping *curve;
+ int flags;
+ float value_min, value_max;
+ int mat_attr;
+} LineStyleThicknessModifier_Material;
+
+/* Geometry modifiers */
+
+typedef struct LineStyleGeometryModifier_Sampling {
+ struct LineStyleModifier modifier;
+
+ float sampling;
+ int pad;
+} LineStyleGeometryModifier_Sampling;
+
+typedef struct LineStyleGeometryModifier_BezierCurve {
+ struct LineStyleModifier modifier;
+
+ float error;
+ int pad;
+} LineStyleGeometryModifier_BezierCurve;
+
+typedef struct LineStyleGeometryModifier_SinusDisplacement {
+ struct LineStyleModifier modifier;
+
+ float wavelength, amplitude, phase;
+ int pad;
+} LineStyleGeometryModifier_SinusDisplacement;
+
+/* LineStyleGeometryModifier_SpatialNoise::flags */
+#define LS_MODIFIER_SPATIAL_NOISE_SMOOTH 1
+#define LS_MODIFIER_SPATIAL_NOISE_PURERANDOM 2
+
+typedef struct LineStyleGeometryModifier_SpatialNoise {
+ struct LineStyleModifier modifier;
+
+ float amplitude, scale;
+ unsigned int octaves;
+ int flags;
+} LineStyleGeometryModifier_SpatialNoise;
+
+typedef struct LineStyleGeometryModifier_PerlinNoise1D {
+ struct LineStyleModifier modifier;
+
+ float frequency, amplitude;
+ float angle; /* in radians! */
+ unsigned int octaves;
+ int seed;
+ int pad1;
+} LineStyleGeometryModifier_PerlinNoise1D;
+
+typedef struct LineStyleGeometryModifier_PerlinNoise2D {
+ struct LineStyleModifier modifier;
+
+ float frequency, amplitude;
+ float angle; /* in radians! */
+ unsigned int octaves;
+ int seed;
+ int pad1;
+} LineStyleGeometryModifier_PerlinNoise2D;
+
+typedef struct LineStyleGeometryModifier_BackboneStretcher {
+ struct LineStyleModifier modifier;
+
+ float backbone_length;
+ int pad;
+} LineStyleGeometryModifier_BackboneStretcher;
+
+typedef struct LineStyleGeometryModifier_TipRemover {
+ struct LineStyleModifier modifier;
+
+ float tip_length;
+ int pad;
+} LineStyleGeometryModifier_TipRemover;
+
+typedef struct LineStyleGeometryModifier_Polygonalization {
+ struct LineStyleModifier modifier;
+
+ float error;
+ int pad;
+} LineStyleGeometryModifier_Polygonalization;
+
+typedef struct LineStyleGeometryModifier_GuidingLines {
+ struct LineStyleModifier modifier;
+
+ float offset;
+ int pad;
+} LineStyleGeometryModifier_GuidingLines;
+
+/* LineStyleGeometryModifier_BluePrintLines::shape */
+#define LS_MODIFIER_BLUEPRINT_CIRCLES 1
+#define LS_MODIFIER_BLUEPRINT_ELLIPSES 2
+#define LS_MODIFIER_BLUEPRINT_SQUARES 4
+
+typedef struct LineStyleGeometryModifier_Blueprint {
+ struct LineStyleModifier modifier;
+
+ int flags;
+ unsigned int rounds;
+ float backbone_length;
+ unsigned int random_radius;
+ unsigned int random_center;
+ unsigned int random_backbone;
+} LineStyleGeometryModifier_Blueprint;
+
+typedef struct LineStyleGeometryModifier_2DOffset {
+ struct LineStyleModifier modifier;
+
+ float start, end;
+ float x, y;
+} LineStyleGeometryModifier_2DOffset;
+
+/* LineStyleGeometryModifier_2DTransform::pivot */
+#define LS_MODIFIER_2D_TRANSFORM_PIVOT_CENTER 1
+#define LS_MODIFIER_2D_TRANSFORM_PIVOT_START 2
+#define LS_MODIFIER_2D_TRANSFORM_PIVOT_END 3
+#define LS_MODIFIER_2D_TRANSFORM_PIVOT_PARAM 4
+#define LS_MODIFIER_2D_TRANSFORM_PIVOT_ABSOLUTE 5
+
+typedef struct LineStyleGeometryModifier_2DTransform {
+ struct LineStyleModifier modifier;
+
+ int pivot;
+ float scale_x, scale_y;
+ float angle; /* in radians! */
+ float pivot_u;
+ float pivot_x, pivot_y;
+ int pad;
+} LineStyleGeometryModifier_2DTransform;
+
+/* Calligraphic thickness modifier */
+
+typedef struct LineStyleThicknessModifier_Calligraphy {
+ struct LineStyleModifier modifier;
+
+ float min_thickness, max_thickness;
+ float orientation; /* in radians! */
+ int pad;
+} LineStyleThicknessModifier_Calligraphy;
+
+/* FreestyleLineStyle::panel */
+#define LS_PANEL_STROKES 1
+#define LS_PANEL_COLOR 2
+#define LS_PANEL_ALPHA 3
+#define LS_PANEL_THICKNESS 4
+#define LS_PANEL_GEOMETRY 5
+#define LS_PANEL_MISC 6
+
+/* FreestyleLineStyle::flag */
+#define LS_DS_EXPAND (1 << 0) /* for animation editors */
+#define LS_SAME_OBJECT (1 << 1)
+#define LS_DASHED_LINE (1 << 2)
+#define LS_MATERIAL_BOUNDARY (1 << 3)
+#define LS_MIN_2D_LENGTH (1 << 4)
+#define LS_MAX_2D_LENGTH (1 << 5)
+#define LS_NO_CHAINING (1 << 6)
+#define LS_MIN_2D_ANGLE (1 << 7)
+#define LS_MAX_2D_ANGLE (1 << 8)
+#define LS_SPLIT_LENGTH (1 << 9)
+#define LS_SPLIT_PATTERN (1 << 10)
+
+/* FreestyleLineStyle::chaining */
+#define LS_CHAINING_PLAIN 1
+#define LS_CHAINING_SKETCHY 2
+
+/* FreestyleLineStyle::caps */
+#define LS_CAPS_BUTT 1
+#define LS_CAPS_ROUND 2
+#define LS_CAPS_SQUARE 3
+
+/* FreestyleLineStyle::thickness_position */
+#define LS_THICKNESS_CENTER 1
+#define LS_THICKNESS_INSIDE 2
+#define LS_THICKNESS_OUTSIDE 3
+#define LS_THICKNESS_RELATIVE 4 /* thickness_ratio is used */
+
+typedef struct FreestyleLineStyle {
+ ID id;
+ struct AnimData *adt;
+
+ float r, g, b, alpha;
+ float thickness;
+ int thickness_position;
+ float thickness_ratio;
+ int flag, caps;
+ int chaining;
+ unsigned int rounds;
+ float split_length;
+ float min_angle, max_angle; /* in radians, for splitting */
+ float min_length, max_length;
+ unsigned short split_dash1, split_gap1;
+ unsigned short split_dash2, split_gap2;
+ unsigned short split_dash3, split_gap3;
+ int pad;
+ unsigned short dash1, gap1, dash2, gap2, dash3, gap3;
+ int panel; /* for UI */
+
+ ListBase color_modifiers;
+ ListBase alpha_modifiers;
+ ListBase thickness_modifiers;
+ ListBase geometry_modifiers;
+} FreestyleLineStyle;
+
+#endif
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index fceea396507..544535303bd 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -177,6 +177,11 @@ typedef struct Material {
short shadowonly_flag; /* "shadowsonly" type */
short index; /* custom index for render passes */
+/* #ifdef WITH_FREESTYLE */
+ short vcol_alpha;
+ short pad4[3];
+/* #endif */
+
ListBase gpumaterial; /* runtime */
} Material;
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
index f2ee73392c7..042a353642a 100644
--- a/source/blender/makesdna/DNA_mesh_types.h
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -201,6 +201,11 @@ typedef struct TFace {
/* debug only option */
#define ME_DRAWEXTRA_INDICES (1 << 13)
+/* #ifdef WITH_FREESTYLE */
+#define ME_DRAW_FREESTYLE_EDGE (1 << 14)
+#define ME_DRAW_FREESTYLE_FACE (1 << 15)
+/* #endif */
+
/* Subsurf Type */
#define ME_CC_SUBSURF 0
#define ME_SIMPLE_SUBSURF 1
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
index ffa5e420fca..b85bdecee02 100644
--- a/source/blender/makesdna/DNA_meshdata_types.h
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -290,6 +290,9 @@ typedef struct MVertSkin {
#define ME_LOOSEEDGE (1<<7)
/* #define ME_SEAM_LAST (1<<8) */ /* UNUSED */
#define ME_SHARP (1<<9) /* only reason this flag remains a 'short' */
+/* #ifdef WITH_FREESTYLE */
+#define ME_FREESTYLE_EDGE (1<<10)
+/* #endif */
/* puno = vertexnormal (mface) */
#define ME_PROJXY 16
@@ -306,6 +309,9 @@ typedef struct MVertSkin {
/* flag (mface) */
#define ME_SMOOTH 1
#define ME_FACE_SEL 2
+/* #ifdef WITH_FREESTYLE */
+#define ME_FREESTYLE_FACE 4
+/* #endif */
/* flag ME_HIDE==16 is used here too */
#define ME_POLY_LOOP_PREV(mloop, mp, i) (&(mloop)[(mp)->loopstart + (((i) + (mp)->totloop - 1) % (mp)->totloop)])
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index b35323def29..dc36e88bc16 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -45,6 +45,9 @@ extern "C" {
#include "DNA_vec_types.h"
#include "DNA_listBase.h"
#include "DNA_ID.h"
+/* #ifdef WITH_FREESTYLE */
+#include "DNA_freestyle_types.h"
+/* #endif */
struct Object;
struct Brush;
@@ -187,6 +190,10 @@ typedef struct SceneRenderLayer {
int samples;
int pad;
+
+/* #ifdef WITH_FREESTYLE */
+ struct FreestyleConfig freestyleConfig;
+/* #endif */
} SceneRenderLayer;
/* srl->layflag */
@@ -196,7 +203,10 @@ typedef struct SceneRenderLayer {
#define SCE_LAY_EDGE 8
#define SCE_LAY_SKY 16
#define SCE_LAY_STRAND 32
- /* flags between 32 and 0x8000 are set to 1 already, for future options */
+/* #ifdef WITH_FREESTYLE */
+#define SCE_LAY_FRS 64
+/* #endif */
+ /* flags between 64 and 0x8000 are set to 1 already, for future options */
#define SCE_LAY_ALL_Z 0x8000
#define SCE_LAY_XOR 0x10000
@@ -541,6 +551,12 @@ typedef struct RenderData {
float pad2;
struct Text *dometext DNA_DEPRECATED; // XXX deprecated since 2.5
+/* #ifdef WITH_FREESTYLE */
+ /* Freestyle line thickness options */
+ int line_thickness_mode;
+ float unit_line_thickness; /* in pixels */
+/* #endif */
+
/* render engine */
char engine[32];
} RenderData;
@@ -1332,6 +1348,12 @@ typedef struct Scene {
/* simplify_flag */
#define R_SIMPLE_NO_TRIANGULATE 1
+/* #ifdef WITH_FREESTYLE */
+/* line_thickness_mode */
+#define R_LINE_THICKNESS_ABSOLUTE 1
+#define R_LINE_THICKNESS_RELATIVE 2
+/* #endif */
+
/* sequencer seq_prev_type seq_rend_type */
@@ -1534,6 +1556,9 @@ typedef enum SculptFlags {
#define EDGE_MODE_TAG_SHARP 2
#define EDGE_MODE_TAG_CREASE 3
#define EDGE_MODE_TAG_BEVEL 4
+/* #ifdef WITH_FREESTYLE */
+#define EDGE_MODE_TAG_FREESTYLE 5
+/* #endif */
/* toolsettings->gpencil_flags */
#define GP_TOOL_FLAG_PAINTSESSIONS_ON (1<<0)
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 1dfcff4a3c4..4c1d2c638b9 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -180,6 +180,7 @@ typedef enum eSpaceButtons_Context {
BCONTEXT_MODIFIER = 10,
BCONTEXT_CONSTRAINT = 11,
BCONTEXT_BONE_CONSTRAINT = 12,
+ BCONTEXT_RENDER_LAYER = 13,
/* always as last... */
BCONTEXT_TOT
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 861d44b214e..c049c981be5 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -240,6 +240,9 @@ typedef struct ThemeSpace {
char bone_solid[4], bone_pose[4], bone_pose_active[4];
char strip[4], strip_select[4];
char cframe[4];
+/* #ifdef WITH_FREESTYLE */
+ char freestyle_edge_mark[4], freestyle_face_mark[4];
+/* #endif */
char nurb_uline[4], nurb_vline[4];
char act_spline[4], nurb_sel_uline[4], nurb_sel_vline[4], lastsel_point[4];
diff --git a/source/blender/makesdna/SConscript b/source/blender/makesdna/SConscript
index a6520a6c03e..d4eabb03b13 100644
--- a/source/blender/makesdna/SConscript
+++ b/source/blender/makesdna/SConscript
@@ -28,10 +28,14 @@
Import ('env')
objs = []
+defs = []
o = SConscript('intern/SConscript')
objs += o
incs = '#/intern/guardedalloc .'
-env.BlenderLib ( 'bf_dna', objs, Split(incs), [], libtype=['core','player'], priority = [215,200] )
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+
+env.BlenderLib ( 'bf_dna', objs, Split(incs), defs, libtype=['core','player'], priority = [215,200] )
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
index 1dd1d7e8f87..0632564b998 100644
--- a/source/blender/makesdna/intern/CMakeLists.txt
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -34,6 +34,9 @@ blender_include_dirs(
..
)
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
# -----------------------------------------------------------------------------
# Build makesdna executable
diff --git a/source/blender/makesdna/intern/SConscript b/source/blender/makesdna/intern/SConscript
index add9611866d..8fd5b67c44b 100644
--- a/source/blender/makesdna/intern/SConscript
+++ b/source/blender/makesdna/intern/SConscript
@@ -39,6 +39,9 @@ root_build_dir=normpath(env['BF_BUILDDIR'])
source_files = ['makesdna.c']
header_files = env.Glob('../*.h')
+if env['WITH_BF_FREESTYLE']:
+ defines.append('WITH_FREESTYLE')
+
makesdna_tool = env.Clone()
dna = env.Clone()
makesdna_tool.Append(CCFLAGS = '-DBASE_HEADER="\\"source/blender/makesdna/\\"" ')
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
index 31ff0ffa8fe..dd65ce53b92 100644
--- a/source/blender/makesdna/intern/makesdna.c
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -134,6 +134,10 @@ static const char *includefiles[] = {
"DNA_dynamicpaint_types.h",
"DNA_mask_types.h",
"DNA_rigidbody_types.h",
+/* #ifdef WITH_FREESTYLE */
+ "DNA_freestyle_types.h",
+ "DNA_linestyle_types.h",
+/* #endif */
/* empty string to indicate end of includefiles */
""
@@ -1264,4 +1268,8 @@ int main(int argc, char **argv)
#include "DNA_dynamicpaint_types.h"
#include "DNA_mask_types.h"
#include "DNA_rigidbody_types.h"
+/* #ifdef WITH_FREESTYLE */
+#include "DNA_freestyle_types.h"
+#include "DNA_linestyle_types.h"
+/* #endif */
/* end of list */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index e8c1a5d0642..821b429e75c 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -243,6 +243,12 @@ extern StructRNA RNA_FluidFluidSettings;
extern StructRNA RNA_FluidSettings;
extern StructRNA RNA_FluidSimulationModifier;
extern StructRNA RNA_FollowPathConstraint;
+#ifdef WITH_FREESTYLE
+extern StructRNA RNA_FreestyleLineStyle;
+extern StructRNA RNA_FreestyleLineSet;
+extern StructRNA RNA_FreestyleModuleSettings;
+extern StructRNA RNA_FreestyleSettings;
+#endif
extern StructRNA RNA_Function;
extern StructRNA RNA_GPencilFrame;
extern StructRNA RNA_GPencilLayer;
@@ -299,6 +305,39 @@ extern StructRNA RNA_LimitDistanceConstraint;
extern StructRNA RNA_LimitLocationConstraint;
extern StructRNA RNA_LimitRotationConstraint;
extern StructRNA RNA_LimitScaleConstraint;
+#ifdef WITH_FREESTYLE
+extern StructRNA RNA_LineStyleAlphaModifier;
+extern StructRNA RNA_LineStyleAlphaModifier_AlongStroke;
+extern StructRNA RNA_LineStyleAlphaModifier_DistanceFromCamera;
+extern StructRNA RNA_LineStyleAlphaModifier_DistanceFromObject;
+extern StructRNA RNA_LineStyleAlphaModifier_Material;
+extern StructRNA RNA_LineStyleColorModifier;
+extern StructRNA RNA_LineStyleColorModifier_AlongStroke;
+extern StructRNA RNA_LineStyleColorModifier_DistanceFromCamera;
+extern StructRNA RNA_LineStyleColorModifier_DistanceFromObject;
+extern StructRNA RNA_LineStyleColorModifier_Material;
+extern StructRNA RNA_LineStyleGeometryModifier;
+extern StructRNA RNA_LineStyleGeometryModifier_2DOffset;
+extern StructRNA RNA_LineStyleGeometryModifier_2DTransform;
+extern StructRNA RNA_LineStyleGeometryModifier_BackboneStretcher;
+extern StructRNA RNA_LineStyleGeometryModifier_BezierCurve;
+extern StructRNA RNA_LineStyleGeometryModifier_Blueprint;
+extern StructRNA RNA_LineStyleGeometryModifier_GuidingLines;
+extern StructRNA RNA_LineStyleGeometryModifier_PerlinNoise1D;
+extern StructRNA RNA_LineStyleGeometryModifier_PerlinNoise2D;
+extern StructRNA RNA_LineStyleGeometryModifier_Polygonalization;
+extern StructRNA RNA_LineStyleGeometryModifier_Sampling;
+extern StructRNA RNA_LineStyleGeometryModifier_SinusDisplacement;
+extern StructRNA RNA_LineStyleGeometryModifier_SpatialNoise;
+extern StructRNA RNA_LineStyleGeometryModifier_TipRemover;
+extern StructRNA RNA_LineStyleModifier;
+extern StructRNA RNA_LineStyleThicknessModifier;
+extern StructRNA RNA_LineStyleThicknessModifier_AlongStroke;
+extern StructRNA RNA_LineStyleThicknessModifier_Calligraphy;
+extern StructRNA RNA_LineStyleThicknessModifier_DistanceFromCamera;
+extern StructRNA RNA_LineStyleThicknessModifier_DistanceFromObject;
+extern StructRNA RNA_LineStyleThicknessModifier_Material;
+#endif
extern StructRNA RNA_LockedTrackConstraint;
extern StructRNA RNA_Macro;
extern StructRNA RNA_MagicTexture;
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index eabf0391c01..8038f97ec54 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -144,6 +144,13 @@ extern EnumPropertyItem clip_editor_mode_items[];
extern EnumPropertyItem icon_items[];
extern EnumPropertyItem uilist_layout_type_items[];
+#ifdef WITH_FREESTYLE
+extern EnumPropertyItem linestyle_color_modifier_type_items[];
+extern EnumPropertyItem linestyle_alpha_modifier_type_items[];
+extern EnumPropertyItem linestyle_thickness_modifier_type_items[];
+extern EnumPropertyItem linestyle_geometry_modifier_type_items[];
+#endif
+
struct bContext;
struct PointerRNA;
struct PropertyRNA;
diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript
index 47750617e55..f3beee8bc14 100644
--- a/source/blender/makesrna/SConscript
+++ b/source/blender/makesrna/SConscript
@@ -108,6 +108,10 @@ if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', '
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ incs += ' ../freestyle'
+ defs.append('WITH_FREESTYLE')
+
rnalib = env.BlenderLib ( 'bf_rna', objs, Split(incs), defines=defs, libtype=['core','player'], priority = [165,20] )
Return ('rnalib')
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 210857a4690..2fb1f0bf6b4 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -93,6 +93,12 @@ set(DEFSRC
rna_world.c
)
+if(WITH_FREESTYLE)
+ list(APPEND DEFSRC
+ rna_linestyle.c
+ )
+endif()
+
set(APISRC
rna_action_api.c
rna_actuator_api.c
@@ -268,6 +274,13 @@ blender_include_dirs(
../../../../intern/smoke/extern
)
+if(WITH_FREESTYLE)
+ blender_include_dirs(
+ ../../freestyle
+ )
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
blender_include_dirs_sys(
${GLEW_INCLUDE_PATH}
)
diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript
index 33d43e1e019..e159b9fd8eb 100644
--- a/source/blender/makesrna/intern/SConscript
+++ b/source/blender/makesrna/intern/SConscript
@@ -38,6 +38,8 @@ root_build_dir=normpath(env['BF_BUILDDIR'])
source_files = env.Glob('*.c')
source_files.remove('rna_access.c')
+if not env['WITH_BF_FREESTYLE']:
+ source_files.remove('rna_linestyle.c')
generated_files = source_files[:]
generated_files.remove('rna_define.c')
@@ -136,6 +138,10 @@ if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', '
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+ incs += ' ../../freestyle'
+
if not env['BF_DEBUG']:
defs.append('NDEBUG')
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 41b6e3e5ca6..b4bf241815d 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3245,6 +3245,9 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_key.c", NULL, RNA_def_key},
{"rna_lamp.c", NULL, RNA_def_lamp},
{"rna_lattice.c", NULL, RNA_def_lattice},
+#ifdef WITH_FREESTYLE
+ {"rna_linestyle.c", NULL, RNA_def_linestyle},
+#endif
{"rna_main.c", "rna_main_api.c", RNA_def_main},
{"rna_material.c", "rna_material_api.c", RNA_def_material},
{"rna_mesh.c", "rna_mesh_api.c", RNA_def_mesh},
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 184ee23b488..18281d4d251 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -56,6 +56,9 @@ EnumPropertyItem id_type_items[] = {
{ID_KE, "KEY", ICON_SHAPEKEY_DATA, "Key", ""},
{ID_LA, "LAMP", ICON_LAMP_DATA, "Lamp", ""},
{ID_LI, "LIBRARY", ICON_LIBRARY_DATA_DIRECT, "Library", ""},
+#ifdef WITH_FREESTYLE
+ {ID_LS, "LINESTYLE", ICON_PARTICLE_DATA, "FreestyleLineStyle", ""}, /* FIXME proper icon */
+#endif
{ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""},
{ID_MA, "MATERIAL", ICON_MATERIAL_DATA, "Material", ""},
{ID_MB, "META", ICON_META_DATA, "MetaBall", ""},
@@ -131,6 +134,9 @@ short RNA_type_to_ID_code(StructRNA *type)
if (RNA_struct_is_a(type, &RNA_Key)) return ID_KE;
if (RNA_struct_is_a(type, &RNA_Lamp)) return ID_LA;
if (RNA_struct_is_a(type, &RNA_Library)) return ID_LI;
+#ifdef WITH_FREESTYLE
+ if (RNA_struct_is_a(type, &RNA_FreestyleLineStyle)) return ID_LS;
+#endif
if (RNA_struct_is_a(type, &RNA_Lattice)) return ID_LT;
if (RNA_struct_is_a(type, &RNA_Material)) return ID_MA;
if (RNA_struct_is_a(type, &RNA_MetaBall)) return ID_MB;
@@ -167,6 +173,9 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_KE: return &RNA_Key;
case ID_LA: return &RNA_Lamp;
case ID_LI: return &RNA_Library;
+#ifdef WITH_FREESTYLE
+ case ID_LS: return &RNA_FreestyleLineStyle;
+#endif
case ID_LT: return &RNA_Lattice;
case ID_MA: return &RNA_Material;
case ID_MB: return &RNA_MetaBall;
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index bf6faa3f2cc..da8aa15cf2e 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -397,6 +397,14 @@ static void rna_def_dopesheet(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_LAMP_DATA, 0);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+#ifdef WITH_FREESTYLE
+ prop = RNA_def_property(srna, "show_linestyles", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NOLINESTYLE);
+ RNA_def_property_ui_text(prop, "Display Line Style", "Include visualization of Line Style related Animation data");
+ RNA_def_property_ui_icon(prop, ICON_BRUSH_DATA, 0); /* FIXME */
+ RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+#endif
+
prop = RNA_def_property(srna, "show_textures", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "filterflag", ADS_FILTER_NOTEX);
RNA_def_property_ui_text(prop, "Display Texture", "Include visualization of texture related animation data");
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index c70dc285b20..f32f28e8143 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -56,6 +56,9 @@
#include "BKE_node.h"
#include "BKE_sequencer.h"
#include "BKE_texture.h"
+#ifdef WITH_FREESTYLE
+# include "BKE_linestyle.h"
+#endif
#include "ED_node.h"
@@ -188,6 +191,16 @@ static char *rna_ColorRamp_path(PointerRNA *ptr)
/* everything else just uses 'color_ramp' */
path = BLI_strdup("color_ramp");
break;
+
+#ifdef WITH_FREESTYLE
+ case ID_LS:
+ {
+ char *path = FRS_path_from_ID_to_color_ramp((FreestyleLineStyle *)id, (ColorBand *)ptr->data);
+ if (path)
+ return path;
+ break;
+ }
+#endif
}
}
else {
@@ -259,6 +272,22 @@ static char *rna_ColorRampElement_path(PointerRNA *ptr)
}
break;
+#ifdef WITH_FREESTYLE
+ case ID_LS:
+ {
+ ListBase listbase;
+ LinkData *link;
+
+ FRS_list_modifier_color_ramps((FreestyleLineStyle *)id, &listbase);
+ for (link = (LinkData *)listbase.first; link; link = link->next) {
+ RNA_pointer_create(id, &RNA_ColorRamp, link->data, &ramp_ptr);
+ COLRAMP_GETPATH;
+ }
+ BLI_freelistN(&listbase);
+ break;
+ }
+#endif
+
default: /* everything else should have a "color_ramp" property */
{
/* create pointer to the ID block, and try to resolve "color_ramp" pointer */
@@ -310,6 +339,15 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
WM_main_add_notifier(NC_TEXTURE, tex);
}
break;
+#ifdef WITH_FREESTYLE
+ case ID_LS:
+ {
+ FreestyleLineStyle *linestyle= ptr->id.data;
+
+ WM_main_add_notifier(NC_LINESTYLE, linestyle);
+ break;
+ }
+#endif
default:
break;
}
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 76947d856f8..99dd0a860d2 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -151,6 +151,9 @@ void RNA_def_image(struct BlenderRNA *brna);
void RNA_def_key(struct BlenderRNA *brna);
void RNA_def_lamp(struct BlenderRNA *brna);
void RNA_def_lattice(struct BlenderRNA *brna);
+#ifdef WITH_FREESTYLE
+void RNA_def_linestyle(struct BlenderRNA *brna);
+#endif
void RNA_def_main(struct BlenderRNA *brna);
void RNA_def_material(struct BlenderRNA *brna);
void RNA_def_mesh(struct BlenderRNA *brna);
@@ -311,6 +314,9 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop);
+#ifdef WITH_FREESTYLE
+void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop);
+#endif
/* ID Properties */
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
new file mode 100644
index 00000000000..370b72126b8
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -0,0 +1,1146 @@
+/*
+ * ***** 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.
+ *
+ * Contributor(s): Blender Foundation (2008).
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_linestyle.c
+ * \ingroup RNA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "DNA_linestyle_types.h"
+#include "DNA_material_types.h"
+#include "DNA_texture_types.h"
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+EnumPropertyItem linestyle_color_modifier_type_items[] = {
+ {LS_MODIFIER_ALONG_STROKE, "ALONG_STROKE", ICON_MODIFIER, "Along Stroke", ""},
+ {LS_MODIFIER_DISTANCE_FROM_CAMERA, "DISTANCE_FROM_CAMERA", ICON_MODIFIER, "Distance from Camera", ""},
+ {LS_MODIFIER_DISTANCE_FROM_OBJECT, "DISTANCE_FROM_OBJECT", ICON_MODIFIER, "Distance from Object", ""},
+ {LS_MODIFIER_MATERIAL, "MATERIAL", ICON_MODIFIER, "Material", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem linestyle_alpha_modifier_type_items[] = {
+ {LS_MODIFIER_ALONG_STROKE, "ALONG_STROKE", ICON_MODIFIER, "Along Stroke", ""},
+ {LS_MODIFIER_DISTANCE_FROM_CAMERA, "DISTANCE_FROM_CAMERA", ICON_MODIFIER, "Distance from Camera", ""},
+ {LS_MODIFIER_DISTANCE_FROM_OBJECT, "DISTANCE_FROM_OBJECT", ICON_MODIFIER, "Distance from Object", ""},
+ {LS_MODIFIER_MATERIAL, "MATERIAL", ICON_MODIFIER, "Material", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem linestyle_thickness_modifier_type_items[] = {
+ {LS_MODIFIER_ALONG_STROKE, "ALONG_STROKE", ICON_MODIFIER, "Along Stroke", ""},
+ {LS_MODIFIER_CALLIGRAPHY, "CALLIGRAPHY", ICON_MODIFIER, "Calligraphy", ""},
+ {LS_MODIFIER_DISTANCE_FROM_CAMERA, "DISTANCE_FROM_CAMERA", ICON_MODIFIER, "Distance from Camera", ""},
+ {LS_MODIFIER_DISTANCE_FROM_OBJECT, "DISTANCE_FROM_OBJECT", ICON_MODIFIER, "Distance from Object", ""},
+ {LS_MODIFIER_MATERIAL, "MATERIAL", ICON_MODIFIER, "Material", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+EnumPropertyItem linestyle_geometry_modifier_type_items[] = {
+ {LS_MODIFIER_2D_OFFSET, "2D_OFFSET", ICON_MODIFIER, "2D Offset", ""},
+ {LS_MODIFIER_2D_TRANSFORM, "2D_TRANSFORM", ICON_MODIFIER, "2D Transform", ""},
+ {LS_MODIFIER_BACKBONE_STRETCHER, "BACKBONE_STRETCHER", ICON_MODIFIER, "Backbone Stretcher", ""},
+ {LS_MODIFIER_BEZIER_CURVE, "BEZIER_CURVE", ICON_MODIFIER, "Bezier Curve", ""},
+ {LS_MODIFIER_BLUEPRINT, "BLUEPRINT", ICON_MODIFIER, "Blueprint", ""},
+ {LS_MODIFIER_GUIDING_LINES, "GUIDING_LINES", ICON_MODIFIER, "Guiding Lines", ""},
+ {LS_MODIFIER_PERLIN_NOISE_1D, "PERLIN_NOISE_1D", ICON_MODIFIER, "Perlin Noise 1D", ""},
+ {LS_MODIFIER_PERLIN_NOISE_2D, "PERLIN_NOISE_2D", ICON_MODIFIER, "Perlin Noise 2D", ""},
+ {LS_MODIFIER_POLYGONIZATION, "POLYGONIZATION", ICON_MODIFIER, "Polygonization", ""},
+ {LS_MODIFIER_SAMPLING, "SAMPLING", ICON_MODIFIER, "Sampling", ""},
+ {LS_MODIFIER_SINUS_DISPLACEMENT, "SINUS_DISPLACEMENT", ICON_MODIFIER, "Sinus Displacement", ""},
+ {LS_MODIFIER_SPATIAL_NOISE, "SPATIAL_NOISE", ICON_MODIFIER, "Spatial Noise", ""},
+ {LS_MODIFIER_TIP_REMOVER, "TIP_REMOVER", ICON_MODIFIER, "Tip Remover", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_linestyle.h"
+
+static StructRNA *rna_LineStyle_color_modifier_refine(struct PointerRNA *ptr)
+{
+ LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ return &RNA_LineStyleColorModifier_AlongStroke;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ return &RNA_LineStyleColorModifier_DistanceFromCamera;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ return &RNA_LineStyleColorModifier_DistanceFromObject;
+ case LS_MODIFIER_MATERIAL:
+ return &RNA_LineStyleColorModifier_Material;
+ default:
+ return &RNA_LineStyleColorModifier;
+ }
+}
+
+static StructRNA *rna_LineStyle_alpha_modifier_refine(struct PointerRNA *ptr)
+{
+ LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ return &RNA_LineStyleAlphaModifier_AlongStroke;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ return &RNA_LineStyleAlphaModifier_DistanceFromCamera;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ return &RNA_LineStyleAlphaModifier_DistanceFromObject;
+ case LS_MODIFIER_MATERIAL:
+ return &RNA_LineStyleAlphaModifier_Material;
+ default:
+ return &RNA_LineStyleAlphaModifier;
+ }
+}
+
+static StructRNA *rna_LineStyle_thickness_modifier_refine(struct PointerRNA *ptr)
+{
+ LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+
+ switch (m->type) {
+ case LS_MODIFIER_ALONG_STROKE:
+ return &RNA_LineStyleThicknessModifier_AlongStroke;
+ case LS_MODIFIER_DISTANCE_FROM_CAMERA:
+ return &RNA_LineStyleThicknessModifier_DistanceFromCamera;
+ case LS_MODIFIER_DISTANCE_FROM_OBJECT:
+ return &RNA_LineStyleThicknessModifier_DistanceFromObject;
+ case LS_MODIFIER_MATERIAL:
+ return &RNA_LineStyleThicknessModifier_Material;
+ case LS_MODIFIER_CALLIGRAPHY:
+ return &RNA_LineStyleThicknessModifier_Calligraphy;
+ default:
+ return &RNA_LineStyleThicknessModifier;
+ }
+}
+
+static StructRNA *rna_LineStyle_geometry_modifier_refine(struct PointerRNA *ptr)
+{
+ LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+
+ switch (m->type) {
+ case LS_MODIFIER_SAMPLING:
+ return &RNA_LineStyleGeometryModifier_Sampling;
+ case LS_MODIFIER_BEZIER_CURVE:
+ return &RNA_LineStyleGeometryModifier_BezierCurve;
+ case LS_MODIFIER_SINUS_DISPLACEMENT:
+ return &RNA_LineStyleGeometryModifier_SinusDisplacement;
+ case LS_MODIFIER_SPATIAL_NOISE:
+ return &RNA_LineStyleGeometryModifier_SpatialNoise;
+ case LS_MODIFIER_PERLIN_NOISE_1D:
+ return &RNA_LineStyleGeometryModifier_PerlinNoise1D;
+ case LS_MODIFIER_PERLIN_NOISE_2D:
+ return &RNA_LineStyleGeometryModifier_PerlinNoise2D;
+ case LS_MODIFIER_BACKBONE_STRETCHER:
+ return &RNA_LineStyleGeometryModifier_BackboneStretcher;
+ case LS_MODIFIER_TIP_REMOVER:
+ return &RNA_LineStyleGeometryModifier_TipRemover;
+ case LS_MODIFIER_POLYGONIZATION:
+ return &RNA_LineStyleGeometryModifier_Polygonalization;
+ case LS_MODIFIER_GUIDING_LINES:
+ return &RNA_LineStyleGeometryModifier_GuidingLines;
+ case LS_MODIFIER_BLUEPRINT:
+ return &RNA_LineStyleGeometryModifier_Blueprint;
+ case LS_MODIFIER_2D_OFFSET:
+ return &RNA_LineStyleGeometryModifier_2DOffset;
+ case LS_MODIFIER_2D_TRANSFORM:
+ return &RNA_LineStyleGeometryModifier_2DTransform;
+ default:
+ return &RNA_LineStyleGeometryModifier;
+ }
+}
+
+static char *rna_LineStyle_color_modifier_path(PointerRNA *ptr)
+{
+ return BLI_sprintfN("color_modifiers[\"%s\"]", ((LineStyleModifier *)ptr->data)->name);
+}
+
+static char *rna_LineStyle_alpha_modifier_path(PointerRNA *ptr)
+{
+ return BLI_sprintfN("alpha_modifiers[\"%s\"]", ((LineStyleModifier *)ptr->data)->name);
+}
+
+static char *rna_LineStyle_thickness_modifier_path(PointerRNA *ptr)
+{
+ return BLI_sprintfN("thickness_modifiers[\"%s\"]", ((LineStyleModifier *)ptr->data)->name);
+}
+
+static char *rna_LineStyle_geometry_modifier_path(PointerRNA *ptr)
+{
+ return BLI_sprintfN("geometry_modifiers[\"%s\"]", ((LineStyleModifier *)ptr->data)->name);
+}
+
+static void rna_LineStyleColorModifier_name_set(PointerRNA *ptr, const char *value)
+{
+ FreestyleLineStyle *linestyle = (FreestyleLineStyle *)ptr->id.data;
+ LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+
+ BLI_strncpy_utf8(m->name, value, sizeof(m->name));
+ BLI_uniquename(&linestyle->color_modifiers, m, "ColorModifier", '.',
+ offsetof(LineStyleModifier, name), sizeof(m->name));
+}
+
+static void rna_LineStyleAlphaModifier_name_set(PointerRNA *ptr, const char *value)
+{
+ FreestyleLineStyle *linestyle = (FreestyleLineStyle *)ptr->id.data;
+ LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+
+ BLI_strncpy_utf8(m->name, value, sizeof(m->name));
+ BLI_uniquename(&linestyle->alpha_modifiers, m, "AlphaModifier", '.',
+ offsetof(LineStyleModifier, name), sizeof(m->name));
+}
+
+static void rna_LineStyleThicknessModifier_name_set(PointerRNA *ptr, const char *value)
+{
+ FreestyleLineStyle *linestyle = (FreestyleLineStyle *)ptr->id.data;
+ LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+
+ BLI_strncpy_utf8(m->name, value, sizeof(m->name));
+ BLI_uniquename(&linestyle->thickness_modifiers, m, "ThicknessModifier", '.',
+ offsetof(LineStyleModifier, name), sizeof(m->name));
+}
+
+static void rna_LineStyleGeometryModifier_name_set(PointerRNA *ptr, const char *value)
+{
+ FreestyleLineStyle *linestyle = (FreestyleLineStyle *)ptr->id.data;
+ LineStyleModifier *m = (LineStyleModifier *)ptr->data;
+
+ BLI_strncpy_utf8(m->name, value, sizeof(m->name));
+ BLI_uniquename(&linestyle->geometry_modifiers, m, "GeometryModifier", '.',
+ offsetof(LineStyleModifier, name), sizeof(m->name));
+}
+
+#else
+
+#include "BLI_math.h"
+
+static void rna_def_modifier_type_common(StructRNA *srna, EnumPropertyItem *modifier_type_items,
+ char *set_name_func, int blend, int color)
+{
+ PropertyRNA *prop;
+
+ /* TODO: Check this is not already defined somewhere else, e.g. in nodes... */
+ static EnumPropertyItem value_blend_items[] = {
+ {LS_VALUE_BLEND, "MIX", 0, "Mix", ""},
+ {LS_VALUE_ADD, "ADD", 0, "Add", ""},
+ {LS_VALUE_SUB, "SUBTRACT", 0, "Subtract", ""},
+ {LS_VALUE_MULT, "MULTIPLY", 0, "Multiply", ""},
+ {LS_VALUE_DIV, "DIVIDE", 0, "Divide", ""},
+ {LS_VALUE_DIFF, "DIFFERENCE", 0, "Divide", ""},
+ {LS_VALUE_MIN, "MININUM", 0, "Minimum", ""},
+ {LS_VALUE_MAX, "MAXIMUM", 0, "Maximum", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "modifier.type");
+ RNA_def_property_enum_items(prop, modifier_type_items);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Modifier Type", "Type of the modifier");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "modifier.name");
+ RNA_def_property_string_funcs(prop, NULL, NULL, set_name_func);
+ RNA_def_property_ui_text(prop, "Modifier Name", "Name of the modifier");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_struct_name_property(srna, prop);
+
+ if (blend) {
+ prop = RNA_def_property(srna, "blend", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "modifier.blend");
+ RNA_def_property_enum_items(prop, (color) ? ramp_blend_items : value_blend_items);
+ RNA_def_property_ui_text(prop, "Blend", "Specify how the modifier value is blended into the base value");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "modifier.influence");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Influence", "Influence factor by which the modifier changes the property");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ }
+
+ prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "modifier.flags", LS_MODIFIER_ENABLED);
+ RNA_def_property_ui_text(prop, "Use", "Enable or disable this modifier during stroke rendering");
+
+ prop = RNA_def_property(srna, "expanded", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "modifier.flags", LS_MODIFIER_EXPANDED);
+ RNA_def_property_ui_text(prop, "Expanded", "True if the modifier tab is expanded");
+}
+
+static void rna_def_color_modifier(StructRNA *srna)
+{
+ rna_def_modifier_type_common(srna, linestyle_color_modifier_type_items,
+ "rna_LineStyleColorModifier_name_set", TRUE, TRUE);
+}
+
+static void rna_def_alpha_modifier(StructRNA *srna)
+{
+ rna_def_modifier_type_common(srna, linestyle_alpha_modifier_type_items,
+ "rna_LineStyleAlphaModifier_name_set", TRUE, FALSE);
+}
+
+static void rna_def_thickness_modifier(StructRNA *srna)
+{
+ rna_def_modifier_type_common(srna, linestyle_thickness_modifier_type_items,
+ "rna_LineStyleThicknessModifier_name_set", TRUE, FALSE);
+}
+
+static void rna_def_geometry_modifier(StructRNA *srna)
+{
+ rna_def_modifier_type_common(srna, linestyle_geometry_modifier_type_items,
+ "rna_LineStyleGeometryModifier_name_set", FALSE, FALSE);
+}
+
+static void rna_def_modifier_color_ramp_common(StructRNA *srna, int range)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "color_ramp");
+ RNA_def_property_struct_type(prop, "ColorRamp");
+ RNA_def_property_ui_text(prop, "Color Ramp", "Color ramp used to change line color");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ if (range) {
+ prop = RNA_def_property(srna, "range_min", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "range_min");
+ RNA_def_property_ui_text(prop, "Range Min", "Lower bound of the input range the mapping is applied");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "range_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "range_max");
+ RNA_def_property_ui_text(prop, "Range Max", "Upper bound of the input range the mapping is applied");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ }
+}
+
+static void rna_def_modifier_curve_common(StructRNA *srna, int range, int value)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem mapping_items[] = {
+ {0, "LINEAR", 0, "Linear", "Use linear mapping"},
+ {LS_MODIFIER_USE_CURVE, "CURVE", 0, "Curve", "Use curve mapping"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
+ RNA_def_property_enum_items(prop, mapping_items);
+ RNA_def_property_ui_text(prop, "Mapping", "Select the mapping type");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LS_MODIFIER_INVERT);
+ RNA_def_property_ui_text(prop, "Invert", "Invert the fade-out direction of the linear mapping");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curve");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_ui_text(prop, "Curve", "Curve used for the curve mapping");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ if (range) {
+ prop = RNA_def_property(srna, "range_min", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "range_min");
+ RNA_def_property_ui_text(prop, "Range Min", "Lower bound of the input range the mapping is applied");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "range_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "range_max");
+ RNA_def_property_ui_text(prop, "Range Max", "Upper bound of the input range the mapping is applied");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ }
+
+ if (value) {
+ prop = RNA_def_property(srna, "value_min", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "value_min");
+ RNA_def_property_ui_text(prop, "Value Min", "Minimum output value of the mapping");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "value_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "value_max");
+ RNA_def_property_ui_text(prop, "Value Max", "Maximum output value of the mapping");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ }
+}
+
+static void rna_def_modifier_material_common(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem mat_attr_items[] = {
+ {LS_MODIFIER_MATERIAL_DIFF, "DIFF", 0, "Diffuse", ""},
+ {LS_MODIFIER_MATERIAL_DIFF_R, "DIFF_R", 0, "Diffuse Red", ""},
+ {LS_MODIFIER_MATERIAL_DIFF_G, "DIFF_G", 0, "Diffuse Green", ""},
+ {LS_MODIFIER_MATERIAL_DIFF_B, "DIFF_B", 0, "Diffuse Blue", ""},
+ {LS_MODIFIER_MATERIAL_SPEC, "SPEC", 0, "Specular", ""},
+ {LS_MODIFIER_MATERIAL_SPEC_R, "SPEC_R", 0, "Specular Red", ""},
+ {LS_MODIFIER_MATERIAL_SPEC_G, "SPEC_G", 0, "Specular Green", ""},
+ {LS_MODIFIER_MATERIAL_SPEC_B, "SPEC_B", 0, "Specular Blue", ""},
+ {LS_MODIFIER_MATERIAL_SPEC_HARD, "SPEC_HARD", 0, "Specular Hardness", ""},
+ {LS_MODIFIER_MATERIAL_ALPHA, "ALPHA", 0, "Alpha", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ prop = RNA_def_property(srna, "material_attr", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mat_attr");
+ RNA_def_property_enum_items(prop, mat_attr_items);
+ RNA_def_property_ui_text(prop, "Material Attribute", "Specify which material attribute is used");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+}
+
+static void rna_def_linestyle_modifiers(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem blueprint_shape_items[] = {
+ {LS_MODIFIER_BLUEPRINT_CIRCLES, "CIRCLES", 0, "Circles", "Draw a blueprint using circular contour strokes"},
+ {LS_MODIFIER_BLUEPRINT_ELLIPSES, "ELLIPSES", 0, "Ellipses", "Draw a blueprint using elliptic contour strokes"},
+ {LS_MODIFIER_BLUEPRINT_SQUARES, "SQUARES", 0, "Squares", "Draw a blueprint using square contour strokes"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem transform_pivot_items[] = {
+ {LS_MODIFIER_2D_TRANSFORM_PIVOT_CENTER, "CENTER", 0, "Stroke Center", ""},
+ {LS_MODIFIER_2D_TRANSFORM_PIVOT_START, "START", 0, "Stroke Start", ""},
+ {LS_MODIFIER_2D_TRANSFORM_PIVOT_END, "END", 0, "Stroke End", ""},
+ {LS_MODIFIER_2D_TRANSFORM_PIVOT_PARAM, "PARAM", 0, "Stroke Point Parameter", ""},
+ {LS_MODIFIER_2D_TRANSFORM_PIVOT_ABSOLUTE, "ABSOLUTE", 0, "Absolute 2D Point", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "LineStyleModifier", NULL);
+ RNA_def_struct_ui_text(srna, "Line Style Modifier", "Base type to define modifiers");
+
+ /* line color modifiers */
+
+ srna = RNA_def_struct(brna, "LineStyleColorModifier", "LineStyleModifier");
+ RNA_def_struct_sdna(srna, "LineStyleModifier");
+ RNA_def_struct_refine_func(srna, "rna_LineStyle_color_modifier_refine");
+ RNA_def_struct_path_func(srna, "rna_LineStyle_color_modifier_path");
+ RNA_def_struct_ui_text(srna, "Line Style Color Modifier", "Base type to define line color modifiers");
+
+ srna = RNA_def_struct(brna, "LineStyleColorModifier_AlongStroke", "LineStyleColorModifier");
+ RNA_def_struct_ui_text(srna, "Along Stroke", "Change line color along stroke");
+ rna_def_color_modifier(srna);
+ rna_def_modifier_color_ramp_common(srna, FALSE);
+
+ srna = RNA_def_struct(brna, "LineStyleColorModifier_DistanceFromCamera", "LineStyleColorModifier");
+ RNA_def_struct_ui_text(srna, "Distance from Camera", "Change line color based on the distance from the camera");
+ rna_def_color_modifier(srna);
+ rna_def_modifier_color_ramp_common(srna, TRUE);
+
+ srna = RNA_def_struct(brna, "LineStyleColorModifier_DistanceFromObject", "LineStyleColorModifier");
+ RNA_def_struct_ui_text(srna, "Distance from Object", "Change line color based on the distance from an object");
+ rna_def_color_modifier(srna);
+ rna_def_modifier_color_ramp_common(srna, TRUE);
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "target");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Target", "Target object from which the distance is measured");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleColorModifier_Material", "LineStyleColorModifier");
+ RNA_def_struct_ui_text(srna, "Material", "Change line color based on a material attribute");
+ rna_def_color_modifier(srna);
+ rna_def_modifier_material_common(srna);
+ rna_def_modifier_color_ramp_common(srna, FALSE);
+
+ prop = RNA_def_property(srna, "use_ramp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LS_MODIFIER_USE_RAMP);
+ RNA_def_property_ui_text(prop, "Ramp", "Use color ramp to map the BW average into an RGB color");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ /* alpha transparency modifiers */
+
+ srna = RNA_def_struct(brna, "LineStyleAlphaModifier", "LineStyleModifier");
+ RNA_def_struct_sdna(srna, "LineStyleModifier");
+ RNA_def_struct_refine_func(srna, "rna_LineStyle_alpha_modifier_refine");
+ RNA_def_struct_path_func(srna, "rna_LineStyle_alpha_modifier_path");
+ RNA_def_struct_ui_text(srna, "Line Style Alpha Modifier", "Base type to define alpha transparency modifiers");
+
+ srna = RNA_def_struct(brna, "LineStyleAlphaModifier_AlongStroke", "LineStyleAlphaModifier");
+ RNA_def_struct_ui_text(srna, "Along Stroke", "Change alpha transparency along stroke");
+ rna_def_alpha_modifier(srna);
+ rna_def_modifier_curve_common(srna, FALSE, FALSE);
+
+ srna = RNA_def_struct(brna, "LineStyleAlphaModifier_DistanceFromCamera", "LineStyleAlphaModifier");
+ RNA_def_struct_ui_text(srna, "Distance from Camera",
+ "Change alpha transparency based on the distance from the camera");
+ rna_def_alpha_modifier(srna);
+ rna_def_modifier_curve_common(srna, TRUE, FALSE);
+
+ srna= RNA_def_struct(brna, "LineStyleAlphaModifier_DistanceFromObject", "LineStyleAlphaModifier");
+ RNA_def_struct_ui_text(srna, "Distance from Object",
+ "Change alpha transparency based on the distance from an object");
+ rna_def_alpha_modifier(srna);
+ rna_def_modifier_curve_common(srna, TRUE, FALSE);
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "target");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Target", "Target object from which the distance is measured");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleAlphaModifier_Material", "LineStyleAlphaModifier");
+ RNA_def_struct_ui_text(srna, "Material", "Change alpha transparency based on a material attribute");
+ rna_def_alpha_modifier(srna);
+ rna_def_modifier_material_common(srna);
+ rna_def_modifier_curve_common(srna, FALSE, FALSE);
+
+ /* line thickness modifiers */
+
+ srna = RNA_def_struct(brna, "LineStyleThicknessModifier", "LineStyleModifier");
+ RNA_def_struct_sdna(srna, "LineStyleModifier");
+ RNA_def_struct_refine_func(srna, "rna_LineStyle_thickness_modifier_refine");
+ RNA_def_struct_path_func(srna, "rna_LineStyle_thickness_modifier_path");
+ RNA_def_struct_ui_text(srna, "Line Style Thickness Modifier", "Base type to define line thickness modifiers");
+
+ srna = RNA_def_struct(brna, "LineStyleThicknessModifier_AlongStroke", "LineStyleThicknessModifier");
+ RNA_def_struct_ui_text(srna, "Along Stroke", "Change line thickness along stroke");
+ rna_def_thickness_modifier(srna);
+ rna_def_modifier_curve_common(srna, FALSE, TRUE);
+
+ srna = RNA_def_struct(brna, "LineStyleThicknessModifier_DistanceFromCamera", "LineStyleThicknessModifier");
+ RNA_def_struct_ui_text(srna, "Distance from Camera", "Change line thickness based on the distance from the camera");
+ rna_def_thickness_modifier(srna);
+ rna_def_modifier_curve_common(srna, TRUE, TRUE);
+
+ srna = RNA_def_struct(brna, "LineStyleThicknessModifier_DistanceFromObject", "LineStyleThicknessModifier");
+ RNA_def_struct_ui_text(srna, "Distance from Object", "Change line thickness based on the distance from an object");
+ rna_def_thickness_modifier(srna);
+ rna_def_modifier_curve_common(srna, TRUE, TRUE);
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "target");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Target", "Target object from which the distance is measured");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleThicknessModifier_Material", "LineStyleThicknessModifier");
+ RNA_def_struct_ui_text(srna, "Material", "Change line thickness based on a material attribute");
+ rna_def_thickness_modifier(srna);
+ rna_def_modifier_material_common(srna);
+ rna_def_modifier_curve_common(srna, FALSE, TRUE);
+
+ srna = RNA_def_struct(brna, "LineStyleThicknessModifier_Calligraphy", "LineStyleThicknessModifier");
+ RNA_def_struct_ui_text(srna, "Calligraphy",
+ "Change line thickness so that stroke looks like made with a calligraphic pen");
+ rna_def_thickness_modifier(srna);
+
+ prop = RNA_def_property(srna, "orientation", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "orientation");
+ RNA_def_property_ui_text(prop, "Orientation", "Angle of the main direction");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "min_thickness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "min_thickness");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_ui_text(prop, "Min Thickness",
+ "Minimum thickness in the direction perpendicular to the main direction");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "max_thickness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "max_thickness");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_ui_text(prop, "Max Thickness", "Maximum thickness in the main direction");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ /* geometry modifiers */
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier", "LineStyleModifier");
+ RNA_def_struct_sdna(srna, "LineStyleModifier");
+ RNA_def_struct_refine_func(srna, "rna_LineStyle_geometry_modifier_refine");
+ RNA_def_struct_path_func(srna, "rna_LineStyle_geometry_modifier_path");
+ RNA_def_struct_ui_text(srna, "Line Style Geometry Modifier", "Base type to define stroke geometry modifiers");
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier_Sampling", "LineStyleGeometryModifier");
+ RNA_def_struct_ui_text(srna, "Sampling",
+ "Specify a new sampling value that determines the resolution of stroke polylines");
+ rna_def_geometry_modifier(srna);
+
+ prop = RNA_def_property(srna, "sampling", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "sampling");
+ RNA_def_property_ui_text(prop, "Sampling", "New sampling value to be used for subsequent modifiers");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier_BezierCurve", "LineStyleGeometryModifier");
+ RNA_def_struct_ui_text(srna, "Bezier Curve",
+ "Replace stroke backbone geometry by a Bezier curve approximation of the "
+ "original backbone geometry");
+ rna_def_geometry_modifier(srna);
+
+ prop = RNA_def_property(srna, "error", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "error");
+ RNA_def_property_ui_text(prop, "Error",
+ "Maximum distance allowed between the new Bezier curve and the "
+ "original backbone geometry)");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier_SinusDisplacement", "LineStyleGeometryModifier");
+ RNA_def_struct_ui_text(srna, "Sinus Displacement", "Add sinus displacement to stroke backbone geometry");
+ rna_def_geometry_modifier(srna);
+
+ prop = RNA_def_property(srna, "wavelength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "wavelength");
+ RNA_def_property_ui_text(prop, "Wavelength", "Wavelength of the sinus displacement");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "amplitude");
+ RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of the sinus displacement");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "phase", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "phase");
+ RNA_def_property_ui_text(prop, "Phase", "Phase of the sinus displacement");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier_SpatialNoise", "LineStyleGeometryModifier");
+ RNA_def_struct_ui_text(srna, "Spatial Noise", "Add spatial noise to stroke backbone geometry");
+ rna_def_geometry_modifier(srna);
+
+ prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "amplitude");
+ RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of the spatial noise");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "scale");
+ RNA_def_property_ui_text(prop, "Scale", "Scale of the spatial noise");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "octaves", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "octaves");
+ RNA_def_property_ui_text(prop, "Octaves", "Number of octaves (i.e., the amount of detail of the spatial noise)");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "smooth", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LS_MODIFIER_SPATIAL_NOISE_SMOOTH);
+ RNA_def_property_ui_text(prop, "Smooth", "If true, the spatial noise is smooth");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "pure_random", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", LS_MODIFIER_SPATIAL_NOISE_PURERANDOM);
+ RNA_def_property_ui_text(prop, "Pure Random", "If true, the spatial noise does not show any coherence");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier_PerlinNoise1D", "LineStyleGeometryModifier");
+ RNA_def_struct_ui_text(srna, "Perlin Noise 1D", "Add one-dimensional Perlin noise to stroke backbone geometry");
+ rna_def_geometry_modifier(srna);
+
+ prop = RNA_def_property(srna, "frequency", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "frequency");
+ RNA_def_property_ui_text(prop, "Frequency", "Frequency of the Perlin noise");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "amplitude");
+ RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of the Perlin noise");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "octaves", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "octaves");
+ RNA_def_property_ui_text(prop, "Octaves", "Number of octaves (i.e., the amount of detail of the Perlin noise)");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "angle");
+ RNA_def_property_ui_text(prop, "Angle", "Displacement direction");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "seed");
+ RNA_def_property_ui_text(prop, "Seed",
+ "Seed for random number generation (if negative, time is used as a seed instead)");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier_PerlinNoise2D", "LineStyleGeometryModifier");
+ RNA_def_struct_ui_text(srna, "Perlin Noise 2D", "Add two-dimensional Perlin noise to stroke backbone geometry");
+ rna_def_geometry_modifier(srna);
+
+ prop = RNA_def_property(srna, "frequency", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "frequency");
+ RNA_def_property_ui_text(prop, "Frequency", "Frequency of the Perlin noise");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "amplitude");
+ RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of the Perlin noise");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "octaves", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "octaves");
+ RNA_def_property_ui_text(prop, "Octaves", "Number of octaves (i.e., the amount of detail of the Perlin noise)");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "angle");
+ RNA_def_property_ui_text(prop, "Angle", "Displacement direction");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "seed");
+ RNA_def_property_ui_text(prop, "Seed",
+ "Seed for random number generation (if negative, time is used as a seed instead)");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier_BackboneStretcher", "LineStyleGeometryModifier");
+ RNA_def_struct_ui_text(srna, "Backbone Stretcher", "Stretch the beginning and the end of stroke backbone");
+ rna_def_geometry_modifier(srna);
+
+ prop = RNA_def_property(srna, "backbone_length", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "backbone_length");
+ RNA_def_property_ui_text(prop, "Backbone Length", "Amount of backbone stretching");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier_TipRemover", "LineStyleGeometryModifier");
+ RNA_def_struct_ui_text(srna, "Tip Remover",
+ "Remove a piece of stroke at the beginning and the end of stroke backbone");
+ rna_def_geometry_modifier(srna);
+
+ prop = RNA_def_property(srna, "tip_length", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "tip_length");
+ RNA_def_property_ui_text(prop, "Tip Length", "Length of tips to be removed");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier_Polygonalization", "LineStyleGeometryModifier");
+ RNA_def_struct_ui_text(srna, "Polygonalization", "Modify the stroke geometry so that it looks more 'polygonal'");
+ rna_def_geometry_modifier(srna);
+
+ prop = RNA_def_property(srna, "error", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "error");
+ RNA_def_property_ui_text(prop, "Error",
+ "Maximum distance between the original stroke and its polygonal approximation");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier_GuidingLines", "LineStyleGeometryModifier");
+ RNA_def_struct_ui_text(srna, "Guiding Lines",
+ "Modify the stroke geometry so that it corresponds to its main direction line");
+ rna_def_geometry_modifier(srna);
+
+ prop = RNA_def_property(srna, "offset", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "offset");
+ RNA_def_property_ui_text(prop, "Offset",
+ "Displacement that is applied to the main direction line along its normal");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier_Blueprint", "LineStyleGeometryModifier");
+ RNA_def_struct_ui_text(srna, "Blueprint",
+ "Produce a blueprint using circular, elliptic, and square contour strokes");
+ rna_def_geometry_modifier(srna);
+
+ prop = RNA_def_property(srna, "shape", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
+ RNA_def_property_enum_items(prop, blueprint_shape_items);
+ RNA_def_property_ui_text(prop, "Shape", "Select the shape of blueprint contour strokes");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "rounds", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "rounds");
+ RNA_def_property_range(prop, 1, 1000);
+ RNA_def_property_ui_text(prop, "Rounds", "Number of rounds in contour strokes");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "backbone_length", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "backbone_length");
+ RNA_def_property_ui_text(prop, "Backbone Length", "Amount of backbone stretching");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "random_radius", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "random_radius");
+ RNA_def_property_ui_text(prop, "Random Radius", "Randomness of the radius");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "random_center", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "random_center");
+ RNA_def_property_ui_text(prop, "Random Center", "Randomness of the center");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "random_backbone", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "random_backbone");
+ RNA_def_property_ui_text(prop, "Random Backbone", "Randomness of the backbone stretching");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier_2DOffset", "LineStyleGeometryModifier");
+ RNA_def_struct_ui_text(srna, "2D Offset", "Add two-dimensional offsets to stroke backbone geometry");
+ rna_def_geometry_modifier(srna);
+
+ prop = RNA_def_property(srna, "start", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "start");
+ RNA_def_property_ui_text(prop, "Start", "Displacement that is applied from the beginning of the stroke");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "end", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "end");
+ RNA_def_property_ui_text(prop, "End", "Displacement that is applied from the end of the stroke");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "x", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "x");
+ RNA_def_property_ui_text(prop, "X", "Displacement that is applied to the X coordinates of stroke vertices");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "y", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "y");
+ RNA_def_property_ui_text(prop, "Y", "Displacement that is applied to the Y coordinates of stroke vertices");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifier_2DTransform", "LineStyleGeometryModifier");
+ RNA_def_struct_ui_text(srna, "2D Transform",
+ "Apply two-dimensional scaling and rotation to stroke backbone geometry");
+ rna_def_geometry_modifier(srna);
+
+ prop = RNA_def_property(srna, "pivot", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "pivot");
+ RNA_def_property_enum_items(prop, transform_pivot_items);
+ RNA_def_property_ui_text(prop, "Pivot", "Pivot of scaling and rotation operations");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "scale_x", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "scale_x");
+ RNA_def_property_ui_text(prop, "Scale X", "Scaling factor that is applied along the X axis");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "scale_y", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "scale_y");
+ RNA_def_property_ui_text(prop, "Scale Y", "Scaling factor that is applied along the Y axis");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "angle");
+ RNA_def_property_ui_text(prop, "Rotation Angle", "Rotation angle");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "pivot_u", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "pivot_u");
+ RNA_def_property_range(prop, 0.f, 1.f);
+ RNA_def_property_ui_text(prop, "Stroke Point Parameter",
+ "Pivot in terms of the stroke point parameter u (0 <= u <= 1)");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "pivot_x", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "pivot_x");
+ RNA_def_property_ui_text(prop, "Pivot X", "2D X coordinate of the absolute pivot");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "pivot_y", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "pivot_y");
+ RNA_def_property_ui_text(prop, "Pivot Y", "2D Y coordinate of the absolute pivot");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+}
+
+static void rna_def_linestyle(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem panel_items[] = {
+ {LS_PANEL_STROKES, "STROKES", 0, "Strokes", "Show the panel for stroke construction"},
+ {LS_PANEL_COLOR, "COLOR", 0, "Color", "Show the panel for line color options"},
+ {LS_PANEL_ALPHA, "ALPHA", 0, "Alpha", "Show the panel for alpha transparency options"},
+ {LS_PANEL_THICKNESS, "THICKNESS", 0, "Thickness", "Show the panel for line thickness options"},
+ {LS_PANEL_GEOMETRY, "GEOMETRY", 0, "Geometry", "Show the panel for stroke geometry options"},
+#if 0 /* hidden for now */
+ {LS_PANEL_MISC, "MISC", 0, "Misc", "Show the panel for miscellaneous options"},
+#endif
+ {0, NULL, 0, NULL, NULL}
+ };
+ static EnumPropertyItem chaining_items[] = {
+ {LS_CHAINING_PLAIN, "PLAIN", 0, "Plain", "Plain chaining"},
+ {LS_CHAINING_SKETCHY, "SKETCHY", 0, "Sketchy", "Sketchy chaining with a multiple touch"},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static EnumPropertyItem cap_items[] = {
+ {LS_CAPS_BUTT, "BUTT", 0, "Butt", "Butt cap (flat)"},
+ {LS_CAPS_ROUND, "ROUND", 0, "Round", "Round cap (half-circle)"},
+ {LS_CAPS_SQUARE, "SQUARE", 0, "Square", "Square cap (flat and extended)"},
+ {0, NULL, 0, NULL, NULL}
+ };
+ static EnumPropertyItem thickness_position_items[] = {
+ {LS_THICKNESS_CENTER, "CENTER", 0, "Center", "Stroke is centered along stroke geometry"},
+ {LS_THICKNESS_INSIDE, "INSIDE", 0, "Inside", "Stroke is drawn inside stroke geometry"},
+ {LS_THICKNESS_OUTSIDE, "OUTSIDE", 0, "Outside", "Stroke is drawn outside stroke geometry"},
+ {LS_THICKNESS_RELATIVE, "RELATIVE", 0, "Relative", "Stroke thinkness is split by a user-defined ratio"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "FreestyleLineStyle", "ID");
+ RNA_def_struct_ui_text(srna, "Freestyle Line Style", "Freestyle line style, reusable by multiple line sets");
+ RNA_def_struct_ui_icon(srna, ICON_BRUSH_DATA); /* FIXME: use a proper icon */
+
+ prop = RNA_def_property(srna, "panel", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "panel");
+ RNA_def_property_enum_items(prop, panel_items);
+ RNA_def_property_ui_text(prop, "Panel", "Select the property panel to be shown");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "r");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Color", "Base line color, possibly modified by line color modifiers");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "alpha");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Alpha",
+ "Base alpha transparency, possibly modified by alpha transparency modifiers");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "thickness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "thickness");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_ui_text(prop, "Thickness", "Base line thickness, possibly modified by line thickness modifiers");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "thickness_position", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "thickness_position");
+ RNA_def_property_enum_items(prop, thickness_position_items);
+ RNA_def_property_ui_text(prop, "Thickness Position", "Select the position of stroke thickness");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "thickness_ratio", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "thickness_ratio");
+ RNA_def_property_range(prop, 0.f, 1.f);
+ RNA_def_property_ui_text(prop, "Thickness Ratio",
+ "A number between 0 (inside) and 1 (outside) specifying the relative position of "
+ "stroke thickness");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "color_modifiers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "color_modifiers", NULL);
+ RNA_def_property_struct_type(prop, "LineStyleColorModifier");
+ RNA_def_property_ui_text(prop, "Color Modifiers", "List of line color modifiers");
+
+ prop = RNA_def_property(srna, "alpha_modifiers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "alpha_modifiers", NULL);
+ RNA_def_property_struct_type(prop, "LineStyleAlphaModifier");
+ RNA_def_property_ui_text(prop, "Alpha Modifiers", "List of alpha trancparency modifiers");
+
+ prop = RNA_def_property(srna, "thickness_modifiers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "thickness_modifiers", NULL);
+ RNA_def_property_struct_type(prop, "LineStyleThicknessModifier");
+ RNA_def_property_ui_text(prop, "Thickness Modifiers", "List of line thickness modifiers");
+
+ prop = RNA_def_property(srna, "use_chaining", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", LS_NO_CHAINING);
+ RNA_def_property_ui_text(prop, "Chaining", "Enable chaining of feature edges");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "chaining", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "chaining");
+ RNA_def_property_enum_items(prop, chaining_items);
+ RNA_def_property_ui_text(prop, "Chaining", "Select the way how feature edges are jointed to form chains");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "rounds", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "rounds");
+ RNA_def_property_range(prop, 1, 1000);
+ RNA_def_property_ui_text(prop, "Rounds", "Number of rounds in a sketchy multiple touch");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "geometry_modifiers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "geometry_modifiers", NULL);
+ RNA_def_property_struct_type(prop, "LineStyleGeometryModifier");
+ RNA_def_property_ui_text(prop, "Geometry Modifiers", "List of stroke geometry modifiers");
+
+ prop = RNA_def_property(srna, "same_object", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_SAME_OBJECT);
+ RNA_def_property_ui_text(prop, "Same Object", "If true, only feature edges of the same object are joined");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "use_split_length", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_SPLIT_LENGTH);
+ RNA_def_property_ui_text(prop, "Use Split Length", "Enable chain splitting by curvilinear 2D length");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "split_length", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "split_length");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_ui_text(prop, "Split Length", "Curvilinear 2D length for chain splitting");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "use_min_angle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_MIN_2D_ANGLE);
+ RNA_def_property_ui_text(prop, "Use Min 2D Angle",
+ "Split chains at points with angles smaller than the minimum 2D angle");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "min_angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "min_angle");
+ RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
+ RNA_def_property_ui_text(prop, "Min 2D Angle", "Minimum 2D angle for splitting chains");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "use_max_angle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_MAX_2D_ANGLE);
+ RNA_def_property_ui_text(prop, "Use Max 2D Angle",
+ "Split chains at points with angles larger than the maximum 2D angle");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "max_angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "max_angle");
+ RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
+ RNA_def_property_ui_text(prop, "Max 2D Angle", "Maximum 2D angle for splitting chains");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "use_min_length", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_MIN_2D_LENGTH);
+ RNA_def_property_ui_text(prop, "Use Min 2D Length", "Enable the selection of chains by a minimum 2D length");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "min_length", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "min_length");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_ui_text(prop, "Min 2D Length", "Minimum curvilinear 2D length for the selection of chains");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "use_max_length", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_MAX_2D_LENGTH);
+ RNA_def_property_ui_text(prop, "Use Max 2D Length", "Enable the selection of chains by a maximum 2D length");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "max_length", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "max_length");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_ui_text(prop, "Max 2D Length", "Maximum curvilinear 2D length for the selection of chains");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "use_split_pattern", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_SPLIT_PATTERN);
+ RNA_def_property_ui_text(prop, "Use Split Pattern", "Enable chain splitting by dashed line patterns");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "split_dash1", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "split_dash1");
+ RNA_def_property_range(prop, 0, USHRT_MAX);
+ RNA_def_property_ui_text(prop, "Split Dash 1", "Length of the 1st dash for splitting");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "split_gap1", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "split_gap1");
+ RNA_def_property_range(prop, 0, USHRT_MAX);
+ RNA_def_property_ui_text(prop, "Split Gap 1", "Length of the 1st gap for splitting");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "split_dash2", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "split_dash2");
+ RNA_def_property_range(prop, 0, USHRT_MAX);
+ RNA_def_property_ui_text(prop, "Split Dash 2", "Length of the 2nd dash for splitting");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "split_gap2", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "split_gap2");
+ RNA_def_property_range(prop, 0, USHRT_MAX);
+ RNA_def_property_ui_text(prop, "Split Gap 2", "Length of the 2nd gap for splitting");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "split_dash3", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "split_dash3");
+ RNA_def_property_range(prop, 0, USHRT_MAX);
+ RNA_def_property_ui_text(prop, "Split Dash 3", "Length of the 3rd dash for splitting");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "split_gap3", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "split_gap3");
+ RNA_def_property_range(prop, 0, USHRT_MAX);
+ RNA_def_property_ui_text(prop, "Split Gap 3", "Length of the 3rd gap for splitting");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "material_boundary", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_MATERIAL_BOUNDARY);
+ RNA_def_property_ui_text(prop, "Material Boundary", "If true, chains of feature edges are split at material boundaries");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "use_dashed_line", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_DASHED_LINE);
+ RNA_def_property_ui_text(prop, "Dashed Line", "Enable or disable dashed line");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "caps", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "caps");
+ RNA_def_property_enum_items(prop, cap_items);
+ RNA_def_property_ui_text(prop, "Cap", "Select the shape of both ends of strokes");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "dash1", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "dash1");
+ RNA_def_property_range(prop, 0, USHRT_MAX);
+ RNA_def_property_ui_text(prop, "Dash 1", "Length of the 1st dash for dashed lines");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "gap1", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "gap1");
+ RNA_def_property_range(prop, 0, USHRT_MAX);
+ RNA_def_property_ui_text(prop, "Gap 1", "Length of the 1st gap for dashed lines");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "dash2", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "dash2");
+ RNA_def_property_range(prop, 0, USHRT_MAX);
+ RNA_def_property_ui_text(prop, "Dash 2", "Length of the 2nd dash for dashed lines");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "gap2", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "gap2");
+ RNA_def_property_range(prop, 0, USHRT_MAX);
+ RNA_def_property_ui_text(prop, "Gap 2", "Length of the 2nd gap for dashed lines");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "dash3", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "dash3");
+ RNA_def_property_range(prop, 0, USHRT_MAX);
+ RNA_def_property_ui_text(prop, "Dash 3", "Length of the 3rd dash for dashed lines");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+
+ prop = RNA_def_property(srna, "gap3", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "gap3");
+ RNA_def_property_range(prop, 0, USHRT_MAX);
+ RNA_def_property_ui_text(prop, "Gap 3", "Length of the 3rd gap for dashed lines");
+ RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+}
+
+void RNA_def_linestyle(BlenderRNA *brna)
+{
+ rna_def_linestyle_modifiers(brna);
+ rna_def_linestyle(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index 04b8d2fa3df..32db099c0c0 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -258,6 +258,14 @@ static void rna_Main_masks_begin(CollectionPropertyIterator *iter, PointerRNA *p
rna_iterator_listbase_begin(iter, &bmain->mask, NULL);
}
+#ifdef WITH_FREESTYLE
+static void rna_Main_linestyle_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Main *bmain = (Main*)ptr->data;
+ rna_iterator_listbase_begin(iter, &bmain->linestyle, NULL);
+}
+#endif
+
#ifdef UNIT_TEST
static PointerRNA rna_Test_test_get(PointerRNA *ptr)
@@ -322,6 +330,9 @@ void RNA_def_main(BlenderRNA *brna)
{"grease_pencil", "GreasePencil", "rna_Main_gpencil_begin", "Grease Pencil", "Grease Pencil datablocks", RNA_def_main_gpencil},
{"movieclips", "MovieClip", "rna_Main_movieclips_begin", "Movie Clips", "Movie Clip datablocks", RNA_def_main_movieclips},
{"masks", "Mask", "rna_Main_masks_begin", "Masks", "Masks datablocks", RNA_def_main_masks},
+#ifdef WITH_FREESTYLE
+ {"linestyles", "FreestyleLineStyle", "rna_Main_linestyle_begin", "Line Styles", "Line Style datablocks", RNA_def_main_linestyles},
+#endif
{NULL, NULL, NULL, NULL, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index e9ed3aa8682..6d182ed17f0 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -72,6 +72,9 @@
#include "BKE_movieclip.h"
#include "BKE_mask.h"
#include "BKE_gpencil.h"
+#ifdef WITH_FREESTYLE
+# include "BKE_linestyle.h"
+#endif
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
@@ -634,6 +637,25 @@ static void rna_Main_grease_pencil_remove(Main *bmain, ReportList *reports, Poin
gpd->id.name + 2, ID_REAL_USERS(gpd));
}
+#ifdef WITH_FREESTYLE
+FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char* name)
+{
+ FreestyleLineStyle *linestyle = FRS_new_linestyle(name, bmain);
+ id_us_min(&linestyle->id);
+ return linestyle;
+}
+
+void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, FreestyleLineStyle *linestyle)
+{
+ if(ID_REAL_USERS(linestyle) <= 0)
+ BKE_libblock_free(&bmain->linestyle, linestyle);
+ else
+ BKE_reportf(reports, RPT_ERROR, "Line style '%s' must have zero users to be removed, found %d", linestyle->id.name+2, ID_REAL_USERS(linestyle));
+
+ /* XXX python now has invalid pointer? */
+}
+#endif
+
/* tag functions, all the same */
static void rna_Main_cameras_tag(Main *bmain, int value) { tag_main_lb(&bmain->camera, value); }
static void rna_Main_scenes_tag(Main *bmain, int value) { tag_main_lb(&bmain->scene, value); }
@@ -665,6 +687,9 @@ static void rna_Main_particles_tag(Main *bmain, int value) { tag_main_lb(&bmain-
static void rna_Main_gpencil_tag(Main *bmain, int value) { tag_main_lb(&bmain->gpencil, value); }
static void rna_Main_movieclips_tag(Main *bmain, int value) { tag_main_lb(&bmain->movieclip, value); }
static void rna_Main_masks_tag(Main *bmain, int value) { tag_main_lb(&bmain->mask, value); }
+#ifdef WITH_FREESTYLE
+void rna_Main_linestyle_tag(Main *bmain, int value) { tag_main_lb(&bmain->linestyle, value); }
+#endif
static int rna_Main_cameras_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_CA); }
static int rna_Main_scenes_is_updated_get(PointerRNA *ptr) { return DAG_id_type_tagged(ptr->data, ID_SCE); }
@@ -1686,4 +1711,32 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
}
+#ifdef WITH_FREESTYLE
+void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "BlendDataLineStyles");
+ srna = RNA_def_struct(brna, "BlendDataLineStyles", NULL);
+ RNA_def_struct_sdna(srna, "Main");
+ RNA_def_struct_ui_text(srna, "Main Line Styles", "Collection of line styles");
+
+ func = RNA_def_function(srna, "new", "rna_Main_linestyles_new");
+ RNA_def_function_ui_description(func, "Add a new line style instance to the main database");
+ parm = RNA_def_string(func, "name", "FreestyleLineStyle", 0, "", "New name for the datablock");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ /* return type */
+ parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "New line style datablock");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_Main_linestyles_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_ui_description(func, "Remove a line style instance from the current blendfile");
+ parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+}
+#endif
+
#endif
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 025279b3836..60625cb0e0b 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -1570,6 +1570,13 @@ static void rna_def_medge(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the EdgeSplit modifier");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+#ifdef WITH_FREESTYLE
+ prop = RNA_def_property(srna, "use_freestyle_edge_mark", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_FREESTYLE_EDGE);
+ RNA_def_property_ui_text(prop, "Freestyle Edge Mark", "Edge mark for Freestyle feature edge detection");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+#endif
+
prop = RNA_def_property(srna, "is_loose", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_LOOSEEDGE);
RNA_def_property_ui_text(prop, "Loose", "Loose edge");
@@ -1625,6 +1632,13 @@ static void rna_def_mface(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SMOOTH);
RNA_def_property_ui_text(prop, "Smooth", "");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+
+#ifdef WITH_FREESTYLE
+ prop = RNA_def_property(srna, "use_freestyle_face_mark", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_FREESTYLE_FACE);
+ RNA_def_property_ui_text(prop, "Freestyle Face Mark", "Face mark for Freestyle feature edge detection");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+#endif
prop = RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION);
RNA_def_property_array(prop, 3);
@@ -1723,6 +1737,13 @@ static void rna_def_mpolygon(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Smooth", "");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+#ifdef WITH_FREESTYLE
+ prop = RNA_def_property(srna, "use_freestyle_face_mark", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_FREESTYLE_FACE);
+ RNA_def_property_ui_text(prop, "Freestyle Face Mark", "Face mark for Freestyle feature edge detection");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+#endif
+
prop = RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION);
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, -1.0f, 1.0f);
@@ -2935,6 +2956,18 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Draw Sharp", "Display sharp edges, used with the EdgeSplit modifier");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+#ifdef WITH_FREESTYLE
+ prop = RNA_def_property(srna, "show_freestyle_edge_marks", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_FREESTYLE_EDGE);
+ RNA_def_property_ui_text(prop, "Draw Freestyle Edge Marks", "Display Freestyle edge marks, used with the Freestyle renderer");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+
+ prop = RNA_def_property(srna, "show_freestyle_face_marks", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAW_FREESTYLE_FACE);
+ RNA_def_property_ui_text(prop, "Draw Freestyle Face Marks", "Display Freestyle face marks, used with the Freestyle renderer");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
+#endif
+
prop = RNA_def_property(srna, "show_extra_edge_length", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWEXTRA_EDGELEN);
RNA_def_property_ui_text(prop, "Edge Length",
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 7304f7c9a49..96bd0fb327e 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -39,6 +39,9 @@
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
#include "DNA_world_types.h"
+#ifdef WITH_FREESTYLE
+# include "DNA_linestyle_types.h"
+#endif
#include "BLI_math.h"
@@ -333,6 +336,10 @@ EnumPropertyItem image_color_depth_items[] = {
#include "RE_engine.h"
+#ifdef WITH_FREESTYLE
+# include "FRS_freestyle.h"
+#endif
+
static void rna_SpaceImageEditor_uv_sculpt_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
{
ED_space_image_uv_sculpt_update(bmain->wm.first, scene->toolsettings);
@@ -1460,6 +1467,52 @@ static char *rna_ToolSettings_path(PointerRNA *ptr)
return BLI_strdup("tool_settings");
}
+#ifdef WITH_FREESTYLE
+static PointerRNA rna_FreestyleLineSet_linestyle_get(PointerRNA *ptr)
+{
+ FreestyleLineSet *lineset = (FreestyleLineSet *)ptr->data;
+
+ return rna_pointer_inherit_refine(ptr, &RNA_FreestyleLineStyle, lineset->linestyle);
+}
+
+static void rna_FreestyleLineSet_linestyle_set(PointerRNA *ptr, PointerRNA value)
+{
+ FreestyleLineSet *lineset = (FreestyleLineSet*)ptr->data;
+
+ lineset->linestyle->id.us--;
+ lineset->linestyle = (FreestyleLineStyle *)value.data;
+ lineset->linestyle->id.us++;
+}
+
+static PointerRNA rna_FreestyleSettings_active_lineset_get(PointerRNA *ptr)
+{
+ FreestyleConfig *config = (FreestyleConfig *)ptr->data;
+ FreestyleLineSet *lineset = FRS_get_active_lineset(config);
+ return rna_pointer_inherit_refine(ptr, &RNA_FreestyleLineSet, lineset);
+}
+
+static void rna_FreestyleSettings_active_lineset_index_range(PointerRNA *ptr, int *min, int *max,
+ int *softmin, int *softmax)
+{
+ FreestyleConfig *config = (FreestyleConfig *)ptr->data;
+
+ *min = 0;
+ *max = max_ii(0, BLI_countlist(&config->linesets) - 1);
+}
+
+static int rna_FreestyleSettings_active_lineset_index_get(PointerRNA *ptr)
+{
+ FreestyleConfig *config = (FreestyleConfig *)ptr->data;
+ return FRS_get_active_lineset_index(config);
+}
+
+static void rna_FreestyleSettings_active_lineset_index_set(PointerRNA *ptr, int value)
+{
+ FreestyleConfig *config = (FreestyleConfig *)ptr->data;
+ FRS_set_active_lineset_index(config, value);
+}
+#endif
+
#else
static void rna_def_transform_orientation(BlenderRNA *brna)
@@ -1527,6 +1580,9 @@ static void rna_def_tool_settings(BlenderRNA *brna)
{EDGE_MODE_TAG_SHARP, "SHARP", 0, "Tag Sharp", ""},
{EDGE_MODE_TAG_CREASE, "CREASE", 0, "Tag Crease", ""},
{EDGE_MODE_TAG_BEVEL, "BEVEL", 0, "Tag Bevel", ""},
+#ifdef WITH_FREESTYLE
+ {EDGE_MODE_TAG_FREESTYLE, "FREESTYLE", 0, "Tag Freestyle Edge Mark", ""},
+#endif
{0, NULL, 0, NULL, NULL}
};
@@ -2078,6 +2134,16 @@ void rna_def_render_layer_common(StructRNA *srna, int scene)
if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+#ifdef WITH_FREESTYLE
+ prop = RNA_def_property(srna, "use_freestyle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_FRS);
+ RNA_def_property_ui_text(prop, "Freestyle", "Render stylized strokes in this Layer");
+ if (scene)
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ else
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+#endif
+
/* passes */
prop = RNA_def_property(srna, "use_pass_combined", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_COMBINED);
@@ -2298,6 +2364,416 @@ void rna_def_render_layer_common(StructRNA *srna, int scene)
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
+#ifdef WITH_FREESTYLE
+static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ RNA_def_property_srna(cprop, "Linesets");
+ srna = RNA_def_struct(brna, "Linesets", NULL);
+ RNA_def_struct_sdna(srna, "FreestyleSettings");
+ RNA_def_struct_ui_text(srna, "Line Sets", "Line sets for associating lines and style parameters");
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "FreestyleLineSet");
+ RNA_def_property_pointer_funcs(prop, "rna_FreestyleSettings_active_lineset_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Active Line Set", "Active line set being displayed");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_funcs(prop, "rna_FreestyleSettings_active_lineset_index_get",
+ "rna_FreestyleSettings_active_lineset_index_set",
+ "rna_FreestyleSettings_active_lineset_index_range");
+ RNA_def_property_ui_text(prop, "Active Line Set Index", "Index of active line set slot");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+}
+
+static void rna_def_freestyle_settings(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem edge_type_negation_items[] = {
+ {0, "INCLUSIVE", 0, "Inclusive", "Select feature edges satisfying the given edge type conditions"},
+ {FREESTYLE_LINESET_FE_NOT, "EXCLUSIVE", 0, "Exclusive",
+ "Select feature edges not satisfying the given edge type conditions"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem edge_type_combination_items[] = {
+ {0, "OR", 0, "Logical OR", "Combine feature edge type conditions by logical OR (logical disjunction)"},
+ {FREESTYLE_LINESET_FE_AND, "AND", 0, "Logical AND",
+ "Combine feature edge type conditions by logical AND (logical conjunction)"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem group_negation_items[] = {
+ {0, "INCLUSIVE", 0, "Inclusive", "Select feature edges belonging to some object in the group"},
+ {FREESTYLE_LINESET_GR_NOT, "EXCLUSIVE", 0, "Exclusive",
+ "Select feature edges not belonging to any object in the group"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem face_mark_negation_items[] = {
+ {0, "INCLUSIVE", 0, "Inclusive", "Select feature edges satisfying the given face mark conditions"},
+ {FREESTYLE_LINESET_FM_NOT, "EXCLUSIVE", 0, "Exclusive",
+ "Select feature edges not satisfying the given face mark conditions"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem face_mark_condition_items[] = {
+ {0, "ONE", 0, "One Face", "Select feature edges if one of faces on the right and left has a face mark"},
+ {FREESTYLE_LINESET_FM_BOTH, "BOTH", 0, "Both Faces",
+ "Select feature edges if both faces on the right and left faces have a face mark"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem freestyle_ui_mode_items[] = {
+ {FREESTYLE_CONTROL_SCRIPT_MODE, "SCRIPT", 0, "Python Scripting Mode",
+ "Advanced mode for using style modules in Python"},
+ {FREESTYLE_CONTROL_EDITOR_MODE, "EDITOR", 0, "Parameter Editor Mode",
+ "Basic mode for interactive style parameter editing"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem visibility_items[] ={
+ {FREESTYLE_QI_VISIBLE, "VISIBLE", 0, "Visible", "Select visible feature edges"},
+ {FREESTYLE_QI_HIDDEN, "HIDDEN", 0, "Hidden", "Select hidden feature edges"},
+ {FREESTYLE_QI_RANGE, "RANGE", 0, "QI Range",
+ "Select feature edges within a range of quantitative invisibility (QI) values"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem freestyle_raycasting_algorithm_items[] = {
+ {FREESTYLE_ALGO_REGULAR, "REGULAR", 0, "Normal Ray Casting", "Consider all FEdges in each ViewEdge"},
+ {FREESTYLE_ALGO_FAST, "FAST", 0, "Fast Ray Casting", "Sample some FEdges in each ViewEdge"},
+ {FREESTYLE_ALGO_VERYFAST, "VERYFAST", 0, "Very Fast Ray Casting",
+ "Sample one FEdge in each ViewEdge; do not save list of occluders"},
+ {FREESTYLE_ALGO_CULLED_ADAPTIVE_TRADITIONAL, "CULLEDADAPTIVETRADITIONAL", 0,
+ "Culled Traditional Visibility Detection",
+ "Culled adaptive grid with heuristic density and "
+ "traditional QI calculation"},
+ {FREESTYLE_ALGO_ADAPTIVE_TRADITIONAL, "ADAPTIVETRADITIONAL", 0, "Unculled Traditional Visibility Detection",
+ "Adaptive grid with heuristic density and traditional QI calculation"},
+ {FREESTYLE_ALGO_CULLED_ADAPTIVE_CUMULATIVE, "CULLEDADAPTIVECUMULATIVE", 0,
+ "Culled Cumulative Visibility Detection",
+ "Culled adaptive grid with heuristic density and "
+ "cumulative QI calculation"},
+ {FREESTYLE_ALGO_ADAPTIVE_CUMULATIVE, "ADAPTIVECUMULATIVE", 0, "Unculled Cumulative Visibility Detection",
+ "Adaptive grid with heuristic density and cumulative QI calculation"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+
+ /* FreestyleLineSet */
+
+ srna = RNA_def_struct(brna, "FreestyleLineSet", NULL);
+ RNA_def_struct_ui_text(srna, "Freestyle Line Set", "Line set for associating lines and style parameters");
+
+ /* access to line style settings is redirected through functions
+ * to allow proper id-buttons functionality
+ */
+ prop = RNA_def_property(srna, "linestyle", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "FreestyleLineStyle");
+ RNA_def_property_flag(prop, PROP_EDITABLE|PROP_NEVER_NULL);
+ RNA_def_property_pointer_funcs(prop, "rna_FreestyleLineSet_linestyle_get",
+ "rna_FreestyleLineSet_linestyle_set", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Line Style", "Line style settings");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "name");
+ RNA_def_property_ui_text(prop, "Line Set Name", "Line set name");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+ RNA_def_struct_name_property(srna, prop);
+
+ prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_LINESET_ENABLED);
+ RNA_def_property_ui_text(prop, "Use", "Enable or disable this line set during stroke rendering");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_by_visibility", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_VISIBILITY);
+ RNA_def_property_ui_text(prop, "Selection by Visibility", "Select feature edges based on visibility");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_by_edge_types", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_EDGE_TYPES);
+ RNA_def_property_ui_text(prop, "Selection by Edge Types", "Select feature edges based on edge types");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_by_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_GROUP);
+ RNA_def_property_ui_text(prop, "Selection by Group", "Select feature edges based on a group of objects");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_by_image_border", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_IMAGE_BORDER);
+ RNA_def_property_ui_text(prop, "Selection by Image Border",
+ "Select feature edges by image border (less memory consumption)");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_by_face_marks", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_FACE_MARK);
+ RNA_def_property_ui_text(prop, "Selection by Face Marks", "Select feature edges by face marks");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "edge_type_negation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
+ RNA_def_property_enum_items(prop, edge_type_negation_items);
+ RNA_def_property_ui_text(prop, "Edge Type Negation",
+ "Set the negation operation for conditions on feature edge types");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "edge_type_combination", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
+ RNA_def_property_enum_items(prop, edge_type_combination_items);
+ RNA_def_property_ui_text(prop, "Edge Type Combination",
+ "Set the combination operation for conditions on feature edge types");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "group", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "group");
+ RNA_def_property_struct_type(prop, "Group");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Group", "A group of objects based on which feature edges are selected");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "group_negation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
+ RNA_def_property_enum_items(prop, group_negation_items);
+ RNA_def_property_ui_text(prop, "Group Negation",
+ "Set the negation operation for conditions on feature edge types");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "face_mark_negation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
+ RNA_def_property_enum_items(prop, face_mark_negation_items);
+ RNA_def_property_ui_text(prop, "Face Mark Negation",
+ "Set the negation operation for the condition on face marks");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "face_mark_condition", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
+ RNA_def_property_enum_items(prop, face_mark_condition_items);
+ RNA_def_property_ui_text(prop, "Face Mark Condition", "Set a feature edge selection condition on face marks");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_silhouette", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_SILHOUETTE);
+ RNA_def_property_ui_text(prop, "Silhouette", "Select silhouette edges");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_border", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_BORDER);
+ RNA_def_property_ui_text(prop, "Border", "Select border edges");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_crease", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_CREASE);
+ RNA_def_property_ui_text(prop, "Crease", "Select crease edges");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_ridge_valley", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_RIDGE_VALLEY);
+ RNA_def_property_ui_text(prop, "Ridge & Valley", "Select ridges and valleys");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_suggestive_contour", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_SUGGESTIVE_CONTOUR);
+ RNA_def_property_ui_text(prop, "Suggestive Contour", "Select suggestive contours");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_material_boundary", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_MATERIAL_BOUNDARY);
+ RNA_def_property_ui_text(prop, "Material Boundary", "Select edges at material boundaries");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_contour", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_CONTOUR);
+ RNA_def_property_ui_text(prop, "Contour", "Select contours");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_external_contour", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_EXTERNAL_CONTOUR);
+ RNA_def_property_ui_text(prop, "External Contour", "Select external contours");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "select_edge_mark", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_EDGE_MARK);
+ RNA_def_property_ui_text(prop, "Edge Mark", "Select edge marks");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "exclude_silhouette", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_SILHOUETTE);
+ RNA_def_property_ui_text(prop, "Silhouette", "Exclude silhouette edges");
+ RNA_def_property_ui_icon(prop, ICON_X, 0);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "exclude_border", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_BORDER);
+ RNA_def_property_ui_text(prop, "Border", "Exclude border edges");
+ RNA_def_property_ui_icon(prop, ICON_X, 0);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "exclude_crease", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_CREASE);
+ RNA_def_property_ui_text(prop, "Crease", "Exclude crease edges");
+ RNA_def_property_ui_icon(prop, ICON_X, 0);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "exclude_ridge_valley", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_RIDGE_VALLEY);
+ RNA_def_property_ui_text(prop, "Ridge & Valley", "Exclude ridges and valleys");
+ RNA_def_property_ui_icon(prop, ICON_X, 0);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "exclude_suggestive_contour", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_SUGGESTIVE_CONTOUR);
+ RNA_def_property_ui_text(prop, "Suggestive Contour", "Exclude suggestive contours");
+ RNA_def_property_ui_icon(prop, ICON_X, 0);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "exclude_material_boundary", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_MATERIAL_BOUNDARY);
+ RNA_def_property_ui_text(prop, "Material Boundary", "Exclude edges at material boundaries");
+ RNA_def_property_ui_icon(prop, ICON_X, 0);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "exclude_contour", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_CONTOUR);
+ RNA_def_property_ui_text(prop, "Contour", "Exclude contours");
+ RNA_def_property_ui_icon(prop, ICON_X, 0);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "exclude_external_contour", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_EXTERNAL_CONTOUR);
+ RNA_def_property_ui_text(prop, "External Contour", "Exclude external contours");
+ RNA_def_property_ui_icon(prop, ICON_X, 0);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "exclude_edge_mark", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_EDGE_MARK);
+ RNA_def_property_ui_text(prop, "Edge Mark", "Exclude edge marks");
+ RNA_def_property_ui_icon(prop, ICON_X, 0);
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "visibility", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "qi");
+ RNA_def_property_enum_items(prop, visibility_items);
+ RNA_def_property_ui_text(prop, "Visibility", "Determine how to use visibility for feature edge selection");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "qi_start", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "qi_start");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_ui_text(prop, "Start", "First QI value of the QI range");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "qi_end", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "qi_end");
+ RNA_def_property_range(prop, 0, INT_MAX);
+ RNA_def_property_ui_text(prop, "End", "Last QI value of the QI range");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ /* FreestyleModuleSettings */
+
+ srna = RNA_def_struct(brna, "FreestyleModuleSettings", NULL);
+ RNA_def_struct_sdna(srna, "FreestyleModuleConfig");
+ RNA_def_struct_ui_text(srna, "Freestyle Module", "Style module configuration for specifying a style module");
+
+ prop = RNA_def_property(srna, "module_path", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_string_sdna(prop, NULL, "module_path");
+ RNA_def_property_ui_text(prop, "Module Path", "Path to a style module file");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "is_displayed", 1);
+ RNA_def_property_ui_text(prop, "Use", "Enable or disable this style module during stroke rendering");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ /* FreestyleSettings */
+
+ srna = RNA_def_struct(brna, "FreestyleSettings", NULL);
+ RNA_def_struct_sdna(srna, "FreestyleConfig");
+ RNA_def_struct_nested(brna, srna, "SceneRenderLayer");
+ RNA_def_struct_ui_text(srna, "Frestyle Settings", "Freestyle settings for a SceneRenderLayer datablock");
+
+ prop = RNA_def_property(srna, "modules", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "modules", NULL);
+ RNA_def_property_struct_type(prop, "FreestyleModuleSettings");
+ RNA_def_property_ui_text(prop, "Style modules", "A list of style modules (to be applied from top to bottom)");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, freestyle_ui_mode_items);
+ RNA_def_property_ui_text(prop, "Control Mode", "Select the Freestyle control mode");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "raycasting_algorithm", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "raycasting_algorithm");
+ RNA_def_property_enum_items(prop, freestyle_raycasting_algorithm_items);
+ RNA_def_property_ui_text(prop, "Raycasting Algorithm", "Select the Freestyle raycasting algorithm");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "use_culling", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_CULLING);
+ RNA_def_property_ui_text(prop, "Culling", "If enabled, out-of-view edges are ignored");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "use_suggestive_contours", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_SUGGESTIVE_CONTOURS_FLAG);
+ RNA_def_property_ui_text(prop, "Suggestive Contours", "Enable suggestive contours");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "use_ridges_and_valleys", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_RIDGES_AND_VALLEYS_FLAG);
+ RNA_def_property_ui_text(prop, "Ridges and Valleys", "Enable ridges and valleys");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "use_material_boundaries", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_MATERIAL_BOUNDARIES_FLAG);
+ RNA_def_property_ui_text(prop, "Material Boundaries", "Enable material boundaries");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "use_smoothness", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_FACE_SMOOTHNESS_FLAG);
+ RNA_def_property_ui_text(prop, "Face Smoothness", "Take face smoothness into account in view map calculation");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "use_advanced_options", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_ADVANCED_OPTIONS_FLAG);
+ RNA_def_property_ui_text(prop, "Advanced Edge Detection Options",
+ "Enable advanced edge detection options (sphere radius and Kr derivative epsilon)");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "sphere_radius", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "sphere_radius");
+ RNA_def_property_range(prop, 0.0, 1000.0);
+ RNA_def_property_ui_text(prop, "Sphere Radius", "Sphere radius for computing curvatures");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "kr_derivative_epsilon", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "dkr_epsilon");
+ RNA_def_property_range(prop, -1000.0, 1000.0);
+ RNA_def_property_ui_text(prop, "Kr Derivative Epsilon", "Kr derivative epsilon for computing suggestive contours");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "crease_angle", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "crease_angle");
+ RNA_def_property_range(prop, 0.0, DEG2RAD(180.0));
+ RNA_def_property_ui_text(prop, "Crease Angle", "Angular threshold for detecting crease edges");
+ RNA_def_property_update(prop, NC_SCENE, NULL);
+
+ prop = RNA_def_property(srna, "linesets", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "linesets", NULL);
+ RNA_def_property_struct_type(prop, "FreestyleLineSet");
+ RNA_def_property_ui_text(prop, "Line Sets", "");
+ rna_def_freestyle_linesets(brna, prop);
+}
+#endif
+
static void rna_def_scene_game_recast_data(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2834,6 +3310,7 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
static void rna_def_scene_render_layer(BlenderRNA *brna)
{
StructRNA *srna;
+ PropertyRNA *prop;
srna = RNA_def_struct(brna, "SceneRenderLayer", NULL);
RNA_def_struct_ui_text(srna, "Scene Render Layer", "Render layer");
@@ -2841,6 +3318,18 @@ static void rna_def_scene_render_layer(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_SceneRenderLayer_path");
rna_def_render_layer_common(srna, 1);
+
+#ifdef WITH_FREESTYLE
+ /* Freestyle */
+
+ rna_def_freestyle_settings(brna);
+
+ prop = RNA_def_property(srna, "freestyle_settings", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "freestyleConfig");
+ RNA_def_property_struct_type(prop, "FreestyleSettings");
+ RNA_def_property_ui_text(prop, "Freestyle Settings", "");
+#endif
}
/* curve.splines */
@@ -3434,6 +3923,15 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+#ifdef WITH_FREESTYLE
+ static EnumPropertyItem freestyle_thickness_items[] = {
+ {R_LINE_THICKNESS_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Specify unit line thickness in pixels"},
+ {R_LINE_THICKNESS_RELATIVE, "RELATIVE", 0, "Relative",
+ "Unit line thickness is scaled by the proportion of the present vertical image "
+ "resolution to 480 pixels"},
+ {0, NULL, 0, NULL, NULL}};
+#endif
+
rna_def_scene_ffmpeg_settings(brna);
#ifdef WITH_QUICKTIME
rna_def_scene_quicktime_settings(brna);
@@ -3678,6 +4176,13 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Edge Color", "Edge color");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+#ifdef WITH_FREESTYLE
+ prop = RNA_def_property(srna, "use_freestyle", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mode", R_EDGE_FRS);
+ RNA_def_property_ui_text(prop, "Edge", "Draw stylized strokes using Freestyle");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+#endif
+
/* threads */
prop = RNA_def_property(srna, "threads", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "threads");
@@ -4133,6 +4638,19 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Persistent Data", "Keep render data around for faster re-renders");
RNA_def_property_update(prop, 0, "rna_Scene_use_persistent_data_update");
+#ifdef WITH_FREESTYLE
+ /* Freestyle line thickness options */
+ prop = RNA_def_property(srna, "line_thickness_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "line_thickness_mode");
+ RNA_def_property_enum_items(prop, freestyle_thickness_items);
+ RNA_def_property_ui_text(prop, "Line Thickness Mode", "Line thickness mode for Freestyle line drawing");
+
+ prop = RNA_def_property(srna, "unit_line_thickness", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "unit_line_thickness");
+ RNA_def_property_range(prop, 0.f, 10000.f);
+ RNA_def_property_ui_text(prop, "Unit Line Thickness", "Unit line thickness in pixels");
+#endif
+
/* Scene API */
RNA_api_scene_render(srna);
}
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 09969ddc7e5..cccdf3258d2 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -1986,6 +1986,7 @@ static void rna_def_space_buttons(BlenderRNA *brna)
static EnumPropertyItem buttons_context_items[] = {
{BCONTEXT_SCENE, "SCENE", ICON_SCENE, "Scene", "Scene"},
{BCONTEXT_RENDER, "RENDER", ICON_SCENE_DATA, "Render", "Render"},
+ {BCONTEXT_RENDER_LAYER, "RENDER_LAYER", ICON_RENDERLAYERS, "Render Layers", "Render Layers"},
{BCONTEXT_WORLD, "WORLD", ICON_WORLD, "World", "World"},
{BCONTEXT_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Object"},
{BCONTEXT_CONSTRAINT, "CONSTRAINT", ICON_CONSTRAINT, "Constraints", "Constraints"},
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 0def5988315..8ebf83532de 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -1194,6 +1194,13 @@ static void rna_def_userdef_theme_spaces_edge(StructRNA *srna)
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Edge UV Face Select", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+#ifdef WITH_FREESTYLE
+ prop = RNA_def_property(srna, "freestyle_edge_mark", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Freestyle Edge Mark", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+#endif
}
static void rna_def_userdef_theme_spaces_face(StructRNA *srna)
@@ -1219,6 +1226,13 @@ static void rna_def_userdef_theme_spaces_face(StructRNA *srna)
RNA_def_property_range(prop, 1, 10);
RNA_def_property_ui_text(prop, "Face Dot Size", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+#ifdef WITH_FREESTYLE
+ prop = RNA_def_property(srna, "freestyle_face_mark", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Freestyle Face Mark", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+#endif
}
static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, short incl_nurbs)
diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript
index c28987eb156..4fb6d771c5b 100644
--- a/source/blender/python/SConscript
+++ b/source/blender/python/SConscript
@@ -98,6 +98,10 @@ if env['WITH_BF_CYCLES']:
if env['WITH_BF_CYCLES_OSL']:
defs.append('WITH_CYCLES_OSL')
+if env['WITH_BF_FREESTYLE']:
+ incs += ' ../freestyle/intern/python'
+ defs.append('WITH_FREESTYLE')
+
if env['WITH_BF_GAMEENGINE']:
defs.append('WITH_GAMEENGINE')
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index ed7b48fb14f..cde977288d1 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -77,11 +77,14 @@ PyC_FlagSet bpy_bm_htype_all_flags[] = {
};
PyC_FlagSet bpy_bm_hflag_all_flags[] = {
- {BM_ELEM_SELECT, "SELECT"},
- {BM_ELEM_HIDDEN, "HIDE"},
- {BM_ELEM_SEAM, "SEAM"},
- {BM_ELEM_SMOOTH, "SMOOTH"},
- {BM_ELEM_TAG, "TAG"},
+ {BM_ELEM_SELECT, "SELECT"},
+ {BM_ELEM_HIDDEN, "HIDE"},
+ {BM_ELEM_SEAM, "SEAM"},
+ {BM_ELEM_SMOOTH, "SMOOTH"},
+ {BM_ELEM_TAG, "TAG"},
+#ifdef WITH_FREESTYLE
+ {BM_ELEM_FREESTYLE, "FREESTYLE"},
+#endif
{0, NULL}
};
@@ -101,6 +104,10 @@ PyDoc_STRVAR(bpy_bm_elem_tag_doc, "Generic attribute scripts can use for own
PyDoc_STRVAR(bpy_bm_elem_smooth_doc, "Smooth state of this element.\n\n:type: boolean");
PyDoc_STRVAR(bpy_bm_elem_seam_doc, "Seam for UV unwrapping.\n\n:type: boolean");
+#ifdef WITH_FREESTYLE
+PyDoc_STRVAR(bpy_bm_freestyle_edge_mark_doc, "Freestyle edge mark.\n\n:type: boolean");
+PyDoc_STRVAR(bpy_bm_freestyle_face_mark_doc, "Freestyle face mark.\n\n:type: boolean");
+#endif
static PyObject *bpy_bm_elem_hflag_get(BPy_BMElem *self, void *flag)
{
@@ -662,6 +669,10 @@ static PyGetSetDef bpy_bmedge_getseters[] = {
{(char *)"smooth", (getter)bpy_bm_elem_hflag_get, (setter)bpy_bm_elem_hflag_set, (char *)bpy_bm_elem_smooth_doc, (void *)BM_ELEM_SMOOTH},
{(char *)"seam", (getter)bpy_bm_elem_hflag_get, (setter)bpy_bm_elem_hflag_set, (char *)bpy_bm_elem_seam_doc, (void *)BM_ELEM_SEAM},
+#ifdef WITH_FREESTYLE
+ {(char *)"freestyle_edge_mark", (getter)bpy_bm_elem_hflag_get, (setter)bpy_bm_elem_hflag_set, (char *)bpy_bm_freestyle_edge_mark_doc, (void *)BM_ELEM_FREESTYLE},
+#endif
+
/* connectivity data */
{(char *)"verts", (getter)bpy_bmelemseq_elem_get, (setter)NULL, (char *)bpy_bmedge_verts_doc, (void *)BM_VERTS_OF_EDGE},
@@ -686,6 +697,10 @@ static PyGetSetDef bpy_bmface_getseters[] = {
{(char *)"smooth", (getter)bpy_bm_elem_hflag_get, (setter)bpy_bm_elem_hflag_set, (char *)bpy_bm_elem_smooth_doc, (void *)BM_ELEM_SMOOTH},
+#ifdef WITH_FREESTYLE
+ {(char *)"freestyle_face_mark", (getter)bpy_bm_elem_hflag_get, (setter)bpy_bm_elem_hflag_set, (char *)bpy_bm_freestyle_face_mark_doc, (void *)BM_ELEM_FREESTYLE},
+#endif
+
{(char *)"normal", (getter)bpy_bmface_normal_get, (setter)bpy_bmface_normal_set, (char *)bpy_bmface_normal_doc, NULL},
{(char *)"material_index", (getter)bpy_bmface_material_index_get, (setter)bpy_bmface_material_index_set, (char *)bpy_bmface_material_index_doc, NULL},
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index b531e08f8d4..30ab4bd4b0e 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -143,6 +143,13 @@ if(WITH_CYCLES_OSL)
add_definitions(-DWITH_CYCLES_OSL)
endif()
+if(WITH_FREESTYLE)
+ list(APPEND INC
+ ../../freestyle/intern/python
+ )
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
if(WITH_GAMEENGINE)
add_definitions(-DWITH_GAMEENGINE)
endif()
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index c4d68290da3..1f8385288bd 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -60,6 +60,10 @@
#include "../generic/blf_py_api.h"
#include "../mathutils/mathutils.h"
+#ifdef WITH_FREESTYLE
+# include "BPy_Freestyle.h"
+#endif
+
PyObject *bpy_package_py = NULL;
PyDoc_STRVAR(bpy_script_paths_doc,
@@ -258,6 +262,9 @@ void BPy_init_modules(void)
}
/* stand alone utility modules not related to blender directly */
IDProp_Init_Types(); /* not actually a submodule, just types */
+#ifdef WITH_FREESTYLE
+ Freestyle_Init();
+#endif
mod = PyModule_New("_bpy");
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 5195f821d56..7889b9a7f0b 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -245,12 +245,13 @@ static PyObject *bpy_app_driver_dict_get(PyObject *UNUSED(self), void *UNUSED(cl
static PyGetSetDef bpy_app_getsets[] = {
- {(char *)"debug", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG},
- {(char *)"debug_ffmpeg", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_FFMPEG},
- {(char *)"debug_python", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_PYTHON},
- {(char *)"debug_events", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_EVENTS},
- {(char *)"debug_handlers", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_HANDLERS},
- {(char *)"debug_wm", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_WM},
+ {(char *)"debug", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG},
+ {(char *)"debug_ffmpeg", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_FFMPEG},
+ {(char *)"debug_freestyle", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_FREESTYLE},
+ {(char *)"debug_python", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_PYTHON},
+ {(char *)"debug_events", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_EVENTS},
+ {(char *)"debug_handlers", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_HANDLERS},
+ {(char *)"debug_wm", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_WM},
{(char *)"debug_value", bpy_app_debug_value_get, bpy_app_debug_value_set, (char *)bpy_app_debug_value_doc, NULL},
{(char *)"tempdir", bpy_app_tempdir_get, NULL, (char *)bpy_app_tempdir_doc, NULL},
diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index 6db0a52bdf0..60105f73f37 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -41,6 +41,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = {
{(char *)"compositor", NULL},
{(char *)"cycles", NULL},
{(char *)"cycles_osl", NULL},
+ {(char *)"freestyle", NULL},
{(char *)"gameengine", NULL},
{(char *)"image_cineon", NULL},
{(char *)"image_dds", NULL},
@@ -137,6 +138,12 @@ static PyObject *make_builtopts_info(void)
SetObjIncref(Py_False);
#endif
+#ifdef WITH_FREESTYLE
+ SetObjIncref(Py_True);
+#else
+ SetObjIncref(Py_False);
+#endif
+
#ifdef WITH_GAMEENGINE
SetObjIncref(Py_True);
#else
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index eb81e7f2049..effc564fdc9 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -144,6 +144,13 @@ if(WITH_MOD_SMOKE)
add_definitions(-DWITH_SMOKE)
endif()
+if(WITH_FREESTYLE)
+ list(APPEND INC
+ ../freestyle
+ )
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
if(WITH_CODEC_QUICKTIME)
list(APPEND INC
../quicktime
diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript
index 992dd8c8262..c4309577ae9 100644
--- a/source/blender/render/SConscript
+++ b/source/blender/render/SConscript
@@ -83,6 +83,10 @@ if env['WITH_BF_QUICKTIME']:
if env['WITH_BF_OPENEXR']:
defs.append('WITH_OPENEXR')
+if env['WITH_BF_FREESTYLE']:
+ incs += ' ../freestyle'
+ defs.append('WITH_FREESTYLE')
+
if env['WITH_BF_GAMEENGINE']:
defs.append('WITH_GAMEENGINE')
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index f97e5ac3c59..020fa57cf94 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -219,6 +219,9 @@ void RE_TileProcessor(struct Render *re);
/* only RE_NewRender() needed, main Blender render calls */
void RE_BlenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene, struct SceneRenderLayer *srl, struct Object *camera_override, unsigned int lay, int frame, const short write_still);
void RE_BlenderAnim(struct Render *re, struct Main *bmain, struct Scene *scene, struct Object *camera_override, unsigned int lay, int sfra, int efra, int tfra);
+#ifdef WITH_FREESTYLE
+void RE_RenderFreestyleStrokes(struct Render *re, struct Main *bmain, struct Scene *scene);
+#endif
/* error reporting */
void RE_SetReports(struct Render *re, struct ReportList *reports);
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index d65da586b9a..deba6d165f2 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -235,6 +235,10 @@ struct Render
ListBase volumes;
ListBase volume_precache_parts;
+#ifdef WITH_FREESTYLE
+ ListBase freestyle_renders;
+#endif
+
/* arena for allocating data for use during render, for
* example dynamic TFaces to go in the VlakRen structure.
*/
@@ -390,6 +394,9 @@ typedef struct VlakRen {
struct Material *mat;
char puno;
char flag, ec;
+#ifdef WITH_FREESTYLE
+ char freestyle_edge_mark;
+#endif
int index;
} VlakRen;
@@ -622,6 +629,15 @@ typedef struct LampRen {
#define R_TANGENT 64
#define R_TRACEBLE 128
+/* vlakren->freestyle_edge_mark */
+#ifdef WITH_FREESTYLE
+# define R_EDGE_V1V2 1
+# define R_EDGE_V2V3 2
+# define R_EDGE_V3V4 4
+# define R_EDGE_V3V1 4
+# define R_EDGE_V4V1 8
+#endif
+
/* strandbuffer->flag */
#define R_STRAND_BSPLINE 1
#define R_STRAND_B_UNITS 2
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 0dc6492fad1..9e9dff63c04 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -42,6 +42,9 @@
#include "BLI_memarena.h"
#include "BLI_ghash.h"
#include "BLI_linklist.h"
+#ifdef WITH_FREESTYLE
+# include "BLI_edgehash.h"
+#endif
#include "DNA_armature_types.h"
#include "DNA_camera_types.h"
@@ -2694,7 +2697,11 @@ static void init_render_dm(DerivedMesh *dm, Render *re, ObjectRen *obr,
v2= mface->v2;
v3= mface->v3;
v4= mface->v4;
- flag= mface->flag & ME_SMOOTH;
+#ifdef WITH_FREESTYLE
+ flag = mface->flag & (ME_SMOOTH | ME_FREESTYLE_FACE);
+#else
+ flag = mface->flag & ME_SMOOTH;
+#endif
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
vlr->v1= RE_findOrAddVert(obr, vertofs+v1);
@@ -3219,6 +3226,26 @@ static void add_volume(Render *re, ObjectRen *obr, Material *ma)
BLI_addtail(&re->volumes, vo);
}
+#ifdef WITH_FREESTYLE
+static EdgeHash *make_freestyle_edge_mark_hash(MEdge *medge, int totedge)
+{
+ EdgeHash *edge_hash= BLI_edgehash_new();
+ int a;
+
+ for(a=0; a<totedge; a++) {
+ if(medge[a].flag & ME_FREESTYLE_EDGE)
+ BLI_edgehash_insert(edge_hash, medge[a].v1, medge[a].v2, medge+a);
+ }
+ return edge_hash;
+}
+
+static int has_freestyle_edge_mark(EdgeHash *edge_hash, int v1, int v2)
+{
+ MEdge *medge= BLI_edgehash_lookup(edge_hash, v1, v2);
+ return (!medge) ? 0 : 1;
+}
+#endif
+
static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
{
Object *ob= obr->ob;
@@ -3363,6 +3390,17 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
}
if (!timeoffset) {
+#ifdef WITH_FREESTYLE
+ EdgeHash *edge_hash;
+ MEdge *medge;
+ int totedge;
+
+ /* create a hash table of Freestyle edge marks */
+ medge = dm->getEdgeArray(dm);
+ totedge = dm->getNumEdges(dm);
+ edge_hash = make_freestyle_edge_mark_hash(medge, totedge);
+#endif
+
/* store customdata names, because DerivedMesh is freed */
RE_set_customdata_names(obr, &dm->faceData);
@@ -3411,7 +3449,11 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
v2= mface->v2;
v3= reverse_verts==0 ? mface->v3 : mface->v1;
v4= mface->v4;
- flag= mface->flag & ME_SMOOTH;
+#ifdef WITH_FREESTYLE
+ flag = mface->flag & (ME_SMOOTH | ME_FREESTYLE_FACE);
+#else
+ flag = mface->flag & ME_SMOOTH;
+#endif
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
vlr->v1= RE_findOrAddVert(obr, vertofs+v1);
@@ -3420,6 +3462,23 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
if (v4) vlr->v4= RE_findOrAddVert(obr, vertofs+v4);
else vlr->v4= 0;
+#ifdef WITH_FREESTYLE
+ /* Freestyle edge marks */
+ {
+ int edge_mark = 0;
+
+ if(has_freestyle_edge_mark(edge_hash, v1, v2)) edge_mark |= R_EDGE_V1V2;
+ if(has_freestyle_edge_mark(edge_hash, v2, v3)) edge_mark |= R_EDGE_V2V3;
+ if (!v4) {
+ if(has_freestyle_edge_mark(edge_hash, v3, v1)) edge_mark |= R_EDGE_V3V1;
+ } else {
+ if(has_freestyle_edge_mark(edge_hash, v3, v4)) edge_mark |= R_EDGE_V3V4;
+ if(has_freestyle_edge_mark(edge_hash, v4, v1)) edge_mark |= R_EDGE_V4V1;
+ }
+ vlr->freestyle_edge_mark= edge_mark;
+ }
+#endif
+
/* render normals are inverted in render */
if (use_original_normals) {
MFace *mf= me->mface+a;
@@ -3501,6 +3560,11 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
}
}
}
+
+#ifdef WITH_FREESTYLE
+ /* release the hash table of Freestyle edge marks */
+ BLI_edgehash_free(edge_hash, NULL);
+#endif
/* exception... we do edges for wire mode. potential conflict when faces exist... */
end= dm->getNumEdges(dm);
@@ -4300,6 +4364,26 @@ static void check_non_flat_quads(ObjectRen *obr)
/* new normals */
normal_tri_v3(vlr->n, vlr->v3->co, vlr->v2->co, vlr->v1->co);
normal_tri_v3(vlr1->n, vlr1->v3->co, vlr1->v2->co, vlr1->v1->co);
+
+#ifdef WITH_FREESTYLE
+ /* Freestyle edge marks */
+ if (vlr->flag & R_DIVIDE_24) {
+ vlr1->freestyle_edge_mark=
+ ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V1V2 : 0) |
+ ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0);
+ vlr->freestyle_edge_mark=
+ ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
+ ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
+ }
+ else {
+ vlr1->freestyle_edge_mark=
+ ((vlr->freestyle_edge_mark & R_EDGE_V3V4) ? R_EDGE_V2V3 : 0) |
+ ((vlr->freestyle_edge_mark & R_EDGE_V4V1) ? R_EDGE_V3V1 : 0);
+ vlr->freestyle_edge_mark=
+ ((vlr->freestyle_edge_mark & R_EDGE_V1V2) ? R_EDGE_V1V2 : 0) |
+ ((vlr->freestyle_edge_mark & R_EDGE_V2V3) ? R_EDGE_V2V3 : 0);
+ }
+#endif
}
/* clear the flag when not divided */
else vlr->flag &= ~R_DIVIDE_24;
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 3e9f5996ddc..866932632c2 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -75,6 +75,11 @@
#include "RE_engine.h"
#include "RE_pipeline.h"
+#ifdef WITH_FREESTYLE
+# include "BKE_library.h"
+# include "FRS_freestyle.h"
+#endif
+
/* internal */
#include "render_result.h"
#include "render_types.h"
@@ -942,6 +947,10 @@ void RE_TileProcessor(Render *re)
/* ************ This part uses API, for rendering Blender scenes ********** */
+#ifdef WITH_FREESTYLE
+static void add_freestyle(Render *re);
+#endif
+
static void do_render_3d(Render *re)
{
float cfra;
@@ -982,6 +991,13 @@ static void do_render_3d(Render *re)
if (!re->test_break(re->tbh))
add_halo_flare(re);
+#ifdef WITH_FREESTYLE
+ /* Freestyle */
+ if( re->r.mode & R_EDGE_FRS)
+ if(!re->test_break(re->tbh))
+ add_freestyle(re);
+#endif
+
/* free all render verts etc */
RE_Database_Free(re);
@@ -1421,6 +1437,74 @@ static void render_composit_stats(void *UNUSED(arg), char *str)
R.i.infostr = NULL;
}
+#ifdef WITH_FREESTYLE
+/* invokes Freestyle stroke rendering */
+static void add_freestyle(Render *re)
+{
+ SceneRenderLayer *srl, *actsrl;
+ LinkData *link;
+
+ actsrl = BLI_findlink(&re->r.layers, re->r.actlay);
+
+ FRS_init_stroke_rendering(re);
+
+ for (srl= (SceneRenderLayer *)re->r.layers.first; srl; srl= srl->next) {
+
+ link = (LinkData *)MEM_callocN(sizeof(LinkData), "LinkData to Freestyle render");
+ BLI_addtail(&re->freestyle_renders, link);
+
+ if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl)
+ continue;
+ if (FRS_is_freestyle_enabled(srl)) {
+ link->data = (void *)FRS_do_stroke_rendering(re, srl);
+ }
+ }
+
+ FRS_finish_stroke_rendering(re);
+}
+
+/* merges the results of Freestyle stroke rendering into a given render result */
+static void composite_freestyle_renders(Render *re, int sample)
+{
+ Render *freestyle_render;
+ SceneRenderLayer *srl, *actsrl;
+ LinkData *link;
+
+ actsrl = BLI_findlink(&re->r.layers, re->r.actlay);
+
+ link = (LinkData *)re->freestyle_renders.first;
+ for (srl= (SceneRenderLayer *)re->r.layers.first; srl; srl= srl->next) {
+ if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl)
+ continue;
+ if (FRS_is_freestyle_enabled(srl)) {
+ freestyle_render = (Render *)link->data;
+ render_result_exr_file_read(freestyle_render, sample);
+ FRS_composite_result(re, srl, freestyle_render);
+ RE_FreeRenderResult(freestyle_render->result);
+ freestyle_render->result = NULL;
+ }
+ link = link->next;
+ }
+}
+
+/* releases temporary scenes and renders for Freestyle stroke rendering */
+static void free_all_freestyle_renders(Scene *scene)
+{
+ Render *re1, *freestyle_render;
+ LinkData *link;
+
+ for (re1= RenderGlobal.renderlist.first; re1; re1= re1->next) {
+ for (link = (LinkData *)re1->freestyle_renders.first; link; link = link->next) {
+ if (link->data) {
+ freestyle_render = (Render *)link->data;
+ BKE_scene_unlink(G.main, freestyle_render->scene, scene);
+ RE_FreeRender(freestyle_render);
+ }
+ }
+ BLI_freelistN( &re1->freestyle_renders );
+ }
+}
+#endif
/* reads all buffers, calls optional composite, merges in first result->rectf */
static void do_merge_fullsample(Render *re, bNodeTree *ntree)
@@ -1462,6 +1546,10 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
if (sample) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
render_result_exr_file_read(re1, sample);
+#ifdef WITH_FREESTYLE
+ if( re1->r.mode & R_EDGE_FRS)
+ composite_freestyle_renders(re1, sample);
+#endif
BLI_rw_mutex_unlock(&re->resultmutex);
}
ntreeCompositTagRender(re1->scene); /* ensure node gets exec to put buffers on stack */
@@ -1664,6 +1752,10 @@ static void do_render_composite_fields_blur_3d(Render *re)
do_merge_fullsample(re, NULL);
}
+#ifdef WITH_FREESTYLE
+ free_all_freestyle_renders(re->scene);
+#endif
+
/* weak... the display callback wants an active renderlayer pointer... */
re->result->renlay = render_get_active_layer(re, re->result);
re->display_draw(re->ddh, re->result, NULL);
@@ -2140,6 +2232,17 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr
G.is_rendering = FALSE;
}
+#ifdef WITH_FREESTYLE
+void RE_RenderFreestyleStrokes(Render *re, Main *bmain, Scene *scene)
+{
+ re->result_ok= 0;
+ if(render_initialize_from_main(re, bmain, scene, NULL, NULL, scene->lay, 0, 0)) {
+ do_render_fields_blur_3d(re);
+ }
+ re->result_ok= 1;
+}
+#endif
+
static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovieHandle *mh, const char *name_override)
{
char name[FILE_MAX];
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 35b06385ae6..62919297e73 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -57,6 +57,10 @@
#include "render_result.h"
#include "render_types.h"
+#ifdef WITH_FREESTYLE
+# include "FRS_freestyle_config.h"
+#endif
+
/********************************** Free *************************************/
void render_result_free(RenderResult *res)
@@ -564,6 +568,9 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
rl->lay = (1 << 20) - 1;
rl->layflag = 0x7FFF; /* solid ztra halo strand */
rl->passflag = SCE_PASS_COMBINED;
+#ifdef WITH_FREESTYLE
+ FRS_add_freestyle_config( srl );
+#endif
re->r.actlay = 0;
}
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index 2d26ebe2b91..003e74bd69a 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -1713,6 +1713,14 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
if (ma->mode & (MA_FACETEXTURE_ALPHA))
shi->alpha= shi->vcol[3];
}
+#ifdef WITH_FREESTYLE
+ else if (ma->vcol_alpha) {
+ shi->r= shi->vcol[0];
+ shi->g= shi->vcol[1];
+ shi->b= shi->vcol[2];
+ shi->alpha= shi->vcol[3];
+ }
+#endif
else if (ma->mode & (MA_VERTEXCOLP)) {
float neg_alpha = 1.0f - shi->vcol[3];
shi->r= shi->r*neg_alpha + shi->vcol[0]*shi->vcol[3];
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 65a8945f82b..8ec61a62d49 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -87,6 +87,13 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_FREESTYLE)
+ list(APPEND INC
+ ../freestyle
+ )
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
if(WITH_OPENCOLLADA)
add_definitions(-DWITH_COLLADA)
endif()
diff --git a/source/blender/windowmanager/SConscript b/source/blender/windowmanager/SConscript
index 6db0e142ac4..5904a417190 100644
--- a/source/blender/windowmanager/SConscript
+++ b/source/blender/windowmanager/SConscript
@@ -69,6 +69,10 @@ if env['BF_BUILDINFO']:
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_FREESTYLE']:
+ incs += ' ../freestyle'
+ defs.append('WITH_FREESTYLE')
+
if env['WITH_BF_COMPOSITOR']:
defs.append("WITH_COMPOSITOR")
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 86fd4856f7e..942cce1b6dd 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -239,6 +239,9 @@ typedef struct wmNotifier {
#define NC_MOVIECLIP (20<<24)
#define NC_MASK (21<<24)
#define NC_GPENCIL (22<<24)
+#ifdef WITH_FREESTYLE
+# define NC_LINESTYLE (23<<24)
+#endif
/* data type, 256 entries is enough, it can overlap */
#define NOTE_DATA 0x00FF0000
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 2196ce7ba65..2d4e4a5334a 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -115,6 +115,10 @@
#include "BPY_extern.h"
#endif
+#ifdef WITH_FREESTYLE
+# include "FRS_freestyle.h"
+#endif
+
#include "WM_api.h"
#include "WM_types.h"
#include "wm.h"
@@ -434,6 +438,9 @@ void WM_file_read(bContext *C, const char *filepath, ReportList *reports)
BPY_app_handlers_reset(FALSE);
BPY_modules_load_user(C);
#endif
+#ifdef WITH_FREESTYLE
+ FRS_read_file(C);
+#endif
/* important to do before NULL'ing the context */
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
diff --git a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
index afd5f5b0177..702210d1c5f 100644
--- a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
+++ b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
@@ -60,4 +60,8 @@ if(WITH_GAMEENGINE)
add_definitions(-DWITH_GAMEENGINE)
endif()
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
blender_add_lib_nolist(blenkernel_blc "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blenderplayer/bad_level_call_stubs/SConscript b/source/blenderplayer/bad_level_call_stubs/SConscript
index f26f4dfea6b..41c84051fdf 100644
--- a/source/blenderplayer/bad_level_call_stubs/SConscript
+++ b/source/blenderplayer/bad_level_call_stubs/SConscript
@@ -41,4 +41,7 @@ if env['WITH_BF_INTERNATIONAL']:
if env['WITH_BF_GAMEENGINE']:
defs += ' WITH_GAMEENGINE'
+if env['WITH_BF_FREESTYLE']:
+ defs += ' WITH_FREESTYLE'
+
env.BlenderLib ('blenkernel_blc', sources = Split(sources), includes=Split(incs), defines=Split(defs), libtype=['player'],priority=[220] )
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 3692f00badc..dc6f40b9e8a 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -55,6 +55,10 @@ struct FCurve;
struct Heap;
struct HeapNode;
struct ID;
+#ifdef WITH_FREESTYLE
+struct FreestyleConfig;
+struct FreestyleLineSet;
+#endif
struct ImBuf;
struct Image;
struct ImageUser;
@@ -83,6 +87,9 @@ struct RenderLayer;
struct RenderResult;
struct Scene;
struct Scene;
+#ifdef WITH_FREESTYLE
+struct SceneRenderLayer;
+#endif
struct ScrArea;
struct SculptSession;
struct ShadeInput;
@@ -531,6 +538,15 @@ struct PyObject *pyrna_id_CreatePyObject(struct ID *id) {return NULL; }
void BPY_context_update(struct bContext *C) {};
const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *msgid) { return msgid; }
+#ifdef WITH_FREESTYLE
+/* Freestyle */
+void FRS_add_freestyle_config(struct SceneRenderLayer* srl) {}
+void FRS_free_freestyle_config(struct SceneRenderLayer* srl) {}
+struct FreestyleLineSet *FRS_get_active_lineset(struct FreestyleConfig *config) { return NULL; }
+short FRS_get_active_lineset_index(struct FreestyleConfig *config) { return 0; }
+void FRS_set_active_lineset_index(struct FreestyleConfig *config, short index) {}
+void FRS_unlink_target_object(struct FreestyleConfig *config, struct Object *ob) {}
+#endif
/* intern/dualcon */
struct DualConMesh;
struct DualConMesh *dualcon(const struct DualConMesh *input_mesh,
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 2115b2a5ff6..4ac8364aa19 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -80,6 +80,11 @@ if(WITH_BINRELOC)
blender_include_dirs(${BINRELOC_INCLUDE_DIRS})
endif()
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+ blender_include_dirs(../blender/freestyle)
+endif()
+
# Setup the exe sources and buildinfo
set(SRC
creator.c
@@ -279,15 +284,24 @@ if(WITH_PYTHON)
set(ADDON_EXCLUDE_CONDITIONAL "_addons_contrib/*") # dummy, wont do anything
endif()
+ # do not install freestyle dir if disabled
+ if(NOT WITH_FREESTYLE)
+ set(FREESTYLE_EXCLUDE_CONDITIONAL "freestyle/*")
+ else()
+ set(FREESTYLE_EXCLUDE_CONDITIONAL "_freestyle/*") # dummy, wont do anything
+ endif()
+
install(
DIRECTORY ${CMAKE_SOURCE_DIR}/release/scripts
DESTINATION ${TARGETDIR_VER}
PATTERN ".svn" EXCLUDE
PATTERN "__pycache__" EXCLUDE
PATTERN "${ADDON_EXCLUDE_CONDITIONAL}" EXCLUDE
+ PATTERN "${FREESTYLE_EXCLUDE_CONDITIONAL}" EXCLUDE
)
unset(ADDON_EXCLUDE_CONDITIONAL)
+ unset(FREESTYLE_EXCLUDE_CONDITIONAL)
endif()
# localization
@@ -852,6 +866,7 @@ endif()
bf_python_ext
bf_python_mathutils
bf_python_bmesh
+ bf_freestyle
bf_ikplugin
bf_modifiers
bf_bmesh
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 624b1148072..5aa0ca51a58 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -117,6 +117,10 @@
#include "BLI_scanfill.h" /* for BLI_setErrorCallBack, TODO, move elsewhere */
+#ifdef WITH_FREESTYLE
+# include "FRS_freestyle.h"
+#endif
+
#ifdef WITH_BUILDINFO_HEADER
# define BUILD_DATE
#endif
@@ -1304,6 +1308,11 @@ static void setupArguments(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
#ifdef WITH_FFMPEG
BLI_argsAdd(ba, 1, NULL, "--debug-ffmpeg", "\n\tEnable debug messages from FFmpeg library", debug_mode_generic, (void *)G_DEBUG_FFMPEG);
#endif
+
+#ifdef WITH_FREESTYLE
+ BLI_argsAdd(ba, 1, NULL, "--debug-freestyle", "\n\tEnable debug/profiling messages from Freestyle rendering", debug_mode_generic, (void *)G_DEBUG_FREESTYLE);
+#endif
+
BLI_argsAdd(ba, 1, NULL, "--debug-python", "\n\tEnable debug messages for python", debug_mode_generic, (void *)G_DEBUG_PYTHON);
BLI_argsAdd(ba, 1, NULL, "--debug-events", "\n\tEnable debug messages for the event system", debug_mode_generic, (void *)G_DEBUG_EVENTS);
BLI_argsAdd(ba, 1, NULL, "--debug-handlers", "\n\tEnable debug messages for event handling", debug_mode_generic, (void *)G_DEBUG_HANDLERS);
@@ -1541,6 +1550,12 @@ int main(int argc, const char **argv)
CTX_py_init_set(C, 1);
WM_keymap_init(C);
+#ifdef WITH_FREESTYLE
+ /* initialize Freestyle */
+ FRS_initialize();
+ FRS_set_context(C);
+#endif
+
/* OK we are ready for it */
#ifndef WITH_PYTHON_MODULE
BLI_argsParse(ba, 4, load_file, C);