X-Git-Url: https://git.ao2.it/vrm.git/blobdiff_plain/58b487476c46b70b9900d613bd875a3d9d42a515..de221ecd94607f731bb5d39c4d71447e3b545098:/vrm.py diff --git a/vrm.py b/vrm.py index 0338065..15fba09 100755 --- a/vrm.py +++ b/vrm.py @@ -1,13 +1,13 @@ #!BPY """ Name: 'VRM' -Blender: 242 +Blender: 245 Group: 'Render' Tooltip: 'Vector Rendering Method script' """ __author__ = "Antonio Ospite" -__url__ = ["http://projects.blender.org/projects/vrm"] +__url__ = ["http://vrm.ao2.it"] __version__ = "0.3.beta" __bpydoc__ = """\ @@ -15,7 +15,7 @@ __bpydoc__ = """\ """ # --------------------------------------------------------------------- -# Copyright (c) 2006 Antonio Ospite +# Copyright (c) 2006, 2007, 2008, 2009 Antonio Ospite # # 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 @@ -40,15 +40,14 @@ __bpydoc__ = """\ # from scratch but Nikola gave me the idea, so I thank him publicly. # # --------------------------------------------------------------------- -# +# # Things TODO for a next release: +# - Shadeless shader # - FIX the issue with negative scales in object tranformations! # - Use a better depth sorting algorithm -# - Implement clipping of primitives and do handle object intersections. -# (for now only clipping away whole objects is supported). # - Review how selections are made (this script uses selection states of # primitives to represent visibility infos) -# - Use a data structure other than Mesh to represent the 2D image? +# - Use a data structure other than Mesh to represent the 2D image? # Think to a way to merge (adjacent) polygons that have the same color. # Or a way to use paths for silhouettes and contours. # - Consider SMIL for animation handling instead of ECMA Script? (Firefox do @@ -62,29 +61,6 @@ __bpydoc__ = """\ # - Check memory use!! # # --------------------------------------------------------------------- -# -# Changelog: -# -# vrm-0.3.py - ... -# * First release after code restucturing. -# Now the script offers a useful set of functionalities -# and it can render animations, too. -# * Optimization in Renderer.doEdgeStyle(), build a topology cache -# so to speed up the lookup of adjacent faces of an edge. -# Thanks ideasman42. -# * The SVG output is now SVG 1.0 valid. -# Checked with: http://jiggles.w3.org/svgvalidator/ValidatorURI.html -# * Progress indicator during HSR. -# * Initial SWF output support (using ming) -# * Fixed a bug in the animation code, now the projection matrix is -# recalculated at each frame! -# * PDF output (using reportlab) -# * Fixed another problem in the animation code the current frame was off -# by one -# * Use fps as specified in blender when VectorWriter handles animation -# * Remove the real file opening in the abstract VectorWriter -# -# --------------------------------------------------------------------- import Blender from Blender import Scene, Object, Mesh, NMesh, Material, Lamp, Camera, Window @@ -92,6 +68,19 @@ from Blender.Mathutils import * from math import * import sys, time +try: + set() +except NameError: + from sets import Set as set + + +def uniq(alist): + tmpdict = dict() + return [tmpdict.setdefault(e,e) for e in alist if e not in tmpdict] + # in python > 2.4 we ca use the following + #return [ u for u in alist if u not in locals()['_[1]'] ] + + # Constants EPS = 10e-5 @@ -99,13 +88,13 @@ EPS = 10e-5 progress = None -# Some global settings +# Config class for global settings class config: polygons = dict() polygons['SHOW'] = True polygons['SHADING'] = 'FLAT' # FLAT or TOON - polygons['HSR'] = 'NEWELL' # PAINTER or NEWELL + polygons['HSR'] = 'PAINTER' # PAINTER or NEWELL # Hidden to the user for now polygons['EXPANSION_TRICK'] = True @@ -123,6 +112,41 @@ class config: output['ANIMATION'] = False output['JOIN_OBJECTS'] = True + def saveToRegistry(): + registry = {} + + for k,v in config.__dict__.iteritems(): + + # config class store settings in dictionaries + if v.__class__ == dict().__class__: + + regkey_prefix = k.upper()+"_" + + for opt_k,opt_v in v.iteritems(): + regkey = regkey_prefix + opt_k + + registry[regkey] = opt_v + + Blender.Registry.SetKey('VRM', registry, True) + + saveToRegistry = staticmethod(saveToRegistry) + + def loadFromRegistry(): + registry = Blender.Registry.GetKey('VRM', True) + if not registry: + return + + for k,v in registry.iteritems(): + k_tmp = k.split('_') + conf_attr = k_tmp[0].lower() + conf_key = str.join("_",k_tmp[1:]) + conf_val = v + + if config.__dict__.has_key(conf_attr): + config.__dict__[conf_attr][conf_key] = conf_val + + loadFromRegistry = staticmethod(loadFromRegistry) + # Utility functions print_debug = False @@ -151,7 +175,7 @@ def debug(msg): sys.stderr.write(msg) def EQ(v1, v2): - return (abs(v1[0]-v2[0]) < EPS and + return (abs(v1[0]-v2[0]) < EPS and abs(v1[1]-v2[1]) < EPS ) by_furthest_z = (lambda f1, f2: cmp(max([v.co[2] for v in f1]), max([v.co[2] for v in f2])+EPS) @@ -190,8 +214,8 @@ class HSR: Geometric objects lying in a common plane are said to be coplanar. Three noncollinear points determine a plane and so are trivially coplanar. Four points are coplanar iff the volume of the tetrahedron defined by them is - 0, - + 0, + | x_1 y_1 z_1 1 | | x_2 y_2 z_2 1 | | x_3 y_3 z_3 1 | @@ -325,7 +349,7 @@ class HSR: def det(a, b, c): return ((b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]) ) - + det = staticmethod(det) def pointInPolygon(q, P): @@ -473,7 +497,7 @@ class HSR: # #newfaces = splitOn(plane, f) - + if newfaces == None: print "Big FAT problem, we weren't able to split POLYGONS!" raise AssertionError @@ -631,7 +655,7 @@ class HSR: #print "d0:", d0, "d1:", d1 - # if the vertex lies in the cutplane + # if the vertex lies in the cutplane if abs(d1) < EPS: #print "d1 On cutplane" posVertList.append(V1) @@ -682,10 +706,14 @@ class HSR: else: negVertList.append(V1) - - # uniq - posVertList = [ u for u in posVertList if u not in locals()['_[1]'] ] - negVertList = [ u for u in negVertList if u not in locals()['_[1]'] ] + + # uniq for python > 2.4 + #posVertList = [ u for u in posVertList if u not in locals()['_[1]'] ] + #negVertList = [ u for u in negVertList if u not in locals()['_[1]'] ] + + # a more portable way + posVertList = uniq(posVertList) + negVertList = uniq(negVertList) # If vertex are all on the same half-space, return @@ -739,7 +767,7 @@ class HSR: class MeshUtils: def buildEdgeFaceUsersCache(me): - ''' + ''' Takes a mesh and returns a list aligned with the meshes edges. Each item is a list of the faces that use the edge would be the equiv for having ed.face_users as a property @@ -755,23 +783,23 @@ class MeshUtils: i1,i2= i2,i1 return i1, i2 - + face_edges_dict= dict([(sorted_edge_indicies(ed), (ed.index, [])) for ed in me.edges]) for f in me.faces: fvi= [v.index for v in f.v]# face vert idx's for i in xrange(len(f)): i1= fvi[i] i2= fvi[i-1] - + if i1>i2: i1,i2= i2,i1 - + face_edges_dict[i1,i2][1].append(f) - + face_edges= [None] * len(me.edges) for ed_index, ed_faces in face_edges_dict.itervalues(): face_edges[ed_index]= ed_faces - + return face_edges def isMeshEdge(adjacent_faces): @@ -862,10 +890,10 @@ class ShadingUtils: class Projector: """Calculate the projection of an object given the camera. - + A projector is useful to so some per-object transformation to obtain the projection of an object given the camera. - + The main method is #doProjection# see the method description for the parameter list. """ @@ -887,17 +915,26 @@ class Projector: fovy = atan(0.5/aspect/(camera.lens/32)) fovy = fovy * 360.0/pi - + + + if Blender.Get('version') < 243: + camPersp = 0 + camOrtho = 1 + else: + camPersp = 'persp' + camOrtho = 'ortho' + # What projection do we want? - if camera.type == 0: - mP = self._calcPerspectiveMatrix(fovy, aspect, near, far) - elif camera.type == 1: - mP = self._calcOrthoMatrix(fovy, aspect, near, far, scale) - + if camera.type == camPersp: + mP = self._calcPerspectiveMatrix(fovy, aspect, near, far) + elif camera.type == camOrtho: + mP = self._calcOrthoMatrix(fovy, aspect, near, far, scale) + + # View transformation cam = Matrix(cameraObj.getInverseMatrix()) - cam.transpose() - + cam.transpose() + mP = mP * cam self.projectionMatrix = mP @@ -912,13 +949,13 @@ class Projector: Given a vertex calculate the projection using the current projection matrix. """ - + # Note that we have to work on the vertex using homogeneous coordinates # From blender 2.42+ we don't need to resize the vector to be 4d # when applying a 4x4 matrix, but we do that anyway since we need the # 4th coordinate later p = self.projectionMatrix * Vector(v).resize4D() - + # Perspective division if p[3] != 0: p[0] = p[0]/p[3] @@ -935,11 +972,11 @@ class Projector: ## # Private methods # - + def _calcPerspectiveMatrix(self, fovy, aspect, near, far): """Return a perspective projection matrix. """ - + top = near * tan(fovy * pi / 360.0) bottom = -top left = bottom*aspect @@ -950,7 +987,7 @@ class Projector: b = (top+bottom) / (top - bottom) c = - ((far+near) / (far-near)) d = - ((2*far*near)/(far-near)) - + m = Matrix( [x, 0.0, a, 0.0], [0.0, y, b, 0.0], @@ -962,15 +999,15 @@ class Projector: def _calcOrthoMatrix(self, fovy, aspect , near, far, scale): """Return an orthogonal projection matrix. """ - + # The 11 in the formula was found emiprically top = near * tan(fovy * pi / 360.0) * (scale * 11) - bottom = -top + bottom = -top left = bottom * aspect right= top * aspect rl = right-left tb = top-bottom - fn = near-far + fn = near-far tx = -((right+left)/rl) ty = -((top+bottom)/tb) tz = ((far+near)/fn) @@ -980,7 +1017,7 @@ class Projector: [0.0, 2.0/tb, 0.0, ty], [0.0, 0.0, 2.0/fn, tz], [0.0, 0.0, 0.0, 1.0]) - + return m @@ -992,7 +1029,7 @@ class Projector: class Progress: """A model for a progress indicator. - + Do the progress calculation calculation and the view independent stuff of a progress indicator. """ @@ -1104,7 +1141,7 @@ class ConsoleProgressIndicator(ProgressIndicator): def show(self, progress, name): ProgressIndicator.show(self, progress, name) - + bar_length = 70 bar_progress = int( (progress/100.0) * bar_length ) bar = ("=" * bar_progress).ljust(bar_length) @@ -1182,12 +1219,18 @@ class VectorWriter: - printCanvas(self, scene, doPrintPolygons=True, doPrintEdges=False, showHiddenEdges=False): """ - + def __init__(self, fileName): """Set the output file name and other properties""" + try: + config.writer + except: + config.writer = dict() + config.writer['SETTING'] = True + self.outputFileName = fileName - + context = Scene.GetCurrent().getRenderingContext() self.canvasSize = ( context.imageSizeX(), context.imageSizeY() ) @@ -1201,7 +1244,7 @@ class VectorWriter: ## # Public Methods # - + def open(self, startFrame=1, endFrame=1): if startFrame != endFrame: self.startFrame = startFrame @@ -1220,7 +1263,7 @@ class VectorWriter: """This is the interface for the needed printing routine. """ return - + ## SVG Writer @@ -1260,13 +1303,13 @@ class SVGVectorWriter(VectorWriter): # remember to call the close method of the parent as last VectorWriter.close(self) - + def printCanvas(self, scene, doPrintPolygons=True, doPrintEdges=False, showHiddenEdges=False): """Convert the scene representation to SVG. """ - Objects = scene.getChildren() + Objects = scene.objects context = scene.getRenderingContext() framenumber = context.currentFrame() @@ -1275,7 +1318,7 @@ class SVGVectorWriter(VectorWriter): framestyle = "display:none" else: framestyle = "display:block" - + # Assign an id to this group so we can set properties on it using DOM self.file.write("\n" % (framenumber, framestyle) ) @@ -1295,22 +1338,22 @@ class SVGVectorWriter(VectorWriter): if doPrintEdges: self._printEdges(mesh, showHiddenEdges) - + self.file.write("\n") self.file.write("\n") - - ## + + ## # Private Methods # - + def _calcCanvasCoord(self, v): """Convert vertex in scene coordinates to canvas coordinates. """ pt = Vector([0, 0, 0]) - + mW = float(self.canvasSize[0])/2.0 mH = float(self.canvasSize[1])/2.0 @@ -1318,12 +1361,12 @@ class SVGVectorWriter(VectorWriter): pt[0] = v.co[0]*mW + mW pt[1] = v.co[1]*mH + mH pt[2] = v.co[2] - + # For now we want (0,0) in the top-left corner of the canvas. # Mirror and translate along y pt[1] *= -1 pt[1] += self.canvasSize[1] - + return pt def _printHeader(self): @@ -1375,13 +1418,13 @@ class SVGVectorWriter(VectorWriter): } \n]]>\n \n""") - + def _printFooter(self): """Print the SVG footer.""" self.file.write("\n\n") - def _printPolygons(self, mesh): + def _printPolygons(self, mesh): """Print the selected (visible) polygons. """ @@ -1403,11 +1446,11 @@ class SVGVectorWriter(VectorWriter): for v in face.v[1:]: p = self._calcCanvasCoord(v) self.file.write("%g,%g " % (p[0], p[1])) - + # get rid of the last blank space, just cosmetics here. - self.file.seek(-1, 1) + self.file.seek(-1, 1) self.file.write(" z\"\n") - + # take as face color the first vertex color if face.col: fcol = face.col[0] @@ -1450,13 +1493,13 @@ class SVGVectorWriter(VectorWriter): stroke_width = config.edges['WIDTH'] stroke_col = config.edges['COLOR'] - + self.file.write("\n") for e in mesh.edges: - + hidden_stroke_style = "" - + if e.sel == 0: if showHiddenEdges == False: continue @@ -1465,7 +1508,7 @@ class SVGVectorWriter(VectorWriter): p1 = self._calcCanvasCoord(e.v1) p2 = self._calcCanvasCoord(e.v2) - + self.file.write(" 0 the face is visible from the camera d = view_vect * normal - + if d > 0: return True else: @@ -2094,6 +2124,38 @@ class Renderer: # Scene methods + def _filterHiddenObjects(self, scene): + """Discard object that are on hidden layers in the scene. + """ + + Objects = scene.objects + + visible_obj_list = [ obj for obj in Objects if + set(obj.layers).intersection(set(scene.getLayers())) ] + + for o in Objects: + if o not in visible_obj_list: + scene.objects.unlink(o) + + scene.update() + + + + def _buildLightSetup(self, scene): + # Get the list of lighting sources + obj_lst = scene.objects + self.lights = [ o for o in obj_lst if o.getType() == 'Lamp' ] + + # When there are no lights we use a default lighting source + # that have the same position of the camera + if len(self.lights) == 0: + l = Lamp.New('Lamp') + lobj = Object.New('Lamp') + lobj.loc = self.cameraObj.loc + lobj.link(l) + self.lights.append(lobj) + + def _doSceneClipping(self, scene): """Clip whole objects against the View Frustum. @@ -2110,21 +2172,44 @@ class Renderer: fovy = atan(0.5/aspect/(self.cameraObj.data.lens/32)) fovy = fovy * 360.0/pi - Objects = scene.getChildren() + Objects = scene.objects + for o in Objects: if o.getType() != 'Mesh': continue; - # TODO: use the object bounding box (that is already in WorldSpace) - # bb = o.getBoundBox() and then: for point in bb: ... - + """ obj_vect = Vector(cam_pos) - self._getObjPosition(o) d = obj_vect*view_vect theta = AngleBetweenVecs(obj_vect, view_vect) - + # if the object is outside the view frustum, clip it away if (d < near) or (d > far) or (theta > fovy): - scene.unlink(o) + scene.objects.unlink(o) + """ + + # Use the object bounding box + # (whose points are already in WorldSpace Coordinate) + + bb = o.getBoundBox() + + points_outside = 0 + for p in bb: + p_vect = Vector(cam_pos) - Vector(p) + + d = p_vect * view_vect + theta = AngleBetweenVecs(p_vect, view_vect) + + # Is this point outside the view frustum? + if (d < near) or (d > far) or (theta > fovy): + points_outside += 1 + + # If the bb is all outside the view frustum we clip the whole + # object away + if points_outside == len(bb): + scene.objects.unlink(o) + + def _doConvertGeometricObjsToMesh(self, scene): """Convert all "geometric" objects to mesh ones. @@ -2132,13 +2217,14 @@ class Renderer: geometricObjTypes = ['Mesh', 'Surf', 'Curve', 'Text'] #geometricObjTypes = ['Mesh', 'Surf', 'Curve'] - Objects = scene.getChildren() + Objects = scene.objects + objList = [ o for o in Objects if o.getType() in geometricObjTypes ] for obj in objList: old_obj = obj obj = self._convertToRawMeshObj(obj) - scene.link(obj) - scene.unlink(old_obj) + scene.objects.link(obj) + scene.objects.unlink(old_obj) # XXX Workaround for Text and Curve which have some normals @@ -2162,29 +2248,37 @@ class Renderer: c = self._getObjPosition(self.cameraObj) - by_center_pos = (lambda o1, o2: + by_obj_center_pos = (lambda o1, o2: (o1.getType() == 'Mesh' and o2.getType() == 'Mesh') and cmp((self._getObjPosition(o1) - Vector(c)).length, (self._getObjPosition(o2) - Vector(c)).length) ) - # TODO: implement sorting by bounding box, if obj1.bb is inside obj2.bb, - # then ob1 goes farther than obj2, useful when obj2 has holes - by_bbox = None - - Objects = scene.getChildren() - Objects.sort(by_center_pos) - + # Implement sorting by bounding box, the object with the bb + # nearest to the camera should be drawn as last. + by_nearest_bbox_point = (lambda o1, o2: + (o1.getType() == 'Mesh' and o2.getType() == 'Mesh') and + cmp( min( [(Vector(p) - Vector(c)).length for p in o1.getBoundBox()] ), + min( [(Vector(p) - Vector(c)).length for p in o2.getBoundBox()] ) + ) + ) + + + Objects = list(scene.objects) + + #Objects.sort(by_obj_center_pos) + Objects.sort(by_nearest_bbox_point) + # update the scene for o in Objects: - scene.unlink(o) - scene.link(o) + scene.objects.unlink(o) + scene.objects.link(o) def _joinMeshObjectsInScene(self, scene): """Merge all the Mesh Objects in a scene into a single Mesh Object. """ - oList = [o for o in scene.getChildren() if o.getType()=='Mesh'] + oList = [o for o in scene.objects if o.getType()=='Mesh'] # FIXME: Object.join() do not work if the list contains 1 object if len(oList) == 1: @@ -2194,23 +2288,23 @@ class Renderer: bigObj = Object.New('Mesh', 'BigOne') bigObj.link(mesh) - scene.link(bigObj) + scene.objects.link(bigObj) try: bigObj.join(oList) except RuntimeError: print "\nWarning! - Can't Join Objects\n" - scene.unlink(bigObj) + scene.objects.unlink(bigObj) return except TypeError: print "Objects Type error?" - + for o in oList: - scene.unlink(o) + scene.objects.unlink(o) scene.update() - + # Per object/mesh methods def _convertToRawMeshObj(self, object): @@ -2246,16 +2340,16 @@ class Renderer: def _doBackFaceCulling(self, mesh): """Simple Backface Culling routine. - + At this level we simply do a visibility test face by face and then select the vertices belonging to visible faces. """ - + # Select all vertices, so edges can be displayed even if there are no # faces for v in mesh.verts: v.sel = 1 - + Mesh.Mode(Mesh.SelectModes['FACE']) # Loop on faces for f in mesh.faces: @@ -2320,7 +2414,7 @@ class Renderer: light_obj = l light_pos = self._getObjPosition(l) light = light_obj.getData() - + L = Vector(light_pos).normalize() V = (Vector(camPos) - Vector(f.cent)).normalize() @@ -2410,7 +2504,7 @@ class Renderer: # The Canonical View Volume, 8 vertices, and 6 faces, # We consider its face normals pointing outside - + v1 = NMesh.Vert(1, 1, -1) v2 = NMesh.Vert(1, -1, -1) v3 = NMesh.Vert(-1, -1, -1) @@ -2441,16 +2535,18 @@ class Renderer: for clipface in cvv: clippedfaces = [] + for f in facelist: - - newfaces = HSR.splitOn(clipface, f, return_positive_faces=False) + + #newfaces = HSR.splitOn(clipface, f, return_positive_faces=False) + newfaces = None if not newfaces: - # Check if the face is inside the view rectangle + # Check if the face is all outside the view frustum # TODO: Do this test before, it is more efficient points_outside = 0 for v in f: - if abs(v[0]) > 1-EPS or abs(v[1]) > 1-EPS: + if abs(v[0]) > 1-EPS or abs(v[1]) > 1-EPS or abs(v[2]) > 1-EPS: points_outside += 1 if points_outside != len(f): @@ -2465,12 +2561,12 @@ class Renderer: nf.col = [f.col[0]] * len(nf.v) clippedfaces.append(nf) - facelist = clippedfaces[:] + nmesh.faces = facelist nmesh.update() - + # HSR routines def __simpleDepthSort(self, mesh): @@ -2542,7 +2638,7 @@ class Renderer: progress.setActivity("HSR: Newell", len(facelist)) #progress.setQuiet(True) - + while len(facelist): debug("\n----------------------\n") debug("len(facelits): %d\n" % len(facelist)) @@ -2566,7 +2662,7 @@ class Renderer: qSign = sign(Q.normal[2]) # TODO: check also if Q is parallel?? - + # Test 0: We need to test only those Qs whose furthest vertex # is closer to the observer than the closest vertex of P. @@ -2584,7 +2680,7 @@ class Renderer: debug("met a marked face\n") continue - + # Test 1: X extent overlapping xP = [v.co[0] for v in P.v] xQ = [v.co[0] for v in Q.v] @@ -2607,7 +2703,7 @@ class Renderer: debug("\nTest 2\n") debug("NOT Y OVERLAP!\n") continue - + # Test 3: P vertices are all behind the plane of Q n = 0 @@ -2657,7 +2753,7 @@ class Renderer: facelist = HSR.facesplit(P, Q, facelist, nmesh) split_done = 1 - break + break # The question now is: Does Q obscure P? @@ -2687,7 +2783,7 @@ class Renderer: debug("\nTest 4bis\n") debug("P IN FRONT OF Q!\n") - + # We don't even know if Q does obscure P, so they should # intersect each other, split one of them in two parts. if not qVerticesBehindPlaneP and not pVerticesInFrontPlaneQ: @@ -2697,16 +2793,16 @@ class Renderer: facelist = HSR.facesplit(P, Q, facelist, nmesh) split_done = 1 - break - + break + facelist.remove(Q) facelist.insert(0, Q) Q.smooth = 1 face_marked = 1 debug("Q marked!\n") break - - # Write P! + + # Write P! if split_done == 0 and face_marked == 0: facelist.remove(P) maplist.append(P) @@ -2725,7 +2821,7 @@ class Renderer: # break # end of while len(facelist) - + nmesh.faces = maplist #for f in nmesh.faces: @@ -2793,10 +2889,10 @@ from Blender import BGL, Draw from Blender.BGL import * class GUI: - + def _init(): - # Output Format menu + # Output Format menu output_format = config.output['FORMAT'] default_value = outputWriters.keys().index(output_format)+1 GUI.outFormatMenu = Draw.Create(default_value) @@ -2813,7 +2909,7 @@ class GUI: # Render filled polygons GUI.polygonsToggle = Draw.Create(config.polygons['SHOW']) - # Shading Style menu + # Shading Style menu shading_style = config.polygons['SHADING'] default_value = shadingStyles.keys().index(shading_style)+1 GUI.shadingStyleMenu = Draw.Create(default_value) @@ -2830,7 +2926,7 @@ class GUI: GUI.showHiddenEdgesToggle = Draw.Create(config.edges['SHOW_HIDDEN']) GUI.evtShowHiddenEdgesToggle = 5 - # Edge Style menu + # Edge Style menu edge_style = config.edges['STYLE'] default_value = edgeStyles.keys().index(edge_style)+1 GUI.edgeStyleMenu = Draw.Create(default_value) @@ -2851,6 +2947,9 @@ class GUI: # Exit Button GUI.evtExitButton = 9 + # Save default button + GUI.evtSaveDefaultButton = 99 + def draw(): # initialize static members @@ -2858,9 +2957,12 @@ class GUI: glClear(GL_COLOR_BUFFER_BIT) glColor3f(0.0, 0.0, 0.0) - glRasterPos2i(10, 350) + glRasterPos2i(10, 380) Draw.Text("VRM: Vector Rendering Method script. Version %s." % __version__) + glRasterPos2i(10, 365) + Draw.Text("%s (c) 2006, 2007" % __author__) + glRasterPos2i(10, 335) Draw.Text("Press Q or ESC to quit.") @@ -2888,6 +2990,9 @@ class GUI: "Start Rendering") Draw.Button("Exit", GUI.evtExitButton, 95, 210-25, 75, 25+18, "Exit!") + Draw.Button("Save settings as default", GUI.evtSaveDefaultButton, 10, 210-50, 160, 18, + "Save settings as default") + # Rendering Styles glRasterPos2i(200, 310) Draw.Text("Rendering Style:") @@ -2914,7 +3019,7 @@ class GUI: "Render polygon edges") if GUI.showEdgesToggle.val == 1: - + # Edge Style edgeStyleMenuStruct = "Edge Style %t" for t in edgeStyles.keys(): @@ -2938,8 +3043,6 @@ class GUI: 200, 160, 160, 18, GUI.showHiddenEdgesToggle.val, "Render hidden edges as dashed lines") - glRasterPos2i(10, 160) - Draw.Text("%s (c) 2006" % __author__) def event(evt, val): @@ -2997,6 +3100,9 @@ class GUI: global outputfile Blender.Window.FileSelector(vectorize, label, outputfile) + elif evt == GUI.evtSaveDefaultButton: + config.saveToRegistry() + else: print "Event: %d not handled!" % evt @@ -3020,7 +3126,7 @@ class GUI: # A wrapper function for the vectorizing process def vectorize(filename): """The vectorizing process is as follows: - + - Instanciate the writer and the renderer - Render! """ @@ -3035,11 +3141,11 @@ def vectorize(filename): actualWriter = outputWriters[config.output['FORMAT']] writer = actualWriter(filename) - + renderer = Renderer() renderer.doRendering(writer, config.output['ANIMATION']) - if editmode: Window.EditMode(1) + if editmode: Window.EditMode(1) @@ -3048,6 +3154,13 @@ if __name__ == "__main__": global progress + config.loadFromRegistry() + + # initialize writer setting also here to configure writer specific + # settings on startup + actualWriter = outputWriters[config.output['FORMAT']] + writer = actualWriter("") + outputfile = "" basename = Blender.sys.basename(Blender.Get('filename')) if basename != "":