# * 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
#
# ---------------------------------------------------------------------
class config:
polygons = dict()
polygons['SHOW'] = True
- polygons['SHADING'] = 'FLAT'
- #polygons['HSR'] = 'PAINTER' # 'PAINTER' or 'NEWELL'
- polygons['HSR'] = 'NEWELL'
+ polygons['SHADING'] = 'FLAT' # FLAT or TOON
+ polygons['HSR'] = 'NEWELL' # PAINTER or NEWELL
# Hidden to the user for now
polygons['EXPANSION_TRICK'] = True
edges = dict()
edges['SHOW'] = False
edges['SHOW_HIDDEN'] = False
- edges['STYLE'] = 'MESH' # or SILHOUETTE
+ edges['STYLE'] = 'MESH' # MESH or SILHOUETTE
edges['WIDTH'] = 2
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
- #output['FORMAT'] = 'SWF'
- #output['ANIMATION'] = True
-
# Utility functions
print_debug = False
isVertInside = staticmethod(isVertInside)
+
+ 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):
+ is_in = False
+
+ point_at_infinity = NMesh.Vert(-INF, q.co[1], -INF)
+
+ det = HSR.det
+
+ for i in range(len(P.v)):
+ p0 = P.v[i-1]
+ p1 = P.v[i]
+ if (det(q.co, point_at_infinity.co, p0.co)<0) != (det(q.co, point_at_infinity.co, p1.co)<0):
+ if det(p0.co, p1.co, q.co) == 0 :
+ #print "On Boundary"
+ return False
+ elif (det(p0.co, p1.co, q.co)<0) != (det(p0.co, p1.co, point_at_infinity.co)<0):
+ is_in = not is_in
+
+ return is_in
+
+ pointInPolygon = staticmethod(pointInPolygon)
+
def projectionsOverlap(f1, f2):
""" If you have nonconvex, but still simple polygons, an acceptable method
is to iterate over all vertices and perform the Point-in-polygon test[1].
# If a point of f1 in inside f2, there is an overlap!
v1 = f1.v[i]
- if HSR.isVertInside(f2, v1):
+ #if HSR.isVertInside(f2, v1):
+ if HSR.pointInPolygon(v1, f2):
return True
# If not the polygon can be ovelap as well, so we check for
"""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
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,
"""
VectorWriter.__init__(self, fileName)
+ self.file = None
+
##
# Public Methods
"""Do some initialization operations.
"""
VectorWriter.open(self, startFrame, endFrame)
+
+ self.file = open(self.outputFileName, "w")
+
self._printHeader()
def close(self):
"""
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)
self.canvasSize)
if self.animation:
+ delay = 1000/self.fps
self.file.write("""\n<script type="text/javascript"><![CDATA[
globalStartFrame=%d;
globalEndFrame=%d;
- /* FIXME: Use 1000 as interval as lower values gives problems */
- timerID = setInterval("NextFrame()", 1000);
+ timerID = setInterval("NextFrame()", %d);
globalFrameCounter=%d;
+ \n""" % (self.startFrame, self.endFrame, delay, self.startFrame) )
+ self.file.write("""\n
function NextFrame()
{
currentElement = document.getElementById('frame'+globalFrameCounter)
}
}
\n]]></script>\n
- \n""" % (self.startFrame, self.endFrame, self.startFrame) )
+ \n""")
def _printFooter(self):
"""Print the SVG footer."""
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.
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.
"""
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)
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])
+
+
# ---------------------------------------------------------------------
#
outputWriters['SVG'] = SVGVectorWriter
if SWFSupported:
outputWriters['SWF'] = SWFVectorWriter
+if PDFSupported:
+ outputWriters['PDF'] = PDFVectorWriter
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()
outputWriter.open(startFrame, endFrame)
# Do the rendering process frame by frame
- print "Start Rendering of %d frames" % (endFrame-startFrame)
+ 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,
if edgestyleSelect(e, mesh):
e.sel = 1
"""
+ #
# ---------------------------------------------------------------------
elif evt == GUI.evtOutFormatMenu:
i = GUI.outFormatMenu.val - 1
config.output['FORMAT']= outputWriters.keys()[i]
+ # Set the new output file
+ global outputfile
+ outputfile = Blender.sys.splitext(basename)[0] + "." + str(config.output['FORMAT']).lower()
elif evt == GUI.evtAnimToggle:
config.output['ANIMATION'] = bool(GUI.animToggle.val)