import sys
import os
import subprocess
class File:
"""Class representing a .pov file."""
def __init__(self, filename = "out.pov", *items):
if filename[-4:] == ".pov":
self.filename = filename[0:-4]
else:
self.filename = filename
self.file = open(self.filename + ".pov", "w")
self.__indent = 0
self.iwrite(*items)
def include(self, name):
"""Writes a POV-Ray include header.
@type name: string
@param name: the name of the POV-Ray include file, but without the
suffix: C{f.include("colors")} => C{#include "colors.inc"}
"""
self.writeln('#include "%s.inc"' % name)
def declare(self, name, val):
"""Writes a POV-Ray declare header in the form C{#declare} I{name}
C{=} I{val}.
@type name: string
@param name: the name to bind to
@type val: I{varies}
@param val: this can be anything that you would conceivable declare
in POV-Ray, be it function, literal, primitive, etc.
"""
self.write("#declare %s = " % name)
if hasattr(val, "iwrite"):
val.iwrite(self, False)
else:
self.writeln(str(val))
def indent(self):
"""Increase the level of indentation."""
self.__indent += 1
def dedent(self):
"""Decrease the level of indentation."""
self.__indent -= 1
assert self.__indent >= 0
def block_begin(self):
"""Opens a POV-Ray block in the file being written to."""
self.writeln("{")
self.indent()
def block_end(self):
"""Closes a POV-Ray block in the file being written to."""
self.dedent()
self.writeln("}")
if self.__indent == 0:
self.writeln()
def iwrite(self, *items):
"""Writes a variable number of Items to the file being written to.
@type items: Item
@param items: the items to be written
"""
for item in items:
item.iwrite(self)
def write(self, s = "", indent = True):
"""Write a string to the file being written to.
@type s: string
@param s: the string to write
@type indent: boolean
@param indent: whether or not to indent the string at the current
level of indentation
"""
self.file.write(
"".join([" " * self.__indent if indent else "", s]))
def writeln(self, s = "", indent = True):
"""Write a string to the file being written to and start a new line.
@type s: string
@param s: the string to write
@type indent: boolean
@param indent: whether or not to indent the string at the current
level of indentation
"""
self.file.write(
"".join([" " * self.__indent if indent else "",
s + os.linesep]))
def close(self):
"""Close the file being written to."""
self.file.close()
def render(self,
width,
height,
# quality = ?,
# add in frame number, time, etc.? and include in the
# non-verbose output message...?
povray = None,
output = None,
location = None,
verbose = True,
clean = False,
silent = True):
"""Close the file being written to (if necessary) and render the
resultant file using the passed arguments.
@type width: int
@param width: The width in pixels at which to render
@type height: int
@param height: The height in pixels at which to render
@type povray: string
@param povray: An optionally provided path to a povray binary
@type output: string
@param output: The name of a file to render to. If not provided,
.png will be appended to C{File:filename}
@type location: string
@param location: The directory to render to, defaults to the
current directory
@type verbose: boolean
@param verbose: Whether or not to output the typical POV-Ray output
information.
@type clean: boolean
@param clean: Whether or not to remove the .pov file after rendering
has finished.
@type silent: boolean
@param silent: Suppress annoying beep following rendering
completion.
"""
if not self.file.closed:
self.close()
if povray is None:
povray = "povray"
if location is None:
location = sys.path[0]
if output is None:
output = self.filename + ".png"
output = "+O%s" % os.path.join(location, output)
if not os.path.exists(location):
os.mkdir(location)
cmd = [povray,
"+I%s" % self.filename + ".pov",
output,
"+W%d" % width,
"+H%d" % height,
"-p" if silent else ""]
if clean:
cmd.extend(["&&", "rm", self.filename + ".pov"])
if verbose:
out = os.popen(" ".join(cmd))
for line in out.readlines():
print(line)
else:
print("Rendering %s..." % self.filename)
null = open(os.devnull, "w")
subprocess.Popen(cmd,
stdout = null,
stderr = null)
null.close()