123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852 |
- # ##### BEGIN GPL LICENSE BLOCK #####
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of the GNU General Public License
- # as published by the Free Software Foundation; either version 2
- # of the License, or (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software Foundation,
- # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- #
- # ##### END GPL LICENSE BLOCK #####
- # <pep8 compliant>
- import bpy
- from bpy.types import Menu, Panel, UIList
- # Render properties
- class RenderFreestyleButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "render"
- # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
- @classmethod
- def poll(cls, context):
- scene = context.scene
- with_freestyle = bpy.app.build_options.freestyle
- return scene and with_freestyle and(context.engine in cls.COMPAT_ENGINES)
- class RENDER_PT_freestyle(RenderFreestyleButtonsPanel, Panel):
- bl_label = "Freestyle"
- bl_options = {'DEFAULT_CLOSED'}
- bl_order = 10
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- def draw_header(self, context):
- rd = context.scene.render
- self.layout.prop(rd, "use_freestyle", text="")
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- layout.use_property_decorate = False # No animation.
- rd = context.scene.render
- layout.active = rd.use_freestyle
- layout.prop(rd, "line_thickness_mode", expand=True)
- if (rd.line_thickness_mode == 'ABSOLUTE'):
- layout.prop(rd, "line_thickness")
- # Render layer properties
- class ViewLayerFreestyleButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "view_layer"
- bl_order = 10
- # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
- @classmethod
- def poll(cls, context):
- scene = context.scene
- rd = scene.render
- with_freestyle = bpy.app.build_options.freestyle
- return (scene and with_freestyle and rd.use_freestyle and
- (context.engine in cls.COMPAT_ENGINES))
- class ViewLayerFreestyleEditorButtonsPanel(ViewLayerFreestyleButtonsPanel):
- # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
- @classmethod
- def poll(cls, context):
- if not super().poll(context):
- return False
- view_layer = context.view_layer
- return view_layer and view_layer.freestyle_settings.mode == 'EDITOR'
- class VIEWLAYER_UL_linesets(UIList):
- def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, index):
- lineset = item
- if self.layout_type in {'DEFAULT', 'COMPACT'}:
- layout.prop(lineset, "name", text="", emboss=False, icon_value=icon)
- layout.prop(lineset, "show_render", text="", index=index)
- elif self.layout_type == 'GRID':
- layout.alignment = 'CENTER'
- layout.label(text="", icon_value=icon)
- class RENDER_MT_lineset_context_menu(Menu):
- bl_label = "Lineset Specials"
- def draw(self, _context):
- layout = self.layout
- layout.operator("scene.freestyle_lineset_copy", icon='COPYDOWN')
- layout.operator("scene.freestyle_lineset_paste", icon='PASTEDOWN')
- class VIEWLAYER_PT_freestyle(ViewLayerFreestyleButtonsPanel, Panel):
- bl_label = "Freestyle"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- def draw(self, context):
- layout = self.layout
- view_layer = context.view_layer
- freestyle = view_layer.freestyle_settings
- layout.active = view_layer.use_freestyle
- row = layout.row()
- layout.prop(freestyle, "mode", text="Control Mode")
- layout.prop(freestyle, "use_view_map_cache", text="View Map Cache")
- layout.label(text="Edge Detection Options:")
- split = layout.split()
- col = split.column()
- col.prop(freestyle, "crease_angle")
- col.prop(freestyle, "use_culling")
- col.prop(freestyle, "use_advanced_options")
- col = split.column()
- col.prop(freestyle, "use_smoothness")
- if freestyle.mode == 'SCRIPT':
- col.prop(freestyle, "use_material_boundaries")
- # Advanced options are hidden by default to warn new users
- if freestyle.use_advanced_options:
- if freestyle.mode == 'SCRIPT':
- row = layout.row()
- row.prop(freestyle, "use_ridges_and_valleys")
- row.prop(freestyle, "use_suggestive_contours")
- row = layout.row()
- row.prop(freestyle, "sphere_radius")
- row.prop(freestyle, "kr_derivative_epsilon")
- if freestyle.mode == 'SCRIPT':
- row = layout.row()
- row.label(text="Style modules:")
- row.operator("scene.freestyle_module_add", text="Add")
- for module in freestyle.modules:
- box = layout.box()
- box.context_pointer_set("freestyle_module", module)
- row = box.row(align=True)
- row.prop(module, "use", text="")
- row.prop(module, "script", text="")
- row.operator("scene.freestyle_module_open", icon='FILEBROWSER', text="")
- row.operator("scene.freestyle_module_remove", icon='X', text="")
- row.operator("scene.freestyle_module_move", icon='TRIA_UP', text="").direction = 'UP'
- row.operator("scene.freestyle_module_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
- class VIEWLAYER_PT_freestyle_lineset(ViewLayerFreestyleEditorButtonsPanel, Panel):
- bl_label = "Freestyle Line Set"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- 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(align=True)
- sub.prop(lineset, exclude_edge_type, text="")
- sub.active = getattr(lineset, select_edge_type)
- def draw(self, context):
- layout = self.layout
- view_layer = context.view_layer
- freestyle = view_layer.freestyle_settings
- lineset = freestyle.linesets.active
- layout.active = view_layer.use_freestyle
- row = layout.row()
- rows = 4 if lineset else 2
- row.template_list(
- "VIEWLAYER_UL_linesets",
- "",
- freestyle,
- "linesets",
- freestyle.linesets,
- "active_index",
- rows=rows,
- )
- sub = row.column(align=True)
- sub.operator("scene.freestyle_lineset_add", icon='ADD', text="")
- sub.operator("scene.freestyle_lineset_remove", icon='REMOVE', text="")
- sub.menu("RENDER_MT_lineset_context_menu", icon='DOWNARROW_HLT', text="")
- if lineset:
- sub.separator()
- sub.separator()
- sub.operator("scene.freestyle_lineset_move", icon='TRIA_UP', text="").direction = 'UP'
- sub.operator("scene.freestyle_lineset_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
- col = layout.column()
- col.label(text="Selection By:")
- row = col.row(align=True)
- row.prop(lineset, "select_by_visibility", text="Visibility", toggle=True)
- row.prop(lineset, "select_by_edge_types", text="Edge Types", toggle=True)
- row.prop(lineset, "select_by_face_marks", text="Face Marks", toggle=True)
- row.prop(lineset, "select_by_collection", text="Collection", toggle=True)
- row.prop(lineset, "select_by_image_border", text="Image Border", toggle=True)
- if lineset.select_by_visibility:
- col.label(text="Visibility:")
- row = col.row(align=True)
- row.prop(lineset, "visibility", expand=True)
- if lineset.visibility == 'RANGE':
- row = col.row(align=True)
- row.prop(lineset, "qi_start")
- row.prop(lineset, "qi_end")
- if lineset.select_by_edge_types:
- col.label(text="Edge Types:")
- row = col.row()
- row.prop(lineset, "edge_type_negation", expand=True)
- row.prop(lineset, "edge_type_combination", expand=True)
- split = col.split()
- sub = split.column()
- self.draw_edge_type_buttons(sub, lineset, "silhouette")
- self.draw_edge_type_buttons(sub, lineset, "border")
- self.draw_edge_type_buttons(sub, lineset, "contour")
- self.draw_edge_type_buttons(sub, lineset, "suggestive_contour")
- self.draw_edge_type_buttons(sub, lineset, "ridge_valley")
- sub = split.column()
- self.draw_edge_type_buttons(sub, lineset, "crease")
- self.draw_edge_type_buttons(sub, lineset, "edge_mark")
- self.draw_edge_type_buttons(sub, lineset, "external_contour")
- self.draw_edge_type_buttons(sub, lineset, "material_boundary")
- if lineset.select_by_face_marks:
- col.label(text="Face Marks:")
- row = col.row()
- row.prop(lineset, "face_mark_negation", expand=True)
- row.prop(lineset, "face_mark_condition", expand=True)
- if lineset.select_by_collection:
- col.label(text="Collection:")
- row = col.row()
- row.prop(lineset, "collection", text="")
- row.prop(lineset, "collection_negation", expand=True)
- class VIEWLAYER_PT_freestyle_linestyle(ViewLayerFreestyleEditorButtonsPanel, Panel):
- bl_label = "Freestyle Line Style"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- def draw_modifier_box_header(self, box, modifier):
- row = box.row()
- row.context_pointer_set("modifier", modifier)
- if modifier.expanded:
- icon = 'TRIA_DOWN'
- else:
- icon = 'TRIA_RIGHT'
- row.prop(modifier, "expanded", text="", icon=icon, emboss=False)
- # TODO: Use icons rather than text label, would save some room!
- row.label(text=modifier.rna_type.name)
- row.prop(modifier, "name", text="")
- if modifier.use:
- icon = 'RESTRICT_RENDER_OFF'
- else:
- icon = 'RESTRICT_RENDER_ON'
- row.prop(modifier, "use", text="", icon=icon)
- sub = row.row(align=True)
- sub.operator("scene.freestyle_modifier_copy", icon='NONE', text="Copy")
- sub.operator("scene.freestyle_modifier_move", icon='TRIA_UP', text="").direction = 'UP'
- sub.operator("scene.freestyle_modifier_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
- sub.operator("scene.freestyle_modifier_remove", icon='X', text="")
- def draw_modifier_box_error(self, box, _modifier, message):
- row = box.row()
- row.label(text=message, icon='ERROR')
- def draw_modifier_common(self, box, modifier):
- row = box.row()
- row.prop(modifier, "blend", text="")
- row.prop(modifier, "influence")
- def draw_modifier_color_ramp_common(self, box, modifier, has_range):
- box.template_color_ramp(modifier, "color_ramp", expand=True)
- if has_range:
- row = box.row(align=True)
- row.prop(modifier, "range_min")
- row.prop(modifier, "range_max")
- def draw_modifier_curve_common(self, box, modifier, has_range, has_value):
- row = box.row()
- row.prop(modifier, "mapping", text="")
- sub = row.column()
- sub.prop(modifier, "invert")
- if modifier.mapping == 'CURVE':
- sub.active = False
- box.template_curve_mapping(modifier, "curve")
- if has_range:
- row = box.row(align=True)
- row.prop(modifier, "range_min")
- row.prop(modifier, "range_max")
- if has_value:
- row = box.row(align=True)
- row.prop(modifier, "value_min")
- row.prop(modifier, "value_max")
- def draw_color_modifier(self, context, modifier):
- layout = self.layout
- col = layout.column(align=True)
- self.draw_modifier_box_header(col.box(), modifier)
- if modifier.expanded:
- box = col.box()
- self.draw_modifier_common(box, modifier)
- if modifier.type == 'ALONG_STROKE':
- self.draw_modifier_color_ramp_common(box, modifier, False)
- elif modifier.type == 'DISTANCE_FROM_OBJECT':
- box.prop(modifier, "target")
- self.draw_modifier_color_ramp_common(box, modifier, True)
- prop = box.operator("scene.freestyle_fill_range_by_selection")
- prop.type = 'COLOR'
- prop.name = modifier.name
- elif modifier.type == 'DISTANCE_FROM_CAMERA':
- self.draw_modifier_color_ramp_common(box, modifier, True)
- prop = box.operator("scene.freestyle_fill_range_by_selection")
- prop.type = 'COLOR'
- prop.name = modifier.name
- elif modifier.type == 'MATERIAL':
- row = box.row()
- row.prop(modifier, "material_attribute", text="")
- sub = row.column()
- sub.prop(modifier, "use_ramp")
- if modifier.material_attribute in {'LINE', 'DIFF', 'SPEC'}:
- sub.active = True
- show_ramp = modifier.use_ramp
- else:
- sub.active = False
- show_ramp = True
- if show_ramp:
- self.draw_modifier_color_ramp_common(box, modifier, False)
- elif modifier.type == 'TANGENT':
- self.draw_modifier_color_ramp_common(box, modifier, False)
- elif modifier.type == 'NOISE':
- self.draw_modifier_color_ramp_common(box, modifier, False)
- row = box.row(align=False)
- row.prop(modifier, "amplitude")
- row.prop(modifier, "period")
- row.prop(modifier, "seed")
- elif modifier.type == 'CREASE_ANGLE':
- self.draw_modifier_color_ramp_common(box, modifier, False)
- row = box.row(align=True)
- row.prop(modifier, "angle_min")
- row.prop(modifier, "angle_max")
- elif modifier.type == 'CURVATURE_3D':
- self.draw_modifier_color_ramp_common(box, modifier, False)
- row = box.row(align=True)
- row.prop(modifier, "curvature_min")
- row.prop(modifier, "curvature_max")
- freestyle = context.view_layer.freestyle_settings
- if not freestyle.use_smoothness:
- message = "Enable Face Smoothness to use this modifier"
- self.draw_modifier_box_error(col.box(), modifier, message)
- def draw_alpha_modifier(self, context, modifier):
- layout = self.layout
- col = layout.column(align=True)
- self.draw_modifier_box_header(col.box(), modifier)
- if modifier.expanded:
- box = col.box()
- self.draw_modifier_common(box, modifier)
- if modifier.type == 'ALONG_STROKE':
- self.draw_modifier_curve_common(box, modifier, False, False)
- elif modifier.type == 'DISTANCE_FROM_OBJECT':
- box.prop(modifier, "target")
- self.draw_modifier_curve_common(box, modifier, True, False)
- prop = box.operator("scene.freestyle_fill_range_by_selection")
- prop.type = 'ALPHA'
- prop.name = modifier.name
- elif modifier.type == 'DISTANCE_FROM_CAMERA':
- self.draw_modifier_curve_common(box, modifier, True, False)
- prop = box.operator("scene.freestyle_fill_range_by_selection")
- prop.type = 'ALPHA'
- prop.name = modifier.name
- elif modifier.type == 'MATERIAL':
- box.prop(modifier, "material_attribute", text="")
- self.draw_modifier_curve_common(box, modifier, False, False)
- elif modifier.type == 'TANGENT':
- self.draw_modifier_curve_common(box, modifier, False, False)
- elif modifier.type == 'NOISE':
- self.draw_modifier_curve_common(box, modifier, False, False)
- row = box.row(align=False)
- row.prop(modifier, "amplitude")
- row.prop(modifier, "period")
- row.prop(modifier, "seed")
- elif modifier.type == 'CREASE_ANGLE':
- self.draw_modifier_curve_common(box, modifier, False, False)
- row = box.row(align=True)
- row.prop(modifier, "angle_min")
- row.prop(modifier, "angle_max")
- elif modifier.type == 'CURVATURE_3D':
- self.draw_modifier_curve_common(box, modifier, False, False)
- row = box.row(align=True)
- row.prop(modifier, "curvature_min")
- row.prop(modifier, "curvature_max")
- freestyle = context.view_layer.freestyle_settings
- if not freestyle.use_smoothness:
- message = "Enable Face Smoothness to use this modifier"
- self.draw_modifier_box_error(col.box(), modifier, message)
- def draw_thickness_modifier(self, context, modifier):
- layout = self.layout
- col = layout.column(align=True)
- self.draw_modifier_box_header(col.box(), modifier)
- if modifier.expanded:
- box = col.box()
- self.draw_modifier_common(box, modifier)
- if modifier.type == 'ALONG_STROKE':
- self.draw_modifier_curve_common(box, modifier, False, True)
- elif modifier.type == 'DISTANCE_FROM_OBJECT':
- box.prop(modifier, "target")
- self.draw_modifier_curve_common(box, modifier, True, True)
- prop = box.operator("scene.freestyle_fill_range_by_selection")
- prop.type = 'THICKNESS'
- prop.name = modifier.name
- elif modifier.type == 'DISTANCE_FROM_CAMERA':
- self.draw_modifier_curve_common(box, modifier, True, True)
- prop = box.operator("scene.freestyle_fill_range_by_selection")
- prop.type = 'THICKNESS'
- prop.name = modifier.name
- elif modifier.type == 'MATERIAL':
- box.prop(modifier, "material_attribute", text="")
- self.draw_modifier_curve_common(box, modifier, False, True)
- elif modifier.type == 'CALLIGRAPHY':
- box.prop(modifier, "orientation")
- row = box.row(align=True)
- row.prop(modifier, "thickness_min")
- row.prop(modifier, "thickness_max")
- elif modifier.type == 'TANGENT':
- self.draw_modifier_curve_common(box, modifier, False, False)
- self.mapping = 'CURVE'
- row = box.row(align=True)
- row.prop(modifier, "thickness_min")
- row.prop(modifier, "thickness_max")
- elif modifier.type == 'NOISE':
- row = box.row(align=False)
- row.prop(modifier, "amplitude")
- row.prop(modifier, "period")
- row = box.row(align=False)
- row.prop(modifier, "seed")
- row.prop(modifier, "use_asymmetric")
- elif modifier.type == 'CREASE_ANGLE':
- self.draw_modifier_curve_common(box, modifier, False, False)
- row = box.row(align=True)
- row.prop(modifier, "thickness_min")
- row.prop(modifier, "thickness_max")
- row = box.row(align=True)
- row.prop(modifier, "angle_min")
- row.prop(modifier, "angle_max")
- elif modifier.type == 'CURVATURE_3D':
- self.draw_modifier_curve_common(box, modifier, False, False)
- row = box.row(align=True)
- row.prop(modifier, "thickness_min")
- row.prop(modifier, "thickness_max")
- row = box.row(align=True)
- row.prop(modifier, "curvature_min")
- row.prop(modifier, "curvature_max")
- freestyle = context.view_layer.freestyle_settings
- if not freestyle.use_smoothness:
- message = "Enable Face Smoothness to use this modifier"
- self.draw_modifier_box_error(col.box(), modifier, message)
- def draw_geometry_modifier(self, _context, modifier):
- layout = self.layout
- col = layout.column(align=True)
- self.draw_modifier_box_header(col.box(), modifier)
- if modifier.expanded:
- box = col.box()
- if modifier.type == 'SAMPLING':
- box.prop(modifier, "sampling")
- elif modifier.type == 'BEZIER_CURVE':
- box.prop(modifier, "error")
- elif modifier.type == 'SINUS_DISPLACEMENT':
- split = box.split()
- col = split.column()
- col.prop(modifier, "wavelength")
- col.prop(modifier, "amplitude")
- col = split.column()
- col.prop(modifier, "phase")
- elif modifier.type == 'SPATIAL_NOISE':
- split = box.split()
- col = split.column()
- col.prop(modifier, "amplitude")
- col.prop(modifier, "scale")
- col.prop(modifier, "octaves")
- col = split.column()
- col.prop(modifier, "smooth")
- col.prop(modifier, "use_pure_random")
- elif modifier.type == 'PERLIN_NOISE_1D':
- split = box.split()
- col = split.column()
- col.prop(modifier, "frequency")
- col.prop(modifier, "amplitude")
- col.prop(modifier, "seed")
- col = split.column()
- col.prop(modifier, "octaves")
- col.prop(modifier, "angle")
- elif modifier.type == 'PERLIN_NOISE_2D':
- split = box.split()
- col = split.column()
- col.prop(modifier, "frequency")
- col.prop(modifier, "amplitude")
- col.prop(modifier, "seed")
- col = split.column()
- col.prop(modifier, "octaves")
- col.prop(modifier, "angle")
- elif modifier.type == 'BACKBONE_STRETCHER':
- box.prop(modifier, "backbone_length")
- elif modifier.type == 'TIP_REMOVER':
- box.prop(modifier, "tip_length")
- elif modifier.type == 'POLYGONIZATION':
- box.prop(modifier, "error")
- elif modifier.type == 'GUIDING_LINES':
- box.prop(modifier, "offset")
- elif modifier.type == 'BLUEPRINT':
- row = box.row()
- row.prop(modifier, "shape", expand=True)
- box.prop(modifier, "rounds")
- row = box.row()
- if modifier.shape in {'CIRCLES', 'ELLIPSES'}:
- row.prop(modifier, "random_radius")
- row.prop(modifier, "random_center")
- elif modifier.shape == 'SQUARES':
- row.prop(modifier, "backbone_length")
- row.prop(modifier, "random_backbone")
- elif modifier.type == '2D_OFFSET':
- row = box.row(align=True)
- row.prop(modifier, "start")
- row.prop(modifier, "end")
- row = box.row(align=True)
- row.prop(modifier, "x")
- row.prop(modifier, "y")
- elif modifier.type == '2D_TRANSFORM':
- box.prop(modifier, "pivot")
- if modifier.pivot == 'PARAM':
- box.prop(modifier, "pivot_u")
- elif modifier.pivot == 'ABSOLUTE':
- row = box.row(align=True)
- row.prop(modifier, "pivot_x")
- row.prop(modifier, "pivot_y")
- row = box.row(align=True)
- row.prop(modifier, "scale_x")
- row.prop(modifier, "scale_y")
- box.prop(modifier, "angle")
- elif modifier.type == 'SIMPLIFICATION':
- box.prop(modifier, "tolerance")
- def draw(self, context):
- layout = self.layout
- view_layer = context.view_layer
- lineset = view_layer.freestyle_settings.linesets.active
- layout.active = view_layer.use_freestyle
- if lineset is None:
- return
- linestyle = lineset.linestyle
- layout.template_ID(lineset, "linestyle", new="scene.freestyle_linestyle_new")
- if linestyle is None:
- return
- row = layout.row(align=True)
- row.prop(linestyle, "panel", expand=True)
- if linestyle.panel == 'STROKES':
- # Chaining
- layout.prop(linestyle, "use_chaining", text="Chaining:")
- split = layout.split(align=True)
- split.active = linestyle.use_chaining
- # First column
- col = split.column()
- col.active = linestyle.use_chaining
- col.prop(linestyle, "chaining", text="")
- if linestyle.chaining == 'SKETCHY':
- col.prop(linestyle, "rounds")
- # Second column
- col = split.column()
- col.prop(linestyle, "use_same_object")
- # Splitting
- layout.label(text="Splitting:")
- split = layout.split(align=True)
- # First column
- col = split.column()
- row = col.row(align=True)
- row.prop(linestyle, "use_angle_min", text="")
- sub = row.row()
- sub.active = linestyle.use_angle_min
- sub.prop(linestyle, "angle_min")
- row = col.row(align=True)
- row.prop(linestyle, "use_angle_max", text="")
- sub = row.row()
- sub.active = linestyle.use_angle_max
- sub.prop(linestyle, "angle_max")
- # Second column
- col = split.column()
- row = col.row(align=True)
- row.prop(linestyle, "use_split_length", text="")
- sub = row.row()
- sub.active = linestyle.use_split_length
- sub.prop(linestyle, "split_length", text="2D Length")
- row = col.row(align=True)
- row.prop(linestyle, "material_boundary")
- # End of columns
- row = layout.row(align=True)
- row.prop(linestyle, "use_split_pattern", text="")
- sub = row.row(align=True)
- sub.active = linestyle.use_split_pattern
- sub.prop(linestyle, "split_dash1", text="D1")
- sub.prop(linestyle, "split_gap1", text="G1")
- sub.prop(linestyle, "split_dash2", text="D2")
- sub.prop(linestyle, "split_gap2", text="G2")
- sub.prop(linestyle, "split_dash3", text="D3")
- sub.prop(linestyle, "split_gap3", text="G3")
- # Sorting
- layout.prop(linestyle, "use_sorting", text="Sorting:")
- col = layout.column()
- col.active = linestyle.use_sorting
- row = col.row(align=True)
- row.prop(linestyle, "sort_key", text="")
- sub = row.row()
- sub.active = linestyle.sort_key in {'DISTANCE_FROM_CAMERA',
- 'PROJECTED_X',
- 'PROJECTED_Y'}
- sub.prop(linestyle, "integration_type", text="")
- row = col.row(align=True)
- row.prop(linestyle, "sort_order", expand=True)
- # Selection
- layout.label(text="Selection:")
- split = layout.split(align=True)
- # First column
- col = split.column()
- row = col.row(align=True)
- row.prop(linestyle, "use_length_min", text="")
- sub = row.row()
- sub.active = linestyle.use_length_min
- sub.prop(linestyle, "length_min")
- row = col.row(align=True)
- row.prop(linestyle, "use_length_max", text="")
- sub = row.row()
- sub.active = linestyle.use_length_max
- sub.prop(linestyle, "length_max")
- # Second column
- col = split.column()
- row = col.row(align=True)
- row.prop(linestyle, "use_chain_count", text="")
- sub = row.row()
- sub.active = linestyle.use_chain_count
- sub.prop(linestyle, "chain_count")
- # Caps
- layout.label(text="Caps:")
- row = layout.row(align=True)
- row.prop(linestyle, "caps", expand=True)
- # Dashed lines
- layout.prop(linestyle, "use_dashed_line", text="Dashed Line:")
- row = layout.row(align=True)
- row.active = linestyle.use_dashed_line
- row.prop(linestyle, "dash1", text="D1")
- row.prop(linestyle, "gap1", text="G1")
- row.prop(linestyle, "dash2", text="D2")
- row.prop(linestyle, "gap2", text="G2")
- row.prop(linestyle, "dash3", text="D3")
- row.prop(linestyle, "gap3", text="G3")
- elif linestyle.panel == 'COLOR':
- col = layout.column()
- row = col.row()
- row.label(text="Base Color:")
- row.prop(linestyle, "color", text="")
- col.label(text="Modifiers:")
- col.operator_menu_enum("scene.freestyle_color_modifier_add", "type", text="Add Modifier")
- for modifier in linestyle.color_modifiers:
- self.draw_color_modifier(context, modifier)
- elif linestyle.panel == 'ALPHA':
- col = layout.column()
- row = col.row()
- row.label(text="Base Transparency:")
- row.prop(linestyle, "alpha")
- col.label(text="Modifiers:")
- col.operator_menu_enum("scene.freestyle_alpha_modifier_add", "type", text="Add Modifier")
- for modifier in linestyle.alpha_modifiers:
- self.draw_alpha_modifier(context, modifier)
- elif linestyle.panel == 'THICKNESS':
- col = layout.column()
- row = col.row()
- row.label(text="Base Thickness:")
- row.prop(linestyle, "thickness")
- subcol = col.column()
- subcol.active = linestyle.chaining == 'PLAIN' and linestyle.use_same_object
- row = subcol.row()
- row.prop(linestyle, "thickness_position", expand=True)
- row = subcol.row()
- row.prop(linestyle, "thickness_ratio")
- row.active = (linestyle.thickness_position == 'RELATIVE')
- col = layout.column()
- col.label(text="Modifiers:")
- col.operator_menu_enum("scene.freestyle_thickness_modifier_add", "type", text="Add Modifier")
- for modifier in linestyle.thickness_modifiers:
- self.draw_thickness_modifier(context, modifier)
- elif linestyle.panel == 'GEOMETRY':
- col = layout.column()
- col.label(text="Modifiers:")
- col.operator_menu_enum("scene.freestyle_geometry_modifier_add", "type", text="Add Modifier")
- for modifier in linestyle.geometry_modifiers:
- self.draw_geometry_modifier(context, modifier)
- elif linestyle.panel == 'TEXTURE':
- layout.separator()
- row = layout.row()
- row.prop(linestyle, "use_nodes")
- row.prop(linestyle, "texture_spacing", text="Spacing Along Stroke")
- row = layout.row()
- props = row.operator(
- "wm.properties_context_change",
- text="Go to Linestyle Textures Properties",
- icon='TEXTURE',
- )
- props.context = 'TEXTURE'
- elif linestyle.panel == 'MISC':
- pass
- # Material properties
- class MaterialFreestyleButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "material"
- # COMPAT_ENGINES must be defined in each subclass, external engines can add themselves here
- @classmethod
- def poll(cls, context):
- scene = context.scene
- material = context.material
- with_freestyle = bpy.app.build_options.freestyle
- return (
- with_freestyle and material and scene and scene.render.use_freestyle and
- (context.engine in cls.COMPAT_ENGINES)
- )
- class MATERIAL_PT_freestyle_line(MaterialFreestyleButtonsPanel, Panel):
- bl_label = "Freestyle Line"
- bl_options = {'DEFAULT_CLOSED'}
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE'}
- def draw(self, context):
- layout = self.layout
- mat = context.material
- row = layout.row()
- row.prop(mat, "line_color", text="")
- row.prop(mat, "line_priority", text="Priority")
- classes = (
- RENDER_PT_freestyle,
- VIEWLAYER_UL_linesets,
- RENDER_MT_lineset_context_menu,
- VIEWLAYER_PT_freestyle,
- VIEWLAYER_PT_freestyle_lineset,
- VIEWLAYER_PT_freestyle_linestyle,
- MATERIAL_PT_freestyle_line,
- )
- if __name__ == "__main__": # only for live edit.
- from bpy.utils import register_class
- for cls in classes:
- register_class(cls)
|