- improve Blender registry handling
- save each mesh in a different color
This commit is contained in:
parent
40261787c2
commit
7ccdc1081a
2 changed files with 88 additions and 72 deletions
|
@ -1,9 +1,9 @@
|
||||||
#!BPY
|
#!BPY
|
||||||
|
|
||||||
# """
|
# """
|
||||||
# Name: 'SVG: Export UV layout to SVG file'
|
# Name: 'UV: Export to SVG'
|
||||||
# Blender: 245
|
# Blender: 245
|
||||||
# Group: 'UV'
|
# Group: 'Image'
|
||||||
# Tooltip: 'Export selected objects to SVG file'
|
# Tooltip: 'Export selected objects to SVG file'
|
||||||
# """
|
# """
|
||||||
|
|
||||||
|
@ -16,11 +16,11 @@ script can be used to re-import such a file. Each object and each group of adjac
|
||||||
faces therein will be made a separate SVG group.
|
faces therein will be made a separate SVG group.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
FILL_COLOR = '' # 'yellow' or '#ffa000' e.g. for uni-color, empty string for random color
|
||||||
ID_SEPARATOR = '_.._'
|
ID_SEPARATOR = '_.._'
|
||||||
FILL_COLOR = 'yellow'
|
|
||||||
|
|
||||||
|
|
||||||
import Blender, sys
|
import Blender, BPyMessages, sys, random
|
||||||
|
|
||||||
|
|
||||||
class Abort(Exception):
|
class Abort(Exception):
|
||||||
|
@ -28,86 +28,94 @@ class Abort(Exception):
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
|
|
||||||
|
|
||||||
def get_adjacent_faces(pool):
|
class UVFaceGroups:
|
||||||
if not len(pool):
|
def __init__(self, mesh):
|
||||||
return []
|
faces = dict([(f.index, f) for f in mesh.faces])
|
||||||
|
self.groups = []
|
||||||
|
while faces:
|
||||||
|
self.groups.append(self.adjacent(faces))
|
||||||
|
|
||||||
i, face = pool.popitem()
|
def __len__(self):
|
||||||
group = [face]
|
return len(self.groups)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self.groups.__iter__()
|
||||||
|
|
||||||
|
def adjacent(self, faces):
|
||||||
uvcoords = {}
|
uvcoords = {}
|
||||||
|
face = faces.popitem()[1]
|
||||||
|
group = [face]
|
||||||
for c in face.uv:
|
for c in face.uv:
|
||||||
uvcoords[(c[0], c[1])] = True
|
uvcoords[(c[0], c[1])] = True
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
found = []
|
found = []
|
||||||
for face in pool.itervalues():
|
for face in faces.itervalues():
|
||||||
for c in face.uv:
|
for c in face.uv:
|
||||||
if (c[0], c[1]) in uvcoords:
|
if (c[0], c[1]) in uvcoords:
|
||||||
for d in face.uv:
|
for c in face.uv:
|
||||||
uvcoords[(d[0], d[1])] = True
|
uvcoords[(c[0], c[1])] = True
|
||||||
found.append(face)
|
found.append(face)
|
||||||
break
|
break
|
||||||
if not found:
|
if not found:
|
||||||
break
|
return group
|
||||||
for face in found:
|
for face in found:
|
||||||
group.append(face)
|
group.append(face)
|
||||||
del pool[face.index]
|
del faces[face.index]
|
||||||
|
|
||||||
return group
|
|
||||||
|
|
||||||
|
|
||||||
def write_svg(filename):
|
def hashcolor(name):
|
||||||
|
random.seed(hash(name))
|
||||||
|
c = [random.randint(220, 255), random.randint(120, 220), random.randint(120, 220)]
|
||||||
|
random.shuffle(c)
|
||||||
|
return "#%02x%02x%02x" % (c[0], c[1], c[2])
|
||||||
|
|
||||||
|
|
||||||
|
def write_svg(path):
|
||||||
size = Blender.Draw.PupMenu("Image size%t|128|256|512|1024|2048|4096|8192")
|
size = Blender.Draw.PupMenu("Image size%t|128|256|512|1024|2048|4096|8192")
|
||||||
if size < 0:
|
if size < 0:
|
||||||
raise Abort('no image size chosen')
|
raise Abort('no image size chosen')
|
||||||
size = 1 << (size + 6)
|
size = 1 << (size + 6)
|
||||||
|
|
||||||
print "exporting to '%s' (size %d) ... " % (filename, size),
|
print "exporting to '%s' (size %d) ... " % (path, size),
|
||||||
svg = open(filename, "w")
|
svg = open(path, "w")
|
||||||
svg.write('<?xml version="1.0" standalone="no"?>\n')
|
svg.write('<?xml version="1.0" standalone="no"?>\n')
|
||||||
svg.write('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n\n')
|
svg.write('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n\n')
|
||||||
svg.write('<svg width="%spx" height="%spx" viewBox="0 0 %d %d" xmlns="http://www.w3.org/2000/svg"' \
|
svg.write('<svg width="%spx" height="%spx" viewBox="0 0 %d %d" xmlns="http://www.w3.org/2000/svg"' \
|
||||||
' version="1.1" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape">\n'
|
' version="1.1" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape">\n'
|
||||||
% (size, size, size, size))
|
% (size, size, size, size))
|
||||||
svg.write("\t<desc>uv_export_svg.py: %s</desc>\n" % filename);
|
svg.write("\t<desc>uv_export_svg.py: %s</desc>\n" % path);
|
||||||
svg.write('\t<rect x="0" y="0" width="%d" height="%d" fill="none" stroke="blue" stroke-width="%f"/>\n'
|
svg.write('\t<rect x="0" y="0" width="%d" height="%d" fill="none" stroke="blue" stroke-width="%f"/>\n'
|
||||||
% (size, size, 1.0))
|
% (size, size, 1.0))
|
||||||
|
|
||||||
unique_meshes = {}
|
objects = {}
|
||||||
for o in Blender.Scene.GetCurrent().objects.selected:
|
for o in Blender.Scene.GetCurrent().objects.selected:
|
||||||
if o.type != "Mesh":
|
if o.type != "Mesh":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
mesh = o.getData(mesh = 1)
|
mesh = o.getData(mesh = 1)
|
||||||
if not mesh.faceUV:
|
if mesh.faceUV:
|
||||||
continue
|
objects[mesh.name] = (o.name, mesh)
|
||||||
if mesh.name in unique_meshes:
|
|
||||||
continue
|
for meshname, v in objects.iteritems():
|
||||||
unique_meshes[mesh.name] = True
|
objname, mesh = v
|
||||||
|
color = FILL_COLOR or hashcolor(meshname)
|
||||||
|
|
||||||
svg.write('\t<g style="fill:%s; stroke:black stroke-width:1px" inkscape:label="%s" ' \
|
svg.write('\t<g style="fill:%s; stroke:black stroke-width:1px" inkscape:label="%s" ' \
|
||||||
'id="%s">\n' % (FILL_COLOR, o.name, o.name))
|
'id="%s">\n' % (color, objname, objname))
|
||||||
|
|
||||||
pool = {}
|
facegroups = UVFaceGroups(mesh)
|
||||||
for f in mesh.faces:
|
for faces in facegroups:
|
||||||
pool[f.index] = f
|
|
||||||
|
|
||||||
groups = []
|
|
||||||
while len(pool):
|
|
||||||
groups.append(get_adjacent_faces(pool))
|
|
||||||
|
|
||||||
for faces in groups:
|
|
||||||
indent = '\t\t'
|
indent = '\t\t'
|
||||||
if len(groups) > 1:
|
if len(facegroups) > 1:
|
||||||
svg.write('\t\t<g>\n')
|
svg.write('\t\t<g>\n')
|
||||||
indent = '\t\t\t'
|
indent = '\t\t\t'
|
||||||
for f in faces:
|
for f in faces:
|
||||||
svg.write('%s<polygon id="%s%s%d" points="' % (indent, mesh.name, ID_SEPARATOR, f.index))
|
svg.write('%s<polygon id="%s%s%d" points="' % (indent, meshname, ID_SEPARATOR, f.index))
|
||||||
for p in f.uv:
|
for p in f.uv:
|
||||||
svg.write('%.8f,%.8f ' % (p[0] * size, size - p[1] * size))
|
svg.write('%.8f,%.8f ' % (p[0] * size, size - p[1] * size))
|
||||||
svg.write('"/>\n')
|
svg.write('"/>\n')
|
||||||
if len(groups) > 1:
|
if len(facegroups) > 1:
|
||||||
svg.write('\t\t</g>\n')
|
svg.write('\t\t</g>\n')
|
||||||
|
|
||||||
svg.write("\t</g>\n")
|
svg.write("\t</g>\n")
|
||||||
|
@ -117,17 +125,18 @@ def write_svg(filename):
|
||||||
print "done."
|
print "done."
|
||||||
|
|
||||||
|
|
||||||
def export(filename):
|
def export(path):
|
||||||
registry = {}
|
if not BPyMessages.Warning_SaveOver(path):
|
||||||
registry[basename] = Blender.sys.basename(filename)
|
return
|
||||||
Blender.Registry.SetKey("UVImportExportSVG", registry, False)
|
|
||||||
|
|
||||||
editmode = Blender.Window.EditMode()
|
editmode = Blender.Window.EditMode()
|
||||||
if editmode:
|
if editmode:
|
||||||
Blender.Window.EditMode(0)
|
Blender.Window.EditMode(0)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
write_svg(filename)
|
write_svg(path)
|
||||||
|
Blender.Registry.SetKey("UVImportExportSVG", { "path" : path }, False)
|
||||||
|
|
||||||
except Abort, e:
|
except Abort, e:
|
||||||
print "Error:", e.msg, " -> aborting ...\n"
|
print "Error:", e.msg, " -> aborting ...\n"
|
||||||
Blender.Draw.PupMenu("Error%t|" + e.msg)
|
Blender.Draw.PupMenu("Error%t|" + e.msg)
|
||||||
|
@ -136,8 +145,13 @@ def export(filename):
|
||||||
Blender.Window.EditMode(1)
|
Blender.Window.EditMode(1)
|
||||||
|
|
||||||
|
|
||||||
|
registry = Blender.Registry.GetKey("UVImportExportSVG", False)
|
||||||
|
if registry and "path" in registry:
|
||||||
|
path = registry["path"]
|
||||||
|
else:
|
||||||
active = Blender.Scene.GetCurrent().objects.active
|
active = Blender.Scene.GetCurrent().objects.active
|
||||||
(basename, extname) = Blender.sys.splitext(Blender.Get("filename"))
|
basename = Blender.sys.basename(Blender.sys.splitext(Blender.Get("filename"))[0])
|
||||||
filename = Blender.sys.basename(basename) + "-" + active.name + ".svg"
|
path = basename + "-" + active.name + ".svg"
|
||||||
Blender.Window.FileSelector(export, "Export to SVG", filename)
|
|
||||||
|
Blender.Window.FileSelector(export, "Export to SVG", path)
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#!BPY
|
#!BPY
|
||||||
|
|
||||||
# """
|
# """
|
||||||
# Name: 'SVG: Re-Import UV layout from SVG file'
|
# Name: 'UV: (Re)Import UV from SVG'
|
||||||
# Blender: 245
|
# Blender: 245
|
||||||
# Group: 'UV'
|
# Group: 'Image'
|
||||||
# Tooltip: 'Re-import UV layout from SVG file'
|
# Tooltip: 'Re-import UV layout from SVG file'
|
||||||
# """
|
# """
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ The choice has been made when the file was saved!
|
||||||
ID_SEPARATOR = '_.._'
|
ID_SEPARATOR = '_.._'
|
||||||
|
|
||||||
|
|
||||||
import Blender, sys, math, re
|
import Blender, BPyMessages, sys, math, re
|
||||||
from xml.sax import saxexts
|
from xml.sax import saxexts
|
||||||
|
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ class import_svg:
|
||||||
|
|
||||||
def endElement(self, name):
|
def endElement(self, name):
|
||||||
self.scandesc = False
|
self.scandesc = False
|
||||||
self.matrices = self.matrices[:-1]
|
self.matrices.pop()
|
||||||
|
|
||||||
def handlePolygon(self, attrs):
|
def handlePolygon(self, attrs):
|
||||||
if not self.verified:
|
if not self.verified:
|
||||||
|
@ -257,7 +257,10 @@ class import_svg:
|
||||||
uv[1] = transuv[i][1]
|
uv[1] = transuv[i][1]
|
||||||
|
|
||||||
|
|
||||||
def run_parser(filename):
|
def run_parser(path):
|
||||||
|
if BPyMessages.Error_NoFile(path):
|
||||||
|
return
|
||||||
|
|
||||||
editmode = Blender.Window.EditMode()
|
editmode = Blender.Window.EditMode()
|
||||||
if editmode:
|
if editmode:
|
||||||
Blender.Window.EditMode(0)
|
Blender.Window.EditMode(0)
|
||||||
|
@ -267,7 +270,8 @@ def run_parser(filename):
|
||||||
svg = saxexts.ParserFactory().make_parser("xml.sax.drivers.drv_xmlproc")
|
svg = saxexts.ParserFactory().make_parser("xml.sax.drivers.drv_xmlproc")
|
||||||
svg.setDocumentHandler(import_svg())
|
svg.setDocumentHandler(import_svg())
|
||||||
svg.setErrorHandler(import_svg())
|
svg.setErrorHandler(import_svg())
|
||||||
svg.parse(filename)
|
svg.parse(path)
|
||||||
|
Blender.Registry.SetKey("UVImportExportSVG", { "path" : path }, False)
|
||||||
|
|
||||||
except Abort, e:
|
except Abort, e:
|
||||||
print "Error:", e.msg, " -> aborting ...\n"
|
print "Error:", e.msg, " -> aborting ...\n"
|
||||||
|
@ -279,13 +283,11 @@ def run_parser(filename):
|
||||||
Blender.Window.EditMode(1)
|
Blender.Window.EditMode(1)
|
||||||
|
|
||||||
|
|
||||||
active = Blender.Scene.GetCurrent().objects.active
|
|
||||||
(basename, extname) = Blender.sys.splitext(Blender.Get("filename"))
|
|
||||||
filename = Blender.sys.basename(basename) + "-" + active.name + ".svg"
|
|
||||||
|
|
||||||
registry = Blender.Registry.GetKey("UVImportExportSVG", False)
|
registry = Blender.Registry.GetKey("UVImportExportSVG", False)
|
||||||
if registry and basename in registry:
|
if registry and "path" in registry and Blender.sys.exists(Blender.sys.expandpath(registry["path"])):
|
||||||
filename = registry[basename]
|
path = registry["path"]
|
||||||
|
else:
|
||||||
|
path = ""
|
||||||
|
|
||||||
Blender.Window.FileSelector(run_parser, "Import SVG", filename)
|
Blender.Window.FileSelector(run_parser, "Import SVG", path)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue