From dc281b3471773935ec4da66864e6a6c768c41ff6 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 3 Nov 2011 23:39:07 -0400 Subject: Add a preview window written with PyQt. --- Makefile.am | 4 ++- dimension/Makefile.am | 3 ++- dimension/client.py.in | 26 +++++++++++++++++++- dimension/preview.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 dimension/preview.py diff --git a/Makefile.am b/Makefile.am index f455fe3..6cad2e3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -28,9 +28,11 @@ EXTRA_DIST = autogen.sh # Set up ./dimension as a python package for tests $(abs_builddir)/dimension/__init__.py: ln -sf "$(abs_top_srcdir)/dimension/__init__.py" dimension/__init__.py +$(abs_builddir)/dimension/preview.py: + ln -sf "$(abs_top_srcdir)/dimension/preview.py" dimension/preview.py $(abs_builddir)/dimension/wrapper.so: ln -sf ../libdimension-python/.libs/wrapper.so dimension/wrapper.so -all-local: $(abs_builddir)/dimension/__init__.py $(abs_builddir)/dimension/wrapper.so +all-local: $(abs_builddir)/dimension/__init__.py $(abs_builddir)/dimension/preview.py $(abs_builddir)/dimension/wrapper.so bench: cd libdimension && $(MAKE) $(AM_MAKEFLAGS) bench diff --git a/dimension/Makefile.am b/dimension/Makefile.am index c12a6b7..a892601 100644 --- a/dimension/Makefile.am +++ b/dimension/Makefile.am @@ -26,7 +26,8 @@ dist_bin_SCRIPTS = dimension # since it's not really installed, so disable the --help and --version checks AM_INSTALLCHECK_STD_OPTIONS_EXEMPT = dimension -pkgpython_PYTHON = __init__.py +pkgpython_PYTHON = __init__.py \ + preview.py nodist_pkgpython_PYTHON = client.py clean-local: diff --git a/dimension/client.py.in b/dimension/client.py.in index 4881f62..127b96c 100644 --- a/dimension/client.py.in +++ b/dimension/client.py.in @@ -23,9 +23,16 @@ import argparse import re import os import sys +import threading from contextlib import contextmanager from dimension import * +have_preview = True +try: + from dimension import preview +except ImportError: + have_preview = False + def main(): """Invoke the client from the command line.""" @@ -68,6 +75,9 @@ def main(): parser.add_argument("input", action = "store", type = str, help = "the input scene description file") + parser.add_argument("-p", "--preview", action = "store_true", + help = "display a preview while the image renders") + # Debugging/testing options parser.add_argument("--strict", action = "store_true", help = argparse.SUPPRESS) @@ -118,6 +128,8 @@ def main(): # Make the canvas canvas = Canvas(width = args.region_width, height = args.region_height) canvas.optimize_PNG() + if args.preview: + canvas.optimize_GL() # Make the scene object scene = Scene(canvas = canvas, @@ -146,12 +158,19 @@ def main(): # Ray-trace the scene future = scene.ray_trace_async() + bar = None if not args.quiet: if scene.nthreads == 1: render_message = "Rendering scene" else: render_message = "Rendering scene (using %d threads)" % scene.nthreads - progress_bar(render_message, future) + bar = progress_bar_async(render_message, future) + if args.preview: + if have_preview: + preview.show_preview(canvas, future) + else: + print("Couldn't display preview window", file = sys.stderr) + bar.join() future.join() # Write the output file @@ -238,3 +257,8 @@ def progress_bar(str, future): # Swallow the failure exception pass raise + +def progress_bar_async(str, future): + thread = threading.Thread(target = progress_bar, args = (str, future)) + thread.start() + return thread diff --git a/dimension/preview.py b/dimension/preview.py new file mode 100644 index 0000000..868c16b --- /dev/null +++ b/dimension/preview.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +######################################################################### +# Copyright (C) 2011 Tavian Barnes # +# # +# This file is part of Dimension. # +# # +# Dimension is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the # +# Free Software Foundation; either version 3 of the License, or (at # +# your option) any later version. # +# # +# Dimension is distributed in the hope that it will be useful, but # +# WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # +# General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +######################################################################### + +from PyQt4 import QtCore, QtGui, QtOpenGL + +class Preview(QtOpenGL.QGLWidget): + """Surface that the scene is rendered to.""" + def __init__(self, parent, canvas): + QtOpenGL.QGLWidget.__init__(self, parent) + self.canvas = canvas + + def paintGL(self): + self.canvas.draw_GL() + +class PreviewWindow(QtGui.QMainWindow): + """Main window for a rendering preview.""" + def __init__(self, canvas, future): + QtGui.QMainWindow.__init__(self) + self.canvas = canvas + self.future = future + + self.setMinimumSize(canvas.width, canvas.height) + self.setMaximumSize(canvas.width, canvas.height) + self.widget = Preview(self, canvas) + self.setCentralWidget(self.widget) + + self.render_timer = QtCore.QTimer(self) + self.render_timer.timeout.connect(self.update_preview) + self.render_timer.start(0) + + @QtCore.pyqtSlot() + def update_preview(self): + self.widget.updateGL() + if self.future.progress() == 1: + self.render_timer.stop() + self.close_timer = QtCore.QTimer(self) + self.close_timer.singleShot(1000, self.close) + + @QtCore.pyqtSlot() + def close(self): + QtCore.QCoreApplication.instance().quit() + +def show_preview(canvas, future): + app = QtGui.QApplication(["Dimension Preview"]) + window = PreviewWindow(canvas, future) + window.show() + app.exec() + del window -- cgit v1.2.3