From 2e6dd3316b0c1a7cd155b055b03f226865dd020c Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Sat, 17 Feb 2007 19:15:27 +0100 Subject: [PATCH] PDF output writer * Use fps as specified in blender when VectorWriter handles animation * PDF output (using reportlab) * Remove the real file opening in the abstract VectorWriter * Fix another problem in the animation code the current frame was off by one Signed-off-by: Antonio Ospite --- vrm.py | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 204 insertions(+), 37 deletions(-) diff --git a/vrm.py b/vrm.py index da71fab..f4cfcbd 100755 --- a/vrm.py +++ b/vrm.py @@ -75,9 +75,14 @@ __bpydoc__ = """\ # * 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 +# * 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 # # --------------------------------------------------------------------- @@ -100,7 +105,7 @@ class config: polygons = dict() polygons['SHOW'] = True polygons['SHADING'] = 'FLAT' # FLAT or TOON - polygons['HSR'] = 'PAINTER' # PAINTER or NEWELL + polygons['HSR'] = 'NEWELL' # PAINTER or NEWELL # Hidden to the user for now polygons['EXPANSION_TRICK'] = True @@ -114,8 +119,9 @@ class config: edges['COLOR'] = [0, 0, 0] output = dict() - output['FORMAT'] = 'SVG' - output['ANIMATION'] = False + output['FORMAT'] = 'PDF' + #output['ANIMATION'] = False + output['ANIMATION'] = True output['JOIN_OBJECTS'] = True @@ -1178,11 +1184,12 @@ class VectorWriter: """Set the output file name and other properties""" self.outputFileName = fileName - self.file = None context = Scene.GetCurrent().getRenderingContext() self.canvasSize = ( context.imageSizeX(), context.imageSizeY() ) + self.fps = context.fps + self.startFrame = 1 self.endFrame = 1 self.animation = False @@ -1198,14 +1205,11 @@ class VectorWriter: self.endFrame = endFrame self.animation = True - self.file = open(self.outputFileName, "w") print "Outputting to: ", self.outputFileName return def close(self): - if self.file: - self.file.close() return def printCanvas(self, scene, doPrintPolygons=True, doPrintEdges=False, @@ -1226,6 +1230,8 @@ class SVGVectorWriter(VectorWriter): """ VectorWriter.__init__(self, fileName) + self.file = None + ## # Public Methods @@ -1235,6 +1241,9 @@ class SVGVectorWriter(VectorWriter): """Do some initialization operations. """ VectorWriter.open(self, startFrame, endFrame) + + self.file = open(self.outputFileName, "w") + self._printHeader() def close(self): @@ -1242,7 +1251,10 @@ class SVGVectorWriter(VectorWriter): """ self._printFooter() - # remember to call the close method of the parent + if self.file: + self.file.close() + + # remember to call the close method of the parent as last VectorWriter.close(self) @@ -1323,15 +1335,17 @@ class SVGVectorWriter(VectorWriter): self.canvasSize) if self.animation: + delay = 1000/self.fps self.file.write("""\n\n - \n""" % (self.startFrame, self.endFrame, self.startFrame) ) + \n""") def _printFooter(self): """Print the SVG footer.""" @@ -1491,10 +1505,10 @@ class SWFVectorWriter(VectorWriter): VectorWriter.open(self, startFrame, endFrame) self.movie = SWFMovie() self.movie.setDimension(self.canvasSize[0], self.canvasSize[1]) - # set fps - self.movie.setRate(25) - numframes = endFrame - startFrame + 1 - self.movie.setFrames(numframes) + if self.animation: + self.movie.setRate(self.fps) + numframes = endFrame - startFrame + 1 + self.movie.setFrames(numframes) def close(self): """Do some finalization operation. @@ -1589,32 +1603,17 @@ class SWFVectorWriter(VectorWriter): p0 = self._calcCanvasCoord(face.verts[0]) s.movePenTo(p0[0], p0[1]) - for v in face.verts[1:]: p = self._calcCanvasCoord(v) s.drawLineTo(p[0], p[1]) # Closing the shape s.drawLineTo(p0[0], p0[1]) + s.end() sprite.add(s) - """ - # use the stroke property to alleviate the "adjacent edges" problem, - # we simulate polygon expansion using borders, - # see http://www.antigrain.com/svg/index.html for more info - stroke_width = 1.0 - - # EXPANSION TRICK is not that useful where there is transparency - if config.polygons['EXPANSION_TRICK'] and color[3] == 255: - # str_col = "#000000" # For debug - self.file.write(" stroke:%s;\n" % str_col) - self.file.write(" stroke-width:" + str(stroke_width) + ";\n") - self.file.write(" stroke-linecap:round;stroke-linejoin:round") - - """ - def _printEdges(self, mesh, sprite, showHiddenEdges=False): """Print the wireframe using mesh edges. """ @@ -1626,7 +1625,7 @@ class SWFVectorWriter(VectorWriter): for e in mesh.edges: - #Next, we set the line width and color for our shape. + # Next, we set the line width and color for our shape. s.setLine(stroke_width, stroke_col[0], stroke_col[1], stroke_col[2], 255) @@ -1653,6 +1652,165 @@ class SWFVectorWriter(VectorWriter): sprite.add(s) +## PDF Writer + +try: + from reportlab.pdfgen import canvas + PDFSupported = True +except: + PDFSupported = False + +class PDFVectorWriter(VectorWriter): + """A concrete class for writing PDF output. + """ + + def __init__(self, fileName): + """Simply call the parent Contructor. + """ + VectorWriter.__init__(self, fileName) + + self.canvas = None + + + ## + # Public Methods + # + + def open(self, startFrame=1, endFrame=1): + """Do some initialization operations. + """ + VectorWriter.open(self, startFrame, endFrame) + size = (self.canvasSize[0], self.canvasSize[1]) + self.canvas = canvas.Canvas(self.outputFileName, pagesize=size, bottomup=0) + + def close(self): + """Do some finalization operation. + """ + self.canvas.save() + + # remember to call the close method of the parent + VectorWriter.close(self) + + def printCanvas(self, scene, doPrintPolygons=True, doPrintEdges=False, + showHiddenEdges=False): + """Convert the scene representation to SVG. + """ + context = scene.getRenderingContext() + framenumber = context.currentFrame() + + Objects = scene.getChildren() + + for obj in Objects: + + if(obj.getType() != 'Mesh'): + continue + + mesh = obj.getData(mesh=1) + + if doPrintPolygons: + self._printPolygons(mesh) + + if doPrintEdges: + self._printEdges(mesh, showHiddenEdges) + + self.canvas.showPage() + + ## + # 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 + + # rescale to canvas size + 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 _printPolygons(self, mesh): + """Print the selected (visible) polygons. + """ + + if len(mesh.faces) == 0: + return + + for face in mesh.faces: + if not face.sel: + continue + + if face.col: + fcol = face.col[0] + color = [fcol.r/255.0, fcol.g/255.0, fcol.b/255.0, + fcol.a/255.0] + else: + color = [1, 1, 1, 1] + + self.canvas.setFillColorRGB(color[0], color[1], color[2]) + # For debug + self.canvas.setStrokeColorRGB(0, 0, 0) + + path = self.canvas.beginPath() + + # The starting point of the path + p0 = self._calcCanvasCoord(face.verts[0]) + path.moveTo(p0[0], p0[1]) + + for v in face.verts[1:]: + p = self._calcCanvasCoord(v) + path.lineTo(p[0], p[1]) + + # Closing the shape + path.close() + + self.canvas.drawPath(path, stroke=0, fill=1) + + def _printEdges(self, mesh, showHiddenEdges=False): + """Print the wireframe using mesh edges. + """ + + stroke_width = config.edges['WIDTH'] + stroke_col = config.edges['COLOR'] + + self.canvas.setLineCap(1) + self.canvas.setLineJoin(1) + self.canvas.setLineWidth(stroke_width) + self.canvas.setStrokeColorRGB(stroke_col[0]/255.0, stroke_col[1]/255.0, + stroke_col[2]/255) + + for e in mesh.edges: + + self.canvas.setLineWidth(stroke_width) + + if e.sel == 0: + if showHiddenEdges == False: + continue + else: + # PDF does not support dashed lines natively, so -for now- + # draw hidden lines thinner + self.canvas.setLineWidth(stroke_width/2.0) + + p1 = self._calcCanvasCoord(e.v1) + p2 = self._calcCanvasCoord(e.v2) + + # FIXME: this is just a workaround, remove that after the + # implementation of propoer Viewport clipping + if abs(p1[0]) < 3000 and abs(p2[0]) < 3000 and abs(p1[1]) < 3000 and abs(p1[2]) < 3000: + self.canvas.line(p1[0], p1[1], p2[0], p2[1]) + + # --------------------------------------------------------------------- # @@ -1675,6 +1833,8 @@ outputWriters = dict() outputWriters['SVG'] = SVGVectorWriter if SWFSupported: outputWriters['SWF'] = SWFVectorWriter +if PDFSupported: + outputWriters['PDF'] = PDFVectorWriter class Renderer: @@ -1705,7 +1865,7 @@ class Renderer: ) # Render from the currently active camera - self.cameraObj = self._SCENE.getCurrentCamera() + #self.cameraObj = self._SCENE.getCurrentCamera() # Get the list of lighting sources obj_lst = self._SCENE.getChildren() @@ -1751,12 +1911,19 @@ class Renderer: print "Start Rendering of %d frames" % (endFrame-startFrame+1) for f in xrange(startFrame, endFrame+1): print "\n\nFrame: %d" % f - context.currentFrame(f) + + # FIXME To get the correct camera position we have to use +1 here. + # Is there a bug somewhere in the Scene module? + context.currentFrame(f+1) + self.cameraObj = self._SCENE.getCurrentCamera() # Use some temporary workspace, a full copy of the scene inputScene = self._SCENE.copy(2) - # And Set our camera accordingly - self.cameraObj = inputScene.getCurrentCamera() + + # To get the objects at this frame remove the +1 ... + ctx = inputScene.getRenderingContext() + ctx.currentFrame(f) + # Get a projector for this camera. # NOTE: the projector wants object in world coordinates, -- 2.1.4