Add Chromium-only Blender WebEngine parity work
This commit is contained in:
584
blender-5.2.0/source/blender/freestyle/CMakeLists.txt
Normal file
584
blender-5.2.0/source/blender/freestyle/CMakeLists.txt
Normal file
@@ -0,0 +1,584 @@
|
||||
# SPDX-FileCopyrightText: 2006 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
set(SRC
|
||||
FRS_freestyle.h
|
||||
intern/application/AppCanvas.cpp
|
||||
intern/application/AppCanvas.h
|
||||
intern/application/AppConfig.cpp
|
||||
intern/application/AppConfig.h
|
||||
intern/application/AppView.cpp
|
||||
intern/application/AppView.h
|
||||
intern/application/Controller.cpp
|
||||
intern/application/Controller.h
|
||||
intern/blender_interface/BlenderFileLoader.cpp
|
||||
intern/blender_interface/BlenderFileLoader.h
|
||||
intern/blender_interface/BlenderStrokeRenderer.cpp
|
||||
intern/blender_interface/BlenderStrokeRenderer.h
|
||||
intern/blender_interface/BlenderStyleModule.h
|
||||
intern/blender_interface/FRS_freestyle.cpp
|
||||
intern/geometry/BBox.h
|
||||
intern/geometry/Bezier.cpp
|
||||
intern/geometry/Bezier.h
|
||||
intern/geometry/FastGrid.cpp
|
||||
intern/geometry/FastGrid.h
|
||||
intern/geometry/FitCurve.cpp
|
||||
intern/geometry/FitCurve.h
|
||||
intern/geometry/Geom.h
|
||||
intern/geometry/GeomCleaner.cpp
|
||||
intern/geometry/GeomCleaner.h
|
||||
intern/geometry/GeomUtils.cpp
|
||||
intern/geometry/GeomUtils.h
|
||||
intern/geometry/Grid.cpp
|
||||
intern/geometry/Grid.h
|
||||
intern/geometry/GridHelpers.cpp
|
||||
intern/geometry/GridHelpers.h
|
||||
intern/geometry/HashGrid.cpp
|
||||
intern/geometry/HashGrid.h
|
||||
intern/geometry/Noise.cpp
|
||||
intern/geometry/Noise.h
|
||||
intern/geometry/Polygon.h
|
||||
intern/geometry/SweepLine.h
|
||||
intern/geometry/VecMat.h
|
||||
intern/geometry/matrix_util.cpp
|
||||
intern/geometry/matrix_util.h
|
||||
intern/geometry/normal_cycle.cpp
|
||||
intern/geometry/normal_cycle.h
|
||||
intern/image/GaussianFilter.cpp
|
||||
intern/image/GaussianFilter.h
|
||||
intern/image/Image.h
|
||||
intern/image/ImagePyramid.cpp
|
||||
intern/image/ImagePyramid.h
|
||||
intern/python/BPy_BBox.cpp
|
||||
intern/python/BPy_BBox.h
|
||||
intern/python/BPy_BinaryPredicate0D.cpp
|
||||
intern/python/BPy_BinaryPredicate0D.h
|
||||
intern/python/BPy_BinaryPredicate1D.cpp
|
||||
intern/python/BPy_BinaryPredicate1D.h
|
||||
intern/python/BPy_ContextFunctions.cpp
|
||||
intern/python/BPy_ContextFunctions.h
|
||||
intern/python/BPy_Convert.cpp
|
||||
intern/python/BPy_Convert.h
|
||||
intern/python/BPy_Freestyle.cpp
|
||||
intern/python/BPy_Freestyle.h
|
||||
intern/python/BPy_FrsMaterial.cpp
|
||||
intern/python/BPy_FrsMaterial.h
|
||||
intern/python/BPy_FrsNoise.cpp
|
||||
intern/python/BPy_FrsNoise.h
|
||||
intern/python/BPy_Id.cpp
|
||||
intern/python/BPy_Id.h
|
||||
intern/python/BPy_IntegrationType.cpp
|
||||
intern/python/BPy_IntegrationType.h
|
||||
intern/python/BPy_Interface0D.cpp
|
||||
intern/python/BPy_Interface0D.h
|
||||
intern/python/BPy_Interface1D.cpp
|
||||
intern/python/BPy_Interface1D.h
|
||||
intern/python/BPy_Iterator.cpp
|
||||
intern/python/BPy_Iterator.h
|
||||
intern/python/BPy_MediumType.cpp
|
||||
intern/python/BPy_MediumType.h
|
||||
intern/python/BPy_Nature.cpp
|
||||
intern/python/BPy_Nature.h
|
||||
intern/python/BPy_Operators.cpp
|
||||
intern/python/BPy_Operators.h
|
||||
intern/python/BPy_SShape.cpp
|
||||
intern/python/BPy_SShape.h
|
||||
intern/python/BPy_StrokeAttribute.cpp
|
||||
intern/python/BPy_StrokeAttribute.h
|
||||
intern/python/BPy_StrokeShader.cpp
|
||||
intern/python/BPy_StrokeShader.h
|
||||
intern/python/BPy_UnaryFunction0D.cpp
|
||||
intern/python/BPy_UnaryFunction0D.h
|
||||
intern/python/BPy_UnaryFunction1D.cpp
|
||||
intern/python/BPy_UnaryFunction1D.h
|
||||
intern/python/BPy_UnaryPredicate0D.cpp
|
||||
intern/python/BPy_UnaryPredicate0D.h
|
||||
intern/python/BPy_UnaryPredicate1D.cpp
|
||||
intern/python/BPy_UnaryPredicate1D.h
|
||||
intern/python/BPy_ViewMap.cpp
|
||||
intern/python/BPy_ViewMap.h
|
||||
intern/python/BPy_ViewShape.cpp
|
||||
intern/python/BPy_ViewShape.h
|
||||
intern/python/BinaryPredicate1D/BPy_FalseBP1D.cpp
|
||||
intern/python/BinaryPredicate1D/BPy_FalseBP1D.h
|
||||
intern/python/BinaryPredicate1D/BPy_Length2DBP1D.cpp
|
||||
intern/python/BinaryPredicate1D/BPy_Length2DBP1D.h
|
||||
intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.cpp
|
||||
intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.h
|
||||
intern/python/BinaryPredicate1D/BPy_TrueBP1D.cpp
|
||||
intern/python/BinaryPredicate1D/BPy_TrueBP1D.h
|
||||
intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.cpp
|
||||
intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.h
|
||||
intern/python/Director.cpp
|
||||
intern/python/Director.h
|
||||
intern/python/Interface0D/BPy_CurvePoint.cpp
|
||||
intern/python/Interface0D/BPy_CurvePoint.h
|
||||
intern/python/Interface0D/BPy_SVertex.cpp
|
||||
intern/python/Interface0D/BPy_SVertex.h
|
||||
intern/python/Interface0D/BPy_ViewVertex.cpp
|
||||
intern/python/Interface0D/BPy_ViewVertex.h
|
||||
intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
|
||||
intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.h
|
||||
intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp
|
||||
intern/python/Interface0D/ViewVertex/BPy_NonTVertex.h
|
||||
intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp
|
||||
intern/python/Interface0D/ViewVertex/BPy_TVertex.h
|
||||
intern/python/Interface1D/BPy_FEdge.cpp
|
||||
intern/python/Interface1D/BPy_FEdge.h
|
||||
intern/python/Interface1D/BPy_FrsCurve.cpp
|
||||
intern/python/Interface1D/BPy_FrsCurve.h
|
||||
intern/python/Interface1D/BPy_Stroke.cpp
|
||||
intern/python/Interface1D/BPy_Stroke.h
|
||||
intern/python/Interface1D/BPy_ViewEdge.cpp
|
||||
intern/python/Interface1D/BPy_ViewEdge.h
|
||||
intern/python/Interface1D/Curve/BPy_Chain.cpp
|
||||
intern/python/Interface1D/Curve/BPy_Chain.h
|
||||
intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
|
||||
intern/python/Interface1D/FEdge/BPy_FEdgeSharp.h
|
||||
intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
|
||||
intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.h
|
||||
intern/python/Iterator/BPy_AdjacencyIterator.cpp
|
||||
intern/python/Iterator/BPy_AdjacencyIterator.h
|
||||
intern/python/Iterator/BPy_ChainPredicateIterator.cpp
|
||||
intern/python/Iterator/BPy_ChainPredicateIterator.h
|
||||
intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp
|
||||
intern/python/Iterator/BPy_ChainSilhouetteIterator.h
|
||||
intern/python/Iterator/BPy_ChainingIterator.cpp
|
||||
intern/python/Iterator/BPy_ChainingIterator.h
|
||||
intern/python/Iterator/BPy_CurvePointIterator.cpp
|
||||
intern/python/Iterator/BPy_CurvePointIterator.h
|
||||
intern/python/Iterator/BPy_Interface0DIterator.cpp
|
||||
intern/python/Iterator/BPy_Interface0DIterator.h
|
||||
intern/python/Iterator/BPy_SVertexIterator.cpp
|
||||
intern/python/Iterator/BPy_SVertexIterator.h
|
||||
intern/python/Iterator/BPy_StrokeVertexIterator.cpp
|
||||
intern/python/Iterator/BPy_StrokeVertexIterator.h
|
||||
intern/python/Iterator/BPy_ViewEdgeIterator.cpp
|
||||
intern/python/Iterator/BPy_ViewEdgeIterator.h
|
||||
intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp
|
||||
intern/python/Iterator/BPy_orientedViewEdgeIterator.h
|
||||
intern/python/StrokeShader/BPy_BackboneStretcherShader.cpp
|
||||
intern/python/StrokeShader/BPy_BackboneStretcherShader.h
|
||||
intern/python/StrokeShader/BPy_BezierCurveShader.cpp
|
||||
intern/python/StrokeShader/BPy_BezierCurveShader.h
|
||||
intern/python/StrokeShader/BPy_BlenderTextureShader.cpp
|
||||
intern/python/StrokeShader/BPy_BlenderTextureShader.h
|
||||
intern/python/StrokeShader/BPy_CalligraphicShader.cpp
|
||||
intern/python/StrokeShader/BPy_CalligraphicShader.h
|
||||
intern/python/StrokeShader/BPy_ColorNoiseShader.cpp
|
||||
intern/python/StrokeShader/BPy_ColorNoiseShader.h
|
||||
intern/python/StrokeShader/BPy_ConstantColorShader.cpp
|
||||
intern/python/StrokeShader/BPy_ConstantColorShader.h
|
||||
intern/python/StrokeShader/BPy_ConstantThicknessShader.cpp
|
||||
intern/python/StrokeShader/BPy_ConstantThicknessShader.h
|
||||
intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.cpp
|
||||
intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.h
|
||||
intern/python/StrokeShader/BPy_GuidingLinesShader.cpp
|
||||
intern/python/StrokeShader/BPy_GuidingLinesShader.h
|
||||
intern/python/StrokeShader/BPy_IncreasingColorShader.cpp
|
||||
intern/python/StrokeShader/BPy_IncreasingColorShader.h
|
||||
intern/python/StrokeShader/BPy_IncreasingThicknessShader.cpp
|
||||
intern/python/StrokeShader/BPy_IncreasingThicknessShader.h
|
||||
intern/python/StrokeShader/BPy_PolygonalizationShader.cpp
|
||||
intern/python/StrokeShader/BPy_PolygonalizationShader.h
|
||||
intern/python/StrokeShader/BPy_SamplingShader.cpp
|
||||
intern/python/StrokeShader/BPy_SamplingShader.h
|
||||
intern/python/StrokeShader/BPy_SmoothingShader.cpp
|
||||
intern/python/StrokeShader/BPy_SmoothingShader.h
|
||||
intern/python/StrokeShader/BPy_SpatialNoiseShader.cpp
|
||||
intern/python/StrokeShader/BPy_SpatialNoiseShader.h
|
||||
intern/python/StrokeShader/BPy_StrokeTextureStepShader.cpp
|
||||
intern/python/StrokeShader/BPy_StrokeTextureStepShader.h
|
||||
intern/python/StrokeShader/BPy_ThicknessNoiseShader.cpp
|
||||
intern/python/StrokeShader/BPy_ThicknessNoiseShader.h
|
||||
intern/python/StrokeShader/BPy_TipRemoverShader.cpp
|
||||
intern/python/StrokeShader/BPy_TipRemoverShader.h
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DDouble.cpp
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DDouble.h
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DEdgeNature.cpp
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DEdgeNature.h
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DFloat.cpp
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DFloat.h
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DId.cpp
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DId.h
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DMaterial.cpp
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DMaterial.h
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.cpp
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DUnsigned.h
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec2f.cpp
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec2f.h
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec3f.cpp
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DVec3f.h
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.cpp
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DVectorViewShape.h
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DViewShape.cpp
|
||||
intern/python/UnaryFunction0D/BPy_UnaryFunction0DViewShape.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.h
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.cpp
|
||||
intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.h
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.cpp
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DDouble.h
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.cpp
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DEdgeNature.h
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.cpp
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DFloat.h
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.cpp
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DUnsigned.h
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.cpp
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec2f.h
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.cpp
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DVec3f.h
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.cpp
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DVectorViewShape.h
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.cpp
|
||||
intern/python/UnaryFunction1D/BPy_UnaryFunction1DVoid.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.h
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.cpp
|
||||
intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.h
|
||||
intern/python/UnaryPredicate0D/BPy_FalseUP0D.cpp
|
||||
intern/python/UnaryPredicate0D/BPy_FalseUP0D.h
|
||||
intern/python/UnaryPredicate0D/BPy_TrueUP0D.cpp
|
||||
intern/python/UnaryPredicate0D/BPy_TrueUP0D.h
|
||||
intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp
|
||||
intern/python/UnaryPredicate1D/BPy_ContourUP1D.h
|
||||
intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.cpp
|
||||
intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.h
|
||||
intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp
|
||||
intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.h
|
||||
intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp
|
||||
intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.h
|
||||
intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp
|
||||
intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.h
|
||||
intern/python/UnaryPredicate1D/BPy_FalseUP1D.cpp
|
||||
intern/python/UnaryPredicate1D/BPy_FalseUP1D.h
|
||||
intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.cpp
|
||||
intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.h
|
||||
intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp
|
||||
intern/python/UnaryPredicate1D/BPy_ShapeUP1D.h
|
||||
intern/python/UnaryPredicate1D/BPy_TrueUP1D.cpp
|
||||
intern/python/UnaryPredicate1D/BPy_TrueUP1D.h
|
||||
intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.cpp
|
||||
intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.h
|
||||
intern/scene_graph/DrawingStyle.h
|
||||
intern/scene_graph/FrsMaterial.h
|
||||
intern/scene_graph/IndexedFaceSet.cpp
|
||||
intern/scene_graph/IndexedFaceSet.h
|
||||
intern/scene_graph/LineRep.cpp
|
||||
intern/scene_graph/LineRep.h
|
||||
intern/scene_graph/Node.h
|
||||
intern/scene_graph/NodeCamera.cpp
|
||||
intern/scene_graph/NodeCamera.h
|
||||
intern/scene_graph/NodeDrawingStyle.cpp
|
||||
intern/scene_graph/NodeDrawingStyle.h
|
||||
intern/scene_graph/NodeGroup.cpp
|
||||
intern/scene_graph/NodeGroup.h
|
||||
intern/scene_graph/NodeLight.cpp
|
||||
intern/scene_graph/NodeLight.h
|
||||
intern/scene_graph/NodeShape.cpp
|
||||
intern/scene_graph/NodeShape.h
|
||||
intern/scene_graph/NodeTransform.cpp
|
||||
intern/scene_graph/NodeTransform.h
|
||||
intern/scene_graph/NodeViewLayer.cpp
|
||||
intern/scene_graph/NodeViewLayer.h
|
||||
intern/scene_graph/OrientedLineRep.cpp
|
||||
intern/scene_graph/OrientedLineRep.h
|
||||
intern/scene_graph/Rep.cpp
|
||||
intern/scene_graph/Rep.h
|
||||
intern/scene_graph/SceneHash.cpp
|
||||
intern/scene_graph/SceneHash.h
|
||||
intern/scene_graph/ScenePrettyPrinter.cpp
|
||||
intern/scene_graph/ScenePrettyPrinter.h
|
||||
intern/scene_graph/SceneVisitor.cpp
|
||||
intern/scene_graph/SceneVisitor.h
|
||||
intern/scene_graph/TriangleRep.cpp
|
||||
intern/scene_graph/TriangleRep.h
|
||||
intern/scene_graph/VertexRep.cpp
|
||||
intern/scene_graph/VertexRep.h
|
||||
intern/stroke/AdvancedFunctions0D.cpp
|
||||
intern/stroke/AdvancedFunctions0D.h
|
||||
intern/stroke/AdvancedFunctions1D.cpp
|
||||
intern/stroke/AdvancedFunctions1D.h
|
||||
intern/stroke/AdvancedPredicates1D.h
|
||||
intern/stroke/AdvancedStrokeShaders.cpp
|
||||
intern/stroke/AdvancedStrokeShaders.h
|
||||
intern/stroke/BasicStrokeShaders.cpp
|
||||
intern/stroke/BasicStrokeShaders.h
|
||||
intern/stroke/Canvas.cpp
|
||||
intern/stroke/Canvas.h
|
||||
intern/stroke/Chain.cpp
|
||||
intern/stroke/Chain.h
|
||||
intern/stroke/ChainingIterators.cpp
|
||||
intern/stroke/ChainingIterators.h
|
||||
intern/stroke/ContextFunctions.cpp
|
||||
intern/stroke/ContextFunctions.h
|
||||
intern/stroke/Curve.cpp
|
||||
intern/stroke/Curve.h
|
||||
intern/stroke/CurveAdvancedIterators.h
|
||||
intern/stroke/CurveIterators.h
|
||||
intern/stroke/Modifiers.h
|
||||
intern/stroke/Module.h
|
||||
intern/stroke/Operators.cpp
|
||||
intern/stroke/Operators.h
|
||||
intern/stroke/PSStrokeRenderer.cpp
|
||||
intern/stroke/PSStrokeRenderer.h
|
||||
intern/stroke/Predicates0D.cpp
|
||||
intern/stroke/Predicates0D.h
|
||||
intern/stroke/Predicates1D.cpp
|
||||
intern/stroke/Predicates1D.h
|
||||
intern/stroke/QInformationMap.h
|
||||
intern/stroke/Stroke.cpp
|
||||
intern/stroke/Stroke.h
|
||||
intern/stroke/StrokeAdvancedIterators.h
|
||||
intern/stroke/StrokeIO.cpp
|
||||
intern/stroke/StrokeIO.h
|
||||
intern/stroke/StrokeIterators.h
|
||||
intern/stroke/StrokeLayer.cpp
|
||||
intern/stroke/StrokeLayer.h
|
||||
intern/stroke/StrokeRenderer.cpp
|
||||
intern/stroke/StrokeRenderer.h
|
||||
intern/stroke/StrokeRep.cpp
|
||||
intern/stroke/StrokeRep.h
|
||||
intern/stroke/StrokeShader.cpp
|
||||
intern/stroke/StrokeShader.h
|
||||
intern/stroke/StrokeTesselator.cpp
|
||||
intern/stroke/StrokeTesselator.h
|
||||
intern/stroke/StyleModule.h
|
||||
intern/stroke/TextStrokeRenderer.cpp
|
||||
intern/stroke/TextStrokeRenderer.h
|
||||
intern/system/BaseIterator.h
|
||||
intern/system/BaseObject.cpp
|
||||
intern/system/BaseObject.h
|
||||
intern/system/Cast.h
|
||||
intern/system/Exception.cpp
|
||||
intern/system/Exception.h
|
||||
intern/system/FreestyleConfig.h
|
||||
intern/system/Id.h
|
||||
intern/system/Interpreter.h
|
||||
intern/system/Iterator.cpp
|
||||
intern/system/Iterator.h
|
||||
intern/system/PointerSequence.h
|
||||
intern/system/Precision.h
|
||||
intern/system/ProgressBar.h
|
||||
intern/system/PseudoNoise.cpp
|
||||
intern/system/PseudoNoise.h
|
||||
intern/system/PythonInterpreter.cpp
|
||||
intern/system/PythonInterpreter.h
|
||||
intern/system/RandGen.cpp
|
||||
intern/system/RandGen.h
|
||||
intern/system/RenderMonitor.h
|
||||
intern/system/StringUtils.cpp
|
||||
intern/system/StringUtils.h
|
||||
intern/system/TimeStamp.cpp
|
||||
intern/system/TimeStamp.h
|
||||
intern/system/TimeUtils.h
|
||||
intern/view_map/ArbitraryGridDensityProvider.cpp
|
||||
intern/view_map/ArbitraryGridDensityProvider.h
|
||||
intern/view_map/AutoPtrHelper.h
|
||||
intern/view_map/AverageAreaGridDensityProvider.cpp
|
||||
intern/view_map/AverageAreaGridDensityProvider.h
|
||||
intern/view_map/BoxGrid.cpp
|
||||
intern/view_map/BoxGrid.h
|
||||
intern/view_map/CulledOccluderSource.cpp
|
||||
intern/view_map/CulledOccluderSource.h
|
||||
intern/view_map/FEdgeXDetector.cpp
|
||||
intern/view_map/FEdgeXDetector.h
|
||||
intern/view_map/Functions0D.cpp
|
||||
intern/view_map/Functions0D.h
|
||||
intern/view_map/Functions1D.cpp
|
||||
intern/view_map/Functions1D.h
|
||||
intern/view_map/GridDensityProvider.h
|
||||
intern/view_map/HeuristicGridDensityProviderFactory.cpp
|
||||
intern/view_map/HeuristicGridDensityProviderFactory.h
|
||||
intern/view_map/Interface0D.cpp
|
||||
intern/view_map/Interface0D.h
|
||||
intern/view_map/Interface1D.cpp
|
||||
intern/view_map/Interface1D.h
|
||||
intern/view_map/OccluderSource.cpp
|
||||
intern/view_map/OccluderSource.h
|
||||
intern/view_map/Pow23GridDensityProvider.cpp
|
||||
intern/view_map/Pow23GridDensityProvider.h
|
||||
intern/view_map/Silhouette.cpp
|
||||
intern/view_map/Silhouette.h
|
||||
intern/view_map/SilhouetteGeomEngine.cpp
|
||||
intern/view_map/SilhouetteGeomEngine.h
|
||||
intern/view_map/SphericalGrid.cpp
|
||||
intern/view_map/SphericalGrid.h
|
||||
intern/view_map/SteerableViewMap.cpp
|
||||
intern/view_map/SteerableViewMap.h
|
||||
intern/view_map/ViewEdgeXBuilder.cpp
|
||||
intern/view_map/ViewEdgeXBuilder.h
|
||||
intern/view_map/ViewMap.cpp
|
||||
intern/view_map/ViewMap.h
|
||||
intern/view_map/ViewMapAdvancedIterators.h
|
||||
intern/view_map/ViewMapBuilder.cpp
|
||||
intern/view_map/ViewMapBuilder.h
|
||||
intern/view_map/ViewMapIterators.h
|
||||
intern/view_map/ViewMapTesselator.cpp
|
||||
intern/view_map/ViewMapTesselator.h
|
||||
intern/winged_edge/Curvature.cpp
|
||||
intern/winged_edge/Curvature.h
|
||||
intern/winged_edge/Nature.h
|
||||
intern/winged_edge/WEdge.cpp
|
||||
intern/winged_edge/WEdge.h
|
||||
intern/winged_edge/WFillGrid.cpp
|
||||
intern/winged_edge/WFillGrid.h
|
||||
intern/winged_edge/WSFillGrid.cpp
|
||||
intern/winged_edge/WSFillGrid.h
|
||||
intern/winged_edge/WXEdge.cpp
|
||||
intern/winged_edge/WXEdge.h
|
||||
intern/winged_edge/WXEdgeBuilder.cpp
|
||||
intern/winged_edge/WXEdgeBuilder.h
|
||||
intern/winged_edge/WingedEdgeBuilder.cpp
|
||||
intern/winged_edge/WingedEdgeBuilder.h
|
||||
)
|
||||
|
||||
set(LIB
|
||||
PRIVATE bf::blenkernel
|
||||
PRIVATE bf::blenlib
|
||||
PRIVATE bf::blentranslation
|
||||
PRIVATE bf::depsgraph
|
||||
PRIVATE bf::dna
|
||||
PRIVATE bf::imbuf
|
||||
PRIVATE bf::intern::guardedalloc
|
||||
bf_python_mathutils
|
||||
PRIVATE bf::render
|
||||
PRIVATE bf::dependencies::optional::python
|
||||
)
|
||||
|
||||
set(INC
|
||||
.
|
||||
../makesrna
|
||||
../python
|
||||
../python/intern
|
||||
../render/intern
|
||||
|
||||
# RNA_prototypes.hh
|
||||
${CMAKE_BINARY_DIR}/source/blender/makesrna
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
)
|
||||
|
||||
add_definitions(-DWITH_FREESTYLE)
|
||||
|
||||
if(WITH_PYTHON_MODULE)
|
||||
add_definitions(-DPy_ENABLE_SHARED)
|
||||
endif()
|
||||
|
||||
if(WITH_PYTHON_SAFETY)
|
||||
# For bpy_rna.hh access.
|
||||
add_definitions(-DWITH_PYTHON_SAFETY)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
# Suppress noisy warnings from GCC.
|
||||
# NOTE(@ideasman42): It seems resolving these could introduce functional changes.
|
||||
# Suppress unless someone is going to address them.
|
||||
string(APPEND CMAKE_CXX_FLAGS " -Wno-deprecated-copy")
|
||||
endif()
|
||||
|
||||
blender_add_lib(bf_freestyle "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
||||
if(COMMAND target_precompile_headers)
|
||||
target_precompile_headers(bf_freestyle PRIVATE FRS_precomp.h)
|
||||
endif()
|
||||
|
||||
# RNA_prototypes.hh
|
||||
add_dependencies(bf_freestyle bf_rna)
|
||||
58
blender-5.2.0/source/blender/freestyle/FRS_freestyle.h
Normal file
58
blender-5.2.0/source/blender/freestyle/FRS_freestyle.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct FreestyleConfig;
|
||||
struct FreestyleLineStyle;
|
||||
struct Material;
|
||||
struct Render;
|
||||
|
||||
struct FreestyleGlobals {
|
||||
struct Scene *scene;
|
||||
|
||||
/* camera information */
|
||||
float viewpoint[3];
|
||||
float mv[4][4];
|
||||
float proj[4][4];
|
||||
int viewport[4];
|
||||
};
|
||||
|
||||
extern struct FreestyleGlobals g_freestyle;
|
||||
|
||||
/* Rendering */
|
||||
void FRS_init(void);
|
||||
void FRS_set_context(struct bContext *C);
|
||||
int FRS_is_freestyle_enabled(struct ViewLayer *view_layer);
|
||||
void FRS_init_stroke_renderer(struct Render *re);
|
||||
void FRS_begin_stroke_rendering(struct Render *re);
|
||||
void FRS_do_stroke_rendering(struct Render *re, struct ViewLayer *view_layer);
|
||||
void FRS_end_stroke_rendering(struct Render *re);
|
||||
void FRS_free_view_map_cache(void);
|
||||
void FRS_composite_result(struct Render *re,
|
||||
struct ViewLayer *view_layer,
|
||||
struct Render *freestyle_render);
|
||||
void FRS_exit(void);
|
||||
|
||||
/* FreestyleConfig.linesets */
|
||||
void FRS_copy_active_lineset(struct FreestyleConfig *config);
|
||||
void FRS_paste_active_lineset(struct FreestyleConfig *config);
|
||||
void FRS_delete_active_lineset(struct FreestyleConfig *config);
|
||||
/**
|
||||
* Reinsert the active lineset at an offset \a direction from current position.
|
||||
* \return if position of active lineset has changed.
|
||||
*/
|
||||
bool FRS_move_active_lineset(struct FreestyleConfig *config, int direction);
|
||||
|
||||
/* Testing */
|
||||
struct Material *FRS_create_stroke_material(struct Main *bmain,
|
||||
struct FreestyleLineStyle *linestyle);
|
||||
|
||||
} // namespace blender
|
||||
53
blender-5.2.0/source/blender/freestyle/FRS_precomp.h
Normal file
53
blender-5.2.0/source/blender/freestyle/FRS_precomp.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/* Pre-compiled headers, see: D2606. */
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <math.h>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
#include <vector>
|
||||
|
||||
#include "intern/python/BPy_BBox.h"
|
||||
#include "intern/python/BPy_BinaryPredicate0D.h"
|
||||
#include "intern/python/BPy_BinaryPredicate1D.h"
|
||||
#include "intern/python/BPy_ContextFunctions.h"
|
||||
#include "intern/python/BPy_Convert.h"
|
||||
#include "intern/python/BPy_Freestyle.h"
|
||||
#include "intern/python/BPy_FrsMaterial.h"
|
||||
#include "intern/python/BPy_FrsNoise.h"
|
||||
#include "intern/python/BPy_Id.h"
|
||||
#include "intern/python/BPy_IntegrationType.h"
|
||||
#include "intern/python/BPy_Interface0D.h"
|
||||
#include "intern/python/BPy_Interface1D.h"
|
||||
#include "intern/python/BPy_Iterator.h"
|
||||
#include "intern/python/BPy_MediumType.h"
|
||||
#include "intern/python/BPy_Nature.h"
|
||||
#include "intern/python/BPy_Operators.h"
|
||||
#include "intern/python/BPy_SShape.h"
|
||||
#include "intern/python/BPy_StrokeAttribute.h"
|
||||
#include "intern/python/BPy_StrokeShader.h"
|
||||
#include "intern/python/BPy_UnaryFunction0D.h"
|
||||
#include "intern/python/BPy_UnaryFunction1D.h"
|
||||
#include "intern/python/BPy_UnaryPredicate0D.h"
|
||||
#include "intern/python/BPy_UnaryPredicate1D.h"
|
||||
#include "intern/python/BPy_ViewMap.h"
|
||||
#include "intern/python/BPy_ViewShape.h"
|
||||
#include "intern/python/Director.h"
|
||||
@@ -0,0 +1,220 @@
|
||||
/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "AppCanvas.h"
|
||||
#include "AppConfig.h"
|
||||
#include "AppView.h"
|
||||
#include "Controller.h"
|
||||
|
||||
#include "../image/Image.h"
|
||||
#include "../stroke/StrokeRenderer.h"
|
||||
#include "../stroke/StyleModule.h"
|
||||
#include "../system/TimeStamp.h"
|
||||
|
||||
#include "../system/StringUtils.h"
|
||||
namespace Freestyle {
|
||||
|
||||
AppCanvas::AppCanvas()
|
||||
{
|
||||
_pViewer = nullptr;
|
||||
_MapsPath = Config::Path::getInstance()->getMapsDir().c_str();
|
||||
}
|
||||
|
||||
AppCanvas::AppCanvas(AppView *iViewer)
|
||||
{
|
||||
_pViewer = iViewer;
|
||||
}
|
||||
|
||||
AppCanvas::AppCanvas(const AppCanvas &iBrother) : Canvas(iBrother)
|
||||
{
|
||||
_pViewer = iBrother._pViewer;
|
||||
}
|
||||
|
||||
AppCanvas::~AppCanvas()
|
||||
{
|
||||
_pViewer = nullptr;
|
||||
}
|
||||
|
||||
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 (uint 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_diffuse.width;
|
||||
int recty = _pass_diffuse.height;
|
||||
float xfac = float(rectx) / float(xmax - xmin);
|
||||
float yfac = float(recty) / float(ymax - ymin);
|
||||
#if 0
|
||||
if (blender::G.debug & blender::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 (blender::G.debug & blender::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() {}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,82 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "../stroke/Canvas.h"
|
||||
#include "AppView.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,76 @@
|
||||
/* SPDX-FileCopyrightText: 2008-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "../system/FreestyleConfig.h"
|
||||
#include "../system/StringUtils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "BKE_appdir.hh"
|
||||
|
||||
namespace Freestyle::Config {
|
||||
|
||||
Path *Path::_pInstance = nullptr;
|
||||
Path::Path()
|
||||
{
|
||||
// get the root directory
|
||||
// soc
|
||||
const std::optional<std::string> path = BKE_appdir_folder_id(blender::BLENDER_SYSTEM_SCRIPTS,
|
||||
nullptr);
|
||||
setRootDir(path.value_or(blender::BKE_appdir_program_dir()));
|
||||
|
||||
_pInstance = this;
|
||||
}
|
||||
|
||||
void Path::setRootDir(const string &iRootDir)
|
||||
{
|
||||
_ProjectDir = iRootDir + string(DIR_SEP) + "freestyle";
|
||||
_ModelsPath = "";
|
||||
_PatternsPath = _ProjectDir + string(DIR_SEP) + "data" + string(DIR_SEP) + "textures" +
|
||||
string(DIR_SEP) + "variation_patterns" + string(DIR_SEP);
|
||||
_BrushesPath = _ProjectDir + string(DIR_SEP) + "data" + string(DIR_SEP) + "textures" +
|
||||
string(DIR_SEP) + "brushes" + string(DIR_SEP);
|
||||
_EnvMapDir = _ProjectDir + string(DIR_SEP) + "data" + string(DIR_SEP) + "env_map" +
|
||||
string(DIR_SEP);
|
||||
_MapsDir = _ProjectDir + string(DIR_SEP) + "data" + string(DIR_SEP) + "maps" + string(DIR_SEP);
|
||||
}
|
||||
|
||||
void Path::setHomeDir(const string &iHomeDir)
|
||||
{
|
||||
_HomeDir = iHomeDir;
|
||||
}
|
||||
|
||||
Path::~Path()
|
||||
{
|
||||
_pInstance = nullptr;
|
||||
}
|
||||
|
||||
Path *Path::getInstance()
|
||||
{
|
||||
return _pInstance;
|
||||
}
|
||||
|
||||
string Path::getEnvVar(const string &iEnvVarName)
|
||||
{
|
||||
string value;
|
||||
if (!getenv(iEnvVarName.c_str())) {
|
||||
cerr << "Warning: You may want to set the $" << iEnvVarName
|
||||
<< " environment variable to use Freestyle." << endl
|
||||
<< " Otherwise, the current directory will be used instead." << endl;
|
||||
value = ".";
|
||||
}
|
||||
else {
|
||||
value = getenv(iEnvVarName.c_str());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace Freestyle::Config
|
||||
@@ -0,0 +1,104 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Configuration file
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "../system/Precision.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
namespace Config {
|
||||
|
||||
class Path {
|
||||
protected:
|
||||
static Path *_pInstance;
|
||||
string _ProjectDir;
|
||||
string _ModelsPath;
|
||||
string _PatternsPath;
|
||||
string _BrushesPath;
|
||||
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 &getEnvMapDir() const
|
||||
{
|
||||
return _EnvMapDir;
|
||||
}
|
||||
const string &getMapsDir() const
|
||||
{
|
||||
return _MapsDir;
|
||||
}
|
||||
const string &getHomeDir() const
|
||||
{
|
||||
return _HomeDir;
|
||||
}
|
||||
|
||||
static string getEnvVar(const string &iEnvVarName);
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Config:Path")
|
||||
};
|
||||
|
||||
//
|
||||
// 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");
|
||||
|
||||
} // namespace Config
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,162 @@
|
||||
/* SPDX-FileCopyrightText: 2008-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "AppConfig.h"
|
||||
#include "AppView.h"
|
||||
#include "Controller.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"
|
||||
#include "../view_map/Silhouette.h"
|
||||
#include "../view_map/ViewMap.h"
|
||||
|
||||
#include "BLI_math_rotation.h"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
#include "IMB_imbuf_types.hh"
|
||||
|
||||
#if 1 // FRS_antialiasing
|
||||
# include "BKE_global.hh"
|
||||
# include "DNA_scene_types.h"
|
||||
#endif
|
||||
|
||||
#include "FRS_freestyle.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
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 = std::min(
|
||||
std::min(_ModelRootNode->bbox().getMin()[0], _ModelRootNode->bbox().getMin()[1]),
|
||||
_ModelRootNode->bbox().getMin()[2]);
|
||||
_maxBBox = std::max(
|
||||
std::max(_ModelRootNode->bbox().getMax()[0], _ModelRootNode->bbox().getMax()[1]),
|
||||
_ModelRootNode->bbox().getMax()[2]);
|
||||
|
||||
_maxAbs = std::max(rabs(_minBBox), rabs(_maxBBox));
|
||||
_minAbs = std::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(UNPACK3(blender::g_freestyle.viewpoint));
|
||||
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(UNPACK3(blender::g_freestyle.viewpoint));
|
||||
|
||||
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 = std::min(
|
||||
(w1 - cameraCenter).norm(),
|
||||
std::min((w2 - cameraCenter).norm(),
|
||||
std::min((w3 - cameraCenter).norm(),
|
||||
std::min((w4 - cameraCenter).norm(),
|
||||
std::min((w5 - cameraCenter).norm(),
|
||||
std::min((w6 - cameraCenter).norm(),
|
||||
std::min((w7 - cameraCenter).norm(),
|
||||
(w8 - cameraCenter).norm())))))));
|
||||
|
||||
return std::max(_znear, 0.001);
|
||||
}
|
||||
|
||||
real AppView::zfar()
|
||||
{
|
||||
BBox<Vec3r> bbox = _ModelRootNode->bbox();
|
||||
Vec3r u = bbox.getMin();
|
||||
Vec3r v = bbox.getMax();
|
||||
Vec3r cameraCenter(UNPACK3(blender::g_freestyle.viewpoint));
|
||||
|
||||
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 = std::max(
|
||||
(w1 - cameraCenter).norm(),
|
||||
std::max((w2 - cameraCenter).norm(),
|
||||
std::max((w3 - cameraCenter).norm(),
|
||||
std::max((w4 - cameraCenter).norm(),
|
||||
std::max((w5 - cameraCenter).norm(),
|
||||
std::max((w6 - cameraCenter).norm(),
|
||||
std::max((w7 - cameraCenter).norm(),
|
||||
(w8 - cameraCenter).norm())))))));
|
||||
|
||||
return _zfar;
|
||||
}
|
||||
|
||||
real AppView::GetFocalLength()
|
||||
{
|
||||
real Near = std::max(0.1, (real)(-2.0f * _maxAbs + distanceToSceneCenter()));
|
||||
return Near;
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,257 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "AppConfig.h"
|
||||
|
||||
#include "../geometry/BBox.h"
|
||||
#include "../geometry/Geom.h"
|
||||
#include "../scene_graph/NodeDrawingStyle.h"
|
||||
#include "../system/Precision.h"
|
||||
|
||||
#include "BLI_math_base.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
using namespace Geometry;
|
||||
|
||||
class AppView {
|
||||
public:
|
||||
AppView(const char *iName = 0);
|
||||
virtual ~AppView();
|
||||
|
||||
public:
|
||||
// inherited
|
||||
inline uint width()
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
inline uint height()
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
inline BBox<Vec2i> border()
|
||||
{
|
||||
return _border;
|
||||
}
|
||||
inline float thickness()
|
||||
{
|
||||
return _thickness;
|
||||
}
|
||||
inline void setWidth(uint width)
|
||||
{
|
||||
_width = width;
|
||||
}
|
||||
inline void setHeight(uint 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:
|
||||
uint _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 = std::min(
|
||||
std::min(_ModelRootNode->bbox().getMin()[0], _ModelRootNode->bbox().getMin()[1]),
|
||||
_ModelRootNode->bbox().getMin()[2]);
|
||||
_maxBBox = std::max(
|
||||
std::max(_ModelRootNode->bbox().getMax()[0], _ModelRootNode->bbox().getMax()[1]),
|
||||
_ModelRootNode->bbox().getMax()[2]);
|
||||
|
||||
_maxAbs = std::max(rabs(_minBBox), rabs(_maxBBox));
|
||||
_minAbs = std::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 = std::min(
|
||||
std::min(_ModelRootNode->bbox().getMin()[0], _ModelRootNode->bbox().getMin()[1]),
|
||||
_ModelRootNode->bbox().getMin()[2]);
|
||||
_maxBBox = std::max(
|
||||
std::max(_ModelRootNode->bbox().getMax()[0], _ModelRootNode->bbox().getMax()[1]),
|
||||
_ModelRootNode->bbox().getMax()[2]);
|
||||
|
||||
_maxAbs = std::max(rabs(_minBBox), rabs(_maxBBox));
|
||||
_minAbs = std::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;
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:AppView")
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,269 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief The spinal tap of the system.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "../geometry/FastGrid.h"
|
||||
#include "../scene_graph/SceneHash.h"
|
||||
#include "../system/Precision.h"
|
||||
#include "../system/TimeUtils.h"
|
||||
#include "../view_map/FEdgeXDetector.h"
|
||||
#include "../view_map/ViewMapBuilder.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace blender {
|
||||
struct Depsgraph;
|
||||
struct Render;
|
||||
struct ViewLayer;
|
||||
} // namespace blender
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
class AppCanvas;
|
||||
class AppView;
|
||||
class Interpreter;
|
||||
class NodeGroup;
|
||||
class ProgressBar;
|
||||
class RenderMonitor;
|
||||
class SShape;
|
||||
class ViewEdge;
|
||||
class ViewMap;
|
||||
|
||||
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(blender::bContext *C);
|
||||
|
||||
// soc
|
||||
void init_options();
|
||||
|
||||
int LoadMesh(blender::Render *re, blender::ViewLayer *view_layer, blender::Depsgraph *depsgraph);
|
||||
int Load3DSFile(const char *iFileName);
|
||||
void CloseFile();
|
||||
void ComputeViewMap();
|
||||
void ComputeSteerableViewMap();
|
||||
void saveSteerableViewMapImages();
|
||||
void toggleEdgeTesselationNature(Nature::EdgeNature iNature);
|
||||
int DrawStrokes();
|
||||
void ResetRenderCount();
|
||||
blender::Render *RenderStrokes(blender::Render *re, bool render);
|
||||
void SwapStyleModules(uint i1, uint i2);
|
||||
void InsertStyleModule(uint index, const char *iFileName);
|
||||
void InsertStyleModule(uint index, const char *iName, const char *iBuffer);
|
||||
void InsertStyleModule(uint index, const char *iName, struct blender::Text *iText);
|
||||
void AddStyleModule(const char *iFileName);
|
||||
void RemoveStyleModule(uint index);
|
||||
void ReloadStyleModule(uint index, const char *iFileName);
|
||||
void Clear();
|
||||
void ClearRootNode();
|
||||
void DeleteWingedEdge();
|
||||
void DeleteViewMap(bool freeCache = false);
|
||||
void toggleLayer(uint index, bool iDisplay);
|
||||
void setModified(uint index, bool iMod);
|
||||
void resetModified(bool iMod = false);
|
||||
void updateCausalStyleModules(uint 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 setViewMapCache(bool iBool);
|
||||
bool getViewMapCache() const;
|
||||
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(float angle)
|
||||
{
|
||||
_creaseAngle = angle;
|
||||
}
|
||||
float getCreaseAngle() const
|
||||
{
|
||||
return _creaseAngle;
|
||||
}
|
||||
void setSphereRadius(float s)
|
||||
{
|
||||
_sphereRadius = s;
|
||||
}
|
||||
float getSphereRadius() const
|
||||
{
|
||||
return _sphereRadius;
|
||||
}
|
||||
void setSuggestiveContourKrDerivativeEpsilon(float dkr)
|
||||
{
|
||||
_suggestiveContourKrDerivativeEpsilon = dkr;
|
||||
}
|
||||
float getSuggestiveContourKrDerivativeEpsilon() const
|
||||
{
|
||||
return _suggestiveContourKrDerivativeEpsilon;
|
||||
}
|
||||
|
||||
void setModelsDir(const string &dir);
|
||||
string getModelsDir() const;
|
||||
void setModulesDir(const string &dir);
|
||||
string getModulesDir() const;
|
||||
|
||||
bool hitViewMapCache();
|
||||
|
||||
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;
|
||||
|
||||
#if 0
|
||||
// Silhouette structure:
|
||||
std::vector<SShape *> _SShapes;
|
||||
NodeGroup *_SRoot;
|
||||
|
||||
// Silhouette
|
||||
NodeGroup *_SilhouetteNode;
|
||||
NodeGroup *_ProjectedSilhouette;
|
||||
NodeGroup *_VisibleProjectedSilhouette;
|
||||
|
||||
// more Debug info
|
||||
NodeGroup *_DebugNode;
|
||||
#endif
|
||||
|
||||
// debug
|
||||
// NodeUser<ViewMap> *_ViewMapNode; // FIXME
|
||||
|
||||
// Chronometer:
|
||||
Chronometer _Chrono;
|
||||
|
||||
// Progress Bar
|
||||
ProgressBar *_ProgressBar;
|
||||
|
||||
// edges tesselation nature
|
||||
int _edgeTesselationNature;
|
||||
|
||||
FastGrid _Grid;
|
||||
// HashGrid _Grid;
|
||||
|
||||
BBox<Vec3r> _Scene3dBBox;
|
||||
uint _SceneNumFaces;
|
||||
#if 0
|
||||
real _minEdgeSize;
|
||||
#endif
|
||||
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 _EnableViewMapCache;
|
||||
bool _EnableQI;
|
||||
bool _EnableFaceSmoothness;
|
||||
bool _ComputeRidges;
|
||||
bool _ComputeSuggestive;
|
||||
bool _ComputeMaterialBoundaries;
|
||||
float _creaseAngle;
|
||||
float _sphereRadius;
|
||||
float _suggestiveContourKrDerivativeEpsilon;
|
||||
|
||||
bool _ComputeSteerableViewMap;
|
||||
|
||||
FEdgeXDetector edgeDetector;
|
||||
|
||||
SceneHash sceneHashFunc;
|
||||
real prevSceneHash;
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Controller")
|
||||
};
|
||||
|
||||
extern Controller *g_pController;
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,830 @@
|
||||
/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BlenderFileLoader.h"
|
||||
|
||||
#include "DNA_layer_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_customdata.hh"
|
||||
#include "BKE_global.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_object.hh"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using blender::float3;
|
||||
using blender::Span;
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
BlenderFileLoader::BlenderFileLoader(blender::Render *re,
|
||||
blender::ViewLayer *view_layer,
|
||||
blender::Depsgraph *depsgraph)
|
||||
{
|
||||
_re = re;
|
||||
_depsgraph = depsgraph;
|
||||
_Scene = nullptr;
|
||||
_numFacesRead = 0;
|
||||
#if 0
|
||||
_minEdgeSize = DBL_MAX;
|
||||
#endif
|
||||
_smooth = (view_layer->freestyle_config.flags & blender::FREESTYLE_FACE_SMOOTHNESS_FLAG) != 0;
|
||||
_pRenderMonitor = nullptr;
|
||||
}
|
||||
|
||||
BlenderFileLoader::~BlenderFileLoader()
|
||||
{
|
||||
_Scene = nullptr;
|
||||
}
|
||||
|
||||
NodeGroup *BlenderFileLoader::Load()
|
||||
{
|
||||
if (blender::G.debug & blender::G_DEBUG_FREESTYLE) {
|
||||
cout << "\n=== Importing triangular meshes into Blender ===" << endl;
|
||||
}
|
||||
|
||||
// creation of the scene root node
|
||||
_Scene = new NodeGroup;
|
||||
|
||||
if (_re->clip_start < 0.0f) {
|
||||
// Adjust clipping start/end and set up a Z offset when the viewport preview
|
||||
// is used with the orthographic view. In this case, _re->clip_start is negative,
|
||||
// while Freestyle assumes that imported mesh data are in the camera coordinate
|
||||
// system with the view point located at origin [bug #36009].
|
||||
_z_near = -0.001f;
|
||||
_z_offset = _re->clip_start + _z_near;
|
||||
_z_far = -_re->clip_end + _z_offset;
|
||||
}
|
||||
else {
|
||||
_z_near = -_re->clip_start;
|
||||
_z_far = -_re->clip_end;
|
||||
_z_offset = 0.0f;
|
||||
}
|
||||
|
||||
int id = 0;
|
||||
const blender::eEvaluationMode eval_mode = blender::DEG_get_mode(_depsgraph);
|
||||
|
||||
using blender::DEG_iterator_objects_end;
|
||||
using blender::DEGObjectIterData;
|
||||
using blender::Object;
|
||||
|
||||
blender::DEGObjectIterSettings deg_iter_settings{};
|
||||
deg_iter_settings.depsgraph = _depsgraph;
|
||||
deg_iter_settings.flags = blender::DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
|
||||
blender::DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
|
||||
blender::DEG_ITER_OBJECT_FLAG_VISIBLE |
|
||||
blender::DEG_ITER_OBJECT_FLAG_DUPLI;
|
||||
|
||||
DEG_OBJECT_ITER_BEGIN (°_iter_settings, ob) {
|
||||
if (_pRenderMonitor && _pRenderMonitor->testBreak()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ob->base_flag & (blender::BASE_HOLDOUT | blender::BASE_INDIRECT_ONLY)) ||
|
||||
(ob->visibility_flag & blender::OB_HOLDOUT))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(BKE_object_visibility(ob, eval_mode) & blender::OB_VISIBLE_SELF)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Evaluated meta-balls will appear as mesh objects in the iterator. */
|
||||
if (ob->type == blender::OB_MBALL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
blender::Mesh *mesh = BKE_object_to_mesh(nullptr, ob, false);
|
||||
|
||||
if (mesh) {
|
||||
insertShapeNode(ob, mesh, ++id);
|
||||
BKE_object_to_mesh_clear(ob);
|
||||
}
|
||||
}
|
||||
DEG_OBJECT_ITER_END;
|
||||
|
||||
// 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 (blender::G.debug & blender::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 (ELEM(sum, 3, -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[5],
|
||||
bool em1,
|
||||
bool em2,
|
||||
bool em3,
|
||||
const 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) {
|
||||
blender::copy_v3_v3(triCoords[k], v[i]);
|
||||
blender::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);
|
||||
blender::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);
|
||||
blender::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);
|
||||
blender::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);
|
||||
blender::copy_v3_v3(triNormals[k], n[j]);
|
||||
edgeMarks[k] = false;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
}
|
||||
BLI_assert(k == 2 + numTris);
|
||||
(void)numTris; /* Ignored in release builds. */
|
||||
}
|
||||
|
||||
void BlenderFileLoader::addTriangle(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];
|
||||
#if 0
|
||||
float len;
|
||||
#endif
|
||||
uint i, j;
|
||||
IndexedFaceSet::FaceEdgeMark marks = 0;
|
||||
|
||||
// initialize the bounding box by the first vertex
|
||||
if (ls->currentIndex == 0) {
|
||||
blender::copy_v3_v3(ls->minBBox, v1);
|
||||
blender::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++) {
|
||||
blender::copy_v3_v3(ls->pv, fv[i]);
|
||||
blender::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];
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
len = len_v3v3(fv[i], fv[(i + 1) % 3]);
|
||||
if (_minEdgeSize > len) {
|
||||
_minEdgeSize = len;
|
||||
}
|
||||
#endif
|
||||
|
||||
*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])
|
||||
{
|
||||
const float eps = 1.0e-6;
|
||||
const float eps_sq = eps * eps;
|
||||
|
||||
#if 0
|
||||
float area = area_tri_v3(v1, v2, v3);
|
||||
bool verbose = (area < 1.0e-6);
|
||||
#endif
|
||||
|
||||
if (blender::equals_v3v3(v1, v2) || blender::equals_v3v3(v2, v3) || blender::equals_v3v3(v1, v3))
|
||||
{
|
||||
#if 0
|
||||
if (verbose && G.debug & blender::G_DEBUG_FREESTYLE) {
|
||||
printf("BlenderFileLoader::testDegenerateTriangle = 1\n");
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
if (blender::dist_squared_to_line_segment_v3(v1, v2, v3) < eps_sq ||
|
||||
blender::dist_squared_to_line_segment_v3(v2, v1, v3) < eps_sq ||
|
||||
blender::dist_squared_to_line_segment_v3(v3, v1, v2) < eps_sq)
|
||||
{
|
||||
#if 0
|
||||
if (verbose && G.debug & blender::G_DEBUG_FREESTYLE) {
|
||||
printf("BlenderFileLoader::testDegenerateTriangle = 2\n");
|
||||
}
|
||||
#endif
|
||||
return 2;
|
||||
}
|
||||
#if 0
|
||||
if (verbose && G.debug & blender::G_DEBUG_FREESTYLE) {
|
||||
printf("BlenderFileLoader::testDegenerateTriangle = 0\n");
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool testEdgeMark(blender::Mesh *mesh,
|
||||
const blender::VArray<bool> &fed,
|
||||
const blender::int3 &tri,
|
||||
int i)
|
||||
{
|
||||
const Span<blender::int2> edges = mesh->edges();
|
||||
const Span<int> corner_verts = mesh->corner_verts();
|
||||
const Span<int> corner_edges = mesh->corner_edges();
|
||||
|
||||
const int corner = tri[i];
|
||||
const int corner_next = tri[(i + 1) % 3];
|
||||
const blender::int2 &edge = edges[corner_edges[corner]];
|
||||
|
||||
if (!ELEM(corner_verts[corner_next], edge[0], edge[1])) {
|
||||
/* Not an edge in the original mesh before triangulation. */
|
||||
return false;
|
||||
}
|
||||
|
||||
return fed[corner_edges[corner]];
|
||||
}
|
||||
|
||||
void BlenderFileLoader::insertShapeNode(blender::Object *ob, blender::Mesh *mesh, int id)
|
||||
{
|
||||
using namespace blender;
|
||||
char *name = ob->id.name + 2;
|
||||
|
||||
const Span<float3> vert_positions = mesh->vert_positions();
|
||||
const OffsetIndices mesh_polys = mesh->faces();
|
||||
const Span<int> corner_verts = mesh->corner_verts();
|
||||
|
||||
// Compute loop triangles
|
||||
int tottri = poly_to_tri_count(mesh->faces_num, mesh->corners_num);
|
||||
blender::int3 *corner_tris = MEM_new_array_uninitialized<blender::int3>(size_t(tottri),
|
||||
__func__);
|
||||
blender::bke::mesh::corner_tris_calc(
|
||||
vert_positions, mesh_polys, corner_verts, {corner_tris, tottri});
|
||||
const Span<int> tri_faces = mesh->corner_tri_faces();
|
||||
const Span<blender::float3> corner_normals = mesh->corner_normals();
|
||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
||||
|
||||
// Get other mesh data
|
||||
const VArray<bool> fed = *attributes.lookup_or_default<bool>(
|
||||
"freestyle_edge", bke::AttrDomain::Edge, false);
|
||||
const VArray<bool> ffa = *attributes.lookup_or_default<bool>(
|
||||
"freestyle_face", bke::AttrDomain::Face, false);
|
||||
|
||||
// Compute view matrix
|
||||
Object *ob_camera_eval = DEG_get_evaluated(_depsgraph, RE_GetCamera(_re));
|
||||
float viewinv[4][4], viewmat[4][4];
|
||||
RE_GetCameraModelMatrix(_re, ob_camera_eval, viewinv);
|
||||
invert_m4_m4(viewmat, viewinv);
|
||||
|
||||
// Compute matrix including camera transform
|
||||
float obmat[4][4], nmat[4][4];
|
||||
mul_m4_m4m4(obmat, viewmat, ob->object_to_world().ptr());
|
||||
invert_m4_m4(nmat, obmat);
|
||||
transpose_m4(nmat);
|
||||
|
||||
// We count the number of triangles after the clipping by the near and far view
|
||||
// planes is applied (NOTE: mesh vertices are in the camera coordinate system).
|
||||
uint numFaces = 0;
|
||||
float v1[3], v2[3], v3[3];
|
||||
float n1[3], n2[3], n3[3], facenormal[3];
|
||||
int clip[3];
|
||||
for (int a = 0; a < tottri; a++) {
|
||||
const int3 &tri = corner_tris[a];
|
||||
|
||||
copy_v3_v3(v1, vert_positions[corner_verts[tri[0]]]);
|
||||
copy_v3_v3(v2, vert_positions[corner_verts[tri[1]]]);
|
||||
copy_v3_v3(v3, vert_positions[corner_verts[tri[2]]]);
|
||||
|
||||
mul_m4_v3(obmat, v1);
|
||||
mul_m4_v3(obmat, v2);
|
||||
mul_m4_v3(obmat, v3);
|
||||
|
||||
v1[2] += _z_offset;
|
||||
v2[2] += _z_offset;
|
||||
v3[2] += _z_offset;
|
||||
|
||||
numFaces += countClippedFaces(v1, v2, v3, clip);
|
||||
}
|
||||
#if 0
|
||||
if (blender::G.debug & blender::G_DEBUG_FREESTYLE) {
|
||||
cout << "numFaces " << numFaces << endl;
|
||||
}
|
||||
#endif
|
||||
if (numFaces == 0) {
|
||||
MEM_delete(corner_tris);
|
||||
return;
|
||||
}
|
||||
|
||||
// We allocate memory for the meshes to be imported
|
||||
NodeGroup *currentMesh = new NodeGroup;
|
||||
NodeShape *shape = new NodeShape;
|
||||
|
||||
uint vSize = 3 * 3 * numFaces;
|
||||
float *vertices = new float[vSize];
|
||||
uint nSize = vSize;
|
||||
float *normals = new float[nSize];
|
||||
uint *numVertexPerFaces = new uint[numFaces];
|
||||
vector<Material *> meshMaterials;
|
||||
vector<FrsMaterial> meshFrsMaterials;
|
||||
|
||||
IndexedFaceSet::TRIANGLES_STYLE *faceStyle = new IndexedFaceSet::TRIANGLES_STYLE[numFaces];
|
||||
uint i;
|
||||
for (i = 0; i < numFaces; i++) {
|
||||
faceStyle[i] = IndexedFaceSet::TRIANGLES;
|
||||
numVertexPerFaces[i] = 3;
|
||||
}
|
||||
|
||||
IndexedFaceSet::FaceEdgeMark *faceEdgeMarks = new IndexedFaceSet::FaceEdgeMark[numFaces];
|
||||
|
||||
uint viSize = 3 * numFaces;
|
||||
uint *VIndices = new uint[viSize];
|
||||
uint niSize = viSize;
|
||||
uint *NIndices = new uint[niSize];
|
||||
uint *MIndices = new uint[viSize]; // Material Indices
|
||||
|
||||
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;
|
||||
|
||||
const VArray<int> material_indices = *attributes.lookup_or_default<int>(
|
||||
"material_index", bke::AttrDomain::Face, 0);
|
||||
const VArray<bool> sharp_faces = *attributes.lookup_or_default<bool>(
|
||||
"sharp_face", bke::AttrDomain::Face, false);
|
||||
|
||||
// We parse the vlak nodes again and import meshes while applying the clipping
|
||||
// by the near and far view planes.
|
||||
for (int a = 0; a < tottri; a++) {
|
||||
const int3 &tri = corner_tris[a];
|
||||
const int poly_i = tri_faces[a];
|
||||
Material *mat = BKE_object_material_get(ob, material_indices[poly_i] + 1);
|
||||
|
||||
copy_v3_v3(v1, vert_positions[corner_verts[tri[0]]]);
|
||||
copy_v3_v3(v2, vert_positions[corner_verts[tri[1]]]);
|
||||
copy_v3_v3(v3, vert_positions[corner_verts[tri[2]]]);
|
||||
|
||||
mul_m4_v3(obmat, v1);
|
||||
mul_m4_v3(obmat, v2);
|
||||
mul_m4_v3(obmat, v3);
|
||||
|
||||
v1[2] += _z_offset;
|
||||
v2[2] += _z_offset;
|
||||
v3[2] += _z_offset;
|
||||
|
||||
if (_smooth && (!sharp_faces[poly_i])) {
|
||||
copy_v3_v3(n1, corner_normals[tri[0]]);
|
||||
copy_v3_v3(n2, corner_normals[tri[1]]);
|
||||
copy_v3_v3(n3, corner_normals[tri[2]]);
|
||||
|
||||
mul_mat3_m4_v3(nmat, n1);
|
||||
mul_mat3_m4_v3(nmat, n2);
|
||||
mul_mat3_m4_v3(nmat, n3);
|
||||
|
||||
normalize_v3(n1);
|
||||
normalize_v3(n2);
|
||||
normalize_v3(n3);
|
||||
}
|
||||
else {
|
||||
normal_tri_v3(facenormal, v3, v2, v1);
|
||||
|
||||
copy_v3_v3(n1, facenormal);
|
||||
copy_v3_v3(n2, facenormal);
|
||||
copy_v3_v3(n3, facenormal);
|
||||
}
|
||||
|
||||
uint numTris = countClippedFaces(v1, v2, v3, clip);
|
||||
if (numTris == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool fm = ffa[poly_i];
|
||||
bool em1 = false, em2 = false, em3 = false;
|
||||
|
||||
if (fed) {
|
||||
em1 = testEdgeMark(mesh, fed, tri, 0);
|
||||
em2 = testEdgeMark(mesh, fed, tri, 1);
|
||||
em3 = testEdgeMark(mesh, fed, tri, 2);
|
||||
}
|
||||
|
||||
if (mat) {
|
||||
tmpMat.setLine(mat->line_col[0], mat->line_col[1], mat->line_col[2], mat->line_col[3]);
|
||||
tmpMat.setDiffuse(mat->r, mat->g, mat->b, 1.0f);
|
||||
tmpMat.setSpecular(mat->specr, mat->specg, mat->specb, 1.0f);
|
||||
tmpMat.setShininess(128.0f);
|
||||
tmpMat.setPriority(mat->line_priority);
|
||||
}
|
||||
|
||||
if (meshMaterials.empty()) {
|
||||
meshMaterials.push_back(mat);
|
||||
meshFrsMaterials.push_back(tmpMat);
|
||||
shape->setFrsMaterial(tmpMat);
|
||||
}
|
||||
else {
|
||||
// find if the Blender material is already in the list
|
||||
uint i = 0;
|
||||
bool found = false;
|
||||
|
||||
for (vector<Material *>::iterator it = meshMaterials.begin(), itend = meshMaterials.end();
|
||||
it != itend;
|
||||
it++, i++)
|
||||
{
|
||||
if (*it == mat) {
|
||||
ls.currentMIndex = i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
meshMaterials.push_back(mat);
|
||||
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
|
||||
|
||||
clipTriangle(
|
||||
numTris, triCoords, v1, v2, v3, triNormals, n1, n2, n3, edgeMarks, em1, em2, em3, clip);
|
||||
for (i = 0; i < numTris; 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) ? edgeMarks[i + 2] : false);
|
||||
_numFacesRead++;
|
||||
}
|
||||
}
|
||||
|
||||
MEM_delete(corner_tris);
|
||||
|
||||
// We might have several times the same vertex. We want a clean
|
||||
// shape with no real-vertex. Here, we are making a cleaning pass.
|
||||
float *cleanVertices = nullptr;
|
||||
uint cvSize;
|
||||
uint *cleanVIndices = nullptr;
|
||||
|
||||
GeomCleaner::CleanIndexedVertexArray(
|
||||
vertices, vSize, VIndices, viSize, &cleanVertices, &cvSize, &cleanVIndices);
|
||||
|
||||
float *cleanNormals = nullptr;
|
||||
uint cnSize;
|
||||
uint *cleanNIndices = nullptr;
|
||||
|
||||
GeomCleaner::CleanIndexedVertexArray(
|
||||
normals, nSize, NIndices, niSize, &cleanNormals, &cnSize, &cleanNIndices);
|
||||
|
||||
// format materials array
|
||||
FrsMaterial **marray = new FrsMaterial *[meshFrsMaterials.size()];
|
||||
uint 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);
|
||||
uint 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
|
||||
}
|
||||
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 (uint 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.empty()) {
|
||||
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 (blender::G.debug & blender::G_DEBUG_FREESTYLE) {
|
||||
printf("Warning: Object %s contains %lu degenerated triangle%s (strokes may be incorrect)\n",
|
||||
name,
|
||||
ulong(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(),
|
||||
nullptr,
|
||||
0,
|
||||
numFaces,
|
||||
numVertexPerFaces,
|
||||
faceStyle,
|
||||
faceEdgeMarks,
|
||||
cleanVIndices,
|
||||
viSize,
|
||||
cleanNIndices,
|
||||
niSize,
|
||||
MIndices,
|
||||
viSize,
|
||||
nullptr,
|
||||
0,
|
||||
0);
|
||||
// sets the id of the rep
|
||||
rep->setId(Id(id, 0));
|
||||
rep->setName(ob->id.name + 2);
|
||||
rep->setLibraryPath(ob->id.lib ? ob->id.lib->filepath : "");
|
||||
|
||||
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);
|
||||
|
||||
currentMesh->AddChild(shape);
|
||||
_Scene->AddChild(currentMesh);
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,148 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include <float.h>
|
||||
#include <string.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/NodeShape.h"
|
||||
#include "../scene_graph/NodeTransform.h"
|
||||
#include "../system/FreestyleConfig.h"
|
||||
#include "../system/RenderMonitor.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "render_types.h"
|
||||
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_material.hh"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_scene.hh"
|
||||
|
||||
#include "BLI_iterator.h"
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
class NodeGroup;
|
||||
|
||||
struct LoaderState {
|
||||
float *pv;
|
||||
float *pn;
|
||||
IndexedFaceSet::FaceEdgeMark *pm;
|
||||
uint *pvi;
|
||||
uint *pni;
|
||||
uint *pmi;
|
||||
uint currentIndex;
|
||||
uint currentMIndex;
|
||||
float minBBox[3];
|
||||
float maxBBox[3];
|
||||
};
|
||||
|
||||
class BlenderFileLoader {
|
||||
public:
|
||||
/** Builds a MaxFileLoader */
|
||||
BlenderFileLoader(blender::Render *re,
|
||||
blender::ViewLayer *view_layer,
|
||||
blender::Depsgraph *depsgraph);
|
||||
virtual ~BlenderFileLoader();
|
||||
|
||||
/** Loads the 3D scene and returns a pointer to the scene root node */
|
||||
NodeGroup *Load();
|
||||
|
||||
/** Gets the number of read faces */
|
||||
inline uint numFacesRead()
|
||||
{
|
||||
return _numFacesRead;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/** Gets the smallest edge size read */
|
||||
inline real minEdgeSize()
|
||||
{
|
||||
return _minEdgeSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Modifiers */
|
||||
inline void setRenderMonitor(RenderMonitor *iRenderMonitor)
|
||||
{
|
||||
_pRenderMonitor = iRenderMonitor;
|
||||
}
|
||||
|
||||
protected:
|
||||
void insertShapeNode(blender::Object *ob, blender::Mesh *mesh, int id);
|
||||
int testDegenerateTriangle(float v1[3], float v2[3], float v3[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,
|
||||
const 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 {
|
||||
uint viA, viB, viP; // 0 <= viA, viB, viP < viSize
|
||||
Vec3r v;
|
||||
uint n;
|
||||
};
|
||||
blender::Render *_re;
|
||||
blender::Depsgraph *_depsgraph;
|
||||
NodeGroup *_Scene;
|
||||
uint _numFacesRead;
|
||||
#if 0
|
||||
real _minEdgeSize;
|
||||
#endif
|
||||
bool _smooth; /* if true, face smoothness is taken into account */
|
||||
float _z_near, _z_far;
|
||||
float _z_offset;
|
||||
|
||||
RenderMonitor *_pRenderMonitor;
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BlenderFileLoader")
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,908 @@
|
||||
/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BlenderStrokeRenderer.h"
|
||||
|
||||
#include "../application/AppConfig.h"
|
||||
#include "../stroke/Canvas.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_prototypes.hh"
|
||||
#include "RNA_types.hh"
|
||||
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_linestyle_types.h"
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
|
||||
#include "BKE_attribute.h"
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_collection.hh"
|
||||
#include "BKE_customdata.hh"
|
||||
#include "BKE_global.hh"
|
||||
#include "BKE_idprop.hh"
|
||||
#include "BKE_layer.hh"
|
||||
#include "BKE_lib_id.hh" /* free_libblock */
|
||||
#include "BKE_main.hh"
|
||||
#include "BKE_material.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_node.hh"
|
||||
#include "BKE_node_legacy_types.hh"
|
||||
#include "BKE_node_tree_update.hh"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_scene.hh"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_color.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
#include "DEG_depsgraph_build.hh"
|
||||
|
||||
#include "RE_pipeline.h"
|
||||
|
||||
#include "render_types.h"
|
||||
|
||||
#include <climits>
|
||||
|
||||
using blender::float3;
|
||||
using blender::Material;
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
const char *BlenderStrokeRenderer::uvNames[] = {"along_stroke", "along_stroke_tips"};
|
||||
|
||||
BlenderStrokeRenderer::BlenderStrokeRenderer(blender::Render *re, int render_count)
|
||||
{
|
||||
using namespace blender;
|
||||
|
||||
freestyle_bmain = blender::BKE_main_new();
|
||||
|
||||
/* NOTE(@sergey): We use the same window manager for freestyle `bmain` as real `bmain` uses.
|
||||
* This is needed because freestyle's `bmain` could be used to tag scenes for update,
|
||||
* which implies call of #ED_render_scene_update in some cases and that function
|
||||
* requires proper window manager to present. */
|
||||
freestyle_bmain->wm = re->main->wm;
|
||||
|
||||
// for stroke mesh generation
|
||||
_width = re->winx;
|
||||
_height = re->winy;
|
||||
|
||||
old_scene = re->scene;
|
||||
|
||||
char name[MAX_ID_NAME - 2];
|
||||
SNPRINTF(name, "FRS%d_%s", render_count, re->scene->id.name + 2);
|
||||
freestyle_scene = BKE_scene_add(freestyle_bmain, name);
|
||||
freestyle_scene->r.cfra = old_scene->r.cfra;
|
||||
freestyle_scene->r.mode = old_scene->r.mode & ~(R_EDGE_FRS | 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.size = 100; // old_scene->r.size
|
||||
freestyle_scene->r.color_mgt_flag = 0; // old_scene->r.color_mgt_flag;
|
||||
freestyle_scene->r.scemode = (old_scene->r.scemode &
|
||||
~(R_SINGLE_LAYER | R_NO_FRAME_UPDATE | R_MULTIVIEW)) &
|
||||
(re->r.scemode);
|
||||
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;
|
||||
STRNCPY(freestyle_scene->r.pic, old_scene->r.pic);
|
||||
freestyle_scene->r.dither_intensity = old_scene->r.dither_intensity;
|
||||
STRNCPY(freestyle_scene->r.engine, old_scene->r.engine);
|
||||
if (blender::G.debug & blender::G_DEBUG_FREESTYLE) {
|
||||
cout << "Stroke rendering engine : " << freestyle_scene->r.engine << endl;
|
||||
}
|
||||
freestyle_scene->r.im_format.color_mode = ImColorMode::RGBA;
|
||||
freestyle_scene->r.im_format.imtype = R_IMF_IMTYPE_PNG;
|
||||
|
||||
// Copy ID properties, including Cycles render properties
|
||||
if (old_scene->id.properties) {
|
||||
freestyle_scene->id.properties = IDP_CopyProperty_ex(old_scene->id.properties, 0);
|
||||
}
|
||||
if (old_scene->id.system_properties) {
|
||||
freestyle_scene->id.system_properties = IDP_CopyProperty_ex(old_scene->id.system_properties,
|
||||
0);
|
||||
}
|
||||
// Copy eevee render settings.
|
||||
BKE_scene_copy_data_eevee(freestyle_scene, old_scene);
|
||||
|
||||
/* Render with transparent background. */
|
||||
freestyle_scene->r.alphamode = R_ALPHAPREMUL;
|
||||
|
||||
if (blender::G.debug & blender::G_DEBUG_FREESTYLE) {
|
||||
printf("%s: %d thread(s)\n", __func__, BKE_render_num_threads(&freestyle_scene->r));
|
||||
}
|
||||
|
||||
BKE_scene_set_background(freestyle_bmain, freestyle_scene);
|
||||
|
||||
// Scene layer.
|
||||
ViewLayer *view_layer = (ViewLayer *)freestyle_scene->view_layers.first;
|
||||
view_layer->layflag = SCE_LAY_SOLID;
|
||||
|
||||
// Camera
|
||||
Object *object_camera = BKE_object_add(
|
||||
freestyle_bmain, freestyle_scene, view_layer, OB_CAMERA, nullptr);
|
||||
|
||||
Camera *camera = (Camera *)object_camera->data;
|
||||
camera->type = CAM_ORTHO;
|
||||
camera->ortho_scale = max(re->rectx, re->recty);
|
||||
camera->clip_start = 0.1f;
|
||||
camera->clip_end = 100.0f;
|
||||
|
||||
_z_delta = 0.00001f;
|
||||
_z = camera->clip_start + _z_delta;
|
||||
|
||||
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;
|
||||
|
||||
// Reset serial mesh ID (used for BlenderStrokeRenderer::NewMesh())
|
||||
_mesh_id = 0xffffffff;
|
||||
|
||||
// Depsgraph
|
||||
freestyle_depsgraph = DEG_graph_new(
|
||||
freestyle_bmain, freestyle_scene, view_layer, DAG_EVAL_RENDER);
|
||||
DEG_graph_id_tag_update(freestyle_bmain, freestyle_depsgraph, &freestyle_scene->id, 0);
|
||||
DEG_graph_id_tag_update(freestyle_bmain, freestyle_depsgraph, &object_camera->id, 0);
|
||||
DEG_graph_tag_relations_update(freestyle_depsgraph);
|
||||
}
|
||||
|
||||
BlenderStrokeRenderer::~BlenderStrokeRenderer()
|
||||
{
|
||||
DEG_graph_free(freestyle_depsgraph);
|
||||
|
||||
FreeStrokeGroups();
|
||||
|
||||
/* detach the window manager from freestyle bmain (see comments
|
||||
* in add_freestyle() for more detail)
|
||||
*/
|
||||
freestyle_bmain->wm.clear_no_delete();
|
||||
|
||||
BKE_main_free(freestyle_bmain);
|
||||
}
|
||||
|
||||
float BlenderStrokeRenderer::get_stroke_vertex_z() const
|
||||
{
|
||||
float z = _z;
|
||||
BlenderStrokeRenderer *self = const_cast<BlenderStrokeRenderer *>(this);
|
||||
self->_z += _z_delta;
|
||||
return -z;
|
||||
}
|
||||
|
||||
uint BlenderStrokeRenderer::get_stroke_mesh_id() const
|
||||
{
|
||||
uint mesh_id = _mesh_id;
|
||||
BlenderStrokeRenderer *self = const_cast<BlenderStrokeRenderer *>(this);
|
||||
self->_mesh_id--;
|
||||
return mesh_id;
|
||||
}
|
||||
|
||||
Material *BlenderStrokeRenderer::GetStrokeShader(blender::Main *bmain,
|
||||
blender::bNodeTree *iNodeTree,
|
||||
bool do_id_user)
|
||||
{
|
||||
using namespace blender;
|
||||
|
||||
Material *ma = BKE_material_add(bmain, "stroke_shader");
|
||||
bNodeTree *ntree;
|
||||
bNode *output_linestyle = nullptr;
|
||||
bNodeSocket *fromsock, *tosock;
|
||||
PointerRNA fromptr, toptr;
|
||||
NodeShaderAttribute *storage;
|
||||
|
||||
id_us_min(&ma->id);
|
||||
|
||||
if (iNodeTree) {
|
||||
// make a copy of linestyle->nodetree
|
||||
if (ma->nodetree) {
|
||||
bke::node_tree_free_embedded_tree(ma->nodetree);
|
||||
MEM_delete(ma->nodetree);
|
||||
ma->nodetree = nullptr;
|
||||
}
|
||||
ntree = blender::bke::node_tree_copy_tree_ex(*iNodeTree, bmain, do_id_user);
|
||||
|
||||
// find the active Output Line Style node
|
||||
for (bNode &node : ntree->nodes) {
|
||||
if (node.type_legacy == SH_NODE_OUTPUT_LINESTYLE && (node.flag & NODE_DO_OUTPUT)) {
|
||||
output_linestyle = &node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ma->nodetree = ntree;
|
||||
ntree->owner_id = &ma->id;
|
||||
}
|
||||
else {
|
||||
ntree = ma->nodetree;
|
||||
}
|
||||
ma->blend_method = MA_BM_HASHED;
|
||||
|
||||
bNode *input_attr_color = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_ATTRIBUTE);
|
||||
input_attr_color->location[0] = 0.0f;
|
||||
input_attr_color->location[1] = -200.0f;
|
||||
storage = (NodeShaderAttribute *)input_attr_color->storage;
|
||||
STRNCPY(storage->name, "Color");
|
||||
|
||||
bNode *mix_rgb_color = blender::bke::node_add_static_node(
|
||||
nullptr, *ntree, SH_NODE_MIX_RGB_LEGACY);
|
||||
mix_rgb_color->custom1 = MA_RAMP_BLEND; // Mix
|
||||
mix_rgb_color->location[0] = 200.0f;
|
||||
mix_rgb_color->location[1] = -200.0f;
|
||||
tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 0); // Fac
|
||||
toptr = RNA_pointer_create_discrete((ID *)ntree, RNA_NodeSocket, tosock);
|
||||
RNA_float_set(&toptr, "default_value", 0.0f);
|
||||
|
||||
bNode *input_attr_alpha = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_ATTRIBUTE);
|
||||
input_attr_alpha->location[0] = 400.0f;
|
||||
input_attr_alpha->location[1] = 300.0f;
|
||||
storage = (NodeShaderAttribute *)input_attr_alpha->storage;
|
||||
STRNCPY(storage->name, "Alpha");
|
||||
|
||||
bNode *mix_rgb_alpha = blender::bke::node_add_static_node(
|
||||
nullptr, *ntree, SH_NODE_MIX_RGB_LEGACY);
|
||||
mix_rgb_alpha->custom1 = MA_RAMP_BLEND; // Mix
|
||||
mix_rgb_alpha->location[0] = 600.0f;
|
||||
mix_rgb_alpha->location[1] = 300.0f;
|
||||
tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 0); // Fac
|
||||
toptr = RNA_pointer_create_discrete((ID *)ntree, RNA_NodeSocket, tosock);
|
||||
RNA_float_set(&toptr, "default_value", 0.0f);
|
||||
|
||||
bNode *shader_emission = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_EMISSION);
|
||||
shader_emission->location[0] = 400.0f;
|
||||
shader_emission->location[1] = -200.0f;
|
||||
|
||||
bNode *input_light_path = blender::bke::node_add_static_node(
|
||||
nullptr, *ntree, SH_NODE_LIGHT_PATH);
|
||||
input_light_path->location[0] = 400.0f;
|
||||
input_light_path->location[1] = 100.0f;
|
||||
|
||||
bNode *mix_shader_color = blender::bke::node_add_static_node(
|
||||
nullptr, *ntree, SH_NODE_MIX_SHADER);
|
||||
mix_shader_color->location[0] = 600.0f;
|
||||
mix_shader_color->location[1] = -100.0f;
|
||||
|
||||
bNode *shader_transparent = blender::bke::node_add_static_node(
|
||||
nullptr, *ntree, SH_NODE_BSDF_TRANSPARENT);
|
||||
shader_transparent->location[0] = 600.0f;
|
||||
shader_transparent->location[1] = 100.0f;
|
||||
|
||||
bNode *mix_shader_alpha = blender::bke::node_add_static_node(
|
||||
nullptr, *ntree, SH_NODE_MIX_SHADER);
|
||||
mix_shader_alpha->location[0] = 800.0f;
|
||||
mix_shader_alpha->location[1] = 100.0f;
|
||||
|
||||
bNode *output_material = blender::bke::node_add_static_node(
|
||||
nullptr, *ntree, SH_NODE_OUTPUT_MATERIAL);
|
||||
output_material->location[0] = 1000.0f;
|
||||
output_material->location[1] = 100.0f;
|
||||
|
||||
fromsock = (bNodeSocket *)BLI_findlink(&input_attr_color->outputs, 0); // Color
|
||||
tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 1); // Color1
|
||||
blender::bke::node_add_link(*ntree, *input_attr_color, *fromsock, *mix_rgb_color, *tosock);
|
||||
|
||||
fromsock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->outputs, 0); // Color
|
||||
tosock = (bNodeSocket *)BLI_findlink(&shader_emission->inputs, 0); // Color
|
||||
blender::bke::node_add_link(*ntree, *mix_rgb_color, *fromsock, *shader_emission, *tosock);
|
||||
|
||||
fromsock = (bNodeSocket *)BLI_findlink(&shader_emission->outputs, 0); // Emission
|
||||
tosock = (bNodeSocket *)BLI_findlink(&mix_shader_color->inputs, 2); // Shader (second)
|
||||
blender::bke::node_add_link(*ntree, *shader_emission, *fromsock, *mix_shader_color, *tosock);
|
||||
|
||||
fromsock = (bNodeSocket *)BLI_findlink(&input_light_path->outputs, 0); // In Camera Ray
|
||||
tosock = (bNodeSocket *)BLI_findlink(&mix_shader_color->inputs, 0); // Fac
|
||||
blender::bke::node_add_link(*ntree, *input_light_path, *fromsock, *mix_shader_color, *tosock);
|
||||
|
||||
fromsock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->outputs, 0); // Color
|
||||
tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 0); // Fac
|
||||
blender::bke::node_add_link(*ntree, *mix_rgb_alpha, *fromsock, *mix_shader_alpha, *tosock);
|
||||
|
||||
fromsock = (bNodeSocket *)BLI_findlink(&input_attr_alpha->outputs, 0); // Color
|
||||
tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 1); // Color1
|
||||
blender::bke::node_add_link(*ntree, *input_attr_alpha, *fromsock, *mix_rgb_alpha, *tosock);
|
||||
|
||||
fromsock = (bNodeSocket *)BLI_findlink(&shader_transparent->outputs, 0); // BSDF
|
||||
tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 1); // Shader (first)
|
||||
blender::bke::node_add_link(*ntree, *shader_transparent, *fromsock, *mix_shader_alpha, *tosock);
|
||||
|
||||
fromsock = (bNodeSocket *)BLI_findlink(&mix_shader_color->outputs, 0); // Shader
|
||||
tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 2); // Shader (second)
|
||||
blender::bke::node_add_link(*ntree, *mix_shader_color, *fromsock, *mix_shader_alpha, *tosock);
|
||||
|
||||
fromsock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->outputs, 0); // Shader
|
||||
tosock = (bNodeSocket *)BLI_findlink(&output_material->inputs, 0); // Surface
|
||||
blender::bke::node_add_link(*ntree, *mix_shader_alpha, *fromsock, *output_material, *tosock);
|
||||
|
||||
if (output_linestyle) {
|
||||
bNodeSocket *outsock;
|
||||
bNodeLink *link;
|
||||
|
||||
mix_rgb_color->custom1 = output_linestyle->custom1; // blend_type
|
||||
mix_rgb_color->custom2 = output_linestyle->custom2; // use_clamp
|
||||
|
||||
outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 0); // Color
|
||||
tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 2); // Color2
|
||||
link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
|
||||
if (link) {
|
||||
blender::bke::node_add_link(
|
||||
*ntree, *link->fromnode, *link->fromsock, *mix_rgb_color, *tosock);
|
||||
}
|
||||
else {
|
||||
float color[4];
|
||||
fromptr = RNA_pointer_create_discrete((ID *)ntree, RNA_NodeSocket, outsock);
|
||||
toptr = RNA_pointer_create_discrete((ID *)ntree, RNA_NodeSocket, tosock);
|
||||
RNA_float_get_array(&fromptr, "default_value", color);
|
||||
RNA_float_set_array(&toptr, "default_value", color);
|
||||
}
|
||||
|
||||
outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 1); // Color Fac
|
||||
tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 0); // Fac
|
||||
link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
|
||||
if (link) {
|
||||
blender::bke::node_add_link(
|
||||
*ntree, *link->fromnode, *link->fromsock, *mix_rgb_color, *tosock);
|
||||
}
|
||||
else {
|
||||
fromptr = RNA_pointer_create_discrete((ID *)ntree, RNA_NodeSocket, outsock);
|
||||
toptr = RNA_pointer_create_discrete((ID *)ntree, RNA_NodeSocket, tosock);
|
||||
RNA_float_set(&toptr, "default_value", RNA_float_get(&fromptr, "default_value"));
|
||||
}
|
||||
|
||||
outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 2); // Alpha
|
||||
tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 2); // Color2
|
||||
link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
|
||||
if (link) {
|
||||
blender::bke::node_add_link(
|
||||
*ntree, *link->fromnode, *link->fromsock, *mix_rgb_alpha, *tosock);
|
||||
}
|
||||
else {
|
||||
float color[4];
|
||||
fromptr = RNA_pointer_create_discrete((ID *)ntree, RNA_NodeSocket, outsock);
|
||||
toptr = RNA_pointer_create_discrete((ID *)ntree, RNA_NodeSocket, tosock);
|
||||
color[0] = color[1] = color[2] = RNA_float_get(&fromptr, "default_value");
|
||||
color[3] = 1.0f;
|
||||
RNA_float_set_array(&toptr, "default_value", color);
|
||||
}
|
||||
|
||||
outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 3); // Alpha Fac
|
||||
tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 0); // Fac
|
||||
link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
|
||||
if (link) {
|
||||
blender::bke::node_add_link(
|
||||
*ntree, *link->fromnode, *link->fromsock, *mix_rgb_alpha, *tosock);
|
||||
}
|
||||
else {
|
||||
fromptr = RNA_pointer_create_discrete((ID *)ntree, RNA_NodeSocket, outsock);
|
||||
toptr = RNA_pointer_create_discrete((ID *)ntree, RNA_NodeSocket, tosock);
|
||||
RNA_float_set(&toptr, "default_value", RNA_float_get(&fromptr, "default_value"));
|
||||
}
|
||||
|
||||
for (bNode &node : ntree->nodes) {
|
||||
if (node.type_legacy == SH_NODE_UVALONGSTROKE) {
|
||||
// UV output of the UV Along Stroke node
|
||||
bNodeSocket *sock = (bNodeSocket *)BLI_findlink(&node.outputs, 0);
|
||||
|
||||
// add new UV Map node
|
||||
bNode *input_uvmap = blender::bke::node_add_static_node(nullptr, *ntree, SH_NODE_UVMAP);
|
||||
input_uvmap->location[0] = node.location[0] - 200.0f;
|
||||
input_uvmap->location[1] = node.location[1];
|
||||
NodeShaderUVMap *storage = (NodeShaderUVMap *)input_uvmap->storage;
|
||||
if (node.custom1 & 1) { // use_tips
|
||||
STRNCPY(storage->uv_map, uvNames[1]);
|
||||
}
|
||||
else {
|
||||
STRNCPY(storage->uv_map, uvNames[0]);
|
||||
}
|
||||
fromsock = (bNodeSocket *)BLI_findlink(&input_uvmap->outputs, 0); // UV
|
||||
|
||||
// replace links from the UV Along Stroke node by links from the UV Map node
|
||||
for (bNodeLink &link : ntree->links) {
|
||||
if (link.fromnode == &node && link.fromsock == sock) {
|
||||
blender::bke::node_add_link(
|
||||
*ntree, *input_uvmap, *fromsock, *link.tonode, *link.tosock);
|
||||
}
|
||||
}
|
||||
blender::bke::node_remove_socket_links(*ntree, *sock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blender::bke::node_set_active(*ntree, *output_material);
|
||||
BKE_ntree_update_after_single_tree_change(*bmain, *ntree);
|
||||
|
||||
return ma;
|
||||
}
|
||||
|
||||
void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
|
||||
{
|
||||
RenderStrokeRepBasic(iStrokeRep);
|
||||
}
|
||||
|
||||
void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
|
||||
{
|
||||
using namespace blender;
|
||||
bNodeTree *nt = iStrokeRep->getNodeTree();
|
||||
Material *ma = _nodetree_hash.lookup_or_add_cb(
|
||||
nt, [&]() { return BlenderStrokeRenderer::GetStrokeShader(freestyle_bmain, nt, false); });
|
||||
iStrokeRep->setMaterial(ma);
|
||||
|
||||
const vector<Strip *> &strips = iStrokeRep->getStrips();
|
||||
const bool hasTex = iStrokeRep->hasTex();
|
||||
int totvert = 0, totedge = 0, faces_num = 0, totloop = 0;
|
||||
int visible_faces, visible_segments;
|
||||
for (vector<Strip *>::const_iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
|
||||
Strip::vertex_container &strip_vertices = (*s)->vertices();
|
||||
|
||||
// count visible faces and strip segments
|
||||
test_strip_visibility(strip_vertices, &visible_faces, &visible_segments);
|
||||
if (visible_faces == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
totvert += visible_faces + visible_segments * 2;
|
||||
totedge += visible_faces * 2 + visible_segments;
|
||||
faces_num += visible_faces;
|
||||
totloop += visible_faces * 3;
|
||||
}
|
||||
|
||||
BlenderStrokeRenderer *self = const_cast<BlenderStrokeRenderer *>(this); // FIXME
|
||||
vector<StrokeGroup *> *groups = hasTex ? &self->texturedStrokeGroups : &self->strokeGroups;
|
||||
StrokeGroup *group;
|
||||
if (groups->empty() || !(groups->back()->totvert + totvert < MESH_MAX_VERTS &&
|
||||
groups->back()->materials.size() + 1 < MAXMAT))
|
||||
{
|
||||
group = new StrokeGroup;
|
||||
groups->push_back(group);
|
||||
}
|
||||
else {
|
||||
group = groups->back();
|
||||
}
|
||||
group->strokes.push_back(iStrokeRep);
|
||||
group->totvert += totvert;
|
||||
group->totedge += totedge;
|
||||
group->faces_num += faces_num;
|
||||
group->totloop += totloop;
|
||||
|
||||
if (!group->materials.contains(ma)) {
|
||||
group->materials.add_new(ma, group->materials.size());
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the triangle is visible (i.e., within the render image boundary)
|
||||
bool BlenderStrokeRenderer::test_triangle_visibility(StrokeVertexRep *svRep[3]) const
|
||||
{
|
||||
int xl, xu, yl, yu;
|
||||
Vec2r p;
|
||||
|
||||
xl = xu = yl = yu = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
p = svRep[i]->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++;
|
||||
}
|
||||
}
|
||||
return !(xl == 3 || xu == 3 || yl == 3 || yu == 3);
|
||||
}
|
||||
|
||||
// Check the visibility of faces and strip segments.
|
||||
void BlenderStrokeRenderer::test_strip_visibility(Strip::vertex_container &strip_vertices,
|
||||
int *visible_faces,
|
||||
int *visible_segments) const
|
||||
{
|
||||
const int strip_vertex_count = strip_vertices.size();
|
||||
Strip::vertex_container::iterator v[3];
|
||||
StrokeVertexRep *svRep[3];
|
||||
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 (int 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]);
|
||||
if (test_triangle_visibility(svRep)) {
|
||||
(*visible_faces)++;
|
||||
if (!visible) {
|
||||
(*visible_segments)++;
|
||||
}
|
||||
visible = true;
|
||||
}
|
||||
else {
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Release allocated memory for stroke groups
|
||||
void BlenderStrokeRenderer::FreeStrokeGroups()
|
||||
{
|
||||
vector<StrokeGroup *>::const_iterator it, itend;
|
||||
|
||||
for (it = strokeGroups.begin(), itend = strokeGroups.end(); it != itend; ++it) {
|
||||
delete (*it);
|
||||
}
|
||||
for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end(); it != itend; ++it) {
|
||||
delete (*it);
|
||||
}
|
||||
}
|
||||
|
||||
// Build a scene populated by mesh objects representing stylized strokes
|
||||
int BlenderStrokeRenderer::GenerateScene()
|
||||
{
|
||||
vector<StrokeGroup *>::const_iterator it, itend;
|
||||
|
||||
/* Each stroke is placed at a different z depth. Compute the delta based the number
|
||||
* of vertices to try to maximize the available precision. */
|
||||
int verts_num = 0;
|
||||
for (it = strokeGroups.begin(), itend = strokeGroups.end(); it != itend; ++it) {
|
||||
verts_num += (*it)->totvert;
|
||||
}
|
||||
for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end(); it != itend; ++it) {
|
||||
verts_num += (*it)->totvert;
|
||||
}
|
||||
|
||||
const blender::Camera *camera = blender::id_cast<const blender::Camera *>(
|
||||
freestyle_scene->camera->data);
|
||||
const float z_range = 0.9f;
|
||||
_z_delta = std::min((verts_num > 0) ? z_range / float(verts_num) : z_range, 1e-5f);
|
||||
_z = camera->clip_start + _z_delta;
|
||||
|
||||
for (it = strokeGroups.begin(), itend = strokeGroups.end(); it != itend; ++it) {
|
||||
GenerateStrokeMesh(*it, false);
|
||||
}
|
||||
for (it = texturedStrokeGroups.begin(), itend = texturedStrokeGroups.end(); it != itend; ++it) {
|
||||
GenerateStrokeMesh(*it, true);
|
||||
}
|
||||
return get_stroke_count();
|
||||
}
|
||||
|
||||
// Return the number of strokes
|
||||
int BlenderStrokeRenderer::get_stroke_count() const
|
||||
{
|
||||
return strokeGroups.size() + texturedStrokeGroups.size();
|
||||
}
|
||||
|
||||
// Build a mesh object representing a group of stylized strokes
|
||||
void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
|
||||
{
|
||||
using namespace blender;
|
||||
#if 0
|
||||
Object *object_mesh = BKE_object_add(
|
||||
freestyle_bmain, (ViewLayer *)freestyle_scene->view_layers.first, OB_MESH);
|
||||
DEG_relations_tag_update(freestyle_bmain);
|
||||
#else
|
||||
Object *object_mesh = NewMesh();
|
||||
#endif
|
||||
Mesh *mesh = (Mesh *)object_mesh->data;
|
||||
|
||||
mesh->verts_num = group->totvert;
|
||||
mesh->edges_num = group->totedge;
|
||||
mesh->faces_num = group->faces_num;
|
||||
mesh->corners_num = group->totloop;
|
||||
mesh->totcol = group->materials.size();
|
||||
BKE_mesh_face_offsets_ensure_alloc(mesh);
|
||||
blender::bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
MutableSpan<int> face_offsets = mesh->face_offsets_for_write();
|
||||
bke::SpanAttributeWriter position_attr = attributes.lookup_or_add_for_write_span<float3>(
|
||||
"position", bke::AttrDomain::Point);
|
||||
bke::SpanAttributeWriter edge_verts_attr = attributes.lookup_or_add_for_write_span<int2>(
|
||||
".edge_verts", bke::AttrDomain::Edge);
|
||||
bke::SpanAttributeWriter corner_vert_attr = attributes.lookup_or_add_for_write_span<int>(
|
||||
".corner_vert", bke::AttrDomain::Corner);
|
||||
bke::SpanAttributeWriter corner_edge_attr = attributes.lookup_or_add_for_write_span<int>(
|
||||
".corner_edge", bke::AttrDomain::Corner);
|
||||
bke::SpanAttributeWriter material_index_attr = attributes.lookup_or_add_for_write_span<int>(
|
||||
"material_index", bke::AttrDomain::Face);
|
||||
float3 *vert_positions = position_attr.span.data();
|
||||
int2 *edges = edge_verts_attr.span.data();
|
||||
int *corner_verts = corner_vert_attr.span.data();
|
||||
int *corner_edges = corner_edge_attr.span.data();
|
||||
int *material_indices = material_index_attr.span.data();
|
||||
|
||||
std::array<bke::SpanAttributeWriter<float2>, 2> uv_map_attrs;
|
||||
blender::float2 *loopsuv[2] = {nullptr};
|
||||
|
||||
if (hasTex) {
|
||||
// First UV layer
|
||||
uv_map_attrs[0] = attributes.lookup_or_add_for_write_span<float2>(uvNames[0],
|
||||
bke::AttrDomain::Corner);
|
||||
loopsuv[0] = uv_map_attrs[0].span.data();
|
||||
mesh->uv_maps_active_set(uvNames[0]);
|
||||
|
||||
// Second UV layer
|
||||
uv_map_attrs[1] = attributes.lookup_or_add_for_write_span<float2>(uvNames[1],
|
||||
bke::AttrDomain::Corner);
|
||||
loopsuv[1] = uv_map_attrs[1].span.data();
|
||||
mesh->uv_maps_active_set(uvNames[1]);
|
||||
}
|
||||
|
||||
// colors and transparency (the latter represented by grayscale colors)
|
||||
bke::SpanAttributeWriter<ColorGeometry4b> colors_attr =
|
||||
attributes.lookup_or_add_for_write_span<ColorGeometry4b>("Color", bke::AttrDomain::Corner);
|
||||
ColorGeometry4b *colors = colors_attr.span.data();
|
||||
bke::SpanAttributeWriter<ColorGeometry4b> transp_attr =
|
||||
attributes.lookup_or_add_for_write_span<ColorGeometry4b>("Alpha", bke::AttrDomain::Corner);
|
||||
ColorGeometry4b *transp = transp_attr.span.data();
|
||||
BKE_id_attributes_active_color_set(&mesh->id, "Color");
|
||||
|
||||
mesh->mat = MEM_new_array_uninitialized<Material *>(size_t(mesh->totcol), "MaterialList");
|
||||
for (const auto item : group->materials.items()) {
|
||||
Material *material = item.key;
|
||||
const int matnr = item.value;
|
||||
mesh->mat[matnr] = material;
|
||||
if (material) {
|
||||
id_us_plus(&material->id);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// Data copy
|
||||
////////////////////
|
||||
|
||||
int vertex_index = 0, edge_index = 0, loop_index = 0, face_index = 0;
|
||||
int visible_faces, visible_segments;
|
||||
bool visible;
|
||||
Strip::vertex_container::iterator v[3];
|
||||
StrokeVertexRep *svRep[3];
|
||||
Vec2r p;
|
||||
|
||||
for (vector<StrokeRep *>::const_iterator it = group->strokes.begin(),
|
||||
itend = group->strokes.end();
|
||||
it != itend;
|
||||
++it)
|
||||
{
|
||||
const int matnr = group->materials.lookup_default((*it)->getMaterial(), 0);
|
||||
|
||||
vector<Strip *> &strips = (*it)->getStrips();
|
||||
for (vector<Strip *>::const_iterator s = strips.begin(), send = strips.end(); s != send; ++s) {
|
||||
Strip::vertex_container &strip_vertices = (*s)->vertices();
|
||||
int strip_vertex_count = strip_vertices.size();
|
||||
|
||||
// count visible faces and strip segments
|
||||
test_strip_visibility(strip_vertices, &visible_faces, &visible_segments);
|
||||
if (visible_faces == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
v[0] = strip_vertices.begin();
|
||||
v[1] = v[0] + 1;
|
||||
v[2] = v[0] + 2;
|
||||
|
||||
visible = false;
|
||||
|
||||
// NOTE: Mesh generation in the following loop assumes stroke strips
|
||||
// to be triangle strips.
|
||||
for (int 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]);
|
||||
if (!test_triangle_visibility(svRep)) {
|
||||
visible = false;
|
||||
}
|
||||
else {
|
||||
if (!visible) {
|
||||
// first vertex
|
||||
vert_positions[vertex_index][0] = svRep[0]->point2d()[0];
|
||||
vert_positions[vertex_index][1] = svRep[0]->point2d()[1];
|
||||
vert_positions[vertex_index][2] = get_stroke_vertex_z();
|
||||
|
||||
++vertex_index;
|
||||
|
||||
// second vertex
|
||||
vert_positions[vertex_index][0] = svRep[1]->point2d()[0];
|
||||
vert_positions[vertex_index][1] = svRep[1]->point2d()[1];
|
||||
vert_positions[vertex_index][2] = get_stroke_vertex_z();
|
||||
|
||||
++vertex_index;
|
||||
|
||||
// first edge
|
||||
edges[edge_index][0] = vertex_index - 2;
|
||||
edges[edge_index][1] = vertex_index - 1;
|
||||
++edge_index;
|
||||
}
|
||||
visible = true;
|
||||
|
||||
// vertex
|
||||
vert_positions[vertex_index][0] = svRep[2]->point2d()[0];
|
||||
vert_positions[vertex_index][1] = svRep[2]->point2d()[1];
|
||||
vert_positions[vertex_index][2] = get_stroke_vertex_z();
|
||||
++vertex_index;
|
||||
|
||||
// edges
|
||||
edges[edge_index][0] = vertex_index - 1;
|
||||
edges[edge_index][1] = vertex_index - 3;
|
||||
++edge_index;
|
||||
|
||||
edges[edge_index][0] = vertex_index - 1;
|
||||
edges[edge_index][1] = vertex_index - 2;
|
||||
++edge_index;
|
||||
|
||||
// poly
|
||||
face_offsets[face_index] = loop_index;
|
||||
*material_indices = matnr;
|
||||
++material_indices;
|
||||
++face_index;
|
||||
|
||||
// Even and odd loops connect triangles vertices differently
|
||||
bool is_odd = n % 2;
|
||||
// loops
|
||||
if (is_odd) {
|
||||
corner_verts[0] = vertex_index - 1;
|
||||
corner_edges[0] = edge_index - 2;
|
||||
|
||||
corner_verts[1] = vertex_index - 3;
|
||||
corner_edges[1] = edge_index - 3;
|
||||
|
||||
corner_verts[2] = vertex_index - 2;
|
||||
corner_edges[2] = edge_index - 1;
|
||||
}
|
||||
else {
|
||||
corner_verts[0] = vertex_index - 1;
|
||||
corner_edges[0] = edge_index - 1;
|
||||
|
||||
corner_verts[1] = vertex_index - 2;
|
||||
corner_edges[1] = edge_index - 3;
|
||||
|
||||
corner_verts[2] = vertex_index - 3;
|
||||
corner_edges[2] = edge_index - 2;
|
||||
}
|
||||
corner_verts += 3;
|
||||
corner_edges += 3;
|
||||
loop_index += 3;
|
||||
|
||||
// UV
|
||||
if (hasTex) {
|
||||
// First UV layer (loopsuv[0]) has no tips (texCoord(0)).
|
||||
// Second UV layer (loopsuv[1]) has tips: (texCoord(1)).
|
||||
for (int L = 0; L < 2; L++) {
|
||||
if (is_odd) {
|
||||
loopsuv[L][0][0] = svRep[2]->texCoord(L).x();
|
||||
loopsuv[L][0][1] = svRep[2]->texCoord(L).y();
|
||||
|
||||
loopsuv[L][1][0] = svRep[0]->texCoord(L).x();
|
||||
loopsuv[L][1][1] = svRep[0]->texCoord(L).y();
|
||||
|
||||
loopsuv[L][2][0] = svRep[1]->texCoord(L).x();
|
||||
loopsuv[L][2][1] = svRep[1]->texCoord(L).y();
|
||||
}
|
||||
else {
|
||||
loopsuv[L][0][0] = svRep[2]->texCoord(L).x();
|
||||
loopsuv[L][0][1] = svRep[2]->texCoord(L).y();
|
||||
|
||||
loopsuv[L][1][0] = svRep[1]->texCoord(L).x();
|
||||
loopsuv[L][1][1] = svRep[1]->texCoord(L).y();
|
||||
|
||||
loopsuv[L][2][0] = svRep[0]->texCoord(L).x();
|
||||
loopsuv[L][2][1] = svRep[0]->texCoord(L).y();
|
||||
}
|
||||
loopsuv[L] += 3;
|
||||
}
|
||||
}
|
||||
|
||||
// colors and alpha transparency. vertex colors are in sRGB
|
||||
// space by convention, so convert from linear
|
||||
float rgba[3][4];
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
copy_v3fl_v3db(rgba[i], &svRep[i]->color()[0]);
|
||||
rgba[i][3] = svRep[i]->alpha();
|
||||
}
|
||||
|
||||
if (is_odd) {
|
||||
linearrgb_to_srgb_uchar4(&colors[0].r, rgba[2]);
|
||||
linearrgb_to_srgb_uchar4(&colors[1].r, rgba[0]);
|
||||
linearrgb_to_srgb_uchar4(&colors[2].r, rgba[1]);
|
||||
}
|
||||
else {
|
||||
linearrgb_to_srgb_uchar4(&colors[0].r, rgba[2]);
|
||||
linearrgb_to_srgb_uchar4(&colors[1].r, rgba[1]);
|
||||
linearrgb_to_srgb_uchar4(&colors[2].r, rgba[0]);
|
||||
}
|
||||
transp[0].r = transp[0].g = transp[0].b = colors[0].a;
|
||||
transp[1].r = transp[1].g = transp[1].b = colors[1].a;
|
||||
transp[2].r = transp[2].g = transp[2].b = colors[2].a;
|
||||
colors += 3;
|
||||
transp += 3;
|
||||
}
|
||||
} // loop over strip vertices
|
||||
} // loop over strips
|
||||
} // loop over strokes
|
||||
|
||||
BKE_object_materials_sync_length(freestyle_bmain, object_mesh, (ID *)mesh);
|
||||
|
||||
position_attr.finish();
|
||||
edge_verts_attr.finish();
|
||||
corner_vert_attr.finish();
|
||||
corner_edge_attr.finish();
|
||||
material_index_attr.finish();
|
||||
uv_map_attrs[0].finish();
|
||||
uv_map_attrs[1].finish();
|
||||
colors_attr.finish();
|
||||
transp_attr.finish();
|
||||
}
|
||||
|
||||
// A replacement of BKE_object_add() for better performance.
|
||||
blender::Object *BlenderStrokeRenderer::NewMesh() const
|
||||
{
|
||||
using namespace blender;
|
||||
Object *ob;
|
||||
char name[MAX_ID_NAME];
|
||||
uint mesh_id = get_stroke_mesh_id();
|
||||
|
||||
SNPRINTF(name, "0%08xOB", mesh_id);
|
||||
ob = BKE_object_add_only_object(freestyle_bmain, OB_MESH, name);
|
||||
SNPRINTF(name, "0%08xME", mesh_id);
|
||||
ob->data = blender::id_cast<ID *>(BKE_mesh_add(freestyle_bmain, name));
|
||||
|
||||
Collection *collection_master = freestyle_scene->master_collection;
|
||||
BKE_collection_object_add(freestyle_bmain, collection_master, ob);
|
||||
DEG_graph_tag_relations_update(freestyle_depsgraph);
|
||||
|
||||
DEG_graph_id_tag_update(freestyle_bmain,
|
||||
freestyle_depsgraph,
|
||||
&ob->id,
|
||||
ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION);
|
||||
|
||||
return ob;
|
||||
}
|
||||
|
||||
blender::Render *BlenderStrokeRenderer::RenderScene(blender::Render *re, bool render)
|
||||
{
|
||||
using namespace blender;
|
||||
#if 0
|
||||
if (blender::G.debug & blender::G_DEBUG_FREESTYLE) {
|
||||
const Camera *camera = (const Camera *)freestyle_scene->camera->data;
|
||||
cout << "clip_start " << camera->clip_start << ", clip_end " << camera->clip_end << endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
Render *freestyle_render = RE_NewSceneRender(freestyle_scene);
|
||||
DEG_graph_relations_update(freestyle_depsgraph);
|
||||
|
||||
freestyle_render->pipeline_depsgraph = re->pipeline_depsgraph;
|
||||
freestyle_render->pipeline_scene_eval = re->pipeline_scene_eval;
|
||||
|
||||
RE_RenderFreestyleStrokes(
|
||||
freestyle_render, freestyle_bmain, freestyle_scene, render && get_stroke_count() > 0);
|
||||
|
||||
freestyle_render->pipeline_depsgraph = nullptr;
|
||||
freestyle_render->pipeline_scene_eval = nullptr;
|
||||
|
||||
return freestyle_render;
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,88 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BLI_map.hh"
|
||||
|
||||
#include "../stroke/StrokeRenderer.h"
|
||||
#include "../system/FreestyleConfig.h"
|
||||
|
||||
namespace blender {
|
||||
struct Depsgraph;
|
||||
struct Main;
|
||||
struct Material;
|
||||
struct Object;
|
||||
struct Render;
|
||||
struct Scene;
|
||||
struct bContext;
|
||||
struct bNodeTree;
|
||||
} // namespace blender
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
class BlenderStrokeRenderer : public StrokeRenderer {
|
||||
public:
|
||||
BlenderStrokeRenderer(blender::Render *re, int render_count);
|
||||
virtual ~BlenderStrokeRenderer();
|
||||
|
||||
/** Renders a stroke rep */
|
||||
virtual void RenderStrokeRep(StrokeRep *iStrokeRep) const;
|
||||
virtual void RenderStrokeRepBasic(StrokeRep *iStrokeRep) const;
|
||||
|
||||
blender::Object *NewMesh() const;
|
||||
|
||||
struct StrokeGroup {
|
||||
explicit StrokeGroup() : totvert(0), totedge(0), faces_num(0), totloop(0) {}
|
||||
vector<StrokeRep *> strokes;
|
||||
blender::Map<blender::Material *, int> materials;
|
||||
int totvert;
|
||||
int totedge;
|
||||
int faces_num;
|
||||
int totloop;
|
||||
};
|
||||
vector<StrokeGroup *> strokeGroups, texturedStrokeGroups;
|
||||
|
||||
int GenerateScene();
|
||||
void GenerateStrokeMesh(StrokeGroup *group, bool hasTex);
|
||||
void FreeStrokeGroups();
|
||||
|
||||
blender::Render *RenderScene(blender::Render *re, bool render);
|
||||
|
||||
static blender::Material *GetStrokeShader(blender::Main *bmain,
|
||||
blender::bNodeTree *iNodeTree,
|
||||
bool do_id_user);
|
||||
|
||||
protected:
|
||||
blender::Main *freestyle_bmain;
|
||||
blender::Scene *old_scene;
|
||||
blender::Scene *freestyle_scene;
|
||||
blender::Depsgraph *freestyle_depsgraph;
|
||||
blender::bContext *_context;
|
||||
float _width, _height;
|
||||
float _z, _z_delta;
|
||||
uint _mesh_id;
|
||||
bool _use_shading_nodes;
|
||||
mutable blender::Map<blender::bNodeTree *, blender::Material *> _nodetree_hash;
|
||||
|
||||
static const char *uvNames[];
|
||||
|
||||
int get_stroke_count() const;
|
||||
float get_stroke_vertex_z(void) const;
|
||||
uint get_stroke_mesh_id(void) const;
|
||||
bool test_triangle_visibility(StrokeVertexRep *svRep[3]) const;
|
||||
void test_strip_visibility(Strip::vertex_container &strip_vertices,
|
||||
int *visible_faces,
|
||||
int *visible_segments) const;
|
||||
|
||||
vector<StrokeRep *> _strokeReps;
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BlenderStrokeRenderer")
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,70 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "../stroke/StyleModule.h"
|
||||
#include "../system/PythonInterpreter.h"
|
||||
|
||||
#include "BLI_utildefines.h" // BLI_assert()
|
||||
|
||||
namespace blender {
|
||||
struct Text;
|
||||
}
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
class BufferedStyleModule : public StyleModule {
|
||||
public:
|
||||
BufferedStyleModule(const string &buffer, const string &file_name, Interpreter *inter)
|
||||
: StyleModule(file_name, inter)
|
||||
{
|
||||
_buffer = buffer;
|
||||
}
|
||||
|
||||
virtual ~BufferedStyleModule() {}
|
||||
|
||||
protected:
|
||||
virtual int interpret()
|
||||
{
|
||||
PythonInterpreter *py_inter = dynamic_cast<PythonInterpreter *>(_inter);
|
||||
BLI_assert(py_inter != 0);
|
||||
return py_inter->interpretString(_buffer, getFileName());
|
||||
}
|
||||
|
||||
private:
|
||||
string _buffer;
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BufferedStyleModule")
|
||||
};
|
||||
|
||||
class BlenderStyleModule : public StyleModule {
|
||||
public:
|
||||
BlenderStyleModule(blender::Text *text, const string &name, Interpreter *inter)
|
||||
: StyleModule(name, inter)
|
||||
{
|
||||
_text = text;
|
||||
}
|
||||
|
||||
virtual ~BlenderStyleModule() {}
|
||||
|
||||
protected:
|
||||
virtual int interpret()
|
||||
{
|
||||
PythonInterpreter *py_inter = dynamic_cast<PythonInterpreter *>(_inter);
|
||||
BLI_assert(py_inter != 0);
|
||||
return py_inter->interpretText(_text, getFileName());
|
||||
}
|
||||
|
||||
private:
|
||||
struct blender::Text *_text;
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BlenderStyleModule")
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,765 @@
|
||||
/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "../application/AppConfig.h"
|
||||
#include "../application/AppView.h"
|
||||
#include "../application/Controller.h"
|
||||
|
||||
#include "BlenderStrokeRenderer.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_collection_types.h"
|
||||
#include "DNA_freestyle_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_text_types.h"
|
||||
|
||||
#include "BKE_callbacks.hh"
|
||||
#include "BKE_context.hh"
|
||||
#include "BKE_freestyle.h"
|
||||
#include "BKE_global.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_linestyle.h"
|
||||
#include "BKE_scene.hh"
|
||||
#include "BKE_text.h"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_color_blend.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_rotation.h"
|
||||
|
||||
#include "BPY_extern.hh"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "IMB_imbuf.hh"
|
||||
|
||||
#include "pipeline.hh"
|
||||
|
||||
#include "FRS_freestyle.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Freestyle;
|
||||
|
||||
namespace blender {
|
||||
|
||||
FreestyleGlobals g_freestyle;
|
||||
|
||||
// Freestyle configuration
|
||||
static bool freestyle_is_initialized = false;
|
||||
static Config::Path *pathconfig = nullptr;
|
||||
static Controller *controller = nullptr;
|
||||
static AppView *view = nullptr;
|
||||
|
||||
// line set buffer for copy & paste
|
||||
static FreestyleLineSet lineset_buffer;
|
||||
static bool lineset_copied = false;
|
||||
|
||||
static void load_post_callback(Main * /*main*/,
|
||||
PointerRNA ** /*pointers*/,
|
||||
const int /*num_pointers*/,
|
||||
void * /*arg*/)
|
||||
{
|
||||
lineset_copied = false;
|
||||
}
|
||||
|
||||
static bCallbackFuncStore load_post_callback_funcstore = {
|
||||
/*next*/ nullptr,
|
||||
/*prev*/ nullptr,
|
||||
/*func*/ load_post_callback,
|
||||
/*arg*/ nullptr,
|
||||
/*alloc*/ 0};
|
||||
|
||||
//=======================================================
|
||||
// Initialization
|
||||
//=======================================================
|
||||
|
||||
void FRS_init()
|
||||
{
|
||||
if (freestyle_is_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
pathconfig = new Config::Path;
|
||||
controller = new Controller();
|
||||
view = new AppView;
|
||||
controller->setView(view);
|
||||
controller->Clear();
|
||||
g_freestyle.scene = nullptr;
|
||||
lineset_copied = false;
|
||||
|
||||
BKE_callback_add(&load_post_callback_funcstore, BKE_CB_EVT_LOAD_POST);
|
||||
|
||||
freestyle_is_initialized = true;
|
||||
}
|
||||
|
||||
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_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->scene->r.line_thickness_mode) {
|
||||
case R_LINE_THICKNESS_ABSOLUTE:
|
||||
thickness = re->scene->r.unit_line_thickness * (re->r.size / 100.0f);
|
||||
break;
|
||||
case R_LINE_THICKNESS_RELATIVE:
|
||||
thickness = height / 480.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
g_freestyle.viewport[0] = 0;
|
||||
g_freestyle.viewport[1] = 0;
|
||||
g_freestyle.viewport[2] = width;
|
||||
g_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 char *escape_quotes(char *name)
|
||||
{
|
||||
char *s = MEM_new_array_uninitialized<char>(strlen(name) * 2 + 1, "escape_quotes");
|
||||
char *p = s;
|
||||
while (*name) {
|
||||
if (*name == '\'') {
|
||||
*(p++) = '\\';
|
||||
}
|
||||
*(p++) = *(name++);
|
||||
}
|
||||
*p = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
static char *create_lineset_handler(char *layer_name, char *lineset_name)
|
||||
{
|
||||
const char *fmt = "__import__('parameter_editor').process('%s', '%s')\n";
|
||||
char *s1 = escape_quotes(layer_name);
|
||||
char *s2 = escape_quotes(lineset_name);
|
||||
char *text = BLI_sprintfN(fmt, s1, s2);
|
||||
MEM_delete(s1);
|
||||
MEM_delete(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(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, ViewLayer *view_layer, Depsgraph *depsgraph)
|
||||
{
|
||||
// load mesh
|
||||
re->i.infostr = RPT_("Freestyle: Mesh loading");
|
||||
re->display->stats_draw(&re->i);
|
||||
re->i.infostr = nullptr;
|
||||
if (controller->LoadMesh(re, view_layer, depsgraph)) {
|
||||
/* Returns if scene cannot be loaded or if empty. */
|
||||
return;
|
||||
}
|
||||
if (re->display->test_break()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add style modules
|
||||
FreestyleConfig *config = &view_layer->freestyle_config;
|
||||
|
||||
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 : config->modules) {
|
||||
if (module_conf.script && module_conf.is_displayed) {
|
||||
const char *id_name = module_conf.script->id.name + 2;
|
||||
if (G.debug & G_DEBUG_FREESTYLE) {
|
||||
cout << " " << layer_count + 1 << ": " << id_name;
|
||||
if (module_conf.script->filepath) {
|
||||
cout << " (" << module_conf.script->filepath << ")";
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
controller->InsertStyleModule(layer_count, id_name, module_conf.script);
|
||||
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;
|
||||
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 = ARRAY_SIZE(conditions);
|
||||
if (G.debug & G_DEBUG_FREESTYLE) {
|
||||
cout << "Linesets:" << endl;
|
||||
}
|
||||
for (FreestyleLineSet &lineset : config->linesets) {
|
||||
if (lineset.flags & FREESTYLE_LINESET_ENABLED) {
|
||||
if (G.debug & G_DEBUG_FREESTYLE) {
|
||||
cout << " " << layer_count + 1 << ": " << lineset.name << " - "
|
||||
<< (lineset.linestyle ? (lineset.linestyle->id.name + 2) : "<null>") << endl;
|
||||
}
|
||||
char *buffer = create_lineset_handler(view_layer->name, lineset.name);
|
||||
controller->InsertStyleModule(layer_count, lineset.name, buffer);
|
||||
controller->toggleLayer(layer_count, true);
|
||||
MEM_delete(buffer);
|
||||
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
|
||||
controller->setSphereRadius(config->sphere_radius);
|
||||
controller->setSuggestiveContourKrDerivativeEpsilon(config->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 << "Ridges 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, view_layer->name);
|
||||
bool diffuse = false, z = false;
|
||||
for (RenderPass &rpass : rl->passes) {
|
||||
float *rpass_buffer_data = rpass.ibuf->float_data_for_write();
|
||||
if (STREQ(rpass.name, RE_PASSNAME_DIFFUSE_COLOR)) {
|
||||
controller->setPassDiffuse(rpass_buffer_data, rpass.rectx, rpass.recty);
|
||||
diffuse = true;
|
||||
}
|
||||
if (STREQ(rpass.name, RE_PASSNAME_DEPTH)) {
|
||||
controller->setPassZ(rpass_buffer_data, rpass.rectx, rpass.recty);
|
||||
z = true;
|
||||
}
|
||||
}
|
||||
if (G.debug & G_DEBUG_FREESTYLE) {
|
||||
cout << "Passes :" << endl;
|
||||
cout << " Diffuse = " << (diffuse ? "enabled" : "disabled") << endl;
|
||||
cout << " Z = " << (z ? "enabled" : "disabled") << endl;
|
||||
}
|
||||
|
||||
if (controller->hitViewMapCache()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// compute view map
|
||||
re->i.infostr = RPT_("Freestyle: View map creation");
|
||||
re->display->stats_draw(&re->i);
|
||||
re->i.infostr = nullptr;
|
||||
controller->ComputeViewMap();
|
||||
}
|
||||
|
||||
void FRS_composite_result(Render *re, ViewLayer *view_layer, Render *freestyle_render)
|
||||
{
|
||||
RenderLayer *rl;
|
||||
float *src, *dest, *pixSrc, *pixDest;
|
||||
int x, y, rectx, recty;
|
||||
|
||||
if (freestyle_render == nullptr || freestyle_render->result == nullptr) {
|
||||
if (view_layer->freestyle_config.flags & FREESTYLE_AS_RENDER_PASS) {
|
||||
// Create a blank render pass output.
|
||||
RE_create_render_pass(
|
||||
re->result, RE_PASSNAME_FREESTYLE, 4, "RGBA", view_layer->name, re->viewname, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
rl = render_get_single_layer(freestyle_render, freestyle_render->result);
|
||||
if (!rl) {
|
||||
if (G.debug & G_DEBUG_FREESTYLE) {
|
||||
cout << "No source render layer to composite" << endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
src = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, freestyle_render->viewname);
|
||||
if (!src) {
|
||||
if (G.debug & G_DEBUG_FREESTYLE) {
|
||||
cout << "No source result image to composite" << endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
if (G.debug & G_DEBUG_FREESTYLE) {
|
||||
cout << "src: " << rl->rectx << " x " << rl->recty << endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
rl = RE_GetRenderLayer(re->result, view_layer->name);
|
||||
if (!rl) {
|
||||
if (G.debug & G_DEBUG_FREESTYLE) {
|
||||
cout << "No destination render layer to composite to" << endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (view_layer->freestyle_config.flags & FREESTYLE_AS_RENDER_PASS) {
|
||||
RE_create_render_pass(
|
||||
re->result, RE_PASSNAME_FREESTYLE, 4, "RGBA", view_layer->name, re->viewname, true);
|
||||
dest = RE_RenderLayerGetPass(rl, RE_PASSNAME_FREESTYLE, re->viewname);
|
||||
}
|
||||
else {
|
||||
dest = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, re->viewname);
|
||||
}
|
||||
if (!dest) {
|
||||
if (G.debug & G_DEBUG_FREESTYLE) {
|
||||
cout << "No destination result image to composite to" << endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
#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);
|
||||
blend_color_mix_float(pixDest, pixDest, pixSrc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int displayed_layer_count(ViewLayer *view_layer)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
switch (view_layer->freestyle_config.mode) {
|
||||
case FREESTYLE_CONTROL_SCRIPT_MODE:
|
||||
for (FreestyleModuleConfig &module : view_layer->freestyle_config.modules) {
|
||||
if (module.script && module.is_displayed) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FREESTYLE_CONTROL_EDITOR_MODE:
|
||||
for (FreestyleLineSet &lineset : view_layer->freestyle_config.linesets) {
|
||||
if (lineset.flags & FREESTYLE_LINESET_ENABLED) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int FRS_is_freestyle_enabled(ViewLayer *view_layer)
|
||||
{
|
||||
return ((view_layer->flag & VIEW_LAYER_RENDER) && (view_layer->flag & VIEW_LAYER_FREESTYLE) &&
|
||||
displayed_layer_count(view_layer) > 0);
|
||||
}
|
||||
|
||||
void FRS_init_stroke_renderer(Render *re)
|
||||
{
|
||||
if (G.debug & G_DEBUG_FREESTYLE) {
|
||||
cout << endl;
|
||||
cout << "#===============================================================" << endl;
|
||||
cout << "# Freestyle" << endl;
|
||||
cout << "#===============================================================" << endl;
|
||||
}
|
||||
|
||||
init_view(re);
|
||||
|
||||
controller->ResetRenderCount();
|
||||
}
|
||||
|
||||
void FRS_begin_stroke_rendering(Render * /*re*/) {}
|
||||
|
||||
void FRS_do_stroke_rendering(Render *re, ViewLayer *view_layer)
|
||||
{
|
||||
RenderMonitor monitor(re);
|
||||
controller->setRenderMonitor(&monitor);
|
||||
controller->setViewMapCache(
|
||||
(view_layer->freestyle_config.flags & FREESTYLE_VIEW_MAP_CACHE) ? true : false);
|
||||
|
||||
if (G.debug & G_DEBUG_FREESTYLE) {
|
||||
cout << endl;
|
||||
cout << "----------------------------------------------------------" << endl;
|
||||
cout << "| " << (re->scene->id.name + 2) << "|" << view_layer->name << endl;
|
||||
cout << "----------------------------------------------------------" << endl;
|
||||
}
|
||||
|
||||
/* Create depsgraph and evaluate scene. */
|
||||
ViewLayer *scene_view_layer = (ViewLayer *)BLI_findstring(
|
||||
&re->scene->view_layers, view_layer->name, offsetof(ViewLayer, name));
|
||||
Depsgraph *depsgraph = DEG_graph_new(re->main, re->scene, scene_view_layer, DAG_EVAL_RENDER);
|
||||
BKE_scene_graph_update_for_newframe(depsgraph);
|
||||
|
||||
/* Init camera
|
||||
* Objects are transformed into camera coordinate system, therefore the camera position
|
||||
* is zero and the model-view matrix is the identity matrix. */
|
||||
Object *ob_camera_orig = RE_GetCamera(re);
|
||||
Object *ob_camera_eval = DEG_get_evaluated(depsgraph, ob_camera_orig);
|
||||
zero_v3(g_freestyle.viewpoint);
|
||||
unit_m4(g_freestyle.mv);
|
||||
RE_GetCameraWindow(re, ob_camera_eval, g_freestyle.proj);
|
||||
|
||||
// prepare Freestyle:
|
||||
// - load mesh
|
||||
// - add style modules
|
||||
// - set parameters
|
||||
// - compute view map
|
||||
prepare(re, view_layer, depsgraph);
|
||||
|
||||
if (re->display->test_break()) {
|
||||
controller->CloseFile();
|
||||
if (G.debug & G_DEBUG_FREESTYLE) {
|
||||
cout << "Break" << endl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// render and composite Freestyle result
|
||||
if (controller->_ViewMap) {
|
||||
// render strokes
|
||||
re->i.infostr = RPT_("Freestyle: Stroke rendering");
|
||||
re->display->stats_draw(&re->i);
|
||||
re->i.infostr = nullptr;
|
||||
g_freestyle.scene = DEG_get_evaluated_scene(depsgraph);
|
||||
int strokeCount = controller->DrawStrokes();
|
||||
Render *freestyle_render = nullptr;
|
||||
if (strokeCount > 0) {
|
||||
freestyle_render = controller->RenderStrokes(re, true);
|
||||
}
|
||||
controller->CloseFile();
|
||||
g_freestyle.scene = nullptr;
|
||||
|
||||
// composite result
|
||||
FRS_composite_result(re, view_layer, freestyle_render);
|
||||
if (freestyle_render) {
|
||||
RE_FreeRender(freestyle_render);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEG_graph_free(depsgraph);
|
||||
}
|
||||
|
||||
void FRS_end_stroke_rendering(Render * /*re*/)
|
||||
{
|
||||
// clear canvas
|
||||
controller->Clear();
|
||||
}
|
||||
|
||||
void FRS_free_view_map_cache()
|
||||
{
|
||||
// free cache
|
||||
controller->DeleteViewMap(true);
|
||||
#if 0
|
||||
if (G.debug & G_DEBUG_FREESTYLE) {
|
||||
printf("View map cache freed\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
// Freestyle Panel Configuration
|
||||
//=======================================================
|
||||
|
||||
void FRS_copy_active_lineset(FreestyleConfig *config)
|
||||
{
|
||||
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(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;
|
||||
STRNCPY(lineset_buffer.name, lineset->name);
|
||||
lineset_copied = true;
|
||||
}
|
||||
}
|
||||
|
||||
void FRS_paste_active_lineset(FreestyleConfig *config)
|
||||
{
|
||||
if (!lineset_copied) {
|
||||
return;
|
||||
}
|
||||
|
||||
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
|
||||
|
||||
if (lineset) {
|
||||
if (lineset->linestyle) {
|
||||
id_us_min(&lineset->linestyle->id);
|
||||
}
|
||||
lineset->linestyle = lineset_buffer.linestyle;
|
||||
if (lineset->linestyle) {
|
||||
id_us_plus(&lineset->linestyle->id);
|
||||
}
|
||||
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) {
|
||||
id_us_min(&lineset->group->id);
|
||||
lineset->group = nullptr;
|
||||
}
|
||||
if (lineset_buffer.group) {
|
||||
lineset->group = lineset_buffer.group;
|
||||
id_us_plus(&lineset->group->id);
|
||||
}
|
||||
STRNCPY(lineset->name, lineset_buffer.name);
|
||||
BKE_freestyle_lineset_unique_name(config, lineset);
|
||||
lineset->flags |= FREESTYLE_LINESET_CURRENT;
|
||||
}
|
||||
}
|
||||
|
||||
void FRS_delete_active_lineset(FreestyleConfig *config)
|
||||
{
|
||||
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
|
||||
|
||||
if (lineset) {
|
||||
BKE_freestyle_lineset_delete(config, lineset);
|
||||
}
|
||||
}
|
||||
|
||||
bool FRS_move_active_lineset(FreestyleConfig *config, int direction)
|
||||
{
|
||||
FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
|
||||
return (lineset != nullptr) && BLI_listbase_link_move(&config->linesets, lineset, direction);
|
||||
}
|
||||
|
||||
// Testing
|
||||
|
||||
Material *FRS_create_stroke_material(Main *bmain, FreestyleLineStyle *linestyle)
|
||||
{
|
||||
bNodeTree *nt = (linestyle->use_nodes) ? linestyle->nodetree : nullptr;
|
||||
Material *ma = BlenderStrokeRenderer::GetStrokeShader(bmain, nt, true);
|
||||
ma->id.us = 0;
|
||||
return ma;
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
141
blender-5.2.0/source/blender/freestyle/intern/geometry/BBox.h
Normal file
141
blender-5.2.0/source/blender/freestyle/intern/geometry/BBox.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief A class to hold a bounding box
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
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 (uint 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)
|
||||
{
|
||||
BLI_assert(!b.empty());
|
||||
_min = b.getMin();
|
||||
_max = b.getMax();
|
||||
_empty = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline BBox<Point> &operator+=(const BBox<Point> &b)
|
||||
{
|
||||
BLI_assert(!b.empty());
|
||||
if (_empty) {
|
||||
_min = b.getMin();
|
||||
_max = b.getMax();
|
||||
_empty = false;
|
||||
}
|
||||
else {
|
||||
for (uint 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 (uint 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;
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BBox")
|
||||
};
|
||||
|
||||
template<class Point> BBox<Point> &operator+(const BBox<Point> &b1, const BBox<Point> &b2)
|
||||
{
|
||||
Point new_min;
|
||||
Point new_max;
|
||||
|
||||
for (uint 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);
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,108 @@
|
||||
/* SPDX-FileCopyrightText: 2012-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define a Bezier curve of order 4.
|
||||
*/
|
||||
|
||||
#include "Bezier.h"
|
||||
#include "FitCurve.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
BezierCurveSegment::~BezierCurveSegment() = default;
|
||||
|
||||
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.emplace_back((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 (!_Segments.empty()) {
|
||||
vector<BezierCurveSegment *>::iterator v, vend;
|
||||
for (v = _Segments.begin(), vend = _Segments.end(); v != vend; ++v) {
|
||||
delete *v;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,74 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define a Bezier curve of order 4.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Geom.h"
|
||||
|
||||
#include "../system/FreestyleConfig.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
using namespace Geometry;
|
||||
|
||||
class BezierCurveSegment {
|
||||
private:
|
||||
std::vector<Vec2d> _ControlPolygon;
|
||||
std::vector<Vec2d> _Vertices;
|
||||
|
||||
public:
|
||||
virtual ~BezierCurveSegment();
|
||||
|
||||
void AddControlPoint(const Vec2d &iPoint);
|
||||
void Build();
|
||||
|
||||
inline int size() const
|
||||
{
|
||||
return _ControlPolygon.size();
|
||||
}
|
||||
|
||||
inline std::vector<Vec2d> &vertices()
|
||||
{
|
||||
return _Vertices;
|
||||
}
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BezierCurveSegment")
|
||||
};
|
||||
|
||||
class 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;
|
||||
}
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BezierCurve")
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,71 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define a cell grid surrounding the bounding box of the scene
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "FastGrid.h"
|
||||
|
||||
#include "BKE_global.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
void FastGrid::clear()
|
||||
{
|
||||
if (!_cells) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _cells_size; i++) {
|
||||
if (_cells[i]) {
|
||||
delete _cells[i];
|
||||
}
|
||||
}
|
||||
delete[] _cells;
|
||||
_cells = nullptr;
|
||||
_cells_size = 0;
|
||||
|
||||
Grid::clear();
|
||||
}
|
||||
|
||||
void FastGrid::configure(const Vec3r &orig, const Vec3r &size, uint 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 (blender::G.debug & blender::G_DEBUG_FREESTYLE) {
|
||||
cout << _cells << " " << p << " " << _cells_nb[0] << "-" << _cells_nb[1] << "-" << _cells_nb[2]
|
||||
<< " " << _cells_size << endl;
|
||||
}
|
||||
#endif
|
||||
BLI_assert_msg(_cells, "_cells is a null pointer");
|
||||
BLI_assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]) < _cells_size);
|
||||
BLI_assert(p[0] < _cells_nb[0]);
|
||||
BLI_assert(p[1] < _cells_nb[1]);
|
||||
BLI_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)
|
||||
{
|
||||
BLI_assert_msg(_cells, "_cells is a null pointer");
|
||||
BLI_assert((_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]) < _cells_size);
|
||||
BLI_assert(p[0] < _cells_nb[0]);
|
||||
BLI_assert(p[1] < _cells_nb[1]);
|
||||
BLI_assert(p[2] < _cells_nb[2]);
|
||||
_cells[_cells_nb[0] * (p[2] * _cells_nb[1] + p[1]) + p[0]] = &cell;
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,63 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define a cell grid surrounding the bounding box of the scene
|
||||
*/
|
||||
|
||||
#include "Grid.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
/** Class to define a regular grid used for ray casting computations
|
||||
* We don't use a hash-table 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 FastGrid : public Grid {
|
||||
public:
|
||||
FastGrid() : Grid()
|
||||
{
|
||||
_cells = nullptr;
|
||||
_cells_size = 0;
|
||||
}
|
||||
|
||||
virtual ~FastGrid()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* clears the grid
|
||||
* Deletes all the cells, clears the hash-table, 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, uint nb);
|
||||
|
||||
/** returns the cell whose coordinates are passed 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;
|
||||
uint _cells_size;
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:FastGrid")
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,569 @@
|
||||
/* SPDX-FileCopyrightText: 2008-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief An Algorithm for Automatically Fitting Digitized Curves by Philip J. Schneider,
|
||||
* \brief from "Graphics Gems", Academic Press, 1990
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib> // for malloc and free
|
||||
|
||||
#include "FitCurve.h"
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
using BezierCurve = Vector2 *;
|
||||
|
||||
/* 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 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);
|
||||
|
||||
/* 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[2]; /* 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 control points. */
|
||||
|
||||
bezCurve = (Vector2 *)malloc(4 * sizeof(Vector2));
|
||||
nPts = last - first + 1;
|
||||
|
||||
/* 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++) {
|
||||
/* Compute the A's */
|
||||
A[0] = tHat1;
|
||||
A[1] = tHat2;
|
||||
V2Scale(&A[0], B1(uPrime[i]));
|
||||
V2Scale(&A[1], B2(uPrime[i]));
|
||||
|
||||
C[0][0] += V2Dot(&A[0], &A[0]);
|
||||
C[0][1] += V2Dot(&A[0], &A[1]);
|
||||
// C[1][0] += V2Dot(&A[0], &A[1]);
|
||||
C[1][0] = C[0][1];
|
||||
C[1][1] += V2Dot(&A[1], &A[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[0], &tmp);
|
||||
X[1] += V2Dot(&A[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(uint((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);
|
||||
|
||||
/* avoid numerical singularity in the special case when V1 == -V2 */
|
||||
if (V2Length(&tHatCenter) < M_EPSILON) {
|
||||
tHatCenter = *V2Normalize(&V1);
|
||||
}
|
||||
|
||||
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(uint(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;
|
||||
}
|
||||
|
||||
//------------------------- WRAPPER -----------------------------//
|
||||
|
||||
FitCurveWrapper::~FitCurveWrapper()
|
||||
{
|
||||
_vertices.clear();
|
||||
}
|
||||
|
||||
void FitCurveWrapper::DrawBezierCurve(int n, Vector2 *curve)
|
||||
{
|
||||
for (int i = 0; i <= n; ++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);
|
||||
|
||||
delete[] d;
|
||||
|
||||
// copy results
|
||||
for (vector<Vector2>::iterator v = _vertices.begin(), vend = _vertices.end(); v != vend; ++v) {
|
||||
oCurve.emplace_back(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);
|
||||
|
||||
free((void *)u);
|
||||
free((void *)bezCurve);
|
||||
u = uPrime;
|
||||
|
||||
bezCurve = GenerateBezier(d, first, last, u, tHat1, tHat2);
|
||||
maxError = ComputeMaxError(d, first, last, bezCurve, u, &splitPoint);
|
||||
|
||||
if (maxError < error) {
|
||||
DrawBezierCurve(3, bezCurve);
|
||||
free((void *)u);
|
||||
free((void *)bezCurve);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,97 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief An Algorithm for Automatically Fitting Digitized Curves by Philip J. Schneider,
|
||||
* \brief from "Graphics Gems", Academic Press, 1990
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Geom.h"
|
||||
|
||||
#include "../system/FreestyleConfig.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
using namespace Geometry;
|
||||
|
||||
/* 2d point */
|
||||
struct Point2 {
|
||||
double coordinates[2];
|
||||
|
||||
Point2()
|
||||
{
|
||||
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];
|
||||
}
|
||||
};
|
||||
|
||||
using Vector2 = Point2;
|
||||
|
||||
class FitCurveWrapper {
|
||||
private:
|
||||
std::vector<Vector2> _vertices;
|
||||
|
||||
public:
|
||||
~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);
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,58 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Vectors and Matrices (useful type definitions)
|
||||
*/
|
||||
|
||||
#include "VecMat.h"
|
||||
|
||||
#include "../system/Precision.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
namespace Geometry {
|
||||
|
||||
typedef VecMat::Vec2<uint> Vec2u;
|
||||
typedef VecMat::Vec2<int> Vec2i;
|
||||
typedef VecMat::Vec2<float> Vec2f;
|
||||
typedef VecMat::Vec2<double> Vec2d;
|
||||
typedef VecMat::Vec2<real> Vec2r;
|
||||
|
||||
typedef VecMat::Vec3<uint> Vec3u;
|
||||
typedef VecMat::Vec3<int> Vec3i;
|
||||
typedef VecMat::Vec3<float> Vec3f;
|
||||
typedef VecMat::Vec3<double> Vec3d;
|
||||
typedef VecMat::Vec3<real> Vec3r;
|
||||
|
||||
typedef VecMat::HVec3<uint> HVec3u;
|
||||
typedef VecMat::HVec3<int> HVec3i;
|
||||
typedef VecMat::HVec3<float> HVec3f;
|
||||
typedef VecMat::HVec3<double> HVec3d;
|
||||
typedef VecMat::HVec3<real> HVec3r;
|
||||
|
||||
typedef VecMat::SquareMatrix<uint, 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<uint, 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<uint, 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
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,243 @@
|
||||
/* SPDX-FileCopyrightText: 2012-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define a cleaner of geometry providing a set of useful tools
|
||||
*/
|
||||
|
||||
#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 <cstdio>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include "GeomCleaner.h"
|
||||
|
||||
#include "../system/TimeUtils.h"
|
||||
|
||||
#include "BKE_global.hh"
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
void GeomCleaner::SortIndexedVertexArray(const float *iVertices,
|
||||
uint iVSize,
|
||||
const uint *iIndices,
|
||||
uint iISize,
|
||||
float **oVertices,
|
||||
uint **oIndices)
|
||||
{
|
||||
// First, we build a list of IndexVertex:
|
||||
list<IndexedVertex> indexedVertices;
|
||||
uint i;
|
||||
for (i = 0; i < iVSize; i += 3) {
|
||||
indexedVertices.emplace_back(Vec3f(iVertices[i], iVertices[i + 1], iVertices[i + 2]), i / 3);
|
||||
}
|
||||
|
||||
// q-sort
|
||||
indexedVertices.sort();
|
||||
|
||||
// build the indices mapping array:
|
||||
uint *mapIndices = new uint[iVSize / 3];
|
||||
*oVertices = new float[iVSize];
|
||||
list<IndexedVertex>::iterator iv;
|
||||
uint newIndex = 0;
|
||||
uint 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 uint[iISize];
|
||||
for (i = 0; i < iISize; i++) {
|
||||
(*oIndices)[i] = 3 * mapIndices[iIndices[i] / 3];
|
||||
}
|
||||
|
||||
delete[] mapIndices;
|
||||
}
|
||||
|
||||
void GeomCleaner::CompressIndexedVertexArray(const float *iVertices,
|
||||
uint iVSize,
|
||||
const uint *iIndices,
|
||||
uint iISize,
|
||||
float **oVertices,
|
||||
uint *oVSize,
|
||||
uint **oIndices)
|
||||
{
|
||||
// First, we build a list of IndexVertex:
|
||||
vector<Vec3f> vertices;
|
||||
uint i;
|
||||
for (i = 0; i < iVSize; i += 3) {
|
||||
vertices.emplace_back(iVertices[i], iVertices[i + 1], iVertices[i + 2]);
|
||||
}
|
||||
|
||||
uint *mapVertex = new uint[iVSize];
|
||||
vector<Vec3f>::iterator v = vertices.begin();
|
||||
|
||||
vector<Vec3f> compressedVertices;
|
||||
Vec3f previous = *v;
|
||||
mapVertex[0] = 0;
|
||||
compressedVertices.push_back(vertices.front());
|
||||
|
||||
v++;
|
||||
Vec3f 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 float[*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 uint[iISize];
|
||||
for (i = 0; i < iISize; i++) {
|
||||
(*oIndices)[i] = 3 * mapVertex[iIndices[i] / 3];
|
||||
}
|
||||
|
||||
delete[] mapVertex;
|
||||
}
|
||||
|
||||
void GeomCleaner::SortAndCompressIndexedVertexArray(const float *iVertices,
|
||||
uint iVSize,
|
||||
const uint *iIndices,
|
||||
uint iISize,
|
||||
float **oVertices,
|
||||
uint *oVSize,
|
||||
uint **oIndices)
|
||||
{
|
||||
// tmp arrays used to store the sorted data:
|
||||
float *tmpVertices;
|
||||
uint *tmpIndices;
|
||||
|
||||
Chronometer chrono;
|
||||
// Sort data
|
||||
chrono.start();
|
||||
GeomCleaner::SortIndexedVertexArray(
|
||||
iVertices, iVSize, iIndices, iISize, &tmpVertices, &tmpIndices);
|
||||
if (blender::G.debug & blender::G_DEBUG_FREESTYLE) {
|
||||
printf("Sorting: %lf sec.\n", chrono.stop());
|
||||
}
|
||||
|
||||
// compress data
|
||||
chrono.start();
|
||||
GeomCleaner::CompressIndexedVertexArray(
|
||||
tmpVertices, iVSize, tmpIndices, iISize, oVertices, oVSize, oIndices);
|
||||
real duration = chrono.stop();
|
||||
if (blender::G.debug & blender::G_DEBUG_FREESTYLE) {
|
||||
printf("Merging: %lf sec.\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 = ulong(p[0] * _MUL) % _MOD;
|
||||
res = (res + ulong(p[1]) * _MUL) % _MOD;
|
||||
return (res + ulong(p[2]) * _MUL) % _MOD;
|
||||
}
|
||||
#undef _MUL
|
||||
#undef _MOD
|
||||
};
|
||||
|
||||
void GeomCleaner::CleanIndexedVertexArray(const float *iVertices,
|
||||
uint iVSize,
|
||||
const uint *iIndices,
|
||||
uint iISize,
|
||||
float **oVertices,
|
||||
uint *oVSize,
|
||||
uint **oIndices)
|
||||
{
|
||||
using cleanHashTable = map<Vec3f, uint>;
|
||||
vector<Vec3f> vertices;
|
||||
uint i;
|
||||
for (i = 0; i < iVSize; i += 3) {
|
||||
vertices.emplace_back(iVertices[i], iVertices[i + 1], iVertices[i + 2]);
|
||||
}
|
||||
|
||||
cleanHashTable ht;
|
||||
vector<uint> newIndices;
|
||||
vector<Vec3f> newVertices;
|
||||
|
||||
// elimination of needless points
|
||||
uint currentIndex = 0;
|
||||
vector<Vec3f>::const_iterator v = vertices.begin();
|
||||
vector<Vec3f>::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 float[*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 uint[iISize];
|
||||
for (i = 0; i < iISize; i++) {
|
||||
(*oIndices)[i] = 3 * newIndices[iIndices[i] / 3];
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,234 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define a cleaner of geometry providing a set of useful tools
|
||||
*/
|
||||
|
||||
#include "Geom.h"
|
||||
|
||||
#include "../system/FreestyleConfig.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
using namespace Geometry;
|
||||
|
||||
class 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 a uint 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 series 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,
|
||||
uint iVSize,
|
||||
const uint *iIndices,
|
||||
uint iISize,
|
||||
float **oVertices,
|
||||
uint **oIndices);
|
||||
|
||||
/** Compress a SORTED indexed vertex array by eliminating multiple
|
||||
* appearing occurrences 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 a uint 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 series 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 float *iVertices,
|
||||
uint iVSize,
|
||||
const uint *iIndices,
|
||||
uint iISize,
|
||||
float **oVertices,
|
||||
uint *oVSize,
|
||||
uint **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 a uint 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 series 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,
|
||||
uint iVSize,
|
||||
const uint *iIndices,
|
||||
uint iISize,
|
||||
float **oVertices,
|
||||
uint *oVSize,
|
||||
uint **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 a uint 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 series 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,
|
||||
uint iVSize,
|
||||
const uint *iIndices,
|
||||
uint iISize,
|
||||
float **oVertices,
|
||||
uint *oVSize,
|
||||
uint **oIndices);
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:GeomCleaner")
|
||||
};
|
||||
|
||||
/** 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:
|
||||
Vec3f _Vector;
|
||||
uint _index;
|
||||
|
||||
public:
|
||||
inline IndexedVertex() {}
|
||||
|
||||
inline IndexedVertex(Vec3f iVector, uint iIndex)
|
||||
{
|
||||
_Vector = iVector;
|
||||
_index = iIndex;
|
||||
}
|
||||
|
||||
/** accessors */
|
||||
inline const Vec3f &vector() const
|
||||
{
|
||||
return _Vector;
|
||||
}
|
||||
|
||||
inline uint index()
|
||||
{
|
||||
return _index;
|
||||
}
|
||||
|
||||
inline float x()
|
||||
{
|
||||
return _Vector[0];
|
||||
}
|
||||
|
||||
inline float y()
|
||||
{
|
||||
return _Vector[1];
|
||||
}
|
||||
|
||||
inline float z()
|
||||
{
|
||||
return _Vector[2];
|
||||
}
|
||||
|
||||
/** modifiers */
|
||||
inline void setVector(const Vec3f &iVector)
|
||||
{
|
||||
_Vector = iVector;
|
||||
}
|
||||
|
||||
inline void setIndex(uint iIndex)
|
||||
{
|
||||
_index = iIndex;
|
||||
}
|
||||
|
||||
/** operators */
|
||||
IndexedVertex &operator=(const IndexedVertex &iv)
|
||||
{
|
||||
_Vector = iv._Vector;
|
||||
_index = iv._index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline float operator[](const uint 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);
|
||||
}
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:IndexedVertex")
|
||||
};
|
||||
|
||||
#if 0
|
||||
bool operator<(const IndexedVertex &iv1, const IndexedVertex &iv2)
|
||||
{
|
||||
return iv1.operator<(iv2);
|
||||
}
|
||||
#endif
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,840 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Various tools for geometry
|
||||
*/
|
||||
|
||||
#include "GeomUtils.h"
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
namespace Freestyle::GeomUtils {
|
||||
|
||||
// This internal procedure is defined below.
|
||||
bool intersect2dSegPoly(Vec2r *seg, Vec2r *poly, uint 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(const Vec3r &normal, const real d, const Vec3r &maxbox);
|
||||
|
||||
bool overlapTriangleBox(const Vec3r &boxcenter, const Vec3r &boxhalfsize, const Vec3r triverts[3])
|
||||
{
|
||||
/* 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.
|
||||
*
|
||||
* Adapted from Tomas Akenine-Möller code. */
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* Fast, Minimum Storage Ray-Triangle Intersection.
|
||||
* Adapted from Tomas Möller and Ben Trumbore code.
|
||||
*
|
||||
* Tomas Möller, Prosolvia Clarus AB, Sweden, <tompa@clarus.se>.
|
||||
* Ben Trumbore, Cornell University, Ithaca, New York <wbt@graphics.cornell.edu>. */
|
||||
|
||||
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 parallel to the plane of the triangle
|
||||
}
|
||||
|
||||
u *= inv_det;
|
||||
v *= inv_det;
|
||||
t = (edge2 * qvec) * inv_det;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
intersection_test intersectRayPlane(const Vec3r &orig,
|
||||
const Vec3r &dir,
|
||||
const Vec3r &norm,
|
||||
const real d,
|
||||
real &t,
|
||||
const real epsilon)
|
||||
{
|
||||
/* Intersection between plane and ray, adapted from Graphics Gems, Didier Badouel
|
||||
* The plane is represented by a set of points P implicitly defined as `dot(norm, P) + d = 0`.
|
||||
* The ray is represented as `r(t) = orig + dir * t`. */
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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 (uint j = 0; j < 4; j++) {
|
||||
scale = hvert[j];
|
||||
for (uint 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)
|
||||
{
|
||||
size_t i;
|
||||
res.resize(vertices.size());
|
||||
for (i = 0; i < vertices.size(); i++) {
|
||||
transformVertex(vertices[i], trans, res[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Vec3r rotateVector(const Matrix44r &mat, const Vec3r &v)
|
||||
{
|
||||
Vec3r res;
|
||||
for (uint i = 0; i < 3; i++) {
|
||||
res[i] = 0;
|
||||
for (uint 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])
|
||||
{
|
||||
const real translation[3] = {
|
||||
model_view_matrix[0][3],
|
||||
model_view_matrix[1][3],
|
||||
model_view_matrix[2][3],
|
||||
};
|
||||
for (ushort i = 0; i < 3; i++) {
|
||||
q[i] = 0.0;
|
||||
for (ushort 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, uint 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 (uint 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;
|
||||
}
|
||||
|
||||
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(const Vec3r &normal, const real d, const Vec3r &maxbox)
|
||||
{
|
||||
Vec3r vmin, vmax;
|
||||
|
||||
for (uint 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 (uint i = 0; i < 4; i++) {
|
||||
for (uint j = 0; j < 4; j++) {
|
||||
hq[i] += transform[i][j] * hp[j];
|
||||
}
|
||||
}
|
||||
|
||||
if (hq[3] == 0) {
|
||||
q = p;
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint k = 0; k < 3; k++) {
|
||||
q[k] = hq[k] / hq[3];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Freestyle::GeomUtils
|
||||
@@ -0,0 +1,254 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Various tools for geometry
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Geom.h"
|
||||
|
||||
#include "../system/FreestyleConfig.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
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
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
enum intersection_test {
|
||||
DONT_INTERSECT,
|
||||
DO_INTERSECT,
|
||||
COLINEAR,
|
||||
COINCIDENT,
|
||||
};
|
||||
|
||||
intersection_test intersect2dSeg2dSeg(const Vec2r &p1,
|
||||
const Vec2r &p2, // first segment
|
||||
const Vec2r &p3,
|
||||
const Vec2r &p4, // second segment
|
||||
Vec2r &res); // found intersection point
|
||||
|
||||
intersection_test intersect2dLine2dLine(const Vec2r &p1,
|
||||
const Vec2r &p2, // first segment
|
||||
const Vec2r &p3,
|
||||
const Vec2r &p4, // second segment
|
||||
Vec2r &res); // found intersection point
|
||||
|
||||
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 */
|
||||
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 */
|
||||
bool include2dSeg2dArea(const Vec2r &min, const Vec2r &max, const Vec2r &A, const Vec2r &B);
|
||||
|
||||
/** Box-triangle overlap test. */
|
||||
bool overlapTriangleBox(const Vec3r &boxcenter, const Vec3r &boxhalfsize, const Vec3r triverts[3]);
|
||||
|
||||
/** Fast, Minimum Storage Ray-Triangle Intersection. */
|
||||
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. */
|
||||
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.
|
||||
*/
|
||||
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 */
|
||||
bool includePointTriangle(const Vec3r &P, const Vec3r &A, const Vec3r &B, const Vec3r &C);
|
||||
|
||||
void transformVertex(const Vec3r &vert, const Matrix44r &matrix, Vec3r &res);
|
||||
|
||||
void transformVertices(const vector<Vec3r> &vertices, const Matrix44r &trans, vector<Vec3r> &res);
|
||||
|
||||
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)
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
void fromCameraToRetina(const Vec3r &p, Vec3r &q, const real projection_matrix[4][4]);
|
||||
|
||||
/** From retina to image.
|
||||
* Returns the coordinates expressed in Image coordinates 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).
|
||||
*/
|
||||
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).
|
||||
*/
|
||||
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)
|
||||
*/
|
||||
void fromRetinaToCamera(const Vec3r &p, Vec3r &q, real focal, 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)
|
||||
*/
|
||||
void fromCameraToWorld(const Vec3r &p, Vec3r &q, const real model_view_matrix[4][4]);
|
||||
|
||||
} // end of namespace GeomUtils
|
||||
|
||||
} /* namespace Freestyle */
|
||||
389
blender-5.2.0/source/blender/freestyle/intern/geometry/Grid.cpp
Normal file
389
blender-5.2.0/source/blender/freestyle/intern/geometry/Grid.cpp
Normal file
@@ -0,0 +1,389 @@
|
||||
/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Base class to define a cell grid surrounding the bounding box of the scene
|
||||
*/
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "BBox.h"
|
||||
#include "Grid.h"
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
// 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 = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Freestyle
|
||||
|
||||
bool firstIntersectionGridVisitor::stop()
|
||||
{
|
||||
if (occluder_) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Grid
|
||||
/////////////////
|
||||
void Grid::clear()
|
||||
{
|
||||
if (!_occluders.empty()) {
|
||||
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, uint 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.
|
||||
uint i;
|
||||
for (i = 0; i < 3; i++) {
|
||||
_cells_nb[i] = uint(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.empty()) {
|
||||
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 coordinates 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.
|
||||
|
||||
uint 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 ¤t_cell, Vec3u &next_cell)
|
||||
{
|
||||
next_cell = current_cell;
|
||||
real t_min, t;
|
||||
uint i;
|
||||
|
||||
t_min = FLT_MAX; // init tmin with handle of the case where one or 2 _u[i] = 0.
|
||||
uint 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
|
||||
// corresponding 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, uint timestamp)
|
||||
{
|
||||
initRay(orig, end, timestamp);
|
||||
allOccludersGridVisitor visitor(occluders);
|
||||
castRayInternal(visitor);
|
||||
}
|
||||
|
||||
void Grid::castInfiniteRay(const Vec3r &orig,
|
||||
const Vec3r &dir,
|
||||
OccludersSet &occluders,
|
||||
uint 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, uint timestamp)
|
||||
{
|
||||
Polygon3r *occluder = nullptr;
|
||||
Vec3r end = Vec3r(orig + FLT_MAX * dir / dir.norm());
|
||||
bool inter = initInfiniteRay(orig, dir, timestamp);
|
||||
if (!inter) {
|
||||
return nullptr;
|
||||
}
|
||||
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, uint timestamp)
|
||||
{
|
||||
_ray_dir = end - orig;
|
||||
_t_end = _ray_dir.norm();
|
||||
_t = 0;
|
||||
_ray_dir.normalize();
|
||||
_timestamp = timestamp;
|
||||
|
||||
for (uint i = 0; i < 3; i++) {
|
||||
_current_cell[i] = uint(floor((orig[i] - _orig[i]) / _cell_size[i]));
|
||||
// soc unused - uint 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, uint 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 (uint i = 0; i < 3; i++) {
|
||||
_current_cell[i] = uint(floor((orig[i] - _orig[i]) / _cell_size[i]));
|
||||
// soc unused - uint 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)) {
|
||||
BLI_assert(tmin != -1.0);
|
||||
Vec3r newOrig = orig + tmin * _ray_dir;
|
||||
for (uint i = 0; i < 3; i++) {
|
||||
_current_cell[i] = uint(floor((newOrig[i] - _orig[i]) / _cell_size[i]));
|
||||
if (_current_cell[i] == _cells_nb[i]) {
|
||||
_current_cell[i] = _cells_nb[i] - 1;
|
||||
}
|
||||
// soc unused - uint u = _current_cell[i];
|
||||
_pt[i] = newOrig[i] - _orig[i] - _current_cell[i] * _cell_size[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//_ray_occluders.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
398
blender-5.2.0/source/blender/freestyle/intern/geometry/Grid.h
Normal file
398
blender-5.2.0/source/blender/freestyle/intern/geometry/Grid.h
Normal file
@@ -0,0 +1,398 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Base class to define a cell grid surrounding the bounding box of the scene
|
||||
*/
|
||||
|
||||
#include <cstring> // for memset
|
||||
#include <float.h>
|
||||
#include <stdint.h> // For POINTER_FROM_UINT, i.e. uintptr_t.
|
||||
#include <vector>
|
||||
|
||||
#include "Geom.h"
|
||||
#include "GeomUtils.h"
|
||||
#include "Polygon.h"
|
||||
|
||||
#include "../system/FreestyleConfig.h"
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
using namespace Geometry;
|
||||
|
||||
typedef vector<Polygon3r *> OccludersSet;
|
||||
|
||||
//
|
||||
// Class to define cells used by the regular grid
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class 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;
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Cell")
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:GridVisitor")
|
||||
};
|
||||
|
||||
/** 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 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 hash-table, 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, uint 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 ((uint)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 passed 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), nullptr 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 (uint 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 constituting a convex polygon
|
||||
*/
|
||||
void insertOccluder(Polygon3r *occluder);
|
||||
|
||||
/** 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, uint timestamp);
|
||||
|
||||
// Prepares to cast ray without generating OccludersSet
|
||||
void initAcceleratedRay(const Vec3r &orig, const Vec3r &end, uint 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,
|
||||
uint timestamp);
|
||||
|
||||
// Prepares to cast ray without generating OccludersSet.
|
||||
bool initAcceleratedInfiniteRay(const Vec3r &orig, const Vec3r &dir, uint 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, uint timestamp);
|
||||
|
||||
/** Init all structures and values for computing the cells intersected by this new ray */
|
||||
void initRay(const Vec3r &orig, const Vec3r &end, uint 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, uint 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 = nullptr;
|
||||
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 (POINTER_AS_UINT((*it)->userdata2) != _timestamp) {
|
||||
(*it)->userdata2 = POINTER_FROM_UINT(_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 ¤t_cell, Vec3u &next_cell);
|
||||
|
||||
uint _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
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle: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;
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:VirtualOccludersSet")
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,35 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define a cell grid surrounding the projected image of a scene
|
||||
*/
|
||||
|
||||
#include "GridHelpers.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
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] = blender::g_freestyle.viewport[2] * (borderZone - bufferZone);
|
||||
viewProscenium[1] = blender::g_freestyle.viewport[2] * (1.0f - borderZone + bufferZone);
|
||||
viewProscenium[2] = blender::g_freestyle.viewport[3] * (borderZone - bufferZone);
|
||||
viewProscenium[3] = blender::g_freestyle.viewport[3] * (1.0f - borderZone + bufferZone);
|
||||
}
|
||||
|
||||
GridHelpers::Transform::~Transform() = default;
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,199 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define a cell grid surrounding the projected image of a scene
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "FRS_freestyle.h"
|
||||
|
||||
#include "GeomUtils.h"
|
||||
#include "Polygon.h"
|
||||
|
||||
#include "../winged_edge/WEdge.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
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 (uint 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 (uint 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;
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:GridHelpers:Transform")
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace GridHelpers
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-FileCopyrightText: 2012-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define a cell grid surrounding the bounding box of the scene
|
||||
*/
|
||||
|
||||
#include "HashGrid.h"
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
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, uint nb)
|
||||
{
|
||||
Grid::configure(orig, size, nb);
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,91 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define a cell grid surrounding the bounding box of the scene
|
||||
*/
|
||||
|
||||
#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"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
/** 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 = (ulong(p[0] * _MUL)) % _MOD;
|
||||
res = ((res + ulong(p[1]) * _MUL)) % _MOD;
|
||||
return ((res + ulong(p[2]) * _MUL)) % _MOD;
|
||||
}
|
||||
#undef _MUL
|
||||
#undef _MOD
|
||||
};
|
||||
|
||||
/** Class to define a regular grid used for ray casting computations */
|
||||
class HashGrid : public Grid {
|
||||
public:
|
||||
typedef map<Vec3u, Cell *> GridHashTable;
|
||||
|
||||
HashGrid() : Grid() {}
|
||||
|
||||
virtual ~HashGrid()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
/** clears the grid
|
||||
* Deletes all the cells, clears the hash-table, 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, uint nb);
|
||||
|
||||
/** returns the cell whose coordinates are passed as argument */
|
||||
virtual Cell *getCell(const Vec3u &p)
|
||||
{
|
||||
Cell *found_cell = nullptr;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
271
blender-5.2.0/source/blender/freestyle/intern/geometry/Noise.cpp
Normal file
271
blender-5.2.0/source/blender/freestyle/intern/geometry/Noise.cpp
Normal file
@@ -0,0 +1,271 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define Perlin noise
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
#include "Noise.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
#define SCURVE(a) ((a) * (a) * (3.0 - 2.0 * (a)))
|
||||
|
||||
#if 0 // XXX Unused
|
||||
# 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
|
||||
#endif
|
||||
|
||||
#define BM 0xff
|
||||
#define N 0x1000
|
||||
#if 0 // XXX Unused
|
||||
# define NP 12 /* 2^N */
|
||||
# define NM 0xfff
|
||||
#endif
|
||||
|
||||
#define LERP(t, a, b) ((a) + (t) * ((b) - (a)))
|
||||
|
||||
#define SETUP(i, b0, b1, r0, r1) \
|
||||
{ \
|
||||
(t) = (i) + (N); \
|
||||
(r0) = modff((t), &(u)); \
|
||||
(r1) = (r0) - 1.0; \
|
||||
(b0) = int(u) & BM; \
|
||||
(b1) = ((b0) + 1) & BM; \
|
||||
} \
|
||||
(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, uint 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, uint 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, uint 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;
|
||||
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;
|
||||
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)
|
||||
{
|
||||
/* Use Blender RNG for repeatable results across platforms. */
|
||||
blender::RNG *rng = blender::BLI_rng_new(seed);
|
||||
int i, j, k;
|
||||
|
||||
for (i = 0; i < _NOISE_B; i++) {
|
||||
p[i] = i;
|
||||
g1[i] = float((BLI_rng_get_int(rng) % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B;
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
g2[i][j] = float((BLI_rng_get_int(rng) % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B;
|
||||
}
|
||||
normalize2(g2[i]);
|
||||
|
||||
for (j = 0; j < 3; j++) {
|
||||
g3[i][j] = float((BLI_rng_get_int(rng) % (_NOISE_B + _NOISE_B)) - _NOISE_B) / _NOISE_B;
|
||||
}
|
||||
normalize3(g3[i]);
|
||||
}
|
||||
|
||||
while (--i) {
|
||||
k = p[i];
|
||||
p[i] = p[j = BLI_rng_get_int(rng) % _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];
|
||||
}
|
||||
}
|
||||
|
||||
BLI_rng_free(rng);
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,64 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define Perlin noise
|
||||
*/
|
||||
|
||||
#include "Geom.h"
|
||||
|
||||
#include "../system/FreestyleConfig.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
#define _NOISE_B 0x100
|
||||
|
||||
using namespace Geometry;
|
||||
|
||||
/** Class to provide Perlin Noise functionalities */
|
||||
class 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, uint oct = 4);
|
||||
|
||||
/** Returns a noise value for a 2D element */
|
||||
float turbulence2(Vec2f &v, float freq, float amp, uint oct = 4);
|
||||
|
||||
/** Returns a noise value for a 3D element */
|
||||
float turbulence3(Vec3f &v, float freq, float amp, uint 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];
|
||||
/* UNUSED */
|
||||
// int start;
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Noise")
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
208
blender-5.2.0/source/blender/freestyle/intern/geometry/Polygon.h
Normal file
208
blender-5.2.0/source/blender/freestyle/intern/geometry/Polygon.h
Normal file
@@ -0,0 +1,208 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define a polygon
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Geom.h"
|
||||
#include "GeomUtils.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
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 uint 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(uint 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 (uint 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;
|
||||
uint _id;
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Geometry:Polygon")
|
||||
};
|
||||
|
||||
//
|
||||
// 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
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,321 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to define a Sweep Line
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
/** Class to define the intersection between 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.
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Intersection")
|
||||
};
|
||||
|
||||
#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 ushort &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.
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Segment")
|
||||
};
|
||||
|
||||
#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.
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:SweepLine")
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
955
blender-5.2.0/source/blender/freestyle/intern/geometry/VecMat.h
Normal file
955
blender-5.2.0/source/blender/freestyle/intern/geometry/VecMat.h
Normal file
@@ -0,0 +1,955 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Vectors and Matrices definition and manipulation
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
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, uint N> class Vec {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
// constructors
|
||||
inline Vec()
|
||||
{
|
||||
for (uint 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 (uint i = 0; i < N; i++) {
|
||||
this->_coord[i] = (T)tab[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<class U> explicit inline Vec(const std::vector<U> &tab)
|
||||
{
|
||||
for (uint i = 0; i < N; i++) {
|
||||
this->_coord[i] = (T)tab[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<class U> explicit inline Vec(const Vec<U, N> &v)
|
||||
{
|
||||
for (uint i = 0; i < N; i++) {
|
||||
this->_coord[i] = (T)v[i];
|
||||
}
|
||||
}
|
||||
|
||||
// accessors
|
||||
inline value_type operator[](const uint i) const
|
||||
{
|
||||
return this->_coord[i];
|
||||
}
|
||||
|
||||
inline value_type &operator[](const uint i)
|
||||
{
|
||||
return this->_coord[i];
|
||||
}
|
||||
|
||||
static inline uint 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 (uint i = 0; i < N; i++) {
|
||||
this->_coord[i] /= n;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Vec<T, N> &normalizeSafe()
|
||||
{
|
||||
value_type n = norm();
|
||||
if (n) {
|
||||
for (uint 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 (uint 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 (uint 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 (uint 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 (uint 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 (uint 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 (uint i = 0; i < N; i++) {
|
||||
this->_coord[i] /= r;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator==(const Vec<T, N> &v) const
|
||||
{
|
||||
for (uint 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 (uint 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 (uint 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 (uint 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,
|
||||
};
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:VecMat:Vec")
|
||||
};
|
||||
|
||||
//
|
||||
// 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 (uint 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];
|
||||
}
|
||||
|
||||
// Access 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 (uint 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, uint M, uint N> class Matrix {
|
||||
public:
|
||||
typedef T value_type;
|
||||
|
||||
inline Matrix()
|
||||
{
|
||||
for (uint 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 (uint i = 0; i < _SIZE; i++) {
|
||||
this->_coord[i] = tab[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<class U> explicit inline Matrix(const std::vector<U> &tab)
|
||||
{
|
||||
for (uint i = 0; i < _SIZE; i++) {
|
||||
this->_coord[i] = tab[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<class U> inline Matrix(const Matrix<U, M, N> &m)
|
||||
{
|
||||
for (uint i = 0; i < M; i++) {
|
||||
for (uint j = 0; j < N; j++) {
|
||||
this->_coord[i * N + j] = (T)m(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline value_type operator()(const uint i, const uint j) const
|
||||
{
|
||||
return this->_coord[i * N + j];
|
||||
}
|
||||
|
||||
inline value_type &operator()(const uint i, const uint j)
|
||||
{
|
||||
return this->_coord[i * N + j];
|
||||
}
|
||||
|
||||
static inline uint rows()
|
||||
{
|
||||
return M;
|
||||
}
|
||||
|
||||
static inline uint cols()
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
inline Matrix<T, M, N> &transpose() const
|
||||
{
|
||||
Matrix<T, N, M> res;
|
||||
for (uint i = 0; i < M; i++) {
|
||||
for (uint j = 0; j < N; j++) {
|
||||
res(j, i) = this->_coord[i * N + j];
|
||||
}
|
||||
}
|
||||
*this = res;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class U> inline Matrix<T, M, N> &operator=(const Matrix<U, M, N> &m)
|
||||
{
|
||||
if (this != &m) {
|
||||
for (uint i = 0; i < M; i++) {
|
||||
for (uint 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 (uint i = 0; i < M; i++) {
|
||||
for (uint 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 (uint i = 0; i < M; i++) {
|
||||
for (uint 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 (uint i = 0; i < M; i++) {
|
||||
for (uint 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 (uint i = 0; i < M; i++) {
|
||||
for (uint j = 0; j < N; j++) {
|
||||
this->_coord[i * N + j] /= lambda;
|
||||
}
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
value_type _coord[_SIZE];
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:VecMat:Matrix")
|
||||
};
|
||||
|
||||
#undef _SIZE
|
||||
|
||||
//
|
||||
// SquareMatrix class
|
||||
// - T: value type
|
||||
// - N: rows & cols
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Dirty, but icc under Windows needs this
|
||||
#define _SIZE (N * N)
|
||||
|
||||
template<class T, uint 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 (uint i = 0; i < N; i++) {
|
||||
res(i, i) = 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
#undef _SIZE
|
||||
|
||||
//
|
||||
// Vector external functions
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if 0
|
||||
template<class T, uint 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, uint 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, uint 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, uint 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, uint 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, uint 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 (uint 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, uint N> inline std::ostream &operator<<(std::ostream &s, const Vec<T, N> &v)
|
||||
{
|
||||
uint i;
|
||||
s << "[";
|
||||
for (i = 0; i < N - 1; i++) {
|
||||
s << v[i] << ", ";
|
||||
}
|
||||
s << v[i] << "]";
|
||||
return s;
|
||||
}
|
||||
|
||||
//
|
||||
// Matrix external functions
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<class T, uint M, uint 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, uint M, uint 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, uint M, uint 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, uint M, uint 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, uint M, uint 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, uint M, uint N, uint P>
|
||||
inline Matrix<T, M, P> operator*(const Matrix<T, M, N> &m1, const Matrix<T, N, P> &m2)
|
||||
{
|
||||
uint 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, uint M, uint 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 (uint j = 0; j < M; j++) {
|
||||
scale = v[j];
|
||||
for (uint i = 0; i < N; i++) {
|
||||
res[i] += m(i, j) * scale;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// stream operator
|
||||
template<class T, uint M, uint N>
|
||||
inline std::ostream &operator<<(std::ostream &s, const Matrix<T, M, N> &m)
|
||||
{
|
||||
uint 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
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,233 @@
|
||||
/* SPDX-FileCopyrightText: 2000 `Bruno Levy <levy@loria.fr>`
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* The Original Code is:
|
||||
* - GXML/Graphite: Geometry and Graphics Programming Library + Utilities.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "matrix_util.h"
|
||||
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
namespace Freestyle::OGF::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 (!ELEM(i, l, 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 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;
|
||||
}
|
||||
|
||||
//_________________________________________________________
|
||||
|
||||
} // namespace Freestyle::OGF::MatrixUtil
|
||||
@@ -0,0 +1,46 @@
|
||||
/* SPDX-FileCopyrightText: 2000 `Bruno Levy <levy@loria.fr>`
|
||||
* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* The Original Code is:
|
||||
* - GXML/Graphite: Geometry and Graphics Programming Library + Utilities.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "../system/FreestyleConfig.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
namespace OGF {
|
||||
|
||||
namespace MatrixUtil {
|
||||
|
||||
/**
|
||||
* computes the eigen values and eigen vectors of a semi definite symmetric matrix
|
||||
*
|
||||
* \param mat: The matrix stored in column symmetric storage, i.e.
|
||||
* <pre>
|
||||
* matrix = { m11, m12, m22, m13, m23, m33, m14, m24, m34, m44 ... }
|
||||
* size = n(n+1)/2
|
||||
* </pre>
|
||||
*
|
||||
* \param eigen_vec: (return) = { v1, v2, v3, ..., vn }
|
||||
* where `vk = vk0, vk1, ..., vkn`
|
||||
* `size = n^2`, must be allocated by caller.
|
||||
*
|
||||
* \param eigen_val: (return) are in decreasing order
|
||||
* `size = n`, must be allocated by caller.
|
||||
*/
|
||||
void semi_definite_symmetric_eigen(const double *mat, int n, double *eigen_vec, double *eigen_val);
|
||||
|
||||
} // namespace MatrixUtil
|
||||
|
||||
} // namespace OGF
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,66 @@
|
||||
/* SPDX-FileCopyrightText: 2000 `Bruno Levy <levy@loria.fr>`
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* The Original Code is:
|
||||
* - OGF/Graphite: Geometry and Graphics Programming Library + Utilities.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "normal_cycle.h"
|
||||
#include "matrix_util.h"
|
||||
|
||||
namespace Freestyle::OGF {
|
||||
|
||||
//_________________________________________________________
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
//_________________________________________________________
|
||||
|
||||
} // namespace Freestyle::OGF
|
||||
@@ -0,0 +1,123 @@
|
||||
/* SPDX-FileCopyrightText: 2000 `Bruno Levy <levy@loria.fr>`
|
||||
* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* The Original Code is:
|
||||
* - OGF/Graphite: Geometry and Graphics Programming Library + Utilities.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "Geom.h"
|
||||
|
||||
#include "../system/FreestyleConfig.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
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 NormalCycle {
|
||||
public:
|
||||
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:
|
||||
/* UNUSED */
|
||||
// real center_[3];
|
||||
Vec3r axis_[3];
|
||||
real eigen_value_[3];
|
||||
real M_[6];
|
||||
int i_[3];
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:OGF:NormalCycle")
|
||||
};
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
//_________________________________________________________
|
||||
|
||||
} // namespace OGF
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,89 @@
|
||||
/* SPDX-FileCopyrightText: 2008-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to perform gaussian filtering operations on an image
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "GaussianFilter.h"
|
||||
|
||||
#include "BLI_math_base.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
GaussianFilter::GaussianFilter(float iSigma)
|
||||
{
|
||||
_sigma = iSigma;
|
||||
_mask = nullptr;
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,132 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to perform gaussian filtering operations on an image
|
||||
*/
|
||||
|
||||
#include <cstdlib> // for abs
|
||||
#include <string.h> // for memcpy
|
||||
|
||||
#include "../system/FreestyleConfig.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
class GaussianFilter {
|
||||
protected:
|
||||
/* The mask is a symmetrical 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. */
|
||||
|
||||
/** The sigma value of the gaussian function. */
|
||||
float _sigma;
|
||||
float *_mask;
|
||||
int _bound;
|
||||
/* The real mask size (must be odd), the size of the mask we store is:
|
||||
* `((_maskSize+1)/2)*((_maskSize+1)/2))`. */
|
||||
int _maskSize;
|
||||
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(uint x, uint y) const;`
|
||||
* - `uint width() const;`
|
||||
* - `uint 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.
|
||||
*/
|
||||
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();
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:GaussianFilter")
|
||||
};
|
||||
|
||||
/*
|
||||
* #############################################
|
||||
* #############################################
|
||||
* #############################################
|
||||
* ###### ######
|
||||
* ###### I M P L E M E N T A T I O N ######
|
||||
* ###### ######
|
||||
* #############################################
|
||||
* #############################################
|
||||
* #############################################
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
401
blender-5.2.0/source/blender/freestyle/intern/image/Image.h
Normal file
401
blender-5.2.0/source/blender/freestyle/intern/image/Image.h
Normal file
@@ -0,0 +1,401 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to encapsulate an array of RGB or Gray level values
|
||||
*/
|
||||
|
||||
#include <string.h> // for memcpy
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
//
|
||||
// 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(uint w, uint 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(uint w, uint h, uint sw, uint sh, uint ox, uint 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 uint width() const
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
|
||||
/** Returns the height of the complete image */
|
||||
inline uint height() const
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
/** Returns the gray value for pixel x,y */
|
||||
virtual float pixel(uint x, uint 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 x:
|
||||
* The x-abscissa of the origin of the rectangle that will actually be stored.
|
||||
* \param y:
|
||||
* 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,
|
||||
uint width,
|
||||
uint height,
|
||||
uint sw,
|
||||
uint sh,
|
||||
uint x,
|
||||
uint 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:
|
||||
uint _width;
|
||||
uint _height;
|
||||
uint _storedWidth;
|
||||
uint _storedHeight;
|
||||
uint _Ox; // origin of the stored part
|
||||
uint _Oy; // origin of the stored part
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:FrsImage")
|
||||
};
|
||||
|
||||
//
|
||||
// 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(uint w, uint h) : FrsImage(w, h)
|
||||
{
|
||||
_rgb = new float[3 * _width * _height];
|
||||
}
|
||||
|
||||
RGBImage(float *rgb, uint w, uint 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, uint w, uint h, uint sw, uint sh, uint ox, uint 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(uint x, uint y) const
|
||||
{
|
||||
return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3];
|
||||
}
|
||||
|
||||
inline float getG(uint x, uint y) const
|
||||
{
|
||||
return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3 + 1];
|
||||
}
|
||||
|
||||
inline float getB(uint x, uint y) const
|
||||
{
|
||||
return _rgb[3 * (y - _Oy) * _storedWidth + (x - _Ox) * 3 + 2];
|
||||
}
|
||||
|
||||
virtual void setPixel(uint x, uint 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(uint x, uint 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, uint width, uint height, uint sw, uint sh, uint x, uint 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(uint w, uint h) : FrsImage(w, h)
|
||||
{
|
||||
_lvl = new float[_width * _height];
|
||||
}
|
||||
|
||||
GrayImage(float *lvl, uint w, uint 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, uint w, uint h, uint sw, uint sh, uint ox, uint 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(uint x, uint y, float v)
|
||||
{
|
||||
_lvl[(y - _Oy) * _storedWidth + (x - _Ox)] = v;
|
||||
}
|
||||
|
||||
inline float pixel(uint x, uint y) const
|
||||
{
|
||||
return _lvl[(y - _Oy) * _storedWidth + (x - _Ox)];
|
||||
}
|
||||
|
||||
/** Sets the array.
|
||||
* copy
|
||||
* If true, the array is copied, otherwise the pounsigneder is copied
|
||||
*/
|
||||
void setArray(
|
||||
float *lvl, uint width, uint height, uint sw, uint sh, uint x, uint 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;
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,181 @@
|
||||
/* SPDX-FileCopyrightText: 2008-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to represent a pyramid of images
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "GaussianFilter.h"
|
||||
#include "Image.h"
|
||||
#include "ImagePyramid.h"
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
#if 0
|
||||
ImagePyramid::ImagePyramid(const GrayImage &level0, uint 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);
|
||||
}
|
||||
uint i = 1 << level;
|
||||
uint sx = x >> level;
|
||||
uint 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, uint nbLevels, float iSigma)
|
||||
{
|
||||
_sigma = iSigma;
|
||||
BuildPyramid(level0, nbLevels);
|
||||
}
|
||||
|
||||
GaussianPyramid::GaussianPyramid(GrayImage *level0, uint nbLevels, float iSigma)
|
||||
{
|
||||
_sigma = iSigma;
|
||||
BuildPyramid(level0, nbLevels);
|
||||
}
|
||||
|
||||
GaussianPyramid::GaussianPyramid(const GaussianPyramid &iBrother) : ImagePyramid(iBrother)
|
||||
{
|
||||
_sigma = iBrother._sigma;
|
||||
}
|
||||
|
||||
void GaussianPyramid::BuildPyramid(const GrayImage &level0, uint nbLevels)
|
||||
{
|
||||
GrayImage *pLevel = new GrayImage(level0);
|
||||
BuildPyramid(pLevel, nbLevels);
|
||||
}
|
||||
|
||||
void GaussianPyramid::BuildPyramid(GrayImage *level0, uint nbLevels)
|
||||
{
|
||||
GrayImage *pLevel = level0;
|
||||
_levels.push_back(pLevel);
|
||||
GaussianFilter gf(_sigma);
|
||||
// build the nbLevels:
|
||||
uint w = pLevel->width();
|
||||
uint h = pLevel->height();
|
||||
if (nbLevels != 0) {
|
||||
for (uint i = 0; i < nbLevels; ++i) { // soc
|
||||
w = pLevel->width() >> 1;
|
||||
h = pLevel->height() >> 1;
|
||||
GrayImage *img = new GrayImage(w, h);
|
||||
for (uint y = 0; y < h; ++y) {
|
||||
for (uint 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 (uint y = 0; y < h; ++y) {
|
||||
for (uint 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,94 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
* \brief Class to represent a pyramid of images
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../system/FreestyleConfig.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace Freestyle {
|
||||
|
||||
class GrayImage;
|
||||
|
||||
class ImagePyramid {
|
||||
protected:
|
||||
std::vector<GrayImage *> _levels;
|
||||
|
||||
public:
|
||||
ImagePyramid() {}
|
||||
ImagePyramid(const ImagePyramid &iBrother);
|
||||
// ImagePyramid(const GrayImage& level0, uint 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, uint nbLevels) = 0;
|
||||
|
||||
/** Builds a pyramid without copying the base level */
|
||||
virtual void BuildPyramid(GrayImage *level0, uint 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();
|
||||
}
|
||||
|
||||
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:ImagePyramid")
|
||||
};
|
||||
|
||||
class GaussianPyramid : public ImagePyramid {
|
||||
protected:
|
||||
float _sigma;
|
||||
|
||||
public:
|
||||
GaussianPyramid(float iSigma = 1.0f) : ImagePyramid()
|
||||
{
|
||||
_sigma = iSigma;
|
||||
}
|
||||
|
||||
GaussianPyramid(const GrayImage &level0, uint nbLevels, float iSigma = 1.0f);
|
||||
GaussianPyramid(GrayImage *level0, uint nbLevels, float iSigma = 1.0f);
|
||||
GaussianPyramid(const GaussianPyramid &iBrother);
|
||||
virtual ~GaussianPyramid() {}
|
||||
|
||||
virtual void BuildPyramid(const GrayImage &level0, uint nbLevels);
|
||||
virtual void BuildPyramid(GrayImage *level0, uint nbLevels);
|
||||
|
||||
/* accessors */
|
||||
inline float getSigma() const
|
||||
{
|
||||
return _sigma;
|
||||
}
|
||||
|
||||
/* modifiers */
|
||||
};
|
||||
|
||||
} /* namespace Freestyle */
|
||||
@@ -0,0 +1,106 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_BBox.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
using namespace Freestyle::Geometry;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int BBox_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&BBox_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "BBox", (PyObject *)&BBox_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
BBox_doc,
|
||||
"Class for representing a bounding box.\n"
|
||||
"\n"
|
||||
".. method:: __init__()\n"
|
||||
"\n"
|
||||
" Default constructor.\n");
|
||||
static int BBox_init(BPy_BBox *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {nullptr};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist)) {
|
||||
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);
|
||||
}
|
||||
|
||||
/*-----------------------BPy_BBox type definition ------------------------------*/
|
||||
|
||||
PyTypeObject BBox_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "BBox",
|
||||
/*tp_basicsize*/ sizeof(BPy_BBox),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)BBox_dealloc,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)BBox_repr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ BBox_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ nullptr,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ nullptr,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)BBox_init,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../geometry/BBox.h"
|
||||
#include "../geometry/Geom.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject BBox_Type;
|
||||
|
||||
#define BPy_BBox_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&BBox_Type))
|
||||
|
||||
/*---------------------------Python BPy_BBox structure definition----------*/
|
||||
struct BPy_BBox {
|
||||
PyObject_HEAD
|
||||
Freestyle::BBox<Freestyle::Geometry::Vec3r> *bb;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_BBox visible prototypes-----------*/
|
||||
|
||||
int BBox_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,174 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_BinaryPredicate0D.h"
|
||||
|
||||
#include "BPy_Convert.h"
|
||||
#include "BPy_Interface0D.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int BinaryPredicate0D_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&BinaryPredicate0D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "BinaryPredicate0D", (PyObject *)&BinaryPredicate0D_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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"
|
||||
" :param inter1: The first Interface0D object.\n"
|
||||
" :type inter1: :class:`Interface0D`\n"
|
||||
" :param 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)
|
||||
{
|
||||
static const char *kwlist[] = {nullptr};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist)) {
|
||||
return -1;
|
||||
}
|
||||
self->bp0D = new BinaryPredicate0D();
|
||||
self->bp0D->py_bp0D = (PyObject *)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void BinaryPredicate0D___dealloc__(BPy_BinaryPredicate0D *self)
|
||||
{
|
||||
delete self->bp0D;
|
||||
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
}
|
||||
|
||||
static PyObject *BinaryPredicate0D___repr__(BPy_BinaryPredicate0D *self)
|
||||
{
|
||||
return PyUnicode_FromFormat("type: %s - address: %p", Py_TYPE(self)->tp_name, self->bp0D);
|
||||
}
|
||||
|
||||
static PyObject *BinaryPredicate0D___call__(BPy_BinaryPredicate0D *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"inter1", "inter2", nullptr};
|
||||
BPy_Interface0D *obj1, *obj2;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "O!O!", (char **)kwlist, &Interface0D_Type, &obj1, &Interface0D_Type, &obj2))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (typeid(*(self->bp0D)) == typeid(BinaryPredicate0D)) {
|
||||
PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
|
||||
return nullptr;
|
||||
}
|
||||
if (self->bp0D->operator()(*(obj1->if0D), *(obj2->if0D)) < 0) {
|
||||
if (!PyErr_Occurred()) {
|
||||
string class_name(Py_TYPE(self)->tp_name);
|
||||
PyErr_SetString(PyExc_RuntimeError, (class_name + " __call__ method failed").c_str());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return PyBool_from_bool(self->bp0D->result);
|
||||
}
|
||||
|
||||
/*----------------------BinaryPredicate0D get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
BinaryPredicate0D_name_doc,
|
||||
"The name of the binary 0D predicate.\n"
|
||||
"\n"
|
||||
":type: str\n");
|
||||
static PyObject *BinaryPredicate0D_name_get(BPy_BinaryPredicate0D *self, void * /*closure*/)
|
||||
{
|
||||
return PyUnicode_FromString(Py_TYPE(self)->tp_name);
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_BinaryPredicate0D_getseters[] = {
|
||||
{"name",
|
||||
(getter)BinaryPredicate0D_name_get,
|
||||
(setter) nullptr,
|
||||
BinaryPredicate0D_name_doc,
|
||||
nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_BinaryPredicate0D type definition ------------------------------*/
|
||||
|
||||
PyTypeObject BinaryPredicate0D_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "BinaryPredicate0D",
|
||||
/*tp_basicsize*/ sizeof(BPy_BinaryPredicate0D),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)BinaryPredicate0D___dealloc__,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)BinaryPredicate0D___repr__,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ (ternaryfunc)BinaryPredicate0D___call__,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ BinaryPredicate0D___doc__,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ nullptr,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_BinaryPredicate0D_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)BinaryPredicate0D___init__,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../stroke/Predicates0D.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject BinaryPredicate0D_Type;
|
||||
|
||||
#define BPy_BinaryPredicate0D_Check(v) \
|
||||
(PyObject_IsInstance((PyObject *)v, (PyObject *)&BinaryPredicate0D_Type))
|
||||
|
||||
/*---------------------------Python BPy_BinaryPredicate0D structure definition----------*/
|
||||
struct BPy_BinaryPredicate0D {
|
||||
PyObject_HEAD
|
||||
Freestyle::BinaryPredicate0D *bp0D;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_BinaryPredicate0D visible prototypes-----------*/
|
||||
|
||||
int BinaryPredicate0D_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,205 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#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"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int BinaryPredicate1D_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&BinaryPredicate1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "BinaryPredicate1D", (PyObject *)&BinaryPredicate1D_Type);
|
||||
|
||||
if (PyType_Ready(&FalseBP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "FalseBP1D", (PyObject *)&FalseBP1D_Type);
|
||||
|
||||
if (PyType_Ready(&Length2DBP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "Length2DBP1D", (PyObject *)&Length2DBP1D_Type);
|
||||
|
||||
if (PyType_Ready(&SameShapeIdBP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "SameShapeIdBP1D", (PyObject *)&SameShapeIdBP1D_Type);
|
||||
|
||||
if (PyType_Ready(&TrueBP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "TrueBP1D", (PyObject *)&TrueBP1D_Type);
|
||||
|
||||
if (PyType_Ready(&ViewMapGradientNormBP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(
|
||||
module, "ViewMapGradientNormBP1D", (PyObject *)&ViewMapGradientNormBP1D_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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"
|
||||
" :param inter1: The first Interface1D object.\n"
|
||||
" :type inter1: :class:`Interface1D`\n"
|
||||
" :param 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)
|
||||
{
|
||||
static const char *kwlist[] = {nullptr};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist)) {
|
||||
return -1;
|
||||
}
|
||||
self->bp1D = new BinaryPredicate1D();
|
||||
self->bp1D->py_bp1D = (PyObject *)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void BinaryPredicate1D___dealloc__(BPy_BinaryPredicate1D *self)
|
||||
{
|
||||
delete self->bp1D;
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
}
|
||||
|
||||
static PyObject *BinaryPredicate1D___repr__(BPy_BinaryPredicate1D *self)
|
||||
{
|
||||
return PyUnicode_FromFormat("type: %s - address: %p", Py_TYPE(self)->tp_name, self->bp1D);
|
||||
}
|
||||
|
||||
static PyObject *BinaryPredicate1D___call__(BPy_BinaryPredicate1D *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"inter1", "inter2", nullptr};
|
||||
BPy_Interface1D *obj1, *obj2;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "O!O!", (char **)kwlist, &Interface1D_Type, &obj1, &Interface1D_Type, &obj2))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (typeid(*(self->bp1D)) == typeid(BinaryPredicate1D)) {
|
||||
PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
|
||||
return nullptr;
|
||||
}
|
||||
if (self->bp1D->operator()(*(obj1->if1D), *(obj2->if1D)) < 0) {
|
||||
if (!PyErr_Occurred()) {
|
||||
string class_name(Py_TYPE(self)->tp_name);
|
||||
PyErr_SetString(PyExc_RuntimeError, (class_name + " __call__ method failed").c_str());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return PyBool_from_bool(self->bp1D->result);
|
||||
}
|
||||
|
||||
/*----------------------BinaryPredicate0D get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
BinaryPredicate1D_name_doc,
|
||||
"The name of the binary 1D predicate.\n"
|
||||
"\n"
|
||||
":type: str\n");
|
||||
static PyObject *BinaryPredicate1D_name_get(BPy_BinaryPredicate1D *self, void * /*closure*/)
|
||||
{
|
||||
return PyUnicode_FromString(Py_TYPE(self)->tp_name);
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_BinaryPredicate1D_getseters[] = {
|
||||
{"name",
|
||||
(getter)BinaryPredicate1D_name_get,
|
||||
(setter) nullptr,
|
||||
BinaryPredicate1D_name_doc,
|
||||
nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_BinaryPredicate1D type definition ------------------------------*/
|
||||
|
||||
PyTypeObject BinaryPredicate1D_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "BinaryPredicate1D",
|
||||
/*tp_basicsize*/ sizeof(BPy_BinaryPredicate1D),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)BinaryPredicate1D___dealloc__,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)BinaryPredicate1D___repr__,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ (ternaryfunc)BinaryPredicate1D___call__,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ BinaryPredicate1D___doc__,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ nullptr,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_BinaryPredicate1D_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)BinaryPredicate1D___init__,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../stroke/Predicates1D.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject BinaryPredicate1D_Type;
|
||||
|
||||
#define BPy_BinaryPredicate1D_Check(v) \
|
||||
(PyObject_IsInstance((PyObject *)v, (PyObject *)&BinaryPredicate1D_Type))
|
||||
|
||||
/*---------------------------Python BPy_BinaryPredicate1D structure definition----------*/
|
||||
struct BPy_BinaryPredicate1D {
|
||||
PyObject_HEAD
|
||||
Freestyle::BinaryPredicate1D *bp1D;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_BinaryPredicate1D visible prototypes-----------*/
|
||||
|
||||
int BinaryPredicate1D_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,342 @@
|
||||
/* SPDX-FileCopyrightText: 2009-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_ContextFunctions.h"
|
||||
#include "BPy_Convert.h"
|
||||
|
||||
#include "../stroke/ContextFunctions.h"
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//------------------------ MODULE FUNCTIONS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ContextFunctions_get_time_stamp___doc__,
|
||||
".. function:: get_time_stamp()\n"
|
||||
"\n"
|
||||
" Returns the system time stamp.\n"
|
||||
"\n"
|
||||
" :return: The system time stamp.\n"
|
||||
" :rtype: int\n");
|
||||
static PyObject *ContextFunctions_get_time_stamp(PyObject * /*self*/)
|
||||
{
|
||||
return PyLong_FromLong(ContextFunctions::GetTimeStampCF());
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ContextFunctions_get_canvas_width___doc__,
|
||||
".. function:: get_canvas_width()\n"
|
||||
"\n"
|
||||
" Returns the canvas width.\n"
|
||||
"\n"
|
||||
" :return: The canvas width.\n"
|
||||
" :rtype: int\n");
|
||||
static PyObject *ContextFunctions_get_canvas_width(PyObject * /*self*/)
|
||||
{
|
||||
return PyLong_FromLong(ContextFunctions::GetCanvasWidthCF());
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ContextFunctions_get_canvas_height___doc__,
|
||||
".. function:: get_canvas_height()\n"
|
||||
"\n"
|
||||
" Returns the canvas height.\n"
|
||||
"\n"
|
||||
" :return: The canvas height.\n"
|
||||
" :rtype: int\n");
|
||||
static PyObject *ContextFunctions_get_canvas_height(PyObject * /*self*/)
|
||||
{
|
||||
return PyLong_FromLong(ContextFunctions::GetCanvasHeightCF());
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ContextFunctions_get_border___doc__,
|
||||
".. function:: get_border()\n"
|
||||
"\n"
|
||||
" Returns the border.\n"
|
||||
"\n"
|
||||
" :return: A tuple of 4 numbers (xmin, ymin, xmax, ymax).\n"
|
||||
" :rtype: tuple[int, int, int, int]\n");
|
||||
static PyObject *ContextFunctions_get_border(PyObject * /*self*/)
|
||||
{
|
||||
BBox<Vec2i> border(ContextFunctions::GetBorderCF());
|
||||
PyObject *v = PyTuple_New(4);
|
||||
PyTuple_SET_ITEMS(v,
|
||||
PyLong_FromLong(border.getMin().x()),
|
||||
PyLong_FromLong(border.getMin().y()),
|
||||
PyLong_FromLong(border.getMax().x()),
|
||||
PyLong_FromLong(border.getMax().y()));
|
||||
return v;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ContextFunctions_load_map___doc__,
|
||||
".. function:: load_map(file_name, map_name, num_levels=4, sigma=1.0)\n"
|
||||
"\n"
|
||||
" Loads an image map for further reading.\n"
|
||||
"\n"
|
||||
" :param file_name: The name of the image file.\n"
|
||||
" :type file_name: str\n"
|
||||
" :param map_name: The name that will be used to access this image.\n"
|
||||
" :type map_name: str\n"
|
||||
" :param num_levels: The number of levels in the map pyramid\n"
|
||||
" (default = 4). If num_levels == 0, the complete pyramid is\n"
|
||||
" built.\n"
|
||||
" :type num_levels: int\n"
|
||||
" :param sigma: The sigma value of the gaussian function.\n"
|
||||
" :type sigma: float\n");
|
||||
static PyObject *ContextFunctions_load_map(PyObject * /*self*/, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"file_name", "map_name", "num_levels", "sigma", nullptr};
|
||||
char *fileName, *mapName;
|
||||
uint nbLevels = 4;
|
||||
float sigma = 1.0;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "ss|If", (char **)kwlist, &fileName, &mapName, &nbLevels, &sigma))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
ContextFunctions::LoadMapCF(fileName, mapName, nbLevels, sigma);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ContextFunctions_read_map_pixel___doc__,
|
||||
".. function:: read_map_pixel(map_name, level, x, y)\n"
|
||||
"\n"
|
||||
" Reads a pixel in a user-defined map.\n"
|
||||
"\n"
|
||||
" :param map_name: The name of the map.\n"
|
||||
" :type map_name: str\n"
|
||||
" :param level: The level of the pyramid in which we wish to read the\n"
|
||||
" pixel.\n"
|
||||
" :type level: int\n"
|
||||
" :param 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"
|
||||
" :param 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_read_map_pixel(PyObject * /*self*/,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"map_name", "level", "x", "y", nullptr};
|
||||
char *mapName;
|
||||
int level;
|
||||
uint x, y;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "siII", (char **)kwlist, &mapName, &level, &x, &y))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return PyFloat_FromDouble(ContextFunctions::ReadMapPixelCF(mapName, level, x, y));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ContextFunctions_read_complete_view_map_pixel___doc__,
|
||||
".. function:: read_complete_view_map_pixel(level, x, y)\n"
|
||||
"\n"
|
||||
" Reads a pixel in the complete view map.\n"
|
||||
"\n"
|
||||
" :param level: The level of the pyramid in which we wish to read the\n"
|
||||
" pixel.\n"
|
||||
" :type level: int\n"
|
||||
" :param 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"
|
||||
" :param 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_read_complete_view_map_pixel(PyObject * /*self*/,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"level", "x", "y", nullptr};
|
||||
int level;
|
||||
uint x, y;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "iII", (char **)kwlist, &level, &x, &y)) {
|
||||
return nullptr;
|
||||
}
|
||||
return PyFloat_FromDouble(ContextFunctions::ReadCompleteViewMapPixelCF(level, x, y));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ContextFunctions_read_directional_view_map_pixel___doc__,
|
||||
".. function:: read_directional_view_map_pixel(orientation, level, x, y)\n"
|
||||
"\n"
|
||||
" Reads a pixel in one of the oriented view map images.\n"
|
||||
"\n"
|
||||
" :param orientation: The number telling which orientation we want to\n"
|
||||
" check.\n"
|
||||
" :type orientation: int\n"
|
||||
" :param level: The level of the pyramid in which we wish to read the\n"
|
||||
" pixel.\n"
|
||||
" :type level: int\n"
|
||||
" :param 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"
|
||||
" :param 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_read_directional_view_map_pixel(PyObject * /*self*/,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"orientation", "level", "x", "y", nullptr};
|
||||
int orientation, level;
|
||||
uint x, y;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "iiII", (char **)kwlist, &orientation, &level, &x, &y))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return PyFloat_FromDouble(
|
||||
ContextFunctions::ReadDirectionalViewMapPixelCF(orientation, level, x, y));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ContextFunctions_get_selected_fedge___doc__,
|
||||
".. function:: get_selected_fedge()\n"
|
||||
"\n"
|
||||
" Returns the selected FEdge.\n"
|
||||
"\n"
|
||||
" :return: The selected FEdge.\n"
|
||||
" :rtype: :class:`FEdge`\n");
|
||||
static PyObject *ContextFunctions_get_selected_fedge(PyObject * /*self*/)
|
||||
{
|
||||
FEdge *fe = ContextFunctions::GetSelectedFEdgeCF();
|
||||
if (fe) {
|
||||
return Any_BPy_FEdge_from_FEdge(*fe);
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/*-----------------------ContextFunctions module docstring-------------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
module_docstring,
|
||||
"The Blender Freestyle.ContextFunctions submodule\n"
|
||||
"\n");
|
||||
/*-----------------------ContextFunctions module functions definitions-------------------*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wcast-function-type"
|
||||
# else
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static PyMethodDef module_functions[] = {
|
||||
{"get_time_stamp",
|
||||
(PyCFunction)ContextFunctions_get_time_stamp,
|
||||
METH_NOARGS,
|
||||
ContextFunctions_get_time_stamp___doc__},
|
||||
{"get_canvas_width",
|
||||
(PyCFunction)ContextFunctions_get_canvas_width,
|
||||
METH_NOARGS,
|
||||
ContextFunctions_get_canvas_width___doc__},
|
||||
{"get_canvas_height",
|
||||
(PyCFunction)ContextFunctions_get_canvas_height,
|
||||
METH_NOARGS,
|
||||
ContextFunctions_get_canvas_height___doc__},
|
||||
{"get_border",
|
||||
(PyCFunction)ContextFunctions_get_border,
|
||||
METH_NOARGS,
|
||||
ContextFunctions_get_border___doc__},
|
||||
{"load_map",
|
||||
(PyCFunction)ContextFunctions_load_map,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
ContextFunctions_load_map___doc__},
|
||||
{"read_map_pixel",
|
||||
(PyCFunction)ContextFunctions_read_map_pixel,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
ContextFunctions_read_map_pixel___doc__},
|
||||
{"read_complete_view_map_pixel",
|
||||
(PyCFunction)ContextFunctions_read_complete_view_map_pixel,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
ContextFunctions_read_complete_view_map_pixel___doc__},
|
||||
{"read_directional_view_map_pixel",
|
||||
(PyCFunction)ContextFunctions_read_directional_view_map_pixel,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
ContextFunctions_read_directional_view_map_pixel___doc__},
|
||||
{"get_selected_fedge",
|
||||
(PyCFunction)ContextFunctions_get_selected_fedge,
|
||||
METH_NOARGS,
|
||||
ContextFunctions_get_selected_fedge___doc__},
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# else
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*-----------------------ContextFunctions module definition--------------------------------*/
|
||||
|
||||
static PyModuleDef module_definition = {
|
||||
/*m_base*/ PyModuleDef_HEAD_INIT,
|
||||
/*m_name*/ "Freestyle.ContextFunctions",
|
||||
/*m_doc*/ module_docstring,
|
||||
/*m_size*/ -1,
|
||||
/*m_methods*/ module_functions,
|
||||
/*m_slots*/ nullptr,
|
||||
/*m_traverse*/ nullptr,
|
||||
/*m_clear*/ nullptr,
|
||||
/*m_free*/ nullptr,
|
||||
};
|
||||
|
||||
//------------------- MODULE INITIALIZATION --------------------------------
|
||||
|
||||
int ContextFunctions_Init(PyObject *module)
|
||||
{
|
||||
PyObject *m;
|
||||
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
m = PyModule_Create(&module_definition);
|
||||
if (m == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "ContextFunctions", m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,17 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
/*---------------------------Python BPy_ContextFunctions visible prototypes-----------*/
|
||||
|
||||
int ContextFunctions_Init(PyObject *module);
|
||||
@@ -0,0 +1,825 @@
|
||||
/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#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 "BPy_Interface1D.h"
|
||||
#include "BPy_MediumType.h"
|
||||
#include "BPy_Nature.h"
|
||||
#include "BPy_SShape.h"
|
||||
#include "BPy_StrokeAttribute.h"
|
||||
#include "BPy_ViewShape.h"
|
||||
#include "Interface0D/BPy_CurvePoint.h"
|
||||
#include "Interface0D/BPy_SVertex.h"
|
||||
#include "Interface0D/BPy_ViewVertex.h"
|
||||
#include "Interface0D/CurvePoint/BPy_StrokeVertex.h"
|
||||
#include "Interface0D/ViewVertex/BPy_NonTVertex.h"
|
||||
#include "Interface0D/ViewVertex/BPy_TVertex.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 "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"
|
||||
|
||||
using namespace Freestyle;
|
||||
using namespace Freestyle::Geometry;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//==============================
|
||||
// C++ => Python
|
||||
//==============================
|
||||
|
||||
PyObject *PyBool_from_bool(bool b)
|
||||
{
|
||||
return PyBool_FromLong(b ? 1 : 0);
|
||||
}
|
||||
|
||||
PyObject *PyLong_subtype_new(PyTypeObject *ty, long value)
|
||||
{
|
||||
BLI_assert(ty->tp_basicsize == sizeof(PyLongObject));
|
||||
PyLongObject *result = PyObject_NewVar(PyLongObject, ty, 1);
|
||||
PyLongObject *value_py = (PyLongObject *)PyLong_FromLong(value);
|
||||
memcpy(&result->long_value, &value_py->long_value, sizeof(result->long_value));
|
||||
Py_DECREF(value_py);
|
||||
return (PyObject *)result;
|
||||
}
|
||||
|
||||
void PyLong_subtype_add_to_dict(PyObject *dict, PyTypeObject *ty, const char *attr, long value)
|
||||
{
|
||||
PyObject *result = PyLong_subtype_new(ty, value);
|
||||
PyDict_SetItemString(dict, attr, result);
|
||||
/* Owned by the dictionary. */
|
||||
Py_DECREF(result);
|
||||
}
|
||||
|
||||
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 blender::Vector_CreatePyObject(vec_data, 2, nullptr);
|
||||
}
|
||||
|
||||
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 blender::Vector_CreatePyObject(vec_data, 3, nullptr);
|
||||
}
|
||||
|
||||
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 blender::Vector_CreatePyObject(vec_data, 3, nullptr);
|
||||
}
|
||||
|
||||
PyObject *BPy_Id_from_Id(Id &id)
|
||||
{
|
||||
PyObject *py_id = Id_Type.tp_new(&Id_Type, nullptr, nullptr);
|
||||
((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));
|
||||
}
|
||||
if (typeid(if0D) == typeid(StrokeVertex)) {
|
||||
return BPy_StrokeVertex_from_StrokeVertex(dynamic_cast<StrokeVertex &>(if0D));
|
||||
}
|
||||
if (typeid(if0D) == typeid(SVertex)) {
|
||||
return BPy_SVertex_from_SVertex(dynamic_cast<SVertex &>(if0D));
|
||||
}
|
||||
if (typeid(if0D) == typeid(ViewVertex)) {
|
||||
return BPy_ViewVertex_from_ViewVertex(dynamic_cast<ViewVertex &>(if0D));
|
||||
}
|
||||
if (typeid(if0D) == typeid(NonTVertex)) {
|
||||
return BPy_NonTVertex_from_NonTVertex(dynamic_cast<NonTVertex &>(if0D));
|
||||
}
|
||||
if (typeid(if0D) == typeid(TVertex)) {
|
||||
return BPy_TVertex_from_TVertex(dynamic_cast<TVertex &>(if0D));
|
||||
}
|
||||
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 nullptr;
|
||||
}
|
||||
|
||||
PyObject *Any_BPy_Interface1D_from_Interface1D(Interface1D &if1D)
|
||||
{
|
||||
if (typeid(if1D) == typeid(ViewEdge)) {
|
||||
return BPy_ViewEdge_from_ViewEdge(dynamic_cast<ViewEdge &>(if1D));
|
||||
}
|
||||
if (typeid(if1D) == typeid(Chain)) {
|
||||
return BPy_Chain_from_Chain(dynamic_cast<Chain &>(if1D));
|
||||
}
|
||||
if (typeid(if1D) == typeid(Stroke)) {
|
||||
return BPy_Stroke_from_Stroke(dynamic_cast<Stroke &>(if1D));
|
||||
}
|
||||
if (typeid(if1D) == typeid(FEdgeSharp)) {
|
||||
return BPy_FEdgeSharp_from_FEdgeSharp(dynamic_cast<FEdgeSharp &>(if1D));
|
||||
}
|
||||
if (typeid(if1D) == typeid(FEdgeSmooth)) {
|
||||
return BPy_FEdgeSmooth_from_FEdgeSmooth(dynamic_cast<FEdgeSmooth &>(if1D));
|
||||
}
|
||||
if (typeid(if1D) == typeid(FEdge)) {
|
||||
return BPy_FEdge_from_FEdge(dynamic_cast<FEdge &>(if1D));
|
||||
}
|
||||
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 nullptr;
|
||||
}
|
||||
|
||||
PyObject *Any_BPy_FEdge_from_FEdge(FEdge &fe)
|
||||
{
|
||||
if (typeid(fe) == typeid(FEdgeSharp)) {
|
||||
return BPy_FEdgeSharp_from_FEdgeSharp(dynamic_cast<FEdgeSharp &>(fe));
|
||||
}
|
||||
if (typeid(fe) == typeid(FEdgeSmooth)) {
|
||||
return BPy_FEdgeSmooth_from_FEdgeSmooth(dynamic_cast<FEdgeSmooth &>(fe));
|
||||
}
|
||||
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 nullptr;
|
||||
}
|
||||
|
||||
PyObject *Any_BPy_ViewVertex_from_ViewVertex(ViewVertex &vv)
|
||||
{
|
||||
if (typeid(vv) == typeid(NonTVertex)) {
|
||||
return BPy_NonTVertex_from_NonTVertex(dynamic_cast<NonTVertex &>(vv));
|
||||
}
|
||||
if (typeid(vv) == typeid(TVertex)) {
|
||||
return BPy_TVertex_from_TVertex(dynamic_cast<TVertex &>(vv));
|
||||
}
|
||||
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 nullptr;
|
||||
}
|
||||
|
||||
PyObject *BPy_Interface0D_from_Interface0D(Interface0D &if0D)
|
||||
{
|
||||
PyObject *py_if0D = Interface0D_Type.tp_new(&Interface0D_Type, nullptr, nullptr);
|
||||
((BPy_Interface0D *)py_if0D)->if0D = &if0D;
|
||||
((BPy_Interface0D *)py_if0D)->borrowed = true;
|
||||
return py_if0D;
|
||||
}
|
||||
|
||||
PyObject *BPy_Interface1D_from_Interface1D(Interface1D &if1D)
|
||||
{
|
||||
PyObject *py_if1D = Interface1D_Type.tp_new(&Interface1D_Type, nullptr, nullptr);
|
||||
((BPy_Interface1D *)py_if1D)->if1D = &if1D;
|
||||
((BPy_Interface1D *)py_if1D)->borrowed = true;
|
||||
return py_if1D;
|
||||
}
|
||||
|
||||
PyObject *BPy_SVertex_from_SVertex(SVertex &sv)
|
||||
{
|
||||
PyObject *py_sv = SVertex_Type.tp_new(&SVertex_Type, nullptr, nullptr);
|
||||
((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 = true;
|
||||
return py_sv;
|
||||
}
|
||||
|
||||
PyObject *BPy_FEdgeSharp_from_FEdgeSharp(FEdgeSharp &fes)
|
||||
{
|
||||
PyObject *py_fe = FEdgeSharp_Type.tp_new(&FEdgeSharp_Type, nullptr, nullptr);
|
||||
((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 = true;
|
||||
return py_fe;
|
||||
}
|
||||
|
||||
PyObject *BPy_FEdgeSmooth_from_FEdgeSmooth(FEdgeSmooth &fes)
|
||||
{
|
||||
PyObject *py_fe = FEdgeSmooth_Type.tp_new(&FEdgeSmooth_Type, nullptr, nullptr);
|
||||
((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 = true;
|
||||
return py_fe;
|
||||
}
|
||||
|
||||
PyObject *BPy_FEdge_from_FEdge(FEdge &fe)
|
||||
{
|
||||
PyObject *py_fe = FEdge_Type.tp_new(&FEdge_Type, nullptr, nullptr);
|
||||
((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 = true;
|
||||
return py_fe;
|
||||
}
|
||||
|
||||
PyObject *BPy_Nature_from_Nature(ushort n)
|
||||
{
|
||||
PyObject *args = PyTuple_New(1);
|
||||
PyTuple_SET_ITEM(args, 0, PyLong_FromLong(n));
|
||||
PyObject *py_n = Nature_Type.tp_new(&Nature_Type, args, nullptr);
|
||||
Py_DECREF(args);
|
||||
return py_n;
|
||||
}
|
||||
|
||||
PyObject *BPy_Stroke_from_Stroke(Stroke &s)
|
||||
{
|
||||
PyObject *py_s = Stroke_Type.tp_new(&Stroke_Type, nullptr, nullptr);
|
||||
((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 = true;
|
||||
return py_s;
|
||||
}
|
||||
|
||||
PyObject *BPy_StrokeAttribute_from_StrokeAttribute(StrokeAttribute &sa)
|
||||
{
|
||||
PyObject *py_sa = StrokeAttribute_Type.tp_new(&StrokeAttribute_Type, nullptr, nullptr);
|
||||
((BPy_StrokeAttribute *)py_sa)->sa = &sa;
|
||||
((BPy_StrokeAttribute *)py_sa)->borrowed = true;
|
||||
return py_sa;
|
||||
}
|
||||
|
||||
PyObject *BPy_MediumType_from_MediumType(Stroke::MediumType n)
|
||||
{
|
||||
PyObject *args = PyTuple_New(1);
|
||||
PyTuple_SET_ITEM(args, 0, PyLong_FromLong(n));
|
||||
PyObject *py_mt = MediumType_Type.tp_new(&MediumType_Type, args, nullptr);
|
||||
Py_DECREF(args);
|
||||
return py_mt;
|
||||
}
|
||||
|
||||
PyObject *BPy_StrokeVertex_from_StrokeVertex(StrokeVertex &sv)
|
||||
{
|
||||
PyObject *py_sv = StrokeVertex_Type.tp_new(&StrokeVertex_Type, nullptr, nullptr);
|
||||
((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 = true;
|
||||
return py_sv;
|
||||
}
|
||||
|
||||
PyObject *BPy_ViewVertex_from_ViewVertex(ViewVertex &vv)
|
||||
{
|
||||
PyObject *py_vv = ViewVertex_Type.tp_new(&ViewVertex_Type, nullptr, nullptr);
|
||||
((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 = true;
|
||||
return py_vv;
|
||||
}
|
||||
|
||||
PyObject *BPy_NonTVertex_from_NonTVertex(NonTVertex &ntv)
|
||||
{
|
||||
PyObject *py_ntv = NonTVertex_Type.tp_new(&NonTVertex_Type, nullptr, nullptr);
|
||||
((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 = true;
|
||||
return py_ntv;
|
||||
}
|
||||
|
||||
PyObject *BPy_TVertex_from_TVertex(TVertex &tv)
|
||||
{
|
||||
PyObject *py_tv = TVertex_Type.tp_new(&TVertex_Type, nullptr, nullptr);
|
||||
((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 = true;
|
||||
return py_tv;
|
||||
}
|
||||
|
||||
PyObject *BPy_BBox_from_BBox(const BBox<Vec3r> &bb)
|
||||
{
|
||||
PyObject *py_bb = BBox_Type.tp_new(&BBox_Type, nullptr, nullptr);
|
||||
((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, nullptr, nullptr);
|
||||
((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 = true;
|
||||
return py_ve;
|
||||
}
|
||||
|
||||
PyObject *BPy_Chain_from_Chain(Chain &c)
|
||||
{
|
||||
PyObject *py_c = Chain_Type.tp_new(&Chain_Type, nullptr, nullptr);
|
||||
((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 = true;
|
||||
return py_c;
|
||||
}
|
||||
|
||||
PyObject *BPy_SShape_from_SShape(SShape &ss)
|
||||
{
|
||||
PyObject *py_ss = SShape_Type.tp_new(&SShape_Type, nullptr, nullptr);
|
||||
((BPy_SShape *)py_ss)->ss = &ss;
|
||||
((BPy_SShape *)py_ss)->borrowed = true;
|
||||
return py_ss;
|
||||
}
|
||||
|
||||
PyObject *BPy_ViewShape_from_ViewShape(ViewShape &vs)
|
||||
{
|
||||
PyObject *py_vs = ViewShape_Type.tp_new(&ViewShape_Type, nullptr, nullptr);
|
||||
((BPy_ViewShape *)py_vs)->vs = &vs;
|
||||
((BPy_ViewShape *)py_vs)->borrowed = true;
|
||||
((BPy_ViewShape *)py_vs)->py_ss = nullptr;
|
||||
return py_vs;
|
||||
}
|
||||
|
||||
PyObject *BPy_FrsMaterial_from_FrsMaterial(const FrsMaterial &m)
|
||||
{
|
||||
PyObject *py_m = FrsMaterial_Type.tp_new(&FrsMaterial_Type, nullptr, nullptr);
|
||||
((BPy_FrsMaterial *)py_m)->m = new FrsMaterial(m);
|
||||
return py_m;
|
||||
}
|
||||
|
||||
PyObject *BPy_IntegrationType_from_IntegrationType(IntegrationType i)
|
||||
{
|
||||
PyObject *args = PyTuple_New(1);
|
||||
PyTuple_SET_ITEM(args, 0, PyLong_FromLong(i));
|
||||
PyObject *py_it = IntegrationType_Type.tp_new(&IntegrationType_Type, args, nullptr);
|
||||
Py_DECREF(args);
|
||||
return py_it;
|
||||
}
|
||||
|
||||
PyObject *BPy_CurvePoint_from_CurvePoint(CurvePoint &cp)
|
||||
{
|
||||
PyObject *py_cp = CurvePoint_Type.tp_new(&CurvePoint_Type, nullptr, nullptr);
|
||||
// CurvePointIterator::operator*() returns a reference of a class data
|
||||
// member whose value is mutable upon iteration over different CurvePoints.
|
||||
// It is likely that such a mutable reference is passed to this function,
|
||||
// so that a new allocated CurvePoint instance is created here to avoid
|
||||
// nasty bugs (cf. #41464).
|
||||
((BPy_CurvePoint *)py_cp)->cp = new CurvePoint(cp);
|
||||
((BPy_CurvePoint *)py_cp)->py_if0D.if0D = ((BPy_CurvePoint *)py_cp)->cp;
|
||||
((BPy_CurvePoint *)py_cp)->py_if0D.borrowed = false;
|
||||
return py_cp;
|
||||
}
|
||||
|
||||
PyObject *BPy_directedViewEdge_from_directedViewEdge(ViewVertex::directedViewEdge &dve)
|
||||
{
|
||||
PyObject *py_dve = PyTuple_New(2);
|
||||
PyTuple_SET_ITEMS(
|
||||
py_dve, BPy_ViewEdge_from_ViewEdge(*(dve.first)), 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, nullptr, nullptr);
|
||||
((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;
|
||||
((BPy_AdjacencyIterator *)py_a_it)->at_start = true;
|
||||
return py_a_it;
|
||||
}
|
||||
|
||||
PyObject *BPy_Interface0DIterator_from_Interface0DIterator(Interface0DIterator &if0D_it,
|
||||
bool reversed)
|
||||
{
|
||||
PyObject *py_if0D_it = Interface0DIterator_Type.tp_new(
|
||||
&Interface0DIterator_Type, nullptr, nullptr);
|
||||
((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)->at_start = true;
|
||||
((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, nullptr, nullptr);
|
||||
((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, bool reversed)
|
||||
{
|
||||
PyObject *py_sv_it = StrokeVertexIterator_Type.tp_new(
|
||||
&StrokeVertexIterator_Type, nullptr, nullptr);
|
||||
((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)->at_start = true;
|
||||
((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, nullptr, nullptr);
|
||||
((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, bool reversed)
|
||||
{
|
||||
PyObject *py_ove_it = orientedViewEdgeIterator_Type.tp_new(
|
||||
&orientedViewEdgeIterator_Type, nullptr, nullptr);
|
||||
((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)->at_start = true;
|
||||
((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, nullptr, nullptr);
|
||||
((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, nullptr, nullptr);
|
||||
((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, nullptr, nullptr);
|
||||
((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, nullptr, nullptr);
|
||||
((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));
|
||||
}
|
||||
|
||||
bool Vec2f_ptr_from_PyObject(PyObject *obj, Vec2f &vec)
|
||||
{
|
||||
if (Vec2f_ptr_from_Vector(obj, vec)) {
|
||||
return true;
|
||||
}
|
||||
if (Vec2f_ptr_from_PyList(obj, vec)) {
|
||||
return true;
|
||||
}
|
||||
if (Vec2f_ptr_from_PyTuple(obj, vec)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Vec3f_ptr_from_PyObject(PyObject *obj, Vec3f &vec)
|
||||
{
|
||||
if (Vec3f_ptr_from_Vector(obj, vec)) {
|
||||
return true;
|
||||
}
|
||||
if (Vec3f_ptr_from_Color(obj, vec)) {
|
||||
return true;
|
||||
}
|
||||
if (Vec3f_ptr_from_PyList(obj, vec)) {
|
||||
return true;
|
||||
}
|
||||
if (Vec3f_ptr_from_PyTuple(obj, vec)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Vec3r_ptr_from_PyObject(PyObject *obj, Vec3r &vec)
|
||||
{
|
||||
if (Vec3r_ptr_from_Vector(obj, vec)) {
|
||||
return true;
|
||||
}
|
||||
if (Vec3r_ptr_from_Color(obj, vec)) {
|
||||
return true;
|
||||
}
|
||||
if (Vec3r_ptr_from_PyList(obj, vec)) {
|
||||
return true;
|
||||
}
|
||||
if (Vec3r_ptr_from_PyTuple(obj, vec)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Vec2f_ptr_from_Vector(PyObject *obj, Vec2f &vec)
|
||||
{
|
||||
using namespace blender;
|
||||
if (!VectorObject_Check(obj) || ((VectorObject *)obj)->vec_num != 2) {
|
||||
return false;
|
||||
}
|
||||
if (BaseMath_ReadCallback((blender::BaseMathObject *)obj) == -1) {
|
||||
return false;
|
||||
}
|
||||
vec[0] = ((VectorObject *)obj)->vec[0];
|
||||
vec[1] = ((VectorObject *)obj)->vec[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Vec3f_ptr_from_Vector(PyObject *obj, Vec3f &vec)
|
||||
{
|
||||
using namespace blender;
|
||||
if (!VectorObject_Check(obj) || ((VectorObject *)obj)->vec_num != 3) {
|
||||
return false;
|
||||
}
|
||||
if (BaseMath_ReadCallback((blender::BaseMathObject *)obj) == -1) {
|
||||
return false;
|
||||
}
|
||||
vec[0] = ((VectorObject *)obj)->vec[0];
|
||||
vec[1] = ((VectorObject *)obj)->vec[1];
|
||||
vec[2] = ((VectorObject *)obj)->vec[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Vec3r_ptr_from_Vector(PyObject *obj, Vec3r &vec)
|
||||
{
|
||||
using namespace blender;
|
||||
if (!VectorObject_Check(obj) || ((VectorObject *)obj)->vec_num != 3) {
|
||||
return false;
|
||||
}
|
||||
if (BaseMath_ReadCallback((blender::BaseMathObject *)obj) == -1) {
|
||||
return false;
|
||||
}
|
||||
vec[0] = ((VectorObject *)obj)->vec[0];
|
||||
vec[1] = ((VectorObject *)obj)->vec[1];
|
||||
vec[2] = ((VectorObject *)obj)->vec[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Vec3f_ptr_from_Color(PyObject *obj, Vec3f &vec)
|
||||
{
|
||||
using namespace blender;
|
||||
if (!ColorObject_Check(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (BaseMath_ReadCallback((blender::BaseMathObject *)obj) == -1) {
|
||||
return false;
|
||||
}
|
||||
vec[0] = ((ColorObject *)obj)->col[0];
|
||||
vec[1] = ((ColorObject *)obj)->col[1];
|
||||
vec[2] = ((ColorObject *)obj)->col[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Vec3r_ptr_from_Color(PyObject *obj, Vec3r &vec)
|
||||
{
|
||||
using namespace blender;
|
||||
if (!ColorObject_Check(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (BaseMath_ReadCallback((blender::BaseMathObject *)obj) == -1) {
|
||||
return false;
|
||||
}
|
||||
vec[0] = ((ColorObject *)obj)->col[0];
|
||||
vec[1] = ((ColorObject *)obj)->col[1];
|
||||
vec[2] = ((ColorObject *)obj)->col[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool float_array_from_PyList(PyObject *obj, float *v, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
v[i] = PyFloat_AsDouble(PyList_GET_ITEM(obj, i));
|
||||
if (v[i] == -1.0f && PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_TypeError, "list elements must be a number");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Vec2f_ptr_from_PyList(PyObject *obj, Vec2f &vec)
|
||||
{
|
||||
float v[2];
|
||||
|
||||
if (!PyList_Check(obj) || PyList_GET_SIZE(obj) != 2) {
|
||||
return false;
|
||||
}
|
||||
if (!float_array_from_PyList(obj, v, 2)) {
|
||||
return false;
|
||||
}
|
||||
vec[0] = v[0];
|
||||
vec[1] = v[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Vec3f_ptr_from_PyList(PyObject *obj, Vec3f &vec)
|
||||
{
|
||||
float v[3];
|
||||
|
||||
if (!PyList_Check(obj) || PyList_GET_SIZE(obj) != 3) {
|
||||
return false;
|
||||
}
|
||||
if (!float_array_from_PyList(obj, v, 3)) {
|
||||
return false;
|
||||
}
|
||||
vec[0] = v[0];
|
||||
vec[1] = v[1];
|
||||
vec[2] = v[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Vec3r_ptr_from_PyList(PyObject *obj, Vec3r &vec)
|
||||
{
|
||||
float v[3];
|
||||
|
||||
if (!PyList_Check(obj) || PyList_GET_SIZE(obj) != 3) {
|
||||
return false;
|
||||
}
|
||||
if (!float_array_from_PyList(obj, v, 3)) {
|
||||
return false;
|
||||
}
|
||||
vec[0] = v[0];
|
||||
vec[1] = v[1];
|
||||
vec[2] = v[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool float_array_from_PyTuple(PyObject *obj, float *v, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
v[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(obj, i));
|
||||
if (v[i] == -1.0f && PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_TypeError, "tuple elements must be a number");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Vec2f_ptr_from_PyTuple(PyObject *obj, Vec2f &vec)
|
||||
{
|
||||
float v[2];
|
||||
|
||||
if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 2) {
|
||||
return false;
|
||||
}
|
||||
if (!float_array_from_PyTuple(obj, v, 2)) {
|
||||
return false;
|
||||
}
|
||||
vec[0] = v[0];
|
||||
vec[1] = v[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Vec3f_ptr_from_PyTuple(PyObject *obj, Vec3f &vec)
|
||||
{
|
||||
float v[3];
|
||||
|
||||
if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 3) {
|
||||
return false;
|
||||
}
|
||||
if (!float_array_from_PyTuple(obj, v, 3)) {
|
||||
return false;
|
||||
}
|
||||
vec[0] = v[0];
|
||||
vec[1] = v[1];
|
||||
vec[2] = v[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Vec3r_ptr_from_PyTuple(PyObject *obj, Vec3r &vec)
|
||||
{
|
||||
float v[3];
|
||||
|
||||
if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 3) {
|
||||
return false;
|
||||
}
|
||||
if (!float_array_from_PyTuple(obj, v, 3)) {
|
||||
return false;
|
||||
}
|
||||
vec[0] = v[0];
|
||||
vec[1] = v[1];
|
||||
vec[2] = v[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
// helpers for argument parsing
|
||||
|
||||
bool float_array_from_PyObject(PyObject *obj, float *v, int n)
|
||||
{
|
||||
using namespace blender;
|
||||
if (VectorObject_Check(obj) && ((VectorObject *)obj)->vec_num == n) {
|
||||
if (BaseMath_ReadCallback((blender::BaseMathObject *)obj) == -1) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
v[i] = ((VectorObject *)obj)->vec[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (ColorObject_Check(obj) && n == 3) {
|
||||
if (BaseMath_ReadCallback((blender::BaseMathObject *)obj) == -1) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
v[i] = ((ColorObject *)obj)->col[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (PyList_Check(obj) && PyList_GET_SIZE(obj) == n) {
|
||||
return float_array_from_PyList(obj, v, n);
|
||||
}
|
||||
if (PyTuple_Check(obj) && PyTuple_GET_SIZE(obj) == n) {
|
||||
return float_array_from_PyTuple(obj, v, n);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int convert_v4(PyObject *obj, void *v)
|
||||
{
|
||||
return blender::mathutils_array_parse((float *)v, 4, 4, obj, "Error parsing 4D vector");
|
||||
}
|
||||
|
||||
int convert_v3(PyObject *obj, void *v)
|
||||
{
|
||||
return blender::mathutils_array_parse((float *)v, 3, 3, obj, "Error parsing 3D vector");
|
||||
}
|
||||
|
||||
int convert_v2(PyObject *obj, void *v)
|
||||
{
|
||||
return blender::mathutils_array_parse((float *)v, 2, 2, obj, "Error parsing 2D vector");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,163 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
#include "../geometry/Geom.h"
|
||||
|
||||
// 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"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "generic/python_utildefines.hh"
|
||||
#include "mathutils/mathutils.hh"
|
||||
|
||||
//==============================
|
||||
// C++ => Python
|
||||
//==============================
|
||||
|
||||
PyObject *PyLong_subtype_new(PyTypeObject *ty, long value);
|
||||
void PyLong_subtype_add_to_dict(PyObject *dict, PyTypeObject *ty, const char *attr, long value);
|
||||
|
||||
PyObject *PyBool_from_bool(bool b);
|
||||
PyObject *Vector_from_Vec2f(Freestyle::Geometry::Vec2f &v);
|
||||
PyObject *Vector_from_Vec3f(Freestyle::Geometry::Vec3f &v);
|
||||
PyObject *Vector_from_Vec3r(Freestyle::Geometry::Vec3r &v);
|
||||
|
||||
PyObject *Any_BPy_Interface0D_from_Interface0D(Freestyle::Interface0D &if0D);
|
||||
PyObject *Any_BPy_Interface1D_from_Interface1D(Freestyle::Interface1D &if1D);
|
||||
PyObject *Any_BPy_FEdge_from_FEdge(Freestyle::FEdge &fe);
|
||||
PyObject *Any_BPy_ViewVertex_from_ViewVertex(Freestyle::ViewVertex &vv);
|
||||
|
||||
PyObject *BPy_BBox_from_BBox(const Freestyle::BBox<Freestyle::Geometry::Vec3r> &bb);
|
||||
PyObject *BPy_CurvePoint_from_CurvePoint(Freestyle::CurvePoint &cp);
|
||||
PyObject *BPy_directedViewEdge_from_directedViewEdge(Freestyle::ViewVertex::directedViewEdge &dve);
|
||||
PyObject *BPy_FEdge_from_FEdge(Freestyle::FEdge &fe);
|
||||
PyObject *BPy_FEdgeSharp_from_FEdgeSharp(Freestyle::FEdgeSharp &fes);
|
||||
PyObject *BPy_FEdgeSmooth_from_FEdgeSmooth(Freestyle::FEdgeSmooth &fes);
|
||||
PyObject *BPy_Id_from_Id(Freestyle::Id &id);
|
||||
PyObject *BPy_Interface0D_from_Interface0D(Freestyle::Interface0D &if0D);
|
||||
PyObject *BPy_Interface1D_from_Interface1D(Freestyle::Interface1D &if1D);
|
||||
PyObject *BPy_IntegrationType_from_IntegrationType(Freestyle::IntegrationType i);
|
||||
PyObject *BPy_FrsMaterial_from_FrsMaterial(const Freestyle::FrsMaterial &m);
|
||||
PyObject *BPy_Nature_from_Nature(ushort n);
|
||||
PyObject *BPy_MediumType_from_MediumType(Freestyle::Stroke::MediumType n);
|
||||
PyObject *BPy_SShape_from_SShape(Freestyle::SShape &ss);
|
||||
PyObject *BPy_Stroke_from_Stroke(Freestyle::Stroke &s);
|
||||
PyObject *BPy_StrokeAttribute_from_StrokeAttribute(Freestyle::StrokeAttribute &sa);
|
||||
PyObject *BPy_StrokeVertex_from_StrokeVertex(Freestyle::StrokeVertex &sv);
|
||||
PyObject *BPy_SVertex_from_SVertex(Freestyle::SVertex &sv);
|
||||
PyObject *BPy_ViewVertex_from_ViewVertex(Freestyle::ViewVertex &vv);
|
||||
PyObject *BPy_NonTVertex_from_NonTVertex(Freestyle::NonTVertex &ntv);
|
||||
PyObject *BPy_TVertex_from_TVertex(Freestyle::TVertex &tv);
|
||||
PyObject *BPy_ViewEdge_from_ViewEdge(Freestyle::ViewEdge &ve);
|
||||
PyObject *BPy_Chain_from_Chain(Freestyle::Chain &c);
|
||||
PyObject *BPy_ViewShape_from_ViewShape(Freestyle::ViewShape &vs);
|
||||
|
||||
PyObject *BPy_AdjacencyIterator_from_AdjacencyIterator(Freestyle::AdjacencyIterator &a_it);
|
||||
PyObject *BPy_Interface0DIterator_from_Interface0DIterator(Freestyle::Interface0DIterator &if0D_it,
|
||||
bool reversed);
|
||||
PyObject *BPy_CurvePointIterator_from_CurvePointIterator(
|
||||
Freestyle::CurveInternal::CurvePointIterator &cp_it);
|
||||
PyObject *BPy_StrokeVertexIterator_from_StrokeVertexIterator(
|
||||
Freestyle::StrokeInternal::StrokeVertexIterator &sv_it, bool reversed);
|
||||
PyObject *BPy_SVertexIterator_from_SVertexIterator(
|
||||
Freestyle::ViewEdgeInternal::SVertexIterator &sv_it);
|
||||
PyObject *BPy_orientedViewEdgeIterator_from_orientedViewEdgeIterator(
|
||||
Freestyle::ViewVertexInternal::orientedViewEdgeIterator &ove_it, bool reversed);
|
||||
PyObject *BPy_ViewEdgeIterator_from_ViewEdgeIterator(
|
||||
Freestyle::ViewEdgeInternal::ViewEdgeIterator &ve_it);
|
||||
PyObject *BPy_ChainingIterator_from_ChainingIterator(Freestyle::ChainingIterator &c_it);
|
||||
PyObject *BPy_ChainPredicateIterator_from_ChainPredicateIterator(
|
||||
Freestyle::ChainPredicateIterator &cp_it);
|
||||
PyObject *BPy_ChainSilhouetteIterator_from_ChainSilhouetteIterator(
|
||||
Freestyle::ChainSilhouetteIterator &cs_it);
|
||||
|
||||
//==============================
|
||||
// Python => C++
|
||||
//==============================
|
||||
|
||||
bool bool_from_PyBool(PyObject *b);
|
||||
Freestyle::IntegrationType IntegrationType_from_BPy_IntegrationType(PyObject *obj);
|
||||
Freestyle::Stroke::MediumType MediumType_from_BPy_MediumType(PyObject *obj);
|
||||
Freestyle::Nature::EdgeNature EdgeNature_from_BPy_Nature(PyObject *obj);
|
||||
bool Vec2f_ptr_from_PyObject(PyObject *obj, Freestyle::Geometry::Vec2f &vec);
|
||||
bool Vec3f_ptr_from_PyObject(PyObject *obj, Freestyle::Geometry::Vec3f &vec);
|
||||
bool Vec3r_ptr_from_PyObject(PyObject *obj, Freestyle::Geometry::Vec3r &vec);
|
||||
bool Vec2f_ptr_from_Vector(PyObject *obj, Freestyle::Geometry::Vec2f &vec);
|
||||
bool Vec3f_ptr_from_Vector(PyObject *obj, Freestyle::Geometry::Vec3f &vec);
|
||||
bool Vec3r_ptr_from_Vector(PyObject *obj, Freestyle::Geometry::Vec3r &vec);
|
||||
bool Vec3f_ptr_from_Color(PyObject *obj, Freestyle::Geometry::Vec3f &vec);
|
||||
bool Vec3r_ptr_from_Color(PyObject *obj, Freestyle::Geometry::Vec3r &vec);
|
||||
bool Vec2f_ptr_from_PyList(PyObject *obj, Freestyle::Geometry::Vec2f &vec);
|
||||
bool Vec3f_ptr_from_PyList(PyObject *obj, Freestyle::Geometry::Vec3f &vec);
|
||||
bool Vec3r_ptr_from_PyList(PyObject *obj, Freestyle::Geometry::Vec3r &vec);
|
||||
bool Vec2f_ptr_from_PyTuple(PyObject *obj, Freestyle::Geometry::Vec2f &vec);
|
||||
bool Vec3f_ptr_from_PyTuple(PyObject *obj, Freestyle::Geometry::Vec3f &vec);
|
||||
bool Vec3r_ptr_from_PyTuple(PyObject *obj, Freestyle::Geometry::Vec3r &vec);
|
||||
|
||||
bool float_array_from_PyObject(PyObject *obj, float *v, int n);
|
||||
|
||||
int convert_v4(PyObject *obj, void *v);
|
||||
int convert_v3(PyObject *obj, void *v);
|
||||
int convert_v2(PyObject *obj, void *v);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,612 @@
|
||||
/* SPDX-FileCopyrightText: 2008-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#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"
|
||||
|
||||
#include "BKE_appdir.hh"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "FRS_freestyle.h"
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_prototypes.hh"
|
||||
#include "bpy_rna.hh" /* pyrna_struct_CreatePyObject() */
|
||||
|
||||
#include "../generic/py_capi_utils.hh" /* #PyC_UnicodeFromBytes */
|
||||
|
||||
#include "BKE_colorband.hh" /* BKE_colorband_evaluate() */
|
||||
#include "BKE_colortools.hh" /* BKE_curvemapping_evaluateF() */
|
||||
#include "BKE_material.hh" /* ramp_blend() */
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//------------------------ MODULE FUNCTIONS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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*/)
|
||||
{
|
||||
blender::Scene *scene = blender::g_freestyle.scene;
|
||||
if (!scene) {
|
||||
PyErr_SetString(PyExc_TypeError, "current scene not available");
|
||||
return nullptr;
|
||||
}
|
||||
blender::PointerRNA ptr_scene = RNA_pointer_create_discrete(
|
||||
&scene->id, blender::RNA_Scene, scene);
|
||||
return pyrna_struct_CreatePyObject(&ptr_scene);
|
||||
}
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
|
||||
static int ramp_blend_type(const char *type)
|
||||
{
|
||||
if (STREQ(type, "MIX")) {
|
||||
return blender::MA_RAMP_BLEND;
|
||||
}
|
||||
if (STREQ(type, "ADD")) {
|
||||
return blender::MA_RAMP_ADD;
|
||||
}
|
||||
if (STREQ(type, "MULTIPLY")) {
|
||||
return blender::MA_RAMP_MULT;
|
||||
}
|
||||
if (STREQ(type, "SUBTRACT")) {
|
||||
return blender::MA_RAMP_SUB;
|
||||
}
|
||||
if (STREQ(type, "SCREEN")) {
|
||||
return blender::MA_RAMP_SCREEN;
|
||||
}
|
||||
if (STREQ(type, "DIVIDE")) {
|
||||
return blender::MA_RAMP_DIV;
|
||||
}
|
||||
if (STREQ(type, "DIFFERENCE")) {
|
||||
return blender::MA_RAMP_DIFF;
|
||||
}
|
||||
if (STREQ(type, "EXCLUSION")) {
|
||||
return blender::MA_RAMP_EXCLUSION;
|
||||
}
|
||||
if (STREQ(type, "DARKEN")) {
|
||||
return blender::MA_RAMP_DARK;
|
||||
}
|
||||
if (STREQ(type, "LIGHTEN")) {
|
||||
return blender::MA_RAMP_LIGHT;
|
||||
}
|
||||
if (STREQ(type, "OVERLAY")) {
|
||||
return blender::MA_RAMP_OVERLAY;
|
||||
}
|
||||
if (STREQ(type, "DODGE")) {
|
||||
return blender::MA_RAMP_DODGE;
|
||||
}
|
||||
if (STREQ(type, "BURN")) {
|
||||
return blender::MA_RAMP_BURN;
|
||||
}
|
||||
if (STREQ(type, "HUE")) {
|
||||
return blender::MA_RAMP_HUE;
|
||||
}
|
||||
if (STREQ(type, "SATURATION")) {
|
||||
return blender::MA_RAMP_SAT;
|
||||
}
|
||||
if (STREQ(type, "VALUE")) {
|
||||
return blender::MA_RAMP_VAL;
|
||||
}
|
||||
if (STREQ(type, "COLOR")) {
|
||||
return blender::MA_RAMP_COLOR;
|
||||
}
|
||||
if (STREQ(type, "SOFT_LIGHT")) {
|
||||
return blender::MA_RAMP_SOFT;
|
||||
}
|
||||
if (STREQ(type, "LINEAR_LIGHT")) {
|
||||
return blender::MA_RAMP_LINEAR;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Freestyle_blendRamp___doc__,
|
||||
".. function:: blendRamp(type, color1, fac, color2)\n"
|
||||
"\n"
|
||||
" Blend two colors according to a ramp blend type.\n"
|
||||
"\n"
|
||||
" :param type: Ramp blend type.\n"
|
||||
" :type type: int\n"
|
||||
" :param color1: 1st color.\n"
|
||||
" :type color1: :class:`mathutils.Vector` | tuple[float, float, float] | list[float]\n"
|
||||
" :param fac: Blend factor.\n"
|
||||
" :type fac: float\n"
|
||||
" :param color2: 1st color.\n"
|
||||
" :type color2: :class:`mathutils.Vector` | tuple[float, float, float] | list[float]\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;
|
||||
float a[4], fac, b[4];
|
||||
|
||||
if (!PyArg_ParseTuple(args, "sOfO", &s, &obj1, &fac, &obj2)) {
|
||||
return nullptr;
|
||||
}
|
||||
type = ramp_blend_type(s);
|
||||
if (type < 0) {
|
||||
PyErr_SetString(PyExc_TypeError, "argument 1 is an unknown ramp blend type");
|
||||
return nullptr;
|
||||
}
|
||||
if (blender::mathutils_array_parse(a,
|
||||
3,
|
||||
3,
|
||||
obj1,
|
||||
"argument 2 must be a 3D vector "
|
||||
"(either a tuple/list of 3 elements or Vector)") == -1)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (blender::mathutils_array_parse(b,
|
||||
3,
|
||||
3,
|
||||
obj2,
|
||||
"argument 4 must be a 3D vector "
|
||||
"(either a tuple/list of 3 elements or Vector)") == -1)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
blender::ramp_blend(type, a, fac, b);
|
||||
return blender::Vector_CreatePyObject(a, 3, nullptr);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Freestyle_evaluateColorRamp___doc__,
|
||||
".. function:: evaluateColorRamp(ramp, in)\n"
|
||||
"\n"
|
||||
" Evaluate a color ramp at a point in the interval 0 to 1.\n"
|
||||
"\n"
|
||||
" :param ramp: Color ramp object.\n"
|
||||
" :type ramp: :class:`bpy.types.ColorRamp`\n"
|
||||
" :param 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)
|
||||
{
|
||||
blender::BPy_StructRNA *py_srna;
|
||||
blender::ColorBand *coba;
|
||||
float in, out[4];
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!f", &blender::pyrna_struct_Type, &py_srna, &in)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!RNA_struct_is_a(py_srna->ptr->type, blender::RNA_ColorRamp)) {
|
||||
PyErr_SetString(PyExc_TypeError, "1st argument is not a ColorRamp object");
|
||||
return nullptr;
|
||||
}
|
||||
coba = (blender::ColorBand *)py_srna->ptr->data;
|
||||
if (!BKE_colorband_evaluate(coba, in, out)) {
|
||||
PyErr_SetString(PyExc_ValueError, "failed to evaluate the color ramp");
|
||||
return nullptr;
|
||||
}
|
||||
return blender::Vector_CreatePyObject(out, 4, nullptr);
|
||||
}
|
||||
|
||||
#include "DNA_color_types.h"
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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"
|
||||
" :param cumap: Curve mapping object.\n"
|
||||
" :type cumap: :class:`bpy.types.CurveMapping`\n"
|
||||
" :param cur: Index of the curve to be used (0 <= cur <= 3).\n"
|
||||
" :type cur: int\n"
|
||||
" :param 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)
|
||||
{
|
||||
blender::BPy_StructRNA *py_srna;
|
||||
blender::CurveMapping *cumap;
|
||||
int cur;
|
||||
float value;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!if", &blender::pyrna_struct_Type, &py_srna, &cur, &value)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!RNA_struct_is_a(py_srna->ptr->type, blender::RNA_CurveMapping)) {
|
||||
PyErr_SetString(PyExc_TypeError, "1st argument is not a CurveMapping object");
|
||||
return nullptr;
|
||||
}
|
||||
if (cur < 0 || cur > 3) {
|
||||
PyErr_SetString(PyExc_ValueError, "2nd argument is out of range");
|
||||
return nullptr;
|
||||
}
|
||||
cumap = (blender::CurveMapping *)py_srna->ptr->data;
|
||||
BKE_curvemapping_init(cumap);
|
||||
/* disable extrapolation if enabled */
|
||||
if (cumap->flag & blender::CUMA_EXTEND_EXTRAPOLATE) {
|
||||
cumap->flag &= ~blender::CUMA_EXTEND_EXTRAPOLATE;
|
||||
BKE_curvemapping_changed(cumap, false);
|
||||
}
|
||||
return PyFloat_FromDouble(BKE_curvemapping_evaluateF(cumap, cur, value));
|
||||
}
|
||||
|
||||
/*-----------------------Freestyle module docstring----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Force wrapped line. */
|
||||
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:`BlenderTextureShader`\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:`StrokeTextureStepShader`\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"
|
||||
" - :class:`WithinImageBoundaryUP1D`\n"
|
||||
"\n"
|
||||
"- :class:`ViewMap`\n"
|
||||
"- :class:`ViewShape`\n"
|
||||
"- :class:`IntegrationType`\n"
|
||||
"- :class:`MediumType`\n"
|
||||
"- :class:`Nature`\n"
|
||||
"\n");
|
||||
|
||||
/*-----------------------Freestyle module method def---------------------------*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wcast-function-type"
|
||||
# else
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
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__},
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# else
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*-----------------------Freestyle module definition---------------------------*/
|
||||
|
||||
static PyModuleDef module_definition = {
|
||||
/*m_base*/ PyModuleDef_HEAD_INIT,
|
||||
/*m_name*/ "_freestyle",
|
||||
/*m_doc*/ module_docstring,
|
||||
/*m_size*/ -1,
|
||||
/*m_methods*/ module_functions,
|
||||
/*m_slots*/ nullptr,
|
||||
/*m_traverse*/ nullptr,
|
||||
/*m_clear*/ nullptr,
|
||||
/*m_free*/ nullptr,
|
||||
};
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
PyObject *Freestyle_Init()
|
||||
{
|
||||
PyObject *module;
|
||||
|
||||
// initialize modules
|
||||
module = PyModule_Create(&module_definition);
|
||||
if (!module) {
|
||||
return nullptr;
|
||||
}
|
||||
PyDict_SetItemString(PySys_GetObject("modules"), module_definition.m_name, module);
|
||||
|
||||
// update 'sys.path' for Freestyle Python API modules
|
||||
const std::optional<std::string> path = BKE_appdir_folder_id(blender::BLENDER_SYSTEM_SCRIPTS,
|
||||
"freestyle");
|
||||
if (path.has_value()) {
|
||||
char modpath[FILE_MAX];
|
||||
blender::BLI_path_join(modpath, sizeof(modpath), path->c_str(), "modules");
|
||||
PyObject *sys_path = PySys_GetObject("path"); /* borrow */
|
||||
PyObject *py_modpath = blender::PyC_UnicodeFromBytes(modpath);
|
||||
PyList_Append(sys_path, py_modpath);
|
||||
Py_DECREF(py_modpath);
|
||||
#if 0
|
||||
printf("Adding Python path: %s\n", modpath);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
printf(
|
||||
"Freestyle: couldn't find 'scripts/freestyle/modules', Freestyle won't work properly.\n");
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,19 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*---------------------------Python BPy_Freestyle visible prototypes-----------*/
|
||||
|
||||
PyObject *Freestyle_Init(void);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,594 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_FrsMaterial.h"
|
||||
|
||||
#include "BPy_Convert.h"
|
||||
|
||||
#include "BLI_hash_mm2a.hh"
|
||||
#include "BLI_math_vector.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int FrsMaterial_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&FrsMaterial_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "Material", (PyObject *)&FrsMaterial_Type);
|
||||
|
||||
FrsMaterial_mathutils_register_callback();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsMaterial_doc,
|
||||
"Class defining a material.\n"
|
||||
"\n"
|
||||
".. method:: __init__(*args)\n"
|
||||
"\n"
|
||||
" Accepted call signatures:\n"
|
||||
"\n"
|
||||
" - ``__init__()``\n"
|
||||
" - ``__init__(brother)``\n"
|
||||
" - ``__init__(line, diffuse, ambient, specular, emission, shininess, priority)``\n"
|
||||
"\n"
|
||||
" Creates a :class:`FrsMaterial` using either default constructor,\n"
|
||||
" copy constructor, or an overloaded constructor\n"
|
||||
"\n"
|
||||
" :param brother: A Material object to be used as a copy constructor.\n"
|
||||
" :type brother: :class:`Material`\n"
|
||||
" :param line: The line color.\n"
|
||||
" :type line: :class:`mathutils.Vector` | tuple[float, float, float, float] | list[float]\n"
|
||||
" :param diffuse: The diffuse color.\n"
|
||||
" :type diffuse: \n"
|
||||
" :param ambient: The ambient color.\n"
|
||||
" :type ambient: :class:`mathutils.Vector` | tuple[float, float, float, float] | "
|
||||
"list[float]\n"
|
||||
" :param specular: The specular color.\n"
|
||||
" :type specular: :class:`mathutils.Vector` | tuple[float, float, float, float] | "
|
||||
"list[float]\n"
|
||||
" :param emission: The emissive color.\n"
|
||||
" :type emission: :class:`mathutils.Vector` | tuple[float, float, float, float] | "
|
||||
"list[float]\n"
|
||||
" :param shininess: The shininess coefficient.\n"
|
||||
" :type shininess: float\n"
|
||||
" :param priority: The line color priority.\n"
|
||||
" :type priority: int\n");
|
||||
static int FrsMaterial_init(BPy_FrsMaterial *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist_1[] = {"brother", nullptr};
|
||||
static const char *kwlist_2[] = {
|
||||
"line", "diffuse", "ambient", "specular", "emission", "shininess", "priority", nullptr};
|
||||
PyObject *brother = nullptr;
|
||||
float line[4], diffuse[4], ambient[4], specular[4], emission[4], shininess;
|
||||
int priority;
|
||||
|
||||
if (PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "|O!", (char **)kwlist_1, &FrsMaterial_Type, &brother))
|
||||
{
|
||||
if (!brother) {
|
||||
self->m = new FrsMaterial();
|
||||
}
|
||||
else {
|
||||
FrsMaterial *m = ((BPy_FrsMaterial *)brother)->m;
|
||||
if (!m) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "invalid Material object");
|
||||
return -1;
|
||||
}
|
||||
self->m = new FrsMaterial(*m);
|
||||
}
|
||||
}
|
||||
else if ((void)PyErr_Clear(),
|
||||
PyArg_ParseTupleAndKeywords(args,
|
||||
kwds,
|
||||
"O&O&O&O&O&fi",
|
||||
(char **)kwlist_2,
|
||||
convert_v4,
|
||||
line,
|
||||
convert_v4,
|
||||
diffuse,
|
||||
convert_v4,
|
||||
ambient,
|
||||
convert_v4,
|
||||
specular,
|
||||
convert_v4,
|
||||
emission,
|
||||
&shininess,
|
||||
&priority))
|
||||
{
|
||||
self->m = new FrsMaterial(line, diffuse, ambient, specular, emission, shininess, priority);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void FrsMaterial_dealloc(BPy_FrsMaterial *self)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/*----------------------mathutils callbacks ----------------------------*/
|
||||
|
||||
/* subtype */
|
||||
#define MATHUTILS_SUBTYPE_DIFFUSE 1
|
||||
#define MATHUTILS_SUBTYPE_SPECULAR 2
|
||||
#define MATHUTILS_SUBTYPE_AMBIENT 3
|
||||
#define MATHUTILS_SUBTYPE_EMISSION 4
|
||||
#define MATHUTILS_SUBTYPE_LINE 5
|
||||
|
||||
static int FrsMaterial_mathutils_check(blender::BaseMathObject *bmo)
|
||||
{
|
||||
if (!BPy_FrsMaterial_Check(bmo->cb_user)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FrsMaterial_mathutils_get(blender::BaseMathObject *bmo, int subtype)
|
||||
{
|
||||
BPy_FrsMaterial *self = (BPy_FrsMaterial *)bmo->cb_user;
|
||||
switch (subtype) {
|
||||
case MATHUTILS_SUBTYPE_LINE:
|
||||
bmo->data[0] = self->m->lineR();
|
||||
bmo->data[1] = self->m->lineG();
|
||||
bmo->data[2] = self->m->lineB();
|
||||
bmo->data[3] = self->m->lineA();
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_DIFFUSE:
|
||||
bmo->data[0] = self->m->diffuseR();
|
||||
bmo->data[1] = self->m->diffuseG();
|
||||
bmo->data[2] = self->m->diffuseB();
|
||||
bmo->data[3] = self->m->diffuseA();
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_SPECULAR:
|
||||
bmo->data[0] = self->m->specularR();
|
||||
bmo->data[1] = self->m->specularG();
|
||||
bmo->data[2] = self->m->specularB();
|
||||
bmo->data[3] = self->m->specularA();
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_AMBIENT:
|
||||
bmo->data[0] = self->m->ambientR();
|
||||
bmo->data[1] = self->m->ambientG();
|
||||
bmo->data[2] = self->m->ambientB();
|
||||
bmo->data[3] = self->m->ambientA();
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_EMISSION:
|
||||
bmo->data[0] = self->m->emissionR();
|
||||
bmo->data[1] = self->m->emissionG();
|
||||
bmo->data[2] = self->m->emissionB();
|
||||
bmo->data[3] = self->m->emissionA();
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FrsMaterial_mathutils_set(blender::BaseMathObject *bmo, int subtype)
|
||||
{
|
||||
BPy_FrsMaterial *self = (BPy_FrsMaterial *)bmo->cb_user;
|
||||
switch (subtype) {
|
||||
case MATHUTILS_SUBTYPE_LINE:
|
||||
self->m->setLine(bmo->data[0], bmo->data[1], bmo->data[2], bmo->data[3]);
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_DIFFUSE:
|
||||
self->m->setDiffuse(bmo->data[0], bmo->data[1], bmo->data[2], bmo->data[3]);
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_SPECULAR:
|
||||
self->m->setSpecular(bmo->data[0], bmo->data[1], bmo->data[2], bmo->data[3]);
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_AMBIENT:
|
||||
self->m->setAmbient(bmo->data[0], bmo->data[1], bmo->data[2], bmo->data[3]);
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_EMISSION:
|
||||
self->m->setEmission(bmo->data[0], bmo->data[1], bmo->data[2], bmo->data[3]);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FrsMaterial_mathutils_get_index(blender::BaseMathObject *bmo, int subtype, int index)
|
||||
{
|
||||
BPy_FrsMaterial *self = (BPy_FrsMaterial *)bmo->cb_user;
|
||||
switch (subtype) {
|
||||
case MATHUTILS_SUBTYPE_LINE: {
|
||||
const float *color = self->m->line();
|
||||
bmo->data[index] = color[index];
|
||||
break;
|
||||
}
|
||||
case MATHUTILS_SUBTYPE_DIFFUSE: {
|
||||
const float *color = self->m->diffuse();
|
||||
bmo->data[index] = color[index];
|
||||
break;
|
||||
}
|
||||
case MATHUTILS_SUBTYPE_SPECULAR: {
|
||||
const float *color = self->m->specular();
|
||||
bmo->data[index] = color[index];
|
||||
break;
|
||||
}
|
||||
case MATHUTILS_SUBTYPE_AMBIENT: {
|
||||
const float *color = self->m->ambient();
|
||||
bmo->data[index] = color[index];
|
||||
break;
|
||||
}
|
||||
case MATHUTILS_SUBTYPE_EMISSION: {
|
||||
const float *color = self->m->emission();
|
||||
bmo->data[index] = color[index];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FrsMaterial_mathutils_set_index(blender::BaseMathObject *bmo, int subtype, int index)
|
||||
{
|
||||
BPy_FrsMaterial *self = (BPy_FrsMaterial *)bmo->cb_user;
|
||||
float color[4];
|
||||
switch (subtype) {
|
||||
case MATHUTILS_SUBTYPE_LINE:
|
||||
blender::copy_v4_v4(color, self->m->line());
|
||||
color[index] = bmo->data[index];
|
||||
self->m->setLine(color[0], color[1], color[2], color[3]);
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_DIFFUSE:
|
||||
blender::copy_v4_v4(color, self->m->diffuse());
|
||||
color[index] = bmo->data[index];
|
||||
self->m->setDiffuse(color[0], color[1], color[2], color[3]);
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_SPECULAR:
|
||||
blender::copy_v4_v4(color, self->m->specular());
|
||||
color[index] = bmo->data[index];
|
||||
self->m->setSpecular(color[0], color[1], color[2], color[3]);
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_AMBIENT:
|
||||
blender::copy_v4_v4(color, self->m->ambient());
|
||||
color[index] = bmo->data[index];
|
||||
self->m->setAmbient(color[0], color[1], color[2], color[3]);
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_EMISSION:
|
||||
blender::copy_v4_v4(color, self->m->emission());
|
||||
color[index] = bmo->data[index];
|
||||
self->m->setEmission(color[0], color[1], color[2], color[3]);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static blender::Mathutils_Callback FrsMaterial_mathutils_cb = {
|
||||
FrsMaterial_mathutils_check,
|
||||
FrsMaterial_mathutils_get,
|
||||
FrsMaterial_mathutils_set,
|
||||
FrsMaterial_mathutils_get_index,
|
||||
FrsMaterial_mathutils_set_index,
|
||||
};
|
||||
|
||||
static uchar FrsMaterial_mathutils_cb_index = -1;
|
||||
|
||||
void FrsMaterial_mathutils_register_callback()
|
||||
{
|
||||
FrsMaterial_mathutils_cb_index = Mathutils_RegisterCallback(&FrsMaterial_mathutils_cb);
|
||||
}
|
||||
|
||||
/*----------------------FrsMaterial get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsMaterial_line_doc,
|
||||
"RGBA components of the line color of the material.\n"
|
||||
"\n"
|
||||
":type: :class:`mathutils.Vector`\n");
|
||||
static PyObject *FrsMaterial_line_get(BPy_FrsMaterial *self, void * /*closure*/)
|
||||
{
|
||||
return blender::Vector_CreatePyObject_cb(
|
||||
(PyObject *)self, 4, FrsMaterial_mathutils_cb_index, MATHUTILS_SUBTYPE_LINE);
|
||||
}
|
||||
|
||||
static int FrsMaterial_line_set(BPy_FrsMaterial *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
float color[4];
|
||||
if (blender::mathutils_array_parse(color, 4, 4, value, "value must be a 4-dimensional vector") ==
|
||||
-1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
self->m->setLine(color[0], color[1], color[2], color[3]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsMaterial_diffuse_doc,
|
||||
"RGBA components of the diffuse color of the material.\n"
|
||||
"\n"
|
||||
":type: :class:`mathutils.Vector`\n");
|
||||
static PyObject *FrsMaterial_diffuse_get(BPy_FrsMaterial *self, void * /*closure*/)
|
||||
{
|
||||
return blender::Vector_CreatePyObject_cb(
|
||||
(PyObject *)self, 4, FrsMaterial_mathutils_cb_index, MATHUTILS_SUBTYPE_DIFFUSE);
|
||||
}
|
||||
|
||||
static int FrsMaterial_diffuse_set(BPy_FrsMaterial *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
float color[4];
|
||||
if (blender::mathutils_array_parse(color, 4, 4, value, "value must be a 4-dimensional vector") ==
|
||||
-1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
self->m->setDiffuse(color[0], color[1], color[2], color[3]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsMaterial_specular_doc,
|
||||
"RGBA components of the specular color of the material.\n"
|
||||
"\n"
|
||||
":type: :class:`mathutils.Vector`\n");
|
||||
static PyObject *FrsMaterial_specular_get(BPy_FrsMaterial *self, void * /*closure*/)
|
||||
{
|
||||
return blender::Vector_CreatePyObject_cb(
|
||||
(PyObject *)self, 4, FrsMaterial_mathutils_cb_index, MATHUTILS_SUBTYPE_SPECULAR);
|
||||
}
|
||||
|
||||
static int FrsMaterial_specular_set(BPy_FrsMaterial *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
float color[4];
|
||||
if (blender::mathutils_array_parse(color, 4, 4, value, "value must be a 4-dimensional vector") ==
|
||||
-1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
self->m->setSpecular(color[0], color[1], color[2], color[3]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsMaterial_ambient_doc,
|
||||
"RGBA components of the ambient color of the material.\n"
|
||||
"\n"
|
||||
":type: :class:`mathutils.Color`\n");
|
||||
static PyObject *FrsMaterial_ambient_get(BPy_FrsMaterial *self, void * /*closure*/)
|
||||
{
|
||||
return blender::Vector_CreatePyObject_cb(
|
||||
(PyObject *)self, 4, FrsMaterial_mathutils_cb_index, MATHUTILS_SUBTYPE_AMBIENT);
|
||||
}
|
||||
|
||||
static int FrsMaterial_ambient_set(BPy_FrsMaterial *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
float color[4];
|
||||
if (blender::mathutils_array_parse(color, 4, 4, value, "value must be a 4-dimensional vector") ==
|
||||
-1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
self->m->setAmbient(color[0], color[1], color[2], color[3]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsMaterial_emission_doc,
|
||||
"RGBA components of the emissive color of the material.\n"
|
||||
"\n"
|
||||
":type: :class:`mathutils.Color`\n");
|
||||
static PyObject *FrsMaterial_emission_get(BPy_FrsMaterial *self, void * /*closure*/)
|
||||
{
|
||||
return blender::Vector_CreatePyObject_cb(
|
||||
(PyObject *)self, 4, FrsMaterial_mathutils_cb_index, MATHUTILS_SUBTYPE_EMISSION);
|
||||
}
|
||||
|
||||
static int FrsMaterial_emission_set(BPy_FrsMaterial *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
float color[4];
|
||||
if (blender::mathutils_array_parse(color, 4, 4, value, "value must be a 4-dimensional vector") ==
|
||||
-1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
self->m->setEmission(color[0], color[1], color[2], color[3]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsMaterial_shininess_doc,
|
||||
"Shininess coefficient of the material.\n"
|
||||
"\n"
|
||||
":type: float\n");
|
||||
static PyObject *FrsMaterial_shininess_get(BPy_FrsMaterial *self, void * /*closure*/)
|
||||
{
|
||||
return PyFloat_FromDouble(self->m->shininess());
|
||||
}
|
||||
|
||||
static int FrsMaterial_shininess_set(BPy_FrsMaterial *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
float scalar;
|
||||
if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) {
|
||||
/* parsed item not a number */
|
||||
PyErr_SetString(PyExc_TypeError, "value must be a number");
|
||||
return -1;
|
||||
}
|
||||
self->m->setShininess(scalar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsMaterial_priority_doc,
|
||||
"Line color priority of the material.\n"
|
||||
"\n"
|
||||
":type: int\n");
|
||||
static PyObject *FrsMaterial_priority_get(BPy_FrsMaterial *self, void * /*closure*/)
|
||||
{
|
||||
return PyLong_FromLong(self->m->priority());
|
||||
}
|
||||
|
||||
static int FrsMaterial_priority_set(BPy_FrsMaterial *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
int scalar;
|
||||
if ((scalar = PyLong_AsLong(value)) == -1 && PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be an integer");
|
||||
return -1;
|
||||
}
|
||||
self->m->setPriority(scalar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_FrsMaterial_getseters[] = {
|
||||
{"line",
|
||||
(getter)FrsMaterial_line_get,
|
||||
(setter)FrsMaterial_line_set,
|
||||
FrsMaterial_line_doc,
|
||||
nullptr},
|
||||
{"diffuse",
|
||||
(getter)FrsMaterial_diffuse_get,
|
||||
(setter)FrsMaterial_diffuse_set,
|
||||
FrsMaterial_diffuse_doc,
|
||||
nullptr},
|
||||
{"specular",
|
||||
(getter)FrsMaterial_specular_get,
|
||||
(setter)FrsMaterial_specular_set,
|
||||
FrsMaterial_specular_doc,
|
||||
nullptr},
|
||||
{"ambient",
|
||||
(getter)FrsMaterial_ambient_get,
|
||||
(setter)FrsMaterial_ambient_set,
|
||||
FrsMaterial_ambient_doc,
|
||||
nullptr},
|
||||
{"emission",
|
||||
(getter)FrsMaterial_emission_get,
|
||||
(setter)FrsMaterial_emission_set,
|
||||
FrsMaterial_emission_doc,
|
||||
nullptr},
|
||||
{"shininess",
|
||||
(getter)FrsMaterial_shininess_get,
|
||||
(setter)FrsMaterial_shininess_set,
|
||||
FrsMaterial_shininess_doc,
|
||||
nullptr},
|
||||
{"priority",
|
||||
(getter)FrsMaterial_priority_get,
|
||||
(setter)FrsMaterial_priority_set,
|
||||
FrsMaterial_priority_doc,
|
||||
nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyObject *BPy_FrsMaterial_richcmpr(PyObject *objectA,
|
||||
PyObject *objectB,
|
||||
int comparison_type)
|
||||
{
|
||||
const BPy_FrsMaterial *matA = nullptr, *matB = nullptr;
|
||||
bool result = false;
|
||||
|
||||
if (!BPy_FrsMaterial_Check(objectA) || !BPy_FrsMaterial_Check(objectB)) {
|
||||
if (comparison_type == Py_NE) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
matA = (BPy_FrsMaterial *)objectA;
|
||||
matB = (BPy_FrsMaterial *)objectB;
|
||||
|
||||
switch (comparison_type) {
|
||||
case Py_NE:
|
||||
result = (*matA->m) != (*matB->m);
|
||||
break;
|
||||
case Py_EQ:
|
||||
result = (*matA->m) == (*matB->m);
|
||||
break;
|
||||
default:
|
||||
PyErr_SetString(PyExc_TypeError, "Material does not support this comparison type");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (result == true) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static Py_hash_t FrsMaterial_hash(PyObject *self)
|
||||
{
|
||||
return (Py_uhash_t)blender::BLI_hash_mm2((const uchar *)self, sizeof(*self), 0);
|
||||
}
|
||||
/*-----------------------BPy_FrsMaterial type definition ------------------------------*/
|
||||
|
||||
PyTypeObject FrsMaterial_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "Material",
|
||||
/*tp_basicsize*/ sizeof(BPy_FrsMaterial),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)FrsMaterial_dealloc,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)FrsMaterial_repr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ (hashfunc)FrsMaterial_hash,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ FrsMaterial_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ (richcmpfunc)BPy_FrsMaterial_richcmpr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ nullptr,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_FrsMaterial_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)FrsMaterial_init,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,35 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../scene_graph/FrsMaterial.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject FrsMaterial_Type;
|
||||
|
||||
#define BPy_FrsMaterial_Check(v) \
|
||||
(PyObject_IsInstance((PyObject *)v, (PyObject *)&FrsMaterial_Type))
|
||||
|
||||
/*---------------------------Python BPy_FrsMaterial structure definition----------*/
|
||||
struct BPy_FrsMaterial {
|
||||
PyObject_HEAD
|
||||
Freestyle::FrsMaterial *m;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_FrsMaterial visible prototypes-----------*/
|
||||
|
||||
int FrsMaterial_Init(PyObject *module);
|
||||
void FrsMaterial_mathutils_register_callback();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,381 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_FrsNoise.h"
|
||||
#include "BPy_Convert.h"
|
||||
|
||||
#include "../system/RandGen.h"
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int FrsNoise_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&FrsNoise_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "Noise", (PyObject *)&FrsNoise_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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"
|
||||
" :param seed: Seed for random number generation.\n"
|
||||
" :type seed: int\n");
|
||||
static int FrsNoise_init(BPy_FrsNoise *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"seed", nullptr};
|
||||
long seed = -1;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|l", (char **)kwlist, &seed)) {
|
||||
return -1;
|
||||
}
|
||||
self->n = new Noise(seed);
|
||||
self->pn = new PseudoNoise();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void FrsNoise_dealloc(BPy_FrsNoise *self)
|
||||
{
|
||||
delete self->n;
|
||||
delete self->pn;
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
}
|
||||
|
||||
static PyObject *FrsNoise_repr(BPy_FrsNoise *self)
|
||||
{
|
||||
return PyUnicode_FromFormat("Noise - address: %p", self->n);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsNoise_turbulence1_doc,
|
||||
".. method:: turbulence1(v, freq, amp, oct=4)\n"
|
||||
"\n"
|
||||
" Returns a noise value for a 1D element.\n"
|
||||
"\n"
|
||||
" :param v: One-dimensional sample point.\n"
|
||||
" :type v: float\n"
|
||||
" :param freq: Noise frequency.\n"
|
||||
" :type freq: float\n"
|
||||
" :param amp: Amplitude.\n"
|
||||
" :type amp: float\n"
|
||||
" :param oct: Number of octaves.\n"
|
||||
" :type oct: int\n"
|
||||
" :return: A noise value.\n"
|
||||
" :rtype: float\n");
|
||||
static PyObject *FrsNoise_drand(BPy_FrsNoise * /*self*/, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"seed", nullptr};
|
||||
long seed = 0;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|I", (char **)kwlist, &seed)) {
|
||||
PyErr_SetString(PyExc_TypeError, "optional argument 1 must be of type int");
|
||||
return nullptr;
|
||||
}
|
||||
if (seed) {
|
||||
RandGen::srand48(seed);
|
||||
}
|
||||
return PyFloat_FromDouble(RandGen::drand48());
|
||||
}
|
||||
|
||||
static PyObject *FrsNoise_turbulence_smooth(BPy_FrsNoise *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"v", "oct", nullptr};
|
||||
|
||||
double x; // NOTE: this has to be a double (not float)
|
||||
uint nbOctaves = 8;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "d|I", (char **)kwlist, &x, &nbOctaves)) {
|
||||
return nullptr;
|
||||
}
|
||||
return PyFloat_FromDouble(self->pn->turbulenceSmooth(x, nbOctaves));
|
||||
}
|
||||
|
||||
static PyObject *FrsNoise_turbulence1(BPy_FrsNoise *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"v", "freq", "amp", "oct", nullptr};
|
||||
float f1, f2, f3;
|
||||
uint i = 4;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "fff|I", (char **)kwlist, &f1, &f2, &f3, &i)) {
|
||||
return nullptr;
|
||||
}
|
||||
return PyFloat_FromDouble(self->n->turbulence1(f1, f2, f3, i));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsNoise_turbulence2_doc,
|
||||
".. method:: turbulence2(v, freq, amp, oct=4)\n"
|
||||
"\n"
|
||||
" Returns a noise value for a 2D element.\n"
|
||||
"\n"
|
||||
" :param v: Two-dimensional sample point.\n"
|
||||
" :type v: :class:`mathutils.Vector` | tuple[float, float] | list[float]\n"
|
||||
" :param freq: Noise frequency.\n"
|
||||
" :type freq: float\n"
|
||||
" :param amp: Amplitude.\n"
|
||||
" :type amp: float\n"
|
||||
" :param 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 *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"v", "freq", "amp", "oct", nullptr};
|
||||
PyObject *obj1;
|
||||
float f2, f3;
|
||||
uint i = 4;
|
||||
Vec2f vec;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "Off|I", (char **)kwlist, &obj1, &f2, &f3, &i)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!Vec2f_ptr_from_PyObject(obj1, vec)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"argument 1 must be a 2D vector (either a list of 2 elements or Vector)");
|
||||
return nullptr;
|
||||
}
|
||||
float t = self->n->turbulence2(vec, f2, f3, i);
|
||||
return PyFloat_FromDouble(t);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsNoise_turbulence3_doc,
|
||||
".. method:: turbulence3(v, freq, amp, oct=4)\n"
|
||||
"\n"
|
||||
" Returns a noise value for a 3D element.\n"
|
||||
"\n"
|
||||
" :param v: Three-dimensional sample point.\n"
|
||||
" :type v: :class:`mathutils.Vector` | tuple[float, float, float] | list[float]\n"
|
||||
" :param freq: Noise frequency.\n"
|
||||
" :type freq: float\n"
|
||||
" :param amp: Amplitude.\n"
|
||||
" :type amp: float\n"
|
||||
" :param 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 *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"v", "freq", "amp", "oct", nullptr};
|
||||
PyObject *obj1;
|
||||
float f2, f3;
|
||||
uint i = 4;
|
||||
Vec3f vec;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "Off|I", (char **)kwlist, &obj1, &f2, &f3, &i)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!Vec3f_ptr_from_PyObject(obj1, vec)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"argument 1 must be a 3D vector (either a list of 3 elements or Vector)");
|
||||
return nullptr;
|
||||
}
|
||||
float t = self->n->turbulence3(vec, f2, f3, i);
|
||||
return PyFloat_FromDouble(t);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsNoise_smoothNoise1_doc,
|
||||
".. method:: smoothNoise1(v)\n"
|
||||
"\n"
|
||||
" Returns a smooth noise value for a 1D element.\n"
|
||||
"\n"
|
||||
" :param 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, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"v", nullptr};
|
||||
float f;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "f", (char **)kwlist, &f)) {
|
||||
return nullptr;
|
||||
}
|
||||
return PyFloat_FromDouble(self->n->smoothNoise1(f));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsNoise_smoothNoise2_doc,
|
||||
".. method:: smoothNoise2(v)\n"
|
||||
"\n"
|
||||
" Returns a smooth noise value for a 2D element.\n"
|
||||
"\n"
|
||||
" :param v: Two-dimensional sample point.\n"
|
||||
" :type v: :class:`mathutils.Vector` | tuple[float, float] | list[float]\n"
|
||||
" :return: A smooth noise value.\n"
|
||||
" :rtype: float\n");
|
||||
static PyObject *FrsNoise_smoothNoise2(BPy_FrsNoise *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"v", nullptr};
|
||||
PyObject *obj;
|
||||
Vec2f vec;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", (char **)kwlist, &obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!Vec2f_ptr_from_PyObject(obj, vec)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"argument 1 must be a 2D vector (either a list of 2 elements or Vector)");
|
||||
return nullptr;
|
||||
}
|
||||
float t = self->n->smoothNoise2(vec);
|
||||
return PyFloat_FromDouble(t);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FrsNoise_smoothNoise3_doc,
|
||||
".. method:: smoothNoise3(v)\n"
|
||||
"\n"
|
||||
" Returns a smooth noise value for a 3D element.\n"
|
||||
"\n"
|
||||
" :param v: Three-dimensional sample point.\n"
|
||||
" :type v: :class:`mathutils.Vector` | tuple[float, float, float] | list[float]\n"
|
||||
" :return: A smooth noise value.\n"
|
||||
" :rtype: float\n");
|
||||
static PyObject *FrsNoise_smoothNoise3(BPy_FrsNoise *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"v", nullptr};
|
||||
PyObject *obj;
|
||||
Vec3f vec;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", (char **)kwlist, &obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!Vec3f_ptr_from_PyObject(obj, vec)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"argument 1 must be a 3D vector (either a list of 3 elements or Vector)");
|
||||
return nullptr;
|
||||
}
|
||||
float t = self->n->smoothNoise3(vec);
|
||||
return PyFloat_FromDouble(t);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wcast-function-type"
|
||||
# else
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static PyMethodDef BPy_FrsNoise_methods[] = {
|
||||
{"turbulence1",
|
||||
(PyCFunction)FrsNoise_turbulence1,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
FrsNoise_turbulence1_doc},
|
||||
{"turbulence2",
|
||||
(PyCFunction)FrsNoise_turbulence2,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
FrsNoise_turbulence2_doc},
|
||||
{"turbulence3",
|
||||
(PyCFunction)FrsNoise_turbulence3,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
FrsNoise_turbulence3_doc},
|
||||
{"smoothNoise1",
|
||||
(PyCFunction)FrsNoise_smoothNoise1,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
FrsNoise_smoothNoise1_doc},
|
||||
{"smoothNoise2",
|
||||
(PyCFunction)FrsNoise_smoothNoise2,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
FrsNoise_smoothNoise2_doc},
|
||||
{"smoothNoise3",
|
||||
(PyCFunction)FrsNoise_smoothNoise3,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
FrsNoise_smoothNoise3_doc},
|
||||
{"rand", (PyCFunction)FrsNoise_drand, METH_VARARGS | METH_KEYWORDS, nullptr},
|
||||
{"turbulence_smooth",
|
||||
(PyCFunction)FrsNoise_turbulence_smooth,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
nullptr},
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# else
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*-----------------------BPy_FrsNoise type definition ------------------------------*/
|
||||
|
||||
PyTypeObject FrsNoise_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "Noise",
|
||||
/*tp_basicsize*/ sizeof(BPy_FrsNoise),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)FrsNoise_dealloc,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)FrsNoise_repr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ FrsNoise_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ BPy_FrsNoise_methods,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ nullptr,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)FrsNoise_init,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,35 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../geometry/Noise.h"
|
||||
#include "../system/PseudoNoise.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject FrsNoise_Type;
|
||||
|
||||
#define BPy_FrsNoise_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&FrsNoise_Type))
|
||||
|
||||
/*---------------------------Python BPy_FrsNoise structure definition----------*/
|
||||
struct BPy_FrsNoise {
|
||||
PyObject_HEAD
|
||||
Freestyle::Noise *n;
|
||||
Freestyle::PseudoNoise *pn;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_FrsNoise visible prototypes-----------*/
|
||||
|
||||
int FrsNoise_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
202
blender-5.2.0/source/blender/freestyle/intern/python/BPy_Id.cpp
Normal file
202
blender-5.2.0/source/blender/freestyle/intern/python/BPy_Id.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_Id.h"
|
||||
|
||||
#include "BPy_Convert.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int Id_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&Id_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyModule_AddObjectRef(module, "Id", (PyObject *)&Id_Type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Id_doc,
|
||||
"Class for representing an object Id.\n"
|
||||
"\n"
|
||||
".. method:: __init__(*args, **kwargs)\n"
|
||||
"\n"
|
||||
" Accepted call signatures:\n"
|
||||
"\n"
|
||||
" - ``__init__(brother)``\n"
|
||||
" - ``__init__(first=0, second=0)``\n"
|
||||
"\n"
|
||||
" Build the Id from two numbers or another :class:`Id` using the copy constructor.\n"
|
||||
"\n"
|
||||
" :param brother: An Id object.\n"
|
||||
" :type brother: :class:`Id`\n"
|
||||
" :param first: The first number.\n"
|
||||
" :type first: int\n"
|
||||
" :param second: The second number.\n"
|
||||
" :type second: int\n");
|
||||
static int Id_init(BPy_Id *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist_1[] = {"brother", nullptr};
|
||||
static const char *kwlist_2[] = {"first", "second", nullptr};
|
||||
PyObject *brother;
|
||||
int first = 0, second = 0;
|
||||
|
||||
if (PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_1, &Id_Type, &brother)) {
|
||||
self->id = new Id(*(((BPy_Id *)brother)->id));
|
||||
}
|
||||
else if ((void)PyErr_Clear(),
|
||||
PyArg_ParseTupleAndKeywords(args, kwds, "|ii", (char **)kwlist_2, &first, &second))
|
||||
{
|
||||
self->id = new Id(first, second);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
|
||||
return -1;
|
||||
}
|
||||
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 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)));
|
||||
case Py_LE:
|
||||
return PyBool_from_bool(o1->id->operator<(*(o2->id)) || o1->id->operator==(*(o2->id)));
|
||||
case Py_EQ:
|
||||
return PyBool_from_bool(o1->id->operator==(*(o2->id)));
|
||||
case Py_NE:
|
||||
return PyBool_from_bool(o1->id->operator!=(*(o2->id)));
|
||||
case Py_GT:
|
||||
return PyBool_from_bool(!(o1->id->operator<(*(o2->id)) || o1->id->operator==(*(o2->id))));
|
||||
case Py_GE:
|
||||
return PyBool_from_bool(!o1->id->operator<(*(o2->id)));
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/*----------------------Id get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Id_first_doc,
|
||||
"The first number constituting the Id.\n"
|
||||
"\n"
|
||||
":type: int\n");
|
||||
static PyObject *Id_first_get(BPy_Id *self, void * /*closure*/)
|
||||
{
|
||||
return PyLong_FromLong(self->id->getFirst());
|
||||
}
|
||||
|
||||
static int Id_first_set(BPy_Id *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
int scalar;
|
||||
if ((scalar = PyLong_AsLong(value)) == -1 && PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be an integer");
|
||||
return -1;
|
||||
}
|
||||
self->id->setFirst(scalar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Id_second_doc,
|
||||
"The second number constituting the Id.\n"
|
||||
"\n"
|
||||
":type: int\n");
|
||||
static PyObject *Id_second_get(BPy_Id *self, void * /*closure*/)
|
||||
{
|
||||
return PyLong_FromLong(self->id->getSecond());
|
||||
}
|
||||
|
||||
static int Id_second_set(BPy_Id *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
int scalar;
|
||||
if ((scalar = PyLong_AsLong(value)) == -1 && PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be an integer");
|
||||
return -1;
|
||||
}
|
||||
self->id->setSecond(scalar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_Id_getseters[] = {
|
||||
{"first", (getter)Id_first_get, (setter)Id_first_set, Id_first_doc, nullptr},
|
||||
{"second", (getter)Id_second_get, (setter)Id_second_set, Id_second_doc, nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_Id type definition ------------------------------*/
|
||||
|
||||
PyTypeObject Id_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "Id",
|
||||
/*tp_basicsize*/ sizeof(BPy_Id),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)Id_dealloc,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)Id_repr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ Id_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ (richcmpfunc)Id_RichCompare,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ nullptr,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_Id_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)Id_init,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,35 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "../system/Id.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject Id_Type;
|
||||
|
||||
#define BPy_Id_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&Id_Type))
|
||||
|
||||
/*---------------------------Python BPy_Id structure definition----------*/
|
||||
struct BPy_Id {
|
||||
PyObject_HEAD
|
||||
Freestyle::Id *id;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_Id visible prototypes-----------*/
|
||||
|
||||
int Id_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,267 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_IntegrationType.h"
|
||||
|
||||
#include "BPy_Convert.h"
|
||||
#include "Iterator/BPy_Interface0DIterator.h"
|
||||
#include "UnaryFunction0D/BPy_UnaryFunction0DDouble.h"
|
||||
#include "UnaryFunction0D/BPy_UnaryFunction0DFloat.h"
|
||||
#include "UnaryFunction0D/BPy_UnaryFunction0DUnsigned.h"
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//------------------------ MODULE FUNCTIONS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Integrator_integrate_doc,
|
||||
".. function:: integrate(func, 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"
|
||||
" :param func: The UnaryFunction0D used to compute a value at each\n"
|
||||
" Interface0D.\n"
|
||||
" :type func: :class:`UnaryFunction0D`\n"
|
||||
" :param 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"
|
||||
" :param it_end: The Interface0DIterator pointing the end of the 0D\n"
|
||||
" elements of the 1D element.\n"
|
||||
" :type it_end: :class:`Interface0DIterator`\n"
|
||||
" :param 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 func is of the :class:`UnaryFunction0DDouble`\n"
|
||||
" or :class:`UnaryFunction0DFloat` type, and int if func is of the\n"
|
||||
" :class:`UnaryFunction0DUnsigned` type.\n"
|
||||
" :rtype: int | float\n");
|
||||
static PyObject *Integrator_integrate(PyObject * /*self*/, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"func", "it", "it_end", "integration_type", nullptr};
|
||||
PyObject *obj1, *obj4 = nullptr;
|
||||
BPy_Interface0DIterator *obj2, *obj3;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args,
|
||||
kwds,
|
||||
"O!O!O!|O!",
|
||||
(char **)kwlist,
|
||||
&UnaryFunction0D_Type,
|
||||
&obj1,
|
||||
&Interface0DIterator_Type,
|
||||
&obj2,
|
||||
&Interface0DIterator_Type,
|
||||
&obj3,
|
||||
&IntegrationType_Type,
|
||||
&obj4))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (BPy_UnaryFunction0DUnsigned_Check(obj1)) {
|
||||
UnaryFunction0D<uint> *fun = ((BPy_UnaryFunction0DUnsigned *)obj1)->uf0D_unsigned;
|
||||
uint res = integrate(*fun, it, it_end, t);
|
||||
return PyLong_FromLong(res);
|
||||
}
|
||||
|
||||
string class_name(Py_TYPE(obj1)->tp_name);
|
||||
PyErr_SetString(PyExc_TypeError, ("unsupported function type: " + class_name).c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*-----------------------Integrator module docstring---------------------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
module_docstring,
|
||||
"The Blender Freestyle.Integrator submodule\n"
|
||||
"\n");
|
||||
|
||||
/*-----------------------Integrator module functions definitions---------------------------*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wcast-function-type"
|
||||
# else
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static PyMethodDef module_functions[] = {
|
||||
{"integrate",
|
||||
(PyCFunction)Integrator_integrate,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
Integrator_integrate_doc},
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# else
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*-----------------------Integrator module definition--------------------------------------*/
|
||||
|
||||
static PyModuleDef module_definition = {
|
||||
/*m_base*/ PyModuleDef_HEAD_INIT,
|
||||
/*m_name*/ "Freestyle.Integrator",
|
||||
/*m_doc*/ module_docstring,
|
||||
/*m_size*/ -1,
|
||||
/*m_methods*/ module_functions,
|
||||
/*m_slots*/ nullptr,
|
||||
/*m_traverse*/ nullptr,
|
||||
/*m_clear*/ nullptr,
|
||||
/*m_free*/ nullptr,
|
||||
};
|
||||
|
||||
/*-----------------------BPy_IntegrationType type definition ------------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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"
|
||||
".. attribute:: MEAN\n"
|
||||
"\n"
|
||||
" The value computed for the 1D element is the mean of the values\n"
|
||||
" obtained for the 0D elements.\n"
|
||||
"\n"
|
||||
".. attribute:: MIN\n"
|
||||
"\n"
|
||||
" The value computed for the 1D element is the minimum of the values\n"
|
||||
" obtained for the 0D elements.\n"
|
||||
"\n"
|
||||
".. attribute:: MAX\n"
|
||||
"\n"
|
||||
" The value computed for the 1D element is the maximum of the values\n"
|
||||
" obtained for the 0D elements.\n"
|
||||
"\n"
|
||||
".. attribute:: FIRST\n"
|
||||
"\n"
|
||||
" The value computed for the 1D element is the first of the values\n"
|
||||
" obtained for the 0D elements.\n"
|
||||
"\n"
|
||||
".. attribute:: LAST\n"
|
||||
"\n"
|
||||
" The value computed for the 1D element is the last of the values\n"
|
||||
" obtained for the 0D elements.\n");
|
||||
PyTypeObject IntegrationType_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "IntegrationType",
|
||||
/*tp_basicsize*/ sizeof(PyLongObject),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ nullptr,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ nullptr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT,
|
||||
/*tp_doc*/ IntegrationType_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ nullptr,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ nullptr,
|
||||
/*tp_base*/ &PyLong_Type,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ nullptr,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ nullptr,
|
||||
};
|
||||
|
||||
/*-----------------------BPy_IntegrationType instance definitions -------------------------*/
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int IntegrationType_Init(PyObject *module)
|
||||
{
|
||||
PyObject *m, *d, *f;
|
||||
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&IntegrationType_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "IntegrationType", (PyObject *)&IntegrationType_Type);
|
||||
|
||||
#define ADD_TYPE_CONST(id) \
|
||||
PyLong_subtype_add_to_dict( \
|
||||
IntegrationType_Type.tp_dict, &IntegrationType_Type, STRINGIFY(id), id)
|
||||
|
||||
ADD_TYPE_CONST(MEAN);
|
||||
ADD_TYPE_CONST(MIN);
|
||||
ADD_TYPE_CONST(MAX);
|
||||
ADD_TYPE_CONST(FIRST);
|
||||
ADD_TYPE_CONST(LAST);
|
||||
|
||||
#undef ADD_TYPE_CONST
|
||||
|
||||
m = PyModule_Create(&module_definition);
|
||||
if (m == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(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);
|
||||
PyModule_AddObjectRef(module, p->ml_name, f);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,28 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../view_map/Interface1D.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,359 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_Interface0D.h"
|
||||
|
||||
#include "BPy_Convert.h"
|
||||
#include "BPy_Nature.h"
|
||||
#include "Interface0D/BPy_CurvePoint.h"
|
||||
#include "Interface0D/BPy_SVertex.h"
|
||||
#include "Interface0D/BPy_ViewVertex.h"
|
||||
#include "Interface0D/CurvePoint/BPy_StrokeVertex.h"
|
||||
#include "Interface0D/ViewVertex/BPy_NonTVertex.h"
|
||||
#include "Interface0D/ViewVertex/BPy_TVertex.h"
|
||||
#include "Interface1D/BPy_FEdge.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int Interface0D_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&Interface0D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "Interface0D", (PyObject *)&Interface0D_Type);
|
||||
|
||||
if (PyType_Ready(&CurvePoint_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "CurvePoint", (PyObject *)&CurvePoint_Type);
|
||||
|
||||
if (PyType_Ready(&SVertex_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "SVertex", (PyObject *)&SVertex_Type);
|
||||
|
||||
if (PyType_Ready(&ViewVertex_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "ViewVertex", (PyObject *)&ViewVertex_Type);
|
||||
|
||||
if (PyType_Ready(&StrokeVertex_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "StrokeVertex", (PyObject *)&StrokeVertex_Type);
|
||||
|
||||
if (PyType_Ready(&NonTVertex_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "NonTVertex", (PyObject *)&NonTVertex_Type);
|
||||
|
||||
if (PyType_Ready(&TVertex_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "TVertex", (PyObject *)&TVertex_Type);
|
||||
|
||||
SVertex_mathutils_register_callback();
|
||||
StrokeVertex_mathutils_register_callback();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------Interface1D methods ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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)
|
||||
{
|
||||
static const char *kwlist[] = {nullptr};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist)) {
|
||||
return -1;
|
||||
}
|
||||
self->if0D = new Interface0D();
|
||||
self->borrowed = false;
|
||||
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);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface0D_get_fedge_doc,
|
||||
".. method:: get_fedge(inter)\n"
|
||||
"\n"
|
||||
" Returns the FEdge that lies between this 0D element and the 0D\n"
|
||||
" element given as the argument.\n"
|
||||
"\n"
|
||||
" :param 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_get_fedge(BPy_Interface0D *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"inter", nullptr};
|
||||
PyObject *py_if0D;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist, &Interface0D_Type, &py_if0D))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
FEdge *fe = self->if0D->getFEdge(*(((BPy_Interface0D *)py_if0D)->if0D));
|
||||
if (PyErr_Occurred()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (fe) {
|
||||
return Any_BPy_FEdge_from_FEdge(*fe);
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wcast-function-type"
|
||||
# else
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static PyMethodDef BPy_Interface0D_methods[] = {
|
||||
{"get_fedge",
|
||||
(PyCFunction)Interface0D_get_fedge,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
Interface0D_get_fedge_doc},
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# else
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*----------------------Interface1D get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface0D_name_doc,
|
||||
"The string of the name of this 0D element.\n"
|
||||
"\n"
|
||||
":type: str\n");
|
||||
static PyObject *Interface0D_name_get(BPy_Interface0D *self, void * /*closure*/)
|
||||
{
|
||||
return PyUnicode_FromString(Py_TYPE(self)->tp_name);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface0D_point_3d_doc,
|
||||
"The 3D point of this 0D element.\n"
|
||||
"\n"
|
||||
":type: :class:`mathutils.Vector`\n");
|
||||
static PyObject *Interface0D_point_3d_get(BPy_Interface0D *self, void * /*closure*/)
|
||||
{
|
||||
Vec3f p(self->if0D->getPoint3D());
|
||||
if (PyErr_Occurred()) {
|
||||
return nullptr;
|
||||
}
|
||||
return Vector_from_Vec3f(p);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface0D_projected_x_doc,
|
||||
"The X coordinate of the projected 3D point of this 0D element.\n"
|
||||
"\n"
|
||||
":type: float\n");
|
||||
static PyObject *Interface0D_projected_x_get(BPy_Interface0D *self, void * /*closure*/)
|
||||
{
|
||||
real x = self->if0D->getProjectedX();
|
||||
if (PyErr_Occurred()) {
|
||||
return nullptr;
|
||||
}
|
||||
return PyFloat_FromDouble(x);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface0D_projected_y_doc,
|
||||
"The Y coordinate of the projected 3D point of this 0D element.\n"
|
||||
"\n"
|
||||
":type: float\n");
|
||||
static PyObject *Interface0D_projected_y_get(BPy_Interface0D *self, void * /*closure*/)
|
||||
{
|
||||
real y = self->if0D->getProjectedY();
|
||||
if (PyErr_Occurred()) {
|
||||
return nullptr;
|
||||
}
|
||||
return PyFloat_FromDouble(y);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface0D_projected_z_doc,
|
||||
"The Z coordinate of the projected 3D point of this 0D element.\n"
|
||||
"\n"
|
||||
":type: float\n");
|
||||
static PyObject *Interface0D_projected_z_get(BPy_Interface0D *self, void * /*closure*/)
|
||||
{
|
||||
real z = self->if0D->getProjectedZ();
|
||||
if (PyErr_Occurred()) {
|
||||
return nullptr;
|
||||
}
|
||||
return PyFloat_FromDouble(z);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface0D_point_2d_doc,
|
||||
"The 2D point of this 0D element.\n"
|
||||
"\n"
|
||||
":type: :class:`mathutils.Vector`\n");
|
||||
static PyObject *Interface0D_point_2d_get(BPy_Interface0D *self, void * /*closure*/)
|
||||
{
|
||||
Vec2f p(self->if0D->getPoint2D());
|
||||
if (PyErr_Occurred()) {
|
||||
return nullptr;
|
||||
}
|
||||
return Vector_from_Vec2f(p);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface0D_id_doc,
|
||||
"The Id of this 0D element.\n"
|
||||
"\n"
|
||||
":type: :class:`Id`\n");
|
||||
static PyObject *Interface0D_id_get(BPy_Interface0D *self, void * /*closure*/)
|
||||
{
|
||||
Id id(self->if0D->getId());
|
||||
if (PyErr_Occurred()) {
|
||||
return nullptr;
|
||||
}
|
||||
return BPy_Id_from_Id(id); // return a copy
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface0D_nature_doc,
|
||||
"The nature of this 0D element.\n"
|
||||
"\n"
|
||||
":type: :class:`Nature`\n");
|
||||
static PyObject *Interface0D_nature_get(BPy_Interface0D *self, void * /*closure*/)
|
||||
{
|
||||
Nature::VertexNature nature = self->if0D->getNature();
|
||||
if (PyErr_Occurred()) {
|
||||
return nullptr;
|
||||
}
|
||||
return BPy_Nature_from_Nature(nature);
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_Interface0D_getseters[] = {
|
||||
{"name", (getter)Interface0D_name_get, (setter) nullptr, Interface0D_name_doc, nullptr},
|
||||
{"point_3d",
|
||||
(getter)Interface0D_point_3d_get,
|
||||
(setter) nullptr,
|
||||
Interface0D_point_3d_doc,
|
||||
nullptr},
|
||||
{"projected_x",
|
||||
(getter)Interface0D_projected_x_get,
|
||||
(setter) nullptr,
|
||||
Interface0D_projected_x_doc,
|
||||
nullptr},
|
||||
{"projected_y",
|
||||
(getter)Interface0D_projected_y_get,
|
||||
(setter) nullptr,
|
||||
Interface0D_projected_y_doc,
|
||||
nullptr},
|
||||
{"projected_z",
|
||||
(getter)Interface0D_projected_z_get,
|
||||
(setter) nullptr,
|
||||
Interface0D_projected_z_doc,
|
||||
nullptr},
|
||||
{"point_2d",
|
||||
(getter)Interface0D_point_2d_get,
|
||||
(setter) nullptr,
|
||||
Interface0D_point_2d_doc,
|
||||
nullptr},
|
||||
{"id", (getter)Interface0D_id_get, (setter) nullptr, Interface0D_id_doc, nullptr},
|
||||
{"nature", (getter)Interface0D_nature_get, (setter) nullptr, Interface0D_nature_doc, nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_Interface0D type definition ------------------------------*/
|
||||
|
||||
PyTypeObject Interface0D_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "Interface0D",
|
||||
/*tp_basicsize*/ sizeof(BPy_Interface0D),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)Interface0D_dealloc,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)Interface0D_repr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ Interface0D_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ BPy_Interface0D_methods,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_Interface0D_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)Interface0D_init,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,35 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../view_map/Interface0D.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject Interface0D_Type;
|
||||
|
||||
#define BPy_Interface0D_Check(v) \
|
||||
(PyObject_IsInstance((PyObject *)v, (PyObject *)&Interface0D_Type))
|
||||
|
||||
/*---------------------------Python BPy_Interface0D structure definition----------*/
|
||||
struct BPy_Interface0D {
|
||||
PyObject_HEAD
|
||||
Freestyle::Interface0D *if0D;
|
||||
bool borrowed; /* true if *if0D is a borrowed object */
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_Interface0D visible prototypes-----------*/
|
||||
|
||||
int Interface0D_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,387 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_Interface1D.h"
|
||||
|
||||
#include "BPy_Convert.h"
|
||||
#include "Interface1D/BPy_FEdge.h"
|
||||
#include "Interface1D/BPy_FrsCurve.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_MediumType.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int Interface1D_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&Interface1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "Interface1D", (PyObject *)&Interface1D_Type);
|
||||
|
||||
if (PyType_Ready(&FrsCurve_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "Curve", (PyObject *)&FrsCurve_Type);
|
||||
|
||||
if (PyType_Ready(&Chain_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "Chain", (PyObject *)&Chain_Type);
|
||||
|
||||
if (PyType_Ready(&FEdge_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "FEdge", (PyObject *)&FEdge_Type);
|
||||
|
||||
if (PyType_Ready(&FEdgeSharp_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "FEdgeSharp", (PyObject *)&FEdgeSharp_Type);
|
||||
|
||||
if (PyType_Ready(&FEdgeSmooth_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "FEdgeSmooth", (PyObject *)&FEdgeSmooth_Type);
|
||||
|
||||
if (PyType_Ready(&Stroke_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "Stroke", (PyObject *)&Stroke_Type);
|
||||
|
||||
#define ADD_TYPE_CONST(id) \
|
||||
PyLong_subtype_add_to_dict(Stroke_Type.tp_dict, &MediumType_Type, STRINGIFY(id), Stroke::id)
|
||||
ADD_TYPE_CONST(DRY_MEDIUM);
|
||||
ADD_TYPE_CONST(HUMID_MEDIUM);
|
||||
ADD_TYPE_CONST(OPAQUE_MEDIUM);
|
||||
#undef ADD_TYPE_CONST
|
||||
|
||||
if (PyType_Ready(&ViewEdge_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "ViewEdge", (PyObject *)&ViewEdge_Type);
|
||||
|
||||
FEdgeSharp_mathutils_register_callback();
|
||||
FEdgeSmooth_mathutils_register_callback();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------Interface1D methods ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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)
|
||||
{
|
||||
static const char *kwlist[] = {nullptr};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist)) {
|
||||
return -1;
|
||||
}
|
||||
self->if1D = new Interface1D();
|
||||
self->borrowed = false;
|
||||
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);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface1D_vertices_begin_doc,
|
||||
".. method:: vertices_begin()\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_vertices_begin(BPy_Interface1D *self)
|
||||
{
|
||||
Interface0DIterator if0D_it(self->if1D->verticesBegin());
|
||||
return BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, false);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface1D_vertices_end_doc,
|
||||
".. method:: vertices_end()\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_vertices_end(BPy_Interface1D *self)
|
||||
{
|
||||
Interface0DIterator if0D_it(self->if1D->verticesEnd());
|
||||
return BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, true);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface1D_points_begin_doc,
|
||||
".. method:: points_begin(t=0.0)\n"
|
||||
"\n"
|
||||
" Returns an iterator over the Interface1D points, pointing to the\n"
|
||||
" first point. The difference with vertices_begin() 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"
|
||||
" :param 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_points_begin(BPy_Interface1D *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"t", nullptr};
|
||||
float f = 0.0f;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|f", (char **)kwlist, &f)) {
|
||||
return nullptr;
|
||||
}
|
||||
Interface0DIterator if0D_it(self->if1D->pointsBegin(f));
|
||||
return BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, false);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface1D_points_end_doc,
|
||||
".. method:: points_end(t=0.0)\n"
|
||||
"\n"
|
||||
" Returns an iterator over the Interface1D points, pointing after the\n"
|
||||
" last point. The difference with vertices_end() 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"
|
||||
" :param 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_points_end(BPy_Interface1D *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"t", nullptr};
|
||||
float f = 0.0f;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|f", (char **)kwlist, &f)) {
|
||||
return nullptr;
|
||||
}
|
||||
Interface0DIterator if0D_it(self->if1D->pointsEnd(f));
|
||||
return BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, true);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wcast-function-type"
|
||||
# else
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static PyMethodDef BPy_Interface1D_methods[] = {
|
||||
{"vertices_begin",
|
||||
(PyCFunction)Interface1D_vertices_begin,
|
||||
METH_NOARGS,
|
||||
Interface1D_vertices_begin_doc},
|
||||
{"vertices_end",
|
||||
(PyCFunction)Interface1D_vertices_end,
|
||||
METH_NOARGS,
|
||||
Interface1D_vertices_end_doc},
|
||||
{"points_begin",
|
||||
(PyCFunction)Interface1D_points_begin,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
Interface1D_points_begin_doc},
|
||||
{"points_end",
|
||||
(PyCFunction)Interface1D_points_end,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
Interface1D_points_end_doc},
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# else
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*----------------------Interface1D get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface1D_name_doc,
|
||||
"The string of the name of the 1D element.\n"
|
||||
"\n"
|
||||
":type: str\n");
|
||||
static PyObject *Interface1D_name_get(BPy_Interface1D *self, void * /*closure*/)
|
||||
{
|
||||
return PyUnicode_FromString(Py_TYPE(self)->tp_name);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface1D_id_doc,
|
||||
"The Id of this Interface1D.\n"
|
||||
"\n"
|
||||
":type: :class:`Id`\n");
|
||||
static PyObject *Interface1D_id_get(BPy_Interface1D *self, void * /*closure*/)
|
||||
{
|
||||
Id id(self->if1D->getId());
|
||||
if (PyErr_Occurred()) {
|
||||
return nullptr;
|
||||
}
|
||||
return BPy_Id_from_Id(id); // return a copy
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface1D_nature_doc,
|
||||
"The nature of this Interface1D.\n"
|
||||
"\n"
|
||||
":type: :class:`Nature`\n");
|
||||
static PyObject *Interface1D_nature_get(BPy_Interface1D *self, void * /*closure*/)
|
||||
{
|
||||
Nature::VertexNature nature = self->if1D->getNature();
|
||||
if (PyErr_Occurred()) {
|
||||
return nullptr;
|
||||
}
|
||||
return BPy_Nature_from_Nature(nature);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface1D_length_2d_doc,
|
||||
"The 2D length of this Interface1D.\n"
|
||||
"\n"
|
||||
":type: float\n");
|
||||
static PyObject *Interface1D_length_2d_get(BPy_Interface1D *self, void * /*closure*/)
|
||||
{
|
||||
real length = self->if1D->getLength2D();
|
||||
if (PyErr_Occurred()) {
|
||||
return nullptr;
|
||||
}
|
||||
return PyFloat_FromDouble(double(length));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Interface1D_time_stamp_doc,
|
||||
"The time stamp of the 1D element, mainly used for selection.\n"
|
||||
"\n"
|
||||
":type: int\n");
|
||||
static PyObject *Interface1D_time_stamp_get(BPy_Interface1D *self, void * /*closure*/)
|
||||
{
|
||||
return PyLong_FromLong(self->if1D->getTimeStamp());
|
||||
}
|
||||
|
||||
static int Interface1D_time_stamp_set(BPy_Interface1D *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
int timestamp;
|
||||
|
||||
if ((timestamp = PyLong_AsLong(value)) == -1 && PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be a number");
|
||||
return -1;
|
||||
}
|
||||
self->if1D->setTimeStamp(timestamp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_Interface1D_getseters[] = {
|
||||
{"name", (getter)Interface1D_name_get, (setter) nullptr, Interface1D_name_doc, nullptr},
|
||||
{"id", (getter)Interface1D_id_get, (setter) nullptr, Interface1D_id_doc, nullptr},
|
||||
{"nature", (getter)Interface1D_nature_get, (setter) nullptr, Interface1D_nature_doc, nullptr},
|
||||
{"length_2d",
|
||||
(getter)Interface1D_length_2d_get,
|
||||
(setter) nullptr,
|
||||
Interface1D_length_2d_doc,
|
||||
nullptr},
|
||||
{"time_stamp",
|
||||
(getter)Interface1D_time_stamp_get,
|
||||
(setter)Interface1D_time_stamp_set,
|
||||
Interface1D_time_stamp_doc,
|
||||
nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_Interface1D type definition ------------------------------*/
|
||||
|
||||
PyTypeObject Interface1D_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "Interface1D",
|
||||
/*tp_basicsize*/ sizeof(BPy_Interface1D),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)Interface1D_dealloc,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)Interface1D_repr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ Interface1D_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ BPy_Interface1D_methods,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_Interface1D_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)Interface1D_init,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,35 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../view_map/Interface1D.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject Interface1D_Type;
|
||||
|
||||
#define BPy_Interface1D_Check(v) \
|
||||
(PyObject_IsInstance((PyObject *)v, (PyObject *)&Interface1D_Type))
|
||||
|
||||
/*---------------------------Python BPy_Interface1D structure definition----------*/
|
||||
struct BPy_Interface1D {
|
||||
PyObject_HEAD
|
||||
Freestyle::Interface1D *if1D;
|
||||
bool borrowed; /* true if *if1D is a borrowed object */
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_Interface1D visible prototypes-----------*/
|
||||
|
||||
int Interface1D_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,268 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_Iterator.h"
|
||||
|
||||
#include "BPy_Convert.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"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int Iterator_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&Iterator_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "Iterator", (PyObject *)&Iterator_Type);
|
||||
|
||||
if (PyType_Ready(&AdjacencyIterator_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "AdjacencyIterator", (PyObject *)&AdjacencyIterator_Type);
|
||||
|
||||
if (PyType_Ready(&Interface0DIterator_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "Interface0DIterator", (PyObject *)&Interface0DIterator_Type);
|
||||
|
||||
if (PyType_Ready(&CurvePointIterator_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "CurvePointIterator", (PyObject *)&CurvePointIterator_Type);
|
||||
|
||||
if (PyType_Ready(&StrokeVertexIterator_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "StrokeVertexIterator", (PyObject *)&StrokeVertexIterator_Type);
|
||||
|
||||
if (PyType_Ready(&SVertexIterator_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "SVertexIterator", (PyObject *)&SVertexIterator_Type);
|
||||
|
||||
if (PyType_Ready(&orientedViewEdgeIterator_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(
|
||||
module, "orientedViewEdgeIterator", (PyObject *)&orientedViewEdgeIterator_Type);
|
||||
|
||||
if (PyType_Ready(&ViewEdgeIterator_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "ViewEdgeIterator", (PyObject *)&ViewEdgeIterator_Type);
|
||||
|
||||
if (PyType_Ready(&ChainingIterator_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "ChainingIterator", (PyObject *)&ChainingIterator_Type);
|
||||
|
||||
if (PyType_Ready(&ChainPredicateIterator_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(
|
||||
module, "ChainPredicateIterator", (PyObject *)&ChainPredicateIterator_Type);
|
||||
|
||||
if (PyType_Ready(&ChainSilhouetteIterator_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(
|
||||
module, "ChainSilhouetteIterator", (PyObject *)&ChainSilhouetteIterator_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Iterator_doc,
|
||||
"Base class to define iterators.\n"
|
||||
"\n"
|
||||
".. method:: __init__()\n"
|
||||
"\n"
|
||||
" Default constructor.\n");
|
||||
static int Iterator_init(BPy_Iterator *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {nullptr};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist)) {
|
||||
return -1;
|
||||
}
|
||||
self->it = new Iterator();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Iterator_dealloc(BPy_Iterator *self)
|
||||
{
|
||||
delete self->it;
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
}
|
||||
|
||||
static PyObject *Iterator_repr(BPy_Iterator *self)
|
||||
{
|
||||
return PyUnicode_FromFormat("type: %s - address: %p", Py_TYPE(self)->tp_name, self->it);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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 nullptr;
|
||||
}
|
||||
self->it->increment();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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 nullptr;
|
||||
}
|
||||
self->it->decrement();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wcast-function-type"
|
||||
# else
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static PyMethodDef BPy_Iterator_methods[] = {
|
||||
{"increment", (PyCFunction)Iterator_increment, METH_NOARGS, Iterator_increment_doc},
|
||||
{"decrement", (PyCFunction)Iterator_decrement, METH_NOARGS, Iterator_decrement_doc},
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# else
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*----------------------Iterator get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Iterator_name_doc,
|
||||
"The string of the name of this iterator.\n"
|
||||
"\n"
|
||||
":type: str\n");
|
||||
static PyObject *Iterator_name_get(BPy_Iterator *self, void * /*closure*/)
|
||||
{
|
||||
return PyUnicode_FromString(Py_TYPE(self)->tp_name);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Iterator_is_begin_doc,
|
||||
"True if the iterator points to the first element.\n"
|
||||
"\n"
|
||||
":type: bool\n");
|
||||
static PyObject *Iterator_is_begin_get(BPy_Iterator *self, void * /*closure*/)
|
||||
{
|
||||
return PyBool_from_bool(self->it->isBegin());
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Iterator_is_end_doc,
|
||||
"True if the iterator points to the last element.\n"
|
||||
"\n"
|
||||
":type: bool\n");
|
||||
static PyObject *Iterator_is_end_get(BPy_Iterator *self, void * /*closure*/)
|
||||
{
|
||||
return PyBool_from_bool(self->it->isEnd());
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_Iterator_getseters[] = {
|
||||
{"name", (getter)Iterator_name_get, (setter) nullptr, Iterator_name_doc, nullptr},
|
||||
{"is_begin", (getter)Iterator_is_begin_get, (setter) nullptr, Iterator_is_begin_doc, nullptr},
|
||||
{"is_end", (getter)Iterator_is_end_get, (setter) nullptr, Iterator_is_end_doc, nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_Iterator type definition ------------------------------*/
|
||||
|
||||
PyTypeObject Iterator_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "Iterator",
|
||||
/*tp_basicsize*/ sizeof(BPy_Iterator),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)Iterator_dealloc,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)Iterator_repr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ Iterator_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ BPy_Iterator_methods,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_Iterator_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)Iterator_init,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,33 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../system/Iterator.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject Iterator_Type;
|
||||
|
||||
#define BPy_Iterator_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&Iterator_Type))
|
||||
|
||||
/*---------------------------Python BPy_Iterator structure definition----------*/
|
||||
struct BPy_Iterator {
|
||||
PyObject_HEAD
|
||||
Freestyle::Iterator *it;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_Iterator visible prototypes-----------*/
|
||||
|
||||
int Iterator_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,89 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_MediumType.h"
|
||||
|
||||
#include "BPy_Convert.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*-----------------------BPy_MediumType type definition ------------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
MediumType_doc,
|
||||
"Class hierarchy: int > :class:`MediumType`\n"
|
||||
"\n"
|
||||
"The different blending modes available to simulate 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 subtraction blending).\n"
|
||||
"* Stroke.OPAQUE_MEDIUM: To simulate an opaque medium (oil, spray...).\n");
|
||||
PyTypeObject MediumType_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "MediumType",
|
||||
/*tp_basicsize*/ sizeof(PyLongObject),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ nullptr,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ nullptr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT,
|
||||
/*tp_doc*/ MediumType_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ nullptr,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ nullptr,
|
||||
/*tp_base*/ &PyLong_Type,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ nullptr,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ nullptr,
|
||||
};
|
||||
|
||||
/*-----------------------BPy_IntegrationType instance definitions -------------------------*/
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
|
||||
int MediumType_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&MediumType_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "MediumType", (PyObject *)&MediumType_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,32 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../stroke/Stroke.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject MediumType_Type;
|
||||
|
||||
#define BPy_MediumType_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&MediumType_Type))
|
||||
|
||||
/*---------------------------Python BPy_MediumType structure definition----------*/
|
||||
struct BPy_MediumType {
|
||||
PyLongObject i;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_MediumType visible prototypes-----------*/
|
||||
|
||||
int MediumType_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,265 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_Nature.h"
|
||||
|
||||
#include "BPy_Convert.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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);
|
||||
|
||||
/*-----------------------BPy_Nature number method definitions --------------------*/
|
||||
|
||||
static PyNumberMethods nature_as_number = {
|
||||
/*nb_add*/ nullptr,
|
||||
/*nb_subtract*/ nullptr,
|
||||
/*nb_multiply*/ nullptr,
|
||||
/*nb_remainder*/ nullptr,
|
||||
/*nb_divmod*/ nullptr,
|
||||
/*nb_power*/ nullptr,
|
||||
/*nb_negative*/ nullptr,
|
||||
/*nb_positive*/ nullptr,
|
||||
/*nb_absolute*/ nullptr,
|
||||
/*nb_bool*/ nullptr,
|
||||
/*nb_invert*/ nullptr,
|
||||
/*nb_lshift*/ nullptr,
|
||||
/*nb_rshift*/ nullptr,
|
||||
/*nb_and*/ (binaryfunc)BPy_Nature_and,
|
||||
/*nb_xor*/ (binaryfunc)BPy_Nature_xor,
|
||||
/*nb_or*/ (binaryfunc)BPy_Nature_or,
|
||||
/*nb_int*/ nullptr,
|
||||
/*nb_reserved*/ nullptr,
|
||||
/*nb_float*/ nullptr,
|
||||
/*nb_inplace_add*/ nullptr,
|
||||
/*nb_inplace_subtract*/ nullptr,
|
||||
/*nb_inplace_multiply*/ nullptr,
|
||||
/*nb_inplace_remainder*/ nullptr,
|
||||
/*nb_inplace_power*/ nullptr,
|
||||
/*nb_inplace_lshift*/ nullptr,
|
||||
/*nb_inplace_rshift*/ nullptr,
|
||||
/*nb_inplace_and*/ nullptr,
|
||||
/*nb_inplace_xor*/ nullptr,
|
||||
/*nb_inplace_or*/ nullptr,
|
||||
/*nb_floor_divide*/ nullptr,
|
||||
/*nb_true_divide*/ nullptr,
|
||||
/*nb_inplace_floor_divide*/ nullptr,
|
||||
/*nb_inplace_true_divide*/ nullptr,
|
||||
/*nb_index*/ nullptr,
|
||||
/*nb_matrix_multiply*/ nullptr,
|
||||
/*nb_inplace_matrix_multiply*/ nullptr,
|
||||
};
|
||||
|
||||
/*-----------------------BPy_Nature type definition ------------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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"
|
||||
".. attribute:: POINT\n"
|
||||
"\n"
|
||||
" True for any 0D element.\n"
|
||||
"\n"
|
||||
".. attribute:: S_VERTEX\n"
|
||||
"\n"
|
||||
" True for SVertex.\n"
|
||||
"\n"
|
||||
".. attribute:: VIEW_VERTEX\n"
|
||||
"\n"
|
||||
" True for ViewVertex.\n"
|
||||
"\n"
|
||||
".. attribute:: NON_T_VERTEX\n"
|
||||
"\n"
|
||||
" True for NonTVertex.\n"
|
||||
"\n"
|
||||
".. attribute:: T_VERTEX\n"
|
||||
"\n"
|
||||
" True for TVertex.\n"
|
||||
"\n"
|
||||
".. attribute:: CUSP\n"
|
||||
"\n"
|
||||
" True for CUSP.\n"
|
||||
"\n"
|
||||
"Edge natures:\n"
|
||||
"\n"
|
||||
".. attribute:: NO_FEATURE\n"
|
||||
"\n"
|
||||
" True for non feature edges (always false for 1D elements of the ViewMap).\n"
|
||||
"\n"
|
||||
".. attribute:: SILHOUETTE\n"
|
||||
"\n"
|
||||
" True for silhouettes.\n"
|
||||
"\n"
|
||||
".. attribute:: BORDER\n"
|
||||
"\n"
|
||||
" True for borders.\n"
|
||||
"\n"
|
||||
".. attribute:: CREASE\n"
|
||||
"\n"
|
||||
" True for creases.\n"
|
||||
"\n"
|
||||
".. attribute:: RIDGE\n"
|
||||
"\n"
|
||||
" True for ridges.\n"
|
||||
"\n"
|
||||
".. attribute:: VALLEY\n"
|
||||
"\n"
|
||||
" True for valleys.\n"
|
||||
"\n"
|
||||
".. attribute:: SUGGESTIVE_CONTOUR\n"
|
||||
"\n"
|
||||
" True for suggestive contours.\n"
|
||||
"\n"
|
||||
".. attribute:: MATERIAL_BOUNDARY\n"
|
||||
"\n"
|
||||
" True for edges at material boundaries.\n"
|
||||
"\n"
|
||||
".. attribute:: EDGE_MARK\n"
|
||||
"\n"
|
||||
" True for edges having user-defined edge marks.\n");
|
||||
PyTypeObject Nature_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "Nature",
|
||||
/*tp_basicsize*/ sizeof(PyLongObject),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ nullptr,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ nullptr,
|
||||
/*tp_as_number*/ &nature_as_number,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT,
|
||||
/*tp_doc*/ Nature_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ nullptr,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ nullptr,
|
||||
/*tp_base*/ &PyLong_Type,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ nullptr,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ nullptr,
|
||||
};
|
||||
|
||||
/*-----------------------BPy_Nature instance definitions ----------------------------------*/
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int Nature_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&Nature_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "Nature", (PyObject *)&Nature_Type);
|
||||
|
||||
#define ADD_TYPE_CONST(id) \
|
||||
PyLong_subtype_add_to_dict(Nature_Type.tp_dict, &Nature_Type, STRINGIFY(id), Nature::id)
|
||||
|
||||
// VertexNature
|
||||
ADD_TYPE_CONST(POINT);
|
||||
ADD_TYPE_CONST(S_VERTEX);
|
||||
ADD_TYPE_CONST(VIEW_VERTEX);
|
||||
ADD_TYPE_CONST(NON_T_VERTEX);
|
||||
ADD_TYPE_CONST(T_VERTEX);
|
||||
ADD_TYPE_CONST(CUSP);
|
||||
|
||||
// EdgeNature
|
||||
ADD_TYPE_CONST(NO_FEATURE);
|
||||
ADD_TYPE_CONST(SILHOUETTE);
|
||||
ADD_TYPE_CONST(BORDER);
|
||||
ADD_TYPE_CONST(CREASE);
|
||||
ADD_TYPE_CONST(RIDGE);
|
||||
ADD_TYPE_CONST(VALLEY);
|
||||
ADD_TYPE_CONST(SUGGESTIVE_CONTOUR);
|
||||
ADD_TYPE_CONST(MATERIAL_BOUNDARY);
|
||||
ADD_TYPE_CONST(EDGE_MARK);
|
||||
|
||||
#undef ADD_TYPE_CONST
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *BPy_Nature_bitwise(PyObject *a, int op, PyObject *b)
|
||||
{
|
||||
long op1, op2, v;
|
||||
|
||||
if (!BPy_Nature_Check(a) || !BPy_Nature_Check(b)) {
|
||||
PyErr_SetString(PyExc_TypeError, "operands must be a Nature object");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ((op1 = PyLong_AsLong(a)) == -1 && PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_ValueError, "operand 1: unexpected Nature value");
|
||||
return nullptr;
|
||||
}
|
||||
if ((op2 = PyLong_AsLong(b)) == -1 && PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_ValueError, "operand 2: unexpected Nature value");
|
||||
return nullptr;
|
||||
}
|
||||
switch (op) {
|
||||
case '&':
|
||||
v = op1 & op2;
|
||||
break;
|
||||
case '^':
|
||||
v = op1 ^ op2;
|
||||
break;
|
||||
case '|':
|
||||
v = op1 | op2;
|
||||
break;
|
||||
default:
|
||||
PyErr_BadArgument();
|
||||
return nullptr;
|
||||
}
|
||||
return PyLong_subtype_new(&Nature_Type, v);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,32 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../winged_edge/Nature.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject Nature_Type;
|
||||
|
||||
#define BPy_Nature_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&Nature_Type))
|
||||
|
||||
/*---------------------------Python BPy_Nature structure definition----------*/
|
||||
struct BPy_Nature {
|
||||
PyLongObject i;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_Nature visible prototypes-----------*/
|
||||
|
||||
int Nature_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,854 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_Operators.h"
|
||||
|
||||
#include "BPy_BinaryPredicate1D.h"
|
||||
#include "BPy_Convert.h"
|
||||
#include "BPy_StrokeShader.h"
|
||||
#include "BPy_UnaryPredicate0D.h"
|
||||
#include "BPy_UnaryPredicate1D.h"
|
||||
#include "Iterator/BPy_ChainingIterator.h"
|
||||
#include "Iterator/BPy_ViewEdgeIterator.h"
|
||||
#include "UnaryFunction0D/BPy_UnaryFunction0DDouble.h"
|
||||
#include "UnaryFunction1D/BPy_UnaryFunction1DVoid.h"
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int Operators_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&Operators_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "Operators", (PyObject *)&Operators_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Operators_select_doc,
|
||||
".. staticmethod:: select(pred)\n"
|
||||
"\n"
|
||||
" Selects the ViewEdges of the ViewMap verifying a specified\n"
|
||||
" condition.\n"
|
||||
"\n"
|
||||
" :param pred: The predicate expressing this condition.\n"
|
||||
" :type pred: :class:`UnaryPredicate1D`\n");
|
||||
static PyObject *Operators_select(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"pred", nullptr};
|
||||
PyObject *obj = nullptr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "O!", (char **)kwlist, &UnaryPredicate1D_Type, &obj))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (!((BPy_UnaryPredicate1D *)obj)->up1D) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Operators.select(): 1st argument: invalid UnaryPredicate1D object");
|
||||
return nullptr;
|
||||
}
|
||||
if (Operators::select(*(((BPy_UnaryPredicate1D *)obj)->up1D)) < 0) {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Operators.select() failed");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Operators_chain_doc,
|
||||
".. staticmethod:: chain(*args)\n"
|
||||
"\n"
|
||||
" Accepted call signatures:\n"
|
||||
"\n"
|
||||
" - ``chain(it, pred, modifier)``\n"
|
||||
" - ``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.\n"
|
||||
"\n"
|
||||
" :param it: The iterator on the ViewEdges of the ViewMap. It contains\n"
|
||||
" the chaining rule.\n"
|
||||
" :type it: :class:`ViewEdgeIterator`\n"
|
||||
" :param pred: The predicate on the ViewEdge that expresses the\n"
|
||||
" stopping condition.\n"
|
||||
" :type pred: :class:`UnaryPredicate1D`\n"
|
||||
" :param 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 modifier).\n"
|
||||
" If this argument is not given, the time stamp is automatically managed.\n"
|
||||
" :type modifier: :class:`UnaryFunction1DVoid`\n");
|
||||
static PyObject *Operators_chain(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"it", "pred", "modifier", nullptr};
|
||||
PyObject *obj1 = nullptr, *obj2 = nullptr, *obj3 = nullptr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args,
|
||||
kwds,
|
||||
"O!O!|O!",
|
||||
(char **)kwlist,
|
||||
&ChainingIterator_Type,
|
||||
&obj1,
|
||||
&UnaryPredicate1D_Type,
|
||||
&obj2,
|
||||
&UnaryFunction1DVoid_Type,
|
||||
&obj3))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (!((BPy_ChainingIterator *)obj1)->c_it) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Operators.chain(): 1st argument: invalid ChainingIterator object");
|
||||
return nullptr;
|
||||
}
|
||||
if (!((BPy_UnaryPredicate1D *)obj2)->up1D) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Operators.chain(): 2nd argument: invalid UnaryPredicate1D object");
|
||||
return nullptr;
|
||||
}
|
||||
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 nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!((BPy_UnaryFunction1DVoid *)obj3)->uf1D_void) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Operators.chain(): 3rd argument: invalid UnaryFunction1DVoid object");
|
||||
return nullptr;
|
||||
}
|
||||
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 nullptr;
|
||||
}
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Operators_bidirectional_chain_doc,
|
||||
".. staticmethod:: bidirectional_chain(*args)\n"
|
||||
"\n"
|
||||
" Accepted call signatures:\n"
|
||||
"\n"
|
||||
" - ``bidirectional_chain(it, pred)``\n"
|
||||
" - ``bidirectional_chain(it)``\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"
|
||||
" :param it: The ChainingIterator on the ViewEdges of the ViewMap. It\n"
|
||||
" contains the chaining rule.\n"
|
||||
" :type it: :class:`ChainingIterator`\n"
|
||||
" :param pred: The predicate on the ViewEdge that expresses the stopping condition.\n"
|
||||
" This parameter is optional, you make not want to pass a stopping criterion\n"
|
||||
" when the stopping criterion is already contained in the iterator definition.\n"
|
||||
" :type pred: :class:`UnaryPredicate1D`\n");
|
||||
static PyObject *Operators_bidirectional_chain(BPy_Operators * /*self*/,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"it", "pred", nullptr};
|
||||
PyObject *obj1 = nullptr, *obj2 = nullptr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args,
|
||||
kwds,
|
||||
"O!|O!",
|
||||
(char **)kwlist,
|
||||
&ChainingIterator_Type,
|
||||
&obj1,
|
||||
&UnaryPredicate1D_Type,
|
||||
&obj2))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (!((BPy_ChainingIterator *)obj1)->c_it) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"Operators.bidirectional_chain(): 1st argument: invalid ChainingIterator object");
|
||||
return nullptr;
|
||||
}
|
||||
if (!obj2) {
|
||||
if (Operators::bidirectionalChain(*(((BPy_ChainingIterator *)obj1)->c_it)) < 0) {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Operators.bidirectional_chain() failed");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!((BPy_UnaryPredicate1D *)obj2)->up1D) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"Operators.bidirectional_chain(): 2nd argument: invalid UnaryPredicate1D object");
|
||||
return nullptr;
|
||||
}
|
||||
if (Operators::bidirectionalChain(*(((BPy_ChainingIterator *)obj1)->c_it),
|
||||
*(((BPy_UnaryPredicate1D *)obj2)->up1D)) < 0)
|
||||
{
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Operators.bidirectional_chain() failed");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Operators_sequential_split_doc,
|
||||
".. staticmethod:: sequential_split(*args, **kwargs)\n"
|
||||
"\n"
|
||||
" Accepted call signatures:\n"
|
||||
"\n"
|
||||
" - ``sequential_split(starting_pred, stopping_pred, sampling=0.0)``\n"
|
||||
" - ``sequential_split(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. 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"
|
||||
" .. tip::\n"
|
||||
"\n"
|
||||
" By specifying a starting and stopping predicate allows\n"
|
||||
" the chains to overlap rather than chains partitioning.\n"
|
||||
"\n"
|
||||
" :param starting_pred: The predicate on a point that expresses the\n"
|
||||
" starting condition. Each time this condition is verified, a new chain begins\n"
|
||||
" :type starting_pred: :class:`UnaryPredicate0D`\n"
|
||||
" :param stopping_pred: The predicate on a point that expresses the\n"
|
||||
" stopping condition. The chain ends as soon as this predicate is verified.\n"
|
||||
" :type stopping_pred: :class:`UnaryPredicate0D`\n"
|
||||
" :param pred: The predicate on a point that expresses the splitting condition.\n"
|
||||
" Each time the condition is verified, the chain is split into two chains.\n"
|
||||
" The resulting set of chains is a partition of the initial chain\n"
|
||||
" :type pred: :class:`UnaryPredicate0D`\n"
|
||||
" :param 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");
|
||||
static PyObject *Operators_sequential_split(BPy_Operators * /*self*/,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist_1[] = {"starting_pred", "stopping_pred", "sampling", nullptr};
|
||||
static const char *kwlist_2[] = {"pred", "sampling", nullptr};
|
||||
PyObject *obj1 = nullptr, *obj2 = nullptr;
|
||||
float f = 0.0f;
|
||||
|
||||
if (PyArg_ParseTupleAndKeywords(args,
|
||||
kwds,
|
||||
"O!O!|f",
|
||||
(char **)kwlist_1,
|
||||
&UnaryPredicate0D_Type,
|
||||
&obj1,
|
||||
&UnaryPredicate0D_Type,
|
||||
&obj2,
|
||||
&f))
|
||||
{
|
||||
if (!((BPy_UnaryPredicate0D *)obj1)->up0D) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"Operators.sequential_split(): 1st argument: invalid UnaryPredicate0D object");
|
||||
return nullptr;
|
||||
}
|
||||
if (!((BPy_UnaryPredicate0D *)obj2)->up0D) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"Operators.sequential_split(): 2nd argument: invalid UnaryPredicate0D object");
|
||||
return nullptr;
|
||||
}
|
||||
if (Operators::sequentialSplit(*(((BPy_UnaryPredicate0D *)obj1)->up0D),
|
||||
*(((BPy_UnaryPredicate0D *)obj2)->up0D),
|
||||
f) < 0)
|
||||
{
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Operators.sequential_split() failed");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else if ((void)PyErr_Clear(),
|
||||
(void)(f = 0.0f),
|
||||
PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "O!|f", (char **)kwlist_2, &UnaryPredicate0D_Type, &obj1, &f))
|
||||
{
|
||||
if (!((BPy_UnaryPredicate0D *)obj1)->up0D) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"Operators.sequential_split(): 1st argument: invalid UnaryPredicate0D object");
|
||||
return nullptr;
|
||||
}
|
||||
if (Operators::sequentialSplit(*(((BPy_UnaryPredicate0D *)obj1)->up0D), f) < 0) {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Operators.sequential_split() failed");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
|
||||
return nullptr;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Operators_recursive_split_doc,
|
||||
".. staticmethod:: recursive_split(*args, **kwargs)\n"
|
||||
"\n"
|
||||
" Accepted call signatures:\n"
|
||||
"\n"
|
||||
" - ``recursive_split(func, pred_1d, sampling=0.0)``\n"
|
||||
" - ``recursive_split(func, pred_0d, pred_1d, 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"
|
||||
" The user can also 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.\n"
|
||||
"\n"
|
||||
" :param 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"
|
||||
" :param pred_0d: 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 pred_0d: :class:`UnaryPredicate0D`\n"
|
||||
" :param pred_1d: The Unary Predicate expressing the recursivity stopping\n"
|
||||
" condition. This predicate is evaluated for each curve before it\n"
|
||||
" actually gets split. If pred_1d(chain) is true, the curve won't be\n"
|
||||
" split anymore.\n"
|
||||
" :type pred_1d: :class:`UnaryPredicate1D`\n"
|
||||
" :param 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_recursive_split(BPy_Operators * /*self*/,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist_1[] = {"func", "pred_1d", "sampling", nullptr};
|
||||
static const char *kwlist_2[] = {"func", "pred_0d", "pred_1d", "sampling", nullptr};
|
||||
PyObject *obj1 = nullptr, *obj2 = nullptr, *obj3 = nullptr;
|
||||
float f = 0.0f;
|
||||
|
||||
if (PyArg_ParseTupleAndKeywords(args,
|
||||
kwds,
|
||||
"O!O!|f",
|
||||
(char **)kwlist_1,
|
||||
&UnaryFunction0DDouble_Type,
|
||||
&obj1,
|
||||
&UnaryPredicate1D_Type,
|
||||
&obj2,
|
||||
&f))
|
||||
{
|
||||
if (!((BPy_UnaryFunction0DDouble *)obj1)->uf0D_double) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"Operators.recursive_split(): 1st argument: invalid UnaryFunction0DDouble object");
|
||||
return nullptr;
|
||||
}
|
||||
if (!((BPy_UnaryPredicate1D *)obj2)->up1D) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"Operators.recursive_split(): 2nd argument: invalid UnaryPredicate1D object");
|
||||
return nullptr;
|
||||
}
|
||||
if (Operators::recursiveSplit(*(((BPy_UnaryFunction0DDouble *)obj1)->uf0D_double),
|
||||
*(((BPy_UnaryPredicate1D *)obj2)->up1D),
|
||||
f) < 0)
|
||||
{
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Operators.recursive_split() failed");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else if ((void)PyErr_Clear(),
|
||||
(void)(f = 0.0f),
|
||||
PyArg_ParseTupleAndKeywords(args,
|
||||
kwds,
|
||||
"O!O!O!|f",
|
||||
(char **)kwlist_2,
|
||||
&UnaryFunction0DDouble_Type,
|
||||
&obj1,
|
||||
&UnaryPredicate0D_Type,
|
||||
&obj2,
|
||||
&UnaryPredicate1D_Type,
|
||||
&obj3,
|
||||
&f))
|
||||
{
|
||||
if (!((BPy_UnaryFunction0DDouble *)obj1)->uf0D_double) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"Operators.recursive_split(): 1st argument: invalid UnaryFunction0DDouble object");
|
||||
return nullptr;
|
||||
}
|
||||
if (!((BPy_UnaryPredicate0D *)obj2)->up0D) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"Operators.recursive_split(): 2nd argument: invalid UnaryPredicate0D object");
|
||||
return nullptr;
|
||||
}
|
||||
if (!((BPy_UnaryPredicate1D *)obj3)->up1D) {
|
||||
PyErr_SetString(
|
||||
PyExc_TypeError,
|
||||
"Operators.recursive_split(): 3rd argument: invalid UnaryPredicate1D object");
|
||||
return nullptr;
|
||||
}
|
||||
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.recursive_split() failed");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
|
||||
return nullptr;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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"
|
||||
" :param pred: The binary predicate used for the comparison.\n"
|
||||
" :type pred: :class:`BinaryPredicate1D`\n");
|
||||
static PyObject *Operators_sort(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"pred", nullptr};
|
||||
PyObject *obj = nullptr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "O!", (char **)kwlist, &BinaryPredicate1D_Type, &obj))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (!((BPy_BinaryPredicate1D *)obj)->bp1D) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Operators.sort(): 1st argument: invalid BinaryPredicate1D object");
|
||||
return nullptr;
|
||||
}
|
||||
if (Operators::sort(*(((BPy_BinaryPredicate1D *)obj)->bp1D)) < 0) {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Operators.sort() failed");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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"
|
||||
" :param pred: The predicate that a chain must verify in order to be\n"
|
||||
" transform as a stroke.\n"
|
||||
" :type pred: :class:`UnaryPredicate1D`\n"
|
||||
" :param shaders: The list of shaders used to shade the strokes.\n"
|
||||
" :type shaders: list[:class:`StrokeShader`]\n");
|
||||
static PyObject *Operators_create(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"pred", "shaders", nullptr};
|
||||
PyObject *obj1 = nullptr, *obj2 = nullptr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "O!O!", (char **)kwlist, &UnaryPredicate1D_Type, &obj1, &PyList_Type, &obj2))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (!((BPy_UnaryPredicate1D *)obj1)->up1D) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Operators.create(): 1st argument: invalid UnaryPredicate1D object");
|
||||
return nullptr;
|
||||
}
|
||||
vector<StrokeShader *> shaders;
|
||||
shaders.reserve(PyList_Size(obj2));
|
||||
for (int i = 0; i < PyList_Size(obj2); i++) {
|
||||
PyObject *py_ss = PyList_GET_ITEM(obj2, i);
|
||||
if (!BPy_StrokeShader_Check(py_ss)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Operators.create(): 2nd argument must be a list of StrokeShader objects");
|
||||
return nullptr;
|
||||
}
|
||||
StrokeShader *shader = ((BPy_StrokeShader *)py_ss)->ss;
|
||||
if (!shader) {
|
||||
stringstream ss;
|
||||
ss << "Operators.create(): item " << (i + 1)
|
||||
<< " of the shaders list is invalid likely due to missing call of "
|
||||
"StrokeShader.__init__()";
|
||||
PyErr_SetString(PyExc_TypeError, ss.str().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
shaders.push_back(shader);
|
||||
}
|
||||
if (Operators::create(*(((BPy_UnaryPredicate1D *)obj1)->up1D), shaders) < 0) {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Operators.create() failed");
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Operators_reset_doc,
|
||||
".. staticmethod:: reset(delete_strokes=True)\n"
|
||||
"\n"
|
||||
" Resets the line stylization process to the initial state. The results of\n"
|
||||
" stroke creation are accumulated if **delete_strokes** is set to False.\n"
|
||||
"\n"
|
||||
" :param delete_strokes: Delete the strokes that are currently stored.\n"
|
||||
" :type delete_strokes: bool\n");
|
||||
static PyObject *Operators_reset(BPy_Operators * /*self*/, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"delete_strokes", nullptr};
|
||||
PyObject *obj1 = nullptr;
|
||||
if (PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist, &PyBool_Type, &obj1)) {
|
||||
// true is the default
|
||||
Operators::reset(obj1 ? bool_from_PyBool(obj1) : true);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Operators.reset() failed");
|
||||
return nullptr;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Operators_get_viewedge_from_index_doc,
|
||||
".. staticmethod:: get_viewedge_from_index(i)\n"
|
||||
"\n"
|
||||
" Returns the ViewEdge at the index in the current set of ViewEdges.\n"
|
||||
"\n"
|
||||
" :param i: index (0 <= i < Operators.get_view_edges_size()).\n"
|
||||
" :type i: int\n"
|
||||
" :return: The ViewEdge object.\n"
|
||||
" :rtype: :class:`ViewEdge`\n");
|
||||
static PyObject *Operators_get_viewedge_from_index(BPy_Operators * /*self*/,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"i", nullptr};
|
||||
uint i;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "I", (char **)kwlist, &i)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (i >= Operators::getViewEdgesSize()) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return nullptr;
|
||||
}
|
||||
return BPy_ViewEdge_from_ViewEdge(*(Operators::getViewEdgeFromIndex(i)));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Operators_get_chain_from_index_doc,
|
||||
".. staticmethod:: get_chain_from_index(i)\n"
|
||||
"\n"
|
||||
" Returns the Chain at the index in the current set of Chains.\n"
|
||||
"\n"
|
||||
" :param i: index (0 <= i < Operators.get_chains_size()).\n"
|
||||
" :type i: int\n"
|
||||
" :return: The Chain object.\n"
|
||||
" :rtype: :class:`Chain`\n");
|
||||
static PyObject *Operators_get_chain_from_index(BPy_Operators * /*self*/,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"i", nullptr};
|
||||
uint i;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "I", (char **)kwlist, &i)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (i >= Operators::getChainsSize()) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return nullptr;
|
||||
}
|
||||
return BPy_Chain_from_Chain(*(Operators::getChainFromIndex(i)));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Operators_get_stroke_from_index_doc,
|
||||
".. staticmethod:: get_stroke_from_index(i)\n"
|
||||
"\n"
|
||||
" Returns the Stroke at the index in the current set of Strokes.\n"
|
||||
"\n"
|
||||
" :param i: index (0 <= i < Operators.get_strokes_size()).\n"
|
||||
" :type i: int\n"
|
||||
" :return: The Stroke object.\n"
|
||||
" :rtype: :class:`Stroke`\n");
|
||||
static PyObject *Operators_get_stroke_from_index(BPy_Operators * /*self*/,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"i", nullptr};
|
||||
uint i;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "I", (char **)kwlist, &i)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (i >= Operators::getStrokesSize()) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return nullptr;
|
||||
}
|
||||
return BPy_Stroke_from_Stroke(*(Operators::getStrokeFromIndex(i)));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Operators_get_view_edges_size_doc,
|
||||
".. staticmethod:: get_view_edges_size()\n"
|
||||
"\n"
|
||||
" Returns the number of ViewEdges.\n"
|
||||
"\n"
|
||||
" :return: The number of ViewEdges.\n"
|
||||
" :rtype: int\n");
|
||||
static PyObject *Operators_get_view_edges_size(BPy_Operators * /*self*/)
|
||||
{
|
||||
return PyLong_FromLong(Operators::getViewEdgesSize());
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Operators_get_chains_size_doc,
|
||||
".. staticmethod:: get_chains_size()\n"
|
||||
"\n"
|
||||
" Returns the number of Chains.\n"
|
||||
"\n"
|
||||
" :return: The number of Chains.\n"
|
||||
" :rtype: int\n");
|
||||
static PyObject *Operators_get_chains_size(BPy_Operators * /*self*/)
|
||||
{
|
||||
return PyLong_FromLong(Operators::getChainsSize());
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
Operators_get_strokes_size_doc,
|
||||
".. staticmethod:: get_strokes_size()\n"
|
||||
"\n"
|
||||
" Returns the number of Strokes.\n"
|
||||
"\n"
|
||||
" :return: The number of Strokes.\n"
|
||||
" :rtype: int\n");
|
||||
static PyObject *Operators_get_strokes_size(BPy_Operators * /*self*/)
|
||||
{
|
||||
return PyLong_FromLong(Operators::getStrokesSize());
|
||||
}
|
||||
|
||||
/*----------------------Operators instance definitions ----------------------------*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wcast-function-type"
|
||||
# else
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static PyMethodDef BPy_Operators_methods[] = {
|
||||
{"select",
|
||||
(PyCFunction)Operators_select,
|
||||
METH_VARARGS | METH_KEYWORDS | METH_STATIC,
|
||||
Operators_select_doc},
|
||||
{"chain",
|
||||
(PyCFunction)Operators_chain,
|
||||
METH_VARARGS | METH_KEYWORDS | METH_STATIC,
|
||||
Operators_chain_doc},
|
||||
{"bidirectional_chain",
|
||||
(PyCFunction)Operators_bidirectional_chain,
|
||||
METH_VARARGS | METH_KEYWORDS | METH_STATIC,
|
||||
Operators_bidirectional_chain_doc},
|
||||
{"sequential_split",
|
||||
(PyCFunction)Operators_sequential_split,
|
||||
METH_VARARGS | METH_KEYWORDS | METH_STATIC,
|
||||
Operators_sequential_split_doc},
|
||||
{"recursive_split",
|
||||
(PyCFunction)Operators_recursive_split,
|
||||
METH_VARARGS | METH_KEYWORDS | METH_STATIC,
|
||||
Operators_recursive_split_doc},
|
||||
{"sort",
|
||||
(PyCFunction)Operators_sort,
|
||||
METH_VARARGS | METH_KEYWORDS | METH_STATIC,
|
||||
Operators_sort_doc},
|
||||
{"create",
|
||||
(PyCFunction)Operators_create,
|
||||
METH_VARARGS | METH_KEYWORDS | METH_STATIC,
|
||||
Operators_create_doc},
|
||||
{"reset",
|
||||
(PyCFunction)Operators_reset,
|
||||
METH_VARARGS | METH_KEYWORDS | METH_STATIC,
|
||||
Operators_reset_doc},
|
||||
{"get_viewedge_from_index",
|
||||
(PyCFunction)Operators_get_viewedge_from_index,
|
||||
METH_VARARGS | METH_KEYWORDS | METH_STATIC,
|
||||
Operators_get_viewedge_from_index_doc},
|
||||
{"get_chain_from_index",
|
||||
(PyCFunction)Operators_get_chain_from_index,
|
||||
METH_VARARGS | METH_KEYWORDS | METH_STATIC,
|
||||
Operators_get_chain_from_index_doc},
|
||||
{"get_stroke_from_index",
|
||||
(PyCFunction)Operators_get_stroke_from_index,
|
||||
METH_VARARGS | METH_KEYWORDS | METH_STATIC,
|
||||
Operators_get_stroke_from_index_doc},
|
||||
{"get_view_edges_size",
|
||||
(PyCFunction)Operators_get_view_edges_size,
|
||||
METH_NOARGS | METH_STATIC,
|
||||
Operators_get_view_edges_size_doc},
|
||||
{"get_chains_size",
|
||||
(PyCFunction)Operators_get_chains_size,
|
||||
METH_NOARGS | METH_STATIC,
|
||||
Operators_get_chains_size_doc},
|
||||
{"get_strokes_size",
|
||||
(PyCFunction)Operators_get_strokes_size,
|
||||
METH_NOARGS | METH_STATIC,
|
||||
Operators_get_strokes_size_doc},
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# else
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*-----------------------BPy_Operators type definition ------------------------------*/
|
||||
|
||||
PyTypeObject Operators_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "Operators",
|
||||
/*tp_basicsize*/ sizeof(BPy_Operators),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)Operators_dealloc,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ nullptr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT,
|
||||
/*tp_doc*/ Operators_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ BPy_Operators_methods,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ nullptr,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ nullptr,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,32 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../stroke/Operators.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject Operators_Type;
|
||||
|
||||
#define BPy_Operators_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&Operators_Type))
|
||||
|
||||
/*---------------------------Python BPy_Operators structure definition----------*/
|
||||
struct BPy_Operators {
|
||||
PyObject_HEAD
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_Operators visible prototypes-----------*/
|
||||
|
||||
int Operators_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,338 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_SShape.h"
|
||||
|
||||
#include "BPy_BBox.h"
|
||||
#include "BPy_Convert.h"
|
||||
#include "BPy_Id.h"
|
||||
#include "Interface0D/BPy_SVertex.h"
|
||||
#include "Interface1D/BPy_FEdge.h"
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
#include "../generic/py_capi_utils.hh"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int SShape_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&SShape_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "SShape", (PyObject *)&SShape_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------SShape methods ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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__(*args)\n"
|
||||
"\n"
|
||||
" Accepted call signatures:\n"
|
||||
"\n"
|
||||
" - ``__init__()``\n"
|
||||
" - ``__init__(brother)``\n"
|
||||
"\n"
|
||||
" Creates a :class:`SShape` class using either a default constructor or copy constructor.\n"
|
||||
"\n"
|
||||
" :param brother: An SShape object.\n"
|
||||
" :type brother: :class:`SShape`\n");
|
||||
static int SShape_init(BPy_SShape *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"brother", nullptr};
|
||||
PyObject *brother = nullptr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist, &SShape_Type, &brother)) {
|
||||
return -1;
|
||||
}
|
||||
if (!brother) {
|
||||
self->ss = new SShape();
|
||||
}
|
||||
else {
|
||||
self->ss = new SShape(*(((BPy_SShape *)brother)->ss));
|
||||
}
|
||||
self->borrowed = false;
|
||||
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_add_edge_doc[] =
|
||||
".. method:: add_edge(edge)\n"
|
||||
"\n"
|
||||
" Adds an FEdge to the list of FEdges.\n"
|
||||
"\n"
|
||||
" :param edge: An FEdge object.\n"
|
||||
" :type edge: :class:`FEdge`\n";
|
||||
|
||||
static PyObject *SShape_add_edge(BPy_SShape *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"edge", nullptr};
|
||||
PyObject *py_fe = nullptr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist, &FEdge_Type, &py_fe)) {
|
||||
return nullptr;
|
||||
}
|
||||
self->ss->AddEdge(((BPy_FEdge *)py_fe)->fe);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
SShape_add_vertex_doc,
|
||||
".. method:: add_vertex(vertex)\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"
|
||||
" :param vertex: An SVertex object.\n"
|
||||
" :type vertex: :class:`SVertex`\n");
|
||||
static PyObject *SShape_add_vertex(BPy_SShape *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"edge", nullptr};
|
||||
PyObject *py_sv = nullptr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist, &SVertex_Type, &py_sv)) {
|
||||
return nullptr;
|
||||
}
|
||||
self->ss->AddNewVertex(((BPy_SVertex *)py_sv)->sv);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
SShape_compute_bbox_doc,
|
||||
".. method:: compute_bbox()\n"
|
||||
"\n"
|
||||
" Compute the bbox of the SShape.\n");
|
||||
static PyObject *SShape_compute_bbox(BPy_SShape *self)
|
||||
{
|
||||
self->ss->ComputeBBox();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// const Material & material (uint i) const
|
||||
// const vector< Material > & materials () const
|
||||
// void SetMaterials (const vector< Material > &iMaterials)
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wcast-function-type"
|
||||
# else
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static PyMethodDef BPy_SShape_methods[] = {
|
||||
{"add_edge", (PyCFunction)SShape_add_edge, METH_VARARGS | METH_KEYWORDS, SShape_add_edge_doc},
|
||||
{"add_vertex",
|
||||
(PyCFunction)SShape_add_vertex,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
SShape_add_vertex_doc},
|
||||
{"compute_bbox", (PyCFunction)SShape_compute_bbox, METH_NOARGS, SShape_compute_bbox_doc},
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# else
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*----------------------SShape get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
SShape_id_doc,
|
||||
"The Id of this SShape.\n"
|
||||
"\n"
|
||||
":type: :class:`Id`\n");
|
||||
static PyObject *SShape_id_get(BPy_SShape *self, void * /*closure*/)
|
||||
{
|
||||
Id id(self->ss->getId());
|
||||
return BPy_Id_from_Id(id); // return a copy
|
||||
}
|
||||
|
||||
static int SShape_id_set(BPy_SShape *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
if (!BPy_Id_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be an Id");
|
||||
return -1;
|
||||
}
|
||||
self->ss->setId(*(((BPy_Id *)value)->id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
SShape_name_doc,
|
||||
"The name of the SShape.\n"
|
||||
"\n"
|
||||
":type: str\n");
|
||||
static PyObject *SShape_name_get(BPy_SShape *self, void * /*closure*/)
|
||||
{
|
||||
return blender::PyC_UnicodeFromStdStr(self->ss->getName());
|
||||
}
|
||||
|
||||
static int SShape_name_set(BPy_SShape *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
if (!PyUnicode_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be a string");
|
||||
return -1;
|
||||
}
|
||||
const char *name = PyUnicode_AsUTF8(value);
|
||||
self->ss->setName(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
SShape_bbox_doc,
|
||||
"The bounding box of the SShape.\n"
|
||||
"\n"
|
||||
":type: :class:`BBox`\n");
|
||||
static PyObject *SShape_bbox_get(BPy_SShape *self, void * /*closure*/)
|
||||
{
|
||||
BBox<Vec3r> bb(self->ss->bbox());
|
||||
return BPy_BBox_from_BBox(bb); // return a copy
|
||||
}
|
||||
|
||||
static int SShape_bbox_set(BPy_SShape *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
if (!BPy_BBox_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be a BBox");
|
||||
return -1;
|
||||
}
|
||||
self->ss->setBBox(*(((BPy_BBox *)value)->bb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
SShape_vertices_doc,
|
||||
"The list of vertices constituting this SShape.\n"
|
||||
"\n"
|
||||
":type: list[:class:`SVertex`]\n");
|
||||
static PyObject *SShape_vertices_get(BPy_SShape *self, void * /*closure*/)
|
||||
{
|
||||
|
||||
vector<SVertex *> vertices = self->ss->getVertexList();
|
||||
vector<SVertex *>::iterator it;
|
||||
PyObject *py_vertices = PyList_New(vertices.size());
|
||||
uint i = 0;
|
||||
|
||||
for (it = vertices.begin(); it != vertices.end(); it++) {
|
||||
PyList_SET_ITEM(py_vertices, i++, BPy_SVertex_from_SVertex(*(*it)));
|
||||
}
|
||||
|
||||
return py_vertices;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
SShape_edges_doc,
|
||||
"The list of edges constituting this SShape.\n"
|
||||
"\n"
|
||||
":type: list[:class:`FEdge`]\n");
|
||||
static PyObject *SShape_edges_get(BPy_SShape *self, void * /*closure*/)
|
||||
{
|
||||
|
||||
vector<FEdge *> edges = self->ss->getEdgeList();
|
||||
vector<FEdge *>::iterator it;
|
||||
PyObject *py_edges = PyList_New(edges.size());
|
||||
uint i = 0;
|
||||
|
||||
for (it = edges.begin(); it != edges.end(); it++) {
|
||||
PyList_SET_ITEM(py_edges, i++, Any_BPy_FEdge_from_FEdge(*(*it)));
|
||||
}
|
||||
|
||||
return py_edges;
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_SShape_getseters[] = {
|
||||
{"id", (getter)SShape_id_get, (setter)SShape_id_set, SShape_id_doc, nullptr},
|
||||
{"name", (getter)SShape_name_get, (setter)SShape_name_set, SShape_name_doc, nullptr},
|
||||
{"bbox", (getter)SShape_bbox_get, (setter)SShape_bbox_set, SShape_bbox_doc, nullptr},
|
||||
{"edges", (getter)SShape_edges_get, (setter) nullptr, SShape_edges_doc, nullptr},
|
||||
{"vertices", (getter)SShape_vertices_get, (setter) nullptr, SShape_vertices_doc, nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_SShape type definition ------------------------------*/
|
||||
|
||||
PyTypeObject SShape_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "SShape",
|
||||
/*tp_basicsize*/ sizeof(BPy_SShape),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)SShape_dealloc,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)SShape_repr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ SShape_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ BPy_SShape_methods,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_SShape_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)SShape_init,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../view_map/Silhouette.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject SShape_Type;
|
||||
|
||||
#define BPy_SShape_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&SShape_Type))
|
||||
|
||||
/*---------------------------Python BPy_SShape structure definition----------*/
|
||||
struct BPy_SShape {
|
||||
PyObject_HEAD
|
||||
Freestyle::SShape *ss;
|
||||
bool borrowed; /* true if *ss is a borrowed object */
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_SShape visible prototypes-----------*/
|
||||
|
||||
int SShape_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,750 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_StrokeAttribute.h"
|
||||
|
||||
#include "BPy_Convert.h"
|
||||
|
||||
#include "../generic/py_capi_utils.hh"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int StrokeAttribute_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&StrokeAttribute_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "StrokeAttribute", (PyObject *)&StrokeAttribute_Type);
|
||||
|
||||
StrokeAttribute_mathutils_register_callback();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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__(*args)\n"
|
||||
"\n"
|
||||
" Accepted call signatures:\n"
|
||||
"\n"
|
||||
" - ``__init__()``\n"
|
||||
" - ``__init__(brother)``\n"
|
||||
" - ``__init__(red, green, blue, alpha, thickness_right, thickness_left)``\n"
|
||||
" - ``__init__(attribute1, attribute2, t)``\n"
|
||||
"\n"
|
||||
" Creates a :class:`StrokeAttribute` object using either a default constructor,\n"
|
||||
" copy constructor, overloaded constructor, or and interpolation constructor\n"
|
||||
" to interpolate between two :class:`StrokeAttribute` objects.\n"
|
||||
"\n"
|
||||
" :param brother: A StrokeAttribute object to be used as a copy constructor.\n"
|
||||
" :type brother: :class:`StrokeAttribute`\n"
|
||||
" :param red: Red component of a stroke color.\n"
|
||||
" :type red: float\n"
|
||||
" :param green: Green component of a stroke color.\n"
|
||||
" :type green: float\n"
|
||||
" :param blue: Blue component of a stroke color.\n"
|
||||
" :type blue: float\n"
|
||||
" :param alpha: Alpha component of a stroke color.\n"
|
||||
" :type alpha: float\n"
|
||||
" :param thickness_right: Stroke thickness on the right.\n"
|
||||
" :type thickness_right: float\n"
|
||||
" :param thickness_left: Stroke thickness on the left.\n"
|
||||
" :type thickness_left: float\n"
|
||||
" :param attribute1: The first StrokeAttribute object.\n"
|
||||
" :type attribute1: :class:`StrokeAttribute`\n"
|
||||
" :param attribute2: The second StrokeAttribute object.\n"
|
||||
" :type attribute2: :class:`StrokeAttribute`\n"
|
||||
" :param t: The interpolation parameter (0 <= t <= 1).\n"
|
||||
" :type t: float\n");
|
||||
static int StrokeAttribute_init(BPy_StrokeAttribute *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist_1[] = {"brother", nullptr};
|
||||
static const char *kwlist_2[] = {"attribute1", "attribute2", "t", nullptr};
|
||||
static const char *kwlist_3[] = {
|
||||
"red", "green", "blue", "alpha", "thickness_right", "thickness_left", nullptr};
|
||||
PyObject *obj1 = nullptr, *obj2 = nullptr;
|
||||
float red, green, blue, alpha, thickness_right, thickness_left, t;
|
||||
|
||||
if (PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "|O!", (char **)kwlist_1, &StrokeAttribute_Type, &obj1))
|
||||
{
|
||||
if (!obj1) {
|
||||
self->sa = new StrokeAttribute();
|
||||
}
|
||||
else {
|
||||
self->sa = new StrokeAttribute(*(((BPy_StrokeAttribute *)obj1)->sa));
|
||||
}
|
||||
}
|
||||
else if ((void)PyErr_Clear(),
|
||||
PyArg_ParseTupleAndKeywords(args,
|
||||
kwds,
|
||||
"O!O!f",
|
||||
(char **)kwlist_2,
|
||||
&StrokeAttribute_Type,
|
||||
&obj1,
|
||||
&StrokeAttribute_Type,
|
||||
&obj2,
|
||||
&t))
|
||||
{
|
||||
self->sa = new StrokeAttribute(
|
||||
*(((BPy_StrokeAttribute *)obj1)->sa), *(((BPy_StrokeAttribute *)obj2)->sa), t);
|
||||
}
|
||||
else if ((void)PyErr_Clear(),
|
||||
PyArg_ParseTupleAndKeywords(args,
|
||||
kwds,
|
||||
"ffffff",
|
||||
(char **)kwlist_3,
|
||||
&red,
|
||||
&green,
|
||||
&blue,
|
||||
&alpha,
|
||||
&thickness_right,
|
||||
&thickness_left))
|
||||
{
|
||||
self->sa = new StrokeAttribute(red, green, blue, alpha, thickness_right, thickness_left);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
|
||||
return -1;
|
||||
}
|
||||
self->borrowed = false;
|
||||
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 blender::PyC_UnicodeFromStdStr(repr.str());
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeAttribute_get_attribute_real_doc,
|
||||
".. method:: get_attribute_real(name)\n"
|
||||
"\n"
|
||||
" Returns an attribute of float type.\n"
|
||||
"\n"
|
||||
" :param name: The name of the attribute.\n"
|
||||
" :type name: str\n"
|
||||
" :return: The attribute value.\n"
|
||||
" :rtype: float\n");
|
||||
static PyObject *StrokeAttribute_get_attribute_real(BPy_StrokeAttribute *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"name", nullptr};
|
||||
char *attr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", (char **)kwlist, &attr)) {
|
||||
return nullptr;
|
||||
}
|
||||
double a = self->sa->getAttributeReal(attr);
|
||||
return PyFloat_FromDouble(a);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeAttribute_get_attribute_vec2_doc,
|
||||
".. method:: get_attribute_vec2(name)\n"
|
||||
"\n"
|
||||
" Returns an attribute of two-dimensional vector type.\n"
|
||||
"\n"
|
||||
" :param name: The name of the attribute.\n"
|
||||
" :type name: str\n"
|
||||
" :return: The attribute value.\n"
|
||||
" :rtype: :class:`mathutils.Vector`\n");
|
||||
static PyObject *StrokeAttribute_get_attribute_vec2(BPy_StrokeAttribute *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"name", nullptr};
|
||||
char *attr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", (char **)kwlist, &attr)) {
|
||||
return nullptr;
|
||||
}
|
||||
Vec2f a = self->sa->getAttributeVec2f(attr);
|
||||
return Vector_from_Vec2f(a);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeAttribute_get_attribute_vec3_doc,
|
||||
".. method:: get_attribute_vec3(name)\n"
|
||||
"\n"
|
||||
" Returns an attribute of three-dimensional vector type.\n"
|
||||
"\n"
|
||||
" :param name: The name of the attribute.\n"
|
||||
" :type name: str\n"
|
||||
" :return: The attribute value.\n"
|
||||
" :rtype: :class:`mathutils.Vector`\n");
|
||||
static PyObject *StrokeAttribute_get_attribute_vec3(BPy_StrokeAttribute *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"name", nullptr};
|
||||
char *attr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", (char **)kwlist, &attr)) {
|
||||
return nullptr;
|
||||
}
|
||||
Vec3f a = self->sa->getAttributeVec3f(attr);
|
||||
return Vector_from_Vec3f(a);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeAttribute_has_attribute_real_doc,
|
||||
".. method:: has_attribute_real(name)\n"
|
||||
"\n"
|
||||
" Checks whether the attribute name of float type is available.\n"
|
||||
"\n"
|
||||
" :param name: The name of the attribute.\n"
|
||||
" :type name: str\n"
|
||||
" :return: True if the attribute is available.\n"
|
||||
" :rtype: bool\n");
|
||||
static PyObject *StrokeAttribute_has_attribute_real(BPy_StrokeAttribute *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"name", nullptr};
|
||||
char *attr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", (char **)kwlist, &attr)) {
|
||||
return nullptr;
|
||||
}
|
||||
return PyBool_from_bool(self->sa->isAttributeAvailableReal(attr));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeAttribute_has_attribute_vec2_doc,
|
||||
".. method:: has_attribute_vec2(name)\n"
|
||||
"\n"
|
||||
" Checks whether the attribute name of two-dimensional vector type\n"
|
||||
" is available.\n"
|
||||
"\n"
|
||||
" :param name: The name of the attribute.\n"
|
||||
" :type name: str\n"
|
||||
" :return: True if the attribute is available.\n"
|
||||
" :rtype: bool\n");
|
||||
static PyObject *StrokeAttribute_has_attribute_vec2(BPy_StrokeAttribute *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"name", nullptr};
|
||||
char *attr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", (char **)kwlist, &attr)) {
|
||||
return nullptr;
|
||||
}
|
||||
return PyBool_from_bool(self->sa->isAttributeAvailableVec2f(attr));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeAttribute_has_attribute_vec3_doc,
|
||||
".. method:: has_attribute_vec3(name)\n"
|
||||
"\n"
|
||||
" Checks whether the attribute name of three-dimensional vector\n"
|
||||
" type is available.\n"
|
||||
"\n"
|
||||
" :param name: The name of the attribute.\n"
|
||||
" :type name: str\n"
|
||||
" :return: True if the attribute is available.\n"
|
||||
" :rtype: bool\n");
|
||||
static PyObject *StrokeAttribute_has_attribute_vec3(BPy_StrokeAttribute *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"name", nullptr};
|
||||
char *attr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", (char **)kwlist, &attr)) {
|
||||
return nullptr;
|
||||
}
|
||||
return PyBool_from_bool(self->sa->isAttributeAvailableVec3f(attr));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeAttribute_set_attribute_real_doc,
|
||||
".. method:: set_attribute_real(name, value)\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"
|
||||
" :param name: The name of the attribute.\n"
|
||||
" :type name: str\n"
|
||||
" :param value: The attribute value.\n"
|
||||
" :type value: float\n");
|
||||
static PyObject *StrokeAttribute_set_attribute_real(BPy_StrokeAttribute *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"name", "value", nullptr};
|
||||
char *s = nullptr;
|
||||
double d = 0;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "sd", (char **)kwlist, &s, &d)) {
|
||||
return nullptr;
|
||||
}
|
||||
self->sa->setAttributeReal(s, d);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeAttribute_set_attribute_vec2_doc,
|
||||
".. method:: set_attribute_vec2(name, value)\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"
|
||||
" :param name: The name of the attribute.\n"
|
||||
" :type name: str\n"
|
||||
" :param value: The attribute value.\n"
|
||||
" :type value: :class:`mathutils.Vector` | tuple[float, float, float] | list[float]\n");
|
||||
static PyObject *StrokeAttribute_set_attribute_vec2(BPy_StrokeAttribute *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"name", "value", nullptr};
|
||||
char *s;
|
||||
PyObject *obj = nullptr;
|
||||
Vec2f vec;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO", (char **)kwlist, &s, &obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!Vec2f_ptr_from_PyObject(obj, vec)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"argument 2 must be a 2D vector (either a list of 2 elements or Vector)");
|
||||
return nullptr;
|
||||
}
|
||||
self->sa->setAttributeVec2f(s, vec);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeAttribute_set_attribute_vec3_doc,
|
||||
".. method:: set_attribute_vec3(name, value)\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"
|
||||
" :param name: The name of the attribute.\n"
|
||||
" :type name: str\n"
|
||||
" :param value: The attribute value as a 3D vector.\n"
|
||||
" :type value: :class:`mathutils.Vector` | tuple[float, float, float] | list[float]\n");
|
||||
static PyObject *StrokeAttribute_set_attribute_vec3(BPy_StrokeAttribute *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"name", "value", nullptr};
|
||||
char *s;
|
||||
PyObject *obj = nullptr;
|
||||
Vec3f vec;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO", (char **)kwlist, &s, &obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!Vec3f_ptr_from_PyObject(obj, vec)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"argument 2 must be a 3D vector (either a list of 3 elements or Vector)");
|
||||
return nullptr;
|
||||
}
|
||||
self->sa->setAttributeVec3f(s, vec);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wcast-function-type"
|
||||
# else
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static PyMethodDef BPy_StrokeAttribute_methods[] = {
|
||||
{"get_attribute_real",
|
||||
(PyCFunction)StrokeAttribute_get_attribute_real,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
StrokeAttribute_get_attribute_real_doc},
|
||||
{"get_attribute_vec2",
|
||||
(PyCFunction)StrokeAttribute_get_attribute_vec2,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
StrokeAttribute_get_attribute_vec2_doc},
|
||||
{"get_attribute_vec3",
|
||||
(PyCFunction)StrokeAttribute_get_attribute_vec3,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
StrokeAttribute_get_attribute_vec3_doc},
|
||||
{"has_attribute_real",
|
||||
(PyCFunction)StrokeAttribute_has_attribute_real,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
StrokeAttribute_has_attribute_real_doc},
|
||||
{"has_attribute_vec2",
|
||||
(PyCFunction)StrokeAttribute_has_attribute_vec2,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
StrokeAttribute_has_attribute_vec2_doc},
|
||||
{"has_attribute_vec3",
|
||||
(PyCFunction)StrokeAttribute_has_attribute_vec3,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
StrokeAttribute_has_attribute_vec3_doc},
|
||||
{"set_attribute_real",
|
||||
(PyCFunction)StrokeAttribute_set_attribute_real,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
StrokeAttribute_set_attribute_real_doc},
|
||||
{"set_attribute_vec2",
|
||||
(PyCFunction)StrokeAttribute_set_attribute_vec2,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
StrokeAttribute_set_attribute_vec2_doc},
|
||||
{"set_attribute_vec3",
|
||||
(PyCFunction)StrokeAttribute_set_attribute_vec3,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
StrokeAttribute_set_attribute_vec3_doc},
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# else
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*----------------------mathutils callbacks ----------------------------*/
|
||||
|
||||
/* subtype */
|
||||
#define MATHUTILS_SUBTYPE_COLOR 1
|
||||
#define MATHUTILS_SUBTYPE_THICKNESS 2
|
||||
|
||||
static int StrokeAttribute_mathutils_check(blender::BaseMathObject *bmo)
|
||||
{
|
||||
if (!BPy_StrokeAttribute_Check(bmo->cb_user)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int StrokeAttribute_mathutils_get(blender::BaseMathObject *bmo, int subtype)
|
||||
{
|
||||
BPy_StrokeAttribute *self = (BPy_StrokeAttribute *)bmo->cb_user;
|
||||
switch (subtype) {
|
||||
case MATHUTILS_SUBTYPE_COLOR:
|
||||
bmo->data[0] = self->sa->getColorR();
|
||||
bmo->data[1] = self->sa->getColorG();
|
||||
bmo->data[2] = self->sa->getColorB();
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_THICKNESS:
|
||||
bmo->data[0] = self->sa->getThicknessR();
|
||||
bmo->data[1] = self->sa->getThicknessL();
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int StrokeAttribute_mathutils_set(blender::BaseMathObject *bmo, int subtype)
|
||||
{
|
||||
BPy_StrokeAttribute *self = (BPy_StrokeAttribute *)bmo->cb_user;
|
||||
switch (subtype) {
|
||||
case MATHUTILS_SUBTYPE_COLOR:
|
||||
self->sa->setColor(bmo->data[0], bmo->data[1], bmo->data[2]);
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_THICKNESS:
|
||||
self->sa->setThickness(bmo->data[0], bmo->data[1]);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int StrokeAttribute_mathutils_get_index(blender::BaseMathObject *bmo,
|
||||
int subtype,
|
||||
int index)
|
||||
{
|
||||
BPy_StrokeAttribute *self = (BPy_StrokeAttribute *)bmo->cb_user;
|
||||
switch (subtype) {
|
||||
case MATHUTILS_SUBTYPE_COLOR:
|
||||
switch (index) {
|
||||
case 0:
|
||||
bmo->data[0] = self->sa->getColorR();
|
||||
break;
|
||||
case 1:
|
||||
bmo->data[1] = self->sa->getColorG();
|
||||
break;
|
||||
case 2:
|
||||
bmo->data[2] = self->sa->getColorB();
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case MATHUTILS_SUBTYPE_THICKNESS:
|
||||
switch (index) {
|
||||
case 0:
|
||||
bmo->data[0] = self->sa->getThicknessR();
|
||||
break;
|
||||
case 1:
|
||||
bmo->data[1] = self->sa->getThicknessL();
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int StrokeAttribute_mathutils_set_index(blender::BaseMathObject *bmo,
|
||||
int subtype,
|
||||
int index)
|
||||
{
|
||||
BPy_StrokeAttribute *self = (BPy_StrokeAttribute *)bmo->cb_user;
|
||||
switch (subtype) {
|
||||
case MATHUTILS_SUBTYPE_COLOR: {
|
||||
float r = (index == 0) ? bmo->data[0] : self->sa->getColorR();
|
||||
float g = (index == 1) ? bmo->data[1] : self->sa->getColorG();
|
||||
float b = (index == 2) ? bmo->data[2] : self->sa->getColorB();
|
||||
self->sa->setColor(r, g, b);
|
||||
break;
|
||||
}
|
||||
case MATHUTILS_SUBTYPE_THICKNESS: {
|
||||
float tr = (index == 0) ? bmo->data[0] : self->sa->getThicknessR();
|
||||
float tl = (index == 1) ? bmo->data[1] : self->sa->getThicknessL();
|
||||
self->sa->setThickness(tr, tl);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static blender::Mathutils_Callback StrokeAttribute_mathutils_cb = {
|
||||
StrokeAttribute_mathutils_check,
|
||||
StrokeAttribute_mathutils_get,
|
||||
StrokeAttribute_mathutils_set,
|
||||
StrokeAttribute_mathutils_get_index,
|
||||
StrokeAttribute_mathutils_set_index,
|
||||
};
|
||||
|
||||
static uchar StrokeAttribute_mathutils_cb_index = -1;
|
||||
|
||||
void StrokeAttribute_mathutils_register_callback()
|
||||
{
|
||||
StrokeAttribute_mathutils_cb_index = Mathutils_RegisterCallback(&StrokeAttribute_mathutils_cb);
|
||||
}
|
||||
|
||||
/*----------------------StrokeAttribute get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeAttribute_alpha_doc,
|
||||
"Alpha component of the stroke color.\n"
|
||||
"\n"
|
||||
":type: float\n");
|
||||
static PyObject *StrokeAttribute_alpha_get(BPy_StrokeAttribute *self, void * /*closure*/)
|
||||
{
|
||||
return PyFloat_FromDouble(self->sa->getAlpha());
|
||||
}
|
||||
|
||||
static int StrokeAttribute_alpha_set(BPy_StrokeAttribute *self,
|
||||
PyObject *value,
|
||||
void * /*closure*/)
|
||||
{
|
||||
float scalar;
|
||||
if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) {
|
||||
/* parsed item not a number */
|
||||
PyErr_SetString(PyExc_TypeError, "value must be a number");
|
||||
return -1;
|
||||
}
|
||||
self->sa->setAlpha(scalar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeAttribute_color_doc,
|
||||
"RGB components of the stroke color.\n"
|
||||
"\n"
|
||||
":type: :class:`mathutils.Color`\n");
|
||||
static PyObject *StrokeAttribute_color_get(BPy_StrokeAttribute *self, void * /*closure*/)
|
||||
{
|
||||
return blender::Color_CreatePyObject_cb(
|
||||
(PyObject *)self, StrokeAttribute_mathutils_cb_index, MATHUTILS_SUBTYPE_COLOR);
|
||||
}
|
||||
|
||||
static int StrokeAttribute_color_set(BPy_StrokeAttribute *self,
|
||||
PyObject *value,
|
||||
void * /*closure*/)
|
||||
{
|
||||
float v[3];
|
||||
if (blender::mathutils_array_parse(v, 3, 3, value, "value must be a 3-dimensional vector") == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
self->sa->setColor(v[0], v[1], v[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeAttribute_thickness_doc,
|
||||
"Right and left components of the stroke thickness.\n"
|
||||
"The right (left) component is the thickness on the right (left) of the vertex\n"
|
||||
"when following the stroke.\n"
|
||||
"\n"
|
||||
":type: :class:`mathutils.Vector`\n");
|
||||
static PyObject *StrokeAttribute_thickness_get(BPy_StrokeAttribute *self, void * /*closure*/)
|
||||
{
|
||||
return blender::Vector_CreatePyObject_cb(
|
||||
(PyObject *)self, 2, StrokeAttribute_mathutils_cb_index, MATHUTILS_SUBTYPE_THICKNESS);
|
||||
}
|
||||
|
||||
static int StrokeAttribute_thickness_set(BPy_StrokeAttribute *self,
|
||||
PyObject *value,
|
||||
void * /*closure*/)
|
||||
{
|
||||
float v[2];
|
||||
if (blender::mathutils_array_parse(v, 2, 2, value, "value must be a 2-dimensional vector") == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
self->sa->setThickness(v[0], v[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeAttribute_visible_doc,
|
||||
"The visibility flag. True if the StrokeVertex is visible.\n"
|
||||
"\n"
|
||||
":type: bool\n");
|
||||
static PyObject *StrokeAttribute_visible_get(BPy_StrokeAttribute *self, void * /*closure*/)
|
||||
{
|
||||
return PyBool_from_bool(self->sa->isVisible());
|
||||
}
|
||||
|
||||
static int StrokeAttribute_visible_set(BPy_StrokeAttribute *self,
|
||||
PyObject *value,
|
||||
void * /*closure*/)
|
||||
{
|
||||
if (!PyBool_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be boolean");
|
||||
return -1;
|
||||
}
|
||||
self->sa->setVisible(bool_from_PyBool(value));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_StrokeAttribute_getseters[] = {
|
||||
{"alpha",
|
||||
(getter)StrokeAttribute_alpha_get,
|
||||
(setter)StrokeAttribute_alpha_set,
|
||||
StrokeAttribute_alpha_doc,
|
||||
nullptr},
|
||||
{"color",
|
||||
(getter)StrokeAttribute_color_get,
|
||||
(setter)StrokeAttribute_color_set,
|
||||
StrokeAttribute_color_doc,
|
||||
nullptr},
|
||||
{"thickness",
|
||||
(getter)StrokeAttribute_thickness_get,
|
||||
(setter)StrokeAttribute_thickness_set,
|
||||
StrokeAttribute_thickness_doc,
|
||||
nullptr},
|
||||
{"visible",
|
||||
(getter)StrokeAttribute_visible_get,
|
||||
(setter)StrokeAttribute_visible_set,
|
||||
StrokeAttribute_visible_doc,
|
||||
nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_StrokeAttribute type definition ------------------------------*/
|
||||
|
||||
PyTypeObject StrokeAttribute_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "StrokeAttribute",
|
||||
/*tp_basicsize*/ sizeof(BPy_StrokeAttribute),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)StrokeAttribute_dealloc,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)StrokeAttribute_repr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ StrokeAttribute_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ BPy_StrokeAttribute_methods,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_StrokeAttribute_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)StrokeAttribute_init,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,36 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../stroke/Stroke.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject StrokeAttribute_Type;
|
||||
|
||||
#define BPy_StrokeAttribute_Check(v) \
|
||||
(PyObject_IsInstance((PyObject *)v, (PyObject *)&StrokeAttribute_Type))
|
||||
|
||||
/*---------------------------Python BPy_StrokeAttribute structure definition----------*/
|
||||
struct BPy_StrokeAttribute {
|
||||
PyObject_HEAD
|
||||
Freestyle::StrokeAttribute *sa;
|
||||
bool borrowed; /* true if *sa is a borrowed reference */
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_StrokeAttribute visible prototypes-----------*/
|
||||
|
||||
int StrokeAttribute_Init(PyObject *module);
|
||||
void StrokeAttribute_mathutils_register_callback();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,313 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#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_BlenderTextureShader.h"
|
||||
#include "StrokeShader/BPy_CalligraphicShader.h"
|
||||
#include "StrokeShader/BPy_ColorNoiseShader.h"
|
||||
#include "StrokeShader/BPy_ConstantColorShader.h"
|
||||
#include "StrokeShader/BPy_ConstantThicknessShader.h"
|
||||
#include "StrokeShader/BPy_ConstrainedIncreasingThicknessShader.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_StrokeTextureStepShader.h"
|
||||
#include "StrokeShader/BPy_ThicknessNoiseShader.h"
|
||||
#include "StrokeShader/BPy_TipRemoverShader.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int StrokeShader_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&StrokeShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "StrokeShader", (PyObject *)&StrokeShader_Type);
|
||||
|
||||
if (PyType_Ready(&BackboneStretcherShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(
|
||||
module, "BackboneStretcherShader", (PyObject *)&BackboneStretcherShader_Type);
|
||||
|
||||
if (PyType_Ready(&BezierCurveShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "BezierCurveShader", (PyObject *)&BezierCurveShader_Type);
|
||||
|
||||
if (PyType_Ready(&BlenderTextureShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "BlenderTextureShader", (PyObject *)&BlenderTextureShader_Type);
|
||||
|
||||
if (PyType_Ready(&CalligraphicShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "CalligraphicShader", (PyObject *)&CalligraphicShader_Type);
|
||||
|
||||
if (PyType_Ready(&ColorNoiseShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "ColorNoiseShader", (PyObject *)&ColorNoiseShader_Type);
|
||||
|
||||
if (PyType_Ready(&ConstantColorShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "ConstantColorShader", (PyObject *)&ConstantColorShader_Type);
|
||||
|
||||
if (PyType_Ready(&ConstantThicknessShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(
|
||||
module, "ConstantThicknessShader", (PyObject *)&ConstantThicknessShader_Type);
|
||||
|
||||
if (PyType_Ready(&ConstrainedIncreasingThicknessShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module,
|
||||
"ConstrainedIncreasingThicknessShader",
|
||||
(PyObject *)&ConstrainedIncreasingThicknessShader_Type);
|
||||
|
||||
if (PyType_Ready(&GuidingLinesShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "GuidingLinesShader", (PyObject *)&GuidingLinesShader_Type);
|
||||
|
||||
if (PyType_Ready(&IncreasingColorShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "IncreasingColorShader", (PyObject *)&IncreasingColorShader_Type);
|
||||
|
||||
if (PyType_Ready(&IncreasingThicknessShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(
|
||||
module, "IncreasingThicknessShader", (PyObject *)&IncreasingThicknessShader_Type);
|
||||
|
||||
if (PyType_Ready(&PolygonalizationShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(
|
||||
module, "PolygonalizationShader", (PyObject *)&PolygonalizationShader_Type);
|
||||
|
||||
if (PyType_Ready(&SamplingShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "SamplingShader", (PyObject *)&SamplingShader_Type);
|
||||
|
||||
if (PyType_Ready(&SmoothingShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "SmoothingShader", (PyObject *)&SmoothingShader_Type);
|
||||
|
||||
if (PyType_Ready(&SpatialNoiseShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "SpatialNoiseShader", (PyObject *)&SpatialNoiseShader_Type);
|
||||
|
||||
if (PyType_Ready(&StrokeTextureStepShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(
|
||||
module, "StrokeTextureStepShader", (PyObject *)&StrokeTextureStepShader_Type);
|
||||
|
||||
if (PyType_Ready(&ThicknessNoiseShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "ThicknessNoiseShader", (PyObject *)&ThicknessNoiseShader_Type);
|
||||
|
||||
if (PyType_Ready(&TipRemoverShader_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "TipRemoverShader", (PyObject *)&TipRemoverShader_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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 not it.is_end:\n"
|
||||
" att = it.object.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)
|
||||
{
|
||||
static const char *kwlist[] = {nullptr};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist)) {
|
||||
return -1;
|
||||
}
|
||||
self->ss = new StrokeShader();
|
||||
self->ss->py_ss = (PyObject *)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void StrokeShader___dealloc__(BPy_StrokeShader *self)
|
||||
{
|
||||
delete self->ss;
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
}
|
||||
|
||||
static PyObject *StrokeShader___repr__(BPy_StrokeShader *self)
|
||||
{
|
||||
return PyUnicode_FromFormat("type: %s - address: %p", Py_TYPE(self)->tp_name, self->ss);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeShader_shade___doc__,
|
||||
".. method:: shade(stroke)\n"
|
||||
"\n"
|
||||
" The shading method. Must be overloaded by inherited classes.\n"
|
||||
"\n"
|
||||
" :param stroke: A Stroke object.\n"
|
||||
" :type stroke: :class:`Stroke`\n");
|
||||
static PyObject *StrokeShader_shade(BPy_StrokeShader *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"stroke", nullptr};
|
||||
PyObject *py_s = nullptr;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist, &Stroke_Type, &py_s)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (typeid(*(self->ss)) == typeid(StrokeShader)) {
|
||||
PyErr_SetString(PyExc_TypeError, "shade method not properly overridden");
|
||||
return nullptr;
|
||||
}
|
||||
if (self->ss->shade(*(((BPy_Stroke *)py_s)->s)) < 0) {
|
||||
if (!PyErr_Occurred()) {
|
||||
string class_name(Py_TYPE(self)->tp_name);
|
||||
PyErr_SetString(PyExc_RuntimeError, (class_name + " shade method failed").c_str());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wcast-function-type"
|
||||
# else
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static PyMethodDef BPy_StrokeShader_methods[] = {
|
||||
{"shade",
|
||||
(PyCFunction)StrokeShader_shade,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
StrokeShader_shade___doc__},
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# else
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*----------------------StrokeShader get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
StrokeShader_name_doc,
|
||||
"The name of the stroke shader.\n"
|
||||
"\n"
|
||||
":type: str\n");
|
||||
static PyObject *StrokeShader_name_get(BPy_StrokeShader *self, void * /*closure*/)
|
||||
{
|
||||
return PyUnicode_FromString(Py_TYPE(self)->tp_name);
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_StrokeShader_getseters[] = {
|
||||
{"name", (getter)StrokeShader_name_get, (setter) nullptr, StrokeShader_name_doc, nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_StrokeShader type definition ------------------------------*/
|
||||
|
||||
PyTypeObject StrokeShader_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "StrokeShader",
|
||||
/*tp_basicsize*/ sizeof(BPy_StrokeShader),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)StrokeShader___dealloc__,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)StrokeShader___repr__,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ StrokeShader___doc__,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ BPy_StrokeShader_methods,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_StrokeShader_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)StrokeShader___init__,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,36 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../system/FreestyleConfig.h"
|
||||
|
||||
#include "../stroke/StrokeShader.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject StrokeShader_Type;
|
||||
|
||||
#define BPy_StrokeShader_Check(v) \
|
||||
(PyObject_IsInstance((PyObject *)v, (PyObject *)&StrokeShader_Type))
|
||||
|
||||
/*---------------------------Python BPy_StrokeShader structure definition----------*/
|
||||
struct BPy_StrokeShader {
|
||||
PyObject_HEAD
|
||||
Freestyle::StrokeShader *ss;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_StrokeShader visible prototypes-----------*/
|
||||
|
||||
int StrokeShader_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,150 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#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"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int UnaryFunction0D_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&UnaryFunction0D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(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 ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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");
|
||||
}
|
||||
|
||||
/*----------------------UnaryFunction0D get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
UnaryFunction0D_name_doc,
|
||||
"The name of the unary 0D function.\n"
|
||||
"\n"
|
||||
":type: str\n");
|
||||
static PyObject *UnaryFunction0D_name_get(BPy_UnaryFunction0D *self, void * /*closure*/)
|
||||
{
|
||||
return PyUnicode_FromString(Py_TYPE(self)->tp_name);
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_UnaryFunction0D_getseters[] = {
|
||||
{"name",
|
||||
(getter)UnaryFunction0D_name_get,
|
||||
(setter) nullptr,
|
||||
UnaryFunction0D_name_doc,
|
||||
nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_UnaryFunction0D type definition ------------------------------*/
|
||||
|
||||
PyTypeObject UnaryFunction0D_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "UnaryFunction0D",
|
||||
/*tp_basicsize*/ sizeof(BPy_UnaryFunction0D),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)UnaryFunction0D___dealloc__,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)UnaryFunction0D___repr__,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ UnaryFunction0D___doc__,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ nullptr,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_UnaryFunction0D_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ nullptr,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../view_map/Functions0D.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject UnaryFunction0D_Type;
|
||||
|
||||
#define BPy_UnaryFunction0D_Check(v) \
|
||||
(PyObject_IsInstance((PyObject *)v, (PyObject *)&UnaryFunction0D_Type))
|
||||
|
||||
/*---------------------------Python BPy_UnaryFunction0D structure definition----------*/
|
||||
struct BPy_UnaryFunction0D {
|
||||
PyObject_HEAD
|
||||
PyObject *py_uf0D;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_UnaryFunction0D visible prototypes-----------*/
|
||||
|
||||
int UnaryFunction0D_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,144 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#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"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int UnaryFunction1D_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&UnaryFunction1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(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 ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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");
|
||||
}
|
||||
|
||||
/*----------------------UnaryFunction1D get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
UnaryFunction1D_name_doc,
|
||||
"The name of the unary 1D function.\n"
|
||||
"\n"
|
||||
":type: str\n");
|
||||
static PyObject *UnaryFunction1D_name_get(BPy_UnaryFunction1D *self, void * /*closure*/)
|
||||
{
|
||||
return PyUnicode_FromString(Py_TYPE(self)->tp_name);
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_UnaryFunction1D_getseters[] = {
|
||||
{"name",
|
||||
(getter)UnaryFunction1D_name_get,
|
||||
(setter) nullptr,
|
||||
UnaryFunction1D_name_doc,
|
||||
nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_UnaryFunction1D type definition ------------------------------*/
|
||||
|
||||
PyTypeObject UnaryFunction1D_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "UnaryFunction1D",
|
||||
/*tp_basicsize*/ sizeof(BPy_UnaryFunction1D),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)UnaryFunction1D___dealloc__,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)UnaryFunction1D___repr__,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ UnaryFunction1D___doc__,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ nullptr,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_UnaryFunction1D_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ nullptr,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../view_map/Functions1D.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject UnaryFunction1D_Type;
|
||||
|
||||
#define BPy_UnaryFunction1D_Check(v) \
|
||||
(PyObject_IsInstance((PyObject *)v, (PyObject *)&UnaryFunction1D_Type))
|
||||
|
||||
/*---------------------------Python BPy_UnaryFunction1D structure definition----------*/
|
||||
struct BPy_UnaryFunction1D {
|
||||
PyObject_HEAD
|
||||
PyObject *py_uf1D;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_UnaryFunction1D visible prototypes-----------*/
|
||||
|
||||
int UnaryFunction1D_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,192 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_UnaryPredicate0D.h"
|
||||
|
||||
#include "BPy_Convert.h"
|
||||
#include "Iterator/BPy_Interface0DIterator.h"
|
||||
#include "UnaryPredicate0D/BPy_FalseUP0D.h"
|
||||
#include "UnaryPredicate0D/BPy_TrueUP0D.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int UnaryPredicate0D_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&UnaryPredicate0D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "UnaryPredicate0D", (PyObject *)&UnaryPredicate0D_Type);
|
||||
|
||||
if (PyType_Ready(&FalseUP0D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "FalseUP0D", (PyObject *)&FalseUP0D_Type);
|
||||
|
||||
if (PyType_Ready(&TrueUP0D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "TrueUP0D", (PyObject *)&TrueUP0D_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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"
|
||||
" :param 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)
|
||||
{
|
||||
static const char *kwlist[] = {nullptr};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist)) {
|
||||
return -1;
|
||||
}
|
||||
self->up0D = new UnaryPredicate0D();
|
||||
self->up0D->py_up0D = (PyObject *)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void UnaryPredicate0D___dealloc__(BPy_UnaryPredicate0D *self)
|
||||
{
|
||||
delete self->up0D;
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
}
|
||||
|
||||
static PyObject *UnaryPredicate0D___repr__(BPy_UnaryPredicate0D *self)
|
||||
{
|
||||
return PyUnicode_FromFormat("type: %s - address: %p", Py_TYPE(self)->tp_name, self->up0D);
|
||||
}
|
||||
|
||||
static PyObject *UnaryPredicate0D___call__(BPy_UnaryPredicate0D *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"it", nullptr};
|
||||
PyObject *py_if0D_it;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "O!", (char **)kwlist, &Interface0DIterator_Type, &py_if0D_it))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Interface0DIterator *if0D_it = ((BPy_Interface0DIterator *)py_if0D_it)->if0D_it;
|
||||
|
||||
if (!if0D_it) {
|
||||
string class_name(Py_TYPE(self)->tp_name);
|
||||
PyErr_SetString(PyExc_RuntimeError, (class_name + " has no Interface0DIterator").c_str());
|
||||
return nullptr;
|
||||
}
|
||||
if (typeid(*(self->up0D)) == typeid(UnaryPredicate0D)) {
|
||||
PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
|
||||
return nullptr;
|
||||
}
|
||||
if (self->up0D->operator()(*if0D_it) < 0) {
|
||||
if (!PyErr_Occurred()) {
|
||||
string class_name(Py_TYPE(self)->tp_name);
|
||||
PyErr_SetString(PyExc_RuntimeError, (class_name + " __call__ method failed").c_str());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return PyBool_from_bool(self->up0D->result);
|
||||
}
|
||||
|
||||
/*----------------------UnaryPredicate0D get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
UnaryPredicate0D_name_doc,
|
||||
"The name of the unary 0D predicate.\n"
|
||||
"\n"
|
||||
":type: str\n");
|
||||
static PyObject *UnaryPredicate0D_name_get(BPy_UnaryPredicate0D *self, void * /*closure*/)
|
||||
{
|
||||
return PyUnicode_FromString(Py_TYPE(self)->tp_name);
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_UnaryPredicate0D_getseters[] = {
|
||||
{"name",
|
||||
(getter)UnaryPredicate0D_name_get,
|
||||
(setter) nullptr,
|
||||
UnaryPredicate0D_name_doc,
|
||||
nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_UnaryPredicate0D type definition ------------------------------*/
|
||||
|
||||
PyTypeObject UnaryPredicate0D_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "UnaryPredicate0D",
|
||||
/*tp_basicsize*/ sizeof(BPy_UnaryPredicate0D),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)UnaryPredicate0D___dealloc__,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)UnaryPredicate0D___repr__,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ (ternaryfunc)UnaryPredicate0D___call__,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ UnaryPredicate0D___doc__,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ nullptr,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_UnaryPredicate0D_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)UnaryPredicate0D___init__,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../stroke/Predicates0D.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject UnaryPredicate0D_Type;
|
||||
|
||||
#define BPy_UnaryPredicate0D_Check(v) \
|
||||
(PyObject_IsInstance((PyObject *)v, (PyObject *)&UnaryPredicate0D_Type))
|
||||
|
||||
/*---------------------------Python BPy_UnaryPredicate0D structure definition----------*/
|
||||
struct BPy_UnaryPredicate0D {
|
||||
PyObject_HEAD
|
||||
Freestyle::UnaryPredicate0D *up0D;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_UnaryPredicate0D visible prototypes-----------*/
|
||||
|
||||
int UnaryPredicate0D_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,242 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#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"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int UnaryPredicate1D_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&UnaryPredicate1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "UnaryPredicate1D", (PyObject *)&UnaryPredicate1D_Type);
|
||||
|
||||
if (PyType_Ready(&ContourUP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "ContourUP1D", (PyObject *)&ContourUP1D_Type);
|
||||
|
||||
if (PyType_Ready(&DensityLowerThanUP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "DensityLowerThanUP1D", (PyObject *)&DensityLowerThanUP1D_Type);
|
||||
|
||||
if (PyType_Ready(&EqualToChainingTimeStampUP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(
|
||||
module, "EqualToChainingTimeStampUP1D", (PyObject *)&EqualToChainingTimeStampUP1D_Type);
|
||||
|
||||
if (PyType_Ready(&EqualToTimeStampUP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "EqualToTimeStampUP1D", (PyObject *)&EqualToTimeStampUP1D_Type);
|
||||
|
||||
if (PyType_Ready(&ExternalContourUP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "ExternalContourUP1D", (PyObject *)&ExternalContourUP1D_Type);
|
||||
|
||||
if (PyType_Ready(&FalseUP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "FalseUP1D", (PyObject *)&FalseUP1D_Type);
|
||||
|
||||
if (PyType_Ready(&QuantitativeInvisibilityUP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(
|
||||
module, "QuantitativeInvisibilityUP1D", (PyObject *)&QuantitativeInvisibilityUP1D_Type);
|
||||
|
||||
if (PyType_Ready(&ShapeUP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "ShapeUP1D", (PyObject *)&ShapeUP1D_Type);
|
||||
|
||||
if (PyType_Ready(&TrueUP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "TrueUP1D", (PyObject *)&TrueUP1D_Type);
|
||||
|
||||
if (PyType_Ready(&WithinImageBoundaryUP1D_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(
|
||||
module, "WithinImageBoundaryUP1D", (PyObject *)&WithinImageBoundaryUP1D_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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"
|
||||
" :param 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)
|
||||
{
|
||||
static const char *kwlist[] = {nullptr};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist)) {
|
||||
return -1;
|
||||
}
|
||||
self->up1D = new UnaryPredicate1D();
|
||||
self->up1D->py_up1D = (PyObject *)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void UnaryPredicate1D___dealloc__(BPy_UnaryPredicate1D *self)
|
||||
{
|
||||
delete self->up1D;
|
||||
Py_TYPE(self)->tp_free((PyObject *)self);
|
||||
}
|
||||
|
||||
static PyObject *UnaryPredicate1D___repr__(BPy_UnaryPredicate1D *self)
|
||||
{
|
||||
return PyUnicode_FromFormat("type: %s - address: %p", Py_TYPE(self)->tp_name, self->up1D);
|
||||
}
|
||||
|
||||
static PyObject *UnaryPredicate1D___call__(BPy_UnaryPredicate1D *self,
|
||||
PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"inter", nullptr};
|
||||
PyObject *py_if1D;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist, &Interface1D_Type, &py_if1D))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Interface1D *if1D = ((BPy_Interface1D *)py_if1D)->if1D;
|
||||
|
||||
if (!if1D) {
|
||||
string class_name(Py_TYPE(self)->tp_name);
|
||||
PyErr_SetString(PyExc_RuntimeError, (class_name + " has no Interface1D").c_str());
|
||||
return nullptr;
|
||||
}
|
||||
if (typeid(*(self->up1D)) == typeid(UnaryPredicate1D)) {
|
||||
PyErr_SetString(PyExc_TypeError, "__call__ method not properly overridden");
|
||||
return nullptr;
|
||||
}
|
||||
if (self->up1D->operator()(*if1D) < 0) {
|
||||
if (!PyErr_Occurred()) {
|
||||
string class_name(Py_TYPE(self)->tp_name);
|
||||
PyErr_SetString(PyExc_RuntimeError, (class_name + " __call__ method failed").c_str());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
return PyBool_from_bool(self->up1D->result);
|
||||
}
|
||||
|
||||
/*----------------------UnaryPredicate1D get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
UnaryPredicate1D_name_doc,
|
||||
"The name of the unary 1D predicate.\n"
|
||||
"\n"
|
||||
":type: str\n");
|
||||
static PyObject *UnaryPredicate1D_name_get(BPy_UnaryPredicate1D *self, void * /*closure*/)
|
||||
{
|
||||
return PyUnicode_FromString(Py_TYPE(self)->tp_name);
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_UnaryPredicate1D_getseters[] = {
|
||||
{"name",
|
||||
(getter)UnaryPredicate1D_name_get,
|
||||
(setter) nullptr,
|
||||
UnaryPredicate1D_name_doc,
|
||||
nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_UnaryPredicate1D type definition ------------------------------*/
|
||||
|
||||
PyTypeObject UnaryPredicate1D_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "UnaryPredicate1D",
|
||||
/*tp_basicsize*/ sizeof(BPy_UnaryPredicate1D),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)UnaryPredicate1D___dealloc__,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)UnaryPredicate1D___repr__,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ (ternaryfunc)UnaryPredicate1D___call__,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ UnaryPredicate1D___doc__,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ nullptr,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_UnaryPredicate1D_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)UnaryPredicate1D___init__,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../stroke/Predicates1D.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject UnaryPredicate1D_Type;
|
||||
|
||||
#define BPy_UnaryPredicate1D_Check(v) \
|
||||
(PyObject_IsInstance((PyObject *)v, (PyObject *)&UnaryPredicate1D_Type))
|
||||
|
||||
/*---------------------------Python BPy_UnaryPredicate1D structure definition----------*/
|
||||
struct BPy_UnaryPredicate1D {
|
||||
PyObject_HEAD
|
||||
Freestyle::UnaryPredicate1D *up1D;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_UnaryPredicate1D visible prototypes-----------*/
|
||||
|
||||
int UnaryPredicate1D_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,230 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_ViewMap.h"
|
||||
|
||||
#include "BPy_BBox.h"
|
||||
#include "BPy_Convert.h"
|
||||
#include "Interface1D/BPy_FEdge.h"
|
||||
#include "Interface1D/BPy_ViewEdge.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
int ViewMap_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&ViewMap_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "ViewMap", (PyObject *)&ViewMap_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------ViewMap methods----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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)
|
||||
{
|
||||
static const char *kwlist[] = {nullptr};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist)) {
|
||||
return -1;
|
||||
}
|
||||
self->vm = new ViewMap();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ViewMap_dealloc(BPy_ViewMap *self)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ViewMap_get_closest_viewedge_doc,
|
||||
".. method:: get_closest_viewedge(x, y)\n"
|
||||
"\n"
|
||||
" Gets the ViewEdge nearest to the 2D point specified as arguments.\n"
|
||||
"\n"
|
||||
" :param x: X coordinate of a 2D point.\n"
|
||||
" :type x: float\n"
|
||||
" :param 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_get_closest_viewedge(BPy_ViewMap *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"x", "y", nullptr};
|
||||
double x, y;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "dd", (char **)kwlist, &x, &y)) {
|
||||
return nullptr;
|
||||
}
|
||||
ViewEdge *ve = const_cast<ViewEdge *>(self->vm->getClosestViewEdge(x, y));
|
||||
if (ve) {
|
||||
return BPy_ViewEdge_from_ViewEdge(*ve);
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ViewMap_get_closest_fedge_doc,
|
||||
".. method:: get_closest_fedge(x, y)\n"
|
||||
"\n"
|
||||
" Gets the FEdge nearest to the 2D point specified as arguments.\n"
|
||||
"\n"
|
||||
" :param x: X coordinate of a 2D point.\n"
|
||||
" :type x: float\n"
|
||||
" :param 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_get_closest_fedge(BPy_ViewMap *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"x", "y", nullptr};
|
||||
double x, y;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "dd", (char **)kwlist, &x, &y)) {
|
||||
return nullptr;
|
||||
}
|
||||
FEdge *fe = const_cast<FEdge *>(self->vm->getClosestFEdge(x, y));
|
||||
if (fe) {
|
||||
return Any_BPy_FEdge_from_FEdge(*fe);
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// static ViewMap *getInstance ();
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wcast-function-type"
|
||||
# else
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static PyMethodDef BPy_ViewMap_methods[] = {
|
||||
{"get_closest_viewedge",
|
||||
(PyCFunction)ViewMap_get_closest_viewedge,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
ViewMap_get_closest_viewedge_doc},
|
||||
{"get_closest_fedge",
|
||||
(PyCFunction)ViewMap_get_closest_fedge,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
ViewMap_get_closest_fedge_doc},
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# else
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*----------------------ViewMap get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ViewMap_scene_bbox_doc,
|
||||
"The 3D bounding box of the scene.\n"
|
||||
"\n"
|
||||
":type: :class:`BBox`\n");
|
||||
static PyObject *ViewMap_scene_bbox_get(BPy_ViewMap *self, void * /*closure*/)
|
||||
{
|
||||
return BPy_BBox_from_BBox(self->vm->getScene3dBBox());
|
||||
}
|
||||
|
||||
static int ViewMap_scene_bbox_set(BPy_ViewMap *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
if (!BPy_BBox_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be a BBox");
|
||||
return -1;
|
||||
}
|
||||
self->vm->setScene3dBBox(*(((BPy_BBox *)value)->bb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_ViewMap_getseters[] = {
|
||||
{"scene_bbox",
|
||||
(getter)ViewMap_scene_bbox_get,
|
||||
(setter)ViewMap_scene_bbox_set,
|
||||
ViewMap_scene_bbox_doc,
|
||||
nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_ViewMap type definition ------------------------------*/
|
||||
|
||||
PyTypeObject ViewMap_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "ViewMap",
|
||||
/*tp_basicsize*/ sizeof(BPy_ViewMap),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)ViewMap_dealloc,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)ViewMap_repr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ ViewMap_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ BPy_ViewMap_methods,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_ViewMap_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)ViewMap_init,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,33 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../view_map/ViewMap.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject ViewMap_Type;
|
||||
|
||||
#define BPy_ViewMap_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&ViewMap_Type))
|
||||
|
||||
/*---------------------------Python BPy_ViewMap structure definition----------*/
|
||||
struct BPy_ViewMap {
|
||||
PyObject_HEAD
|
||||
Freestyle::ViewMap *vm;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_ViewMap visible prototypes-----------*/
|
||||
|
||||
int ViewMap_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,413 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_ViewShape.h"
|
||||
|
||||
#include "BPy_Convert.h"
|
||||
#include "BPy_SShape.h"
|
||||
#include "Interface0D/BPy_ViewVertex.h"
|
||||
#include "Interface1D/BPy_ViewEdge.h"
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
#include "../generic/py_capi_utils.hh"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//-------------------MODULE INITIALIZATION--------------------------------
|
||||
|
||||
int ViewShape_Init(PyObject *module)
|
||||
{
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (PyType_Ready(&ViewShape_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyModule_AddObjectRef(module, "ViewShape", (PyObject *)&ViewShape_Type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------ViewShape methods ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
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__(*args)\n"
|
||||
"\n"
|
||||
" Accepted call signatures:\n"
|
||||
"\n"
|
||||
" - ``__init__()``\n"
|
||||
" - ``__init__(brother)``\n"
|
||||
" - ``__init__(sshape)``\n"
|
||||
"\n"
|
||||
" Builds a :class:`ViewShape` using the default constructor,\n"
|
||||
" copy constructor, or from a :class:`SShape`.\n"
|
||||
"\n"
|
||||
" :param brother: A ViewShape object.\n"
|
||||
" :type brother: :class:`ViewShape`\n"
|
||||
" :param sshape: An SShape object.\n"
|
||||
" :type sshape: :class:`SShape`\n");
|
||||
static int ViewShape_init(BPy_ViewShape *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist_1[] = {"brother", nullptr};
|
||||
static const char *kwlist_2[] = {"sshape", nullptr};
|
||||
PyObject *obj = nullptr;
|
||||
|
||||
if (PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist_1, &ViewShape_Type, &obj)) {
|
||||
if (!obj) {
|
||||
self->vs = new ViewShape();
|
||||
self->py_ss = nullptr;
|
||||
}
|
||||
else {
|
||||
self->vs = new ViewShape(*(((BPy_ViewShape *)obj)->vs));
|
||||
self->py_ss = ((BPy_ViewShape *)obj)->py_ss;
|
||||
}
|
||||
}
|
||||
else if ((void)PyErr_Clear(),
|
||||
PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_2, &SShape_Type, &obj))
|
||||
{
|
||||
BPy_SShape *py_ss = (BPy_SShape *)obj;
|
||||
self->vs = new ViewShape(py_ss->ss);
|
||||
self->py_ss = (!py_ss->borrowed) ? py_ss : nullptr;
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
|
||||
return -1;
|
||||
}
|
||||
self->borrowed = false;
|
||||
Py_XINCREF(self->py_ss);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ViewShape_dealloc(BPy_ViewShape *self)
|
||||
{
|
||||
if (self->py_ss) {
|
||||
self->vs->setSShape((SShape *)nullptr);
|
||||
Py_DECREF(self->py_ss);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ViewShape_add_edge_doc,
|
||||
".. method:: add_edge(edge)\n"
|
||||
"\n"
|
||||
" Adds a ViewEdge to the list of ViewEdge objects.\n"
|
||||
"\n"
|
||||
" :param edge: A ViewEdge object.\n"
|
||||
" :type edge: :class:`ViewEdge`\n");
|
||||
static PyObject *ViewShape_add_edge(BPy_ViewShape *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"edge", nullptr};
|
||||
PyObject *py_ve = nullptr;
|
||||
|
||||
if (PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist, &ViewEdge_Type, &py_ve)) {
|
||||
return nullptr;
|
||||
}
|
||||
self->vs->AddEdge(((BPy_ViewEdge *)py_ve)->ve);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ViewShape_add_vertex_doc,
|
||||
".. method:: add_vertex(vertex)\n"
|
||||
"\n"
|
||||
" Adds a ViewVertex to the list of the ViewVertex objects.\n"
|
||||
"\n"
|
||||
" :param vertex: A ViewVertex object.\n"
|
||||
" :type vertex: :class:`ViewVertex`\n");
|
||||
static PyObject *ViewShape_add_vertex(BPy_ViewShape *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {"vertex", nullptr};
|
||||
PyObject *py_vv = nullptr;
|
||||
|
||||
if (PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist, &ViewVertex_Type, &py_vv)) {
|
||||
return nullptr;
|
||||
}
|
||||
self->vs->AddVertex(((BPy_ViewVertex *)py_vv)->vv);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
// virtual ViewShape *duplicate()
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wcast-function-type"
|
||||
# else
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static PyMethodDef BPy_ViewShape_methods[] = {
|
||||
{"add_edge",
|
||||
(PyCFunction)ViewShape_add_edge,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
ViewShape_add_edge_doc},
|
||||
{"add_vertex",
|
||||
(PyCFunction)ViewShape_add_vertex,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
ViewShape_add_vertex_doc},
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
# else
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*----------------------ViewShape get/setters ----------------------------*/
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ViewShape_sshape_doc,
|
||||
"The SShape on top of which this ViewShape is built.\n"
|
||||
"\n"
|
||||
":type: :class:`SShape`\n");
|
||||
static PyObject *ViewShape_sshape_get(BPy_ViewShape *self, void * /*closure*/)
|
||||
{
|
||||
SShape *ss = self->vs->sshape();
|
||||
if (!ss) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
return BPy_SShape_from_SShape(*ss);
|
||||
}
|
||||
|
||||
static int ViewShape_sshape_set(BPy_ViewShape *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
if (!BPy_SShape_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be an SShape");
|
||||
return -1;
|
||||
}
|
||||
BPy_SShape *py_ss = (BPy_SShape *)value;
|
||||
self->vs->setSShape(py_ss->ss);
|
||||
if (self->py_ss) {
|
||||
Py_DECREF(self->py_ss);
|
||||
}
|
||||
if (!py_ss->borrowed) {
|
||||
self->py_ss = py_ss;
|
||||
Py_INCREF(self->py_ss);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ViewShape_vertices_doc,
|
||||
"The list of ViewVertex objects contained in this ViewShape.\n"
|
||||
"\n"
|
||||
":type: list[:class:`ViewVertex`]\n");
|
||||
static PyObject *ViewShape_vertices_get(BPy_ViewShape *self, void * /*closure*/)
|
||||
{
|
||||
vector<ViewVertex *> vertices = self->vs->vertices();
|
||||
vector<ViewVertex *>::iterator it;
|
||||
PyObject *py_vertices = PyList_New(vertices.size());
|
||||
uint i = 0;
|
||||
|
||||
for (it = vertices.begin(); it != vertices.end(); it++) {
|
||||
PyList_SET_ITEM(py_vertices, i++, Any_BPy_ViewVertex_from_ViewVertex(*(*it)));
|
||||
}
|
||||
return py_vertices;
|
||||
}
|
||||
|
||||
static int ViewShape_vertices_set(BPy_ViewShape *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
PyObject *item;
|
||||
vector<ViewVertex *> v;
|
||||
|
||||
if (!PyList_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be a list of ViewVertex objects");
|
||||
return -1;
|
||||
}
|
||||
|
||||
v.reserve(PyList_GET_SIZE(value));
|
||||
for (uint i = 0; i < PyList_GET_SIZE(value); i++) {
|
||||
item = PyList_GET_ITEM(value, i);
|
||||
if (BPy_ViewVertex_Check(item)) {
|
||||
v.push_back(((BPy_ViewVertex *)item)->vv);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be a list of ViewVertex objects");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
self->vs->setVertices(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ViewShape_edges_doc,
|
||||
"The list of ViewEdge objects contained in this ViewShape.\n"
|
||||
"\n"
|
||||
":type: list[:class:`ViewEdge`]\n");
|
||||
static PyObject *ViewShape_edges_get(BPy_ViewShape *self, void * /*closure*/)
|
||||
{
|
||||
vector<ViewEdge *> edges = self->vs->edges();
|
||||
vector<ViewEdge *>::iterator it;
|
||||
PyObject *py_edges = PyList_New(edges.size());
|
||||
uint i = 0;
|
||||
|
||||
for (it = edges.begin(); it != edges.end(); it++) {
|
||||
PyList_SET_ITEM(py_edges, i++, BPy_ViewEdge_from_ViewEdge(*(*it)));
|
||||
}
|
||||
return py_edges;
|
||||
}
|
||||
|
||||
static int ViewShape_edges_set(BPy_ViewShape *self, PyObject *value, void * /*closure*/)
|
||||
{
|
||||
PyObject *item;
|
||||
vector<ViewEdge *> v;
|
||||
|
||||
if (!PyList_Check(value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "value must be a list of ViewEdge objects");
|
||||
return -1;
|
||||
}
|
||||
|
||||
v.reserve(PyList_GET_SIZE(value));
|
||||
for (int i = 0; i < PyList_GET_SIZE(value); i++) {
|
||||
item = PyList_GET_ITEM(value, i);
|
||||
if (BPy_ViewEdge_Check(item)) {
|
||||
v.push_back(((BPy_ViewEdge *)item)->ve);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError, "argument must be list of ViewEdge objects");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
self->vs->setEdges(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ViewShape_name_doc,
|
||||
"The name of the ViewShape.\n"
|
||||
"\n"
|
||||
":type: str\n");
|
||||
static PyObject *ViewShape_name_get(BPy_ViewShape *self, void * /*closure*/)
|
||||
{
|
||||
return blender::PyC_UnicodeFromStdStr(self->vs->getName());
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ViewShape_library_path_doc,
|
||||
"The library path of the ViewShape, or None if the ViewShape is not part of\n"
|
||||
"a library.\n"
|
||||
"\n"
|
||||
":type: str | None\n");
|
||||
static PyObject *ViewShape_library_path_get(BPy_ViewShape *self, void * /*closure*/)
|
||||
{
|
||||
return blender::PyC_UnicodeFromStdStr(self->vs->getLibraryPath());
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
ViewShape_id_doc,
|
||||
"The Id of this ViewShape.\n"
|
||||
"\n"
|
||||
":type: :class:`Id`\n");
|
||||
static PyObject *ViewShape_id_get(BPy_ViewShape *self, void * /*closure*/)
|
||||
{
|
||||
Id id(self->vs->getId());
|
||||
return BPy_Id_from_Id(id); // return a copy
|
||||
}
|
||||
|
||||
static PyGetSetDef BPy_ViewShape_getseters[] = {
|
||||
{"sshape",
|
||||
(getter)ViewShape_sshape_get,
|
||||
(setter)ViewShape_sshape_set,
|
||||
ViewShape_sshape_doc,
|
||||
nullptr},
|
||||
{"vertices",
|
||||
(getter)ViewShape_vertices_get,
|
||||
(setter)ViewShape_vertices_set,
|
||||
ViewShape_vertices_doc,
|
||||
nullptr},
|
||||
{"edges",
|
||||
(getter)ViewShape_edges_get,
|
||||
(setter)ViewShape_edges_set,
|
||||
ViewShape_edges_doc,
|
||||
nullptr},
|
||||
{"name", (getter)ViewShape_name_get, (setter) nullptr, ViewShape_name_doc, nullptr},
|
||||
{"library_path",
|
||||
(getter)ViewShape_library_path_get,
|
||||
(setter) nullptr,
|
||||
ViewShape_library_path_doc,
|
||||
nullptr},
|
||||
{"id", (getter)ViewShape_id_get, (setter) nullptr, ViewShape_id_doc, nullptr},
|
||||
{nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
|
||||
};
|
||||
|
||||
/*-----------------------BPy_ViewShape type definition ------------------------------*/
|
||||
|
||||
PyTypeObject ViewShape_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "ViewShape",
|
||||
/*tp_basicsize*/ sizeof(BPy_ViewShape),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ (destructor)ViewShape_dealloc,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ (reprfunc)ViewShape_repr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ ViewShape_doc,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ BPy_ViewShape_methods,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ BPy_ViewShape_getseters,
|
||||
/*tp_base*/ nullptr,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)ViewShape_init,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ PyType_GenericNew,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,37 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#include <Python.h>
|
||||
}
|
||||
|
||||
#include "../view_map/ViewMap.h"
|
||||
|
||||
#include "BPy_SShape.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern PyTypeObject ViewShape_Type;
|
||||
|
||||
#define BPy_ViewShape_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&ViewShape_Type))
|
||||
|
||||
/*---------------------------Python BPy_ViewShape structure definition----------*/
|
||||
struct BPy_ViewShape {
|
||||
PyObject_HEAD
|
||||
Freestyle::ViewShape *vs;
|
||||
bool borrowed; /* true if *vs a borrowed object */
|
||||
BPy_SShape *py_ss;
|
||||
};
|
||||
|
||||
/*---------------------------Python BPy_ViewShape visible prototypes-----------*/
|
||||
|
||||
int ViewShape_Init(PyObject *module);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,86 @@
|
||||
/* SPDX-FileCopyrightText: 2004-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup freestyle
|
||||
*/
|
||||
|
||||
#include "BPy_FalseBP1D.h"
|
||||
|
||||
using namespace Freestyle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//------------------------INSTANCE METHODS ----------------------------------
|
||||
|
||||
PyDoc_STRVAR(
|
||||
/* Wrap. */
|
||||
FalseBP1D___doc__,
|
||||
"Class hierarchy: :class:`freestyle.types.BinaryPredicate1D` > :class:`FalseBP1D`\n"
|
||||
"\n"
|
||||
".. method:: __call__(inter1, inter2)\n"
|
||||
"\n"
|
||||
" Always returns false.\n"
|
||||
"\n"
|
||||
" :param inter1: The first Interface1D object.\n"
|
||||
" :type inter1: :class:`freestyle.types.Interface1D`\n"
|
||||
" :param inter2: The second Interface1D object.\n"
|
||||
" :type inter2: :class:`freestyle.types.Interface1D`\n"
|
||||
" :return: False.\n"
|
||||
" :rtype: bool\n");
|
||||
static int FalseBP1D___init__(BPy_FalseBP1D *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
static const char *kwlist[] = {nullptr};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist)) {
|
||||
return -1;
|
||||
}
|
||||
self->py_bp1D.bp1D = new Predicates1D::FalseBP1D();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------BPy_FalseBP1D type definition ------------------------------*/
|
||||
|
||||
PyTypeObject FalseBP1D_Type = {
|
||||
/*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
|
||||
/*tp_name*/ "FalseBP1D",
|
||||
/*tp_basicsize*/ sizeof(BPy_FalseBP1D),
|
||||
/*tp_itemsize*/ 0,
|
||||
/*tp_dealloc*/ nullptr,
|
||||
/*tp_vectorcall_offset*/ 0,
|
||||
/*tp_getattr*/ nullptr,
|
||||
/*tp_setattr*/ nullptr,
|
||||
/*tp_as_async*/ nullptr,
|
||||
/*tp_repr*/ nullptr,
|
||||
/*tp_as_number*/ nullptr,
|
||||
/*tp_as_sequence*/ nullptr,
|
||||
/*tp_as_mapping*/ nullptr,
|
||||
/*tp_hash*/ nullptr,
|
||||
/*tp_call*/ nullptr,
|
||||
/*tp_str*/ nullptr,
|
||||
/*tp_getattro*/ nullptr,
|
||||
/*tp_setattro*/ nullptr,
|
||||
/*tp_as_buffer*/ nullptr,
|
||||
/*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
/*tp_doc*/ FalseBP1D___doc__,
|
||||
/*tp_traverse*/ nullptr,
|
||||
/*tp_clear*/ nullptr,
|
||||
/*tp_richcompare*/ nullptr,
|
||||
/*tp_weaklistoffset*/ 0,
|
||||
/*tp_iter*/ nullptr,
|
||||
/*tp_iternext*/ nullptr,
|
||||
/*tp_methods*/ nullptr,
|
||||
/*tp_members*/ nullptr,
|
||||
/*tp_getset*/ nullptr,
|
||||
/*tp_base*/ &BinaryPredicate1D_Type,
|
||||
/*tp_dict*/ nullptr,
|
||||
/*tp_descr_get*/ nullptr,
|
||||
/*tp_descr_set*/ nullptr,
|
||||
/*tp_dictoffset*/ 0,
|
||||
/*tp_init*/ (initproc)FalseBP1D___init__,
|
||||
/*tp_alloc*/ nullptr,
|
||||
/*tp_new*/ nullptr,
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user