Newer
Older
file.write("Antialias=off\n")
#print("ini file closed %s" % file.closed)
#print("ini file closed %s" % file.closed)
bl_label = "POV-Ray 3.7"
def _export(self, scene, povPath, renderImagePath):
Bastien Montagne
committed
if scene.pov.tempfiles_enable:
self._temp_file_in = tempfile.NamedTemporaryFile(suffix=".pov", delete=False).name
Bastien Montagne
committed
# PNG with POV 3.7, can show the background color with alpha. In the long run using the
# POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".png", delete=False).name
#self._temp_file_out = tempfile.NamedTemporaryFile(suffix=".tga", delete=False).name
self._temp_file_ini = tempfile.NamedTemporaryFile(suffix=".ini", delete=False).name
else:
self._temp_file_in = povPath + ".pov"
Bastien Montagne
committed
# PNG with POV 3.7, can show the background color with alpha. In the long run using the
# POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
self._temp_file_out = renderImagePath + ".png"
#self._temp_file_out = renderImagePath + ".tga"
self._temp_file_ini = povPath + ".ini"
'''
self._temp_file_in = "/test.pov"
Bastien Montagne
committed
# PNG with POV 3.7, can show the background color with alpha. In the long run using the
# POV-Ray interactive preview like bishop 3D could solve the preview for all formats.
self._temp_file_out = "/test.png"
#self._temp_file_out = "/test.tga"
self._temp_file_ini = "/test.ini"
'''
self.update_stats("", "POV-Ray 3.7: " + txt)
write_pov(self._temp_file_in, scene, info_callback)
Constantin Rahn
committed
def _render(self, scene):
addon_prefs = bpy.context.user_preferences.addons[__package__].preferences
os.remove(self._temp_file_out) # so as not to load the old file
write_pov_ini(scene, self._temp_file_ini, self._temp_file_in, self._temp_file_out)
print ("***-STARTING-***")
# Use the system preference if its set.
pov_binary = addon_prefs.filepath_povray
pov_binary_default = "povray"
if pov_binary:
pov_binary_found = os.path.exists(pov_binary)
else:
pov_binary = pov_binary_default
pov_binary_found = False
Doug Hammond
committed
extra_args = []
Bastien Montagne
committed
if scene.pov.command_line_switches != "":
for newArg in scene.pov.command_line_switches.split(" "):
Constantin Rahn
committed
extra_args.append(newArg)
self._is_windows = False
self._is_windows = True
#extra_args.append("/EXIT")
import platform as pltfrm
if pltfrm.architecture()[0] == "64bit":
bitness = 64
else:
bitness = 32
regKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\POV-Ray\\v3.7\\Windows")
Maurice Raybaud
committed
# TODO, report api
# 64 bits blender
if not pov_binary_found:
pov_binary = winreg.QueryValueEx(regKey, "Home")[0] + "\\bin\\pvengine64"
Bastien Montagne
committed
self._process = subprocess.Popen(
[pov_binary, self._temp_file_ini] + extra_args,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
Maurice Raybaud
committed
# This would work too but means we have to wait until its done:
# os.system("%s %s" % (pov_binary, self._temp_file_ini))
except OSError:
# someone might run povray 32 bits on a 64 bits blender machine
try:
if not pov_binary_found:
pov_binary = winreg.QueryValueEx(regKey, "Home")[0] + "\\bin\\pvengine"
Bastien Montagne
committed
self._process = subprocess.Popen(
[pov_binary, self._temp_file_ini] + extra_args,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError:
Maurice Raybaud
committed
# TODO, report api
Bastien Montagne
committed
print("POV-Ray 3.7: could not execute '%s', possibly POV-Ray isn't " \
"installed" % pov_binary)
Maurice Raybaud
committed
import traceback
traceback.print_exc()
print ("***-DONE-***")
return False
else:
print("POV-Ray 3.7 64 bits could not execute, running 32 bits instead")
Maurice Raybaud
committed
print("Command line arguments passed: " + str(extra_args))
return True
else:
print("POV-Ray 3.7 64 bits found")
Maurice Raybaud
committed
print("Command line arguments passed: " + str(extra_args))
return True
if not pov_binary_found:
pov_binary = winreg.QueryValueEx(regKey, "Home")[0] + "\\bin\\pvengine"
Bastien Montagne
committed
self._process = subprocess.Popen(
[pov_binary, self._temp_file_ini] + extra_args,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# someone might also run povray 64 bits with a 32 bits build of blender.
except OSError:
try:
if not pov_binary_found:
pov_binary = winreg.QueryValueEx(regKey, "Home")[0] + "\\bin\\pvengine64"
Bastien Montagne
committed
self._process = subprocess.Popen(
[pov_binary, self._temp_file_ini] + extra_args,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError:
Maurice Raybaud
committed
# TODO, report api
Bastien Montagne
committed
print("POV-Ray 3.7: could not execute '%s', possibly POV-Ray isn't " \
"installed" % pov_binary)
Maurice Raybaud
committed
import traceback
traceback.print_exc()
print ("***-DONE-***")
return False
Bastien Montagne
committed
print("Running POV-Ray 3.7 64 bits build with 32 bits Blender,\n" \
"You might want to run Blender 64 bits as well.")
Maurice Raybaud
committed
print("Command line arguments passed: " + str(extra_args))
return True
else:
print("POV-Ray 3.7 32 bits found")
Maurice Raybaud
committed
print("Command line arguments passed: " + str(extra_args))
return True
Doug Hammond
committed
else:
# DH - added -d option to prevent render window popup which leads to segfault on linux
extra_args.append("-d")
if not pov_binary_found:
pov_binary_found = False
sysPathList = os.getenv("PATH").split(':')
sysPathList.append("")
for dirName in sysPathList:
fn = os.path.join(dirName, pov_binary_default)
if os.path.exists(fn):
pov_binary = fn
pov_binary_found = True
break
if not pov_binary_found:
print("POV-Ray 3.7: could not found execute '%s' - not if PATH" % pov_binary)
import traceback
traceback.print_exc()
print ("***-DONE-***")
return False
self._process = subprocess.Popen([pov_binary, self._temp_file_ini] + extra_args,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except OSError:
# TODO, report api
print("POV-Ray 3.7: could not execute '%s'" % pov_binary)
import traceback
traceback.print_exc()
print ("***-DONE-***")
return False
else:
print("POV-Ray 3.7 found")
print("Command line arguments passed: " + str(extra_args))
return True
# Now that we have a valid process
def _cleanup(self):
for f in (self._temp_file_in, self._temp_file_ini, self._temp_file_out):
for i in range(5):
try:
os.unlink(f)
break
except OSError:
# Wait a bit before retrying file might be still in use by Blender,
# and Windows does not know how to delete a file in use!
time.sleep(self.DELAY)
## if r.image_settings.file_format == 'OPENEXR':
## render.image_settings.color_mode = 'RGBA'
## r.image_settings.file_format = 'TARGA'
## r.image_settings.color_mode = 'RGBA'
blendSceneName = bpy.data.filepath.split(os.path.sep)[-1].split(".")[0]
povSceneName = ""
povPath = ""
renderImagePath = ""
Bastien Montagne
committed
# has to be called to update the frame on exporting animations
scene.frame_set(scene.frame_current)
Bastien Montagne
committed
if not scene.pov.tempfiles_enable:
Bastien Montagne
committed
povPath = bpy.path.abspath(scene.pov.scene_path).replace('\\', '/')
if bpy.data.is_saved:
povPath = bpy.path.abspath("//")
else:
povPath = tempfile.gettempdir()
elif povPath.endswith("/"):
if povPath == "/":
povPath = bpy.path.abspath("//")
else:
Bastien Montagne
committed
povPath = bpy.path.abspath(scene.pov.scene_path)
try:
os.makedirs(povPath)
except:
import traceback
traceback.print_exc()
print("POV-Ray 3.7: Cannot create scenes directory: %r" % povPath)
Bastien Montagne
committed
self.update_stats("", "POV-Ray 3.7: Cannot create scenes directory %r" % \
povPath)
time.sleep(2.0)
return
Bastien Montagne
committed
renderImagePath = bpy.path.abspath(scene.pov.renderimage_path).replace('\\','/')
if bpy.data.is_saved:
renderImagePath = bpy.path.abspath("//")
else:
renderImagePath = tempfile.gettempdir()
#print("Path: " + renderImagePath)
elif path.endswith("/"):
if renderImagePath == "/":
renderImagePath = bpy.path.abspath("//")
else:
Bastien Montagne
committed
renderImagePath = bpy.path.abspath(scene.pov.renderimage_path)
if not os.path.exists(path):
print("POV-Ray 3.7: Cannot find render image directory")
self.update_stats("", "POV-Ray 3.7: Cannot find render image directory")
time.sleep(2.0)
return
'''
# check name
Bastien Montagne
committed
if scene.pov.scene_name == "":
if blendSceneName != "":
povSceneName = blendSceneName
else:
povSceneName = "untitled"
else:
Bastien Montagne
committed
povSceneName = scene.pov.scene_name
if os.path.isfile(povSceneName):
povSceneName = os.path.basename(povSceneName)
povSceneName = povSceneName.split('/')[-1].split('\\')[-1]
if not povSceneName:
print("POV-Ray 3.7: Invalid scene name")
self.update_stats("", "POV-Ray 3.7: Invalid scene name")
time.sleep(2.0)
return
povSceneName = os.path.splitext(povSceneName)[0]
print("Scene name: " + povSceneName)
print("Export path: " + povPath)
povPath = os.path.join(povPath, povSceneName)
povPath = os.path.realpath(povPath)
Bastien Montagne
committed
# for now this has to be the same like the pov output. Bug in POV-Ray RC3.
# renderImagePath = renderImagePath + "\\" + povSceneName
renderImagePath = povPath # Bugfix for POV-Ray RC3 bug
# renderImagePath = os.path.realpath(renderImagePath) # Bugfix for POV-Ray RC3 bug
#print("Export path: %s" % povPath)
#print("Render Image path: %s" % renderImagePath)
# start export
self.update_stats("", "POV-Ray 3.7: Exporting data from Blender")
self._export(scene, povPath, renderImagePath)
self.update_stats("", "POV-Ray 3.7: Parsing File")
if not self._render(scene):
self.update_stats("", "POV-Ray 3.7: Not found")
return
r = scene.render
# compute resolution
x = int(r.resolution_x * r.resolution_percentage * 0.01)
y = int(r.resolution_y * r.resolution_percentage * 0.01)
# This makes some tests on the render, returning True if all goes good, and False if
# it was finished one way or the other.
# It also pauses the script (time.sleep())
def _test_wait():
time.sleep(self.DELAY)
# User interrupts the rendering
print("***POV INTERRUPTED***")
return False
Doug Hammond
committed
poll_result = self._process.poll()
# POV process is finisehd, one way or the other
if poll_result < 0:
print("***POV PROCESS FAILED : %s ***" % poll_result)
self.update_stats("", "POV-Ray 3.7: Failed")
return False
return True
# Wait for the file to be created
# XXX This is no more valid, as 3.7 always creates output file once render is finished!
parsing = re.compile(br"= \[Parsing\.\.\.\] =")
rendering = re.compile(br"= \[Rendering\.\.\.\] =")
percent = re.compile(r"\(([0-9]{1,3})%\)")
# print("***POV WAITING FOR FILE***")
data = b""
last_line = ""
while _test_wait():
# POV in Windows does not output its stdout/stderr, it displays them in its GUI
if self._is_windows:
self.update_stats("", "POV-Ray 3.7: Rendering File")
else:
Bastien Montagne
committed
t_data = self._process.stdout.read(10000)
data += t_data
Bastien Montagne
committed
# XXX This is working for UNIX, not sure whether it might need adjustments for
# other OSs
# First replace is for windows
t_data = str(t_data).replace('\\r\\n', '\\n').replace('\\r', '\r')
lines = t_data.split('\\n')
last_line += lines[0]
lines[0] = last_line
print('\n'.join(lines), end="")
last_line = lines[-1]
if rendering.search(data):
_pov_rendering = True
match = percent.findall(str(data))
if match:
self.update_stats("", "POV-Ray 3.7: Rendering File (%s%%)" % match[-1])
else:
self.update_stats("", "POV-Ray 3.7: Rendering File")
elif parsing.search(data):
self.update_stats("", "POV-Ray 3.7: Parsing File")
if os.path.exists(self._temp_file_out):
# print("***POV FILE OK***")
#self.update_stats("", "POV-Ray 3.7: Rendering")
# prev_size = -1
xmin = int(r.border_min_x * x)
ymin = int(r.border_min_y * y)
xmax = int(r.border_max_x * x)
ymax = int(r.border_max_y * y)
# print("***POV UPDATING IMAGE***")
result = self.begin_result(0, 0, x, y)
Bastien Montagne
committed
# XXX, tests for border render.
#result = self.begin_result(xmin, ymin, xmax - xmin, ymax - ymin)
#result = self.begin_result(0, 0, xmax - xmin, ymax - ymin)
lay = result.layers[0]
# This assumes the file has been fully written We wait a bit, just in case!
time.sleep(self.DELAY)
try:
lay.load_from_file(self._temp_file_out)
Bastien Montagne
committed
# XXX, tests for border render.
#lay.load_from_file(self._temp_file_out, xmin, ymin)
except RuntimeError:
print("***POV ERROR WHILE READING OUTPUT FILE***")
# Not needed right now, might only be useful if we find a way to use temp raw output of
# pov 3.7 (in which case it might go under _test_wait()).
# def update_image():
# # possible the image wont load early on.
# try:
# lay.load_from_file(self._temp_file_out)
Bastien Montagne
committed
# # XXX, tests for border render.
# #lay.load_from_file(self._temp_file_out, xmin, ymin)
# #lay.load_from_file(self._temp_file_out, xmin, ymin)
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
# except RuntimeError:
# pass
# # Update while POV-Ray renders
# while True:
# # print("***POV RENDER LOOP***")
# # test if POV-Ray exists
# if self._process.poll() is not None:
# print("***POV PROCESS FINISHED***")
# update_image()
# break
# # user exit
# if self.test_break():
# try:
# self._process.terminate()
# print("***POV PROCESS INTERRUPTED***")
# except OSError:
# pass
# break
# # Would be nice to redirect the output
# # stdout_value, stderr_value = self._process.communicate() # locks
# # check if the file updated
# new_size = os.path.getsize(self._temp_file_out)
# if new_size != prev_size:
# update_image()
# prev_size = new_size
# time.sleep(self.DELAY)
self.end_result(result)
Doug Hammond
committed
else:
print("***POV FILE NOT FOUND***")
print("***POV FINISHED***")
self.update_stats("", "")
Bastien Montagne
committed
if scene.pov.tempfiles_enable or scene.pov.deletefiles_enable: