diff --git a/release/scripts/freestyle/style_modules/parameter_editor.py b/release/scripts/freestyle/style_modules/parameter_editor.py index e817771732a..71d55e9a541 100644 --- a/release/scripts/freestyle/style_modules/parameter_editor.py +++ b/release/scripts/freestyle/style_modules/parameter_editor.py @@ -762,6 +762,8 @@ class RoundCapShader(StrokeShader): r = self.round_cap_thickness((nverts_end - i + 1) * n) stroke[-i-1].setAttribute(attr) stroke[-i-1].attribute().setThickness(R * r, L * r) + # update the curvilinear 2D length of each vertex + stroke.UpdateLength() class SquareCapShader(StrokeShader): def shade(self, stroke): @@ -798,24 +800,26 @@ class SquareCapShader(StrokeShader): d = p - q stroke[-1].setPoint(p + d / d.length * caplen_beg) stroke[-1].setAttribute(attr) + # update the curvilinear 2D length of each vertex + stroke.UpdateLength() -# dashed line +# Split by dashed line pattern -class DashedLineStartingUP0D(UnaryPredicate0D): +class SplitPatternStartingUP0D(UnaryPredicate0D): def __init__(self, controller): UnaryPredicate0D.__init__(self) self._controller = controller def __call__(self, inter): return self._controller.start() -class DashedLineStoppingUP0D(UnaryPredicate0D): +class SplitPatternStoppingUP0D(UnaryPredicate0D): def __init__(self, controller): UnaryPredicate0D.__init__(self) self._controller = controller def __call__(self, inter): return self._controller.stop() -class DashedLineController: +class SplitPatternController: def __init__(self, pattern, sampling): self.sampling = float(sampling) k = len(pattern) // 2 @@ -845,6 +849,35 @@ class DashedLineController: return True return False +# Dashed line + +class DashedLineShader(StrokeShader): + def __init__(self, pattern): + StrokeShader.__init__(self) + self._pattern = pattern + def getName(self): + return "DashedLineShader" + def shade(self, stroke): + index = 0 # pattern index + start = 0.0 # 2D curvilinear length + visible = True + sampling = 1.0 + it = stroke.strokeVerticesBegin(sampling) + while not it.isEnd(): + pos = it.t() + # The extra 'sampling' term is added below, because the + # visibility attribute of the i-th vertex refers to the + # visibility of the stroke segment between the i-th and + # (i+1)-th vertices. + if pos - start + sampling > self._pattern[index]: + start = pos + index += 1 + if index == len(self._pattern): + index = 0 + visible = not visible + it.getObject().attribute().setVisible(visible) + it.increment() + # predicates for chaining class AngleLargerThanBP1D(BinaryPredicate1D): @@ -1117,29 +1150,28 @@ def process(layer_name, lineset_name): Operators.sequentialSplit(Curvature2DAngleThresholdUP0D(min_angle, max_angle)) if linestyle.use_split_length: Operators.sequentialSplit(Length2DThresholdUP0D(linestyle.split_length), 1.0) + if linestyle.use_split_pattern: + pattern = [] + if linestyle.split_dash1 > 0 and linestyle.split_gap1 > 0: + pattern.append(linestyle.split_dash1) + pattern.append(linestyle.split_gap1) + if linestyle.split_dash2 > 0 and linestyle.split_gap2 > 0: + pattern.append(linestyle.split_dash2) + pattern.append(linestyle.split_gap2) + if linestyle.split_dash3 > 0 and linestyle.split_gap3 > 0: + pattern.append(linestyle.split_dash3) + pattern.append(linestyle.split_gap3) + if len(pattern) > 0: + sampling = 1.0 + controller = SplitPatternController(pattern, sampling) + Operators.sequentialSplit(SplitPatternStartingUP0D(controller), + SplitPatternStoppingUP0D(controller), + sampling) # select chains if linestyle.use_min_length or linestyle.use_max_length: min_length = linestyle.min_length if linestyle.use_min_length else None max_length = linestyle.max_length if linestyle.use_max_length else None Operators.select(LengthThresholdUP1D(min_length, max_length)) - # dashed line - if linestyle.use_dashed_line: - pattern = [] - if linestyle.dash1 > 0 and linestyle.gap1 > 0: - pattern.append(linestyle.dash1) - pattern.append(linestyle.gap1) - if linestyle.dash2 > 0 and linestyle.gap2 > 0: - pattern.append(linestyle.dash2) - pattern.append(linestyle.gap2) - if linestyle.dash3 > 0 and linestyle.gap3 > 0: - pattern.append(linestyle.dash3) - pattern.append(linestyle.gap3) - if len(pattern) > 0: - sampling = 1.0 - controller = DashedLineController(pattern, sampling) - Operators.sequentialSplit(DashedLineStartingUP0D(controller), - DashedLineStoppingUP0D(controller), - sampling) # prepare a list of stroke shaders shaders_list = [] for m in linestyle.geometry_modifiers: @@ -1269,5 +1301,18 @@ def process(layer_name, lineset_name): shaders_list.append(RoundCapShader()) elif linestyle.caps == "SQUARE": shaders_list.append(SquareCapShader()) + if linestyle.use_dashed_line: + pattern = [] + if linestyle.dash1 > 0 and linestyle.gap1 > 0: + pattern.append(linestyle.dash1) + pattern.append(linestyle.gap1) + if linestyle.dash2 > 0 and linestyle.gap2 > 0: + pattern.append(linestyle.dash2) + pattern.append(linestyle.gap2) + if linestyle.dash3 > 0 and linestyle.gap3 > 0: + pattern.append(linestyle.dash3) + pattern.append(linestyle.gap3) + if len(pattern) > 0: + shaders_list.append(DashedLineShader(pattern)) # create strokes using the shaders list Operators.create(TrueUP1D(), shaders_list) diff --git a/release/scripts/startup/bl_ui/properties_render_layer.py b/release/scripts/startup/bl_ui/properties_render_layer.py index 940d5f0d631..631c636a783 100644 --- a/release/scripts/startup/bl_ui/properties_render_layer.py +++ b/release/scripts/startup/bl_ui/properties_render_layer.py @@ -620,6 +620,7 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerButtonsPanel, Panel): subsub = sub.row() subsub.enabled = linestyle.use_max_angle subsub.prop(linestyle, "max_angle") + col.prop(linestyle, "use_split_pattern", text="Split Pattern") col = row.column() sub = col.row(align=True) sub.prop(linestyle, "use_split_length", text="") @@ -627,6 +628,15 @@ class RENDERLAYER_PT_freestyle_linestyle(RenderLayerButtonsPanel, Panel): subsub.enabled = linestyle.use_split_length subsub.prop(linestyle, "split_length", text="2D Length") col.prop(linestyle, "material_boundary") + row = layout.row(align=True) + row.enabled = linestyle.use_split_pattern + row.prop(linestyle, "split_dash1") + row.prop(linestyle, "split_gap1") + row.prop(linestyle, "split_dash2") + row.prop(linestyle, "split_gap2") + row.prop(linestyle, "split_dash3") + row.prop(linestyle, "split_gap3") + # Selection layout.label(text="Selection:") row = layout.row() diff --git a/source/blender/makesdna/DNA_linestyle_types.h b/source/blender/makesdna/DNA_linestyle_types.h index 9ffb53e83b6..2507b072a2f 100644 --- a/source/blender/makesdna/DNA_linestyle_types.h +++ b/source/blender/makesdna/DNA_linestyle_types.h @@ -390,6 +390,7 @@ typedef struct LineStyleThicknessModifier_Calligraphy { #define LS_MIN_2D_ANGLE 128 #define LS_MAX_2D_ANGLE 256 #define LS_SPLIT_LENGTH 512 +#define LS_SPLIT_PATTERN 1024 /* FreestyleLineStyle::chaining */ #define LS_CHAINING_PLAIN 1 @@ -420,6 +421,10 @@ typedef struct FreestyleLineStyle { float split_length; float min_angle, max_angle; /* for splitting */ float min_length, max_length; + unsigned short split_dash1, split_gap1; + unsigned short split_dash2, split_gap2; + unsigned short split_dash3, split_gap3; + int pad; unsigned short dash1, gap1, dash2, gap2, dash3, gap3; int panel; /* for UI */ diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c index 62d69ee8732..fbe8eae31b3 100644 --- a/source/blender/makesrna/intern/rna_linestyle.c +++ b/source/blender/makesrna/intern/rna_linestyle.c @@ -1019,6 +1019,47 @@ static void rna_def_linestyle(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Max 2D Length", "Maximum curvilinear 2D length for the selection of chains"); RNA_def_property_update(prop, NC_LINESTYLE, NULL); + prop= RNA_def_property(srna, "use_split_pattern", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_SPLIT_PATTERN); + RNA_def_property_ui_text(prop, "Use Split Pattern", "Enable chain splitting by dashed line patterns"); + RNA_def_property_update(prop, NC_LINESTYLE, NULL); + + prop= RNA_def_property(srna, "split_dash1", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "split_dash1"); + RNA_def_property_range(prop, 0, USHRT_MAX); + RNA_def_property_ui_text(prop, "Split Dash 1", "Length of the 1st dash for splitting"); + RNA_def_property_update(prop, NC_LINESTYLE, NULL); + + prop= RNA_def_property(srna, "split_gap1", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "split_gap1"); + RNA_def_property_range(prop, 0, USHRT_MAX); + RNA_def_property_ui_text(prop, "Split Gap 1", "Length of the 1st gap for splitting"); + RNA_def_property_update(prop, NC_LINESTYLE, NULL); + + prop= RNA_def_property(srna, "split_dash2", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "split_dash2"); + RNA_def_property_range(prop, 0, USHRT_MAX); + RNA_def_property_ui_text(prop, "Split Dash 2", "Length of the 2nd dash for splitting"); + RNA_def_property_update(prop, NC_LINESTYLE, NULL); + + prop= RNA_def_property(srna, "split_gap2", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "split_gap2"); + RNA_def_property_range(prop, 0, USHRT_MAX); + RNA_def_property_ui_text(prop, "Split Gap 2", "Length of the 2nd gap for splitting"); + RNA_def_property_update(prop, NC_LINESTYLE, NULL); + + prop= RNA_def_property(srna, "split_dash3", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "split_dash3"); + RNA_def_property_range(prop, 0, USHRT_MAX); + RNA_def_property_ui_text(prop, "Split Dash 3", "Length of the 3rd dash for splitting"); + RNA_def_property_update(prop, NC_LINESTYLE, NULL); + + prop= RNA_def_property(srna, "split_gap3", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "split_gap3"); + RNA_def_property_range(prop, 0, USHRT_MAX); + RNA_def_property_ui_text(prop, "Split Gap 3", "Length of the 3rd gap for splitting"); + RNA_def_property_update(prop, NC_LINESTYLE, NULL); + prop= RNA_def_property(srna, "material_boundary", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_MATERIAL_BOUNDARY); RNA_def_property_ui_text(prop, "Material Boundary", "If true, chains of feature edges are split at material boundaries"); @@ -1038,37 +1079,37 @@ static void rna_def_linestyle(BlenderRNA *brna) prop= RNA_def_property(srna, "dash1", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "dash1"); RNA_def_property_range(prop, 0, USHRT_MAX); - RNA_def_property_ui_text(prop, "Dash 1", "Length of the 1st dash"); + RNA_def_property_ui_text(prop, "Dash 1", "Length of the 1st dash for dashed lines"); RNA_def_property_update(prop, NC_LINESTYLE, NULL); prop= RNA_def_property(srna, "gap1", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "gap1"); RNA_def_property_range(prop, 0, USHRT_MAX); - RNA_def_property_ui_text(prop, "Gap 1", "Length of the 1st gap"); + RNA_def_property_ui_text(prop, "Gap 1", "Length of the 1st gap for dashed lines"); RNA_def_property_update(prop, NC_LINESTYLE, NULL); prop= RNA_def_property(srna, "dash2", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "dash2"); RNA_def_property_range(prop, 0, USHRT_MAX); - RNA_def_property_ui_text(prop, "Dash 2", "Length of the 2nd dash"); + RNA_def_property_ui_text(prop, "Dash 2", "Length of the 2nd dash for dashed lines"); RNA_def_property_update(prop, NC_LINESTYLE, NULL); prop= RNA_def_property(srna, "gap2", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "gap2"); RNA_def_property_range(prop, 0, USHRT_MAX); - RNA_def_property_ui_text(prop, "Gap 2", "Length of the 2nd gap"); + RNA_def_property_ui_text(prop, "Gap 2", "Length of the 2nd gap for dashed lines"); RNA_def_property_update(prop, NC_LINESTYLE, NULL); prop= RNA_def_property(srna, "dash3", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "dash3"); RNA_def_property_range(prop, 0, USHRT_MAX); - RNA_def_property_ui_text(prop, "Dash 3", "Length of the 3rd dash"); + RNA_def_property_ui_text(prop, "Dash 3", "Length of the 3rd dash for dashed lines"); RNA_def_property_update(prop, NC_LINESTYLE, NULL); prop= RNA_def_property(srna, "gap3", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "gap3"); RNA_def_property_range(prop, 0, USHRT_MAX); - RNA_def_property_ui_text(prop, "Gap 3", "Length of the 3rd gap"); + RNA_def_property_ui_text(prop, "Gap 3", "Length of the 3rd gap for dashed lines"); RNA_def_property_update(prop, NC_LINESTYLE, NULL); }