diff options
5 files changed, 213 insertions, 64 deletions
diff --git a/release/scripts/freestyle/style_modules/parameter_editor.py b/release/scripts/freestyle/style_modules/parameter_editor.py index 0c4987aabb8..dc98b968acf 100644 --- a/release/scripts/freestyle/style_modules/parameter_editor.py +++ b/release/scripts/freestyle/style_modules/parameter_editor.py @@ -505,7 +505,7 @@ class QuantitativeInvisibilityRangeUP1D(UnaryPredicate1D): def join_unary_predicates(upred_list, bpred): if not upred_list: - return TrueUP1D() + return None upred = upred_list[0] for p in upred_list[1:]: upred = bpred(upred, p) @@ -835,47 +835,36 @@ def process(layer_name, lineset_name): # prepare selection criteria by edge types if lineset.select_by_edge_types: edge_type_criteria = [] - if lineset.edge_type_combination == "OR": - flags = Nature.NO_FEATURE - if lineset.select_silhouette: - flags |= Nature.SILHOUETTE - if lineset.select_border: - flags |= Nature.BORDER - if lineset.select_crease: - flags |= Nature.CREASE - if lineset.select_ridge: - flags |= Nature.RIDGE - if lineset.select_valley: - flags |= Nature.VALLEY - if lineset.select_suggestive_contour: - flags |= Nature.SUGGESTIVE_CONTOUR - if lineset.select_material_boundary: - flags |= Nature.MATERIAL_BOUNDARY - if lineset.select_edge_mark: - flags |= Nature.EDGE_MARK - if flags != Nature.NO_FEATURE: - edge_type_criteria.append(pyNatureUP1D(flags)) - else: - if lineset.select_silhouette: - edge_type_criteria.append(pyNatureUP1D(Nature.SILHOUETTE)) - if lineset.select_border: - edge_type_criteria.append(pyNatureUP1D(Nature.BORDER)) - if lineset.select_crease: - edge_type_criteria.append(pyNatureUP1D(Nature.CREASE)) - if lineset.select_ridge: - edge_type_criteria.append(pyNatureUP1D(Nature.RIDGE)) - if lineset.select_valley: - edge_type_criteria.append(pyNatureUP1D(Nature.VALLEY)) - if lineset.select_suggestive_contour: - edge_type_criteria.append(pyNatureUP1D(Nature.SUGGESTIVE_CONTOUR)) - if lineset.select_material_boundary: - edge_type_criteria.append(pyNatureUP1D(Nature.MATERIAL_BOUNDARY)) - if lineset.select_edge_mark: - edge_type_criteria.append(pyNatureUP1D(Nature.EDGE_MARK)) + if lineset.select_silhouette: + upred = pyNatureUP1D(Nature.SILHOUETTE) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_silhouette else upred) + if lineset.select_border: + upred = pyNatureUP1D(Nature.BORDER) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_border else upred) + if lineset.select_crease: + upred = pyNatureUP1D(Nature.CREASE) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_crease else upred) + if lineset.select_ridge: + upred = pyNatureUP1D(Nature.RIDGE) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_ridge else upred) + if lineset.select_valley: + upred = pyNatureUP1D(Nature.VALLEY) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_valley else upred) + if lineset.select_suggestive_contour: + upred = pyNatureUP1D(Nature.SUGGESTIVE_CONTOUR) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_suggestive_contour else upred) + if lineset.select_material_boundary: + upred = pyNatureUP1D(Nature.MATERIAL_BOUNDARY) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_material_boundary else upred) + if lineset.select_edge_mark: + upred = pyNatureUP1D(Nature.EDGE_MARK) + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_edge_mark else upred) if lineset.select_contour: - edge_type_criteria.append(ContourUP1D()) + upred = ContourUP1D() + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_contour else upred) if lineset.select_external_contour: - edge_type_criteria.append(ExternalContourUP1D()) + upred = ExternalContourUP1D() + edge_type_criteria.append(NotUP1D(upred) if lineset.exclude_external_contour else upred) if lineset.edge_type_combination == "OR": upred = join_unary_predicates(edge_type_criteria, OrUP1D) else: diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 04d3ecb120f..e7aca0c9930 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -261,6 +261,17 @@ class RENDER_PT_freestyle_lineset(RenderButtonsPanel, Panel): return freestyle.mode == "EDITOR" and freestyle.linesets.active return False + def draw_edge_type_buttons(self, box, lineset, edge_type): + # property names + select_edge_type = "select_" + edge_type + exclude_edge_type = "exclude_" + edge_type + # draw edge type buttons + row = box.row(align=True) + row.prop(lineset, select_edge_type) + sub = row.column() + sub.prop(lineset, exclude_edge_type, text="") + sub.enabled = getattr(lineset, select_edge_type) + def draw(self, context): layout = self.layout @@ -293,17 +304,18 @@ class RENDER_PT_freestyle_lineset(RenderButtonsPanel, Panel): row = col.row() sub = row.column() - sub.prop(lineset, "select_silhouette") - sub.prop(lineset, "select_border") - sub.prop(lineset, "select_crease") - sub.prop(lineset, "select_ridge") - sub.prop(lineset, "select_valley") - sub.prop(lineset, "select_suggestive_contour") - sub.prop(lineset, "select_material_boundary") - sub.prop(lineset, "select_edge_mark") + self.draw_edge_type_buttons(sub, lineset, "silhouette") + self.draw_edge_type_buttons(sub, lineset, "border") + + self.draw_edge_type_buttons(sub, lineset, "crease") + self.draw_edge_type_buttons(sub, lineset, "ridge") + self.draw_edge_type_buttons(sub, lineset, "valley") + self.draw_edge_type_buttons(sub, lineset, "suggestive_contour") + self.draw_edge_type_buttons(sub, lineset, "material_boundary") + self.draw_edge_type_buttons(sub, lineset, "edge_mark") sub = row.column() - sub.prop(lineset, "select_contour") - sub.prop(lineset, "select_external_contour") + self.draw_edge_type_buttons(sub, lineset, "contour") + self.draw_edge_type_buttons(sub, lineset, "external_contour") col.separator() # XXX col.prop(lineset, "select_by_face_marks") diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp index ec3bd9f5c5b..ab1d9e371e7 100644 --- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp +++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp @@ -160,6 +160,69 @@ extern "C" { return text; } + struct edge_type_condition { + int edge_type, value; + }; + + // examines the conditions and returns true if the target edge type needs to be computed + static bool test_edge_type_conditions(struct edge_type_condition *conditions, + int num_edge_types, bool logical_and, int target, bool distinct) + { + int target_condition = 0; + int num_non_target_positive_conditions = 0; + int num_non_target_negative_conditions = 0; + + for (int i = 0; i < num_edge_types; i++) { + if (conditions[i].edge_type == target) + target_condition = conditions[i].value; + else if (conditions[i].value > 0) + ++num_non_target_positive_conditions; + else if (conditions[i].value < 0) + ++num_non_target_negative_conditions; + } + if (distinct) { + // In this case, the 'target' edge type is assumed to appear on distinct edge + // of its own and never together with other edge types. + if (logical_and) { + if (num_non_target_positive_conditions > 0) + return false; + if (target_condition > 0) + return true; + if (target_condition < 0) + return false; + if (num_non_target_negative_conditions > 0) + return true; + } else { + if (target_condition > 0) + return true; + if (num_non_target_negative_conditions > 0) + return true; + if (target_condition < 0) + return false; + if (num_non_target_positive_conditions > 0) + return false; + } + } else { + // In this case, the 'target' edge type may appear together with other edge types. + if (target_condition > 0) + return true; + if (target_condition < 0) + return true; + if (logical_and) { + if (num_non_target_positive_conditions > 0) + return false; + if (num_non_target_negative_conditions > 0) + return true; + } else { + if (num_non_target_negative_conditions > 0) + return true; + if (num_non_target_positive_conditions > 0) + return false; + } + } + return true; + } + static void prepare(Render* re, SceneRenderLayer* srl ) { // load mesh @@ -197,6 +260,18 @@ extern "C" { int use_ridges_and_valleys = 0; int use_suggestive_contours = 0; int use_material_boundaries = 0; + struct edge_type_condition conditions[] = { + {FREESTYLE_FE_SILHOUETTE, 0}, + {FREESTYLE_FE_BORDER, 0}, + {FREESTYLE_FE_CREASE, 0}, + {FREESTYLE_FE_RIDGE, 0}, + {FREESTYLE_FE_VALLEY, 0}, + {FREESTYLE_FE_SUGGESTIVE_CONTOUR, 0}, + {FREESTYLE_FE_MATERIAL_BOUNDARY, 0}, + {FREESTYLE_FE_CONTOUR, 0}, + {FREESTYLE_FE_EXTERNAL_CONTOUR, 0}, + {FREESTYLE_FE_EDGE_MARK, 0}}; + int num_edge_types = sizeof(conditions) / sizeof(struct edge_type_condition); cout << "Linesets:"<< endl; for (FreestyleLineSet *lineset = (FreestyleLineSet *)config->linesets.first; lineset; lineset = lineset->next) { if (lineset->flags & FREESTYLE_LINESET_ENABLED) { @@ -208,21 +283,33 @@ extern "C" { ++use_ridges_and_valleys; ++use_suggestive_contours; ++use_material_boundaries; - } else if (lineset->flags & FREESTYLE_LINESET_FE_NOT) { - if (!(lineset->edge_types & ~FREESTYLE_FE_RIDGE) || - !(lineset->edge_types & ~FREESTYLE_FE_VALLEY) || - (lineset->flags & FREESTYLE_LINESET_FE_AND)) - ++use_ridges_and_valleys; - if (lineset->edge_types & ~FREESTYLE_FE_SUGGESTIVE_CONTOUR) - ++use_suggestive_contours; - if (lineset->edge_types & ~FREESTYLE_FE_MATERIAL_BOUNDARY) - ++use_material_boundaries; } else { - if (lineset->edge_types & (FREESTYLE_FE_RIDGE | FREESTYLE_FE_VALLEY)) + // 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, true) || + test_edge_type_conditions(conditions, num_edge_types, logical_and, FREESTYLE_FE_VALLEY, true)) ++use_ridges_and_valleys; - if (lineset->edge_types & FREESTYLE_FE_SUGGESTIVE_CONTOUR) + if (test_edge_type_conditions(conditions, num_edge_types, logical_and, FREESTYLE_FE_SUGGESTIVE_CONTOUR, true)) ++use_suggestive_contours; - if (lineset->edge_types & FREESTYLE_FE_MATERIAL_BOUNDARY) + if (test_edge_type_conditions(conditions, num_edge_types, logical_and, FREESTYLE_FE_MATERIAL_BOUNDARY, true)) ++use_material_boundaries; } layer_count++; diff --git a/source/blender/makesdna/DNA_freestyle_types.h b/source/blender/makesdna/DNA_freestyle_types.h index 08b4f406223..30888bff15f 100644 --- a/source/blender/makesdna/DNA_freestyle_types.h +++ b/source/blender/makesdna/DNA_freestyle_types.h @@ -61,7 +61,7 @@ struct FreestyleLineStyle; #define FREESTYLE_SEL_IMAGE_BORDER 8 #define FREESTYLE_SEL_FACE_MARK 16 -/* FreestyleLineSet::fedge_types */ +/* FreestyleLineSet::edge_types, exclude_edge_types */ #define FREESTYLE_FE_SILHOUETTE 1 #define FREESTYLE_FE_BORDER 2 #define FREESTYLE_FE_CREASE 4 @@ -98,7 +98,8 @@ typedef struct FreestyleLineSet { short qi; /* quantitative invisibility */ short pad1; int qi_start, qi_end; - int edge_types; /* feature edge types */ + int edge_types, exclude_edge_types; /* feature edge types */ + int pad2; struct Group *group; /* group of target objects */ struct FreestyleLineStyle *linestyle; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index b505b4b80fa..8cee0987c2e 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1969,6 +1969,66 @@ static void rna_def_freestyle_settings(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Edge Mark", "Select edge marks."); RNA_def_property_update(prop, NC_SCENE, NULL); + prop= RNA_def_property(srna, "exclude_silhouette", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_SILHOUETTE); + RNA_def_property_ui_text(prop, "Silhouette", "Exclude silhouette edges."); + RNA_def_property_ui_icon(prop, ICON_X, 0); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "exclude_border", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_BORDER); + RNA_def_property_ui_text(prop, "Border", "Exclude border edges."); + RNA_def_property_ui_icon(prop, ICON_X, 0); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "exclude_crease", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_CREASE); + RNA_def_property_ui_text(prop, "Crease", "Exclude crease edges."); + RNA_def_property_ui_icon(prop, ICON_X, 0); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "exclude_ridge", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_RIDGE); + RNA_def_property_ui_text(prop, "Ridge", "Exclude ridges."); + RNA_def_property_ui_icon(prop, ICON_X, 0); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "exclude_valley", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_VALLEY); + RNA_def_property_ui_text(prop, "Valley", "Exclude valleys."); + RNA_def_property_ui_icon(prop, ICON_X, 0); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "exclude_suggestive_contour", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_SUGGESTIVE_CONTOUR); + RNA_def_property_ui_text(prop, "Suggestive Contour", "Exclude suggestive contours."); + RNA_def_property_ui_icon(prop, ICON_X, 0); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "exclude_material_boundary", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_MATERIAL_BOUNDARY); + RNA_def_property_ui_text(prop, "Material Boundary", "Exclude edges at material boundaries."); + RNA_def_property_ui_icon(prop, ICON_X, 0); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "exclude_contour", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_CONTOUR); + RNA_def_property_ui_text(prop, "Contour", "Exclude contours."); + RNA_def_property_ui_icon(prop, ICON_X, 0); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "exclude_external_contour", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_EXTERNAL_CONTOUR); + RNA_def_property_ui_text(prop, "External Contour", "Exclude external contours."); + RNA_def_property_ui_icon(prop, ICON_X, 0); + RNA_def_property_update(prop, NC_SCENE, NULL); + + prop= RNA_def_property(srna, "exclude_edge_mark", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_EDGE_MARK); + RNA_def_property_ui_text(prop, "Edge Mark", "Exclude edge marks."); + RNA_def_property_ui_icon(prop, ICON_X, 0); + RNA_def_property_update(prop, NC_SCENE, NULL); + prop= RNA_def_property(srna, "visibility", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "qi"); RNA_def_property_enum_items(prop, visibility_items); |