Skip to content
Snippets Groups Projects
Commit 861519e4 authored by Folkert de Vries's avatar Folkert de Vries
Browse files

Freestyle SVG Exporter: make it possible to export strokes and fills on a per-linestyle basis

parent 2f6c86c4
Branches
Tags
No related merge requests found
...@@ -58,7 +58,7 @@ from freestyle.utils import ( ...@@ -58,7 +58,7 @@ from freestyle.utils import (
get_object_name, get_object_name,
) )
from freestyle.functions import ( from freestyle.functions import (
GetShapeF1D, GetShapeF1D,
CurveMaterialF0D, CurveMaterialF0D,
) )
from freestyle.predicates import ( from freestyle.predicates import (
...@@ -156,6 +156,30 @@ def create_path(scene): ...@@ -156,6 +156,30 @@ def create_path(scene):
return os.path.join(dirname, basename + frame + ".svg") return os.path.join(dirname, basename + frame + ".svg")
class SVGExporterLinesetPanel(bpy.types.Panel):
"""Creates a Panel in the Render Layers context of the properties editor"""
bl_idname = "RENDER_PT_SVGExporterLinesetPanel"
bl_space_type = 'PROPERTIES'
bl_label = "Freestyle Line Style SVG Export"
bl_region_type = 'WINDOW'
bl_context = "render_layer"
def draw(self, context):
layout = self.layout
scene = context.scene
svg = scene.svg_export
freestyle = scene.render.layers.active.freestyle_settings
linestyle = freestyle.linesets.active.linestyle
layout.active = (svg.use_svg_export and freestyle.mode != 'SCRIPT')
row = layout.row()
column = row.column()
column.prop(linestyle, 'use_export_strokes')
column = row.column()
column.active = svg.object_fill
column.prop(linestyle, 'use_export_fills')
class SVGExport(bpy.types.PropertyGroup): class SVGExport(bpy.types.PropertyGroup):
"""Implements the properties for the SVG exporter""" """Implements the properties for the SVG exporter"""
bl_idname = "RENDER_PT_svg_export" bl_idname = "RENDER_PT_svg_export"
...@@ -470,10 +494,20 @@ class SVGFillBuilder: ...@@ -470,10 +494,20 @@ class SVGFillBuilder:
tree = et.parse(self.filepath) tree = et.parse(self.filepath)
root = tree.getroot() root = tree.getroot()
scene = bpy.context.scene scene = bpy.context.scene
name = self._name
lineset_group = find_svg_elem(tree, ".//svg:g[@id='{}']".format(self._name)) lineset_group = find_svg_elem(tree, ".//svg:g[@id='{}']".format(self._name))
if lineset_group is None: if lineset_group is None:
print("searched for {}, but could not find a <g> with that id".format(self._name)) lineset_group = et.XML('<g/>')
return lineset_group.attrib = {
'id': name,
'xmlns:inkscape': namespaces["inkscape"],
'inkscape:groupmode': 'lineset',
'inkscape:label': name,
}
root.append(lineset_group)
print('added new lineset group ', name)
# <g> for the fills of the current frame # <g> for the fills of the current frame
fill_group = et.XML('<g/>') fill_group = et.XML('<g/>')
...@@ -520,19 +554,16 @@ class ParameterEditorCallback(object): ...@@ -520,19 +554,16 @@ class ParameterEditorCallback(object):
def lineset_post(self, scene, layer, lineset): def lineset_post(self, scene, layer, lineset):
raise NotImplementedError() raise NotImplementedError()
@classmethod
def evaluate(cls, scene):
'Evaluates whether these callbacks should run'
return (
scene.render.use_freestyle
and scene.svg_export.use_svg_export
)
class SVGPathShaderCallback(ParameterEditorCallback): class SVGPathShaderCallback(ParameterEditorCallback):
@classmethod
def poll(cls, scene, linestyle):
return scene.render.use_freestyle and scene.svg_export.use_svg_export and linestyle.use_export_strokes
@classmethod @classmethod
def modifier_post(cls, scene, layer, lineset): def modifier_post(cls, scene, layer, lineset):
if not cls.evaluate(scene): if not cls.poll(scene, lineset.linestyle):
return [] return []
split = scene.svg_export.split_at_invisible split = scene.svg_export.split_at_invisible
...@@ -542,31 +573,35 @@ class SVGPathShaderCallback(ParameterEditorCallback): ...@@ -542,31 +573,35 @@ class SVGPathShaderCallback(ParameterEditorCallback):
return [cls.shader] return [cls.shader]
@classmethod @classmethod
def lineset_post(cls, scene, *args): def lineset_post(cls, scene, layer, lineset):
if not cls.evaluate(scene): if not cls.poll(scene, lineset.linestyle):
return return []
cls.shader.write() cls.shader.write()
class SVGFillShaderCallback(ParameterEditorCallback): class SVGFillShaderCallback(ParameterEditorCallback):
@staticmethod @classmethod
def lineset_post(scene, layer, lineset): def poll(cls, scene, linestyle):
if not (scene.render.use_freestyle and scene.svg_export.use_svg_export and scene.svg_export.object_fill): return scene.render.use_freestyle and scene.svg_export.use_svg_export and scene.svg_export.object_fill and linestyle.use_export_fills
@classmethod
def lineset_post(cls, scene, layer, lineset):
if not cls.poll(scene, lineset.linestyle):
return return
# reset the stroke selection (but don't delete the already generated strokes) # reset the stroke selection (but don't delete the already generated strokes)
Operators.reset(delete_strokes=False) Operators.reset(delete_strokes=False)
# Unary Predicates: visible and correct edge nature # Unary Predicates: visible and correct edge nature
upred = AndUP1D( upred = AndUP1D(
QuantitativeInvisibilityUP1D(0), QuantitativeInvisibilityUP1D(0),
OrUP1D(ExternalContourUP1D(), OrUP1D(ExternalContourUP1D(),
pyNatureUP1D(Nature.BORDER)), pyNatureUP1D(Nature.BORDER)),
) )
# select the new edges # select the new edges
Operators.select(upred) Operators.select(upred)
# Binary Predicates # Binary Predicates
bpred = AndBP1D( bpred = AndBP1D(
MaterialBP1D(), MaterialBP1D(),
NotBP1D(pyZDiscontinuityBP1D()), NotBP1D(pyZDiscontinuityBP1D()),
) )
bpred = OrBP1D(bpred, AndBP1D(NotBP1D(bpred), AndBP1D(SameShapeIdBP1D(), MaterialBP1D()))) bpred = OrBP1D(bpred, AndBP1D(NotBP1D(bpred), AndBP1D(SameShapeIdBP1D(), MaterialBP1D())))
...@@ -609,16 +644,29 @@ def register_namespaces(namespaces=namespaces): ...@@ -609,16 +644,29 @@ def register_namespaces(namespaces=namespaces):
classes = ( classes = (
SVGExporterPanel, SVGExporterPanel,
SVGExporterLinesetPanel,
SVGExport, SVGExport,
) )
def register(): def register():
linestyle = bpy.types.FreestyleLineStyle
linestyle.use_export_strokes = BoolProperty(
name="Export Strokes",
description="Export strokes for this Line Style",
default=True,
)
linestyle.use_export_fills = BoolProperty(
name="Export Fills",
description="Export fills for this Line Style",
default=False,
)
for cls in classes: for cls in classes:
bpy.utils.register_class(cls) bpy.utils.register_class(cls)
bpy.types.Scene.svg_export = PointerProperty(type=SVGExport) bpy.types.Scene.svg_export = PointerProperty(type=SVGExport)
# add callbacks # add callbacks
bpy.app.handlers.render_init.append(render_init) bpy.app.handlers.render_init.append(render_init)
bpy.app.handlers.render_write.append(render_write) bpy.app.handlers.render_write.append(render_write)
...@@ -639,6 +687,9 @@ def unregister(): ...@@ -639,6 +687,9 @@ def unregister():
for cls in classes: for cls in classes:
bpy.utils.unregister_class(cls) bpy.utils.unregister_class(cls)
del bpy.types.Scene.svg_export del bpy.types.Scene.svg_export
linestyle = bpy.types.FreestyleLineStyle
del linestyle.use_export_strokes
del linestyle.use_export_fills
# remove callbacks # remove callbacks
bpy.app.handlers.render_init.remove(render_init) bpy.app.handlers.render_init.remove(render_init)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment