cleanup phase is done -- merging into the default branch

metadata
Wenzel Jakob 2010-09-21 23:33:59 +02:00
commit ebc7c814dd
651 changed files with 69476 additions and 14314 deletions

View File

@ -1,46 +1,63 @@
^Mitsuba.app/.*$
.*\.obj$
.*\.os$
.*\.so$
.*\.pyc$
.*\.o$
.*\.exe$
.*\.pdb$
.*\.manifest$
.*\.exp$
.*\.dylib$
# Documentation
^doc/doxygen/.*$
^doc/.*\.aux$
^doc/.*\.log$
^doc/.*\.out$
^doc/.*\.pdf$
^doc/.*\.toc$
# Qt-related
.*ui_.*\.h$
.*moc_.*\.cc$
.*qrc_.*\.cc$
\.DS_Store
# SCons-related
^\.sconf_temp/.*$
^.sconsign.dblite$
^config.py$
^config.log$
^.sconsign.dblite$
^src/utils/addimages$
.*\.pyc$
# OSX binaries and byproducts
^Mitsuba.app/.*$
\.DS_Store
.*\.dylib$
# Linux binaries and byproducts
^src/utils/createvol$
^src/utils/dumpimage$
^src/utils/joinrgb$
^src/utils/ssalbedo$
^src/utils/ttest$
^src/utils/utils_test$
^dist/.*$
^mitsuba$
^mtssrv$
^mtsgui$
^mtsimport$
^mtsutil$
.*\.so$
.*\.os$
.*\.o$
# Windows binaries and byproducts
.*\.exe$
.*\.obj$
^src/.*\.lib$
^src/.*\.dll$
^plugins/.*\.lib$
^plugins/.*\.dll$
^dist/.*$
tools/windows/mitsuba_res.res
.*\.pdb$
.*\.manifest$
.*\.exp$
# Imported geometry
^meshes/.*$
^textures/.*$
^mitsuba.*.log$
^doc/doxygen/.*$
# Eclipse CDT project files
^.externalToolBuilders/.*$
^.settings/.*$
^.cproject$
^.project$

177
ChangeLog
View File

@ -1,177 +0,0 @@
2010-08-12 Wenzel Jakob <wenzel@cs.cornell.edu>
* converter.cpp: Much better import of COLLADA scenes from
blender.
* importdlg.cpp: User interface for importing scenes.
2010-08-09 Wenzel Jakob <wenzel@cs.cornell.edu>
* rendersettingsdlg.cpp: Try to maintain the number of
samples/pixel when switching between different samplers.
2010-08-05 Wenzel Jakob <wenzel@cs.cornell.edu>
* constant.cpp, src/libhw/vpl.cpp: Support for image environment
sources and spot lights in the real-time preview.
2010-08-03 Wenzel Jakob <wenzel@cs.cornell.edu>
* mitsuba.cpp: Ability to run the 'mitsuba' execubable in arbitrary
locations on OSX while ensuring that it still finds all plugins etc.
* mtsimport: COLLADA importer support for ambient lights and 'polylist' meshes.
* scene.cpp: Create a default camera when none is specified in the XML file.
* constant.cpp, src/libhw/vpl.cpp: Support for rendering constant environment
sources in the real-time preview.
2010-07-21 Wenzel Jakob <wenzel@cs.cornell.edu>
* glwidget.cpp, mainwindow.cpp: Support for Drag & Drop
* glwidget.cpp, mainwindow.cpp: The Mitsuba user interface now also
doubles as an EXR viewer / tonemapper. Drag an EXR file onto the
UI or open it using the File menu, and the image opens in a new
tab. Afterwards, it is possible to export the image as a tonemapped
8-bit PNG image.
2010-07-19 Wenzel Jakob <wenzel@cs.cornell.edu>
* include/mitsuba/mitsuba.h: First semi-official external release 0.1.1
* rendersettingsdlg.cpp: Perform a sanity check when changing the rendering
settings: if the configuration doesn't make any sense, prevent the
user from continuing.
* mainwindow.cpp, many others: Numerous bugfixes for all platforms
2010-07-18 Wenzel Jakob <wenzel@cs.cornell.edu>
* previewsettingsdlg_cocoa_impl.mm: When running on OSX, use a
Cocoa-based settings tweaker using a 'HUD Layout' instead of
the Qt version.
* debian/*: Finished debian package support
* glwidget.cpp: Fixed some crashes
2010-07-17 Wenzel Jakob <wenzel@cs.cornell.edu>
* preview.cpp: Many bugfixes for standard ray tracing. The partial
preview shown while moving through the scene now adapts to its
complexity, making the interaction smoother.
* preview.cpp: Support for coherent ray tracing -- about 2-4x
faster than standard ray tracing.
* glwidget.cpp: When rendering very complex scenes, it was possible
that the UI required a long time to acquire a image containing
the most recent preview. This part is now allowed to time out
gracefully, leading to a more responsive user interface.
* mainwindow.cpp: "Resize to Fit" menu action.
* mainwindow.cpp: Open/Save dialogs now remember their position,
layout and directory.
* debian/*: Support for generating Debian/Ubuntu packages
2010-07-15 Wenzel Jakob <wenzel@cs.cornell.edu>
* preview.cpp: Very basic support for rendering the preview using
standard ray tracing.
2010-07-14 Wenzel Jakob <wenzel@cs.cornell.edu>
* errctrl.cpp: Added a feature that enables the error-controlling
integrator to switch between an image-wide and a per-pixel based
error criterion.
* glwidget.cpp, mainwindow.cpp, previewsettingsdlg.cpp: Added support
for the tonemapping technique by Reinhard et al. from 2002. It
dynamically adapts to the average luminance in the viewport.
2010-07-13 Wenzel Jakob <wenzel@cs.cornell.edu>
* xmltreemodel.cpp: When showing the integrator/sampler/film properties
in the render setting editor, the less important ones are now drawn
using a light grey color.
* triangle.cpp: Fixed a numerical issue when primitive clipping/
perfect splits were active while building the kd-tree -- in some
rare cases, this could result in missing geometry.
* glwidget.cpp, preview.cpp: Nicer behavior when switching tabs.
Previously, the preview would regenerate from scratch, which caused
unpleasant flicker. Now, the preview stores the complete state just
before switching away, and this is used to resume when switching
back to the tab.
* sceneloader.cpp, mainwindow.cpp: The interactive preview now tries
to detect the path length from the current scene configuration.
* rendersettingsdlg.cpp, save.cpp: It is now possible to configure the
adaptive integrator & irradiance cache from within the GUI.
2010-07-11 Wenzel Jakob <wenzel@cs.cornell.edu>
* mainwindow.cpp: Added a 'clone tab' feature, which is accessible
in the File menu and using a context menu on the tabs
* many files: Changed the system how scenes are transmitted over the
network. The camera and integrator are now serialized separately and
reattached to a shallow scene copy on the remote side. This makes it
possible to render a scene from multiple viewpoints & using different
techniques, while not having to send the (potentially large) scene
over the wire every time.
2010-07-10 Wenzel Jakob <wenzel@cs.cornell.edu>
* mainwindow.cpp: Added a feature to export images (preview+rendered)
from within the user interface.
* glwidget.cpp: Better-behaved UI when rendering tiny images (e.g. 100x100).
The app now has a specified minimum size; smaller images will be
surrounded by gray margins and frame highlights the image dimensions.
* mainwindow.cpp, glwidget.cpp: Better-behaved UI when rendering huge
images. When the image does not fit on the screen, scroll bars appear.
Scrolling is supported using either two-finger gestures (OSX), the
mouse scroll wheel or by using the scroll bars themselves.
* mainwindow.cpp, glwidget.cpp: Got rid of numerous sources of flickering
when switching between tabs. To make it all work, the OSX version now
requires Qt 4.7.x (tech preview 2) or higher.
* glwidget.cpp: The field of view can now be changed using the right
mouse button. It is also possible to move within the film plane using
the middle mouse button.
2010-07-08 Wenzel Jakob <wenzel@cs.cornell.edu>
* path.h, path.cpp, pathvertex.h, pathvertex.cpp: Reorganized path related
code, switched away from the purely inline-based header files.
* save.cpp: The save feature now stores changes to the integrator, sampler
and image reconstruction filter. The XML output has been made much
more readable.
2010-07-07 Wenzel Jakob <wenzel@cs.cornell.edu>
* mainwindow.cpp [OSX]: Detect crash reports and submit them
over the web. This is only supported on OSX for now, since the
other platforms don't collect them in a suitable way.
* renderjob.cpp: Fix for the missing plugin crashes on Steve's machine
* bidir_proc.cpp: Corrected sample positions for BDPT, which caused
grid-like artifacts when rendering with the box filter.
* path.h, mlt_*.cpp: Consolidated lots of repeated code into a new
PathVertex::connect() function.
2010-07-07 Wenzel Jakob <wenzel@cs.cornell.edu>
* ChangeLog: starting to keep a change log of notable changes (it
won't contain minor edits).

View File

@ -45,7 +45,9 @@ vars.Add('GLLIB', 'OpenGL+GLEW libraries')
vars.Add('GLINCLUDE', 'OpenGL+GLEW include path')
vars.Add('GLFLAGS', 'OpenGL+GLEW-related compiler flags')
vars.Add('GLLIBDIR', 'OpenGL+GLEW library path')
vars.Add('BOOSTINCLUDE', 'BOOST include path')
vars.Add('BOOSTINCLUDE', 'boost include path')
vars.Add('BOOSTLIB', 'boost libraries')
vars.Add('BOOSTLIBDIR', 'boost library path')
vars.Add('TARGET_ARCH', 'Target architecture')
try:
@ -64,12 +66,16 @@ env.Append(LIBPATH=[])
env.Append(LIBS=env['BASELIB'])
if env.has_key('BOOSTINCLUDE'):
env.Append(CPPPATH=env['BOOSTINCLUDE'])
if env.has_key('BOOSTLIBDIR'):
env.Append(LIBPATH=env['BOOSTLIBDIR'])
if env.has_key('BOOSTLIB'):
env.Append(LIBS=env['BOOSTLIB'])
if env.has_key('BASELIBDIR'):
env.Append(LIBPATH=env['BASELIBDIR'])
env.Decider('MD5-timestamp')
env.SetOption('num_jobs', multiprocessing.cpu_count())
#env.SetOption('num_jobs', multiprocessing.cpu_count())
AddOption("--dist", dest="dist", type="string", nargs=0, action='store', help='Make an official release')
@ -267,7 +273,8 @@ libcore_objects = [
'src/libcore/cstream.cpp', 'src/libcore/mstream.cpp',
'src/libcore/sched.cpp', 'src/libcore/sched_remote.cpp',
'src/libcore/sshstream.cpp', 'src/libcore/wavelet.cpp',
'src/libcore/zstream.cpp', 'src/libcore/shvector.cpp'
'src/libcore/zstream.cpp', 'src/libcore/shvector.cpp',
'src/libcore/fresolver.cpp'
]
if sys.platform == 'darwin':
coreEnv_osx = coreEnv.Clone();
@ -307,13 +314,13 @@ librender = renderEnv.SharedLibrary('src/librender/mitsuba-render', [
'src/librender/scene.cpp', 'src/librender/subsurface.cpp',
'src/librender/texture.cpp', 'src/librender/shape.cpp',
'src/librender/trimesh.cpp', 'src/librender/rfilter.cpp',
'src/librender/sampler.cpp', 'src/librender/records.cpp',
'src/librender/sampler.cpp', 'src/librender/util.cpp',
'src/librender/irrcache.cpp', 'src/librender/testcase.cpp',
'src/librender/preview.cpp', 'src/librender/photonmap.cpp',
'src/librender/gatherproc.cpp', 'src/librender/mipmap3d.cpp',
'src/librender/volume.cpp', 'src/librender/vpl.cpp',
'src/librender/shader.cpp', 'src/librender/shandler.cpp',
'src/librender/util.cpp'
'src/librender/intersection.cpp'
])
if sys.platform == "darwin":
@ -480,6 +487,7 @@ plugins = []
# Build the plugins -- utilities
plugins += env.SharedLibrary('plugins/addimages', ['src/utils/addimages.cpp'])
plugins += env.SharedLibrary('plugins/kdbench', ['src/utils/kdbench.cpp'])
# BSDFs
plugins += env.SharedLibrary('plugins/lambertian', ['src/bsdfs/lambertian.cpp'])
@ -703,7 +711,10 @@ elif sys.platform == 'darwin':
installTargets += env.OSXLibInst('Mitsuba.app/Contents/Frameworks', 'tools/darwin/Xerces-C.framework/Resources/lib/libxerces-c-3.0.dylib')
installTargets += env.OSXLibInst('Mitsuba.app/Contents/Frameworks', 'tools/darwin/libpng.framework/Resources/lib/libpng.dylib')
installTargets += env.OSXLibInst('Mitsuba.app/Contents/Frameworks', 'tools/darwin/libjpeg.framework/Resources/lib/libjpeg.dylib')
installTargets += env.OSXLibInst('Mitsuba.app/Contents/Frameworks', 'tools/darwin/Collada14Dom.framework/Resources/lib/libCollada14Dom.dylib')
installTargets += env.OSXLibInst('Mitsuba.app/Contents/Frameworks', 'tools/darwin/libboost.framework/Resources/lib/libboost_system-xgcc42-mt-1_39.dylib')
installTargets += env.OSXLibInst('Mitsuba.app/Contents/Frameworks', 'tools/darwin/libboost.framework/Resources/lib/libboost_filesystem-xgcc42-mt-1_39.dylib')
if hasCollada:
installTargets += env.OSXLibInst('Mitsuba.app/Contents/Frameworks', 'tools/darwin/Collada14Dom.framework/Resources/lib/libCollada14Dom.dylib')
if hasQt:
installTargets += env.Install('Mitsuba.app/Contents/MacOS', 'mtsgui')
installTargets += env.OSXLibInst('Mitsuba.app/Contents/Frameworks', '/Library/Frameworks/QtCore.framework/Versions/4/QtCore')

View File

@ -20,6 +20,8 @@ GLLIBDIR = ['#tools/darwin/GLEW.framework/Resources/libs']
GLLIB = ['GLEW', 'objc']
GLFLAGS = ['-DGLEW_MX']
BOOSTINCLUDE = ['#tools/boost']
BOOSTLIB = ['boost_filesystem-xgcc42-mt-1_39', 'boost_system-xgcc42-mt-1_39']
BOOSTLIBDIR = ['tools/darwin/libboost.framework/Resources/lib']
COLLADAINCLUDE = ['#tools/windows/include/colladadom', '#tools/windows/include/colladadom/1.4']
COLLADALIB = ['libCollada14Dom']
COLLADALIBDIR = ['#tools/darwin/Collada14Dom.framework/Resources/lib']

View File

@ -20,6 +20,8 @@ GLLIBDIR = ['#tools/darwin/GLEW.framework/Resources/libs']
GLLIB = ['GLEW', 'objc']
GLFLAGS = ['-DGLEW_MX']
BOOSTINCLUDE = ['#tools/boost']
BOOSTLIB = ['boost_filesystem-xgcc42-mt-1_39', 'boost_system-xgcc42-mt-1_39']
BOOSTLIBDIR = ['tools/darwin/libboost.framework/Resources/lib']
COLLADAINCLUDE = ['#tools/windows/include/colladadom', '#tools/windows/include/colladadom/1.4']
COLLADALIB = ['libCollada14Dom']
COLLADALIBDIR = ['#tools/darwin/Collada14Dom.framework/Resources/lib']

View File

@ -20,6 +20,8 @@ GLLIBDIR = ['#tools/darwin/GLEW.framework/Resources/libs']
GLLIB = ['GLEW', 'objc']
GLFLAGS = ['-DGLEW_MX']
BOOSTINCLUDE = ['#tools/boost']
BOOSTLIB = ['boost_filesystem-xgcc42-mt-1_39', 'boost_system-xgcc42-mt-1_39']
BOOSTLIBDIR = ['tools/darwin/libboost.framework/Resources/lib']
COLLADAINCLUDE = ['#tools/windows/include/colladadom', '#tools/windows/include/colladadom/1.4']
COLLADALIB = ['libCollada14Dom']
COLLADALIBDIR = ['#tools/darwin/Collada14Dom.framework/Resources/lib']

View File

@ -13,5 +13,6 @@ XERCESLIB = ['xerces-c']
GLLIB = ['GL', 'GLEWmx', 'Xxf86vm']
GLFLAGS = ['-DGLEW_MX']
BOOSTINCLUDE = ['#tools/boost']
BOOSTLIB = ['libboost_system', 'libboost_filesystem']
COLLADAINCLUDE = ['/usr/include/collada-dom', '/usr/include/collada-dom/1.4']
COLLADALIB = ['libcollada14dom', 'libboost_system', 'libboost_filesystem']
COLLADALIB = ['libcollada14dom']

View File

@ -13,8 +13,9 @@ OEXRINCLUDE = ['#tools/windows/include/OpenEXR']
OEXRFLAGS = ['/D', 'OPENEXR_DLL']
OEXRLIB = ['IlmImf', 'IlmThread', 'Iex', 'zlib1', 'Half']
BOOSTINCLUDE = ['#tools/boost']
BOOSTLIB = ['libboost_system', 'libboost_filesystem']
COLLADAINCLUDE = ['#tools/windows/include/colladadom', '#tools/windows/include/colladadom/1.4']
COLLADALIB = ['libcollada14dom21', 'libboost_system', 'libboost_filesystem']
COLLADALIB = ['libcollada14dom21']
XERCESLIB = ['xerces-c_3']
PNGLIB = ['libpng13']
JPEGLIB = ['jpeg62']

View File

@ -13,8 +13,9 @@ OEXRINCLUDE = ['#tools/windows/include/OpenEXR']
OEXRFLAGS = ['/D', 'OPENEXR_DLL']
OEXRLIB = ['IlmImf', 'IlmThread', 'Iex', 'zlib1', 'Half']
BOOSTINCLUDE = ['#tools/boost']
BOOSTLIB = ['libboost_system', 'libboost_filesystem']
COLLADAINCLUDE = ['#tools/windows/include/colladadom', '#tools/windows/include/colladadom/1.4']
COLLADALIB = ['libcollada14dom21', 'libboost_system', 'libboost_filesystem']
COLLADALIB = ['libcollada14dom21']
XERCESLIB = ['xerces-c_3']
PNGLIB = ['libpng13']
JPEGLIB = ['jpeg62']

View File

@ -31,7 +31,7 @@ PROJECT_NAME = Mitsuba
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = 0.1.1
PROJECT_NUMBER = 0.1.3
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
@ -133,7 +133,7 @@ STRIP_FROM_PATH =
# definition is used. Otherwise one should specify the include paths that
# are normally passed to the compiler using the -I flag.
STRIP_FROM_INC_PATH =
STRIP_FROM_INC_PATH = include
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
# (but less readable) file names. This can be useful is your file systems
@ -263,7 +263,7 @@ IDL_PROPERTY_SUPPORT = YES
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
DISTRIBUTE_GROUP_DOC = NO
DISTRIBUTE_GROUP_DOC = YES
# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
# the same type (for instance a group of public functions) to be put as a
@ -590,7 +590,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = include
INPUT = include/mitsuba/core doc/doxyfiles
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@ -608,36 +608,10 @@ INPUT_ENCODING = UTF-8
# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.d \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.idl \
*.odl \
*.cs \
*.php \
*.php3 \
*.inc \
*.m \
*.mm \
*.dox \
*.py \
*.f90 \
*.f \
*.vhd \
*.vhdl
*.dox
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
@ -1224,7 +1198,7 @@ MAN_LINKS = NO
# generate an XML file that captures the structure of
# the code including all documentation.
GENERATE_XML = NO
GENERATE_XML = YES
# The XML_OUTPUT tag is used to specify where the XML pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
@ -1311,7 +1285,7 @@ ENABLE_PREPROCESSING = YES
# compilation will be performed. Macro expansion can be done in a controlled
# way by setting EXPAND_ONLY_PREDEF to YES.
MACRO_EXPANSION = NO
MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
# then the macro expansion is limited to the macros specified with the
@ -1328,7 +1302,7 @@ SEARCH_INCLUDES = YES
# contain include files that are not input files but should be processed by
# the preprocessor.
INCLUDE_PATH =
INCLUDE_PATH = include
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the

View File

@ -12,7 +12,6 @@ Mitsuba makes heavy use of the following amazing libraries and tools:
\item The Boost C+\!+ class library
\item GLEW by Milan Ikits, Marcelo E. Magallon and Lev Povalahev
\item Mersenne Twister by Makoto Matsumoto and Takuji Nishimura
\item ccvt (Capacity-Constrained Voronoi Tessellations) by Michael Balzer, Thomas Schlömer and Oliver Deussen
\item COLLADA DOM by Sony Computer Entertainment
\item libjpeg by the Independent JPEG Group
\item libpng by Guy Eric Schalnat, Andreas Dilger, Glenn Randers-Pehrson and \mbox{others}

View File

@ -0,0 +1,29 @@
/**
\mainpage Mitsuba Renderer API Documentation
<center>
<a href="http://www.mitsuba-renderer.org">www.mitsuba-renderer.org</a>
<table width=1000 border=0 style="border: 0px solid #EEEEEE"><tr><td>
<div class="featuretitle">Basic Information</div>
- <a href="http://www.mitsuba-renderer.org/documentation.pdf">Reference Manual (PDF)</a>
</div>
<div class="featuretitle">API Documentation</div>
- <a href="annotated.html">Annotated Class List</a>
- <a href="classes.html">Alphabetical Class List</a>
- <a href="hierarchy.html">Class Hierarchy</a>
</div>
<div class="featuretitle">Community</div>
- <a href="http://www.mitsuba-renderer.org/devblog">Development Blog</a>
- <a href="https://www.mitsuba-renderer.org/bugtracker/projects/mitsuba">Bug Tracker</a>
- <a href="https://www.mitsuba-renderer.org/hg">List of repositories</a>
</div>
</td></tr></table>
</center>
*/

View File

