PsychoBlend: use stdin/out to transfer scene data by default.
This eliminates writing temp files to disk for any part of the Blender/Psychopath integration. The option to export to a file still exists, however, by specifying an export output path.
This commit is contained in:
parent
a82c674308
commit
59555f67f9
|
@ -86,14 +86,16 @@ class IndentedWriter:
|
|||
|
||||
def write(self, text, do_indent=True):
|
||||
if do_indent:
|
||||
self.f.write(' '*self.indent_level + text)
|
||||
self.f.write(bytes(' '*self.indent_level + text, "utf-8"))
|
||||
else:
|
||||
self.f.write(text)
|
||||
self.f.write(bytes(text, "utf-8"))
|
||||
|
||||
|
||||
|
||||
|
||||
class PsychoExporter:
|
||||
def __init__(self, render_engine, scene):
|
||||
def __init__(self, f, render_engine, scene):
|
||||
self.w = IndentedWriter(f)
|
||||
self.render_engine = render_engine
|
||||
self.scene = scene
|
||||
|
||||
|
@ -119,24 +121,19 @@ class PsychoExporter:
|
|||
else:
|
||||
self.scene.frame_set(frame-1, 1.0+fraction)
|
||||
|
||||
def export_psy(self, export_path):
|
||||
def export_psy(self):
|
||||
try:
|
||||
f = open(export_path, 'w')
|
||||
self._export_psy(f, export_path)
|
||||
self._export_psy()
|
||||
except ExportCancelled:
|
||||
# Cleanup
|
||||
f.close()
|
||||
self.scene.frame_set(self.fr)
|
||||
return False
|
||||
else:
|
||||
# Cleanup
|
||||
f.close()
|
||||
self.scene.frame_set(self.fr)
|
||||
return True
|
||||
|
||||
def _export_psy(self, f, export_path):
|
||||
self.w = IndentedWriter(f)
|
||||
|
||||
def _export_psy(self):
|
||||
# Info
|
||||
self.w.write("# Exported from Blender 2.7x\n")
|
||||
|
||||
|
|
|
@ -2,16 +2,10 @@ import bpy
|
|||
import time
|
||||
import os
|
||||
import subprocess
|
||||
import tempfile
|
||||
import base64
|
||||
import struct
|
||||
from . import psy_export
|
||||
|
||||
def get_temp_filename(suffix=""):
|
||||
tmpf = tempfile.mkstemp(suffix=suffix, prefix='tmp')
|
||||
os.close(tmpf[0])
|
||||
return(tmpf[1])
|
||||
|
||||
class PsychopathRender(bpy.types.RenderEngine):
|
||||
bl_idname = 'PSYCHOPATH_RENDER'
|
||||
bl_label = "Psychopath"
|
||||
|
@ -40,23 +34,21 @@ class PsychopathRender(bpy.types.RenderEngine):
|
|||
return psy_binary
|
||||
return ""
|
||||
|
||||
def _export(self, scene, export_path):
|
||||
exporter = psy_export.PsychoExporter(self, scene)
|
||||
return exporter.export_psy(export_path)
|
||||
|
||||
def _render(self, scene, psy_filepath):
|
||||
def _render(self, scene, psy_filepath, use_stdin):
|
||||
psy_binary = PsychopathRender._locate_binary()
|
||||
if not psy_binary:
|
||||
print("Psychopath: could not execute psychopath, possibly Psychopath isn't installed")
|
||||
return False
|
||||
|
||||
# TODO: figure out command line options
|
||||
args = ["--spb", str(scene.psychopath.max_samples_per_bucket), "--blender_output", "-i", psy_filepath]
|
||||
if use_stdin:
|
||||
args = ["--spb", str(scene.psychopath.max_samples_per_bucket), "--blender_output", "--use_stdin"]
|
||||
else:
|
||||
args = ["--spb", str(scene.psychopath.max_samples_per_bucket), "--blender_output", "-i", psy_filepath]
|
||||
|
||||
# Start Rendering!
|
||||
try:
|
||||
self._process = subprocess.Popen([psy_binary] + args, bufsize=1,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
self._process = subprocess.Popen([psy_binary] + args, bufsize=1, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
except OSError:
|
||||
# TODO, report api
|
||||
print("Psychopath: could not execute '%s'" % psy_binary)
|
||||
|
@ -90,25 +82,44 @@ class PsychopathRender(bpy.types.RenderEngine):
|
|||
# has to be called to update the frame on exporting animations
|
||||
scene.frame_set(scene.frame_current)
|
||||
|
||||
export_path = scene.psychopath.export_path
|
||||
export_path = scene.psychopath.export_path.strip()
|
||||
use_stdin = False
|
||||
if export_path != "":
|
||||
export_path += "_%d.psy" % scene.frame_current
|
||||
else:
|
||||
# Create a temporary file for exporting
|
||||
export_path = get_temp_filename('.psy')
|
||||
# We'll write directly to Psychopath's stdin
|
||||
use_stdin = True
|
||||
|
||||
# start export
|
||||
self.update_stats("", "Psychopath: Exporting data from Blender")
|
||||
if not self._export(scene, export_path):
|
||||
# Render cancelled in the middle of exporting,
|
||||
# so just return.
|
||||
return
|
||||
if use_stdin:
|
||||
# Start rendering
|
||||
if not self._render(scene, export_path, use_stdin):
|
||||
self.update_stats("", "Psychopath: Not found")
|
||||
return
|
||||
|
||||
# Start rendering
|
||||
self.update_stats("", "Psychopath: Rendering from exported file")
|
||||
if not self._render(scene, export_path):
|
||||
self.update_stats("", "Psychopath: Not found")
|
||||
return
|
||||
self.update_stats("", "Psychopath: Exporting data from Blender")
|
||||
# Export to Psychopath's stdin
|
||||
if not psy_export.PsychoExporter(self._process.stdin, self, scene).export_psy():
|
||||
# Render cancelled in the middle of exporting,
|
||||
# so just return.
|
||||
return
|
||||
self._process.stdin.write(bytes("__PSY_EOF__", "utf-8"))
|
||||
self._process.stdin.flush()
|
||||
|
||||
self.update_stats("", "Psychopath: Rendering")
|
||||
else:
|
||||
# start export
|
||||
self.update_stats("", "Psychopath: Exporting data from Blender")
|
||||
with open(export_path, 'w+b') as f:
|
||||
if not psy_export.PsychoExporter(f, self, scene).export_psy():
|
||||
# Render cancelled in the middle of exporting,
|
||||
# so just return.
|
||||
return
|
||||
|
||||
# Start rendering
|
||||
self.update_stats("", "Psychopath: Rendering from %s" % export_path)
|
||||
if not self._render(scene, export_path, use_stdin):
|
||||
self.update_stats("", "Psychopath: Not found")
|
||||
return
|
||||
|
||||
r = scene.render
|
||||
# compute resolution
|
||||
|
|
50
src/main.rs
50
src/main.rs
|
@ -82,7 +82,7 @@ fn main() {
|
|||
.value_name("FILE")
|
||||
.help("Input .psy file")
|
||||
.takes_value(true)
|
||||
.required_unless("dev")
|
||||
.required_unless_one(&["dev", "use_stdin"])
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("spp")
|
||||
|
@ -148,6 +148,12 @@ fn main() {
|
|||
.help("Used by PsychoBlend to pass render output through standard in/out.")
|
||||
.hidden(true)
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("use_stdin")
|
||||
.long("use_stdin")
|
||||
.help("Take scene file in from stdin instead of a file path.")
|
||||
.hidden(true)
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
// Print some misc useful dev info.
|
||||
|
@ -169,14 +175,46 @@ fn main() {
|
|||
"Parsing scene file...",
|
||||
);
|
||||
t.tick();
|
||||
let mut psy_contents = String::new();
|
||||
let dt = {
|
||||
let psy_contents = if args.is_present("use_stdin") {
|
||||
// Read from stdin
|
||||
let mut input = Vec::new();
|
||||
let tmp = std::io::stdin();
|
||||
let mut stdin = tmp.lock();
|
||||
let mut buf = vec![0u8; 4096];
|
||||
loop {
|
||||
let count = stdin
|
||||
.read(&mut buf)
|
||||
.expect("Unexpected end of scene input.");
|
||||
let start = if input.len() < 11 {
|
||||
0
|
||||
} else {
|
||||
input.len() - 11
|
||||
};
|
||||
let end = input.len() + count;
|
||||
input.extend(&buf[..count]);
|
||||
|
||||
let mut done = false;
|
||||
let mut trunc_len = 0;
|
||||
if let nom::IResult::Done(remaining, _) = take_until!(&input[start..end], "__PSY_EOF__") {
|
||||
done = true;
|
||||
trunc_len = input.len() - remaining.len();
|
||||
}
|
||||
if done {
|
||||
input.truncate(trunc_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
String::from_utf8(input).unwrap()
|
||||
} else {
|
||||
// Read from file
|
||||
let mut input = String::new();
|
||||
let fp = args.value_of("input").unwrap();
|
||||
let mut f = io::BufReader::new(File::open(fp).unwrap());
|
||||
let _ = f.read_to_string(&mut psy_contents);
|
||||
|
||||
DataTree::from_str(&psy_contents).unwrap()
|
||||
let _ = f.read_to_string(&mut input);
|
||||
input
|
||||
};
|
||||
|
||||
let dt = DataTree::from_str(&psy_contents).unwrap();
|
||||
println!("\tParsed scene file in {:.3}s", t.tick());
|
||||
|
||||
// Iterate through scenes and render them
|
||||
|
|
Loading…
Reference in New Issue
Block a user