summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2011-06-16 21:40:18 -0600
committerTavian Barnes <tavianator@gmail.com>2011-06-16 21:42:18 -0600
commit415c34935c58c05b5ca0e99a10198f871a90edf4 (patch)
tree7589888d26bbb4a7e711df020305ef4bff682aba
parenta2267a685e45593da8687f6dc5fd65e76d0259d3 (diff)
downloaddimension-415c34935c58c05b5ca0e99a10198f871a90edf4.tar.xz
Implement Progress class.
-rw-r--r--.gitignore2
-rw-r--r--dimension/dimension.in34
-rw-r--r--libdimension-python/Makefile.am4
-rw-r--r--libdimension-python/dimension.pxd15
-rw-r--r--libdimension-python/dimension.pyx58
-rw-r--r--libdimension-python/platform.c41
-rw-r--r--libdimension-python/platform.h29
7 files changed, 167 insertions, 16 deletions
diff --git a/.gitignore b/.gitignore
index 98c0048..0b501ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,7 +18,7 @@ Makefile.in
/*/doc
Doxyfile
__pycache__
-libdimension-python/*.c
+libdimension-python/dimension.c
dimension/dimension
# pkg-config files
diff --git a/dimension/dimension.in b/dimension/dimension.in
index dc243ab..1b6c229 100644
--- a/dimension/dimension.in
+++ b/dimension/dimension.in
@@ -21,6 +21,25 @@
import argparse
import os.path
+import sys
+
+# Display a progress bar
+def progress_bar(str, progress):
+ if not _args.quiet:
+ print(str, end = ' ')
+ sys.stdout.flush()
+
+ term_width = terminal_width()
+ width = term_width - (len(str) + 1)%term_width
+ for i in range(width):
+ progress.wait(i/width)
+ print('.', end = '')
+ sys.stdout.flush()
+
+ print()
+ sys.stdout.flush()
+
+ progress.finish()
# Parse the command line
_parser = argparse.ArgumentParser(
@@ -74,6 +93,7 @@ die_on_warnings(_args.strict)
# Defaults
objects = []
lights = []
+camera = PerspectiveCamera()
default_texture = Texture(finish = Ambient(0.1) + Diffuse(0.6))
default_interior = Interior()
background = Black
@@ -110,17 +130,15 @@ if _args.quality is not None:
scene.quality = _args.quality
# Raytrace the scene
-if not _args.quiet:
- if scene.nthreads == 1:
- print("Rendering scene ...")
- else:
- print("Rendering scene (using %d threads) ..." % scene.nthreads)
-
-scene.raytrace()
+if scene.nthreads == 1:
+ render_message = "Rendering scene"
+else:
+ render_message = "Rendering scene (using %d threads)" % scene.nthreads
+progress_bar(render_message, scene.raytrace_async())
# Write the output file
export_timer = Timer()
-canvas.write_PNG(_args.output)
+progress_bar("Writing %s" % _args.output, canvas.write_PNG_async(_args.output))
export_timer.complete()
# Print execution times
diff --git a/libdimension-python/Makefile.am b/libdimension-python/Makefile.am
index c1f5274..90d7d45 100644
--- a/libdimension-python/Makefile.am
+++ b/libdimension-python/Makefile.am
@@ -29,7 +29,9 @@ dimension.c: dimension.pyx dimension.pxd
cython --line-directives dimension.pyx
pyexec_LTLIBRARIES = dimension.la
-dimension_la_SOURCES = dimension.c
+dimension_la_SOURCES = dimension.c \
+ platform.c \
+ platform.h
dimension_la_LDFLAGS = -avoid-version -module
dimension_la_LIBADD = $(top_builddir)/libdimension/libdimension.la
diff --git a/libdimension-python/dimension.pxd b/libdimension-python/dimension.pxd
index b73b99c..6ac6319 100644
--- a/libdimension-python/dimension.pxd
+++ b/libdimension-python/dimension.pxd
@@ -64,6 +64,16 @@ cdef extern from "../libdimension/dimension.h":
void dmnsn_array_remove(dmnsn_array *array, size_t i)
void dmnsn_array_apply(dmnsn_array *array, dmnsn_callback_fn *callback)
+ ############
+ # Progress #
+ ############
+
+ ctypedef struct dmnsn_progress
+
+ int dmnsn_finish_progress(dmnsn_progress *progress)
+ double dmnsn_get_progress(dmnsn_progress *progress)
+ void dmnsn_wait_progress(dmnsn_progress *progress, double prog)
+
##########
# Timers #
##########
@@ -178,6 +188,7 @@ cdef extern from "../libdimension/dimension.h":
int dmnsn_png_optimize_canvas(dmnsn_canvas *canvas)
int dmnsn_png_write_canvas(dmnsn_canvas *canvas, FILE *file)
+ dmnsn_progress *dmnsn_png_write_canvas_async(dmnsn_canvas *canvas, FILE *file)
int dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas)
int dmnsn_gl_write_canvas(dmnsn_canvas *canvas)
@@ -377,3 +388,7 @@ cdef extern from "../libdimension/dimension.h":
void dmnsn_delete_scene(dmnsn_scene *scene)
void dmnsn_raytrace_scene(dmnsn_scene *scene)
+ dmnsn_progress *dmnsn_raytrace_scene_async(dmnsn_scene *scene)
+
+cdef extern from "platform.h":
+ unsigned int dmnsn_terminal_width()
diff --git a/libdimension-python/dimension.pyx b/libdimension-python/dimension.pyx
index d5fbd1f..e1aba28 100644
--- a/libdimension-python/dimension.pyx
+++ b/libdimension-python/dimension.pyx
@@ -28,11 +28,53 @@ import os
# Globals #
###########
-# Make warnings fatal
def die_on_warnings(always_die):
"""Whether to treat Dimension warnings as errors."""
dmnsn_die_on_warnings(always_die)
+def terminal_width():
+ """Return the width of the terminal, if present."""
+ return dmnsn_terminal_width()
+
+############
+# Progress #
+############
+
+cdef class Progress:
+ cdef dmnsn_progress *_progress
+
+ def __cinit__(self):
+ self._progress = NULL
+
+ def __init__(self):
+ raise RuntimeError("attempt to create a Progress object.")
+
+ def __dealloc__(self):
+ self.finish()
+
+ def finish(self):
+ if self._progress != NULL:
+ try:
+ if dmnsn_finish_progress(self._progress) != 0:
+ raise RuntimeError("background task failed.")
+ finally:
+ self._progress = NULL
+
+ def progress(self):
+ if self._progress == NULL:
+ raise RuntimeError("background task finished.")
+ return dmnsn_get_progress(self._progress)
+
+ def wait(self, progress):
+ if self._progress == NULL:
+ raise RuntimeError("background task finished.")
+ dmnsn_wait_progress(self._progress, progress)
+
+cdef _Progress(dmnsn_progress *progress):
+ cdef Progress self = Progress.__new__(Progress)
+ self._progress = progress
+ return self
+
##########
# Timers #
##########
@@ -107,7 +149,7 @@ cdef class Vector:
elif args[0] == 0:
self._v = dmnsn_zero
else:
- raise TypeError, "expected a sequence or 0"
+ raise TypeError("expected a sequence or 0")
else:
self._real_init(*args, **kwargs)
@@ -471,14 +513,16 @@ cdef class Canvas:
def write_PNG(self, path):
"""Export the canvas as a PNG file."""
+ self.write_PNG_async(path).finish()
+ def write_PNG_async(self, path):
+ """Export the canvas as a PNG file, in the background."""
bpath = path.encode("UTF-8")
cdef char *cpath = bpath
cdef FILE *file = fopen(cpath, "wb")
if file == NULL:
raise OSError(errno, os.strerror(errno))
- if dmnsn_png_write_canvas(self._canvas, file) != 0:
- raise OSError(errno, os.strerror(errno))
+ return _Progress(dmnsn_png_write_canvas_async(self._canvas, file))
def draw_GL(self):
"""Export the canvas to the current OpenGL context."""
@@ -1317,11 +1361,13 @@ cdef class Scene:
def raytrace(self):
"""Render the scene."""
+ self.raytrace_async().finish()
+ def raytrace_async(self):
+ """Render the scene, in the background."""
# Ensure the default texture is complete
cdef Texture default = Texture(Black)
dmnsn_texture_cascade(default._texture, &self._scene.default_texture)
-
- dmnsn_raytrace_scene(self._scene)
+ return _Progress(dmnsn_raytrace_scene_async(self._scene))
def __dealloc__(self):
dmnsn_delete_scene(self._scene)
diff --git a/libdimension-python/platform.c b/libdimension-python/platform.c
new file mode 100644
index 0000000..30dde93
--- /dev/null
+++ b/libdimension-python/platform.c
@@ -0,0 +1,41 @@
+/*************************************************************************
+ * Copyright (C) 2011 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * This file is part of The Dimension Python Module. *
+ * *
+ * The Dimension Python Module 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. *
+ * *
+ * The Dimension Python Module 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 <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#include "platform.h"
+#if HAVE_UNISTD_H
+ #include <unistd.h>
+#endif
+#if DMNSN_TIOCGWINSZ
+ #include <sys/ioctl.h>
+#endif
+
+unsigned int
+dmnsn_terminal_width(void)
+{
+ unsigned int width = 80;
+
+#if DMNSN_TIOCGWINSZ
+ struct winsize ws;
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0) {
+ width = ws.ws_col;
+ }
+#endif
+
+ return width;
+}
diff --git a/libdimension-python/platform.h b/libdimension-python/platform.h
new file mode 100644
index 0000000..892217a
--- /dev/null
+++ b/libdimension-python/platform.h
@@ -0,0 +1,29 @@
+/*************************************************************************
+ * Copyright (C) 2011 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * This file is part of The Dimension Python Module. *
+ * *
+ * The Dimension Python Module 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. *
+ * *
+ * The Dimension Python Module 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 <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#ifndef PLATFORM_H
+#define PLATFORM_H
+
+/**
+ * Get the width of the terminal.
+ * @return The width (in characters) of the terminal, defaulting to 80.
+ */
+unsigned int dmnsn_terminal_width(void);
+
+#endif /* PLATFORM_H */