@ -23,25 +23,35 @@
MTS_NAMESPACE_BEGIN
/** \brief Axis-aligned bounding box data structure
/**
* \brief Axis-aligned bounding box data structure in three dimensions
*
* Maintains a component-wise minimum and maximum position and provides
* various convenience functions to query or change them.
*/
struct MTS_EXPORT_CORE AABB {
public:
Point min;
Point max;
Point min; ///< Component-wise minimum
Point max; ///< Component-wise maximum
/// Construct an invalid bounding box
/**
* \brief Construct an invalid bounding box
*
* The minimum and maximum positions will be
* initialized to \f$(\infty,\infty,\infty)\f$
* and \f$(-\infty, -\infty, -\infty)\f$, respectively.
*/
inline AABB() {
reset();
}
/// Unserialize an AABB from a stream
/// Unserialize a bounding box from a binary data stream
inline AABB(Stream *stream) {
min = Point(stream);
max = Point(stream);
}
/// Create a bounding box from two 3-dimension vectors
/// Create a bounding box from two 3D positions
inline AABB(const Point &min, const Point &max)
: min(min), max(max) {
SAssert(min.x <= max.x
@ -61,33 +71,30 @@ public:
return *this;
}
/// Equal operator
/// Equality test
inline bool operator==(const AABB &aabb) const {
return min == aabb.min && max == aabb.max;
}
/// Not equal operator
/// Inequality test
inline bool operator!=(const AABB &aabb) const {
return min != aabb.min || max != aabb.max;
}
/// Mark the bounding box as invalid
/**
* \brief Mark the bounding box as invalid.
*
* This operation sets the
* minimum position to \f$(\infty,\infty,\infty)\f$ and the
* maximum position to \f$(-\infty, -\infty, -\infty)\f$.
*/
inline void reset() {
const Float inf = std::numeric_limits<Float>::infinity();
min = Point(inf, inf, inf);
max = Point(-inf, -inf, -inf);
}
/// Calculate the volume of the bounding box
inline Float getVolume() const {
Float x = max.x - min.x;
Float y = max.y - min.y;
Float z = max.z - min.z;
return x*x + y*y + z*z;
}
/// Clip to another AABB
/// Clip to another bounding box
inline void clip(const AABB &aabb) {
min.x = std::max(min.x, aabb.min.x);
min.y = std::max(min.y, aabb.min.y);
@ -99,21 +106,33 @@ public:
/// Return the center point
inline Point getCenter() const {
return max*.5f + min*.5f;
return (max + min) * (Float) 0.5;
}
/// Calculate the volume of the bounding box
inline Float getVolume() const {
Float x = max.x - min.x;
Float y = max.y - min.y;
Float z = max.z - min.z;
return x*x + y*y + z*z;
}
/// Calculate the surface area of the bounding box
inline Float getSurfaceArea() const {
Vector d = max - min;
return 2.0f * (d.x*d.y + d.x*d.z + d.y*d.z);
return (Float) 2.0 * (d.x*d.y + d.x*d.z + d.y*d.z);
}
/// Calculate the AABB extents
/**
* \brief Calculate the bounding box extents
* \return max-min
*/
inline Vector getExtents() const {
return max - min;
}
/// Return the axis with the largest corresponding AABB side
/// Return the axis index with the largest associated side length
inline int getLargestAxis() const {
Vector d = max - min;
if (d.x >= d.y && d.x >= d.z)
@ -124,7 +143,7 @@ public:
return 2;
}
/// Return the axis with the smallest corresponding AABB side
/// Return the axis index with the smallest associated side length
inline int getSmallestAxis() const {
Vector d = max - min;
if (d.x <= d.y && d.x <= d.z)
@ -141,8 +160,8 @@ public:
}
/**
* Return whether this bounding box covers a non-zero
* amount of space
* \brief Return whether or not this bounding box covers a
* nonzero amount of space
*/
inline bool isEmpty() const {
return max.x <= min.x
@ -151,47 +170,41 @@ public:
}
/// Return the minimum vector of the bounding box
/// Return the component-wise minimum point of the bounding box
inline const Point &getMinimum() const {
return min;
}
/// Return the maximum vector of the bounding box
/// Return the component-wise maximum point of the bounding box
inline const Point &getMaximum() const {
return max;
}
/// Return the middle point
Point getMidPoint() const;
/** \brief Return the vector coordinates of a bounding
* box corner
* @param corner Corner index (0..7)
/**
* \brief Return the position of a bounding box corner
* \param corner Requested corner index (0..7)
*/
Point getCorner(uint8_t corner) const;
/// Checks whether a vector is inside the bounding box
/// Check whether a point lies on or inside the bounding box
bool contains(const Point &vec) const;
/// Bounding sphere-AABB overlap test
inline bool overlaps(const BSphere &sphere) const {
Float distance = 0;
for (int i=0; i<3; ++i) {
if (sphere.center[i] < min[i]) {
Float d = sphere.center[i]-min[i];
distance += d*d;
} else if (sphere.center[i] > max[i]) {
Float d = sphere.center[i]-max[i];
distance += d*d;
}
}
return distance < sphere.radius*sphere.radius;
}
/**
* \brief Bounding sphere-box overlap test
*
* Implements the technique proposed by Jim Arvo in
* "A simple method for box-sphere intersection testing"
* (Graphics Gems, 1990)
*/
bool overlaps(const BSphere &sphere) const;
/// Expands the bounding box to contain another vector
/// Axis-aligned bounding box overlap test
bool overlaps(const AABB &saabb) const;
/// Expand the bounding box to contain another point
void expandBy(const Point &vec);
/// Expands the bounding box to contain another bounding box
/// Expand the bounding box to contain another bounding box
void expandBy(const AABB &aabb);
/// Calculate the point-AABB distance
@ -237,19 +250,22 @@ public:
#ifdef MTS_SSE
/**
* Intersect against a packet of four rays. Returns false if none of
* the rays intersect.
* \brief Intersect against a packet of four rays.
* \return \a false if none of the rays intersect.
*/
FINLINE bool rayIntersectPacket(const RayPacket4 &ray, RayInterval4 &interval) const;
#endif
/// Serialize this AABB to a stream
/// Create a bounding sphere, which contains the axis-aligned box
BSphere getBSphere() const;
/// Serialize this bounding box to a binary data stream
inline void serialize(Stream *stream) const {
min.serialize(stream);
max.serialize(stream);
}
/// Returns a string representation of the bounding box
/// Return a string representation of the bounding box
std::string toString() const;
};

View File

@ -19,6 +19,8 @@
#if !defined(__APPENDER_H)
#define __APPENDER_H
#include <mitsuba/mitsuba.h>
MTS_NAMESPACE_BEGIN
/** \brief This class defines an abstract destination
@ -26,16 +28,16 @@ MTS_NAMESPACE_BEGIN
*/
class MTS_EXPORT_CORE Appender : public Object {
public:
/// Append a line of text
virtual void append(ELogLevel level, const std::string &pText) = 0;
/// Append a line of text with the given log level
virtual void append(ELogLevel level, const std::string &text) = 0;
/**
* Process a progress message
* @param progress Percentage value in [0,100]
* @param name Title of the progress message
* @param formatted Formatted string representation of the message
* @param eta Estimated time until 100% is reached.
* @param ptr Custom pointer payload
* \brief Process a progress message
* \param progress Percentage value in [0,100]
* \param name Title of the progress message
* \param formatted Formatted string representation of the message
* \param eta Estimated time until 100% is reached.
* \param ptr Custom pointer payload
*/
virtual void logProgress(Float progress, const std::string &name,
const std::string &formatted, const std::string &eta, const void *ptr) = 0;
@ -46,7 +48,7 @@ protected:
virtual ~Appender() { }
};
/** \brief Appender implementation which writes to an
/** \brief Appender implementation, which writes to an
* arbitrary C++ stream
*/
class MTS_EXPORT_CORE StreamAppender : public Appender {
@ -82,7 +84,7 @@ private:
bool m_lastMessageWasProgress;
};
/** \brief Appender implementation which writes to an
/** \brief Appender implementation, which writes to an
* unbuffered file descriptor.
*/
class MTS_EXPORT_CORE UnbufferedAppender : public Appender {

View File

@ -19,61 +19,62 @@
#if !defined(__BSPHERE_H)
#define __BSPHERE_H
#include <mitsuba/mitsuba.h>
#include <mitsuba/core/ray.h>
MTS_NAMESPACE_BEGIN
/** \brief Bounding sphere class
/** \brief Bounding sphere data structure in three dimensions
*/
struct BSphere {
Point center;
Float radius;
/// Construct an empty bounding sphere
/// Construct a bounding sphere at the origin having radius zero
inline BSphere() {
radius = 0.0f;
}
/// Unserialize an AABB from a stream
/// Unserialize a bounding sphere from a binary data stream
inline BSphere(Stream *stream) {
center = Point(stream);
radius = stream->readFloat();
}
/// Create a bounding sphere from a given center point and a radius
inline BSphere(const Point &pCenter, Float pRadius)
: center(pCenter), radius(pRadius) {
/// Create a bounding sphere from a given center point and radius
inline BSphere(const Point &center, Float radius)
: center(center), radius(radius) {
}
/// Copy-constructor
/// Copy constructor
inline BSphere(const BSphere &boundingSphere)
: center(boundingSphere.center), radius(boundingSphere.radius) {
}
/// Return whether this bounding sphere is empty
/// Return whether this bounding sphere has a radius of zero or less.
inline bool isEmpty() const {
return radius <= 0.0f;
}
/** \brief Expands the bounding sphere to contain another point.
* Does not move the center point
*/
/// Expand the bounding sphere radius to contain another point.
inline void expandBy(const Point p) {
Vector dir = p - center;
radius = std::max(radius, (p-center).length());
}
/// Comparison operator
/// Equality test
inline bool operator==(const BSphere &boundingSphere) const {
return center == boundingSphere.center && radius == boundingSphere.radius;
}
/// Comparison operator
/// Inequality test
inline bool operator!=(const BSphere &boundingSphere) const {
return !operator==(boundingSphere);
return center != boundingSphere.center || radius != boundingSphere.radius;
}
/// Calculate the intersection points with the given ray
/**
* \brief Calculate the intersection points with the given ray
* \return \a true if the ray intersects the bounding sphere
*/
inline bool rayIntersect(const Ray &ray, Float &nearHit, Float &farHit) const {
Vector originToCenter = center - ray.o;
Float distToRayClosest = dot(originToCenter, ray.d);
@ -109,13 +110,13 @@ struct BSphere {
return true;
}
/// Serialize this AABB to a stream
/// Serialize this bounding sphere to a binary data stream
inline void serialize(Stream *stream) const {
center.serialize(stream);
stream->writeFloat(radius);
}
/// Returns a string representation of the bounding sphere
/// Return a string representation of the bounding sphere
inline std::string toString() const {
std::ostringstream oss;
oss << "BSphere[center = " << center.toString()

View File

@ -21,43 +21,63 @@
MTS_NAMESPACE_BEGIN
/* Forward declarations */
class Stream;
class Object;
class InstanceManager;
/** \brief Universal class descriptor.
* @see ref, Object
/**
* \headerfile mitsuba/core/class.h mitsuba/mitsuba.h
* \brief Stores meta-information about \ref Object instances.
*
* This class provides a thin layer of RTTI (run-time type information),
* which is useful for doing things like:
*
* <ul>
* <li> Checking if an object derives from a certain class </li>
* <li> Determining the parent of a class at runtime </li>
* <li> Instantiating a class by name </li>
* <li> Unserializing a class from a binary data stream </li>
* </ul>
*
* \sa ref, Object
*/
class MTS_EXPORT_CORE Class {
public:
/// Construct a new class descriptor
/**
* \brief Construct a new class descriptor
*
* This method should never be called manually. Instead, use
* one of the \ref MTS_IMPLEMENT_CLASS, \ref MTS_IMPLEMENT_CLASS_S,
* \ref MTS_IMPLEMENT_CLASS_I or \ref MTS_IMPLEMENT_CLASS_IS macros
* to automatically do this for you.
*
* \param name Name of the class
* \param abstract \a true if the class contains pure virtual methods
* \param superClassName Name of the parent class
* \param instPtr Pointer to an instantiation function
* \param unSerPtr Pointer to an unserialization function
*/
Class(const std::string &name, bool abstract, const std::string &superClassName,
void *instPtr = NULL, void *unSerPtr = NULL);
/// Return the class' name
/// Return the name of the represented class
inline const std::string &getName() const { return m_name; }
/** \brief Return whether the class represented
* by this Class object is abstract
/**
* \brief Return whether or not the class represented
* by this Class object contains pure virtual methods
*/
inline bool isAbstract() const { return m_abstract; }
/** \brief Does the class support instantiation over RTTI?
*/
/// Does the class support instantiation over RTTI?
inline bool isInstantiable() const { return m_instPtr != NULL; }
/** \brief Does the class support serialization?
*/
/// Does the class support serialization?
inline bool isSerializable() const { return m_unSerPtr != NULL; }
/** \brief Return this class' super class or NULL
* if it has no super class
/** \brief Return the Class object associated with the parent
* class of NULL if it does not have one.
*/
inline const Class *getSuperClass() const { return m_superClass; }
/// Check whether this class derives from pClass
bool derivesFrom(const Class *pClass) const;
/// Check whether this class derives from \a theClass
bool derivesFrom(const Class *theClass) const;
/// Look up a class by its name
static const Class *forName(const std::string &name);
@ -68,11 +88,11 @@ public:
static const Class *forName(const char *name);
/** \brief Unserialize an instance of the class (if this is
* supported by the class).
* supported).
*/
Object *unserialize(Stream *stream = NULL, InstanceManager *manager = NULL) const;
/// Generate an instance of this class (if supported)
/// Generate an instance of this class (if this is supported)
Object *instantiate() const;
/** \brief Initializes the built-in RTTI and creates
@ -95,20 +115,34 @@ private:
void *m_instPtr, *m_unSerPtr;
};
/* Class instantiation macros */
/**
* \brief This macro must be used in the declaration of
* all classes derived from \ref Object.
*/
#define MTS_DECLARE_CLASS() \
virtual const Class *getClass() const; \
public: \
static Class *m_theClass;
// basic RTTI support for a class
/**
* \brief Creates basic RTTI support for a class
* \param name Name of the class
* \param abstract \a true if the class contains pure virtual methods
* \param super Name of the parent class
*/
#define MTS_IMPLEMENT_CLASS(name, abstract, super) \
Class *name::m_theClass = new Class(#name, abstract, #super); \
const Class *name::getClass() const { \
return m_theClass;\
}
// Extended version, records that the class supports instantiation by name
/**
* \brief Creates basic RTTI support for a class. Assumes that
* the class can be instantiated by name.
* \param name Name of the class
* \param abstract \a true if the class contains pure virtual methods
* \param super Name of the parent class
*/
#define MTS_IMPLEMENT_CLASS_I(name, abstract, super) \
Object *__##name ##_inst() { \
return new name(); \
@ -118,7 +152,13 @@ public: \
return m_theClass;\
}
// Extended version, records that the class can be unserialized from a binary data stream
/**
* \brief Creates basic RTTI support for a class. Assumes that
* the class can be unserialized from a binary data stream.
* \param name Name of the class
* \param abstract \a true if the class contains pure virtual methods
* \param super Name of the parent class
*/
#define MTS_IMPLEMENT_CLASS_S(name, abstract, super) \
Object *__##name ##_unSer(Stream *stream, InstanceManager *manager) { \
return new name(stream, manager); \
@ -128,7 +168,14 @@ public: \
return m_theClass;\
}
// Extended version, records that the class can be unserialized from a binary data stream as well as instantiated by name
/**
* \brief Creates basic RTTI support for a class. Assumes that
* the class can be unserialized from a binary data stream as well
* as instantiated by name.
* \param name Name of the class
* \param abstract \a true if the class contains pure virtual methods
* \param super Name of the parent class
*/
#define MTS_IMPLEMENT_CLASS_IS(name, abstract, super) \
Object *__##name ##_unSer(Stream *stream, InstanceManager *manager) { \
return new name(stream, manager); \

View File

@ -24,45 +24,54 @@
MTS_NAMESPACE_BEGIN
/** \brief Interface of a generic serializable object that can be
* configured by an instance of the Properties class.
/** \brief Generic serializable object, which supports construction
* from a Properties instance.
*
* All plugins in Mitsuba derive from ConfigurableObject. This mechanism
* lets them accept parameters specified in an external XML file. Additionally,
* they can have child objects, which correspond to nested instantiation
* requests in the XML file.
*/
class MTS_EXPORT_CORE ConfigurableObject : public SerializableObject {
public:
/// Constructor
inline ConfigurableObject(const Properties &props) : SerializableObject(), m_configured(false), m_parent(NULL) { }
/// Unserialize a configurable object
ConfigurableObject(Stream *stream, InstanceManager *manager);
/// Set the parent object
virtual void setParent(ConfigurableObject *parent);
/// Get the parent object
/// Return the parent object
inline ConfigurableObject *getParent() { return m_parent; }
/// Get the parent object
/// Return the parent object (const version)
inline const ConfigurableObject *getParent() const { return m_parent; }
/// Add a child (default implementation throws an error)
virtual void addChild(const std::string &name, ConfigurableObject *child);
/** \brief Configure the object (called _once_ after construction
and addition of all child ConfigurableObjects. */
/** \brief Configure the object (called <em>once</em> after construction
and addition of all child ConfigurableObjects) */
virtual void configure();
/// Serialize this object to a stream
/// Serialize this object to a binary data stream
virtual void serialize(Stream *stream, InstanceManager *manager) const;
MTS_DECLARE_CLASS()
protected:
/// Virtual destructor
virtual ~ConfigurableObject() { }
/// Construct a configurable object
inline ConfigurableObject(const Properties &props)
: SerializableObject(), m_parent(NULL), m_configured(false) { }
/// Unserialize a configurable object
ConfigurableObject(Stream *stream, InstanceManager *manager);
protected:
bool m_configured;
ConfigurableObject *m_parent;
bool m_configured;
};
/** \brief This macro creates the binary interface, which Mitsuba
* requires to load a plugin.
*/
#define MTS_EXPORT_PLUGIN(name, descr) \
extern "C" { \
void MTS_EXPORT *CreateInstance(const Properties &props) { \

View File

@ -23,7 +23,7 @@
MTS_NAMESPACE_BEGIN
/** \brief Console stream
/** \brief Interface to the default stdin/stdout console streams
*/
class MTS_EXPORT_CORE ConsoleStream : public Stream {
public:
@ -46,11 +46,7 @@ public:
MTS_DECLARE_CLASS()
protected:
/** \brief Virtual destructor
*
* The destructor frees all resources and closes
* the socket if it is still open
*/
/// Virtual destructor
virtual ~ConsoleStream();
};

View File

@ -1,108 +0,0 @@
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2010 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba 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/>.
*/
#if !defined(__FIFO_H)
#define __FIFO_H
#include <mitsuba/mitsuba.h>
#include <pthread.h>
#include <deque>
#if defined(__OSX__)
#include <mach/semaphore.h>
#include <mach/mach.h>
#include <mach/task.h>
#else
#include <semaphore.h>
#endif
MTS_NAMESPACE_BEGIN
/**
* Simple synchronized FIFO class with an underlying
* deque container
*/
template <class T> class FIFO {
public:
FIFO() {
#if defined(__OSX__)
if (semaphore_create(::mach_task_self(), &m_available,
SYNC_POLICY_FIFO, 0) != KERN_SUCCESS)
SLog(EError, "Could not create a semaphore!");
#else
if (sem_init(&m_available, PTHREAD_PROCESS_PRIVATE, 0))
SLog(EError, "Could not create a semaphore!");
#endif
pthread_mutex_init(&m_mutex, NULL);
}
void put(T value) {
pthread_mutex_lock(&m_mutex);
m_data.push_back(value);
pthread_mutex_unlock(&m_mutex);
#if defined(__OSX__)
semaphore_signal(m_available);
#else
sem_post(&m_available);
#endif
}
T get() {
T result;
#if defined(__OSX__)
semaphore_wait(m_available);
#else
while (sem_wait(&m_available) != 0)
;
#endif
pthread_mutex_lock(&m_mutex);
result = m_data.front();
m_data.pop_front();
pthread_mutex_unlock(&m_mutex);
return result;
}
int getSize() const {
int result;
pthread_mutex_lock(&m_mutex);
result = m_data.size();
pthread_mutex_unlock(&m_mutex);
return result;
}
~FIFO() {
#if defined(__OSX__)
semaphore_destroy(::mach_task_self(), m_available);
#else
sem_destroy(&m_available);
#endif
pthread_mutex_destroy(&m_mutex);
}
private:
std::deque<T> m_data;
mutable pthread_mutex_t m_mutex;
#if defined(__OSX__)
semaphore_t m_available;
#else
sem_t m_available;
#endif
};
MTS_NAMESPACE_END
#endif /* __FIFO_H */

View File

@ -19,33 +19,37 @@
#if !defined(__FORMATTER_H)
#define __FORMATTER_H
#include <mitsuba/mitsuba.h>
MTS_NAMESPACE_BEGIN
/// Available Log message types
enum ELogLevel {
/// Trace message, for extremely verbose debugging
ETrace = 0,
/// Debug message, usually turned off
EDebug = 100,
/// More relevant debug / information message
EInfo = 200,
/// Warning message
EWarn = 300,
/// Error message, causes an exception to be thrown
EError = 400
ETrace = 0, ///< Trace message, for extremely verbose debugging
EDebug = 100, ///< Debug message, usually turned off
EInfo = 200, ///< More relevant debug / information message
EWarn = 300, ///< Warning message
EError = 400 ///< Error message, causes an exception to be thrown
};
class Thread;
/** \brief The Formatter class defines an interface for converting
* log information into a human-readable format
/** \brief Abstract interface for converting log information into
* a human-readable format
*/
class MTS_EXPORT_CORE Formatter : public Object {
public:
/// Format a line of text
virtual std::string format(ELogLevel pLogLevel, const Class *pClass,
const Thread *pThread, const std::string &pText,
const char *pFile, int pLine) = 0;
/**
* \brief Turn a log message into a human-readable format
* \param logLevel The importance of the debug message
* \param theClass Originating class or NULL
* \param thread Thread, which is reponsible for creating the message
* \param text Text content associated with the log message
* \param file File, which is responsible for creating the message
* \param line Associated line within the source file
*/
virtual std::string format(ELogLevel logLevel, const Class *theClass,
const Thread *thread, const std::string &text,
const char *file, int line) = 0;
MTS_DECLARE_CLASS()
protected:
@ -53,19 +57,19 @@ protected:
virtual ~Formatter() { }
};
/** \brief The default formatter implementation
/** \brief The default formatter used to turn log messages into
* a human-readable form
*/
class MTS_EXPORT_CORE DefaultFormatter : public Formatter {
public:
/// Create a new default formatter
DefaultFormatter();
/// Format a line of text
std::string format(ELogLevel pLogLevel, const Class *pClass,
const Thread *pThread, const std::string &pText,
const char *pFile, int pLine);
std::string format(ELogLevel logLevel, const Class *theClass,
const Thread *thread, const std::string &text,
const char *file, int line);
/// Should the date be included?
/// Should date information be included? The default is yes.
inline void setHaveDate(bool value) { m_haveDate = value; }
MTS_DECLARE_CLASS()

View File

@ -24,38 +24,34 @@
MTS_NAMESPACE_BEGIN
/**
* This data structure stores an arbitrary three-dimensional cartesian
* coordinate system and provides routines to convert coordinates and
* efficiently compute several other quantities.
* \brief Stores a three-dimensional orthonormal coordinate frame
*
* This class is mostly used to quickly convert between different
* cartesian coordinate systems and to efficiently compute certain
* quantities (e.g. \ref cosTheta(), \ref tanTheta, ..).
*/
struct Frame {
Vector s, t;
Normal n;
/// Default constructor
inline Frame() {
}
/// Default constructor -- performs no initialization!
inline Frame() { }
/// Given a normal and tangent vectors, construct a new coordinate frame
inline Frame(const Vector &s, const Vector &t, const Normal &n)
: s(s), t(t), n(n) {
}
/// Construct a frame from the given cartesian coordinate system
/// Construct a frame from the given orthonormal vectors
inline Frame(const Vector &x, const Vector &y, const Vector &z)
: s(x), t(y), n(Normal(z)) {
: s(x), t(y), n(z) {
}
/// Construct a new coordinate frame from a single vector
inline Frame(const Vector &n) : n(Normal(n)) {
inline Frame(const Vector &n) : n(n) {
coordinateSystem(n, s, t);
}
/// Construct a new coordinate frame from a single normal vector
inline Frame(const Normal &n) : n(n) {
coordinateSystem(Vector(n), s, t);
}
/// Unserialize from a binary data stream
inline Frame(Stream *stream) {
s = Vector(stream);

View File

@ -19,236 +19,72 @@
#if !defined(__FRESOLVER_H)
#define __FRESOLVER_H
#include <mitsuba/core/fstream.h>
#include <mitsuba/core/tls.h>
#if defined(WIN32)
#include <direct.h>
#define PATH_MAX 1024
#else
#include <unistd.h>
#endif
#include <mitsuba/mitsuba.h>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#define PATHSEP '/'
namespace fs = boost::filesystem;
MTS_NAMESPACE_BEGIN
/**
* Utility class that searchs for files within a set of user-defined
* directories. Each thread has its own, unique file resolver, which
* makes it possible to have per-thread current working directories.
* \brief File resolution helper
*
* FileResolver is a convenience class that allows searching for files
* within a set of specifiable search paths in a cross-platform
* compatible manner (similar to the $PATH variable on various
* operating systems).
*/
class MTS_EXPORT_CORE FileResolver : public Object {
public:
/// Return the current thread's resolver instance
inline static FileResolver *getInstance() {
FileResolver *resolver = m_tls.get();
if (!resolver) {
resolver = new FileResolver();
m_tls.set(resolver);
}
return resolver;
}
/// Set the current thread's resolver instance
inline static void setInstance(FileResolver *resolver) {
m_tls.set(resolver);
}
/// Clone a file resolver
inline FileResolver *clone() {
FileResolver *cloned = new FileResolver();
cloned->m_paths = m_paths;
cloned->m_currentDirectory = m_currentDirectory;
return cloned;
}
/// Reset the search path
inline void clear() {
m_paths.clear();
}
/// Add a search path
inline void addPath(const std::string &path) {
m_paths.push_back(path);
}
/// Check if the list of search paths contains a certain entry
inline bool contains(const std::string &path) const {
return std::find(m_paths.begin(), m_paths.end(), path) != m_paths.end();
}
/// Set the resolver's current working directory
inline void setCurrentDirectory(const std::string &cwd) {
m_currentDirectory = cwd;
}
/// Return the resolver's current working directory
inline const std::string &getCurrentDirectory() const {
return m_currentDirectory;
}
/// Set the current directory by stripping away the last component
inline void setCurrentDirectoryFromFile(const std::string &cwd) {
m_currentDirectory = getParentDirectory(cwd);
}
/// Adds a path while stripping away the last component
inline void addPathFromFile(const std::string &path) {
addPath(getParentDirectory(path));
}
/// Strip the last component from a path
inline std::string getParentDirectory(const std::string &path) const {
std::vector<std::string> components = tokenize(path, "/\\");
if (components.size() == 1)
return ".";
std::string newPath = components[0];
for (unsigned int i=1; i<components.size() - 1; i++)
newPath += PATHSEP + components[i];
if (path[0] == PATHSEP)
newPath = PATHSEP + newPath;
else if (path[0] == '\\')
newPath = "\\" + newPath;
return newPath;
}
/// Return the last component of a path
inline std::string getChild(const std::string &path) const {
std::vector<std::string> components = tokenize(path, "/\\");
return components[components.size()-1];
}
/// Try to resolve a path to an existing file
inline std::string resolve(const std::string &path) const {
if (!FileStream::exists(path)) {
for (unsigned int i=0; i<m_paths.size(); i++) {
std::string testPath = m_paths[i] + "/" + path;
if (FileStream::exists(testPath))
return testPath;
}
}
return path;
}
/// Try to resolve all paths to an existing file
inline std::vector<std::string> resolveAll(const std::string &path) const {
std::vector<std::string> result;
if (FileStream::exists(path))
result.push_back(path);
for (unsigned int i=0; i<m_paths.size(); i++) {
std::string testPath = m_paths[i] + "/" + path;
if (FileStream::exists(testPath))
result.push_back(testPath);
}
return result;
}
/**
* \brief Create a new file resolver with the default settings
*
* Create a new file resolver containing the current working
* directory as the initial search path.
*/
FileResolver();
/**
* Try to resolve a path to an existing file (returns an
* absolute path
* \brief Resolve a file using the stored list of search paths
*
* Go through the list of search paths and try to resolve the
* supplied path with respect to each one. If everything fails,
* the path is returned as-is.
*/
inline std::string resolveAbsolute(const std::string &path) const {
return makeAbsolute(resolve(path));
}
fs::path resolve(const fs::path &path) const;
/**
* \brief Resolve a file using the stored list of search paths
*
* In comparison to \ref resolve(), this funtion returns all
* matches instead of only the first one.
*/
std::vector<fs::path> resolveAll(const fs::path &path) const;
/**
* \brief Does the same as \ref resolve(), but returns an
* absolute path.
*/
fs::path resolveAbsolute(const fs::path &path) const;
/// Create a clone of the file resolver
FileResolver *clone() const;
/// Add a search path to the resolver
void addPath(const fs::path &path);
/// Try to resolve all paths to an existing file (returns absolute paths)
inline std::vector<std::string> resolveAllAbsolute(const std::string &path) const {
std::vector<std::string> result;
if (FileStream::exists(path))
result.push_back(makeAbsolute(path));
for (unsigned int i=0; i<m_paths.size(); i++) {
std::string testPath = m_paths[i] + "/" + path;
if (FileStream::exists(testPath))
result.push_back(makeAbsolute(testPath));
}
return result;
}
/**
* Create a path for a new file. If the path is relative, it
* is appended to the thread's current working directory
*/
inline std::string resolveDest(const std::string &path) const {
if (isAbsolute(path))
return path;
else
return m_currentDirectory + "/" + path;
}
/**
* Return the filename (e.g. last component) of an absolute
* or relative path
*/
inline static std::string getFilename(const std::string &path) {
std::vector<std::string> components = tokenize(path, "/\\");
if (components.size() == 0)
return "";
return components[components.size()-1];
}
/// Clear all stored search paths
void clear();
/**
* Return the filename of an absolute or relative path. This
* version also removes the file extension (everything after
* the first period sign)
*/
inline static std::string getFilenameWithoutExtension(const std::string &path) {
std::string filename = getFilename(path);
size_t pos = filename.find('.');
if (pos != std::string::npos)
filename = filename.substr(0, pos);
return filename;
}
inline ~FileResolver() { }
inline std::string toString() const {
std::ostringstream oss;
oss << "FileResolver[" << endl
<< " cwd = \"" << m_currentDirectory << "\"," << endl
<< " paths = {" << endl;
for (size_t i=0; i<m_paths.size(); ++i)
oss << " \"" << m_paths[i] << "\"," << endl;
oss << " }" << endl
<< "]";
return oss.str();
}
/// Return a human-readable string representation
std::string toString() const;
MTS_DECLARE_CLASS()
protected:
inline FileResolver() { }
/// Check whether a given path is absolute
bool isAbsolute(const std::string &path) const {
#if defined(__OSX__) || defined(__LINUX__)
return (path.length() > 0 &&
(path[0] == '/' || path[0] == '~'));
#else
return (strchr(path.c_str(), ':') != NULL) ||
(path.length() > 0 && path[0] == '\\');
#endif
}
/// Turn a path into an absolute path
std::string makeAbsolute(const std::string &path) const {
if (isAbsolute(path))
return path;
char cwd[PATH_MAX];
#if !defined(WIN32)
if (getcwd(cwd, PATH_MAX) == NULL)
#else
if (_getcwd(cwd, PATH_MAX) == NULL)
#endif
Log(EError, "Cannot detect current path!");
return std::string(cwd) + PATHSEP + path;
}
virtual ~FileResolver() { }
private:
static ThreadLocal<FileResolver> m_tls;
std::vector<std::string> m_paths;
std::string m_currentDirectory;
std::vector<fs::path> m_paths;
};
MTS_NAMESPACE_END

View File

@ -21,46 +21,40 @@
#include <mitsuba/mitsuba.h>
#include <mitsuba/core/stream.h>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
MTS_NAMESPACE_BEGIN
/** \brief Simple Stream implementation which can be used to access files.
/** \brief Simple \ref Stream implementation for accessing files.
*
* This class uses streams on posix platforms and the native
* WIN32 API when used on windows.
* This class uses POSIX streams on Linux and OSX and the native
* WIN32 API when used on Windows.
*/
class MTS_EXPORT_CORE FileStream : public Stream {
public:
/// File opening modes
enum EFileMode {
/// rb
EReadOnly = 0,
/// rb+
EReadWrite,
/// wb
ETruncWrite,
/// wb+
ETruncReadWrite,
/// ab
EAppendWrite,
/// ab+
EAppendReadWrite
EReadOnly = 0, ///< rb
EReadWrite, ///< rb+
ETruncWrite, ///< wb
ETruncReadWrite, ///< wb+
EAppendWrite, ///< ab
EAppendReadWrite ///< ab+
};
/// Create a file stream class with no file open
FileStream();
/// Create a file stream class and open a file with a given EFileMode
FileStream(const std::string &filename, EFileMode mode = EReadOnly);
explicit FileStream(const fs::path &path, EFileMode mode = EReadOnly);
/// Return the file name
inline const std::string &getFileName() const { return m_filename; }
/// Check whether a file exists
static bool exists(const std::string &filename);
/// Return the file path
inline const fs::path &getPath() const { return m_path; }
/// Open a file with a given open mode
void open(const std::string &filename, EFileMode mode = EReadOnly);
void open(const fs::path &filename, EFileMode mode = EReadOnly);
/// Close the current file
void close();
@ -99,7 +93,7 @@ protected:
bool m_write;
bool m_read;
EFileMode m_mode;
std::string m_filename;
fs::path m_path;
};
MTS_NAMESPACE_END

116
include/mitsuba/core/fwd.h Normal file
View File

@ -0,0 +1,116 @@
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2010 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba 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/>.
*/
#if !defined(__CORE_FWD_H)
#define __CORE_FWD_H
MTS_NAMESPACE_BEGIN
struct AABB;
class Appender;
class Bitmap;
class BlackBodySpectrum;
struct BSphere;
class ConfigurableObject;
struct CacheLineCounter;
class Class;
class ConditionVariable;
class ConsoleStream;
class DefaultFormatter;
struct DiscretePDF;
class FileResolver;
class FileStream;
class Formatter;
struct Frame;
class InstanceManager;
class InterpolatedSpectrum;
class LocalWorker;
class Logger;
class Matrix4x4;
class MemoryStream;
class Mutex;
class NetworkedObject;
struct Normal;
class Object;
class ParallelProcess;
class Plugin;
class PluginManager;
class ProgressReporter;
class Properties;
class Random;
struct Ray;
struct RayDifferential;
class RemoteProcess;
class RemoteWorker;
class RemoteWorkerReader;
class Scheduler;
class Serializable;
class SerializableObject;
struct SHRotation;
class SHSampler;
struct SHVector;
struct SHVector4D;
class SmoothSpectrum;
class SocketStream;
class SparseWavelet2D;
class SparseWaveletOctree;
struct Spectrum;
class SSHStream;
class Statistics;
class StatsCounter;
class Stream;
class StreamAppender;
class StreamBackend;
class Thread;
class Timer;
struct Transform;
struct Triangle;
class UnbufferedAppender;
template <typename T> struct TVector2;
template <typename T> struct TVector3;
template <typename T> struct TVector4;
template <typename T> struct TPoint2;
template <typename T> struct TPoint3;
template <typename T> struct TPoint4;
typedef TVector2<Float> Vector2;
typedef TVector2<int> Vector2i;
typedef TVector3<Float> Vector;
typedef TVector3<Float> Vector3;
typedef TVector3<int> Vector3i;
typedef TVector4<Float> Vector4;
typedef TVector4<int> Vector4i;
typedef TPoint2<Float> Point2;
typedef TPoint2<int> Point2i;
typedef TPoint3<Float> Point;
typedef TPoint3<Float> Point3;
typedef TPoint3<int> Point3i;
typedef TPoint4<Float> Point4;
typedef TPoint4<int> Point4i;
struct Vertex;
class WaitFlag;
class Wavelet2D;
class Wavelet3D;
class Worker;
class WorkProcessor;
class WorkResult;
class WorkUnit;
class ZStream;
MTS_NAMESPACE_END
#endif /* __CORE_FWD_H */

View File

@ -20,13 +20,11 @@
#define __GRID_H
#include <mitsuba/mitsuba.h>
#include <stdexcept>
MTS_NAMESPACE_BEGIN
/**
* Uniform 3D grid for storing arbitrary quantities, which can
* be queried and updated by rasterizing rays to the grid.
* \brief Uniform 3D grid for storing and manipulating arbitrary quantities
*/
template <typename ValueType> class Grid {
public:
@ -83,7 +81,7 @@ public:
/// Return the grid AABB
inline const AABB &getAABB() const { return m_aabb; }
/// Return the grid resolution
inline const Vector3i &getResolution() const { return m_res; }
@ -99,7 +97,7 @@ public:
inline const ValueType &operator()(int x, int y, int z) const {
return m_cells[x + y*m_res.x + z*m_slab];
}
/// Return the underlying array
/// Return a pointer to the underlying array
inline ValueType *getData() const { return m_cells; }
/// Return a string representation
@ -173,7 +171,10 @@ public:
return true;
}
/// Rasterize a ray to the grid
/**
* \brief Rasterize a ray to the grid and apply the functor to
* every traversed cell
*/
template <typename Functor> void rasterize(const Ray &ray, Functor &functor) {
Float mint, maxt, t;

View File

@ -24,14 +24,14 @@
MTS_NAMESPACE_BEGIN
/**
* Thin wrapper around the recursive pthreads lock
* \brief Thin wrapper around the recursive pthreads lock
*/
class MTS_EXPORT_CORE Mutex : public Object {
friend class ConditionVariable;
public:
/// Create a new mutex object
Mutex();
/// Lock the mutex
inline void lock() {
pthread_mutex_lock(&m_mutex);
@ -51,15 +51,15 @@ private:
};
/**
* Wait flag synchronization primitive. Can be used to
* wait for a certain flag to become true.
* \brief Wait flag synchronization primitive. Can be used to
* wait for a certain event to occur.
*/
class MTS_EXPORT_CORE WaitFlag : public Object {
public:
/**
* Create a new wait flag
* \brief Create a new wait flag
* @param flag
* Initial state of the flag. If set to true, <tt>wait()</tt>
* Initial state of the flag. If set to true, \ref wait()
* will immediately return.
*/
WaitFlag(bool flag = false);
@ -67,16 +67,20 @@ public:
/// Return the current flag value
inline const bool &get() const { return m_flag; }
/// Set the value of the internal flag
/// Set the value of the flag
void set(bool value);
/// Wait for the flag to become true
/// Wait for the flag to be set to true
void wait();
/**
* Similar to wait(), but also uses a time value given
* in milliseconds. A return value of <tt>false</tt> signals
* \brief Temporarily wait for the flag to be set to true
*
* Similar to \ref wait(), but also uses a time value given
* in milliseconds. A return value of \a false signals
* that a timeout has occurred.
*
* \param ms Maximum waiting time in milliseconds
*/
bool wait(int ms);
@ -84,27 +88,29 @@ public:
protected:
/// Virtual destructor
virtual ~WaitFlag();
protected:
private:
bool m_flag;
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
};
/**
* Condition variable synchronization primitive. Can be used to
* wait for an arbitrary condition to become true in a safe way.
* \brief Condition variable synchronization primitive. Can be used to
* wait for a condition to become true in a safe way.
*/
class MTS_EXPORT_CORE ConditionVariable : public Object {
public:
/**
* Create a new condition variable. Also takes a mutex, which
* is later used by wait().
* \brief Create a new condition variable. Also takes a
* mutex, which is later used by wait().
*/
ConditionVariable(Mutex *mutex);
/**
* Send a signal, which wakes up at least one of the waiting
* threads. The calling thread does not have to hold the lock,
* \brief Send a signal, which wakes up at least one of
* the waiting threads.
*
* The calling thread does not have to hold the lock,
* but more predictable scheduling will occur if this is the
* case.
*/
@ -113,8 +119,9 @@ public:
}
/**
* Send a signal, which wakes up any waiting threads. The
* calling thread does not have to hold the lock, but more
* \brief Send a signal, which wakes up any waiting threads.
*
* The calling thread does not have to hold the lock, but more
* predictable scheduling will occur if this is the case.
*/
inline void broadcast() {
@ -122,7 +129,8 @@ public:
}
/**
* Wait for a signal and release the lock in the meanwhile.
* \brief Wait for a signal and release the lock in the meanwhile.
*
* Assumes that the lock specified in the constructor has
* previously been acquired. After returning, the lock is
* held again.
@ -132,10 +140,14 @@ public:
}
/**
* \brief Temporarily wait for a signal and release the lock in the meanwhile.
*
* Similar to wait(), but also uses a time value given
* in milliseconds. A return value of <tt>false</tt> signals
* in milliseconds. A return value of \a false signals
* that a timeout has occurred. The lock is held after
* returning in either case.
*
* \param ms Maximum waiting time in milliseconds
*/
bool wait(int ms);
@ -143,7 +155,7 @@ public:
protected:
/// Virtual destructor
virtual ~ConditionVariable();
protected:
private:
bool m_flag;
ref<Mutex> m_mutex;
pthread_cond_t m_cond;

View File

@ -20,14 +20,13 @@
#define __LOGGER_H
#include <mitsuba/core/formatter.h>
#include <mitsuba/core/appender.h>
MTS_NAMESPACE_BEGIN
// -----------------------------------------------------------------------
// Logging
// -----------------------------------------------------------------------
MTS_NAMESPACE_BEGIN
/// Write a Log message to the console (to be used within subclasses of <tt>Object</tt>)
#define Log(level, fmt, ...) Thread::getThread()->getLogger()->log(level, m_theClass, \
__FILE__, __LINE__, fmt, ## __VA_ARGS__)
@ -68,35 +67,39 @@ MTS_NAMESPACE_BEGIN
} while (0)
#endif
/** \brief The logger is the class responsible for the propagation of
* debug information. It invokes a Formatter implementation to convert
* events into a human-readable form and then sends this information to
* every registered Appender implementation.
/**
* \headerfile mitsuba/core/logger.h mitsuba/mitsuba.h
* \brief Responsible for processing log messages
*
* Upon receiving a log message, the Logger class invokes
* a Formatter to convert it into a human-readable form.
* Following that, it sends this information to every
* registered Appender.
*/
class MTS_EXPORT_CORE Logger : public Object {
public:
/// Construct a new logger
/// Construct a new logger with the given minimum log level
Logger(ELogLevel logLevel = EDebug);
/**
* Process a log message
* @param level Log level of the message
* @param theClass Class descriptor of the message creator
* @param fileName Source file of the message creator
* @param lineNumber Source line number of the message creator
* @param fmt printf-style string formatter
* \brief Process a log message
* \param level Log level of the message
* \param theClass Class descriptor of the message creator
* \param fileName Source file of the message creator
* \param lineNumber Source line number of the message creator
* \param fmt printf-style string formatter
*/
void log(ELogLevel level, const Class *theClass,
const char *fileName, int lineNumber,
const char *fmt, ...);
/**
* Process a progress message
* @param progress Percentage value in [0,100]
* @param name Title of the progress message
* @param formatted Formatted string representation of the message
* @param eta Estimated time until 100% is reached.
* @param ptr Custom pointer payload
* \brief Process a progress message
* \param progress Percentage value in [0,100]
* \param name Title of the progress message
* \param formatted Formatted string representation of the message
* \param eta Estimated time until 100% is reached.
* \param ptr Custom pointer payload
*/
void logProgress(Float progress, const std::string &name,
const std::string &formatted, const std::string &eta,
@ -142,7 +145,7 @@ public:
protected:
/// Virtual destructor
virtual ~Logger();
protected:
private:
ELogLevel m_logLevel;
ref<Formatter> m_formatter;
ref<Mutex> m_mutex;

View File

@ -24,7 +24,9 @@
MTS_NAMESPACE_BEGIN
/** \brief Simple memory buffer-based stream with automatic memory management
* (dynamically expands as data is written to it)
*
* The underlying memory storage of this implementation dynamically expands
* as data is written to the stream.
*/
class MTS_EXPORT_CORE MemoryStream : public Stream {
public:

View File

@ -19,30 +19,24 @@
#if !defined(__NETOBJECT_H)
#define __NETOBJECT_H
#include <mitsuba/core/sched.h>
#include <mitsuba/core/cobject.h>
MTS_NAMESPACE_BEGIN
/** \brief Interface of an abstract object referencing
* globally shared resources. When it is serialized for use in a
* parallel process executed on several machines, the object
* is first given the opportunity to bind named resources to
* the process, which will then be distributed to all participating
* compute servers. Once unserialized on the remote side,
* <tt>wakeup</tt> is called to let the object re-associate
* with the shared resources.
/** \brief Abstract interface for objects that reference shared network resources.
*
* When a networked object is serialized as part of a parallel process executed on
* multiple machines, the object is first given the opportunity to bind named resources
* to the process (by a call to <tt>\ref bindUsedResources()</tt>). These will then be
* distributed to all participating compute servers. Once unserialized on the remote side,
* <tt>\ref wakeup()</tt> is called to let the object re-associate with the shared resources.
*/
class MTS_EXPORT_CORE NetworkedObject : public ConfigurableObject {
public:
/// Constructor
inline NetworkedObject(const Properties &props) : ConfigurableObject(props) { }
/// Unserialize a configurable object
inline NetworkedObject(Stream *stream, InstanceManager *manager)
: ConfigurableObject(stream, manager) {
}
/// Bind any used resources to the process \a proc
virtual void bindUsedResources(ParallelProcess *proc) const;
/// Retrieve any required resources
virtual void wakeup(std::map<std::string, SerializableObject *> &params);
/// Serialize this object to a stream
@ -52,6 +46,14 @@ public:
protected:
/// Virtual destructor
virtual ~NetworkedObject() { }
/// Constructor
inline NetworkedObject(const Properties &props) : ConfigurableObject(props) { }
/// Unserialize a configurable object
inline NetworkedObject(Stream *stream, InstanceManager *manager)
: ConfigurableObject(stream, manager) {
}
};
MTS_NAMESPACE_END

View File

@ -23,165 +23,48 @@
MTS_NAMESPACE_BEGIN
/** \brief Simple three-dimensional normal class using floating point values.
* This class is different from the Vector class in how it is treated
* by linear transformations.
/**
* \headerfile mitsuba/core/normal.h mitsuba/mitsuba.h
* \brief Three-dimensional normal data structure
*
* Internally represented using floating point numbers of the chosen
* compile-time precision. The main difference in comparison to <tt>TVector3&lt;Float&gt;</tt>
* is in how instances of <tt>Normal</tt> are treated by linear transformations.
*/
class Normal {
public:
Float x, y, z;
struct Normal : public TVector3<Float> {
/** \brief Construct a new normal without initializing it.
*
* This construtor is useful when the normal will either not
* be used at all (it might be part of a larger data structure)
* or initialized at a later point in time. Always make sure
* that one of the two is the case! Otherwise your program will do
* computations involving uninitialized memory, which will probably
* lead to a difficult-to-find bug.
*/
Normal() { }
inline Normal(Float _x = 0.0f, Float _y = 0.0f, Float _z = 0.0f)
: x(_x), y(_y), z(_z) {
/// Initialize the vector with the specified X and Z components
Normal(Float x, Float y, Float z) : TVector3<Float>(x, y, z) { }
/// Initialize all components of the the normal with the specified value
explicit Normal(Float val) : TVector3<Float>(val) { }
/// Unserialize a normal from a binary data stream
Normal(Stream *stream) {
x = stream->readElement<Float>();
y = stream->readElement<Float>();
z = stream->readElement<Float>();
}
explicit inline Normal(const Vector &v)
: x(v.x), y(v.y), z(v.z) {
}
/// Construct a normal from a vector data structure
Normal(const TVector3<Float> &v) : TVector3<Float>(v.x, v.y, v.z) { }
inline Normal(Stream *stream) {
x = stream->readFloat();
y = stream->readFloat();
z = stream->readFloat();
}
inline Normal operator+(const Normal &v) const {
return Normal(x + v.x, y + v.y, z + v.z);
}
inline Normal operator-(const Normal &v) const {
return Normal(x - v.x, y - v.y, z - v.z);
}
inline Normal& operator+=(const Normal &v) {
x += v.x; y += v.y; z += v.z;
return *this;
}
inline Normal& operator-=(const Normal &v) {
x -= v.x; y -= v.y; z -= v.z;
return *this;
}
inline Normal operator*(Float f) const {
return Normal(x*f, y*f, z*f);
}
inline Normal &operator*=(Float f) {
x *= f;
y *= f;
z *= f;
return *this;
}
inline Normal operator-() const {
return Normal(-x, -y, -z);
}
inline Normal operator/(Float f) const {
#ifdef MTS_DEBUG
if (f == 0)
SLog(EWarn, "Normal: Division by zero!");
#endif
Float r = 1.0f / f;
return Normal(x * r, y * r, z * r);
}
inline Normal &operator/=(Float f) {
#ifdef MTS_DEBUG
if (f == 0)
SLog(EWarn, "Normal: Division by zero!");
#endif
Float r = 1.0f / f;
x *= r;
y *= r;
z *= r;
return *this;
}
inline Float operator[](int i) const {
return (&x)[i];
}
inline Float &operator[](int i) {
return (&x)[i];
}
inline bool isZero() const {
return x==0 && y == 0 && z == 0;
}
inline Float lengthSquared() const {
return x*x + y*y + z*z;
}
inline Float length() const {
return std::sqrt(lengthSquared());
}
inline bool operator==(const Normal &v) const {
return (v.x == x && v.y == y && v.z == z);
}
inline bool operator!=(const Normal &v) const {
return !operator==(v);
}
inline void serialize(Stream *stream) const {
stream->writeFloat(x);
stream->writeFloat(y);
stream->writeFloat(z);
}
inline std::string toString() const {
std::ostringstream oss;
oss << "[" << x << ", " << y << ", " << z << "]";
return oss.str();
/// Assign a vector to this normal
void operator=(const TVector3<Float> &v) {
x = v.x; y = v.y; z = v.z;
}
};
inline Float dot(const Normal &v1, const Normal &v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
inline Float dot(const Vector &v1, const Normal &v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
inline Float dot(const Normal &v1, const Vector &v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
inline Float absDot(const Normal &v1, const Normal &v2) {
return std::abs(dot(v1, v2));
}
inline Float absDot(const Vector &v1, const Normal &v2) {
return std::abs(dot(v1, v2));
}
inline Float absDot(const Normal &v1, const Vector &v2) {
return std::abs(dot(v1, v2));
}
inline Normal normalize(const Normal &n) {
Float length = n.length();
#ifdef MTS_DEBUG
if (length == 0.0f) {
SLog(EWarn, "Zero-length normal encountered!");
return n;
} else {
return n / length;
}
#else
return n / length;
#endif
}
inline Vector::Vector(const Normal &n)
: x(n.x), y(n.y), z(n.z) {
}
MTS_NAMESPACE_END
#endif /* __NORMAL_H */

View File

@ -24,42 +24,52 @@
MTS_NAMESPACE_BEGIN
/** \brief Base class of all Mitsuba classes.
/**
* \headerfile mitsuba/core/object.h mitsuba/mitsuba.h
* \brief Parent of all Mitsuba classes.
*
* Contains functions relevant to every object
* such as reference counting, limited type
* introspection and lifetime management.
* Contains functions relevant to every object such as reference counting,
* limited type introspection and lifetime management.
*
* @see ref, Class
* \sa ref, Class
*/
class MTS_EXPORT_CORE Object {
public:
/// Object constructor
/// Construct a new object
Object();
/// Get the reference count
/// Return the current reference count
inline int getRefCount() const;
/** \brief Increase the reference count of the
* object.
* object by one.
*/
void incRef() const;
/** \brief Decrease the reference count object
* of the object. It will automatically be de-
* allocated once the reference count reaches
* zero.
/** \brief Decrease the reference count of
* the object and possibly deallocate it.
*
* The object will automatically be deallocated once
* the reference count reaches zero.
*/
void decRef() const;
/// Retrieve this object's class
virtual const Class *getClass() const;
/// Convert to string
/**
* \brief Return a human-readable string representation
* of the object's contents.
*
* This function is mainly useful for debugging purposes
* and should ideally be implemented by all subclasses.
* The default implementation simply returns <tt>MyObject[unknown]</tt>,
* where <tt>MyObject</tt> is the name of the subclass.
*/
virtual std::string toString() const;
protected:
/** \brief Virtual private deconstructor.
* (Will only be called by 'ref')
* (Will only be called by \ref ref)
*/
virtual ~Object();
private:
@ -70,7 +80,7 @@ private:
mutable pthread_mutex_t m_refLock;
#endif
public:
static Class *m_theClass;
static Class *m_theClass; ///< Pointer to the object's class descriptor
};
inline int Object::getRefCount() const {

View File

@ -25,16 +25,24 @@
MTS_NAMESPACE_BEGIN
/**
* Templated multiple-reference octree. Based on the excellent
* implementation in PBRT. Modifications are the addition of a
* bounding sphere query and support for multithreading.
* \brief Generic multiple-reference octree.
*
* Based on the excellent implementation in PBRT. Modifications are
* the addition of a bounding sphere query and support for multithreading.
*/
template <typename T> class Octree {
public:
/**
* \brief Create a new octree
*
* By default, the maximum tree depth is set to 16
*/
inline Octree(const AABB &aabb, int maxDepth = 16)
: m_aabb(aabb), m_maxDepth(maxDepth) {
}
/// Insert an item with the specified cell coverage
inline void insert(const T &value, const AABB &coverage) {
insert(&m_root, m_aabb, value, coverage,
coverage.getExtents().lengthSquared(), 0);

View File

@ -22,12 +22,12 @@
MTS_NAMESPACE_BEGIN
/**
* Utility class, which represents a discrete probability
* distribution function along with its cumulative distribution
* function. Can transform uniformly distributed samples so
* that they match the stored distribution.
* \brief Stores a discrete probability distribution
*
* This class can be used to transform uniformly distributed samples
* so that they match the stored distribution.
*/
class DiscretePDF {
struct DiscretePDF {
public:
/// Allocate a PDF with the given number of entries
explicit inline DiscretePDF(int nEntries = 0) : m_ready(false) {
@ -41,7 +41,7 @@ public:
m_cdf.push_back(0.0f);
}
/// Return the amount of entries
/// Return the number of entries
inline size_t size() const {
return m_pdf.size();
}
@ -67,9 +67,9 @@ public:
}
/**
* Normalize the PDF and build the associated cumulative
* distribution function. Returns the sum of all unnormalized
* PDF values.
* \brief Normalize the PDF and build the associated cumulative
* distribution function.
* \return Sum of all unnormalized PDF values
*/
inline Float build() {
SAssert(m_pdf.size() > 0 && !m_ready);
@ -87,8 +87,9 @@ public:
}
/**
* Transform a uniformly distributed sample. Returns the
* PDF entry index.
* \brief %Transform a uniformly distributed sample
* \param[in] sampleValue Uniform sample
* \return Sample index
*/
inline int sample(Float sampleValue) const {
std::vector<Float>::const_iterator entry =
@ -98,8 +99,10 @@ public:
}
/**
* Transform a uniformly distributed sample. Returns the
* PDF entry index and the probability value at that index
* \brief %Transform a uniformly distributed sample.
* \param[in] sampleValue Uniform sample
* \param[out] pdf Probability value of the sample
* \return Sample index
*/
inline int sample(Float sampleValue, Float &pdf) const {
int index = sample(sampleValue);
@ -108,9 +111,11 @@ public:
}
/**
* Transform a uniformly distributed sample. Returns the
* PDF entry index. The original sample is transformed so
* that it can be re-used.
* \brief %Transform a uniformly distributed sample.
*
* The original sample is adjusted so that it can be reused.
* \param[in,out] sampleValue Uniform sample
* \return Sample index
*/
inline int sampleReuse(Float &sampleValue) const {
int index = sample(sampleValue);
@ -120,9 +125,12 @@ public:
}
/**
* Transform a uniformly distributed sample. Returns the
* PDF entry index and the probability value at that index.
* The original sample is transformed so that it can be re-used.
* \brief %Transform a uniformly distributed sample.
*
* The original sample is adjusted so that it can be reused.
* \param[in,out] sampleValue Uniform sample
* \param[out] pdf Probability value of the sample
* \return Sample index
*/
inline int sampleReuse(Float &sampleValue, Float &pdf) const {
int index = sample(sampleValue, pdf);

View File

@ -90,6 +90,8 @@
#endif
#define SIZE_T_FMT "%Iu"
#define BOOST_FILESYSTEM_NO_LIB
#define BOOST_SYSTEM_NO_LIB
#else
#define MTS_EXPORT
#define MTS_EXPORT_CORE

View File

@ -20,15 +20,18 @@
#define __PLUGIN_H
#include <mitsuba/mitsuba.h>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
MTS_NAMESPACE_BEGIN
class Utility;
/**
* Abstract plugin class -- can represent loadable configurable objects
* and utilities. Please see the <tt>ConfigurableObject</tt> and
* <tt>Utility</tt> class for details
* \brief Abstract plugin class -- represents loadable configurable objects
* and utilities.
*
* Please see the <tt>\ref ConfigurableObject</tt> and
* <tt>\ref Utility</tt> classes for details
*/
class MTS_EXPORT_CORE Plugin {
typedef void *(*CreateInstanceFunc)(const Properties &props);
@ -36,7 +39,7 @@ class MTS_EXPORT_CORE Plugin {
typedef char *(*GetDescriptionFunc)();
public:
/// Load a plugin from the supplied path
Plugin(const std::string &shortName, const std::string &path);
Plugin(const std::string &shortName, const fs::path &path);
/// Virtual destructor
virtual ~Plugin();
@ -54,7 +57,7 @@ public:
std::string getDescription() const;
/// Return the path of this plugin
inline const std::string &getPath() const { return m_path; }
inline const fs::path &getPath() const { return m_path; }
/// Return a short name of this plugin
inline const std::string &getShortName() const { return m_shortName; }
@ -68,15 +71,18 @@ private:
void *m_handle;
#endif
std::string m_shortName;
std::string m_path;
fs::path m_path;
bool m_isUtility;
GetDescriptionFunc m_getDescription;
CreateInstanceFunc m_createInstance;
CreateUtilityFunc m_createUtility;
};
class FileResolver;
/**
* \brief The plugin manager is responsible for resolving and
* loading external plugins.
*/
class MTS_EXPORT_CORE PluginManager : public Object {
public:
/// Return the global plugin manager
@ -90,7 +96,15 @@ public:
/// Return the list of loaded plugins
std::vector<std::string> getLoadedPlugins() const;
/// Instantiate an object
/**
* \brief Instantiate an object using a plugin
* \param classType Expected type of the plugin. An
* exception will be thrown if it turns out not
* to derive from this class.
* \param props A \ref Properties instance containing
* all information required to find and construct
* the plugin.
*/
ConfigurableObject *createObject(
const Class *classType,
const Properties &props

View File

@ -23,470 +23,572 @@
MTS_NAMESPACE_BEGIN
/** \brief Simple three-dimensional point class using floating point values.
* This class is different from the Vector class in how it is treated
* by linear transformations.
/**
* \headerfile mitsuba/core/point.h mitsuba/mitsuba.h
* \brief Parameterizable two-dimensional point data structure
*/
class Point {
public:
Float x, y, z;
template <typename T> struct TPoint2 {
T x, y;
inline Point(Float _x = 0.0f, Float _y = 0.0f, Float _z = 0.0f)
: x(_x), y(_y), z(_z) {
}
inline Point(Stream *stream) {
x = stream->readFloat();
y = stream->readFloat();
z = stream->readFloat();
}
explicit inline Point(const Vector &v)
: x(v.x), y(v.y), z(v.z) {
}
inline Point operator+(const Vector &v) const {
return Point(x + v.x, y + v.y, z + v.z);
}
inline Point operator-(const Vector &v) const {
return Point(x - v.x, y - v.y, z - v.z);
}
inline Vector operator-(const Point &p) const {
return Vector(x - p.x, y - p.y, z - p.z);
}
inline Point operator+(const Point &p) const {
return Point(x + p.x, y + p.y, z + p.z);
}
inline Point& operator+=(const Point &p) {
x += p.x; y += p.y; z += p.z;
return *this;
}
inline Point& operator+=(const Vector &v) {
x += v.x; y += v.y; z += v.z;
return *this;
}
inline Point& operator-=(const Vector &v) {
x -= v.x; y -= v.y; z -= v.z;
return *this;
}
inline Point operator*(Float f) const {
return Point(x*f, y*f, z*f);
}
inline Point &operator*=(Float f) {
x *= f;
y *= f;
z *= f;
return *this;
}
inline Point operator/(Float f) const {
#ifdef MTS_DEBUG
if (f == 0)
SLog(EWarn, "Point: Division by zero!");
/** \brief Construct a new point without initializing it.
*
* This construtor is useful when the point will either not
* be used at all (it might be part of a larger data structure)
* or initialized at a later point in time. Always make sure
* that one of the two is the case! Otherwise your program will do
* computations involving uninitialized memory, which will probably
* lead to a difficult-to-find bug.
*/
#if !defined(MTS_DEBUG_UNINITIALIZED)
TPoint2() { }
#else
TPoint2() { x = y = std::numeric_limits<double>::quiet_NaN(); }
#endif
Float r = 1.0f / f;
return Point(x * r, y * r, z * r);
/// Initialize the point with the specified X, Y and Z components
TPoint2(T x, T y) : x(x), y(y) { }
/// Initialize the point with the components of another point
template <typename T2> explicit TPoint2(const TPoint2<T2> &p)
: x((T) p.x), y((T) p.y) { }
/// Initialize the point with the components of a vector data structure
template <typename T2> explicit TPoint2(const TVector2<T2> &v)
: x((T) v.x), y((T) v.y) { }
/// Initialize all components of the the point with the specified value
explicit TPoint2(T val) : x(val), y(val) { }
/// Unserialize a point from a binary data stream
TPoint2(Stream *stream) {
x = stream->readElement<T>();
y = stream->readElement<T>();
}
inline Point &operator/=(Float f) {
#ifdef MTS_DEBUG
if (f == 0)
SLog(EWarn, "Point: Division by zero!");
#endif
Float r = 1.0f / f;
x *= r;
y *= r;
z *= r;
/// Add a vector to a point and return the result
TPoint2 operator+(const TVector2<T> &v) const {
return TPoint2(x + v.x, y + v.y);
}
/// Add two points and return the result (e.g. to compute a weighted position)
TPoint2 operator+(const TPoint2 &p) const {
return TPoint2(x + p.x, y + p.y);
}
/// Add a vector to this one (e.g. to compute a weighted position)
TPoint2& operator+=(const TVector2<T> &v) {
x += v.x; y += v.y;
return *this;
}
inline Float operator[](int i) const {
return (&x)[i];
}
inline Float &operator[](int i) {
return (&x)[i];
}
inline bool operator==(const Point &v) const {
return (v.x == x && v.y == y && v.z == z);
}
inline bool operator!=(const Point &v) const {
return !operator==(v);
}
inline bool isZero() const {
return x==0 && y == 0 && z == 0;
}
inline void serialize(Stream *stream) const {
stream->writeFloat(x);
stream->writeFloat(y);
stream->writeFloat(z);
}
inline std::string toString() const {
std::ostringstream oss;
oss << "[" << x << ", " << y << ", " << z << "]";
return oss.str();
}
};
class Point2 {
public:
Float x, y;
inline Point2(Float _x = 0.0f, Float _y = 0.0f)
: x(_x), y(_y) {
}
inline Point2(Stream *stream) {
x = stream->readFloat();
y = stream->readFloat();
}
inline Point2 operator*(Float f) const {
return Point2(x*f, y*f);
}
inline Point2 &operator*=(Float f) {
x *= f;
y *= f;
return *this;
}
inline Point2 operator+(const Point2 &p) const {
return Point2(x + p.x, y + p.y);
}
inline Point2 operator+(const Vector2 &p) const {
return Point2(x + p.x, y + p.y);
}
inline Point2& operator+=(const Point2 &p) {
x += p.x; y += p.y;
return *this;
}
inline Point2& operator+=(const Vector2 &p) {
/// Add a point to this one (e.g. to compute a weighted position)
TPoint2& operator+=(const TPoint2 &p) {
x += p.x; y += p.y;
return *this;
}
inline Vector2 operator-(const Point2 &p) const {
return Vector2(x - p.x, y - p.y);
}
inline Point2 operator-(const Vector2 &p) const {
return Point2(x - p.x, y - p.y);
/// Subtract a vector from this point
TPoint2 operator-(const TVector2<T> &v) const {
return TPoint2(x - v.x, y - v.y);
}
inline Point2& operator-=(const Point2 &p) {
x -= p.x; y -= p.y;
return *this;
}
inline Point2& operator-=(const Vector2 &p) {
x -= p.x; y -= p.y;
return *this;
/// Subtract two points from each other and return the difference as a vector
TVector2<T> operator-(const TPoint2 &p) const {
return TVector2<T>(x - p.x, y - p.y);
}
inline Point2 operator/(Float f) const {
Float r = 1.0f / f;
return Point2(x * r, y * r);
}
inline Point2 &operator/=(Float f) {
Float r = 1.0f / f;
x *= r;
y *= r;
return *this;
}
inline Float operator[](int i) const {
return (&x)[i];
}
inline Float &operator[](int i) {
return (&x)[i];
}
inline bool operator==(const Point2 &v) const {
return (v.x == x && v.y == y);
}
inline bool operator!=(const Point2 &v) const {
return !operator==(v);
}
inline bool isZero() const {
return x==0 && y == 0;
}
inline void serialize(Stream *stream) const {
stream->writeFloat(x);
stream->writeFloat(y);
}
inline std::string toString() const {
std::ostringstream oss;
oss << "[" << x << ", " << y << "]";
return oss.str();
}
};
class Point3i {
public:
int x, y, z;
inline Point3i(int _x = 0, int _y = 0, int _z = 0)
: x(_x), y(_y), z(_z) {
}
inline Point3i(Stream *stream) {
x = stream->readInt();
y = stream->readInt();
z = stream->readInt();
}
explicit inline Point3i(const Vector3i &v)
: x(v.x), y(v.y), z(v.z) {
}
inline Point3i operator+(const Vector3i &v) const {
return Point3i(x + v.x, y + v.y, z + v.z);
}
inline Point3i operator-(const Vector3i &v) const {
return Point3i(x - v.x, y - v.y, z - v.z);
}
inline Vector3i operator-(const Point3i &p) const {
return Vector3i(x - p.x, y - p.y, z - p.z);
}
inline Point3i operator+(const Point3i &p) const {
return Point3i(x + p.x, y + p.y, z + p.z);
}
inline Point3i& operator+=(const Point3i &p) {
x += p.x; y += p.y; z += p.z;
return *this;
}
inline Point3i& operator+=(const Vector3i &v) {
x += v.x; y += v.y; z += v.z;
return *this;
}
inline Point3i& operator-=(const Vector3i &v) {
x -= v.x; y -= v.y; z -= v.z;
return *this;
}
inline Point3i operator*(int f) const {
return Point3i(x*f, y*f, z*f);
}
inline Point3i &operator*=(int f) {
x *= f;
y *= f;
z *= f;
return *this;
}
inline Point3i operator/(int i) const {
#ifdef MTS_DEBUG
if (i == 0)
SLog(EWarn, "Point3i: Division by zero!");
#endif
return Point3i(x / i, y / i, z / i);
}
inline Point3i &operator/=(int i) {
#ifdef MTS_DEBUG
if (i == 0)
SLog(EWarn, "Point3i: Division by zero!");
#endif
x /= i;
y /= i;
z /= i;
return *this;
}
inline int operator[](int i) const {
return (&x)[i];
}
inline int &operator[](int i) {
return (&x)[i];
}
inline bool operator==(const Point3i &v) const {
return (v.x == x && v.y == y && v.z == z);
}
inline bool operator!=(const Point3i &v) const {
return !operator==(v);
}
inline bool isZero() const {
return x==0 && y == 0 && z == 0;
}
inline void serialize(Stream *stream) const {
stream->writeInt(x);
stream->writeInt(y);
stream->writeInt(z);
}
inline std::string toString() const {
std::ostringstream oss;
oss << "[" << x << ", " << y << ", " << z << "]";
return oss.str();
}
};
class Point2i {
public:
int x, y;
inline Point2i(int _x = 0, int _y = 0)
: x(_x), y(_y) {
}
explicit inline Point2i(const Vector2i &v)
: x(v.x), y(v.y) {
}
inline Point2i(Stream *stream) {
x = stream->readInt();
y = stream->readInt();
}
inline Point2i operator*(int i) const {
return Point2i(x*i, y*i);
}
inline Point2i &operator*=(int i) {
x *= i;
y *= i;
return *this;
}
inline Point2i operator+(const Point2i &p) const {
return Point2i(x + p.x, y + p.y);
}
inline Point2i operator+(const Vector2i &v) const {
return Point2i(x + v.x, y + v.y);
}
inline Point2i& operator+=(const Point2i &p) {
x += p.x; y += p.y;
return *this;
}
inline Point2i& operator+=(const Vector2i &v) {
x += v.x; y += v.y;
return *this;
}
inline Point2i operator-(const Point2i &p) const {
return Point2i(x - p.x, y - p.y);
}
inline Point2i operator-(const Vector2i &v) const {
return Point2i(x - v.x, y - v.y);
}
inline Point2i& operator-=(const Point2i &p) {
x -= p.x; y -= p.y;
return *this;
}
inline Point2i& operator-=(const Vector2i &v) {
/// Subtract a vector from this point
TPoint2& operator-=(const TVector2<T> &v) {
x -= v.x; y -= v.y;
return *this;
}
inline Point2i operator/(int i) const {
return Point2i(x / i, y / i);
/// Scale the point's coordinates by the given scalar and return the result
TPoint2 operator*(T f) const {
return TPoint2(x * f, y * f);
}
inline Point2i &operator/=(int i) {
x /= i;
y /= i;
/// Scale the point's coordinates by the given scalar
TPoint2 &operator*=(T f) {
x *= f; y *= f;
return *this;
}
int operator[](int i) const {
/// Return a version of the point, which has been flipped along the origin
TPoint2 operator-() const {
return TPoint2(-x, -y);
}
/// Divide the point's coordinates by the given scalar and return the result
TPoint2 operator/(T f) const {
#ifdef MTS_DEBUG
if (f == 0)
SLog(EWarn, "Point2: Division by zero!");
#endif
T recip = (T) 1 / f;
return TPoint2(x * recip, y * recip);
}
/// Divide the point's coordinates by the given scalar
TPoint2 &operator/=(T f) {
#ifdef MTS_DEBUG
if (f == 0)
SLog(EWarn, "Point2: Division by zero!");
#endif
T recip = (T) 1 / f;
x *= recip; y *= recip;
return *this;
}
/// Index into the point's components
T &operator[](int i) {
return (&x)[i];
}
int &operator[](int i) {
/// Index into the point's components (const version)
T operator[](int i) const {
return (&x)[i];
}
inline bool operator==(const Point2i &v) const {
/// Return whether or not this point is identically zero
bool isZero() const {
return x == 0 && y == 0;
}
/// Equality test
bool operator==(const TPoint2 &v) const {
return (v.x == x && v.y == y);
}
inline bool operator!=(const Point2i &v) const {
return !operator==(v);
/// Inequality test
bool operator!=(const TPoint2 &v) const {
return v.x != x || v.y != y;
}
inline bool isZero() const {
return x==0 && y == 0;
/// Serialize this point to a binary data stream
void serialize(Stream *stream) const {
stream->writeElement<T>(x);
stream->writeElement<T>(y);
}
inline void serialize(Stream *stream) const {
stream->writeInt(x);
stream->writeInt(y);
}
inline std::string toString() const {
/// Return a readable string representation of this point
std::string toString() const {
std::ostringstream oss;
oss << "[" << x << ", " << y << "]";
return oss.str();
}
};
inline Vector::Vector(const Point3i &p)
: x((Float) p.x), y((Float) p.y), z((Float) p.z) {
template <typename T> inline TPoint2<T> operator*(T f, const TPoint2<T> &v) {
return v*f;
}
inline Vector3i::Vector3i(const Point3i &p)
: x(p.x), y(p.y), z(p.z) {
template <typename T> inline T distance(const TPoint2<T> &p1, const TPoint2<T> &p2) {
return (p1-p2).length();
}
inline Vector::Vector(const Point &p)
: x(p.x), y(p.y), z(p.z) {
template <typename T> inline T distanceSquared(const TPoint2<T> &p1, const TPoint2<T> &p2) {
return (p1-p2).lengthSquared();
}
inline Vector2::Vector2(const Point2 &p)
: x(p.x), y(p.y) {
template <> inline TPoint2<int> TPoint2<int>::operator/(int s) const {
#ifdef MTS_DEBUG
if (s == 0)
SLog(EWarn, "Point2i: Division by zero!");
#endif
return TPoint2(x/s, y/s);
}
inline Vector2i::Vector2i(const Point2i &p)
: x(p.x), y(p.y) {
template <> inline TPoint2<int> &TPoint2<int>::operator/=(int s) {
#ifdef MTS_DEBUG
if (s == 0)
SLog(EWarn, "Point2i: Division by zero!");
#endif
x /= s;
y /= s;
return *this;
}
inline Float distance(const Point &p1, const Point &p2) {
return (p1 - p2).length();
/**
* \headerfile mitsuba/core/point.h mitsuba/mitsuba.h
* \brief Parameterizable three-dimensional point data structure
*/
template <typename T> struct TPoint3 {
T x, y, z;
/** \brief Construct a new point without initializing it.
*
* This construtor is useful when the point will either not
* be used at all (it might be part of a larger data structure)
* or initialized at a later point in time. Always make sure
* that one of the two is the case! Otherwise your program will do
* computations involving uninitialized memory, which will probably
* lead to a difficult-to-find bug.
*/
#if !defined(MTS_DEBUG_UNINITIALIZED)
TPoint3() { }
#else
TPoint3() { x = y = z = std::numeric_limits<double>::quiet_NaN(); }
#endif
/// Initialize the point with the specified X, Y and Z components
TPoint3(T x, T y, T z) : x(x), y(y), z(z) { }
/// Initialize the point with the components of another point
template <typename T2> explicit TPoint3(const TPoint3<T2> &p)
: x((T) p.x), y((T) p.y), z((T) p.z) { }
/// Initialize the point with the components of a vector data structure
template <typename T2> explicit TPoint3(const TVector3<T2> &v)
: x((T) v.x), y((T) v.y), z((T) v.z) { }
/// Initialize all components of the the point with the specified value
explicit TPoint3(T val) : x(val), y(val), z(val) { }
/// Unserialize a point from a binary data stream
TPoint3(Stream *stream) {
x = stream->readElement<T>();
y = stream->readElement<T>();
z = stream->readElement<T>();
}
/// Add a vector to a point and return the result
TPoint3 operator+(const TVector3<T> &v) const {
return TPoint3(x + v.x, y + v.y, z + v.z);
}
/// Add two points and return the result (e.g. to compute a weighted position)
TPoint3 operator+(const TPoint3 &p) const {
return TPoint3(x + p.x, y + p.y, z + p.z);
}
/// Add a vector to this one (e.g. to compute a weighted position)
TPoint3& operator+=(const TVector3<T> &v) {
x += v.x; y += v.y; z += v.z;
return *this;
}
/// Add a point to this one (e.g. to compute a weighted position)
TPoint3& operator+=(const TPoint3 &p) {
x += p.x; y += p.y; z += p.z;
return *this;
}
/// Subtract a vector from this point
TPoint3 operator-(const TVector3<T> &v) const {
return TPoint3(x - v.x, y - v.y, z - v.z);
}
/// Subtract two points from each other and return the difference as a vector
TVector3<T> operator-(const TPoint3 &p) const {
return TVector3<T>(x - p.x, y - p.y, z - p.z);
}
/// Subtract a vector from this point
TPoint3& operator-=(const TVector3<T> &v) {
x -= v.x; y -= v.y; z -= v.z;
return *this;
}
/// Scale the point's coordinates by the given scalar and return the result
TPoint3 operator*(T f) const {
return TPoint3(x * f, y * f, z * f);
}
/// Scale the point's coordinates by the given scalar
TPoint3 &operator*=(T f) {
x *= f; y *= f; z *= f;
return *this;
}
/// Return a version of the point, which has been flipped along the origin
TPoint3 operator-() const {
return TPoint3(-x, -y, -z);
}
/// Divide the point's coordinates by the given scalar and return the result
TPoint3 operator/(T f) const {
#ifdef MTS_DEBUG
if (f == 0)
SLog(EWarn, "Point3: Division by zero!");
#endif
T recip = (T) 1 / f;
return TPoint3(x * recip, y * recip, z * recip);
}
/// Divide the point's coordinates by the given scalar
TPoint3 &operator/=(T f) {
#ifdef MTS_DEBUG
if (f == 0)
SLog(EWarn, "Point3: Division by zero!");
#endif
T recip = (T) 1 / f;
x *= recip; y *= recip; z *= recip;
return *this;
}
/// Index into the point's components
T &operator[](int i) {
return (&x)[i];
}
/// Index into the point's components (const version)
T operator[](int i) const {
return (&x)[i];
}
/// Return whether or not this point is identically zero
bool isZero() const {
return x == 0 && y == 0 && z == 0;
}
/// Equality test
bool operator==(const TPoint3 &v) const {
return (v.x == x && v.y == y && v.z == z);
}
/// Inequality test
bool operator!=(const TPoint3 &v) const {
return v.x != x || v.y != y || v.z != z;
}
/// Serialize this point to a binary data stream
void serialize(Stream *stream) const {
stream->writeElement<T>(x);
stream->writeElement<T>(y);
stream->writeElement<T>(z);
}
/// Return a readable string representation of this point
std::string toString() const {
std::ostringstream oss;
oss << "[" << x << ", " << y << ", " << z << "]";
return oss.str();
}
};
template <typename T> inline TPoint3<T> operator*(T f, const TPoint3<T> &v) {
return v*f;
}
inline Float distanceSquared(const Point &p1, const Point &p2) {
return (p1 - p2).lengthSquared();
template <typename T> inline T distance(const TPoint3<T> &p1, const TPoint3<T> &p2) {
return (p1-p2).length();
}
template <typename T> inline T distanceSquared(const TPoint3<T> &p1, const TPoint3<T> &p2) {
return (p1-p2).lengthSquared();
}
template <> inline TPoint3<int> TPoint3<int>::operator/(int s) const {
#ifdef MTS_DEBUG
if (s == 0)
SLog(EWarn, "Point3i: Division by zero!");
#endif
return TPoint3(x/s, y/s, z/s);
}
template <> inline TPoint3<int> &TPoint3<int>::operator/=(int s) {
#ifdef MTS_DEBUG
if (s == 0)
SLog(EWarn, "Point3i: Division by zero!");
#endif
x /= s;
y /= s;
z /= s;
return *this;
}
/**
* \headerfile mitsuba/core/point.h mitsuba/mitsuba.h
* \brief Parameterizable four-dimensional point data structure
*/
template <typename T> struct TPoint4 {
T x, y, z, w;
/** \brief Construct a new point without initializing it.
*
* This construtor is useful when the point will either not
* be used at all (it might be part of a larger data structure)
* or initialized at a later point in time. Always make sure
* that one of the two is the case! Otherwise your program will do
* computations involving uninitialized memory, which will probably
* lead to a difficult-to-find bug.
*/
#if !defined(MTS_DEBUG_UNINITIALIZED)
TPoint4() { }
#else
TPoint4() { x = y = z = w = std::numeric_limits<double>::quiet_NaN(); }
#endif
/// Initialize the point with the specified X, Y and Z components
TPoint4(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) { }
/// Initialize the point with the components of another point
template <typename T2> explicit TPoint4(const TPoint4<T2> &p)
: x((T) p.x), y((T) p.y), z((T) p.z), w((T) p.w) { }
/// Initialize the point with the components of a vector data structure
template <typename T2> explicit TPoint4(const TVector4<T2> &v)
: x((T) v.x), y((T) v.y), z((T) v.z), w((T) v.w) { }
/// Initialize all components of the the point with the specified value
explicit TPoint4(T val) : x(val), y(val), z(val), w(val) { }
/// Unserialize a point from a binary data stream
TPoint4(Stream *stream) {
x = stream->readElement<T>();
y = stream->readElement<T>();
z = stream->readElement<T>();
w = stream->readElement<T>();
}
/// Add a vector to a point and return the result
TPoint4 operator+(const TVector4<T> &v) const {
return TPoint4(x + v.x, y + v.y, z + v.z, w + v.w);
}
/// Add two points and return the result (e.g. to compute a weighted position)
TPoint4 operator+(const TPoint4 &p) const {
return TPoint4(x + p.x, y + p.y, z + p.z, w + p.w);
}
/// Add a vector to this one (e.g. to compute a weighted position)
TPoint4& operator+=(const TVector4<T> &v) {
x += v.x; y += v.y; z += v.z; w += v.w;
return *this;
}
/// Add a point to this one (e.g. to compute a weighted position)
TPoint4& operator+=(const TPoint4 &p) {
x += p.x; y += p.y; z += p.z; w += p.w;
return *this;
}
/// Subtract a vector from this point
TPoint4 operator-(const TVector4<T> &v) const {
return TPoint4(x - v.x, y - v.y, z - v.z, w - v.w);
}
/// Subtract two points from each other and return the difference as a vector
TVector4<T> operator-(const TPoint4 &p) const {
return TVector4<T>(x - p.x, y - p.y, z - p.z, w - p.w);
}
/// Subtract a vector from this point
TPoint4& operator-=(const TVector4<T> &v) {
x -= v.x; y -= v.y; z -= v.z; w -= v.w;
return *this;
}
/// Scale the point's coordinates by the given scalar and return the result
TPoint4 operator*(T f) const {
return TPoint4(x * f, y * f, z * f, w * f);
}
/// Scale the point's coordinates by the given scalar
TPoint4 &operator*=(T f) {
x *= f; y *= f; z *= f; w *= f;
return *this;
}
/// Return a version of the point, which has been flipped along the origin
TPoint4 operator-() const {
return TPoint4(-x, -y, -z, -w);
}
/// Divide the point's coordinates by the given scalar and return the result
TPoint4 operator/(T f) const {
#ifdef MTS_DEBUG
if (f == 0)
SLog(EWarn, "Point4: Division by zero!");
#endif
T recip = (T) 1 / f;
return TPoint4(x * recip, y * recip, z * recip, w * recip);
}
/// Divide the point's coordinates by the given scalar
TPoint4 &operator/=(T f) {
#ifdef MTS_DEBUG
if (f == 0)
SLog(EWarn, "Point4: Division by zero!");
#endif
T recip = (T) 1 / f;
x *= recip; y *= recip; z *= recip; w *= recip;
return *this;
}
/// Index into the point's components
T &operator[](int i) {
return (&x)[i];
}
/// Index into the point's components (const version)
T operator[](int i) const {
return (&x)[i];
}
/// Return whether or not this point is identically zero
bool isZero() const {
return x == 0 && y == 0 && z == 0 && w == 0;
}
/// Equality test
bool operator==(const TPoint4 &v) const {
return (v.x == x && v.y == y && v.z == z && v.w == w);
}
/// Inequality test
bool operator!=(const TPoint4 &v) const {
return v.x != x || v.y != y || v.z != z || v.w != w;
}
/// Serialize this point to a binary data stream
void serialize(Stream *stream) const {
stream->writeElement<T>(x);
stream->writeElement<T>(y);
stream->writeElement<T>(z);
stream->writeElement<T>(w);
}
/// Return a readable string representation of this point
std::string toString() const {
std::ostringstream oss;
oss << "[" << x << ", " << y << ", " << z << ", " << w << "]";
return oss.str();
}
};
template <typename T> inline TPoint4<T> operator*(T f, const TPoint4<T> &v) {
return v*f;
}
template <typename T> inline T distance(const TPoint4<T> &p1, const TPoint4<T> &p2) {
return (p1-p2).length();
}
template <typename T> inline T distanceSquared(const TPoint4<T> &p1, const TPoint4<T> &p2) {
return (p1-p2).lengthSquared();
}
template <> inline TPoint4<int> TPoint4<int>::operator/(int s) const {
#ifdef MTS_DEBUG
if (s == 0)
SLog(EWarn, "Point4i: Division by zero!");
#endif
return TPoint4(x/s, y/s, z/s, w/s);
}
template <> inline TPoint4<int> &TPoint4<int>::operator/=(int s) {
#ifdef MTS_DEBUG
if (s == 0)
SLog(EWarn, "Point4i: Division by zero!");
#endif
x /= s;
y /= s;
z /= s;
w /= s;
return *this;
}
MTS_NAMESPACE_END

View File

@ -19,14 +19,13 @@
#if !defined(__PROPERTIES_H)
#define __PROPERTIES_H
#include <mitsuba/mitsuba.h>
#include <mitsuba/core/transform.h>
#include <mitsuba/core/spectrum.h>
#include <map>
MTS_NAMESPACE_BEGIN
/** \brief Associative map for values of various types. Used to
* construct sub-classes of <tt>ConfigurableObject</tt>
* construct subclasses of <tt>ConfigurableObject</tt>.
*/
class MTS_EXPORT_CORE Properties {
public:
@ -135,6 +134,7 @@ public:
/// Return a string representation
std::string toString() const;
private:
/// \cond
struct Element {
PropertyType type;
union {
@ -150,6 +150,7 @@ private:
std::string v_string;
mutable bool queried;
};
/// \endcond
std::map<std::string, Element> m_elements;
std::string m_pluginName, m_id;

View File

@ -20,7 +20,7 @@
#define __RANDOM_H
#include <mitsuba/mitsuba.h>
#include <algorithm>
#include <mitsuba/core/cobject.h>
/*
A C-program for MT19937-64 (2004/9/29 version).
@ -86,12 +86,17 @@
MTS_NAMESPACE_BEGIN
/**
* \brief %Random number generator based on Mersenne Twister
* by Takuji Nishimura and Makoto Matsumoto.
*/
class MTS_EXPORT_CORE Random : public SerializableObject {
public:
/**
* Construct a new seeded random generator. Uses the default
* seed on Windows and '/dev/urandom' on OSX and Linux.
* \brief Construct a new seeded random generator.
*
* Uses the default seed on Windows and '/dev/urandom'
* on OSX and Linux.
*/
Random();
@ -123,8 +128,10 @@ public:
Float nextFloat();
/**
* Draw a uniformly distributed permutation and permute the given STL container
* (see Knuth, TAoCP Vol. 2 (3rd 3d), Section 3.4.2)
* \brief Draw a uniformly distributed permutation and permute the
* given STL container.
*
* See Knuth, TAoCP Vol. 2 (3rd 3d), Section 3.4.2.
*/
template <typename Iterator> void shuffle(Iterator it1, Iterator it2) {
for (Iterator it = it2 - 1; it > it1; --it)

View File

@ -19,24 +19,18 @@
#if !defined(__RAY_H)
#define __RAY_H
#include <mitsuba/core/point.h>
#include <mitsuba/mitsuba.h>
MTS_NAMESPACE_BEGIN
/** \brief Simple three-dimensional ray class with
minimum / maximum extent information */
class Ray {
public:
/// Ray origin
Point o;
/// Minimum range for intersection tests
Float mint;
/// Ray direction
Vector d;
/// Maximum range for intersection tests
Float maxt;
/// Ray direction reciprocal
Vector dRcp;
struct Ray {
Point o; ///< Ray origin
Float mint; ///< Minimum range for intersection tests
Vector d; ///< Ray direction
Float maxt; ///< Maximum range for intersection tests
Vector dRcp; ///< Componentwise reciprocals of the ray direction
/// Construct a new ray
inline Ray() : mint(Epsilon), maxt(std::numeric_limits<Float>::infinity()) {
@ -108,10 +102,9 @@ public:
}
};
/** \brief Ray differential -- enhances the basic ray class with
/** \brief %Ray differential -- enhances the basic ray class with
information about the rays of adjacent pixels on the view plane */
class RayDifferential : public Ray {
public:
struct RayDifferential : public Ray {
bool hasDifferentials;
Ray rx, ry;
@ -126,16 +119,29 @@ public:
inline explicit RayDifferential(const Ray &ray)
: Ray(ray), hasDifferentials(false) {
}
inline RayDifferential(const RayDifferential &ray)
: Ray(ray), hasDifferentials(ray.hasDifferentials), rx(ray.rx), ry(ray.ry) {
}
inline void operator=(const RayDifferential &ray) {
o = ray.o;
mint = ray.mint;
d = ray.d;
maxt = ray.maxt;
dRcp = ray.dRcp;
hasDifferentials = ray.hasDifferentials;
rx = ray.rx;
ry = ray.ry;
}
inline void operator=(const Ray &ray) {
setOrigin(ray.o);
setDirection(ray.d);
o = ray.o;
mint = ray.mint;
d = ray.d;
maxt = ray.maxt;
dRcp = ray.dRcp;
hasDifferentials = false;
}
};

View File

@ -21,8 +21,16 @@
MTS_NAMESPACE_BEGIN
/** \brief A simple wrapper class which takes care of
* referencing and unreferencing objects
/**
* \headerfile mitsuba/core/ref.h mitsuba/mitsuba.h
* \brief Reference counting helper
*
* The \a ref refeference template is a simple wrapper to store a
* pointer to an object. It takes care of increasing and decreasing
* the reference count of the object. When the last reference goes
* out of scope, the associated object will be deallocated.
*
* \author Wenzel Jakob
*/
template <typename T> class ref {
public:
@ -30,13 +38,13 @@ public:
ref() : m_ptr(NULL) { }
/// Construct a reference from a pointer
ref(T *ptr) : m_ptr(ptr) { if (m_ptr) m_ptr->incRef(); }
ref(T *ptr) : m_ptr(ptr) { if (m_ptr) ((Object *) m_ptr)->incRef(); }
/// Copy-constructor
ref(const ref &pRef) : m_ptr(pRef.m_ptr) { if (m_ptr) m_ptr->incRef(); }
ref(const ref &pRef) : m_ptr(pRef.m_ptr) { if (m_ptr) ((Object *) m_ptr)->incRef(); }
/// Destroy this reference
~ref() { if (m_ptr) m_ptr->decRef(); }
~ref() { if (m_ptr) ((Object *) m_ptr)->decRef(); }
/// Overwrite this reference with another reference
inline ref& operator= (const ref& pref) {
@ -45,9 +53,9 @@ public:
T* tmp = m_ptr;
m_ptr = pref.m_ptr;
if (m_ptr)
m_ptr->incRef();
((Object *) m_ptr)->incRef();
if (tmp)
tmp->decRef();
((Object *) tmp)->decRef();
return *this;
}
@ -58,9 +66,9 @@ public:
T* tmp = m_ptr;
m_ptr = ptr;
if (m_ptr)
m_ptr->incRef();
((Object *) m_ptr)->incRef();
if (tmp)
tmp->decRef();
((Object *) tmp)->decRef();
return *this;
}

View File

@ -19,7 +19,8 @@
#if !defined(__SCHED_H)
#define __SCHED_H
#include <mitsuba/core/mstream.h>
#include <mitsuba/core/serialization.h>
#include <mitsuba/core/lock.h>
#include <set>
#include <deque>
@ -31,7 +32,7 @@
MTS_NAMESPACE_BEGIN
/**
* Abstract work unit. Represents a small amount of information
* \brief Abstract work unit -- represents a small amount of information
* that encodes part of a larger processing task.
*/
class MTS_EXPORT_CORE WorkUnit : public Object {
@ -55,8 +56,8 @@ protected:
};
/**
* Abstract work result. Represents the information that encodes
* the result of a processed <tt>WorkUnit</tt> instance.
* \brief Abstract work result -- represents the result of a
* processed <tt>\ref WorkUnit</tt> instance.
*/
class MTS_EXPORT_CORE WorkResult : public Object {
public:
@ -76,30 +77,28 @@ protected:
};
/**
* Abstract work processor. Takes work units and turns them into
* <tt>WorkResult</tt> instances. The class is serializable so that
* it can be sent over the network if required. It is possible to
* keep local state in <tt>WorkProcessor</tt> instances (e.g. scratch
* space for computations), though anything not returned in the form
* of <tt>WorkResult</tt>s will eventually be lost. Each worker
* (both locally and remotely) has its own <tt>WorkProcessor</tt>,
* and therefore no form of locking is required.
* \brief Abstract work processor -- takes work units and turns them into
* <tt>WorkResult</tt> instances.
*
* The class is serializable so that it can be sent over the network if
* required. It is possible to keep local state in <tt>WorkProcessor</tt>
* instances (e.g. scratch space for computations), though anything not
* returned in the form of <tt>WorkResult</tt>s will eventually be lost.
* Each worker (both locally and remotely) has its own <tt>WorkProcessor</tt>,
* and therefore no form of locking is required within instances of this class.
*/
class MTS_EXPORT_CORE WorkProcessor : public SerializableObject {
friend class Scheduler;
public:
/**
* Create a work unit of the proper type and size.
*/
/// Create a work unit of the proper type and size.
virtual ref<WorkUnit> createWorkUnit() const = 0;
/**
* Create a work result of the proper type and size
*/
/// Create a work result of the proper type and size
virtual ref<WorkResult> createWorkResult() const = 0;
/**
* Create a copy of this work processor instance.
* \brief Create a copy of this work processor instance.
*
* Note: Before the cloned work processor is used, its
* prepare() method will be called - therefore, state
* that is initialized there does not have to be copied.
@ -107,22 +106,23 @@ public:
virtual ref<WorkProcessor> clone() const = 0;
/**
* Called once before processing starts. This is useful for allocating
* scratch space or resolving references to resource objects. Lengthy
* computations should be performed in process() instead of here, since
* this this method will be called while the central scheduler lock
* is held. A thrown exception will lead to the termination of the parallel
* process.
* \brief Called once before processing starts.
*
* This is useful for allocating scratch space or resolving references
* to resource objects. Lengthy computations should be performed in
* process() instead of here, since this this method will be called
* while the central scheduler lock is held. A thrown exception will
* lead to the termination of the parallel process.
*/
virtual void prepare() = 0;
/**
* Process a work unit and store the computed results. The <tt>active</tt>
* parameter can be used to signal a premature stop of the execution flow.
* In this case, the work result is allowed to be undefined (it will
* simply be ignored).
* A thrown exception will lead to the termination of the parallel
* process.
* \brief Process a work unit and store the computed results.
*
* The <tt>active</tt> parameter can be used to signal a premature
* stop of the execution flow. In this case, the work result is allowed
* to be undefined (it will simply be ignored). A thrown exception will
* lead to the termination of the parallel process.
*/
virtual void process(const WorkUnit *workUnit, WorkResult *workResult,
const bool &stop) = 0;
@ -137,9 +137,10 @@ protected:
: SerializableObject(stream, manager) { }
/**
* Look up a named resource, which has been bound to the associated
* parallel process. Throws an exception if the resource is not
* known / bound.
* \brief Look up a named resource, which has been bound to
* the associated parallel process.
*
* Throws an exception if the resource is not known / bound.
*/
SerializableObject *getResource(const std::string &name);
protected:
@ -147,114 +148,143 @@ protected:
};
/**
* Abstract parallelizable task. Models a larger piece of work that
* can be split into independent `units' and subsequently farmed
* out over a cluster or processed locally. After the work units have
* been completed, the results are pieced back together to a solution of
* the original large-scale problem. This class implements the core logic
* running on the central scheduling server, i.e. the part that is
* responsible for generating work units and accepting their results.
* The module that performs the actual computation is an instance of
* <tt>WorkProcessor</tt>, which is also specified here.
* \brief Abstract parallelizable task.
*
* Models a larger piece of work that can be split into independent
* `units' and subsequently farmed out over a cluster or processed locally.
* After the work units have been completed, the results are pieced back
* together to a solution of the original large-scale problem. This class
* implements the core logic running on the central scheduling server,
* i.e. the part that is responsible for generating work units and
* accepting their results. The module that performs the actual computation
* is an instance of <tt>WorkProcessor</tt>, which is also specified here.
* Finally, the this class references `resources', which denote
* chunks of globally shared read-only data required during execution.
*/
class MTS_EXPORT_CORE ParallelProcess : public Object {
friend class Scheduler;
public:
/// Binding from local resource names to global resource IDs
typedef std::map<std::string, int> ResourceBindings;
/// Return codes used by generateWork() and getReturnStatus()
enum EStatus {
EUnknown,
EPause,
ESuccess,
EFailure
EUnknown, ///< Unknown return status
EPause, ///< Temporarily, no work units can be created
ESuccess, ///< The process finished / a piece of work was generated
EFailure ///< The process failed / no more work is available
};
/**
* Generate a piece of work. Takes a pre-allocated <tt>WorkUnit</tt>
* instance of the appropriate sub-type and size (as specified by
* <tt>ParallelProcess::getWorkUnitName</tt>) and fills it with the
* appropriate content. Returns ESuccess on success and EFailure or EPause
* when no more work is left -- in that case, the work unit will
* be ignored and the process completed (EFailure) or temporarily
* paused (EPause). When EPause was used, resubmission via
* <tt>Scheduler::schedule()</tt> will be required once more work
* is available. In some cases, it is useful to distribute 'nearby'
* pieces of work to the same processor -- the <tt>worker</tt>
* parameter can be used to implement this.
* This function should run as quickly as possible, since it will
* be executed while the scheduler mutex is held. A thrown exception
* will lead to the termination of the parallel process.
* \brief Generate a piece of work.
*
* Takes a pre-allocated <tt>\ref WorkUnit</tt> instance of
* the appropriate sub-type and size (as specified by
* <tt>\ref ParallelProcess::getWorkUnitName()</tt>) and
* fills it with the appropriate content. Returns ESuccess
* on success and EFailure or EPause when no more work is
* left -- in that case, the work unit will be ignored and
* the process completed (\ref EFailure) or temporarily
* paused (\ref EPause). When \ref EPause was used,
* resubmission via <tt>\ref Scheduler::schedule()</tt> will
* be required once more work is available. In some cases, it
* is useful to distribute 'nearby' pieces of work to the same
* processor -- the <tt>worker</tt> parameter can be used to
* implement this.
* This function should run as quickly as possible, since it
* will be executed while the scheduler mutex is held. A
* thrown exception will lead to the termination of the
* parallel process.
*
* \param unit Work unit data structure to be filled
* \param worker ID of the worker executing this function
*/
virtual EStatus generateWork(WorkUnit *unit, int worker) = 0;
/**
* Called whenever a work unit has been completed. Note
* that this may be executed by different threads and
* likely out of order (some sort of locking will
* generally be required when modifying data structures).
* \brief Called whenever a work unit has been completed.
*
* Note that this function may concurrently be executed by
* multiple threads. Also, processing of work results will
* generally be out of order with respect to the creation
* in \ref generateWork().
*
* When a work unit is only partially completed due to
* a call to <tt>Scheduler::cancel</tt>, the second
* parameter is set to true.
* A thrown exception will lead to the termination of
* the parallel process.
*
* \param result Work result to be processed
* \param cancelled Was the associated work unit not fully completed
*/
virtual void processResult(const WorkResult *result,
bool cancelled) = 0;
/**
* Called when the parallel process is canceled
* by Scheduler::cancel(). The default implementation
* does nothing.
* \brief Called when the parallel process is canceled by
* \ref Scheduler::cancel().
*
* The default implementation does nothing.
*/
virtual void handleCancellation();
/**
* After a process has finished excecution, its return
* status can be queried through this method.
* Returns one of <tt>Success, Failure or Unknown</tt>
* (EUnknown means that the process is either still running
* \brief Query the return status of a process after its
* execution has finished.
*
* Returns one of <tt>\ref Success, \ref Failure or \ref Unknown</tt>
* (\ref EUnknown means that the process is either still running
* or has never been scheduled).
*/
inline EStatus getReturnStatus() const { return m_returnStatus; }
/**
* Create an instance of the algorithm responsible
* \brief Create an instance of the algorithm responsible
* for executing the work units of this parallel process.
*/
virtual ref<WorkProcessor> createWorkProcessor() const = 0;
/**
* Bind a resource to this parallel process. Takes a resource
* ID as given by the scheduler and associates it with a name.
* This name can later be used by the work processor to access
* the resource data.
* \brief Bind a resource to this parallel process.
*
* Takes a resource ID as given by the scheduler and associates it
* with a name. This name can later be used by the work processor
* to access the resource data.
*
* \param name Process-specific name of the resource
* \param id Resource ID as returned by \ref Scheduler::registerResource()
* \sa WorkProcessor::getResource
*/
virtual void bindResource(const std::string &name, int id);
/**
* Is this process local, i.e. not distributed to remote
* processing nodes? The default implementation returs false.
* \brief Is this process strictly local?
*
* If a process is marked as local, it shouldn't be distributed
* to remote processing nodes? The default implementation
* returns false.
*/
virtual bool isLocal() const;
/**
* Return the log level for events associated with this process.
* \brief Return the log level for events associated with this process.
*
* By default, this is set to EDebug
*/
inline ELogLevel getLogLevel() const { return m_logLevel; }
/**
* Return a list of the bound resources
* \brief Return a list of all bound resources
*/
inline const ResourceBindings &getResourceBindings() const { return m_bindings; }
/**
* Return a list of plugins required by this parallel process.
* The default implementation just returns all plugins that are
* loaded in the current application image.
* \brief Return a list of plugins required by this parallel process.
*
* This is required so that remote machines can load the plugins before
* they accept work from this process. The default implementation just
* returns all plugins that are loaded in the current application.
*/
virtual std::vector<std::string> getRequiredPlugins();
@ -274,35 +304,40 @@ protected:
class Worker;
/**
* Centralized task scheduler implementation. Accepts parallelizable
* jobs and distributes their computational load both locally and remotely.
* This is done by associating different types of <tt>Worker</tt>s with
* the scheduler. These try to acquire work units from the scheduler,
* which are then executed on the current machine or sent to remote
* nodes over a network connection.
* \brief Centralized task scheduler implementation.
*
* Accepts parallelizable jobs and distributes their computational load
* both locally and remotely. This is done by associating different types
* of <tt>\ref Worker</tt>s with the scheduler. These try to acquire work
* units from the scheduler, which are then executed on the current machine
* or sent to remote nodes over a network connection.
*/
class MTS_EXPORT_CORE Scheduler : public Object {
friend class Worker;
public:
/**
* Schedule a parallelizable process for execution. If the
* scheduler is currently running and idle, its execution
* will begin immediately. Returns false if the process
* is already scheduled and has not yet terminated.
* \brief Schedule a parallelizable process for execution.
*
* If the scheduler is currently running and idle, its execution
* will begin immediately. Returns \a false if the process
* is already scheduled and has not yet terminated and \a true
* in any other case.
*/
bool schedule(ParallelProcess *process);
/**
* Block until the process has successfully been completed
* or canceled prematurely. Returns false if the process
* does not exist or has already finished by the time
* <tt>wait()</tt> is invoked.
* \brief Block until the process has successfully been completed
* or canceled prematurely.
*
* Returns false if the process does not exist or has already
* finished by the time <tt>\ref wait()</tt> is invoked.
*/
bool wait(const ParallelProcess *process);
/**
* Cancel the execution of a parallelizable process. Upon
* return, no more work from this process is running.
* \brief Cancel the execution of a parallelizable process.
*
* Upon return, no more work from this process is running.
* Returns false if the process does not exist (anymore).
*/
inline bool cancel(ParallelProcess *proc) {
@ -310,41 +345,49 @@ public:
}
/**
* Register a serializable resource with the scheduler. This should be
* thought of as a constant state that is shared amongst all processing
* nodes. Resources can be reused by subsequent parallel processes, and
* consequently do not have to be re-transmitted over the network. Returns
* a resource ID, which can be used to reference the associated data.
* \brief Register a serializable resource with the scheduler.
*
* A resource should be thought of as a constant state that is shared
* amongst all processing nodes. Resources can be reused by
* subsequent parallel processes, and consequently do not have to be
* re-transmitted over the network. Returns a resource ID, which can be
* used to reference the associated data.
*/
int registerResource(SerializableObject *resource);
/**
* Register a 'manifold' resource with the scheduler. Manifold means that
* in comparison to the previous method, a separate instance is provided
* for every core. An example where this is useful is to distribute
* random generator state when performing parallel Monte Carlo simulations.
* <tt>resources</tt> must be a vector whose length is equal
* to <tt>getCoreCount()</tt>.
* \brief Register a \a manifold resource with the scheduler.
*
* \a Manifold means that in comparison to the previous method, a separate
* instance is provided for every core. An example where this is useful
* is to distribute random generator state when performing parallel
* Monte Carlo simulations. <tt>resources</tt> must be a vector whose
* length is equal to <tt>\ref getCoreCount()</tt>.
*/
int registerManifoldResource(std::vector<SerializableObject *> &resources);
/**
* Increase the reference count of a previously registered resource.
* \brief Increase the reference count of a previously registered resource.
*
* The resource must be unregistered an additional time after calling
* this function.
*
* \sa unregisterResource
*/
void retainResource(int resourceID);
/**
* Unregister a resource from the scheduler (takes the previously
* created ID). Note that the resource's won't be removed
* until all processes using it have terminated)
* \brief Unregister a resource from the scheduler
*
* Note that the resource's won't be removed until all processes using
* it have terminated)
*/
void unregisterResource(int id);
/**
* Return the ID of a registered resource. Throws an exception
* if the resource cannot be found.
* \brief Return the ID of a registered resource
*
* Throws an exception if the resource cannot be found.
*/
int getResourceID(const SerializableObject *resource) const;
@ -364,15 +407,15 @@ public:
void start();
/**
* Puase the distribution of work units and shut down all running workers.
* Any currently scheduled work units are still completed. Processing can
* be resumed via <tt>start()</tt>.
* \brief Pause the distribution of work units and shut down all
* running workers.
*
* Any currently scheduled work units are still completed.
* Processing can be resumed via <tt>\ref start()</tt>.
*/
void pause();
/**
* Cancel all running processes and free memory used by resources
*/
/// Cancel all running processes and free memory used by resources
void stop();
/// Return the total number of cores exposed through this scheduler
@ -401,6 +444,8 @@ public:
MTS_DECLARE_CLASS()
public:
// Public, but shouldn't be part of the documentation
/// \cond
struct ProcessRecord {
/* Unique ID value assigned to this process */
int id;
@ -476,6 +521,8 @@ public:
/// The scheduler is shutting down
EStop
};
/// \endcond
/// Look up a resource by ID & core index
SerializableObject *getResource(int id, int coreIndex = -1);
@ -483,13 +530,14 @@ public:
const MemoryStream *getResourceStream(int id);
/**
* Test whether a resource is marked as manifold,
* i.e. different for every core
* \brief Test whether a resource is marked as manifold,
* i.e. different for every core.
*/
bool isManifoldResource(int id) const;
protected:
/// Protected constructor
Scheduler();
/// Virtual destructor
virtual ~Scheduler();
@ -519,7 +567,7 @@ protected:
signalProcessTermination(item.proc, item.rec);
m_mutex->unlock();
}
/**
* Cancel the execution of a parallelizable process. Upon
* return, no more work from this process is running. When
@ -583,7 +631,7 @@ private:
};
/**
* Base class of all worker implementations
* \brief Base class of all worker implementations
*/
class MTS_EXPORT_CORE Worker : public Thread {
friend class Scheduler;
@ -609,20 +657,22 @@ protected:
int workerIndex, int coreOffset);
/**
* Called to inform a worker that a resource is no longer in use. The
* remote worker uses this to notify the machine on the other end that
* \brief Called to inform a worker that a resource is no longer in use.
*
* The remote worker uses this to notify the machine on the other end that
* the memory used by this resource can now be released.
*/
virtual void signalResourceExpiration(int id) = 0;
/**
* Called to inform a worker that a process has been cancelled
* \brief Called to inform a worker that a process has been cancelled
*
* Guaranteed to be called while the Scheduler's main lock is held.
*/
virtual void signalProcessCancellation(int id) = 0;
/**
* Called to inform a worker that a process has successfully been
* \brief Called to inform a worker that a process has successfully been
* completed and any associated resources can be freed.
*/
virtual void signalProcessTermination(int id) = 0;
@ -663,7 +713,7 @@ protected:
};
/**
* Local worker thread. Acquires work from the scheduler and executes
* \brief Acquires work from the scheduler and executes
* it locally.
*/
class MTS_EXPORT_CORE LocalWorker : public Worker {

View File

@ -21,11 +21,11 @@
#include <mitsuba/core/sched.h>
/* How many work units should be sent to a remote worker
/** How many work units should be sent to a remote worker
at a time? This is a multiple of the worker's core count */
#define BACKLOG_FACTOR 3
/* Once the back log factor drops below this value (also a
/** Once the back log factor drops below this value (also a
multiple of the core size), the stream processor will
continue sending batches of work units */
#define CONTINUE_FACTOR 2
@ -34,16 +34,18 @@ MTS_NAMESPACE_BEGIN
class RemoteWorkerReader;
class StreamBackend;
class FileResolver;
/**
* Remote worker thread. Acquires work from the scheduler and forwards
* it to a processing node reachable over some form of stream (usually
* a <tt>SocketStream</tt>).
* \brief Acquires work from the scheduler and forwards
* it to a processing node reachable through a \ref Stream.
*/
class MTS_EXPORT_CORE RemoteWorker : public Worker {
friend class RemoteWorkerReader;
public:
/**
* \brief Construct a new remote worker with the given name and
* communication stream
*/
RemoteWorker(const std::string &name, Stream *stream);
/// Return the name of the node on the other side
@ -85,8 +87,9 @@ protected:
};
/**
* Remote worker helper thread - constantly waits for finished
* work units sent by the processing node.
* \brief Communication helper thread required by \ref RemoteWorker.
*
* Constantly waits for finished work units sent by the processing node.
*/
class MTS_EXPORT_CORE RemoteWorkerReader : public Thread {
friend class RemoteWorker;
@ -111,11 +114,19 @@ private:
};
/**
* 'Fake' parallel process used to insert work units from a
* \brief Parallel process facade used to insert work units from a
* remote scheduler into the local one.
*/
class MTS_EXPORT_CORE RemoteProcess : public ParallelProcess {
public:
/**
* \brief Create a new remote process
*
* \param id Identification number for this process
* \param logLevel Log level for events associated with this process
* \param backend The responsible server-side communication backend
* \param proc Work processor instance for use with this process
*/
RemoteProcess(int id, ELogLevel logLevel,
StreamBackend *backend, WorkProcessor *proc);
@ -126,6 +137,7 @@ public:
ref<WorkProcessor> createWorkProcessor() const;
void handleCancellation();
/// Get an empty work unit from the process (or create one)
inline WorkUnit *getEmptyWorkUnit() {
ref<WorkUnit> wu;
m_mutex->lock();
@ -140,12 +152,14 @@ public:
return wu;
}
/// Make a full work unit available to the process
inline void putFullWorkUnit(WorkUnit *wu) {
m_mutex->lock();
m_full.push_back(wu);
m_mutex->unlock();
}
/// Mark the process as finished
inline void setDone() {
m_mutex->lock();
m_done = true;
@ -167,9 +181,10 @@ private:
};
/**
* Stream backend - attaches to the end of a stream, accepts work units
* and forwards them to the local scheduler. Can be used to create
* remote processing nodes.
* \brief Network processing communication backend
*
* Attaches to the end of a stream, accepts work units and forwards
* them to the local scheduler. Can be used to create network processing nodes.
*/
class MTS_EXPORT_CORE StreamBackend : public Thread {
friend class RemoteProcess;
@ -193,7 +208,7 @@ public:
};
/**
* Create a new stream backend
* \brief Create a new stream backend
*
* @param name
* Name of the created thread
@ -224,7 +239,6 @@ private:
std::map<int, RemoteProcess *> m_processes;
std::map<int, int> m_resources;
ref<Mutex> m_sendMutex;
ref<FileResolver> m_resolver;
bool m_detach;
};

View File

@ -23,7 +23,7 @@
MTS_NAMESPACE_BEGIN
/** \brief Serializable interface
/** \brief Abstract interface implemented by all serializable classes
*/
class MTS_EXPORT_CORE Serializable {
public:
@ -34,43 +34,49 @@ protected:
virtual ~Serializable() { }
};
/** \brief Base class of all reference-counted objects with serialization support.
/** \brief Base class of all reference-counted objects with serialization support
*
* To support unserialization from a stream, the implementation should use one of the
* RTTI macros "MTS_IMPLEMENT_CLASS_*S".
* RTTI macros \ref MTS_IMPLEMENT_CLASS_S or \ref MTS_IMPLEMENT_CLASS_IS.
*/
class MTS_EXPORT_CORE SerializableObject : public Object, public Serializable {
public:
inline SerializableObject() { }
/// Unserialize a serializable object
SerializableObject(Stream *stream, InstanceManager *manager);
MTS_DECLARE_CLASS()
protected:
/// Construct a serializable object
inline SerializableObject() { }
/// Virtual deconstructor
virtual ~SerializableObject() { }
};
/** \brief The instance manager coordinates the serialization/
* unserialization process when link structures are encountered
* in which an object is referenced by multiple other objects
* within the same data stream. Cyclic dependencies can also
* be handled.
/** \brief Coordinates the serialization and unserialization of object graphs
*
* When serializaing a complicated object graph to a binary data stream,
* the instance manager annotates the data stream to avoid serializing
* objects twice or becoming stuck in a cyclic dependency. This allows
* arbitrary connected graphs to be serialized.
*
* Similarly when unserializing a stream, it ensures that the resulting
* object graph has the same structure.
*/
class MTS_EXPORT_CORE InstanceManager : public Object {
friend class SerializableObject;
public:
/** \brief Construct a new instance manager */
/// \brief Construct a new instance manager
InstanceManager();
/// Retrieve/load an instance by ID
/// Retrieve an instance from the given stream
SerializableObject *getInstance(Stream *stream);
/// Store/skip an instance returning its ID
/// Store an instance to the given stream
void serialize(Stream *stream, const SerializableObject *inst);
MTS_DECLARE_CLASS()
protected:
private:
/// Virtual destructor
virtual ~InstanceManager();

View File

@ -32,10 +32,13 @@ namespace ublas = boost::numeric::ublas;
struct SHVector;
/* Stores the diagonal blocks of a spherical harmonic rotation matrix */
/**
* \brief Stores the diagonal blocks of a spherical harmonic rotation matrix
*/
struct MTS_EXPORT_CORE SHRotation {
std::vector<ublas::matrix<Float> > blocks;
/// Construct a new rotation storage for the given number of bands
inline SHRotation(int bands) : blocks(bands) {
for (int i=0; i<bands; ++i) {
int dim = 2*i+1;
@ -44,26 +47,31 @@ struct MTS_EXPORT_CORE SHRotation {
}
/**
* Transform a coefficient vector and store the result into
* the given target vector. The source and target must have
* the same number of bands.
* \brief Transform a coefficient vector and store the result into
* the given target vector.
*
* The source and target must have the same number of bands.
*/
void operator()(const SHVector &source, SHVector &target) const;
};
/**
* Stores a truncated real spherical harmonics representation of
* an L2-integrable function. Also provides some other useful
* functionality, such as evaluation, projection and rotation.
* \brief Stores a truncated real spherical harmonics representation of
* an L2-integrable function.
*
* Also provides some other useful functionality, such as evaluation,
* projection and rotation.
*
* The Mathematica equivalent of the basis functions implemented here is:
*
* <pre>
* SphericalHarmonicQ[l_, m_, \[Theta]_, \[Phi]_] :=
* Piecewise[{
* {SphericalHarmonicY[l, m, \[Theta], \[Phi]], m == 0},
* {Sqrt[2]*Re[SphericalHarmonicY[l, m, \[Theta], \[Phi]]], m > 0},
* {Sqrt[2]*Im[SphericalHarmonicY[l, -m, \[Theta], \[Phi]]], m < 0}
* }]
* </pre>
*/
struct MTS_EXPORT_CORE SHVector {
public:
@ -169,18 +177,20 @@ public:
/// Evaluate for a direction given in spherical coordinates
Float eval(Float theta, Float phi) const;
/// Evaluate for a direction given in cartesian coordinates
/// Evaluate for a direction given in Cartesian coordinates
Float eval(const Vector &v) const;
/**
* Evaluate for a direction given in spherical coordinates.
* \brief Evaluate for a direction given in spherical coordinates.
*
* This function is much faster but only works for azimuthally
* invariant functions
*/
Float evalAzimuthallyInvariant(Float theta, Float phi) const;
/**
* Evaluate for a direction given in cartesian coordinates.
* \brief Evaluate for a direction given in cartesian coordinates.
*
* This function is much faster but only works for azimuthally
* invariant functions
*/
@ -214,8 +224,10 @@ public:
void offset(Float value);
/**
* Convolve the SH representation with the supplied kernel,
* which must be rotationally symmetric around the Z-axis.
* \brief Convolve the SH representation with the supplied kernel.
*
* Based on the Funk-Hecke theorem -- the kernel must be rotationally
* symmetric around the Z-axis.
*/
void convolve(const SHVector &kernel);
@ -303,7 +315,7 @@ public:
return error/denom;
}
/* Evaluate an associated Legendre polynomial using the usual recurrence formulae */
/// Evaluate an associated Legendre polynomial using the usual recurrence formulae
static Float legendre(int l, int m, Float x);
/// Return a normalization coefficient
@ -315,8 +327,9 @@ public:
}
/**
* Recursively computes rotation matrices for each band of SH coefficients. Based on
* 'Rotation Matrices for Real Spherical Harmonics. Direct Determination by Recursion'
* \brief Recursively computes rotation matrices for each band of SH coefficients.
*
* Based on 'Rotation Matrices for Real Spherical Harmonics. Direct Determination by Recursion'
* by Ivanic and Ruedenberg. The implemented tables follow the notation in
* 'Spherical Harmonic Lighting: The Gritty Details' by Robin Green.
*/
@ -340,22 +353,23 @@ private:
};
/**
* Implementation of 'Importance Sampling Spherical Harmonics'
* \brief Implementation of 'Importance Sampling Spherical Harmonics'
* by W. Jarsz, N. Carr and H. W. Jensen (EUROGRAPHICS 2009)
*/
class MTS_EXPORT_CORE SHSampler : public Object {
public:
/**
* Create a spherical harmonics sampler object for the
* specified amount of SH coefficient bands. The 'depth'
* parameter specifies the number of recursive sample
* warping steps.
* \brief Precompute a spherical harmonics sampler object
*
* \param bands Number of SH coefficient bands to support
* \param depth Number of recursive sample warping steps.
*/
SHSampler(int bands, int depth);
/**
* Warp a uniform sample in [0,1]^2 to one that is
* \brief Warp a uniform sample in [0,1]^2 to one that is
* approximately proportional to the specified function.
*
* The resulting sample will have spherical coordinates
* [0,pi]x[0,2pi] and its actual PDF (which might be
* slightly different from the function evaluated at the
@ -370,7 +384,7 @@ public:
protected:
/// Virtual destructor
virtual ~SHSampler();
/* Index into the assoc. legendre polynomial table */
inline int I(int l, int m) const { return l*(l+1)/2 + m; }
@ -381,11 +395,11 @@ protected:
return -m_phiMap[depth][phiBlock][P(m)] * m_legendreMap[depth][zBlock][I(l, std::abs(m))];
}
/* Recursively compute assoc. legendre & phi integrals */
/// Recursively compute assoc. legendre & phi integrals
Float *legendreIntegrals(Float a, Float b);
Float *phiIntegrals(Float a, Float b);
/* Integrate a SH expansion over the specified mip-map region */
/// Integrate a SH expansion over the specified mip-map region
Float integrate(int depth, int zBlock, int phiBlock, const SHVector &f) const;
protected:
int m_bands;

View File

@ -24,10 +24,11 @@
MTS_NAMESPACE_BEGIN
/**
* Stores a 4D function f(wi, wo) (such as a BRDF or phase function)
* using a 2D table of spherical harmonics expansions. Discretizaiton
* occurs in the 'wi' space. Later lookups interpolate amongst
* the 4 adjacent samples
* \brief Stores a 4D function f(wi, wo) (such as a BRDF or phase function)
* using a 2D table of spherical harmonics expansions.
*
* Discretizaiton occurs in the 'wi' space. Lookups interpolate amongst
* the 4 adjacent samples.
*/
struct SHVector4D {
public:

View File

@ -30,49 +30,53 @@ MTS_NAMESPACE_BEGIN
/**
* \brief Abstract smooth spectral power distribution data type,
* which supports sampling at arbitrary wavelengths
* which supports evaluation at arbitrary wavelengths
*/
class MTS_EXPORT_CORE SmoothSpectrum {
public:
/**
* Return the value of the spectral power distribution
* for the given wavelength.
* Evaluate the value of the spectral power distribution
* at the given wavelength.
*/
virtual Float sample(Float lambda) const = 0;
virtual Float eval(Float lambda) const = 0;
virtual ~SmoothSpectrum() { }
};
/**
* This class uses Plank's black body law to compute the
* spectral power distribution of a black body with the
* given temperature.
* \brief Spectral power distribution based on Planck's black body law
*
* Computes the spectral power distribution of a black body of the
* specified temperature.
*/
class MTS_EXPORT_CORE BlackBodySpectrum : public SmoothSpectrum {
public:
/**
* Construct a new black body spectrum given the emitter's
* temperature in kelvin.
* \brief Construct a new black body spectrum given the emitter's
* temperature in Kelvin.
*/
inline BlackBodySpectrum(Float temperature) {
m_temperature = temperature;
}
/**
* Return the value of the spectral power distribution
* for the given wavelength.
virtual ~BlackBodySpectrum() { }
/** \brief Return the value of the spectral power distribution
* at the given wavelength.
*/
virtual Float sample(Float lambda) const;
virtual Float eval(Float lambda) const;
private:
Float m_temperature;
};
/**
* Linearly interpolated spectral power distribution
* \brief Linearly interpolated spectral power distribution
*/
class MTS_EXPORT_CORE InterpolatedSpectrum : public SmoothSpectrum {
public:
/**
* Construct a new black body spectrum given the emitter's
* temperature in kelvin.
* \brief Create a new interpolated spectrum with space
* for the specified number of samples
*/
inline InterpolatedSpectrum(size_t size = 0) {
m_wavelength.reserve(size);
@ -80,49 +84,56 @@ public:
}
/**
* Append an entry to the spectral power distribution. Entries
* must be added in order of increasing wavelength
* \brief Append an entry to the spectral power distribution.
*
* Entries must be added in order of increasing wavelength
*/
void appendSample(Float lambda, Float value);
/**
* Return the value of the spectral power distribution
* for the given wavelength.
* \brief Return the value of the spectral power distribution
* at the given wavelength.
*/
virtual Float sample(Float lambda) const;
virtual Float eval(Float lambda) const;
virtual ~InterpolatedSpectrum() { }
private:
std::vector<Float> m_wavelength, m_value;
};
/** \brief Spectral power distribution data type
* using a fixed number of wavelength samples. When
* SPECTRUM_SAMPLES is set to 3, the class falls back
* to linear RGB.
/** \brief Discrete spectral power distribution
* based on a (usually small) number of wavelength samples.
*
* When SPECTRUM_SAMPLES is set to 3 (the default), this class
* falls back to linear RGB as its internal representation.
*/
class MTS_EXPORT_CORE Spectrum {
struct MTS_EXPORT_CORE Spectrum {
public:
/// Set all samples to the given value
inline Spectrum(Float v = 0.0f) {
/// Create a new spectral power distribution, but don't initialize the contents
#if !defined(MTS_DEBUG_UNINITIALIZED)
inline Spectrum() { }
#else
inline Spectrum() {
for (int i=0; i<SPECTRUM_SAMPLES; i++)
s[i] = std::numeric_limits<double>::quiet_NaN();
}
#endif
/// Create a new spectral power distribution with all samples set to the given value
explicit inline Spectrum(Float v) {
for (int i=0; i<SPECTRUM_SAMPLES; i++)
s[i] = v;
}
/// Initialize with spectral values from a smooth spectrum
Spectrum(const SmoothSpectrum *smooth);
/// Convert from RGBE
inline Spectrum(const uint8_t rgbe[4]) {
fromRGBE(rgbe);
}
/// Copy a spectrum
inline Spectrum(Float spd[SPECTRUM_SAMPLES]) {
/// Copy a spectral power distribution
explicit inline Spectrum(Float spd[SPECTRUM_SAMPLES]) {
for (int i=0; i<SPECTRUM_SAMPLES; i++)
s[i] = spd[i];
}
/// Unserialize a spectrum
inline Spectrum(Stream *stream) {
/// Unserialize a spectral power distribution from a binary data stream
explicit inline Spectrum(Stream *stream) {
stream->readFloatArray(s, SPECTRUM_SAMPLES);
}
@ -134,7 +145,7 @@ public:
return value;
}
/// Add two spectral power distributions
/// Add a spectral power distribution to this instance
inline Spectrum& operator+=(const Spectrum &spd) {
for (int i=0; i<SPECTRUM_SAMPLES; i++)
s[i] += spd.s[i];
@ -149,14 +160,14 @@ public:
return value;
}
/// Subtract a spectral power distribution
/// Subtract a spectral power distribution from this instance
inline Spectrum& operator-=(const Spectrum &spd) {
for (int i=0; i<SPECTRUM_SAMPLES; i++)
s[i] -= spd.s[i];
return *this;
}
/// Multiplication with a scalar
/// Multiply by a scalar
inline Spectrum operator*(Float f) const {
Spectrum value = *this;
for (int i=0; i<SPECTRUM_SAMPLES; i++)
@ -164,19 +175,19 @@ public:
return value;
}
/// Multiplication with a scalar
/// Multiply by a scalar
inline friend Spectrum operator*(Float f, Spectrum &spd) {
return spd * f;
}
/// Multiplication with a scalar
/// Multiply by a scalar
inline Spectrum& operator*=(Float f) {
for (int i=0; i<SPECTRUM_SAMPLES; i++)
s[i] *= f;
return *this;
}
/// Multiplication with another spectrum
/// Perform a component-wise multiplication by another spectrum
inline Spectrum operator*(const Spectrum &spd) const {
Spectrum value = *this;
for (int i=0; i<SPECTRUM_SAMPLES; i++)
@ -184,21 +195,29 @@ public:
return value;
}
/// Multiplication with another spectrum
/// Perform a component-wise multiplication by another spectrum
inline Spectrum& operator*=(const Spectrum &spd) {
for (int i=0; i<SPECTRUM_SAMPLES; i++)
s[i] *= spd.s[i];
return *this;
}
/// Component-wise division by another spectrum
/// Perform a component-wise division by another spectrum
inline Spectrum& operator/=(const Spectrum &spd) {
for (int i=0; i<SPECTRUM_SAMPLES; i++)
s[i] /= spd.s[i];
return *this;
}
/// Perform a component-wise division by another spectrum
inline Spectrum operator/(Spectrum spd) const {
Spectrum value = *this;
for (int i=0; i<SPECTRUM_SAMPLES; i++)
value.s[i] /= spd.s[i];
return value;
}
/// Division by a scalar
/// Divide by a scalar
inline Spectrum operator/(Float f) const {
Spectrum value = *this;
#ifdef MTS_DEBUG
@ -213,15 +232,7 @@ public:
return value;
}
/// Component-wise division by another spectrum
inline Spectrum operator/(Spectrum spd) const {
Spectrum value = *this;
for (int i=0; i<SPECTRUM_SAMPLES; i++)
value.s[i] /= spd.s[i];
return value;
}
/// Component-wise comparison against another spectrum
/// Equality test
inline bool operator==(Spectrum spd) const {
for (int i=0; i<SPECTRUM_SAMPLES; i++) {
if (s[i] != spd.s[i])
@ -230,17 +241,17 @@ public:
return true;
}
/// Component-wise comparison against another spectrum
/// Inequality test
inline bool operator!=(Spectrum spd) const {
return !operator==(spd);
}
/// Division by a scalar
/// Divide by a scalar
inline friend Spectrum operator/(Float f, Spectrum &spd) {
return spd / f;
}
/// Division by a scalar
/// Divide by a scalar
inline Spectrum& operator/=(Float f) {
#ifdef MTS_DEBUG
if (f == 0) {
@ -262,7 +273,7 @@ public:
return false;
}
/// Returns whether the spectrum only contains valid non-negative samples
/// Returns whether the spectrum only contains valid (non-NaN, nonnegative) samples
inline bool isValid() const {
for (int i=0; i<SPECTRUM_SAMPLES; i++)
if (ubi_isnan(s[i]) || s[i] < 0.0f)
@ -270,7 +281,7 @@ public:
return true;
}
/// Multiply-accumulate operation
/// Multiply-accumulate operation, adds \a weight * \a spd
inline void addWeighted(Float weight, const Spectrum &spd) {
for (int i=0; i<SPECTRUM_SAMPLES; i++)
s[i] += weight * spd.s[i];
@ -352,10 +363,10 @@ public:
bool isBlack() const;
/**
* Sample the SPD at an arbitrary wavelength
* \brief Evaluate the SPD at an arbitrary wavelength
* (uses interpolation)
*/
Float sample(Float lambda) const;
Float eval(Float lambda) const;
/// Return the luminance in candelas.
#if SPECTRUM_SAMPLES == 3
@ -400,14 +411,15 @@ public:
/// Convert from sRGB
void fromSRGB(Float r, Float g, Float b);
/** Linear RGBE conversion based on Bruce Walter's and Greg Ward's code
-> http://www.graphics.cornell.edu/online/formats/rgbe/rgbe.c */
/// Linear RGBE conversion based on Bruce Walter's and Greg Ward's code
void fromRGBE(const uint8_t rgbe[4]);
/** Linear RGBE conversion based on Bruce Walter's and Greg Ward's code
-> http://www.graphics.cornell.edu/online/formats/rgbe/rgbe.c */
/// Linear RGBE conversion based on Bruce Walter's and Greg Ward's code
void toRGBE(uint8_t rgbe[4]) const;
/// Initialize with spectral values from a smooth spectrum representation
void fromSmoothSpectrum(const SmoothSpectrum *smooth);
/// Serialize this spectrum to a stream
inline void serialize(Stream *stream) const {
stream->writeFloatArray(s, SPECTRUM_SAMPLES);
@ -434,12 +446,16 @@ protected:
/// Configured wavelengths in nanometers
static Float m_wavelengths[SPECTRUM_SAMPLES];
/// Normalization factors for XYZ<->RGB conversion
/// Normalization factor for XYZ<->RGB conversion
static Float m_normalization;
/// Inverse of \ref m_normalization
static Float m_invNormalization;
/* CIE 1931 XYZ color matching functions from
http://www.cvrl.org/database/data/cmfs/ciexyz31_1.txt */
/**
* @{ \name CIE 1931 XYZ color matching functions.
* From http://www.cvrl.org/database/data/cmfs/ciexyz31_1.txt
*/
static const int CIE_start = 360;
static const int CIE_end = 830;
static const int CIE_count = CIE_end - CIE_start + 1;
@ -447,6 +463,7 @@ protected:
static const Float CIE_X[CIE_count];
static const Float CIE_Y[CIE_count];
static const Float CIE_Z[CIE_count];
/// @}
};
MTS_NAMESPACE_END

View File

@ -94,7 +94,10 @@
MTS_NAMESPACE_BEGIN
/* SSE 4-vector and handy aliases */
/**
* \headerfile mitsuba/core/sse.h mitsuba/mitsuba.h
* \brief SSE 4-vector and useful aliases
*/
union SSEVector {
__m128 ps;
__m128i pi;
@ -124,7 +127,10 @@ union SSEVector {
}
};
/** Some useful constant values for use with SSE */
/**
* \brief Some useful constant values for use with SSE
* \headerfile mitsuba/core/sse.h mitsuba/mitsuba.h
*/
class MTS_EXPORT_CORE SSEConstants {
public:
/// (0, 0, 0, 0)

View File

@ -24,12 +24,13 @@
MTS_NAMESPACE_BEGIN
/** \brief SSH stream implementation - remotely runs a program
* and exposes its stdin/stdout streams through an instance of
* <tt>Stream</tt>. To make this work, passwordless authentication
* must be enabled (for example by using public key authentication
* in addition to a running ssh-agent which stores the decrypted
* private key).
/** \brief Stream implementation based on an encrypted SSH tunnel
*
* This class remotely starts a program and exposes its stdin/stdout
* streams through an instance of <tt>\ref Stream</tt>. To make all
* of this work, passwordless authentication must be enabled (for
* example by using public key authentication in addition to a
* running ssh-agent, which stores the decrypted private key).
*
* On Windows, things are implemented a bit differently: Instead
* of OpenSSH, plink.exe (from PUTTY) is used and must be available
@ -46,6 +47,12 @@ public:
* the maximum amount of time that can be spent before failing to
* create the initial connection. This feature is unsupported
* (and ignored) on Windows.
*
* \param userName Username to use for the authentication
* \param hostName Destination host name
* \param cmdLine Command (with arguments) to be executed on the remote side
* \param port Destination port
* \param timeout Maximum time to use for the connection attempt (in seconds)
*/
SSHStream(const std::string &userName,
const std::string &hostName,
@ -87,7 +94,7 @@ protected:
* the socket if it is still open
*/
virtual ~SSHStream();
protected:
private:
std::string m_userName, m_hostName;
int m_port, m_timeout;
size_t m_received, m_sent;

View File

@ -30,25 +30,34 @@ MTS_NAMESPACE_BEGIN
/// Size of the console-based progress message
#define PROGRESS_MSG_SIZE 56
/// Specifies the number of internal counters associated with each statistics counter
/// Needed for SMP/ccNUMA systems where different processors might be
/// contending for a cache line containing a counter. The solution used here
/// tries to ensure that every processor has its own local counter.
/**
* Specifies the number of internal counters associated with each
* statistics counter. Needed for SMP/ccNUMA systems where different
* processors might be contending for a cache line containing a counter.
* The solution used here tries to ensure that every processor has
* its own local counter.
*/
#define NUM_COUNTERS 128 // Must be a power of 2
#define NUM_COUNTERS_MASK (NUM_COUNTERS-1)
/* Determines the multiples (e.g. 1000, 1024) and units */
/// Determines the multiples (e.g. 1000, 1024) and units
enum EStatsType {
ENumberValue,
EByteCount,
EPercentage
ENumberValue = 0, ///< Simple unitless number, e.g. # of rays
EByteCount, ///< Number of read/written/transferred bytes
EPercentage ///< Percentage with respect to a base counter
};
struct CacheLineCounter { // Counter in 128 bytes - avoid false sharing
/**
* \brief Counter data structure, which is suitable for ccNUMA/SMP machines
*
* This counter takes up at least one cache line
* to reduce false sharing.
*/
struct CacheLineCounter {
#if (defined(WIN32) && !defined(WIN64)) || (defined(__POWERPC__) && !defined(_LP64))
// WIN32 & Darwin (PPC/32) doesn't support atomic 64 bit increment operations
// -> restrict counters to 32bit
// -> restrict counters to 32bit :(
uint32_t value;
uint32_t unused2;
#else
@ -58,12 +67,27 @@ struct CacheLineCounter { // Counter in 128 bytes - avoid false sharing
};
/** \brief General-purpose statistics counter
*
* This class implements a simple counter, which can be used to track various
* quantities within Mitsuba. At various points during the execution, it is
* possible to then call \ref Statistics::printStats() to get a human-readable
* report of their values.
*/
class MTS_EXPORT_CORE StatsCounter {
public:
/// Create a new statistics counter and associate it with a category:name pair
/**
* \brief Create a new statistics counter
*
* \param category Category of the counter when shown in the statistics summary
* \param name Name of the counter when shown in the statistics summary
* \param type Characterization of the quantity that will be measured
* \param initial Initial value of the counter
* \param base Initial value of the base counter (only for <tt>type == EPercentage</tt>)
*/
StatsCounter(const std::string &category, const std::string &name,
EStatsType type = ENumberValue, uint64_t initial = 0L, uint64_t base = 0L);
/// Free all storage used by the counter
~StatsCounter();
/// Increment the counter value by one
@ -91,7 +115,7 @@ public:
}
#endif
/// Increment the counter amount by the specified amount
/// Increment the counter by the specified amount
#ifdef MTS_NO_STATISTICS
inline void operator+=(size_t amount) { }
#elif defined(WIN64)
@ -108,7 +132,7 @@ public:
}
#endif
/// Increment the base amount by the specified amount (only for use with EPercentage)
/// Increment the base counter by the specified amount (only for use with EPercentage)
#ifdef MTS_NO_STATISTICS
inline void incrementBase(size_t amount = 1) { }
#elif defined(WIN64)
@ -158,8 +182,6 @@ public:
}
#endif
/// Set the reference number (only used with the EPercentage counter type)
/// Sorting by name (for the statistics)
bool operator<(const StatsCounter &v) const;
private:
@ -200,7 +222,7 @@ public:
/// Check whether progress bars are enabled
static inline bool isEnabled() { return m_enabled; }
protected:
private:
/// Convert a time value to a human-readable format
void printTime(Float time, std::ostream &os) const;
private:
@ -247,7 +269,7 @@ protected:
Statistics();
/// Virtual destructor
virtual ~Statistics() { }
private:
struct compareCategory {
bool operator()(const StatsCounter *c1, const StatsCounter *c2) {
if (c1->getCategory() == c2->getCategory())
@ -255,7 +277,7 @@ protected:
return c1->getCategory() < c2->getCategory();
}
};
private:
static ref<Statistics> m_instance;
std::vector<const StatsCounter *> m_counters;
std::vector<std::pair<std::string, std::string> > m_plugins;

View File

@ -18,7 +18,7 @@
#ifndef __MITSUBA_STL_H
#define __MITSUBA_STL_H
/* Include some SGI STL extensions, which might be missing */
#ifdef __GNUC__
#include <ext/functional>
@ -26,7 +26,10 @@ using __gnu_cxx::select2nd;
using __gnu_cxx::compose1;
#else
#include <functional>
namespace std {
/// \cond
// (Don't include in the documentation)
template <class _Pair> struct _Select1st : public unary_function<_Pair, typename _Pair::first_type> {
const typename _Pair::first_type& operator()(const _Pair& __x) const {
return __x.first;
@ -56,10 +59,9 @@ namespace std {
template <class _Operation1, class _Operation2> inline unary_compose<_Operation1,_Operation2> compose1(const _Operation1& __fn1, const _Operation2& __fn2) {
return unary_compose<_Operation1,_Operation2>(__fn1, __fn2);
}
/// @endcond
#if defined(_MSC_VER)
#define _USE_MATH_DEFINES
#include <math.h>
#include <float.h>
#define snprintf _snprintf
@ -93,62 +95,69 @@ using std::compose1;
MTS_NAMESPACE_BEGIN
extern MTS_EXPORT_CORE void * __restrict allocAligned(size_t size);
extern MTS_EXPORT_CORE void freeAligned(void *ptr);
MTS_NAMESPACE_END
namespace std {
template <typename T> class aligned_allocator {
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
/**
* \brief Aligned memory allocator for use with SSE2-based code
* \headerfile mitsuba/core/stl.h mitsuba/mitsuba.h
*
* Basic implementaiton, which forwards all calls to \ref allocAligned.
*/
template <typename T> class aligned_allocator {
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
template <class U> struct rebind {
typedef aligned_allocator<U> other;
};
pointer address (reference value) const {
return &value;
}
const_pointer address (const_reference value) const {
return &value;
}
aligned_allocator() throw() { }
aligned_allocator(const aligned_allocator&) throw() { }
template <class U> aligned_allocator (const aligned_allocator<U>&) throw() { }
~aligned_allocator() throw() { }
size_type max_size () const throw() {
return INT_MAX;
}
T* __restrict allocate (size_type num, const_pointer *hint = 0) {
return (T *) mitsuba::allocAligned(num*sizeof(T));
}
void construct (pointer p, const T& value) {
*p=value;
}
void destroy (pointer p) {
p->~T();
};
void deallocate (pointer p, size_type num) {
freeAligned(p);
}
/// \cond
template <class U> struct rebind {
typedef aligned_allocator<U> other;
};
/// \endcond
pointer address (reference value) const {
return &value;
}
const_pointer address (const_reference value) const {
return &value;
}
aligned_allocator() throw() { }
aligned_allocator(const aligned_allocator&) throw() { }
template <class U> aligned_allocator (const aligned_allocator<U>&) throw() { }
~aligned_allocator() throw() { }
size_type max_size () const throw() {
return INT_MAX;
}
T* __restrict allocate (size_type num, const_pointer *hint = 0) {
return (T *) mitsuba::allocAligned(num*sizeof(T));
}
void construct (pointer p, const T& value) {
*p=value;
}
void destroy (pointer p) {
p->~T();
};
void deallocate (pointer p, size_type num) {
freeAligned(p);
}
};
MTS_NAMESPACE_END
#if defined(WIN32)
inline bool ubi_isnan(float f) {
int classification = ::_fpclass(f);

View File

@ -23,34 +23,55 @@
MTS_NAMESPACE_BEGIN
/** \brief Abstract seekable stream class which defines
* all functions to be implemented by stream subclasses,
* such as <tt>FileStream</tt>, <tt>MemoryStream</tt>,
* <tt>SocketStream</tt>, <tt>ConsoleStream</tt> or
* <tt>SSHStream</tt>.
/** \brief Abstract seekable stream class
*
* Also supports platform-independent reads and writes
* (automatic endianness conversion).
* Specifies all functions to be implemented by stream
* subclasses and provides various convenience functions
* based on them.
*
* All read<b>X</b>() and write<b>X</b>() methods support transparent
* endianness conversion based on the endianness of the underlying
* system and the value passed to \ref setByteOrder().
*
* \sa FileStream, MemoryStream, SocketStream,
* ConsoleStream, SSHStream, ZStream
*/
class MTS_EXPORT_CORE Stream : public Object {
public:
/// Defines the byte order to use in this Stream
enum EByteOrder {
/// PowerPC, SPARC, Motorola 68K
EBigEndian = 0,
/// x86
ELittleEndian = 1,
/// Network byte order
ENetworkByteOrder = EBigEndian
EBigEndian = 0, ///< PowerPC, SPARC, Motorola 68K
ELittleEndian = 1, ///< x86, x86_64
ENetworkByteOrder = EBigEndian ///< Network byte order (an alias for big endian)
};
/// Create a new stream
/**
* \brief Create a new stream.
*
* By default, it assumes the byte order of the
* underlying system, i.e. no endianness conversion
* is performed.
*/
Stream();
/// Set the stream byte order
void setByteOrder(EByteOrder byteOrder);
/// Read data from the stream
/// Return the byte order of this stream
inline EByteOrder getByteOrder() const { return m_byteOrder; }
/// Return the byte order of the underlying machine
inline EByteOrder getHostByteOrder() { return m_hostByteOrder; }
/// Return a string representation
virtual std::string toString() const;
/// @{ \name Abstract methods to be implemented by subclasses
/// Read a specified amount of data from the stream
virtual void read(void *ptr, size_t size) = 0;
/// Write data into the stream
/// Write a specified amount of data into the stream
virtual void write(const void *ptr, size_t size) = 0;
/// Seek to a position inside the stream
@ -62,7 +83,7 @@ public:
/// Get the current position inside the stream
virtual size_t getPos() const = 0;
/// Return the current size of the stream
/// Return the size of the stream
virtual size_t getSize() const = 0;
/// Flush the stream's buffers
@ -74,6 +95,10 @@ public:
/// Can we read from the stream?
virtual bool canRead() const = 0;
/// @}
/// @{ \name Convenience functions
/// Skip the given number of bytes
void skip(size_t amount);
@ -123,32 +148,32 @@ public:
inline void writeBool(bool value) { writeUChar(value); }
/// Write a single-precision floating point number (32 bit) to the stream
void writeSingle(float pFloat);
void writeSingle(float value);
/// Write a single-precision floating point array (32 bit) to the stream
void writeSingleArray(const float *pFloat, size_t size);
void writeSingleArray(const float *data, size_t size);
/// Write a double-precision floating point number (64 bit) to the stream
void writeDouble(double pDouble);
void writeDouble(double value);
/// Write a double-precision floating point array (64 bit) to the stream
void writeDoubleArray(const double *pDouble, size_t size);
void writeDoubleArray(const double *data, size_t size);
/// Write a floating point number (configured precision) to the stream
inline void writeFloat(Float pFloat) {
inline void writeFloat(Float value) {
#ifdef SINGLE_PRECISION
writeSingle(pFloat);
writeSingle(value);
#else
writeDouble(pFloat);
writeDouble(value);
#endif
}
/// Write an array of floating point values (configured precision) to the stream
inline void writeFloatArray(const Float *pFloat, size_t size) {
inline void writeFloatArray(const Float *data, size_t size) {
#ifdef SINGLE_PRECISION
writeSingleArray(pFloat, size);
writeSingleArray(data, size);
#else
writeDoubleArray(pFloat, size);
writeDoubleArray(data, size);
#endif
}
@ -204,13 +229,13 @@ public:
float readSingle();
/// Read a double-precision floating point array (64 bit) from the stream
void readSingleArray(float *pDouble, size_t size);
void readSingleArray(float *data, size_t size);
/// Read a double-precision floating point number (64 bit) from the stream
double readDouble();
/// Read a double-precision floating point array (64 bit) from the stream
void readDoubleArray(double *pDouble, size_t size);
void readDoubleArray(double *data, size_t size);
/// Write a floating point number (configured precision) to the stream
inline Float readFloat() {
@ -222,33 +247,30 @@ public:
}
/// Write an array of floating point values (configured precision) to the stream
inline void readFloatArray(Float *pFloat, size_t size) {
inline void readFloatArray(Float *data, size_t size) {
#ifdef SINGLE_PRECISION
readSingleArray(pFloat, size);
readSingleArray(data, size);
#else
readDoubleArray(pFloat, size);
readDoubleArray(data, size);
#endif
}
/**
* Copy content from this stream into another stream
* @param numBytes
* \brief Copy content from this stream into another stream
* \param stream Destination stream
* \param numBytes
* The number of bytes to copy. When -1 is specified,
* copying proceeds until the end of the source stream.
*/
void copyTo(Stream *stream, int64_t numBytes = -1);
/// Return a string representation
virtual std::string toString() const;
/// Read an element from the stream (uses partial template specialization)
template <typename T> T readElement();
/// Set the stream byte order
void setByteOrder(EByteOrder byteOrder);
/// Write an element to the stream (uses partial template specialization)
template <typename T> void writeElement(T value);
/// Return the stream byte order
inline EByteOrder getByteOrder() const { return m_byteOrder; }
/// Return the host byte order
inline EByteOrder getHostByteOrder() { return m_hostByteOrder; }
/// @}
MTS_DECLARE_CLASS()
protected:
@ -259,6 +281,43 @@ private:
EByteOrder m_byteOrder;
};
template <typename T> inline T Stream::readElement() {
Log(EError, "Stream::readElement<T>: not implemented!");
}
template <typename T> inline void Stream::writeElement(T value) {
Log(EError, "Stream::writeElement<T>: not implemented!");
}
/// \cond
template <> inline float Stream::readElement() { return readSingle(); }
template <> inline double Stream::readElement() { return readDouble(); }
template <> inline char Stream::readElement() { return readChar(); }
template <> inline unsigned char Stream::readElement() { return readUChar(); }
template <> inline bool Stream::readElement() { return readBool(); }
template <> inline int16_t Stream::readElement() { return readShort(); }
template <> inline uint16_t Stream::readElement() { return readUShort(); }
template <> inline int32_t Stream::readElement() { return readInt(); }
template <> inline uint32_t Stream::readElement() { return readUInt(); }
template <> inline int64_t Stream::readElement() { return readLong(); }
template <> inline uint64_t Stream::readElement() { return readULong(); }
template <> inline std::string Stream::readElement() { return readString(); }
template <> inline void Stream::writeElement(float val) { return writeSingle(val); }
template <> inline void Stream::writeElement(double val) { return writeDouble(val); }
template <> inline void Stream::writeElement(char val) { return writeChar(val); }
template <> inline void Stream::writeElement(unsigned char val) { return writeUChar(val); }
template <> inline void Stream::writeElement(bool val) { return writeBool(val); }
template <> inline void Stream::writeElement(int16_t val) { return writeShort(val); }
template <> inline void Stream::writeElement(uint16_t val) { return writeUShort(val); }
template <> inline void Stream::writeElement(int32_t val) { return writeInt(val); }
template <> inline void Stream::writeElement(uint32_t val) { return writeUInt(val); }
template <> inline void Stream::writeElement(int64_t val) { return writeLong(val); }
template <> inline void Stream::writeElement(uint64_t val) { return writeULong(val); }
template <> inline void Stream::writeElement(const std::string &val) { return writeString(val); }
/// \endcond
MTS_NAMESPACE_END
#endif /* __STREAM_H */

View File

@ -23,9 +23,13 @@
MTS_NAMESPACE_BEGIN
/**
* \headerfile mitsuba/core/thread.h mitsuba/mitsuba.h
* \brief Cross-platform thread implementation
*/
class MTS_EXPORT_CORE Thread : public Object {
public:
/// Available thread priorities
/// Possible priority values for \ref Thread::setPriority()
enum EThreadPriority {
EIdlePriority = 0,
ELowestPriority,
@ -36,17 +40,32 @@ public:
ERealtimePriority
};
/// Create a new thread object
/**
* \brief Create a new thread object
* \param name An identifying name of this thread
* (will be shown in debug messages)
* \param stackSize Initial stack size of the thread
* (0 = default)
*/
Thread(const std::string &name,
unsigned int stackSize = 0);
/// Set the thread priority
void setPriority(EThreadPriority priority);
/**
* \brief Set the thread priority
*
* This does not always work -- for instance, Linux
* requires root privileges for this operation.
*
* \return \a true upon success.
*/
bool setPriority(EThreadPriority priority);
/**
* Set the critical flag. When an thread marked critical crashes
* from an uncaught exception, the whole process is terminated
* (default: false).
* \brief Specify whether or not this thread is critical
*
* When an thread marked critical crashes from an uncaught
* exception, the whole process is brought down.
* The default is \a false.
*/
inline void setCritical(bool critical) { m_critical = critical; }
@ -59,7 +78,7 @@ public:
/// Return the thread's stack size
inline int getStackSize() const { return m_stackSize; }
/// Return the thread's ID
/// Return the thread ID
#if defined(__OSX__)
inline static int getID() { return getThread()->m_id; }
#elif defined(WIN32)
@ -68,24 +87,30 @@ public:
inline static int getID() { return m_id; }
#endif
/// Return the thread's name
/// Return the name of this thread
inline const std::string &getName() const { return m_name; }
/// Set the thread's name
/// Set the name of this thread
inline void setName(const std::string &name) { m_name = name; }
/// Return the parent thread
inline Thread *getParent() { return m_parent; }
/// Return the parent thread
/// Return the parent thread (const version)
inline const Thread *getParent() const { return m_parent.get(); }
/// Set the thread's logger
/// Set the logger instance used to process log messages from this thread
inline void setLogger(Logger *logger) { m_logger = logger; }
/// Return the thread's logger
/// Return the thread's logger instance
inline Logger *getLogger() { return m_logger; }
/// Set the thread's file resolver
inline void setFileResolver(FileResolver *fresolver) { m_fresolver = fresolver; }
/// Return the thread's file resolver
inline FileResolver *getFileResolver() { return m_fresolver; }
/// Return the current thread
inline static Thread *getThread() {
return m_self->get();
@ -98,9 +123,11 @@ public:
void start();
/**
* Detach the thread - after this, <tt>join()</tt>
* cannot be used anymore. Releases resources,
* would otherwise be held until a call to <tt>join().</tt>
* \brief Detach the thread and release resources
*
* After a call to this function, \ref join()
* cannot be used anymore. This releases resources, which
* would otherwise be held until a call to \ref join().
*/
void detach();
@ -141,6 +168,7 @@ protected:
private:
ref<Thread> m_parent;
ref<Logger> m_logger;
ref<FileResolver> m_fresolver;
ref<Mutex> m_joinMutex;
std::string m_name;
unsigned int m_stackSize;

View File

@ -19,6 +19,8 @@
#if !defined(__TIMER_H)
#define __TIMER_H
#include <mitsuba/mitsuba.h>
#ifndef WIN32
#include <sys/time.h>
#endif

View File

@ -20,21 +20,41 @@
#define __TLS_H
#include <mitsuba/mitsuba.h>
#include <pthread.h>
/**
* Thin wrapper around posix thread local storage
* \headerfile mitsuba/core/tls.h mitsuba/mitsuba.h
* \brief Thin wrapper around posix thread local storage.
* Stores references to Object instances.
*
* This class implements a simple reference-counting thread-local
* pointer storage.
* \sa PrimitiveThreadLocal
*/
template <typename T> class ThreadLocal {
public:
/// Create a new (empty) thread-local reference
inline ThreadLocal() {
pthread_key_create(&m_key, ThreadLocal::deletePtr);
}
/**
* \brief Destroy the thread-local reference
*
* Beware: all threads that ever used this TLS (other than
* the caller of the destructor) must either either died or
* called \ref cleanup() prior to the destructor invocation --
* otherwise, the reference counts will be incorrect and
* memory leaks will ensue..
*/
inline ~ThreadLocal() {
cleanup();
pthread_key_delete(m_key);
}
/**
* \brief Make the thread-local reference point to the given
* instance and update the reference counts
*/
inline void set(T *value) {
T *previous = get();
if (previous != NULL)
@ -44,41 +64,60 @@ public:
pthread_setspecific(m_key, value);
}
/// Return the currently stored reference
inline T *get() {
return static_cast<T *>(pthread_getspecific(m_key));
}
protected:
/// Return the currently stored reference (const version)
inline const T *get() const {
return static_cast<const T *>(pthread_getspecific(m_key));
}
/// Set the reference to <tt>NULL</tt> and update the reference counts.
void cleanup() {
set(NULL);
}
private:
static void deletePtr(void *ptr) {
static_cast<T *>(ptr)->decRef();
}
protected:
pthread_key_t m_key;
};
/**
* As above, but meant for stack-allocated objects
* \headerfile mitsuba/core/tls.h mitsuba/mitsuba.h
* \brief Thin wrapper around posix thread local storage.
* Stores heap-allocated data other than Object instances.
* \sa ThreadLocal
*/
template <typename T> class PrimitiveThreadLocal {
public:
/// Create a new thread local storage object
inline PrimitiveThreadLocal() {
pthread_key_create(&m_key, PrimitiveThreadLocal::deletePtr);
}
/**
* \brief Destroy the thread local storage object
*
* Beware: all threads that ever used this TLS (other than
* the caller) must either either died or called cleanup()
* before this destructor is called -- otherwise memory leaks
* will ensue.
* the caller of the destructor) must either either died or
* called \ref cleanup() prior to the destructor invocation --
* otherwise, memory leaks will ensue..
*/
inline ~PrimitiveThreadLocal() {
cleanup();
pthread_key_delete(m_key);
}
/// Update the data associated with the current thread
inline void set(T &value) {
get() = value;
}
/// Return a reference to the data associated with the current thread
inline T &get() {
T *value = static_cast<T *>(pthread_getspecific(m_key));
if (value == NULL) {
@ -89,6 +128,10 @@ public:
return *value;
}
/**
* \brief Return a reference to the data associated with the
* current thread (const version)
*/
inline const T &get() const {
T *value = static_cast<T *>(pthread_getspecific(m_key));
if (value == NULL) {
@ -99,19 +142,19 @@ public:
return *value;
}
/// Delete the data record associated with the current thread
void cleanup() {
T *value = static_cast<T *>(pthread_getspecific(m_key));
if (value != NULL)
delete value;
pthread_setspecific(m_key, NULL);
}
protected:
private:
static void deletePtr(void *ptr) {
delete static_cast<T *>(ptr);
}
protected:
pthread_key_t m_key;
};
#endif /* __TLS_H */

View File

@ -19,8 +19,8 @@
#if !defined(__TRANSFORM_H)
#define __TRANSFORM_H
#include <mitsuba/mitsuba.h>
#include <mitsuba/core/ray.h>
#include <mitsuba/core/normal.h>
MTS_NAMESPACE_BEGIN
@ -76,13 +76,10 @@ protected:
virtual ~Matrix4x4() { }
};
struct Frame;
/**
* \brief Transform class encapsulating a linear affine
* transformation (using homogenous coordinates) and its inverse
* \brief Encapsulates a 4x4 linear transformation and its inverse
*/
class MTS_EXPORT_CORE Transform {
struct MTS_EXPORT_CORE Transform {
public:
/// Create an identity transformation
Transform();
@ -264,47 +261,47 @@ public:
/** \brief Create a perspective transformation.
* (Maps [near, far] to [0, 1])
* @param fov Field of view in degrees
* @param clipNear Near clipping plane
* @param clipFar Far clipping plane
* \param fov Field of view in degrees
* \param clipNear Near clipping plane
* \param clipFar Far clipping plane
*/
static Transform perspective(Float fov, Float clipNear, Float clipFar);
/** \brief Create a perspective transformation for OpenGL.
* (Maps [near, far] to [-1, 1])
* @param fov Field of view in degrees
* @param clipNear Near clipping plane distance
* @param clipFar Far clipping plane distance
* \param fov Field of view in degrees
* \param clipNear Near clipping plane distance
* \param clipFar Far clipping plane distance
*/
static Transform glPerspective(Float fov, Float clipNear, Float clipFar);
/** \brief Create a perspective transformation for OpenGL.
* @param left Left clipping plane coordinate
* @param right Right clipping plane coordinate
* @param top Top clipping plane coordinate
* @param bottom Bottom clipping plane coordinate
* @param clipNear Near clipping plane distance
* @param clipFar Far clipping plane distance
* \param left Left clipping plane coordinate
* \param right Right clipping plane coordinate
* \param top Top clipping plane coordinate
* \param bottom Bottom clipping plane coordinate
* \param nearVal Near clipping plane distance
* \param farVal Far clipping plane distance
*/
static Transform glFrustum(Float left, Float right, Float bottom, Float top, Float nearVal, Float farVal);
/** \brief Create an orthographic transformation, which maps Z to [0,1]
* and leaves the X and Y coordinates untouched.
* @param clipNear Near clipping plane
* @param clipFar Far clipping plane
* \param clipNear Near clipping plane
* \param clipFar Far clipping plane
*/
static Transform orthographic(Float clipNear, Float clipFar);
/** \brief Create an orthographic transformation for OpenGL
* @param clipNear Near clipping plane
* @param clipFar Far clipping plane
* \param clipNear Near clipping plane
* \param clipFar Far clipping plane
*/
static Transform glOrthographic(Float clipNear, Float clipFar);
/** \brief Create a look-at camera transformation
* @param p Camera position
* @param t Target vector
* @param u Up vector
* \param p Camera position
* \param t Target vector
* \param u Up vector
*/
static Transform lookAt(const Point &p, const Point &t, const Vector &u);

View File

@ -25,17 +25,18 @@
MTS_NAMESPACE_BEGIN
/**
* Mesh vertex data structure. Stores 3D coordinates,
* vertex normals, UV coordinates and a tangent frame
* \brief Mesh vertex data structure. Stores 3D coordinates,
* vertex normals, UV coordinates and a tangent frame.
*/
struct Vertex {
Point v;
Normal n;
Point2 uv;
Vector dpdu, dpdv;
Point p; ///< %Position
Normal n; ///< %Normal
Point2 uv; ///< %Texture coordinates
Vector dpdu; ///< Partial derivative of the position with respect to \a u.
Vector dpdv; ///< Partial derivative of the position with respect to \a v.
inline bool operator==(const Vertex &vert) const {
return (v == vert.v && n == vert.n && uv == vert.uv
return (p == vert.p && n == vert.n && uv == vert.uv
&& dpdu == vert.dpdu && dpdv == vert.dpdv);
}
@ -44,26 +45,29 @@ struct Vertex {
}
};
/** \brief Triangle class including a collection of routines
* for analysis and transformation. Triangles are stored as
* indices into a vertex array
/**
* \brief Simple triangle class including a collection of routines
* for analysis and transformation.
*
* Triangles are stored as indices into a vertex array
*/
struct MTS_EXPORT_CORE Triangle {
/* Indices into a vertex buffer */
/// Indices into a vertex buffer
unsigned int idx[3];
/// Construct an axis-aligned box, which contains the triangle
AABB getAABB(const Vertex *buffer) const;
/**
* Returns the axis-aligned bounding box of a triangle after it has
* clipped to the extends of another, given AABB. This function uses the
* Sutherland-Hodgman algorithm to calculate the convex polygon, which
* is created when applying all 6 AABB splitting planes to the triangle.
* Afterwards, the AABB of the newly created convex polygon is returned.
* This function is an important component for efficiently creating
* 'Perfect Split' KD-trees. For more detail, see
* "On building fast kd-Trees for Ray Tracing, and on doing
* \brief Returns the axis-aligned bounding box of a triangle after it has
* clipped to the extends of another, given AABB.
*
* This function uses the Sutherland-Hodgman algorithm to calculate the
* convex polygon, which is created when applying all 6 AABB splitting
* planes to the triangle. Afterwards, the AABB of the newly created
* convex polygon is returned. This function is an important component
* for efficiently creating 'Perfect Split' KD-trees. For more detail,
* see "On building fast kd-Trees for Ray Tracing, and on doing
* that in O(N log N)" by Ingo Wald and Vlastimil Havran
*/
AABB getClippedAABB(const Vertex *buffer, const AABB &aabb) const;
@ -73,8 +77,8 @@ struct MTS_EXPORT_CORE Triangle {
* Uses the algorithm presented by Moeller and Trumbore at
* http://www.acm.org/jgt/papers/MollerTrumbore97/code.html
* Returns true if an intersection has been detected
* On success, pT contains the distance from the ray origin to the
* intersection point and pUV contains the intersection point in
* On success, \a t contains the distance from the ray origin to the
* intersection point, and \a u and \a v contain the intersection point in
* the local triangle coordinate system
*/
bool rayIntersect(const Vertex *buffer, const Ray &ray, Float &u,

View File

@ -21,7 +21,6 @@
MTS_NAMESPACE_BEGIN
class Random;
// -----------------------------------------------------------------------
// Miscellaneous
// -----------------------------------------------------------------------
@ -45,21 +44,9 @@ extern MTS_EXPORT_CORE std::string indent(const std::string &string, int amount=
/// Convert a time difference (in ms) to a string representation
extern MTS_EXPORT_CORE std::string timeToString(Float time);
/// Convert a string to lower case
extern MTS_EXPORT_CORE std::string toLowerCase(const std::string &string);
/// Convert a string to upper case
extern MTS_EXPORT_CORE std::string toUpperCase(const std::string &string);
/// Trim spaces (' ', '\n', '\r', '\t') from the ends of a string
/// Trim spaces (' ', '\\n', '\\r', '\\t') from the ends of a string
extern MTS_EXPORT_CORE std::string trim(const std::string& str);
/// Determines whether a string starts with the string given as second parameter
extern MTS_EXPORT_CORE bool startsWith(const std::string& str, const std::string& start);
/// Determines whether a string ends with the string given as second parameter
extern MTS_EXPORT_CORE bool endsWith(const std::string& str, const std::string& end);
/// Allocate an aligned region of memory
extern MTS_EXPORT_CORE void * __restrict allocAligned(size_t size);
@ -123,21 +110,23 @@ extern MTS_EXPORT_CORE bool solveLinearSystem2x2(const Float a[2][2], const Floa
extern MTS_EXPORT_CORE void coordinateSystem(const Vector &a, Vector &b, Vector &c);
/**
* \brief Generate optionally jittered, stratified 1D samples
* @param dest A pointer to a floating point array with at least
* \brief Generate (optionally jittered) stratified 1D samples
* \param random Source of random numbers
* \param dest A pointer to a floating point array with at least
* count entries
* @param count The interval [0, 1] is split into count strata
* @param jitter Randomly jitter the samples?
* \param count The interval [0, 1] is split into count strata
* \param jitter Randomly jitter the samples?
*/
extern MTS_EXPORT_CORE void stratifiedSample1D(Random *random, Float *dest,
int count, bool jitter);
/**
* \brief Generate optionally jittered, stratified 2D samples
* @param dest A pointer to a floating point array
* @param countX The X axis interval [0, 1] is split into countX strata
* @param countY The Y axis interval [0, 1] is split into countY strata
* @param jitter Randomly jitter the samples?
* \brief Generate (optionally jittered) stratified 2D samples
* \param random Source of random numbers
* \param dest A pointer to a floating point array
* \param countX The X axis interval [0, 1] is split into countX strata
* \param countY The Y axis interval [0, 1] is split into countY strata
* \param jitter Randomly jitter the samples?
*/
extern MTS_EXPORT_CORE void stratifiedSample2D(Random *random, Point2 *dest,
int countX, int countY, bool jitter);
@ -175,12 +164,12 @@ extern MTS_EXPORT_CORE Point2 squareToTriangle(const Point2 &sample);
/// Convert radians to degrees
inline Float radToDeg(Float rad) {
return 180.0f*rad/M_PI;
return 180.0f * rad / M_PI;
}
/// Convert degrees to radians
inline Float degToRad(Float deg) {
return deg*M_PI/180.0f;
return deg * M_PI / 180.0f;
}
/// Simple floating point clamping function
@ -205,13 +194,13 @@ inline int clamp(int value, int min, int max) {
* Calculates the unpolarized fresnel reflection coefficient for a
* dielectric material
*
* @param cosTheta1
* \param cosTheta1
* Cosine of the angle between the normal and the incident ray
* @param cosTheta2
* \param cosTheta2
* Cosine of the angle between the normal and the transmitted ray
* @param etaExt
* \param etaExt
* Refraction coefficient outside of the material
* @param etaInt
* \param etaInt
* Refraction coefficient inside the material
*/
extern MTS_EXPORT_CORE Float fresnelDielectric(Float cosTheta1, Float cosTheta2,
@ -221,11 +210,11 @@ extern MTS_EXPORT_CORE Float fresnelDielectric(Float cosTheta1, Float cosTheta2,
* Calculates the unpolarized fresnel reflection coefficient for a
* dielectric material. Handles incidence from either sides.
*
* @param cosTheta1
* \param cosTheta1
* Cosine of the angle between the normal and the incident ray
* @param etaExt
* \param etaExt
* Refraction coefficient outside of the material
* @param etaInt
* \param etaInt
* Refraction coefficient inside the material
*/
extern MTS_EXPORT_CORE Float fresnel(Float cosTheta1, Float etaExt, Float etaInt);
@ -234,11 +223,11 @@ extern MTS_EXPORT_CORE Float fresnel(Float cosTheta1, Float etaExt, Float etaInt
* Calculates the unpolarized fresnel reflection coefficient on
* an interface to a conductor.
*
* @param cosTheta
* \param cosTheta
* Cosine of the angle between the normal and the incident ray
* @param eta
* \param eta
* Relative refractive index (per wavelength)
* @param k
* \param k
* Absorption coefficient (per wavelength)
*/
extern MTS_EXPORT_CORE Spectrum fresnelConductor(Float cosTheta, const Spectrum &eta, const Spectrum &k);
@ -259,7 +248,12 @@ extern MTS_EXPORT_CORE Float radicalInverse(int b, int i);
*/
extern MTS_EXPORT_CORE Float radicalInverseIncremental(int b, Float x);
/* Rational approximation to the inverse normal cumulative distribution function */
/**
* Rational approximation to the inverse normal
* cumulative distribution function
* Source: http://home.online.no/~pjacklam/notes/invnorm/impl/sprouse/ltqnorm.c
* \author Peter J. Acklam
*/
extern MTS_EXPORT_CORE double normalQuantile(double p);
MTS_NAMESPACE_END

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@
#define __WAVELET_H
#include <mitsuba/core/bitmap.h>
#include <mitsuba/core/serialization.h>
//#define USE_GOOGLE_SPARSE_HASHMAP 1
//#define USE_GOOGLE_DENSE_HASHMAP 1
@ -37,19 +38,18 @@
MTS_NAMESPACE_BEGIN
class SparseWavelet2D;
class SparseWaveletOctree;
/**
* Non-standard 2D Haar wavelet transformation. Based on
* "Wavelets for computer graphics: A primer, part 1" by
* \brief Performs non-standard 2D Haar wavelet transformations.
*
* Based on "Wavelets for computer graphics: A primer, part 1" by
* Eric J. Stollnitz, Tony D. DeRose, and David H. Salesin
* (IEEE Computer Graphics and Applications, May 1995)
*/
class MTS_EXPORT_CORE Wavelet2D : public Object {
public:
/**
* Create a wavelet representation from a given bitmap.
* \brief Create a wavelet representation from a given bitmap.
*
* Only one color channel is supported for this encoding, so
* the desired channel must be selected using the `colorChannel'
* parameter.
@ -60,7 +60,8 @@ public:
Wavelet2D(const SparseWavelet2D *sw);
/**
* Turn the wavelet representation back into an image.
* \brief Turn the wavelet representation back into an image.
*
* Optionally, scale+offset factors can be supplied to
* map the bitmap to a desired brightness
*/
@ -70,7 +71,7 @@ public:
void discard(Float fraction);
/**
* Discard components such that the relative L^2-error is below the
* \brief Discard components such that the relative L^2-error is below the
* given bound. Returns the achieved compression ratio.
*/
Float compress(Float maxError);
@ -101,6 +102,7 @@ protected:
/// Virtual destructor
virtual ~Wavelet2D();
protected:
/// \cond
struct coeff_t {
inline coeff_t() { }
inline coeff_t(size_t index, float value)
@ -112,15 +114,16 @@ protected:
size_t index;
float value;
};
/// \endcond
protected:
float *m_data;
float *m_temp;
Vector2 m_range;
size_t m_size;
};
/**
* Implements the non-standard 3D wavelet transform using Haar basis functions.
* \brief Implements the non-standard 3D wavelet transform using
* Haar basis functions.
*/
class MTS_EXPORT_CORE Wavelet3D : public Object {
public:
@ -132,7 +135,7 @@ public:
Wavelet3D(const float *data, size_t resolution);
/**
* Turn the wavelet representation back into a dense format
* \brief Turn the wavelet representation back into a dense format
*/
void decode(float *target);
@ -140,7 +143,7 @@ public:
void discard(Float fraction);
/**
* Discard components such that the relative L^2-error is below the
* \brief Discard components such that the relative L^2-error is below the
* given bound. Returns the achieved compression ratio.
*/
Float compress(Float maxRelError);
@ -169,6 +172,7 @@ protected:
/// Virtual destructor
virtual ~Wavelet3D();
protected:
/// \cond
struct coeff_t {
inline coeff_t() { }
inline coeff_t(size_t index, float value)
@ -182,18 +186,19 @@ protected:
size_t index;
float value;
};
/// \endcond
protected:
float *m_data;
float *m_temp;
Vector2 m_range;
size_t m_size, m_slab;
};
/**
* Sparse 2D wavelet representation using the Haar basis
* \brief Sparse 2D wavelet representation using the Haar basis
*/
class MTS_EXPORT_CORE SparseWavelet2D : public SerializableObject {
public:
/// 2D wavelet coefficient index for \ref SparseWavelet2D
struct Key {
uint16_t empty;
uint8_t level; // level in the hierarchy
@ -298,8 +303,9 @@ public:
Float getPixel(const Point2i &pt) const;
/**
* Compute a line integral in 2D wavelet space. Coordinates are
* expected as pixel coordinates in [0,0]-[size,size],
* \brief Compute a line integral in 2D wavelet space.
*
* Coordinates are expected as pixel coordinates in [0,0]-[size,size],
* but are allowed to be fractional
*/
Float lineIntegral(Point2 start, Point2 end) const;
@ -325,7 +331,8 @@ protected:
};
/**
* Sparse 3D wavelet representation using the Haar basis and an octree structure
* \brief Sparse 3D wavelet representation using the Haar basis and an
* octree structure
*/
class MTS_EXPORT_CORE SparseWaveletOctree : public Object {
public:
@ -350,6 +357,9 @@ public:
MTS_DECLARE_CLASS()
protected:
/// Virtual destructor
virtual ~SparseWaveletOctree() { }
private:
struct Node {
inline Node(float value) : value(value) {
for (int i=0; i<8; ++i)
@ -363,9 +373,6 @@ protected:
Float lineIntegral(int32_t idx,
Float tx0, Float ty0, Float tz0,
Float tx1, Float ty1, Float tz1, uint8_t a) const;
/// Virtual destructor
virtual ~SparseWaveletOctree() { }
private:
Node *m_root;
std::vector<Node> m_nodes;

View File

@ -68,6 +68,21 @@ public:
/// Set a Vector4 parameter
void setParameter(int id, const Vector4 &value);
/// Set a Point parameter
void setParameter(int id, const Point &value);
/// Set a Point3i parameter
void setParameter(int id, const Point3i &value);
/// Set a Point2 parameter
void setParameter(int id, const Point2 &value);
/// Set a Point2i parameter
void setParameter(int id, const Point2i &value);
/// Set a Point4 parameter
void setParameter(int id, const Point4 &value);
/// Set a Transform parameter
void setParameter(int id, const Transform &value);

View File

@ -98,13 +98,43 @@ public:
bool failIfMissing = true) {
setParameter(getParameterID(name, failIfMissing), value);
}
/// Set a Vector4 parameter by name
inline void setParameter(const std::string &name, const Vector4 &value,
bool failIfMissing = true) {
setParameter(getParameterID(name, failIfMissing), value);
}
/// Set a Point parameter by name
inline void setParameter(const std::string &name, const Point &value,
bool failIfMissing = true) {
setParameter(getParameterID(name, failIfMissing), value);
}
/// Set a Point3i parameter by name
inline void setParameter(const std::string &name, const Point3i &value,
bool failIfMissing = true) {
setParameter(getParameterID(name, failIfMissing), value);
}
/// Set a Point2 parameter by name
inline void setParameter(const std::string &name, const Point2 &value,
bool failIfMissing = true) {
setParameter(getParameterID(name, failIfMissing), value);
}
/// Set a Point2i parameter by name
inline void setParameter(const std::string &name, const Point2i &value,
bool failIfMissing = true) {
setParameter(getParameterID(name, failIfMissing), value);
}
/// Set a Point4 parameter by name
inline void setParameter(const std::string &name, const Point4 &value,
bool failIfMissing = true) {
setParameter(getParameterID(name, failIfMissing), value);
}
/// Set a Transform parameter by name
inline void setParameter(const std::string &name, const Transform &value,
bool failIfMissing = true) {
@ -145,6 +175,21 @@ public:
/// Set a Vector4 parameter
virtual void setParameter(int id, const Vector4 &value) = 0;
/// Set a Point parameter
virtual void setParameter(int id, const Point &value) = 0;
/// Set a Point3i parameter
virtual void setParameter(int id, const Point3i &value) = 0;
/// Set a Point2 parameter
virtual void setParameter(int id, const Point2 &value) = 0;
/// Set a Point2i parameter
virtual void setParameter(int id, const Point2i &value) = 0;
/// Set a Point4 parameter
virtual void setParameter(int id, const Point4 &value) = 0;
/// Set a Transform parameter
virtual void setParameter(int id, const Transform &value) = 0;

View File

@ -31,28 +31,44 @@
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdexcept>
#include <limits>
/// Current release of Mitsuba
#define MTS_VERSION "0.1.3"
/// Year of this release
#define MTS_YEAR "2010"
/// Default port of <tt>mtssrv</tt>
#define MTS_DEFAULT_PORT 7554
#if defined(__LINUX__)
/// Default resource directory for packaged releases on Linux
#define MTS_RESOURCE_DIR "/usr/share/mitsuba"
#endif
using std::cout;
using std::cerr;
using std::endl;
#include <mitsuba/core/stl.h>
#include <mitsuba/core/ref.h>
#include <mitsuba/core/object.h>
#include <mitsuba/core/sse.h>
/**
* Include a basic subset of the core classes
*/
#include <mitsuba/core/constants.h>
#include <mitsuba/core/fwd.h>
#include <mitsuba/render/fwd.h>
#include <mitsuba/core/stl.h>
#include <mitsuba/core/object.h>
#include <mitsuba/core/ref.h>
#include <mitsuba/core/sse.h>
#include <mitsuba/core/tls.h>
#include <mitsuba/core/lock.h>
#include <mitsuba/core/logger.h>
#include <mitsuba/core/thread.h>
#include <mitsuba/core/statistics.h>
#include <mitsuba/core/properties.h>
#include <mitsuba/core/cobject.h>
#include <mitsuba/core/vector.h>
#include <mitsuba/core/point.h>
#include <mitsuba/core/normal.h>
#include <mitsuba/core/spectrum.h>
#include <mitsuba/core/util.h>
#endif /* __MITSUBA_H */

View File

@ -19,11 +19,104 @@
#if !defined(__BSDF_H)
#define __BSDF_H
#include <mitsuba/render/records.h>
#include <mitsuba/core/cobject.h>
#include <mitsuba/core/frame.h>
#include <mitsuba/core/properties.h>
#include <mitsuba/render/shader.h>
MTS_NAMESPACE_BEGIN
/**
* Specifies the transported quantity when sampling / evaluating a BSDF
*/
enum ETransportQuantity {
ERadiance = 1,
EImportance = 2
};
/**
* Data structure, which contains all information required to
* sample or query a BSDF.
*/
struct MTS_EXPORT_RENDER BSDFQueryRecord {
public:
/**
* Given a surface interaction and an incident direction
* construct a query record which can be used to sample
* an outgoing direction.
* For convenience, this function uses the local incident direction
* vector contained in the supplied intersection record.
*/
inline BSDFQueryRecord(RadianceQueryRecord &rRec,
const Intersection &its, Point2 sample);
/**
* Given a surface interaction and an incident direction,
* construct a query record which can be used to sample
* an outgoing direction.
* For convenience, this function uses the local incident direction
* vector contained in the supplied intersection record.
*/
inline BSDFQueryRecord(const Intersection &its, Point2 sample);
/**
* Given a surface interaction an an incident/exitant direction
* pair (wi, wo), create a BSDF query record to evaluate f(wi, wo).
* For convenience, this function uses the local incident direction
* vector contained in the supplied intersection record.
*/
inline BSDFQueryRecord(RadianceQueryRecord &rRec,
const Intersection &its, const Vector &wo);
/**
* Given a surface interaction an an incident/exitant direction
* pair (wi, wo), create a BSDF query record to evaluate f(wi, wo).
* For convenience, this function uses the local incident direction
* vector contained in the supplied intersection record.
*/
inline BSDFQueryRecord(const Intersection &its, const Vector &wo);
/**
* Given a surface interaction an an incident/exitant direction
* pair (wi, wo), create a BSDF query record to evaluate f(wi, wo).
*/
inline BSDFQueryRecord(const Intersection &its, const Vector &wi,
const Vector &wo);
/// Return a string representation
std::string toString() const;
public:
/* Pointer to the associated radiance query record (or NULL) */
RadianceQueryRecord *rRec;
/* Surface interaction */
const Intersection &its;
/* Incident direction */
Vector wi;
/* Outgoing/sampled direction */
Vector wo;
/* Random sample used to generate the new direction */
Point2 sample;
/* Transported quantity (radiance or importance) -- required for
non-reciprocal BSDFs such as transmission through a dielectric
material */
ETransportQuantity quantity;
/* Bit mask containing the component types, which may be sampled.
After sampling has been performed, the component type is stored
inside 'sampledType'. */
unsigned int typeMask, sampledType;
/* To sample a specific BSDF component, this entry must be non-negative.
After sampling has been performed, the component index is stored
inside 'sampledComponent' */
int component, sampledComponent;
};
/** \brief Abstract BxDF base-class, which supports reflection and
* transmission using a common interface for sampling and evaluation.
* A BSDF can consist of several components, which can optionally be
@ -99,6 +192,8 @@ public:
*/
inline Spectrum sampleCos(BSDFQueryRecord &bRec) const {
Spectrum bsdfVal = sample(bRec);
if (bsdfVal.isBlack())
return bsdfVal; // bRec.wo is undefined, play safe
return bsdfVal * std::abs(Frame::cosTheta(bRec.wo));
}
@ -119,6 +214,8 @@ public:
*/
inline Spectrum sampleCos(BSDFQueryRecord &bRec, Float &pdf) const {
Spectrum bsdfVal(sample(bRec, pdf));
if (bsdfVal.isBlack())
return bsdfVal; // bRec.wo is undefined, play safe
return bsdfVal * std::abs(Frame::cosTheta(bRec.wo));
}
@ -172,6 +269,8 @@ protected:
std::string m_name;
};
extern void operator<<(const ETransportQuantity &quantity, std::ostream &os);
MTS_NAMESPACE_END
#endif /* __BSDF_H */

View File

@ -0,0 +1,68 @@
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2010 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba 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/>.
*/
#if !defined(__CONST_TEXTURE_H)
#define __CONST_TEXTURE_H
#include <mitsuba/core/properties.h>
#include <mitsuba/render/texture.h>
MTS_NAMESPACE_BEGIN
class MTS_EXPORT_RENDER ConstantTexture : public Texture {
public:
inline ConstantTexture(const Spectrum &value)
: Texture(Properties()), m_value(value) {
}
ConstantTexture(Stream *stream, InstanceManager *manager);
inline Spectrum getValue(const Intersection &its) const {
return m_value;
}
inline Spectrum getAverage() const {
return m_value;
}
inline Spectrum getMaximum() const {
return m_value;
}
inline std::string toString() const {
std::ostringstream oss;
oss << "ConstantTexture[value=" << m_value.toString() << "]";
return oss.str();
}
inline bool usesRayDifferentials() const {
return false;
}
Shader *createShader(Renderer *renderer) const;
void serialize(Stream *stream, InstanceManager *manager) const;
MTS_DECLARE_CLASS()
protected:
Spectrum m_value;
};
MTS_NAMESPACE_END
#endif /* __CONST_TEXTURE_H */

View File

@ -21,11 +21,12 @@
#include <mitsuba/render/sampler.h>
#include <mitsuba/render/renderproc_wr.h>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
MTS_NAMESPACE_BEGIN
class Bitmap;
/** \brief Abstract Film base class - used to store samples
* generated by the Integrator.
*/
@ -55,7 +56,7 @@ public:
virtual void toBitmap(Bitmap *bitmap) const = 0;
/// Develop the film and write the result to the specified filename
virtual void develop(const std::string &fileName) = 0;
virtual void develop(const fs::path &fileName) = 0;
/// Ignoring the crop window, return the resolution of the underlying sensor
inline const Vector2i &getSize() const { return m_size; }
@ -89,7 +90,7 @@ public:
virtual void serialize(Stream *stream, InstanceManager *manager) const;
/// Does the destination already exist?
virtual bool destinationExists(const std::string &baseName) const = 0;
virtual bool destinationExists(const fs::path &baseName) const = 0;
/// Return the properties of this film
inline const Properties &getProperties() const { return m_properties; }

View File

@ -0,0 +1,83 @@
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2010 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba 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/>.
*/
#if !defined(__RENDER_FWD_H)
#define __RENDER_FWD_H
MTS_NAMESPACE_BEGIN
class BlockedImageProcess;
class BlockedRenderProcess;
class BlockListener;
class BSDF;
struct BSDFQueryRecord;
class Camera;
class ConstantTexture;
struct EmissionRecord;
class Film;
class GatherPhotonProcess;
class HemisphereSampler;
class HWResource;
class ImageBlock;
class Integrator;
struct Intersection;
class IrradianceCache;
class KDTree;
class LocalWorker;
class Luminaire;
struct LuminaireSamplingRecord;
class Medium;
struct MediumSamplingRecord;
class MIPMap;
class MonteCarloIntegrator;
class ParticleProcess;
class ParticleTracer;
class PhaseFunction;
class PhotonMap;
class PreviewWorker;
class ProjectiveCamera;
struct RadianceQueryRecord;
class Random;
class RangeWorkUnit;
class ReconstructionFilter;
class RectangularWorkUnit;
class RenderJob;
class RenderListener;
class RenderQueue;
class SampleIntegrator;
class Sampler;
class Scene;
class SceneHandler;
class Shader;
class Shape;
struct ShapeSamplingRecord;
class SparseMipmap3D;
class Spiral;
class Subsurface;
class TabulatedFilter;
class Texture;
struct TriAccel;
struct TriAccel4;
class TriMesh;
class Utility;
class VolumeDataSource;
struct VPL;
MTS_NAMESPACE_END
#endif /* __RENDER_FWD_H */

View File

@ -19,16 +19,12 @@
#if !defined(__INTEGRATOR_H)
#define __INTEGRATOR_H
#include <mitsuba/render/sampler.h>
#include <mitsuba/core/netobject.h>
#include <mitsuba/core/properties.h>
#include <mitsuba/render/shape.h>
MTS_NAMESPACE_BEGIN
class Scene;
class Camera;
class RenderQueue;
class RenderJob;
/**
* Abstract integrator base-class. Does not make any assumptions on
* how radiance is computed.
@ -45,7 +41,7 @@ public:
* which have been made available to all local and remote workers.
* The default implementation simply returns.
*/
virtual void preprocess(const Scene *scene, RenderQueue *queue,
virtual bool preprocess(const Scene *scene, RenderQueue *queue,
const RenderJob *job, int sceneResID, int cameraResID,
int samplerResID);
@ -110,6 +106,170 @@ protected:
Properties m_properties;
};
struct MTS_EXPORT_RENDER RadianceQueryRecord {
public:
/**
* List of suported query types. These can be combined by a binary OR.
*/
enum ERadianceQuery {
/* Emitted radiance from a luminaire intersected by the ray */
EEmittedRadiance = 0x0001,
/* Emitted radiance from a subsurface integrator */
ESubsurfaceRadiance = 0x0002,
/* Direct (surface) radiance */
EDirectRadiance = 0x0004,
/* Indirect (surface) radiance, where the last bounce did not go
through a Dirac delta BSDF */
EIndirectRadiance = 0x0008,
/* Indirect (surface) radiance, where the last bounce went
through a Dirac delta BSDF */
ECausticRadiance = 0x0010,
/* In-scattered radiance due to volumetric scattering (direct) */
EInscatteredDirectRadiance = 0x0020,
/* In-scattered radiance due to volumetric scattering (indirect) */
EInscatteredIndirectRadiance = 0x0040,
/* Distance to the next surface intersection */
EDistance = 0x0080,
/* Opacity value: 1 when a surface was hit, 0 when the ray leads
into empty space. When there is a participating medium,
this can also take on fractional values. */
EOpacity = 0x0100,
/* A ray intersection may need to be performed. This can be set to
zero if the caller has already provided the intersection */
EIntersection = 0x0200,
/* Radiance from volumes */
EVolumeRadiance = EInscatteredDirectRadiance | EInscatteredIndirectRadiance,
/* Radiance query without emitted radiance, ray intersection required */
ERadianceNoEmission = ESubsurfaceRadiance | EDirectRadiance | EIndirectRadiance
| ECausticRadiance | EInscatteredDirectRadiance | EInscatteredIndirectRadiance | EIntersection,
/* Default radiance query, ray intersection required */
ERadiance = ERadianceNoEmission | EEmittedRadiance,
/* Radiance + opacity */
ECameraRay = ERadiance | EOpacity
};
/// Construct an invalid radiance query record
inline RadianceQueryRecord()
: type(0), scene(NULL), sampler(NULL),
depth(0), alpha(0), dist(-1), wavelength(-1), extra(0) {
}
/// Construct a radiance query record for the given scene and sampler
inline RadianceQueryRecord(const Scene *scene, Sampler *sampler)
: type(0), scene(scene), sampler(sampler),
depth(0), alpha(0), dist(-1), wavelength(-1), extra(0) {
}
/// Copy constructor
inline RadianceQueryRecord(const RadianceQueryRecord &rRec)
: type(rRec.type), scene(rRec.scene), sampler(rRec.sampler),
depth(rRec.depth), alpha(rRec.alpha), dist(rRec.dist),
wavelength(rRec.wavelength), extra(rRec.extra) {
}
/// Begin a new query of the given type
inline void newQuery(int _type) {
type = _type;
depth = 1;
wavelength = -1;
extra = 0;
}
/// Initialize the query record for a recursive query
inline void recursiveQuery(const RadianceQueryRecord &parent, int _type) {
type = _type;
scene = parent.scene;
sampler = parent.sampler;
depth = parent.depth+1;
wavelength = parent.wavelength;
extra = 0;
}
/**
* Search for a ray intersection. This
* does several things at once - if the intersection has
* already been provided, the function returns.
* Otherwise, it
* - performs the ray intersection
* - computes the attenuation due to participating media
* and stores it in <tt>attenuation</tt>.
* - sets the alpha value (if <tt>EAlpha</tt> is set in <tt>type</tt>)
* - sets the distance value (if <tt>EDistance</tt> is set in <tt>type</tt>)
* - clears the <tt>EIntersection</tt> flag in <tt>type</tt>
* Returns true if there is a valid intersection.
*/
inline bool rayIntersect(const RayDifferential &ray);
/// Retrieve a 2D sample
inline Point2 nextSample2D();
/// Retrieve a 1D sample
inline Float nextSample1D();
/// Return a string representation
std::string toString() const;
public:
// An asterisk (*) marks entries, which may be overwritten
// by the callee.
/// Query type (*)
int type;
/// Pointer to the associated scene
const Scene *scene;
/// Sample generator
Sampler *sampler;
/// Current depth value (# of light bounces) (*)
int depth;
/// Surface interaction data structure (*)
Intersection its;
/// Attenuation along the current ray (*)
Spectrum attenuation;
/// Opacity value of the associated pixel (*)
Float alpha;
/**
* Ray distance to the first surface interaction
* (if requested by the query type EDistance) (*)
*/
Float dist;
/**
* In some cases, the integrator may be forced to restrict
* radiance computations to one wavelength (e.g. when intersecting
* a dielectric material with dispersion or while path
* tracing through a highly scattering medium with a non-constant
* scattering coefficient). This attribute is used to store the
* chosen wavelength. (*)
*/
int wavelength;
/**
* Internal flag, which can be used to pass additional information
* amonst recursive calls inside an integrator. The use
* is dependent on the particular integrator implementation. (*)
*/
int extra;
};
/** \brief Abstract base class, which describes integrators
* capable of computing samples of the scene's radiance function.
*/

View File

@ -19,9 +19,7 @@
#if !defined(__KD_TREE_H)
#define __KD_TREE_H
#include <mitsuba/render/trimesh.h>
#include <mitsuba/render/triaccel.h>
#include <mitsuba/core/aabb.h>
#include <mitsuba/render/shape.h>
/**
* First, some default configuration definitions:
@ -36,7 +34,6 @@
#define MTS_USE_TRIACCEL 1
#else
#define MTS_USE_TRIACCEL 1
#include <mitsuba/render/triaccel.h>
#endif
#if defined(MTS_HAS_COHERENT_RT)
@ -56,6 +53,8 @@
#define MTS_USE_MT 1
#endif
#include <mitsuba/render/triaccel.h>
/**
* Pre-defined max. stack size for the ray traversal algorithm
*/
@ -190,6 +189,8 @@ protected:
/// Virtual destructor
virtual ~KDTree();
/// \cond
/// KD-tree node in 8 bytes
struct KDNode {
union {
@ -435,6 +436,7 @@ protected:
const KDNode * __restrict node;
};
#endif
/// \endcond
/**
* Intersection method from Vlastimil Havran's
@ -470,7 +472,7 @@ protected:
/* Pointers to all contained shapes */
std::vector<const Shape *> m_shapes;
/// Storage for kd-tree nodes
std::vector<KDNode, std::aligned_allocator<KDNode> > m_nodes;
std::vector<KDNode, aligned_allocator<KDNode> > m_nodes;
#if defined(MTS_USE_TRIACCEL4)
/// Explicitly store per-leaf quad-packed triangles
TriAccel4 *m_packedTriangles;

View File

@ -19,12 +19,98 @@
#if !defined(__LUMINAIRE_H)
#define __LUMINAIRE_H
#include <mitsuba/render/records.h>
#include <mitsuba/render/shape.h>
#include <mitsuba/render/shader.h>
MTS_NAMESPACE_BEGIN
class Scene;
/**
* Data structure used to record information associated with
* sampled shadow rays
*/
struct MTS_EXPORT_RENDER LuminaireSamplingRecord {
public:
/// Create an invalid record
inline LuminaireSamplingRecord() : luminaire(NULL) { }
/**
* When a ray strikes a luminaire that is part of the scene,
* the associated intersection record can be converted into
* a luminaire sampling record in order to query the luminaire
* for emitted radiance. (defined in records.inl)
*/
LuminaireSamplingRecord(const Intersection &its, const Vector &direction);
/// Return a string representation
std::string toString() const;
public:
/// Associated luminaire
const Luminaire *luminaire;
/// Data record of the associated shape sample
ShapeSamplingRecord sRec;
/// Direction vector pointing away from the light source
Vector d;
/// Probability density of the sampled point on the luminaire
Float pdf;
/**
* Emitted radiance at 'p' into direction 'd' divided by the associated
* probability. Already contains the geometric term and optionally
* attenuation when generated via Scene::sampleLuminaireAttenuated.
*/
Spectrum Le;
};
/**
* Data structure used to record information associated with
* luminaire emission sampling
*/
struct MTS_EXPORT_RENDER EmissionRecord {
public:
enum ESamplingType {
ENormal,
EPreview
};
/// Construct a luminaire sampling record that can be used to query a luminaire
inline EmissionRecord(const Luminaire *luminaire,
const ShapeSamplingRecord &sRec, const Vector &d)
: luminaire(luminaire), type(ENormal), sRec(sRec), d(d) { }
inline EmissionRecord() : luminaire(NULL), type(ENormal) { }
/// Return a string representation
std::string toString() const;
public:
/// Associated luminaire
const Luminaire *luminaire;
ESamplingType type;
/// Data record of the associated shape sample
ShapeSamplingRecord sRec;
/// Direction vector pointing away from the light source
Vector d;
/**
* Radiant emittance at the sampled point. When this
* record was populated using Scene::sampleEmission(), 'P'
* has already been multiplied by the directional
* scattering distribution and divided by the associated
* sampling densities.
*/
Spectrum P;
/// Area probability density
Float pdfArea;
/// Directional probability density (wrt. projected solid angles)
Float pdfDir;
};
/**
* Abstract implementation of a luminaire. Supports emission and

View File

@ -21,16 +21,63 @@
#include <mitsuba/core/netobject.h>
#include <mitsuba/core/aabb.h>
#include <mitsuba/render/records.h>
MTS_NAMESPACE_BEGIN
/**
* Data record associated with the sampling procedure responsible for
* choosing a point on the in-scattering line integral (while solving
* the radiative transfer equation using Monte Carlo methods).
*/
struct MTS_EXPORT_RENDER MediumSamplingRecord {
public:
inline MediumSamplingRecord() : medium(NULL) { }
class Scene;
class Sampler;
class RenderQueue;
class RenderJob;
/// Return a string representation
std::string toString() const;
public:
/* Traveled distance */
Float t;
/** \brief Abstract phase function
/* Interaction point */
Point p;
/* Local particle orientation */
Vector orientation;
/* Reference to the associated medium */
const Medium *medium;
/* Specifies the attenuation along the segment [mint, t].
When sampling a distance fails, this contains the
attenuation along the whole ray.
*/
Spectrum attenuation;
/* The medium's absorption coefficient at that point */
Spectrum sigmaA;
/* The medium's scattering coefficient at that point */
Spectrum sigmaS;
/**
* Can contain two things:
* If a medium interaction occurred, this records the probability
* of having sampled the point p. Otherwise, it contains the
* probability of moving through the medium without an interaction.
*/
Float pdf;
/// Max. albedo over all spectral samples
Float albedo;
/// Multiple importance sampling weight
Float miWeight;
};
/** \brief Abstract phase function.
*
* The convention used here is that the incident and exitant
* direction arguments point away from the scattering event (similar to BSDFs).
*/
class MTS_EXPORT_RENDER PhaseFunction : public ConfigurableObject {
public:
@ -39,7 +86,7 @@ public:
EDelta
};
/// Evaluate the phase function for a pair of directions (wi, wo)
/// Evaluate the phase function for an outward-pointing pair of directions (wi, wo)
virtual Spectrum f(const MediumSamplingRecord &mRec, const Vector &wi, const Vector &wo) const = 0;
/**

View File

@ -19,8 +19,8 @@
#if !defined(__MIPMAP_H)
#define __MIPMAP_H
#include <mitsuba/render/records.h>
#include <mitsuba/core/bitmap.h>
#include <mitsuba/render/shape.h>
MTS_NAMESPACE_BEGIN
@ -66,6 +66,14 @@ public:
/// Return a pointer to internal image representation at full resolution
inline const Spectrum *getImageData() const { return m_pyramid[0]; }
/// Return a pointer to internal image representation at the specified resolution
inline const Spectrum *getImageData(int level) const { return m_pyramid[level]; }
/// Return the resolution of the specified level
inline const Vector2i getLevelResolution(int level) const {
return Vector2i(m_levelWidth[level], m_levelHeight[level]);
}
/// Get the component-wise maximum at the zero level
Spectrum getMaximum() const;
@ -78,10 +86,12 @@ public:
MTS_DECLARE_CLASS()
protected:
/// \cond
struct ResampleWeight {
int firstTexel;
Float weight[4];
};
/// \endcond
/// Calculate weights for up-sampling a texture
ResampleWeight *resampleWeights(int oldRes, int newRes) const;

View File

@ -20,6 +20,7 @@
#define __MIPMAP3D_H
#include <mitsuba/core/aabb.h>
#include <mitsuba/core/cobject.h>
MTS_NAMESPACE_BEGIN
@ -82,6 +83,7 @@ public:
MTS_DECLARE_CLASS()
protected:
/// \cond
struct QueryContext {
uint8_t a; // ray directionality flag
Float maxt;
@ -99,6 +101,7 @@ protected:
int32_t child[8];
float value;
};
/// \endcond
uint32_t build(int level, const Point3i &p, float **pyramid,
std::vector<bool> *bitPyramid);

View File

@ -19,8 +19,8 @@
#if !defined(__PHOTONMAP_H)
#define __PHOTONMAP_H
#include <mitsuba/core/serialization.h>
#include <mitsuba/core/aabb.h>
#include <mitsuba/render/records.h>
MTS_NAMESPACE_BEGIN
@ -313,7 +313,9 @@ public:
#if defined(DOUBLE_PRECISION) || SPECTRUM_SAMPLES > 3
return power;
#else
return Spectrum(power);
Spectrum result;
result.fromRGBE(power);
return result;
#endif
}
@ -358,6 +360,7 @@ protected:
typedef std::vector<photon_ptr>::iterator photon_iterator;
typedef std::pair<float, const_photon_ptr> search_result;
/// \cond
/* Photon position comparison functor (< comparison). */
struct comparePhotonLess : public std::unary_function<photon_ptr, bool> {
public:
@ -397,6 +400,8 @@ protected:
return a.first <= b.first;
}
};
/// \endcond
protected:
/* ===================================================================== */
/* Protected subroutines */
@ -466,11 +471,10 @@ protected:
inline size_t rightChild(size_t index) const { return 2*index + 1; }
inline bool isInnerNode(size_t index) const { return index <= m_lastInnerNode; }
inline bool hasRightChild(size_t index) const { return index <= m_lastRChildNode; }
protected:
private:
/* ===================================================================== */
/* Protected attributes */
/* ===================================================================== */
struct ThreadContext {
AABB aabb;
int photonOffset;

View File

@ -1,556 +0,0 @@
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2010 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba 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/>.
*/
#if !defined(__RECORDS_H)
#define __RECORDS_H
#include <mitsuba/core/frame.h>
MTS_NAMESPACE_BEGIN
class Shape;
class Luminaire;
class Medium;
class Scene;
class Sampler;
class BSDF;
/**
* Specifies the transported quantity when sampling a BSDF
*/
enum ETransportQuantity {
ERadiance = 1,
EImportance = 2
};
/** \brief Container for all information related to
* a surface intersection
*/
struct MTS_EXPORT_RENDER Intersection {
public:
inline Intersection() : t(std::numeric_limits<Float>::infinity()), shape(NULL) {
}
/* Convert a vector expressed inside the shading frame into world
coordinates */
inline Vector toWorld(const Vector &v) const {
return shFrame.toWorld(v);
}
/* Convert a vector expressed inside world coordinates frame into
shading frame coordinates */
inline Vector toLocal(const Vector &v) const {
return shFrame.toLocal(v);
}
/// Is the current intersection valid?
inline bool isValid() const {
return t != std::numeric_limits<Float>::infinity();
}
/// Is the intersected shape also a luminaire?
inline bool isLuminaire() const;
/// Does the intersected shape have a subsurface integrator?
inline bool hasSubsurface() const;
/**
* Returns the BSDF of the intersected shape. The
* parameter ray must match the one used to create
* the intersection record. Computes texture coordinate
* partials if this is required by the BSDF.
* Should only be called if there is a valid
* intersection!
*/
inline const BSDF *getBSDF(const RayDifferential &ray);
/**
* Returns radiance emitted into direction d.
* Should only be called if the intersected
* shape is indeed a luminaire!
*/
inline Spectrum Le(const Vector &d) const;
/**
* Returns radiance from a subsurface integrator
* emitted into direction d.
* Should only be called if the intersected
* shape does indeed have a subsurface integrator!
*/
inline Spectrum LoSub(const Scene *scene, const Vector &d) const;
/// Computes texture coordinate partials
void computePartials(const RayDifferential &ray);
/* Return a string representation */
std::string toString() const;
public:
/* Incident direction in the local frame */
Vector wi;
/* Distance traveled along the ray */
Float t;
/* Intersection point in 3D coordinates */
Point p;
/* Geometry frame */
Frame geoFrame;
/* Shading frame */
Frame shFrame;
/* UV surface coordinates */
Point2 uv;
/* Position partials wrt. to changes in texture-space */
Vector dpdu, dpdv;
/* Texture coordinate mapping partials wrt. changes in screen-space */
Float dudx, dudy, dvdx, dvdy;
/* Affected shape */
const Shape *shape;
/* Have texture coordinate partials been computed */
bool hasUVPartials;
};
struct MTS_EXPORT_RENDER ShapeSamplingRecord {
public:
inline ShapeSamplingRecord() { }
inline ShapeSamplingRecord(const Point &p, const Normal &n)
: p(p), n(n) { }
/// Return a string representation
std::string toString() const;
public:
/// Sampled surface position
Point p;
/// Sampled surface normal
Normal n;
};
/**
* Data structure used to record information associated with
* sampled shadow rays
*/
struct MTS_EXPORT_RENDER LuminaireSamplingRecord {
public:
/// Create an invalid record
inline LuminaireSamplingRecord() : luminaire(NULL) { }
/**
* When a ray strikes a luminaire that is part of the scene,
* the associated intersection record can be converted into
* a luminaire sampling record in order to query the luminaire
* for emitted radiance. (defined in shape.h)
*/
inline LuminaireSamplingRecord(const Intersection &its, const Vector &direction);
/// Return a string representation
std::string toString() const;
public:
/// Associated luminaire
const Luminaire *luminaire;
/// Data record of the associated shape sample
ShapeSamplingRecord sRec;
/// Direction vector pointing away from the light source
Vector d;
/// Probability density of the sampled point on the luminaire
Float pdf;
/**
* Emitted radiance at 'p' into direction 'd' divided by the associated
* probability. Already contains the geometric term and optionally
* attenuation when generated via Scene::sampleLuminaireAttenuated.
*/
Spectrum Le;
};
struct MTS_EXPORT_RENDER EmissionRecord {
public:
enum ESamplingType {
ENormal,
EPreview
};
/// Construct a luminaire sampling record that can be used to query a luminaire
inline EmissionRecord(const Luminaire *luminaire,
const ShapeSamplingRecord &sRec, const Vector &d)
: luminaire(luminaire), type(ENormal), sRec(sRec), d(d) { }
inline EmissionRecord() : luminaire(NULL), type(ENormal) { }
/// Return a string representation
std::string toString() const;
public:
/// Associated luminaire
const Luminaire *luminaire;
ESamplingType type;
/// Data record of the associated shape sample
ShapeSamplingRecord sRec;
/// Direction vector pointing away from the light source
Vector d;
/**
* Radiant emittance at the sampled point. When this
* record was populated using Scene::sampleEmission(), 'P'
* has already been multiplied by the directional
* scattering distribution and divided by the associated
* sampling densities.
*/
Spectrum P;
/// Area probability density
Float pdfArea;
/// Directional probability density (wrt. projected solid angles)
Float pdfDir;
};
/**
* Data record associated with the sampling procedure responsible for
* choosing a point on the in-scattering line integral (while solving
* the radiative transfer equation using Monte Carlo methods).
*/
struct MTS_EXPORT_RENDER MediumSamplingRecord {
public:
inline MediumSamplingRecord() : medium(NULL) { }
/// Return a string representation
std::string toString() const;
public:
/* Traveled distance */
Float t;
/* Interaction point */
Point p;
/* Local particle orientation */
Vector orientation;
/* Reference to the associated medium */
const Medium *medium;
/* Specifies the attenuation along the segment [mint, t].
When sampling a distance fails, this contains the
attenuation along the whole ray.
*/
Spectrum attenuation;
/* The medium's absorption coefficient at that point */
Spectrum sigmaA;
/* The medium's scattering coefficient at that point */
Spectrum sigmaS;
/**
* Can contain two things:
* If a medium interaction occurred, this records the probability
* of having sampled the point p. Otherwise, it contains the
* probability of moving through the medium without an interaction.
*/
Float pdf;
/// Max. albedo over all spectral samples
Float albedo;
/// Multiple importance sampling weight
Float miWeight;
};
struct MTS_EXPORT_RENDER RadianceQueryRecord {
public:
/**
* List of suported query types. These can be combined by a binary OR.
*/
enum ERadianceQuery {
/* Emitted radiance from a luminaire intersected by the ray */
EEmittedRadiance = 0x0001,
/* Emitted radiance from a subsurface integrator */
ESubsurfaceRadiance = 0x0002,
/* Direct (surface) radiance */
EDirectRadiance = 0x0004,
/* Indirect (surface) radiance, where the last bounce did not go
through a Dirac delta BSDF */
EIndirectRadiance = 0x0008,
/* Indirect (surface) radiance, where the last bounce went
through a Dirac delta BSDF */
ECausticRadiance = 0x0010,
/* In-scattered radiance due to volumetric scattering (direct) */
EInscatteredDirectRadiance = 0x0020,
/* In-scattered radiance due to volumetric scattering (indirect) */
EInscatteredIndirectRadiance = 0x0040,
/* Distance to the next surface intersection */
EDistance = 0x0080,
/* Opacity value: 1 when a surface was hit, 0 when the ray leads
into empty space. When there is a participating medium,
this can also take on fractional values. */
EOpacity = 0x0100,
/* A ray intersection may need to be performed. This can be set to
zero if the caller has already provided the intersection */
EIntersection = 0x0200,
/* Radiance from volumes */
EVolumeRadiance = EInscatteredDirectRadiance | EInscatteredIndirectRadiance,
/* Radiance query without emitted radiance, ray intersection required */
ERadianceNoEmission = ESubsurfaceRadiance | EDirectRadiance | EIndirectRadiance
| ECausticRadiance | EInscatteredDirectRadiance | EInscatteredIndirectRadiance | EIntersection,
/* Default radiance query, ray intersection required */
ERadiance = ERadianceNoEmission | EEmittedRadiance,
/* Radiance + opacity */
ECameraRay = ERadiance | EOpacity
};
/// Construct an invalid radiance query record
inline RadianceQueryRecord()
: type(0), scene(NULL), sampler(NULL),
depth(0), alpha(0), dist(-1), wavelength(-1), extra(0) {
}
/// Construct a radiance query record for the given scene and sampler
inline RadianceQueryRecord(const Scene *scene, Sampler *sampler)
: type(0), scene(scene), sampler(sampler),
depth(0), alpha(0), dist(-1), wavelength(-1), extra(0) {
}
/// Copy constructor
inline RadianceQueryRecord(const RadianceQueryRecord &rRec)
: type(rRec.type), scene(rRec.scene), sampler(rRec.sampler),
depth(rRec.depth), alpha(rRec.alpha), dist(rRec.dist),
wavelength(rRec.wavelength), extra(rRec.extra) {
}
/// Begin a new query of the given type
inline void newQuery(int _type) {
type = _type;
depth = 1;
wavelength = -1;
extra = 0;
}
/// Initialize the query record for a recursive query
inline void recursiveQuery(const RadianceQueryRecord &parent, int _type) {
type = _type;
scene = parent.scene;
sampler = parent.sampler;
depth = parent.depth+1;
wavelength = parent.wavelength;
extra = 0;
}
/**
* Search for a ray intersection (in records.inl). This
* does several things at once - if the intersection has
* already been provided, the function returns.
* Otherwise, it
* - performs the ray intersection
* - computes the attenuation due to participating media
* and stores it in <tt>attenuation</tt>.
* - sets the alpha value (if <tt>EAlpha</tt> is set in <tt>type</tt>)
* - sets the distance value (if <tt>EDistance</tt> is set in <tt>type</tt>)
* - clears the <tt>EIntersection</tt> flag in <tt>type</tt>
* Returns true if there is a valid intersection.
*/
inline bool rayIntersect(const RayDifferential &ray);
/// Retrieve a 2D sample
inline Point2 nextSample2D();
/// Retrieve a 1D sample
inline Float nextSample1D();
/// Return a string representation
std::string toString() const;
public:
// An asterisk (*) marks entries, which may be overwritten
// by the callee.
/// Query type (*)
int type;
/// Pointer to the associated scene
const Scene *scene;
/// Sample generator
Sampler *sampler;
/// Current depth value (# of light bounces) (*)
int depth;
/// Surface interaction data structure (*)
Intersection its;
/// Attenuation along the current ray (*)
Spectrum attenuation;
/// Opacity value of the associated pixel (*)
Float alpha;
/**
* Ray distance to the first surface interaction
* (if requested by the query type EDistance) (*)
*/
Float dist;
/**
* In some cases, the integrator may be forced to restrict
* radiance computations to one wavelength (e.g. when intersecting
* a dielectric material with dispersion or while path
* tracing through a highly scattering medium with a non-constant
* scattering coefficient). This attribute is used to store the
* chosen wavelength. (*)
*/
int wavelength;
/**
* Internal flag, which can be used to pass additional information
* amonst recursive calls inside an integrator. The use
* is dependent on the particular integrator implementation. (*)
*/
int extra;
};
/**
* Data structure, which contains all information required to
* sample or query a BSDF.
*/
struct MTS_EXPORT_RENDER BSDFQueryRecord {
public:
/**
* Given a surface interaction and an incident direction
* construct a query record which can be used to sample
* an outgoing direction.
* For convenience, this function uses the local incident direction
* vector contained in the supplied intersection record.
*/
explicit inline BSDFQueryRecord(RadianceQueryRecord &rRec, const Intersection &its, Point2 sample)
: rRec(&rRec), its(its), wi(its.wi), sample(sample), quantity(ERadiance),
typeMask(0xFFFFFFFF), sampledType(0), component(-1), sampledComponent(-1) {
}
/**
* Given a surface interaction and an incident direction,
* construct a query record which can be used to sample
* an outgoing direction.
* For convenience, this function uses the local incident direction
* vector contained in the supplied intersection record.
*/
explicit inline BSDFQueryRecord(const Intersection &its, Point2 sample)
: rRec(NULL), its(its), wi(its.wi), sample(sample), quantity(ERadiance),
typeMask(0xFFFFFFFF), sampledType(0), component(-1), sampledComponent(-1) {
}
/**
* Given a surface interaction an an incident/exitant direction
* pair (wi, wo), create a BSDF query record to evaluate f(wi, wo).
* For convenience, this function uses the local incident direction
* vector contained in the supplied intersection record.
*/
explicit inline BSDFQueryRecord(RadianceQueryRecord &rRec,
const Intersection &its, const Vector &wo)
: rRec(&rRec), its(its), wi(its.wi), wo(wo), sample(sample), quantity(ERadiance),
typeMask(0xFFFFFFFF), sampledType(0), component(-1), sampledComponent(-1) {
}
/**
* Given a surface interaction an an incident/exitant direction
* pair (wi, wo), create a BSDF query record to evaluate f(wi, wo).
* For convenience, this function uses the local incident direction
* vector contained in the supplied intersection record.
*/
explicit inline BSDFQueryRecord(const Intersection &its, const Vector &wo)
: rRec(NULL), its(its), wi(its.wi), wo(wo), sample(sample), quantity(ERadiance),
typeMask(0xFFFFFFFF), sampledType(0), component(-1), sampledComponent(-1) {
}
/**
* Given a surface interaction an an incident/exitant direction
* pair (wi, wo), create a BSDF query record to evaluate f(wi, wo).
*/
explicit inline BSDFQueryRecord(const Intersection &its, const Vector &wi, const Vector &wo)
: rRec(NULL), its(its), wi(wi), wo(wo), sample(sample), quantity(ERadiance),
typeMask(0xFFFFFFFF), sampledType(0), component(-1), sampledComponent(-1) {
}
inline BSDFQueryRecord(const BSDFQueryRecord &r) :
rRec(r.rRec), its(r.its), wi(r.wi), wo(r.wo), sample(r.sample), quantity(r.quantity),
typeMask(r.typeMask), sampledType(r.sampledType), component(r.component),
sampledComponent(r.sampledComponent) {
}
/// Return a string representation
std::string toString() const;
public:
/* Pointer to the associated radiance query record (or NULL) */
RadianceQueryRecord *rRec;
/* Surface interaction */
const Intersection &its;
/* Incident direction */
Vector wi;
/* Outgoing/sampled direction */
Vector wo;
/* Random sample used to generate the new direction */
Point2 sample;
/* Transported quantity (radiance or importance) -- required for
non-reciprocal BSDFs such as transmission through a dielectric
material */
ETransportQuantity quantity;
/* Bit mask containing the component types, which may be sampled.
After sampling has been performed, the component type is stored
inside 'sampledType'. */
unsigned int typeMask, sampledType;
/* To sample a specific BSDF component, this entry must be non-negative.
After sampling has been performed, the component index is stored
inside 'sampledComponent' */
int component, sampledComponent;
};
extern void operator<<(const ETransportQuantity &quantity, std::ostream &os);
MTS_NAMESPACE_END
#endif /* __RECORDS_H */

View File

@ -2,6 +2,33 @@
#define __RECORDS_INLINE_H
MTS_NAMESPACE_BEGIN
inline BSDFQueryRecord::BSDFQueryRecord(RadianceQueryRecord &rRec,
const Intersection &its, Point2 sample): rRec(&rRec),
its(its), wi(its.wi), sample(sample), quantity(ERadiance),
typeMask(0xFFFFFFFF), sampledType(0), component(-1), sampledComponent(-1) {
}
inline BSDFQueryRecord::BSDFQueryRecord(const Intersection &its, Point2 sample)
: rRec(NULL), its(its), wi(its.wi), sample(sample), quantity(ERadiance),
typeMask(0xFFFFFFFF), sampledType(0), component(-1), sampledComponent(-1) {
}
inline BSDFQueryRecord::BSDFQueryRecord(RadianceQueryRecord &rRec,
const Intersection &its, const Vector &wo)
: rRec(&rRec), its(its), wi(its.wi), wo(wo), sample(sample), quantity(ERadiance),
typeMask(0xFFFFFFFF), sampledType(0), component(-1), sampledComponent(-1) {
}
inline BSDFQueryRecord::BSDFQueryRecord(const Intersection &its, const Vector &wo)
: rRec(NULL), its(its), wi(its.wi), wo(wo), sample(sample), quantity(ERadiance),
typeMask(0xFFFFFFFF), sampledType(0), component(-1), sampledComponent(-1) {
}
inline BSDFQueryRecord::BSDFQueryRecord(const Intersection &its, const Vector &wi, const Vector &wo)
: rRec(NULL), its(its), wi(wi), wo(wo), sample(sample), quantity(ERadiance),
typeMask(0xFFFFFFFF), sampledType(0), component(-1), sampledComponent(-1) {
}
inline bool Intersection::hasSubsurface() const {
return shape->hasSubsurface();

View File

@ -62,7 +62,6 @@ private:
ref<Scene> m_scene;
ref<RenderQueue> m_queue;
ref<TestSupervisor> m_testSupervisor;
ref<FileResolver> m_fileResolver;
int m_sceneResID, m_samplerResID, m_cameraResID;
bool m_ownsSceneResource;
bool m_ownsCameraResource;

View File

@ -25,8 +25,6 @@
MTS_NAMESPACE_BEGIN
class RenderJob;
/**
* Parallel process for rendering with sampling-based integrators. Splits
* an image into square pixel regions, which can be processed independently.

View File

@ -24,8 +24,6 @@
MTS_NAMESPACE_BEGIN
class RenderJob;
/**
* Abstract render listener - can be used to react to
* progress messages (e.g. in a GUI)
@ -96,7 +94,7 @@ public:
private:
/// Virtual destructor
virtual ~RenderQueue();
protected:
private:
struct JobRecord {
/* Only starting time for now */
unsigned int startTime;

View File

@ -19,7 +19,8 @@
#if !defined(__RFILTER_H)
#define __RFILTER_H
#include <mitsuba/mitsuba.h>
#include <mitsuba/core/cobject.h>
#include <mitsuba/core/properties.h>
MTS_NAMESPACE_BEGIN

View File

@ -21,6 +21,7 @@
#include <mitsuba/mitsuba.h>
#include <mitsuba/core/random.h>
#include <mitsuba/core/properties.h>
MTS_NAMESPACE_BEGIN

View File

@ -19,11 +19,17 @@
#if !defined(__SCENE_H)
#define __SCENE_H
#include <mitsuba/core/fresolver.h>
#include <mitsuba/render/camera.h>
#include <mitsuba/core/netobject.h>
#include <mitsuba/core/pdf.h>
#include <mitsuba/core/aabb.h>
#include <mitsuba/render/trimesh.h>
#include <mitsuba/render/kdtree.h>
#include <mitsuba/render/camera.h>
#include <mitsuba/render/luminaire.h>
#include <mitsuba/render/integrator.h>
#include <mitsuba/render/bsdf.h>
#include <mitsuba/render/subsurface.h>
#include <mitsuba/render/texture.h>
#include <mitsuba/render/medium.h>
MTS_NAMESPACE_BEGIN
@ -80,7 +86,7 @@ public:
* which have been made available to all local and remote workers.
* Returns true upon successful completion.
*/
void preprocess(RenderQueue *queue, const RenderJob *job,
bool preprocess(RenderQueue *queue, const RenderJob *job,
int sceneResID, int cameraResID, int samplerResID);
/**
@ -366,13 +372,13 @@ public:
inline const std::vector<ConfigurableObject *> &getReferencedObjects() const { return m_objects; }
/// Return the name of the file containing the original description of this scene
inline const std::string getSourceFile() const { return m_sourceFile; }
inline const fs::path getSourceFile() const { return m_sourceFile; }
/// Set the name of the file containing the original description of this scene
void setSourceFile(const std::string &name) { m_sourceFile = name; }
void setSourceFile(const fs::path &name) { m_sourceFile = name; }
/// Return the render output filename
inline const std::string getDestinationFile() const { return m_destinationFile; }
inline const fs::path getDestinationFile() const { return m_destinationFile; }
/// Set the render output filename
void setDestinationFile(const std::string &name) { m_destinationFile = name; }
void setDestinationFile(const fs::path &name) { m_destinationFile = name; }
/// Does the destination file already exist?
inline bool destinationExists() const { return m_camera->getFilm()->destinationExists(m_destinationFile); }
@ -410,8 +416,8 @@ private:
std::vector<Subsurface *> m_ssIntegrators;
std::vector<ConfigurableObject *> m_objects;
std::vector<NetworkedObject *> m_netObjects;
std::string m_sourceFile;
std::string m_destinationFile;
fs::path m_sourceFile;
fs::path m_destinationFile;
DiscretePDF m_luminairePDF;
AABB m_aabb;
BSphere m_bsphere;

View File

@ -36,6 +36,8 @@ class GPUProgram;
class MTS_EXPORT_RENDER HWResource {
public:
virtual Shader *createShader(Renderer *renderer) const;
virtual ~HWResource() { }
};
/**

View File

@ -19,16 +19,128 @@
#if !defined(__SHAPE_H)
#define __SHAPE_H
#include <mitsuba/core/bsphere.h>
#include <mitsuba/core/cobject.h>
#include <mitsuba/core/transform.h>
#include <mitsuba/core/frame.h>
#include <mitsuba/core/aabb.h>
#include <mitsuba/core/serialization.h>
#include <mitsuba/render/records.h>
#include <mitsuba/render/bsdf.h>
#include <mitsuba/render/luminaire.h>
#include <mitsuba/render/subsurface.h>
MTS_NAMESPACE_BEGIN
/** \brief Data record, which holds sampling-related information
* for a shape.
*/
struct MTS_EXPORT_RENDER ShapeSamplingRecord {
public:
/// Create a sampling record (does no initialization!)
inline ShapeSamplingRecord() { }
/// Create a sampling record with the specified position and normal
inline ShapeSamplingRecord(const Point &p, const Normal &n)
: p(p), n(n) { }
/// Return a string representation
std::string toString() const;
public:
/// Sampled surface position
Point p;
/// Sampled surface normal
Normal n;
};
/** \brief Container for all information related to
* a surface intersection
*/
struct MTS_EXPORT_RENDER Intersection {
public:
inline Intersection() : t(std::numeric_limits<Float>::infinity()), shape(NULL) {
}
/* Convert a vector expressed inside the shading frame into world
coordinates */
inline Vector toWorld(const Vector &v) const {
return shFrame.toWorld(v);
}
/* Convert a vector expressed inside world coordinates frame into
shading frame coordinates */
inline Vector toLocal(const Vector &v) const {
return shFrame.toLocal(v);
}
/// Is the current intersection valid?
inline bool isValid() const {
return t != std::numeric_limits<Float>::infinity();
}
/// Is the intersected shape also a luminaire?
inline bool isLuminaire() const;
/// Does the intersected shape have a subsurface integrator?
inline bool hasSubsurface() const;
/**
* Returns the BSDF of the intersected shape. The
* parameter ray must match the one used to create
* the intersection record. Computes texture coordinate
* partials if this is required by the BSDF.
* Should only be called if there is a valid
* intersection!
*/
inline const BSDF *getBSDF(const RayDifferential &ray);
/**
* Returns radiance emitted into direction d.
* Should only be called if the intersected
* shape is indeed a luminaire!
*/
inline Spectrum Le(const Vector &d) const;
/**
* Returns radiance from a subsurface integrator
* emitted into direction d.
* Should only be called if the intersected
* shape does indeed have a subsurface integrator!
*/
inline Spectrum LoSub(const Scene *scene, const Vector &d) const;
/// Computes texture coordinate partials
void computePartials(const RayDifferential &ray);
/* Return a string representation */
std::string toString() const;
public:
/* Incident direction in the local frame */
Vector wi;
/* Distance traveled along the ray */
Float t;
/* Intersection point in 3D coordinates */
Point p;
/* Geometry frame */
Frame geoFrame;
/* Shading frame */
Frame shFrame;
/* UV surface coordinates */
Point2 uv;
/* Position partials wrt. to changes in texture-space */
Vector dpdu, dpdv;
/* Texture coordinate mapping partials wrt. changes in screen-space */
Float dudx, dudy, dvdx, dvdy;
/* Affected shape */
const Shape *shape;
/* Have texture coordinate partials been computed */
bool hasUVPartials;
};
/** \brief Abstract base class of all shapes
*/
class MTS_EXPORT_RENDER Shape : public ConfigurableObject {
@ -82,16 +194,15 @@ public:
/**
* Sample a point on the shape - should be uniform
* wrt. solid angle. Returns the associated probability
* wrt. solid angle as seen from \a x. Returns the associated probability
* density
*/
virtual Float sampleSolidAngle(ShapeSamplingRecord &sRec, const Point &from, const Point2 &sample) const;
virtual Float sampleSolidAngle(ShapeSamplingRecord &sRec, const Point &x, const Point2 &sample) const;
/**
* Return the probability density of sampling the
* given point using sampleSolidAngle()
* Return the probability density of sampling the given point using sampleSolidAngle()
*/
virtual Float pdfSolidAngle(const ShapeSamplingRecord &sRec, const Point &from) const;
virtual Float pdfSolidAngle(const ShapeSamplingRecord &sRec, const Point &x) const;
/// Return the shape's surface area
inline Float getSurfaceArea() const { return m_surfaceArea; }
@ -150,3 +261,5 @@ protected:
MTS_NAMESPACE_END
#endif /* __SHAPE_H */

View File

@ -19,15 +19,10 @@
#if !defined(__SUBSURFACE_H)
#define __SUBSURFACE_H
#include <mitsuba/render/records.h>
#include <mitsuba/core/netobject.h>
MTS_NAMESPACE_BEGIN
class Scene;
class RenderQueue;
class RenderJob;
/**
* Abstract subsurface integrator -- can be attached to an arbitrary
* shape to compute exitant radiance due to internal scattering.
@ -39,9 +34,12 @@ public:
* resource IDs of the associated scene, camera and sample generator,
* which have been made available to all local and remote workers.
*/
virtual void preprocess(const Scene *scene, RenderQueue *queue, const RenderJob *job,
virtual bool preprocess(const Scene *scene, RenderQueue *queue, const RenderJob *job,
int sceneResID, int cameraResID, int samplerResID) = 0;
/// Cancel any running pre-process tasks
virtual void cancel() = 0;
/// Return the list of shapes associated with this subsurface integrator
inline const std::vector<Shape *> getShapes() const { return m_shapes; }

View File

@ -122,7 +122,7 @@ protected:
private:
struct TestResult {
bool success;
std::string input, output;
fs::path input, output;
std::string message;
};

View File

@ -19,7 +19,7 @@
#if !defined(__TEXTURE_H)
#define __TEXTURE_H
#include <mitsuba/render/records.h>
#include <mitsuba/core/cobject.h>
#include <mitsuba/render/shader.h>
MTS_NAMESPACE_BEGIN
@ -40,45 +40,6 @@ protected:
virtual ~Texture();
};
class MTS_EXPORT_RENDER ConstantTexture : public Texture {
public:
inline ConstantTexture(const Spectrum &value)
: Texture(Properties()), m_value(value) {
}
ConstantTexture(Stream *stream, InstanceManager *manager);
inline Spectrum getValue(const Intersection &its) const {
return m_value;
}
inline Spectrum getAverage() const {
return m_value;
}
inline Spectrum getMaximum() const {
return m_value;
}
inline std::string toString() const {
std::ostringstream oss;
oss << "ConstantTexture[value=" << m_value.toString() << "]";
return oss.str();
}
inline bool usesRayDifferentials() const {
return false;
}
Shader *createShader(Renderer *renderer) const;
void serialize(Stream *stream, InstanceManager *manager) const;
MTS_DECLARE_CLASS()
protected:
Spectrum m_value;
};
MTS_NAMESPACE_END
#endif /* __TEXTURE_H */

View File

@ -83,7 +83,7 @@ inline int TriAccel::load(const Point &A, const Point &B, const Point &C) {
/* Pre-compute intersection calculation constants */
n_u = N[u] / n_k;
n_v = N[v] / n_k;
n_d = dot(A, N) / n_k;
n_d = dot(Vector(A), N) / n_k;
b_nu = b[u] / denom;
b_nv = -b[v] / denom;
a_u = A[u];

View File

@ -171,7 +171,7 @@ inline int TriAccel4::load(const Point *A, const Point *B, const Point *C,
constants */
nu[i] = N[u] / n_k;
nv[i] = N[v] / n_k;
nd[i] = dot(A[i], N) / n_k;
nd[i] = dot(Vector(A[i]), N) / n_k;
bnu[i] = b[u] / denom;
bnv[i] = -b[v] / denom;
au[i] = A[i][u];

View File

@ -19,7 +19,7 @@
#if !defined(__VOLUME_H)
#define __VOLUME_H
#include <mitsuba/core/fstream.h>
#include <mitsuba/core/cobject.h>
#include <mitsuba/core/aabb.h>
MTS_NAMESPACE_BEGIN

View File

@ -17,7 +17,7 @@
*/
#include <mitsuba/render/bsdf.h>
#include <mitsuba/render/texture.h>
#include <mitsuba/render/consttexture.h>
#include <mitsuba/hw/renderer.h>
MTS_NAMESPACE_BEGIN

View File

@ -17,15 +17,26 @@
*/
#include <mitsuba/render/bsdf.h>
#include <mitsuba/render/texture.h>
#include <mitsuba/render/consttexture.h>
#include <mitsuba/core/properties.h>
#include <mitsuba/hw/renderer.h>
MTS_NAMESPACE_BEGIN
/*!
The Lambertian material represents a one-sided ideal diffuse material
with the specified amount of reflectance. Optionally, a texture map may
be applied. If no extra information is provided, the material will revert to
the default of uniform 50% reflectance.
/**
* Simple one-sided Lambertian (i.e. perfectly diffuse) material
*/
Seen from the back side, this material will appear completely black.
\verbatim
<bsdf type="lambertian">
<srgb name="reflectance" value="#a4da85"/>
</bsdf>
\endverbatim
*/
class Lambertian : public BSDF {
public:
Lambertian(const Properties &props)

View File

@ -17,7 +17,7 @@
*/
#include <mitsuba/render/bsdf.h>
#include <mitsuba/render/texture.h>
#include <mitsuba/render/consttexture.h>
#include <mitsuba/hw/renderer.h>
MTS_NAMESPACE_BEGIN

View File

@ -17,7 +17,7 @@
*/
#include <mitsuba/render/bsdf.h>
#include <mitsuba/render/texture.h>
#include <mitsuba/render/consttexture.h>
#include <mitsuba/hw/gpuprogram.h>
MTS_NAMESPACE_BEGIN

View File

@ -17,7 +17,7 @@
*/
#include <mitsuba/render/bsdf.h>
#include <mitsuba/render/texture.h>
#include <mitsuba/render/consttexture.h>
#include <mitsuba/hw/gpuprogram.h>
MTS_NAMESPACE_BEGIN

View File

@ -327,7 +327,8 @@ public:
Frame mFrame(sampleBeckmannD(bRec.sample));
/* Perfect specular reflection along the microsurface normal */
refract(mFrame.toLocal(bRec.wi), bRec.wo, bRec.quantity);
if (refract(mFrame.toLocal(bRec.wi), bRec.wo, bRec.quantity) == 0)
return Spectrum(0.0f);
bRec.wo = mFrame.toWorld(bRec.wo);
bRec.sampledComponent = 1;
@ -335,7 +336,7 @@ public:
if (Frame::cosTheta(bRec.wi)*Frame::cosTheta(bRec.wo) >= 0)
return Spectrum(0.0f);
return f(bRec) / pdf(bRec);
}

View File

@ -17,7 +17,7 @@
*/
#include <mitsuba/render/bsdf.h>
#include <mitsuba/render/texture.h>
#include <mitsuba/render/consttexture.h>
#include <mitsuba/hw/gpuprogram.h>
MTS_NAMESPACE_BEGIN

View File

@ -16,20 +16,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define BOOST_FILESYSTEM_NO_LIB
#define BOOST_SYSTEM_NO_LIB
#include <mitsuba/mitsuba.h>
#include <mitsuba/render/trimesh.h>
#include <mitsuba/core/fresolver.h>
#include <mitsuba/core/fstream.h>
#include <dae.h>
#include <dom/domCOLLADA.h>
#include <dom/domProfile_COMMON.h>
#include <boost/filesystem.hpp>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#if defined(__OSX__)
#include <OpenGL/glu.h>
@ -48,7 +44,7 @@ enum ESourceType {
EVertexColors = 3,
ELast
};
struct Vec4 {
Float x, y, z, w;
@ -85,6 +81,7 @@ struct VertexData {
std::vector<Vec4 *> data;
std::vector<int> typeToOffset;
std::vector<int> typeToOffsetInStream;
std::vector<size_t> typeToCount;
VertexData() : glPos(NULL) {
}
@ -116,9 +113,12 @@ VertexData *fetchVertexData(Transform transform, std::ostream &os,
for (size_t i=0; i<result->nSources; ++i)
result->data[i] = NULL;
result->typeToOffset.resize(ELast);
result->typeToCount.resize(ELast);
result->typeToOffsetInStream.resize(ELast);
for (int i=0; i<ELast; ++i)
for (int i=0; i<ELast; ++i) {
result->typeToOffset[i] = result->typeToOffsetInStream[i] = -1;
result->typeToCount[i] = 0;
}
int vertInputIndex = 0;
for (size_t i=0; i<inputs.getCount(); ++i) {
@ -151,14 +151,14 @@ VertexData *fetchVertexData(Transform transform, std::ostream &os,
domAccessor *accessor = techniqueCommon->getAccessor();
if (!accessor)
SLog(EError, "Data source does not have a <accessor> tag!");
int nParams = (int) accessor->getParam_array().getCount(),
stride = (int) accessor->getStride(),
size = (int) accessor->getCount();
unsigned int nParams = (unsigned int) accessor->getParam_array().getCount(),
stride = (unsigned int) accessor->getStride();
size_t size = (size_t) accessor->getCount();
SAssert(nParams <= 4);
Vec4 *target = new Vec4[size];
for (int j=0; j<size; ++j)
for (int k=0; k<nParams; ++k)
for (size_t j=0; j<size; ++j)
for (unsigned int k=0; k<nParams; ++k)
target[j][k] = (Float) floatArray[j*stride+k];
result->data[offset] = target;
@ -167,9 +167,10 @@ VertexData *fetchVertexData(Transform transform, std::ostream &os,
SAssert(accessor->getStride() == 3);
SAssert(result->typeToOffset[EPosition] == -1);
result->typeToOffset[EPosition] = offset;
result->typeToCount[EPosition] = size;
result->typeToOffsetInStream[EPosition] = offsetInStream;
result->glPos = new GLdouble[3*size];
for (int k=0; k<3*size; ++k)
for (size_t k=0; k<3*size; ++k)
result->glPos[k] = floatArray[k];
} else if (semantic == "NORMAL") {
SAssert(accessor->getStride() == 3);
@ -177,12 +178,14 @@ VertexData *fetchVertexData(Transform transform, std::ostream &os,
result->hasNormals = true;
result->typeToOffset[ENormal] = offset;
result->typeToOffsetInStream[ENormal] = offsetInStream;
result->typeToCount[ENormal] = size;
} else if (semantic == "TEXCOORD") {
SAssert(accessor->getStride() == 2 || accessor->getStride() == 3);
if (result->typeToOffset[EUV] == -1) {
result->hasUVs = true;
result->typeToOffset[EUV] = offset;
result->typeToOffsetInStream[EUV] = offsetInStream;
result->typeToCount[EUV] = size;
} else {
SLog(EWarn, "Found multiple sets of texture coordinates - ignoring!");
}
@ -191,6 +194,7 @@ VertexData *fetchVertexData(Transform transform, std::ostream &os,
"(Lighting/shading -> Batch Bake in Maya)");
result->typeToOffset[EVertexColors] = offset;
result->typeToOffsetInStream[EVertexColors] = offsetInStream;
result->typeToCount[EVertexColors] = size;
} else {
SLog(EError, "Encountered an unknown source semantic: %s", semantic.c_str());
}
@ -204,12 +208,12 @@ VertexData *fetchVertexData(Transform transform, std::ostream &os,
struct vertex_key_order : public
std::binary_function<Vertex, Vertex, bool> {
static int compare(const Vertex &v1, const Vertex &v2) {
if (v1.v.x < v2.v.x) return -1;
else if (v1.v.x > v2.v.x) return 1;
if (v1.v.y < v2.v.y) return -1;
else if (v1.v.y > v2.v.y) return 1;
if (v1.v.z < v2.v.z) return -1;
else if (v1.v.z > v2.v.z) return 1;
if (v1.p.x < v2.p.x) return -1;
else if (v1.p.x > v2.p.x) return 1;
if (v1.p.y < v2.p.y) return -1;
else if (v1.p.y > v2.p.y) return 1;
if (v1.p.z < v2.p.z) return -1;
else if (v1.p.z > v2.p.z) return 1;
if (v1.n.x < v2.n.x) return -1;
else if (v1.n.x > v2.n.x) return 1;
if (v1.n.y < v2.n.y) return -1;
@ -264,7 +268,7 @@ struct triangle_key_order : public std::binary_function<SimpleTriangle, SimpleTr
typedef std::map<SimpleTriangle, bool, triangle_key_order> TriangleMap;
void writeGeometry(std::string prefixName, std::string id, int geomIndex, std::string matID, Transform transform,
std::ostream &os, VertexData *vData, TriangleMap &triMap, const std::string &meshesDirectory) {
std::ostream &os, VertexData *vData, TriangleMap &triMap, const fs::path &meshesDirectory) {
std::vector<Vertex> vertexBuffer;
std::vector<Triangle> triangles;
std::map<Vertex, int, vertex_key_order> vertexMap;
@ -278,16 +282,24 @@ void writeGeometry(std::string prefixName, std::string id, int geomIndex, std::s
for (size_t i=0; i<tess_data.size(); i+=tess_nSources) {
Vertex vertex;
domUint posRef = tess_data[i+vData->typeToOffsetInStream[EPosition]];
vertex.v = vData->data[vData->typeToOffset[EPosition]][posRef].toPoint();
vertex.p = vData->data[vData->typeToOffset[EPosition]][posRef].toPoint();
vertex.dpdu = vertex.dpdv = Vector(0.0f);
if (vData->typeToOffset[ENormal] != -1) {
domUint normalRef = tess_data[i+vData->typeToOffsetInStream[ENormal]];
vertex.n = vData->data[vData->typeToOffset[ENormal]][normalRef].toNormal();
} else {
vertex.n = Normal(0.0f);
}
if (vData->typeToOffset[EUV] != -1) {
domUint uvRef = tess_data[i+vData->typeToOffsetInStream[EUV]];
vertex.uv = vData->data[vData->typeToOffset[EUV]][uvRef].toPoint2();
#if 1
vertex.uv.y = 1-vertex.uv.y; // Invert the V coordinate
#endif
} else {
vertex.uv = Point2(0.0f);
}
int key = -1;
@ -299,11 +311,12 @@ void writeGeometry(std::string prefixName, std::string id, int geomIndex, std::s
vertexMap[vertex] = (int) key;
vertexBuffer.push_back(vertex);
}
triangle.idx[triangleIdx++] = key;
if (triangleIdx == 3) {
Point p0 = vertexBuffer[triangle.idx[0]].v,
p1 = vertexBuffer[triangle.idx[1]].v,
p2 = vertexBuffer[triangle.idx[2]].v;
Point p0 = vertexBuffer[triangle.idx[0]].p,
p1 = vertexBuffer[triangle.idx[1]].p,
p2 = vertexBuffer[triangle.idx[2]].p;
if (triMap.find(SimpleTriangle(p0, p1, p2)) != triMap.end() ||
triMap.find(SimpleTriangle(p2, p0, p1)) != triMap.end() ||
triMap.find(SimpleTriangle(p1, p2, p0)) != triMap.end() ||
@ -324,7 +337,8 @@ void writeGeometry(std::string prefixName, std::string id, int geomIndex, std::s
if (duplicates > 0) {
if (triangles.size() == 0) {
SLog(EWarn, "%s: Only contains duplicates of already-existing geometry. Ignoring.");
SLog(EWarn, "\"%s/%s\": Only contains duplicates (%i triangles) of already-existing geometry. Ignoring.",
prefixName.c_str(), id.c_str(), duplicates);
os << "\t<!-- Ignored shape \"" << prefixName << "/"
<< id << "\" (mat=\"" << matID << "\"), since it only contains duplicate geometry. -->" << endl << endl;
return;
@ -334,8 +348,8 @@ void writeGeometry(std::string prefixName, std::string id, int geomIndex, std::s
}
SAssert(triangleIdx == 0);
SLog(EInfo, "%s: Converted " SIZE_T_FMT " triangles, " SIZE_T_FMT
" vertices (merged " SIZE_T_FMT " vertices).", id.c_str(),
SLog(EInfo, "\"%s/%s\": Converted " SIZE_T_FMT " triangles, " SIZE_T_FMT
" vertices (merged " SIZE_T_FMT " vertices).", prefixName.c_str(), id.c_str(),
triangles.size(), vertexBuffer.size(), numMerged);
ref<TriMesh> mesh = new TriMesh(triangles.size(), vertexBuffer.size());
@ -344,7 +358,7 @@ void writeGeometry(std::string prefixName, std::string id, int geomIndex, std::s
mesh->calculateTangentSpaceBasis(vData->typeToOffset[ENormal]!=-1, vData->typeToOffset[EUV]!=-1);
std::string filename = id + std::string(".serialized");
ref<FileStream> stream = new FileStream(meshesDirectory + filename, FileStream::ETruncReadWrite);
ref<FileStream> stream = new FileStream(meshesDirectory / filename, FileStream::ETruncReadWrite);
stream->setByteOrder(Stream::ENetworkByteOrder);
mesh->serialize(stream);
stream->close();
@ -368,7 +382,7 @@ void writeGeometry(std::string prefixName, std::string id, int geomIndex, std::s
}
void loadGeometry(std::string prefixName, Transform transform, std::ostream &os, domGeometry &geom,
StringMap &matLookupTable, const std::string &meshesDir) {
StringMap &matLookupTable, const fs::path &meshesDir) {
std::string identifier;
if (geom.getId() != NULL) {
identifier = geom.getId();
@ -425,14 +439,35 @@ void loadGeometry(std::string prefixName, Transform transform, std::ostream &os,
for (size_t j=0; j<indexArray.getCount(); ++j) {
domListOfUInts &indices = indexArray[j]->getValue();
domUint *temp = new domUint[indices.getCount()];
for (size_t l = 0; l<indices.getCount(); ++l)
bool invalid = false;
for (int m=0; m<ELast; ++m) {
int offset = data->typeToOffsetInStream[m];
if (offset == -1)
continue;
size_t count = data->typeToCount[m];
for (size_t l = 0; l < indices.getCount(); l+=data->nSources) {
domUint idx = indices.get(l+offset);
if (idx >= count) {
SLog(EWarn, "Encountered the invalid polygon index %i "
"(must be in [0, " SIZE_T_FMT "]) -- ignoring polygon!", (domInt) idx, count-1);
invalid = true;
break;
}
}
}
if (invalid)
continue;
for (size_t l = 0; l<indices.getCount(); ++l)
temp[l] = indices.get(l);
gluTessBeginPolygon(tess, NULL);
gluTessBeginContour(tess);
for (size_t k=0; k<indices.getCount(); k+=data->nSources)
gluTessVertex(tess, &data->glPos[temp[k+posOffset]*3], (GLvoid *) (k+temp));
gluTessVertex(tess, &data->glPos[3*temp[k+posOffset]], (GLvoid *) (temp+k));
gluTessEndContour(tess);
gluTessEndPolygon(tess);
@ -463,8 +498,29 @@ void loadGeometry(std::string prefixName, Transform transform, std::ostream &os,
for (size_t j=0; j<vcount.getCount(); ++j) {
size_t vertexCount = (size_t) vcount.get(j);
domUint *temp = new domUint[vertexCount * data->nSources];
bool invalid = false;
for (int m=0; m<ELast; ++m) {
int offset = data->typeToOffsetInStream[m];
if (offset == -1)
continue;
size_t count = data->typeToCount[m];
for (size_t l = 0; l < vertexCount; ++l) {
domUint idx = indexArray.get(l*data->nSources+offset);
if (idx >= count) {
SLog(EWarn, "Encountered the invalid polygon index %i "
"(must be in [0, " SIZE_T_FMT "]) -- ignoring polygon!", (domInt) idx, count-1);
invalid = true;
break;
}
}
}
if (invalid)
continue;
for (size_t l = 0; l<vertexCount * data->nSources; ++l)
temp[l] = indexArray.get(indexOffset++);
@ -491,7 +547,7 @@ void loadGeometry(std::string prefixName, Transform transform, std::ostream &os,
}
}
void loadMaterialParam(GeometryConverter *cvt, std::ostream &os, const std::string &name, StringMap &idToTexture,
void loadMaterialParam(GeometryConverter *cvt, std::ostream &os, const fs::path &name, StringMap &idToTexture,
domCommon_color_or_texture_type *value, bool handleRefs) {
if (!value)
return;
@ -517,7 +573,7 @@ void loadMaterialParam(GeometryConverter *cvt, std::ostream &os, const std::stri
}
}
void loadMaterialParam(GeometryConverter *cvt, std::ostream &os, const std::string &name, StringMap &,
void loadMaterialParam(GeometryConverter *cvt, std::ostream &os, const fs::path &name, StringMap &,
domCommon_float_or_param_type *value, bool handleRef) {
if (!value)
return;
@ -622,18 +678,11 @@ void loadMaterial(GeometryConverter *cvt, std::ostream &os, domMaterial &mat, St
os << "\t</bsdf>" << endl << endl;
}
} else if (lambert) {
domCommon_float_or_param_type* transparency = lambert->getTransparency();
domCommon_float_or_param_type::domFloat *transparencyValue =
transparency ? transparency->getFloat() : NULL;
if (transparencyValue && transparencyValue->getValue() > 0.5) {
os << "\t<bsdf id=\"" << identifier << "\" type=\"dielectric\"/>" << endl << endl;
} else {
domCommon_color_or_texture_type* diffuse = lambert->getDiffuse();
os << "\t<bsdf id=\"" << identifier << "\" type=\"lambertian\">" << endl;
loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, false);
loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, true);
os << "\t</bsdf>" << endl << endl;
}
domCommon_color_or_texture_type* diffuse = lambert->getDiffuse();
os << "\t<bsdf id=\"" << identifier << "\" type=\"lambertian\">" << endl;
loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, false);
loadMaterialParam(cvt, os, "reflectance", idToTexture, diffuse, true);
os << "\t</bsdf>" << endl << endl;
} else if (blinn) {
SLog(EWarn, "\"%s\": Encountered a \"blinn\" COLLADA material, which is currently "
"unsupported in Mitsuba -- replacing it using a Phong material.", identifier.c_str());
@ -702,7 +751,7 @@ void loadLight(Transform transform, std::ostream &os, domLight &light) {
transform = transform * Transform::scale(Vector(1, 1, -1));
Point pos = transform(Point(0, 0, 0));
Vector target = transform(Point(0, 0, 1));
Point target = transform(Point(0, 0, 1));
Float intensity = 1;
const domTechnique_Array &techniques = light.getTechnique_array();
@ -783,7 +832,7 @@ void loadLight(Transform transform, std::ostream &os, domLight &light) {
SLog(EWarn, "Encountered an unknown light type!");
}
void loadImage(GeometryConverter *cvt, std::ostream &os, const std::string &textureDir,
void loadImage(GeometryConverter *cvt, std::ostream &os, const fs::path &textureDir,
domImage &image, StringMap &idToTexture, StringMap &fileToId) {
std::string identifier;
if (image.getId() != NULL) {
@ -808,27 +857,27 @@ void loadImage(GeometryConverter *cvt, std::ostream &os, const std::string &text
idToTexture[identifier] = identifier;
fileToId[filename] = identifier;
boost::filesystem::path path = boost::filesystem::path(filename, boost::filesystem::native);
std::string targetPath = textureDir + path.leaf();
fs::path path = fs::path(filename);
fs::path targetPath = textureDir / path.leaf();
fs::path resolved = filename;
if (endsWith(filename, ".rgb"))
std::string extension = boost::to_lower_copy(fs::extension(path));
if (extension == ".rgb")
SLog(EWarn, "Maya RGB images must be converted to PNG, EXR or JPEG! The 'imgcvt' "
"utility found in the Maya binary directory can be used to do this.");
if (!FileStream::exists(targetPath)) {
ref<FileResolver> fRes = FileResolver::getInstance();
std::string resolved = fRes->resolve(path.leaf());
if (!FileStream::exists(filename)) {
if (!FileStream::exists(resolved)) {
SLog(EWarn, "Found neither \"%s\" nor \"%s\"!", filename.c_str(), resolved.c_str());
filename = cvt->locateResource(filename);
if (filename == "")
if (!fs::exists(targetPath)) {
ref<FileResolver> fRes = Thread::getThread()->getFileResolver();
if (!fs::exists(resolved)) {
resolved = fRes->resolve(path.leaf());
if (!fs::exists(resolved)) {
SLog(EWarn, "Found neither \"%s\" nor \"%s\"!", filename.c_str(), resolved.file_string().c_str());
resolved = cvt->locateResource(path.leaf());
if (resolved.empty())
SLog(EError, "Unable to locate a resource -- aborting conversion.");
} else {
filename = resolved;
}
}
ref<FileStream> input = new FileStream(filename, FileStream::EReadOnly);
ref<FileStream> input = new FileStream(resolved, FileStream::EReadOnly);
ref<FileStream> output = new FileStream(targetPath, FileStream::ETruncReadWrite);
input->copyTo(output);
input->close();
@ -945,7 +994,7 @@ void loadCamera(GeometryConverter *cvt, Transform transform, std::ostream &os, d
}
void loadNode(GeometryConverter *cvt, Transform transform, std::ostream &os,
domNode &node, std::string prefixName, const std::string &meshesDir) {
domNode &node, std::string prefixName, const fs::path &meshesDir) {
std::string identifier;
if (node.getId() != NULL) {
identifier = node.getId();
@ -964,13 +1013,21 @@ void loadNode(GeometryConverter *cvt, Transform transform, std::ostream &os,
for (size_t i=0; i<children.getCount(); ++i) {
daeElement *element = children.get(i);
if (element->typeID() == domRotate::ID()) {
/* Skip rotations labeled as "post-rotationY". Maya exports these with some cameras,
which introduces an incorrect 90 degree rotation unless ignored */
/* Skip rotations labeled as "post-rotationY". Maya and 3ds max export these with some
cameras, which introduces an incorrect 90 degree rotation unless ignored */
if (element->hasAttribute("sid") && element->getAttribute("sid") == "post-rotationY")
continue;
daeTArray<double> value = daeSafeCast<domRotate>(element)->getValue();
transform = transform *
Transform::rotate(Vector((Float) value.get(0), (Float) value.get(1), (Float) value.get(2)), (Float) value.get(3));
Vector axis((Float) value.get(0), (Float) value.get(1), (Float) value.get(2));
Float angle = (Float) value.get(3);
if (angle != 0) {
if (axis.isZero()) {
SLog(EWarn, "Encountered a rotation around a zero vector -- ignoring!");
} else {
transform = transform *
Transform::rotate(axis, (Float) value.get(3));
}
}
} else if (element->typeID() == domTranslate::ID()) {
daeTArray<double> value = daeSafeCast<domTranslate>(element)->getValue();
transform = transform *
@ -1080,7 +1137,7 @@ GLvoid __stdcall tessVertex(void *data) {
GLvoid __stdcall tessCombine(GLdouble coords[3], void *vertex_data[4],
GLfloat weight[4], void **outData) {
SLog(EWarn, "Detected a self-intersecting polygon!");
SLog(EWarn, "Detected a degenerate or self-intersecting polygon!");
}
GLvoid __stdcall tessEnd() {
@ -1093,23 +1150,17 @@ GLvoid __stdcall tessError(GLenum error) {
GLvoid __stdcall tessEdgeFlag(GLboolean) {
}
void GeometryConverter::convertCollada(const std::string &inputFile,
void GeometryConverter::convertCollada(const fs::path &inputFile,
std::ostream &os,
const std::string &textureDirectory,
const std::string &meshesDirectory) {
#if defined(__LINUX__)
std::string path = std::string("file://") +
FileResolver::getInstance()->resolveAbsolute(inputFile);
#else
std::string path = inputFile;
#endif
const fs::path &textureDirectory,
const fs::path &meshesDirectory) {
DAE *dae = new DAE();
SLog(EInfo, "Loading \"%s\" ..", path.c_str());
if (dae->load(path.c_str()) != DAE_OK)
SLog(EError, "Could not load \"%s\"!", path.c_str());
SLog(EInfo, "Loading \"%s\" ..", inputFile.leaf().c_str());
if (dae->load(inputFile.file_string().c_str()) != DAE_OK)
SLog(EError, "Could not load \"%s\"!",
inputFile.file_string().c_str());
domCOLLADA *document = dae->getDom(path.c_str());
domCOLLADA *document = dae->getDom(inputFile.file_string().c_str());
domVisual_scene *visualScene = daeSafeCast<domVisual_scene>
(document->getDescendant("visual_scene"));
if (!visualScene)

View File

@ -29,12 +29,10 @@
#include <xercesc/framework/Wrapper4InputSource.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
#include <xercesc/util/XMLUni.hpp>
#include <mitsuba/mitsuba.h>
#include <mitsuba/core/fresolver.h>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <set>
XERCES_CPP_NAMESPACE_USE
@ -46,18 +44,15 @@ public:
inline ImporterDOMErrorHandler() { }
bool handleError(const DOMError& domError) {
ELogLevel logLevel;
if (domError.getSeverity() == DOMError::DOM_SEVERITY_WARNING)
logLevel = EWarn;
else
logLevel = EError;
SLog(logLevel, "%s (line %i, char %i): %s",
SLog(EWarn, "%s (line %i, char %i): %s",
XMLString::transcode(domError.getLocation()->getURI()),
domError.getLocation()->getLineNumber(),
domError.getLocation()->getColumnNumber(),
XMLString::transcode(domError.getMessage()));
if (domError.getSeverity() != DOMError::DOM_SEVERITY_WARNING)
SLog(EError, "Encountered a critical DOM error -- giving up!");
return true;
}
};
@ -129,62 +124,45 @@ bool cleanupPass(DOMNode *node, const std::set<std::string> &removals) {
return false;
}
void GeometryConverter::convert(const std::string &inputFile,
const std::string &outputDirectory,
const std::string &sceneName,
const std::string &adjustmentFile) {
void GeometryConverter::convert(const fs::path &inputFile,
const fs::path &outputDirectory,
const fs::path &sceneName,
const fs::path &adjustmentFile) {
std::string textureDirectory = "textures";
std::string meshesDirectory = "meshes";
std::string outputFile = sceneName;
fs::path textureDirectory = "textures";
fs::path meshesDirectory = "meshes";
fs::path outputFile = sceneName;
SLog(EInfo, "Creating directories ..");
#if !defined(WIN32)
if (outputDirectory != "") {
textureDirectory = outputDirectory + "/textures";
meshesDirectory = outputDirectory + "/meshes";
outputFile = outputDirectory + std::string("/") + sceneName;
if (!outputDirectory.empty()) {
textureDirectory = outputDirectory / "textures";
meshesDirectory = outputDirectory / "meshes";
outputFile = outputDirectory / sceneName;
}
int status = mkdir(textureDirectory.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (status != 0 && errno != EEXIST)
SLog(EError, "Could not create the directory \"%s\"", textureDirectory.c_str());
status = mkdir(meshesDirectory.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (status != 0 && errno != EEXIST)
SLog(EError, "Could not create the directory \"%s\"", meshesDirectory.c_str());
textureDirectory += "/";
meshesDirectory += "/";
#else
if (outputDirectory != "") {
textureDirectory = outputDirectory + "\\textures";
meshesDirectory = outputDirectory + "\\meshes";
outputFile = outputDirectory + std::string("\\") + sceneName;
if (!fs::exists(textureDirectory)) {
SLog(EInfo, "Creating directory \"%s\" ..", textureDirectory.file_string().c_str());
fs::create_directory(textureDirectory);
}
int status = CreateDirectory(textureDirectory.c_str(), NULL);
if (status == 0 && GetLastError() != ERROR_ALREADY_EXISTS)
SLog(EError, "Could not create the directory \"%s\"", textureDirectory.c_str());
status = CreateDirectory(meshesDirectory.c_str(), NULL);
if (status == 0 && GetLastError() != ERROR_ALREADY_EXISTS)
SLog(EError, "Could not create the directory \"%s\"", meshesDirectory.c_str());
textureDirectory += "\\";
meshesDirectory += "\\";
#endif
if (!fs::exists(meshesDirectory)) {
SLog(EInfo, "Creating directory \"%s\" ..", meshesDirectory.file_string().c_str());
fs::create_directory(meshesDirectory);
}
std::ostringstream os;
SLog(EInfo, "Beginning conversion ..");
if (endsWith(toLowerCase(inputFile), ".dae") || endsWith(toLowerCase(inputFile), ".zae")) {
std::string extension = boost::to_lower_copy(fs::extension(inputFile));
if (extension == ".dae" || extension == ".zae") {
convertCollada(inputFile, os, textureDirectory, meshesDirectory);
} else if (endsWith(toLowerCase(inputFile), ".obj")) {
} else if (extension == ".obj") {
convertOBJ(inputFile, os, textureDirectory, meshesDirectory);
} else {
SLog(EError, "Unknown input format (must end in either .DAE, .ZAE or .OBJ)");
}
if (adjustmentFile != "") {
if (!adjustmentFile.empty()) {
SLog(EInfo, "Applying adjustments ..");
static const XMLCh gLS[] = { chLatin_L, chLatin_S, chNull };
DOMImplementationLS *impl = DOMImplementationRegistry::getDOMImplementation(gLS);
@ -199,8 +177,10 @@ void GeometryConverter::convert(const std::string &inputFile,
xmlString.length(), "bufID", false);
Wrapper4InputSource *wrapper = new Wrapper4InputSource(memBufIS, false);
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *doc = parser->parse(wrapper);
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *adj = parser->parseURI(adjustmentFile.c_str());
XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument *adj = parser->parseURI(adjustmentFile.file_string().c_str());
if (adj == NULL)
SLog(EError, "Could not parse adjustments file!");
std::set<std::string> removals, emptyList;
cleanupPass(adj, emptyList);
findRemovals(adj, removals);
@ -241,7 +221,7 @@ void GeometryConverter::convert(const std::string &inputFile,
DOMLSOutput *output = impl->createLSOutput();
serConf->setParameter(XMLUni::fgDOMErrorHandler, &errorHandler);
serConf->setParameter(XMLUni::fgDOMWRTFormatPrettyPrint, true);
XMLFormatTarget *target = new LocalFileFormatTarget(outputFile.c_str());
XMLFormatTarget *target = new LocalFileFormatTarget(outputFile.file_string().c_str());
output->setByteStream(target);
serializer->write(doc, output);
delete output;
@ -251,9 +231,9 @@ void GeometryConverter::convert(const std::string &inputFile,
delete serializer;
parser->release();
} else {
std::ofstream ofile(outputFile.c_str());
fs::ofstream ofile(outputFile);
if (ofile.fail())
SLog(EError, "Could not write to \"%s\"!", outputFile.c_str());
SLog(EError, "Could not write to \"%s\"!", outputFile.file_string().c_str());
ofile << os.str();
ofile.close();
}

View File

@ -1,4 +1,22 @@
#include <mitsuba/mitsuba.h>
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2010 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba 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 <mitsuba/core/fresolver.h>
using namespace mitsuba;
@ -12,29 +30,29 @@ public:
m_fov = -1;
}
void convert(const std::string &inputFile,
const std::string &outputDirectory,
const std::string &sceneName,
const std::string &adjustmentFile);
void convert(const fs::path &inputFile,
const fs::path &outputDirectory,
const fs::path &sceneName,
const fs::path &adjustmentFile);
virtual std::string locateResource(const std::string &resource) = 0;
virtual fs::path locateResource(const fs::path &resource) = 0;
inline void setSRGB(bool srgb) { m_srgb = srgb; }
inline void setMapSmallerSide(bool mapSmallerSide) { m_mapSmallerSide = mapSmallerSide; }
inline void setResolution(int xres, int yres) { m_xres = xres; m_yres = yres; }
inline void setSamplesPerPixel(int samplesPerPixel) { m_samplesPerPixel = samplesPerPixel; }
inline void setFov(Float fov) { m_fov = fov; }
inline const std::string &getFilename() const { return m_filename; }
inline const fs::path &getFilename() const { return m_filename; }
private:
void convertCollada(const std::string &inputFile, std::ostream &os,
const std::string &textureDirectory,
const std::string &meshesDirectory);
void convertOBJ(const std::string &inputFile, std::ostream &os,
const std::string &textureDirectory,
const std::string &meshesDirectory);
void convertCollada(const fs::path &inputFile, std::ostream &os,
const fs::path &textureDirectory,
const fs::path &meshesDirectory);
void convertOBJ(const fs::path &inputFile, std::ostream &os,
const fs::path &textureDirectory,
const fs::path &meshesDirectory);
public:
bool m_srgb, m_mapSmallerSide;
int m_xres, m_yres, m_samplesPerPixel;
Float m_fov;
std::string m_filename;
fs::path m_filename;
};

View File

@ -1,21 +1,3 @@
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2010 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba 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/>.
*/
/**
* Mitsuba COLLADA 1.4 and Wavefront OBJ -> XML converter
*
@ -51,8 +33,8 @@
#include <xercesc/dom/DOMException.hpp>
#include "converter.h"
#include <mitsuba/hw/glrenderer.h>
#include <mitsuba/core/fresolver.h>
#include <mitsuba/core/plugin.h>
#include <mitsuba/core/statistics.h>
#if defined(WIN32)
#include "../mitsuba/getopt.h"
#endif
@ -64,8 +46,8 @@ public:
inline ConsoleGeometryConverter() {
}
std::string locateResource(const std::string &resource) {
return "";
fs::path locateResource(const fs::path &resource) {
return fs::path();
}
};
@ -90,7 +72,7 @@ int colladaMain(int argc, char **argv) {
int xres = -1, yres = -1;
int samplesPerPixel = 8;
Float fov = -1;
FileResolver *resolver = FileResolver::getInstance();
FileResolver *fileResolver = Thread::getThread()->getFileResolver();
ELogLevel logLevel = EInfo;
optind = 1;
@ -100,7 +82,7 @@ int colladaMain(int argc, char **argv) {
case 'a': {
std::vector<std::string> paths = tokenize(optarg, ";");
for (unsigned int i=0; i<paths.size(); ++i)
resolver->addPath(paths[i]);
fileResolver->addPath(paths[i]);
}
break;
case 's':
@ -118,7 +100,7 @@ int colladaMain(int argc, char **argv) {
logLevel = EDebug;
break;
case 'f':
fov = strtod(optarg, &end_ptr);
fov = (Float) strtod(optarg, &end_ptr);
if (*end_ptr != '\0')
SLog(EError, "Invalid field of view value!");
break;
@ -190,26 +172,13 @@ int ubi_main(int argc, char **argv) {
Thread::getThread()->getLogger()->setLogLevel(EInfo);
FileResolver *resolver = FileResolver::getInstance();
#if defined(WIN32)
char lpFilename[1024];
if (GetModuleFileNameA(NULL,
lpFilename, sizeof(lpFilename))) {
resolver->addPathFromFile(lpFilename);
} else {
SLog(EWarn, "Could not determine the executable path");
}
#elif defined(__LINUX__)
char exePath[PATH_MAX];
if (getcwd(exePath, PATH_MAX)) {
resolver->addPathFromFile(exePath);
} else {
SLog(EWarn, "Could not determine the executable path");
}
resolver->addPath("/usr/share/mitsuba");
#else
FileResolver *fileResolver = Thread::getThread()->getFileResolver();
#if defined(__LINUX__)
fileResolver->addPath(MTS_RESOURCE_DIR);
#elif defined(__OSX__)
MTS_AUTORELEASE_BEGIN()
resolver->addPath(__ubi_bundlepath());
fileResolver->addPath(__ubi_bundlepath());
MTS_AUTORELEASE_END()
#endif

Some files were not shown because too many files have changed in this diff Show More