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):
|
def write(self, text, do_indent=True):
|
||||||
if do_indent:
|
if do_indent:
|
||||||
self.f.write(' '*self.indent_level + text)
|
self.f.write(bytes(' '*self.indent_level + text, "utf-8"))
|
||||||
else:
|
else:
|
||||||
self.f.write(text)
|
self.f.write(bytes(text, "utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PsychoExporter:
|
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.render_engine = render_engine
|
||||||
self.scene = scene
|
self.scene = scene
|
||||||
|
|
||||||
|
@ -119,24 +121,19 @@ class PsychoExporter:
|
||||||
else:
|
else:
|
||||||
self.scene.frame_set(frame-1, 1.0+fraction)
|
self.scene.frame_set(frame-1, 1.0+fraction)
|
||||||
|
|
||||||
def export_psy(self, export_path):
|
def export_psy(self):
|
||||||
try:
|
try:
|
||||||
f = open(export_path, 'w')
|
self._export_psy()
|
||||||
self._export_psy(f, export_path)
|
|
||||||
except ExportCancelled:
|
except ExportCancelled:
|
||||||
# Cleanup
|
# Cleanup
|
||||||
f.close()
|
|
||||||
self.scene.frame_set(self.fr)
|
self.scene.frame_set(self.fr)
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
# Cleanup
|
# Cleanup
|
||||||
f.close()
|
|
||||||
self.scene.frame_set(self.fr)
|
self.scene.frame_set(self.fr)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _export_psy(self, f, export_path):
|
def _export_psy(self):
|
||||||
self.w = IndentedWriter(f)
|
|
||||||
|
|
||||||
# Info
|
# Info
|
||||||
self.w.write("# Exported from Blender 2.7x\n")
|
self.w.write("# Exported from Blender 2.7x\n")
|
||||||
|
|
||||||
|
|
|
@ -2,16 +2,10 @@ import bpy
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
|
||||||
import base64
|
import base64
|
||||||
import struct
|
import struct
|
||||||
from . import psy_export
|
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):
|
class PsychopathRender(bpy.types.RenderEngine):
|
||||||
bl_idname = 'PSYCHOPATH_RENDER'
|
bl_idname = 'PSYCHOPATH_RENDER'
|
||||||
bl_label = "Psychopath"
|
bl_label = "Psychopath"
|
||||||
|
@ -40,23 +34,21 @@ class PsychopathRender(bpy.types.RenderEngine):
|
||||||
return psy_binary
|
return psy_binary
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def _export(self, scene, export_path):
|
def _render(self, scene, psy_filepath, use_stdin):
|
||||||
exporter = psy_export.PsychoExporter(self, scene)
|
|
||||||
return exporter.export_psy(export_path)
|
|
||||||
|
|
||||||
def _render(self, scene, psy_filepath):
|
|
||||||
psy_binary = PsychopathRender._locate_binary()
|
psy_binary = PsychopathRender._locate_binary()
|
||||||
if not psy_binary:
|
if not psy_binary:
|
||||||
print("Psychopath: could not execute psychopath, possibly Psychopath isn't installed")
|
print("Psychopath: could not execute psychopath, possibly Psychopath isn't installed")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# TODO: figure out command line options
|
# 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!
|
# Start Rendering!
|
||||||
try:
|
try:
|
||||||
self._process = subprocess.Popen([psy_binary] + args, bufsize=1,
|
self._process = subprocess.Popen([psy_binary] + args, bufsize=1, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
||||||
except OSError:
|
except OSError:
|
||||||
# TODO, report api
|
# TODO, report api
|
||||||
print("Psychopath: could not execute '%s'" % psy_binary)
|
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
|
# has to be called to update the frame on exporting animations
|
||||||
scene.frame_set(scene.frame_current)
|
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 != "":
|
if export_path != "":
|
||||||
export_path += "_%d.psy" % scene.frame_current
|
export_path += "_%d.psy" % scene.frame_current
|
||||||
else:
|
else:
|
||||||
# Create a temporary file for exporting
|
# We'll write directly to Psychopath's stdin
|
||||||
export_path = get_temp_filename('.psy')
|
use_stdin = True
|
||||||
|
|
||||||
# start export
|
if use_stdin:
|
||||||
self.update_stats("", "Psychopath: Exporting data from Blender")
|
# Start rendering
|
||||||
if not self._export(scene, export_path):
|
if not self._render(scene, export_path, use_stdin):
|
||||||
# Render cancelled in the middle of exporting,
|
self.update_stats("", "Psychopath: Not found")
|
||||||
# so just return.
|
return
|
||||||
return
|
|
||||||
|
|
||||||
# Start rendering
|
self.update_stats("", "Psychopath: Exporting data from Blender")
|
||||||
self.update_stats("", "Psychopath: Rendering from exported file")
|
# Export to Psychopath's stdin
|
||||||
if not self._render(scene, export_path):
|
if not psy_export.PsychoExporter(self._process.stdin, self, scene).export_psy():
|
||||||
self.update_stats("", "Psychopath: Not found")
|
# Render cancelled in the middle of exporting,
|
||||||
return
|
# 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
|
r = scene.render
|
||||||
# compute resolution
|
# compute resolution
|
||||||
|
|
50
src/main.rs
50
src/main.rs
|
@ -82,7 +82,7 @@ fn main() {
|
||||||
.value_name("FILE")
|
.value_name("FILE")
|
||||||
.help("Input .psy file")
|
.help("Input .psy file")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.required_unless("dev")
|
.required_unless_one(&["dev", "use_stdin"])
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("spp")
|
Arg::with_name("spp")
|
||||||
|
@ -148,6 +148,12 @@ fn main() {
|
||||||
.help("Used by PsychoBlend to pass render output through standard in/out.")
|
.help("Used by PsychoBlend to pass render output through standard in/out.")
|
||||||
.hidden(true)
|
.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();
|
.get_matches();
|
||||||
|
|
||||||
// Print some misc useful dev info.
|
// Print some misc useful dev info.
|
||||||
|
@ -169,14 +175,46 @@ fn main() {
|
||||||
"Parsing scene file...",
|
"Parsing scene file...",
|
||||||
);
|
);
|
||||||
t.tick();
|
t.tick();
|
||||||
let mut psy_contents = String::new();
|
let psy_contents = if args.is_present("use_stdin") {
|
||||||
let dt = {
|
// 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 fp = args.value_of("input").unwrap();
|
||||||
let mut f = io::BufReader::new(File::open(fp).unwrap());
|
let mut f = io::BufReader::new(File::open(fp).unwrap());
|
||||||
let _ = f.read_to_string(&mut psy_contents);
|
let _ = f.read_to_string(&mut input);
|
||||||
|
input
|
||||||
DataTree::from_str(&psy_contents).unwrap()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let dt = DataTree::from_str(&psy_contents).unwrap();
|
||||||
println!("\tParsed scene file in {:.3}s", t.tick());
|
println!("\tParsed scene file in {:.3}s", t.tick());
|
||||||
|
|
||||||
// Iterate through scenes and render them
|
// Iterate through scenes and render them
|
||||||
|
|
Loading…
Reference in New Issue
Block a user