summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2011-07-29 00:38:18 -0600
committerTavian Barnes <tavianator@gmail.com>2011-07-29 00:38:18 -0600
commit5a8b1d413e98abd10b8ca6b1eb5eb91987f39ebf (patch)
tree705f357b3e8acddce87578f46cb8f9cb013b36eb
parent9de8a544bc0bae9ebbc2eed10c120a7e14af441e (diff)
downloaddimension-5a8b1d413e98abd10b8ca6b1eb5eb91987f39ebf.tar.xz
Support rendering image subregions.
This is the first step to supporting distributed renders.
-rw-r--r--dimension/dimension.in92
-rw-r--r--libdimension-python/dimension.pxd7
-rw-r--r--libdimension-python/dimension.pyx47
-rw-r--r--libdimension/dimension/scene.h6
-rw-r--r--libdimension/raytrace.c4
-rw-r--r--libdimension/scene.c11
6 files changed, 127 insertions, 40 deletions
diff --git a/dimension/dimension.in b/dimension/dimension.in
index f8cb114..b81f44b 100644
--- a/dimension/dimension.in
+++ b/dimension/dimension.in
@@ -19,36 +19,19 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
#########################################################################
-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()
+import argparse as _argparse
+import re as _re
+import os.path as _path
+import sys as _sys
# Specialized parser to print --version output to stdout rather than stderr,
# to pass distcheck
-class _DimensionArgumentParser(argparse.ArgumentParser):
+class _DimensionArgumentParser(_argparse.ArgumentParser):
def exit(self, status = 0, message = None):
if message:
- file = sys.stdout if status == 0 else sys.stderr
+ file = _sys.stdout if status == 0 else _sys.stderr
file.write(message)
- sys.exit(status)
+ _sys.exit(status)
# Parse the command line
_parser = _DimensionArgumentParser(
@@ -56,7 +39,7 @@ _parser = _DimensionArgumentParser(
"@PACKAGE_URL@\n"
"Copyright (C) 2009-2011 Tavian Barnes <@PACKAGE_BUGREPORT@>\n"
"Licensed under the GNU General Public License",
- formatter_class = argparse.RawDescriptionHelpFormatter,
+ formatter_class = _argparse.RawDescriptionHelpFormatter,
conflict_handler = "resolve", # For -h as height instead of help
)
@@ -67,6 +50,9 @@ _parser.add_argument("-w", "--width", action = "store", type = int,
default = 768, help = "image width")
_parser.add_argument("-h", "--height", action = "store", type = int,
default = 480, help = "image height")
+_parser.add_argument("--region", action = "store", type = str,
+ default = None,
+ help = "subregion to render, as \"((x1, y1), (x2, y2))\"")
_parser.add_argument("-v", "--verbose", action = "store_true",
help = "print more information")
@@ -85,23 +71,63 @@ _parser.add_argument("input", action = "store", type = str,
# Debugging/testing options
_parser.add_argument("--strict", action = "store_true",
- help = argparse.SUPPRESS)
+ help = _argparse.SUPPRESS)
_args = _parser.parse_args()
+# Calculate subregion
+if _args.region is None:
+ _args.region_x = 0
+ _args.region_y = 0
+ _args.region_width = _args.width
+ _args.region_height = _args.height
+else:
+ _pattern = r"^\s*\(\s*\(\s*(\d*)\s*,\s*(\d*)\s*\)\s*,\s*\(\s*(\d*)\s*,\s*(\d*)\s*\)\s*\)\s*$"
+ _match = _re.match(_pattern, _args.region)
+ if _match is None:
+ raise RuntimeError("range specified in invalid format.")
+ _args.region_x = int(_match.group(1))
+ _args.region_y = int(_match.group(2))
+ _args.region_width = int(_match.group(3)) - _args.region_x
+ _args.region_height = int(_match.group(4)) - _args.region_y
+ if _args.region_x + _args.region_width >= _args.width:
+ raise RuntimeError("region exceeds width of image.")
+ if _args.region_y + _args.region_height >= _args.height:
+ raise RuntimeError("region exceeds height of image.")
+
# Default output is basename(input).png
if _args.output is None:
- _noext = os.path.splitext(os.path.basename(_args.input))[0]
+ _noext = _path.splitext(_path.basename(_args.input))[0]
_args.output = _noext + ".png"
# Imports available to scripts
from math import *
from dimension import *
+# 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()
+
# --strict option
die_on_warnings(_args.strict)
-# Defaults
+# Defaults/available variables
+image_width = _args.width
+image_height = _args.height
objects = []
lights = []
camera = PerspectiveCamera()
@@ -121,7 +147,7 @@ with open(_args.input) as _fh:
parse_timer.complete()
# Make the canvas
-canvas = Canvas(width = _args.width, height = _args.height)
+canvas = Canvas(width = _args.region_width, height = _args.region_height)
canvas.optimize_PNG()
# Make the scene object
@@ -129,6 +155,10 @@ scene = Scene(canvas = canvas,
objects = objects,
lights = lights,
camera = camera)
+scene.region_x = _args.region_x
+scene.region_y = _args.region_y
+scene.outer_width = _args.width
+scene.outer_height = _args.height
scene.default_texture = default_texture
scene.background = background
if sky_sphere is not None:
@@ -145,11 +175,11 @@ 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())
+_progress_bar(render_message, scene.raytrace_async())
# Write the output file
export_timer = Timer()
-progress_bar("Writing %s" % _args.output, canvas.write_PNG_async(_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/dimension.pxd b/libdimension-python/dimension.pxd
index 9bfe5a9..411be3f 100644
--- a/libdimension-python/dimension.pxd
+++ b/libdimension-python/dimension.pxd
@@ -372,10 +372,15 @@ cdef extern from "../libdimension/dimension.h":
dmnsn_texture *default_texture
dmnsn_interior *default_interior
+ dmnsn_canvas *canvas
+ size_t region_x
+ size_t region_y
+ size_t outer_width
+ size_t outer_height
+
dmnsn_array *objects
dmnsn_array *lights
dmnsn_camera *camera
- dmnsn_canvas *canvas
dmnsn_quality quality
unsigned int reclimit
diff --git a/libdimension-python/dimension.pyx b/libdimension-python/dimension.pyx
index 2197edd..baafcd6 100644
--- a/libdimension-python/dimension.pyx
+++ b/libdimension-python/dimension.pyx
@@ -1298,6 +1298,8 @@ cdef class Scene:
self._scene.canvas = canvas._canvas
DMNSN_INCREF(self._scene.canvas)
+ self.outer_width = self._scene.canvas.width
+ self.outer_height = self._scene.canvas.height
cdef dmnsn_object *o
for obj in objects:
@@ -1311,14 +1313,35 @@ cdef class Scene:
DMNSN_INCREF(l)
dmnsn_array_push(self._scene.lights, &l)
- # Account for image dimensions in the camera
- camera._camera.trans = dmnsn_matrix_mul(
- camera._camera.trans,
- dmnsn_scale_matrix(dmnsn_new_vector(canvas.width/canvas.height, 1.0, 1.0))
- )
self._scene.camera = camera._camera
DMNSN_INCREF(self._scene.camera)
+ # Subregion render support
+ property region_x:
+ """The x-coordinate of the subregion in the broader image."""
+ def __get__(self):
+ return self._scene.region_x
+ def __set__(self, x):
+ self._scene.region_x = x
+ property region_y:
+ """The y-coordinate of the subregion in the broader image."""
+ def __get__(self):
+ return self._scene.region_y
+ def __set__(self, y):
+ self._scene.region_y = y
+ property outer_width:
+ """The width of the broader image."""
+ def __get__(self):
+ return self._scene.outer_width
+ def __set__(self, width):
+ self._scene.outer_width = width
+ property outer_height:
+ """The height of the broader image."""
+ def __get__(self):
+ return self._scene.outer_height
+ def __set__(self, height):
+ self._scene.outer_height = height
+
property default_texture:
"""The default Texture for objects."""
def __get__(self):
@@ -1400,8 +1423,20 @@ cdef class Scene:
self.raytrace_async().finish()
def raytrace_async(self):
"""Render the scene, in the background."""
+ # Account for image dimensions in the camera
+ # Do this here so subregion renders can tell us the broader image size
+ self._scene.camera.trans = dmnsn_matrix_mul(
+ self._scene.camera.trans,
+ dmnsn_scale_matrix(
+ dmnsn_new_vector(
+ self.outer_width/self.outer_height,
+ 1.0,
+ 1.0
+ )
+ )
+ )
# Ensure the default texture is complete
- cdef Texture default = Texture(Black)
+ cdef Texture default = Texture(pigment = Black)
dmnsn_texture_cascade(default._texture, &self._scene.default_texture)
return _Progress(dmnsn_raytrace_scene_async(self._scene))
diff --git a/libdimension/dimension/scene.h b/libdimension/dimension/scene.h
index 969fa45..41e2360 100644
--- a/libdimension/dimension/scene.h
+++ b/libdimension/dimension/scene.h
@@ -48,6 +48,12 @@ typedef struct dmnsn_scene {
/** Canvas. */
dmnsn_canvas *canvas;
+ /* Support for rendering image subregions. */
+ size_t region_x; /**< The x position of the canvas in the broader image. */
+ size_t region_y; /**< The y position of the canvas in the broader image. */
+ size_t outer_width; /**< Width of the broader image. */
+ size_t outer_height; /**< Height of the broader image. */
+
/** Objects. */
dmnsn_array *objects;
diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c
index 06878fd..cb5c8b6 100644
--- a/libdimension/raytrace.c
+++ b/libdimension/raytrace.c
@@ -184,8 +184,8 @@ dmnsn_raytrace_scene_concurrent(void *ptr, unsigned int thread,
/* Get the ray corresponding to the (x,y)'th pixel */
dmnsn_line ray = dmnsn_camera_ray(
scene->camera,
- ((double)x)/(scene->canvas->width - 1),
- ((double)y)/(scene->canvas->height - 1)
+ ((double)(x + scene->region_x))/(scene->outer_width - 1),
+ ((double)(y + scene->region_y))/(scene->outer_height - 1)
);
/* Shoot a ray */
diff --git a/libdimension/scene.c b/libdimension/scene.c
index ef597ee..f0ff451 100644
--- a/libdimension/scene.c
+++ b/libdimension/scene.c
@@ -37,6 +37,10 @@ dmnsn_new_scene(void)
scene->default_texture = dmnsn_new_texture();
scene->default_interior = dmnsn_new_interior();
scene->canvas = NULL;
+ scene->region_x = 0;
+ scene->region_y = 0;
+ scene->outer_width = 0;
+ scene->outer_height = 0;
scene->objects = dmnsn_new_array(sizeof(dmnsn_object *));
scene->lights = dmnsn_new_array(sizeof(dmnsn_light *));
scene->camera = NULL;
@@ -83,6 +87,13 @@ dmnsn_initialize_scene(dmnsn_scene *scene)
dmnsn_assert(!scene->initialized, "Texture double-initialized.");
scene->initialized = true;
+ if (scene->outer_width == 0) {
+ scene->outer_width = scene->canvas->width;
+ }
+ if (scene->outer_height == 0) {
+ scene->outer_height = scene->canvas->height;
+ }
+
dmnsn_initialize_texture(scene->default_texture);
if (scene->sky_sphere) {