Merge with default

metadata
Edgar Velazquez-Armendariz 2014-04-02 15:58:32 -04:00
commit 2963094267
104 changed files with 1161 additions and 382 deletions

View File

@ -10,3 +10,4 @@ ee26517b27207353b0c8a7d357bcb4977b5d93fb v0.4.0
f1b73d39617071297167cc7ce96f3892f21105fc v0.4.3 f1b73d39617071297167cc7ce96f3892f21105fc v0.4.3
bd6ddacdf7955e51d9b80be639c282d4974e6f56 v0.4.4 bd6ddacdf7955e51d9b80be639c282d4974e6f56 v0.4.4
454ebc86e4bd5b3c1d5eb6585099e66ccd8522fe v0.4.5 454ebc86e4bd5b3c1d5eb6585099e66ccd8522fe v0.4.5
e6a8a0178556bbce63a2a154191351aa58285623 v0.5.0

View File

@ -24,6 +24,9 @@ PYTHON27LIBDIR = ['/System/Library/Frameworks/Python.framework/Versions/2.7/lib'
PYTHON27LIB = ['boost_python27', 'boost_system'] PYTHON27LIB = ['boost_python27', 'boost_system']
PYTHON33INCLUDE= ['#dependencies/include/python3.3'] PYTHON33INCLUDE= ['#dependencies/include/python3.3']
PYTHON33LIB = ['boost_python33', 'boost_system'] PYTHON33LIB = ['boost_python33', 'boost_system']
PYTHON34INCLUDE= ['#dependencies/include/python3.4']
PYTHON34LIB = ['boost_python34', 'boost_system']
COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4']
COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4'] COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4']
COLLADALIB = ['collada14dom24'] COLLADALIB = ['collada14dom24']
QTDIR = '#dependencies' QTDIR = '#dependencies'

View File

@ -24,6 +24,8 @@ PYTHON27LIBDIR = ['/System/Library/Frameworks/Python.framework/Versions/2.7/lib'
PYTHON27LIB = ['boost_python27', 'boost_system'] PYTHON27LIB = ['boost_python27', 'boost_system']
PYTHON33INCLUDE= ['#dependencies/include/python3.3'] PYTHON33INCLUDE= ['#dependencies/include/python3.3']
PYTHON33LIB = ['boost_python33', 'boost_system'] PYTHON33LIB = ['boost_python33', 'boost_system']
PYTHON34INCLUDE= ['#dependencies/include/python3.4']
PYTHON34LIB = ['boost_python34', 'boost_system']
COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4'] COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4']
COLLADALIB = ['collada14dom24'] COLLADALIB = ['collada14dom24']
QTDIR = '#dependencies' QTDIR = '#dependencies'

View File

@ -24,6 +24,8 @@ PYTHON27LIBDIR = ['/System/Library/Frameworks/Python.framework/Versions/2.7/lib'
PYTHON27LIB = ['boost_python27', 'boost_system'] PYTHON27LIB = ['boost_python27', 'boost_system']
PYTHON33INCLUDE= ['#dependencies/include/python3.3'] PYTHON33INCLUDE= ['#dependencies/include/python3.3']
PYTHON33LIB = ['boost_python33', 'boost_system'] PYTHON33LIB = ['boost_python33', 'boost_system']
PYTHON34INCLUDE= ['#dependencies/include/python3.4']
PYTHON34LIB = ['boost_python34', 'boost_system']
COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4'] COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4']
COLLADALIB = ['collada14dom24'] COLLADALIB = ['collada14dom24']
QTDIR = '#dependencies' QTDIR = '#dependencies'

View File

@ -25,6 +25,8 @@ PYTHON27LIBDIR = ['/System/Library/Frameworks/Python.framework/Versions/2.7/lib'
PYTHON27LIB = ['boost_python27', 'boost_system'] PYTHON27LIB = ['boost_python27', 'boost_system']
PYTHON33INCLUDE= ['#dependencies/include/python3.3'] PYTHON33INCLUDE= ['#dependencies/include/python3.3']
PYTHON33LIB = ['boost_python33', 'boost_system'] PYTHON33LIB = ['boost_python33', 'boost_system']
PYTHON34INCLUDE= ['#dependencies/include/python3.4']
PYTHON34LIB = ['boost_python34', 'boost_system']
COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4'] COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4']
COLLADALIB = ['collada14dom24'] COLLADALIB = ['collada14dom24']
QTDIR = '#dependencies' QTDIR = '#dependencies'

View File

@ -25,6 +25,8 @@ PYTHON27LIBDIR = ['/System/Library/Frameworks/Python.framework/Versions/2.7/lib'
PYTHON27LIB = ['boost_python27', 'boost_system'] PYTHON27LIB = ['boost_python27', 'boost_system']
PYTHON33INCLUDE= ['#dependencies/include/python3.3'] PYTHON33INCLUDE= ['#dependencies/include/python3.3']
PYTHON33LIB = ['boost_python33', 'boost_system'] PYTHON33LIB = ['boost_python33', 'boost_system']
PYTHON34INCLUDE= ['#dependencies/include/python3.4']
PYTHON34LIB = ['boost_python34', 'boost_system']
COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4'] COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4']
COLLADALIB = ['collada14dom24'] COLLADALIB = ['collada14dom24']
QTDIR = '#dependencies' QTDIR = '#dependencies'

View File

@ -24,6 +24,8 @@ PYTHON27LIBDIR = ['/System/Library/Frameworks/Python.framework/Versions/2.7/lib'
PYTHON27LIB = ['boost_python27', 'boost_system'] PYTHON27LIB = ['boost_python27', 'boost_system']
PYTHON33INCLUDE= ['#dependencies/include/python3.3'] PYTHON33INCLUDE= ['#dependencies/include/python3.3']
PYTHON33LIB = ['boost_python33', 'boost_system'] PYTHON33LIB = ['boost_python33', 'boost_system']
PYTHON34INCLUDE= ['#dependencies/include/python3.4']
PYTHON34LIB = ['boost_python34', 'boost_system']
COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4'] COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4']
COLLADALIB = ['collada14dom24'] COLLADALIB = ['collada14dom24']
QTDIR = '#dependencies' QTDIR = '#dependencies'

View File

@ -24,6 +24,8 @@ PYTHON27LIBDIR = ['/System/Library/Frameworks/Python.framework/Versions/2.7/lib'
PYTHON27LIB = ['boost_python27', 'boost_system'] PYTHON27LIB = ['boost_python27', 'boost_system']
PYTHON33INCLUDE= ['#dependencies/include/python3.3'] PYTHON33INCLUDE= ['#dependencies/include/python3.3']
PYTHON33LIB = ['boost_python33', 'boost_system'] PYTHON33LIB = ['boost_python33', 'boost_system']
PYTHON34INCLUDE= ['#dependencies/include/python3.4']
PYTHON34LIB = ['boost_python34', 'boost_system']
COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4'] COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4']
COLLADALIB = ['collada14dom24'] COLLADALIB = ['collada14dom24']
QTDIR = '#dependencies' QTDIR = '#dependencies'

View File

@ -24,6 +24,8 @@ PYTHON27LIBDIR = ['/System/Library/Frameworks/Python.framework/Versions/2.7/lib'
PYTHON27LIB = ['boost_python27', 'boost_system'] PYTHON27LIB = ['boost_python27', 'boost_system']
PYTHON33INCLUDE= ['#dependencies/include/python3.3'] PYTHON33INCLUDE= ['#dependencies/include/python3.3']
PYTHON33LIB = ['boost_python33', 'boost_system'] PYTHON33LIB = ['boost_python33', 'boost_system']
PYTHON34INCLUDE= ['#dependencies/include/python3.4']
PYTHON34LIB = ['boost_python34', 'boost_system']
COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4'] COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4']
COLLADALIB = ['collada14dom24'] COLLADALIB = ['collada14dom24']
QTDIR = '#dependencies' QTDIR = '#dependencies'

View File

@ -25,6 +25,8 @@ PYTHON27LIBDIR = ['/System/Library/Frameworks/Python.framework/Versions/2.7/lib'
PYTHON27LIB = ['boost_python27', 'boost_system'] PYTHON27LIB = ['boost_python27', 'boost_system']
PYTHON33INCLUDE= ['#dependencies/include/python3.3'] PYTHON33INCLUDE= ['#dependencies/include/python3.3']
PYTHON33LIB = ['boost_python33', 'boost_system'] PYTHON33LIB = ['boost_python33', 'boost_system']
PYTHON34INCLUDE= ['#dependencies/include/python3.4']
PYTHON34LIB = ['boost_python34', 'boost_system']
COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4'] COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4']
COLLADALIB = ['collada14dom24'] COLLADALIB = ['collada14dom24']
QTDIR = '#dependencies' QTDIR = '#dependencies'

View File

@ -25,6 +25,8 @@ PYTHON27LIBDIR = ['/System/Library/Frameworks/Python.framework/Versions/2.7/lib'
PYTHON27LIB = ['boost_python27', 'boost_system'] PYTHON27LIB = ['boost_python27', 'boost_system']
PYTHON33INCLUDE= ['#dependencies/include/python3.3'] PYTHON33INCLUDE= ['#dependencies/include/python3.3']
PYTHON33LIB = ['boost_python33', 'boost_system'] PYTHON33LIB = ['boost_python33', 'boost_system']
PYTHON34INCLUDE= ['#dependencies/include/python3.4']
PYTHON34LIB = ['boost_python34', 'boost_system']
COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4'] COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4']
COLLADALIB = ['collada14dom24'] COLLADALIB = ['collada14dom24']
QTDIR = '#dependencies' QTDIR = '#dependencies'

View File

@ -24,6 +24,8 @@ PYTHON27LIBDIR = ['/System/Library/Frameworks/Python.framework/Versions/2.7/lib'
PYTHON27LIB = ['boost_python27', 'boost_system'] PYTHON27LIB = ['boost_python27', 'boost_system']
PYTHON33INCLUDE= ['#dependencies/include/python3.3'] PYTHON33INCLUDE= ['#dependencies/include/python3.3']
PYTHON33LIB = ['boost_python33', 'boost_system'] PYTHON33LIB = ['boost_python33', 'boost_system']
PYTHON34INCLUDE= ['#dependencies/include/python3.4']
PYTHON34LIB = ['boost_python34', 'boost_system']
COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4'] COLLADAINCLUDE = ['#dependencies/include/collada-dom', '#dependencies/include/collada-dom/1.4']
COLLADALIB = ['collada14dom24'] COLLADALIB = ['collada14dom24']
QTDIR = '#dependencies' QTDIR = '#dependencies'

View File

@ -32,6 +32,8 @@ PYTHON32LIB = ['boost_python32-vc100-mt-1_53', 'python32']
PYTHON32INCLUDE = ['#dependencies/include/python32'] PYTHON32INCLUDE = ['#dependencies/include/python32']
PYTHON33LIB = ['boost_python33-vc100-mt-1_53', 'python33'] PYTHON33LIB = ['boost_python33-vc100-mt-1_53', 'python33']
PYTHON33INCLUDE = ['#dependencies/include/python33'] PYTHON33INCLUDE = ['#dependencies/include/python33']
PYTHON34LIB = ['boost_python34-vc100-mt-1_53', 'python34']
PYTHON34INCLUDE = ['#dependencies/include/python34']
QTINCLUDE = ['#dependencies/qt/include'] QTINCLUDE = ['#dependencies/qt/include']
QTDIR = '#dependencies/qt/i386_vc10' QTDIR = '#dependencies/qt/i386_vc10'
FFTWLIB = ['libfftw-3.3'] FFTWLIB = ['libfftw-3.3']

View File

@ -30,6 +30,8 @@ PYTHON32LIB = ['boost_python32-vc100-mt-1_53', 'python32']
PYTHON32INCLUDE = ['#dependencies/include/python32'] PYTHON32INCLUDE = ['#dependencies/include/python32']
PYTHON33LIB = ['boost_python33-vc100-mt-1_53', 'python33'] PYTHON33LIB = ['boost_python33-vc100-mt-1_53', 'python33']
PYTHON33INCLUDE = ['#dependencies/include/python33'] PYTHON33INCLUDE = ['#dependencies/include/python33']
PYTHON34LIB = ['boost_python34-vc100-mt-1_53', 'python34']
PYTHON34INCLUDE = ['#dependencies/include/python34']
QTINCLUDE = ['#dependencies/qt/include'] QTINCLUDE = ['#dependencies/qt/include']
QTDIR = '#dependencies/qt/i386_vc10' QTDIR = '#dependencies/qt/i386_vc10'
FFTWLIB = ['libfftw-3.3'] FFTWLIB = ['libfftw-3.3']

View File

@ -33,6 +33,8 @@ PYTHON32LIB = ['boost_python32-vc100-mt-1_53', 'python32']
PYTHON32INCLUDE = ['#dependencies/include/python32'] PYTHON32INCLUDE = ['#dependencies/include/python32']
PYTHON33LIB = ['boost_python33-vc100-mt-1_53', 'python33'] PYTHON33LIB = ['boost_python33-vc100-mt-1_53', 'python33']
PYTHON33INCLUDE = ['#dependencies/include/python33'] PYTHON33INCLUDE = ['#dependencies/include/python33']
PYTHON34LIB = ['boost_python34-vc100-mt-1_53', 'python34']
PYTHON34INCLUDE = ['#dependencies/include/python34']
QTINCLUDE = ['#dependencies/qt/include'] QTINCLUDE = ['#dependencies/qt/include']
QTDIR = '#dependencies/qt/i386_vc10' QTDIR = '#dependencies/qt/i386_vc10'
FFTWLIB = ['libfftw-3.3'] FFTWLIB = ['libfftw-3.3']

View File

@ -32,6 +32,8 @@ PYTHON32LIB = ['boost_python32-vc100-mt-1_53', 'python32']
PYTHON32INCLUDE = ['#dependencies/include/python32'] PYTHON32INCLUDE = ['#dependencies/include/python32']
PYTHON33LIB = ['boost_python33-vc100-mt-1_53', 'python33'] PYTHON33LIB = ['boost_python33-vc100-mt-1_53', 'python33']
PYTHON33INCLUDE = ['#dependencies/include/python33'] PYTHON33INCLUDE = ['#dependencies/include/python33']
PYTHON34LIB = ['boost_python34-vc100-mt-1_53', 'python34']
PYTHON34INCLUDE = ['#dependencies/include/python34']
QTINCLUDE = ['#dependencies/qt/include'] QTINCLUDE = ['#dependencies/qt/include']
QTDIR = '#dependencies/qt/x64_vc10' QTDIR = '#dependencies/qt/x64_vc10'
FFTWLIB = ['libfftw-3.3'] FFTWLIB = ['libfftw-3.3']

View File

@ -30,6 +30,8 @@ PYTHON32LIB = ['boost_python32-vc100-mt-1_53', 'python32']
PYTHON32INCLUDE = ['#dependencies/include/python32'] PYTHON32INCLUDE = ['#dependencies/include/python32']
PYTHON33LIB = ['boost_python33-vc100-mt-1_53', 'python33'] PYTHON33LIB = ['boost_python33-vc100-mt-1_53', 'python33']
PYTHON33INCLUDE = ['#dependencies/include/python33'] PYTHON33INCLUDE = ['#dependencies/include/python33']
PYTHON34LIB = ['boost_python34-vc100-mt-1_53', 'python34']
PYTHON34INCLUDE = ['#dependencies/include/python34']
QTINCLUDE = ['#dependencies/qt/include'] QTINCLUDE = ['#dependencies/qt/include']
QTDIR = '#dependencies/qt/x64_vc10' QTDIR = '#dependencies/qt/x64_vc10'
FFTWLIB = ['libfftw-3.3'] FFTWLIB = ['libfftw-3.3']

View File

@ -33,6 +33,8 @@ PYTHON32LIB = ['boost_python32-vc100-mt-1_53', 'python32']
PYTHON32INCLUDE = ['#dependencies/include/python32'] PYTHON32INCLUDE = ['#dependencies/include/python32']
PYTHON33LIB = ['boost_python33-vc100-mt-1_53', 'python33'] PYTHON33LIB = ['boost_python33-vc100-mt-1_53', 'python33']
PYTHON33INCLUDE = ['#dependencies/include/python33'] PYTHON33INCLUDE = ['#dependencies/include/python33']
PYTHON34LIB = ['boost_python34-vc100-mt-1_53', 'python34']
PYTHON34INCLUDE = ['#dependencies/include/python34']
QTINCLUDE = ['#dependencies/qt/include'] QTINCLUDE = ['#dependencies/qt/include']
QTDIR = '#dependencies/qt/x64_vc10' QTDIR = '#dependencies/qt/x64_vc10'
FFTWLIB = ['libfftw-3.3'] FFTWLIB = ['libfftw-3.3']

View File

@ -30,6 +30,8 @@ PYTHON32LIB = ['boost_python32-vc120-mt-1_53', 'python32']
PYTHON32INCLUDE = ['#dependencies/include/python32'] PYTHON32INCLUDE = ['#dependencies/include/python32']
PYTHON33LIB = ['boost_python33-vc120-mt-1_53', 'python33'] PYTHON33LIB = ['boost_python33-vc120-mt-1_53', 'python33']
PYTHON33INCLUDE = ['#dependencies/include/python33'] PYTHON33INCLUDE = ['#dependencies/include/python33']
PYTHON34LIB = ['boost_python34-vc120-mt-1_53', 'python34']
PYTHON34INCLUDE = ['#dependencies/include/python34']
QTINCLUDE = ['#dependencies/qt/include'] QTINCLUDE = ['#dependencies/qt/include']
QTDIR = '#dependencies/qt/x64_vc12' QTDIR = '#dependencies/qt/x64_vc12'
FFTWLIB = ['libfftw-3.3'] FFTWLIB = ['libfftw-3.3']

View File

@ -33,6 +33,8 @@ PYTHON32LIB = ['boost_python32-vc120-mt-1_53', 'python32']
PYTHON32INCLUDE = ['#dependencies/include/python32'] PYTHON32INCLUDE = ['#dependencies/include/python32']
PYTHON33LIB = ['boost_python33-vc120-mt-1_53', 'python33'] PYTHON33LIB = ['boost_python33-vc120-mt-1_53', 'python33']
PYTHON33INCLUDE = ['#dependencies/include/python33'] PYTHON33INCLUDE = ['#dependencies/include/python33']
PYTHON34LIB = ['boost_python34-vc120-mt-1_53', 'python34']
PYTHON34INCLUDE = ['#dependencies/include/python34']
QTINCLUDE = ['#dependencies/qt/include'] QTINCLUDE = ['#dependencies/qt/include']
QTDIR = '#dependencies/qt/x64_vc12' QTDIR = '#dependencies/qt/x64_vc12'
FFTWLIB = ['libfftw-3.3'] FFTWLIB = ['libfftw-3.3']

View File

@ -1,3 +1,24 @@
mitsuba (0.5.0-1) unstable; urgency=low
* Mitsuba can now perform renderings of images with multiple channels
(e.g. a path traced rendering plus surface normals and depth). All
channels are rendered in one pass and written to a multi-channel EXR file.
* Anton Kaplanyan contributed mtsgui GUI usability tweaks and several
MLT-related robustness improvements
* Greatly improved Python integration, nice interaction with PyQt and NumPy,
Python 3.3. support on all platforms
* The 'mfilm' plugin now supports writing binary NumPy files (Joe Kider)
* Switch tabs in the gui using Alt+Left/Right keys
* Ask whether to stop long-running rendering processes when dragging the
mouse in the GUI
* Windows 8 compatibility
* CMake build system working again (Edgar Velázquez-Armendáriz)
* Statistics are now automatically reset between renderings
* mtssrv robustness improvements on OSX
* The 'thindielectric' plugin still computed incorrect results in some
situations, which is now fixed
* Added a new 'default' XML tag
-- Wenzel Jakob <wenzel@cs.cornell.edu> Tue, 25 Feb 2014 00:00:00 -0400
mitsuba (0.4.5-1) unstable; urgency=low mitsuba (0.4.5-1) unstable; urgency=low
* New height field intersection shape * New height field intersection shape
* kd-tree precision improvements when rendering in double precision * kd-tree precision improvements when rendering in double precision

View File

@ -1,5 +1,5 @@
Name: mitsuba Name: mitsuba
Version: 0.4.5 Version: 0.5.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: Mitsuba renderer Summary: Mitsuba renderer
Group: Applications/Graphics Group: Applications/Graphics
@ -24,7 +24,7 @@ building custom plugins and other extensions for Mitsuba.
%prep %prep
%setup -q %setup -q
%build %build
cat build/config-linux-gcc.py | sed -e "s/\(boost_[^']*\)/\1-mt/g" > config.py cat build/config-linux-gcc.py | sed -e "s/collada14dom/libcollada-dom2.4-dp/g" | sed -e "s/include\/collada-dom/include\/collada-dom2.4/g" > config.py
scons scons
%install %install
rm -rf $RPM_BUILD_ROOT rm -rf $RPM_BUILD_ROOT
@ -66,6 +66,9 @@ rm -rf $RPM_BUILD_ROOT
/usr/include/* /usr/include/*
%changelog %changelog
* Tue Feb 25 2014 Wenzel Jakob <wenzel@cs.cornell.edu> 0.5.0%{?dist}
- Upgrade to version 0.5.0
* Sun Nov 10 2013 Wenzel Jakob <wenzel@cs.cornell.edu> 0.4.5%{?dist} * Sun Nov 10 2013 Wenzel Jakob <wenzel@cs.cornell.edu> 0.4.5%{?dist}
- Upgrade to version 0.4.5 - Upgrade to version 0.4.5

View File

@ -17,19 +17,22 @@ add_custom_command (
OUTPUT "${SCHEMA_DIR}/scene.xsd" OUTPUT "${SCHEMA_DIR}/scene.xsd"
"${SCHEMA_DIR}/upgrade_0.3.0.xsl" "${SCHEMA_DIR}/upgrade_0.3.0.xsl"
"${SCHEMA_DIR}/upgrade_0.4.0.xsl" "${SCHEMA_DIR}/upgrade_0.4.0.xsl"
"${SCHEMA_DIR}/upgrade_0.5.0.xsl"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/scene.xsd" "${SCHEMA_DIR}/scene.xsd" "${CMAKE_CURRENT_SOURCE_DIR}/scene.xsd" "${SCHEMA_DIR}/scene.xsd"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/upgrade_0.3.0.xsl" "${SCHEMA_DIR}/upgrade_0.3.0.xsl" "${CMAKE_CURRENT_SOURCE_DIR}/upgrade_0.3.0.xsl" "${SCHEMA_DIR}/upgrade_0.3.0.xsl"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/upgrade_0.4.0.xsl" "${SCHEMA_DIR}/upgrade_0.4.0.xsl" "${CMAKE_CURRENT_SOURCE_DIR}/upgrade_0.4.0.xsl" "${SCHEMA_DIR}/upgrade_0.4.0.xsl"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/upgrade_0.5.0.xsl" "${SCHEMA_DIR}/upgrade_0.5.0.xsl"
MAIN_DEPENDENCY "scene.xsd" MAIN_DEPENDENCY "scene.xsd"
DEPENDS "scene.xsd" "upgrade_0.3.0.xsl" "upgrade_0.4.0.xsl" DEPENDS "scene.xsd" "upgrade_0.3.0.xsl" "upgrade_0.4.0.xsl" "upgrade_0.5.0.xsl"
COMMENT "Copying XML data: scene schema and upgrade XSL files" COMMENT "Copying XML data: scene schema and upgrade XSL files"
) )
add_custom_target (scene_schema add_custom_target (scene_schema
DEPENDS "${SCHEMA_DIR}/scene.xsd" DEPENDS "${SCHEMA_DIR}/scene.xsd"
"${SCHEMA_DIR}/upgrade_0.3.0.xsl" "${SCHEMA_DIR}/upgrade_0.4.0.xsl" "${SCHEMA_DIR}/upgrade_0.3.0.xsl" "${SCHEMA_DIR}/upgrade_0.4.0.xsl" "${SCHEMA_DIR}/upgrade_0.5.0.xsl"
) )
set_target_properties (scene_schema PROPERTIES FOLDER "data") set_target_properties (scene_schema PROPERTIES FOLDER "data")

View File

@ -12,7 +12,7 @@
</xsl:template> </xsl:template>
<!-- Update the name of the bump plugin --> <!-- Update the name of the bump plugin -->
<xsl:template match="integrator[@type='bump']/@type"> <xsl:template match="bsdf[@type='bump']/@type">
<xsl:attribute name="type">bumpmap</xsl:attribute> <xsl:attribute name="type">bumpmap</xsl:attribute>
</xsl:template> </xsl:template>

View File

@ -513,7 +513,6 @@
author={Kelemen, C. and Szirmay-Kalos, L. and Antal, G. and Csonka, F.}, author={Kelemen, C. and Szirmay-Kalos, L. and Antal, G. and Csonka, F.},
booktitle={Computer Graphics Forum}, booktitle={Computer Graphics Forum},
volume={21}, volume={21},
number={3},
pages={531--540}, pages={531--540},
year={2002} year={2002}
} }

View File

@ -40,8 +40,8 @@
\setcounter{secnumdepth}{3} \setcounter{secnumdepth}{3}
\setcounter{tocdepth}{3} \setcounter{tocdepth}{3}
\newcommand{\MitsubaVersion}{0.4.5} \newcommand{\MitsubaVersion}{0.5.0}
\newcommand{\MitsubaYear}{2013} \newcommand{\MitsubaYear}{2014}
\typearea[current]{last} \typearea[current]{last}
\raggedbottom \raggedbottom

View File

@ -100,6 +100,8 @@ print(trafo * myVector)
\subsection{Recipes} \subsection{Recipes}
The following section contains a series of ``recipes'' on how to do The following section contains a series of ``recipes'' on how to do
certain things with the help of the Python bindings. certain things with the help of the Python bindings.
To copy and paste from this chapter, the \LaTeX source code may
be more convenient. It is available at the following URL: \url{https://www.mitsuba-renderer.org/repos/mitsuba/files/tip/doc/python.tex}.
\subsubsection{Loading a scene} \subsubsection{Loading a scene}
The following script demonstrates how to use the The following script demonstrates how to use the
@ -303,6 +305,158 @@ scene.addChild(pmgr.create({
scene.configure() scene.configure()
\end{python} \end{python}
\subsubsection{Flexible scene generation for rendering in-process and emitting XML}
The following example shows how to construct a scene in a way so that it can
be rendered in-process or alternatively written to an XML file for later processing.
This is the recommended way of integrating Mitsuba into modeling software.
Roughly, the approach is to create an ordered dictionary version of the entire
scene (named \code{scene\_descr} below) that can either be passed to the
\code{PluginManager} or a simple function that turns it into Mitsuba-compatible XML.
The example below also does instancing via the \pluginref{shapegroup}
and \pluginref{instance} plugins to show how referencing can be implemented
for such an approach.
\begin{python}
import mitsuba
from mitsuba.core import *
from mitsuba.render import *
from collections import OrderedDict
def rgb_spectrum(r, g, b):
spec = Spectrum()
spec.fromLinearRGB(r, g, b)
return spec
# Map that explains what functionality different plugins implement
plugin_type_map ={
'sphere' : 'shape',
'instance' : 'shape',
'shapegroup' : 'shape',
'diffuse' : 'bsdf',
'orthographic' : 'sensor' # need to complete
}
# Scene description as a big dictionary. The outermost layer
# should be ordered so that references can be processed correctly
scene_descr = OrderedDict([
('type', 'scene'),
('shapegroup_0', {
'type' : 'shapegroup',
'id' : 'my_shapegroup',
'some_child_geometry' : {
'type' : 'sphere',
'bsdf' : {
'type' : 'diffuse',
'reflectance' : rgb_spectrum(0.5, 0.7, 0.1)
}
}
}),
('instance_0', {
'type' : 'instance',
# This is how a reference is specified (type='ref')
'reference_to_shapegroup' : {
'type' : 'ref',
'id' : 'my_shapegroup'
},
'toWorld' : Transform.translate(Vector(1, 2.5, 3))
}),
('sensor_0', {
'type' : 'orthographic',
'toWorld' : Transform.lookAt(Point(0, 0, -1),
Point(0, 0, 0), Vector(0, 1, 0)) * Transform.scale(Vector(10, 10, 1))
})
])
def scene_descr_to_xml(descr):
import xml.etree.cElementTree as et
from xml.dom import minidom
def property_to_xml(key, value, parent):
if type(value) is Transform:
el = et.SubElement(parent, 'transform')
el.set('name', key)
el2 = et.SubElement(el, 'matrix')
matrix = value.getMatrix()
matrix_str = ""
for i in range(4):
for j in range(4):
matrix_str += "%.15g " % matrix[(i, j)]
el2.set('value', matrix_str[:-1])
elif type(value) is Spectrum:
r, g, b = value.toLinearRGB()
el = et.SubElement(parent, 'rgb')
el.set('name', key)
el.set('value', "%.15g %.15g %.15g" % (r, g, b))
elif type(value) is Point:
el = et.SubElement(parent, 'point')
el.set('name', key)
el.set('x', '%.15g' % value.x)
el.set('y', '%.15g' % value.y)
el.set('z', '%.15g' % value.z)
elif type(value) is Vector:
el = et.SubElement(parent, 'vector')
el.set('name', key)
el.set('x', '%.15g' % value.x)
el.set('y', '%.15g' % value.y)
el.set('z', '%.15g' % value.z)
elif type(value) is float:
el = et.SubElement(parent, 'float')
el.set('name', key)
el.set('value', '%.15g' % value)
elif type(value) is int:
el = et.SubElement(parent, 'int')
el.set('name', key)
el.set('value', '%i' % value)
elif type(value) is bool:
el = et.SubElement(parent, 'boolean')
el.set('name', key)
el.set('value', '%s' % ('true' if value else 'false'))
elif type(value) is str:
el = et.SubElement(parent, 'string')
el.set('name', key)
el.set('value', value)
else:
return None # (More kinds of attributes may need to be supported here..)
return el
def dict_to_xml(name, item, parent):
if parent is None:
el = et.Element('scene')
elif item['type'] == 'ref':
el = et.SubElement(parent, 'ref')
el.set('name', name)
el.set('id', item['id'])
else:
el = et.SubElement(parent, plugin_type_map[item['type']])
el.set('type', item['type'])
if name:
el.set('name', name)
if 'id' in item:
el.set('id', item['id'])
for key, value in item.items():
if key == 'id' or key == 'type':
continue
if type(value) is dict:
dict_to_xml(key, value, el)
else:
property_to_xml(key, value, el)
return el
root = dict_to_xml(None, descr, None)
root.set('version', $\texttt{\MitsubaVersion}$)
# Indent the ElementTree output (unfortunately this involves re-parsing..)
return minidom.parseString(
et.tostring(root, 'utf-8')).toprettyxml(indent='\t')
print('Mitsuba version: ')
print(PluginManager.getInstance().create(scene_descr))
print('XML version: ')
print(scene_descr_to_xml(scene_descr))
\end{python}
\subsubsection{Taking control of the logging system} \subsubsection{Taking control of the logging system}
Many operations in Mitsuba will print one or more log messages Many operations in Mitsuba will print one or more log messages
during their execution. By default, they will be printed to the console, during their execution. By default, they will be printed to the console,

View File

@ -223,6 +223,16 @@ public:
*/ */
EPFM, EPFM,
/**
* \brief PPM (Portable Pixel Map) image format
*
* The following is supported
* <ul>
* <li>Loading and saving of \ref EUInt8 and \ref EUInt16 - based RGB bitmaps</li>
* </ul>
*/
EPPM,
/** /**
* \brief Joint Photographic Experts Group file format * \brief Joint Photographic Experts Group file format
* *
@ -678,12 +688,17 @@ public:
* specified component format. Names for each of the resulting channels should * specified component format. Names for each of the resulting channels should
* be provided via the \c channelNames parameters. * be provided via the \c channelNames parameters.
* *
* This function is currently only used by the \c hdrfilm plugin but located here * This feature is currently used by the \c hdrfilm and \c tiledhdrfilm plugins.
* as it is tied to the internals of this class.
*/ */
ref<Bitmap> convertMultiSpectrumAlphaWeight(const std::vector<EPixelFormat> &pixelFormats, ref<Bitmap> convertMultiSpectrumAlphaWeight(const std::vector<EPixelFormat> &pixelFormats,
EComponentFormat componentFormat, const std::vector<std::string> &channelNames) const; EComponentFormat componentFormat, const std::vector<std::string> &channelNames) const;
/// Similar to the above, but writes to an already existing image
static void convertMultiSpectrumAlphaWeight(const Bitmap *source,
const uint8_t *sourcePtr, const Bitmap *target, uint8_t *targetPtr,
const std::vector<EPixelFormat> &pixelFormats,
EComponentFormat componentFormat, size_t count);
/** /**
* \brief Apply Reinhard et al's tonemapper in chromaticity space * \brief Apply Reinhard et al's tonemapper in chromaticity space
* *
@ -1110,6 +1125,12 @@ protected:
/// Write a file using the PFM file format /// Write a file using the PFM file format
void writePFM(Stream *stream) const; void writePFM(Stream *stream) const;
/// Read a file stored using the PPM file format
void readPPM(Stream *stream);
/// Write a file using the PPM file format
void writePPM(Stream *stream) const;
/// Read a file stored using the TGA file format /// Read a file stored using the TGA file format
void readTGA(Stream *stream); void readTGA(Stream *stream);

View File

@ -67,6 +67,7 @@ protected:
* \ingroup libpython * \ingroup libpython
*/ */
class MTS_EXPORT_CORE DefaultFormatter : public Formatter { class MTS_EXPORT_CORE DefaultFormatter : public Formatter {
friend class Logger;
public: public:
/// Create a new default formatter /// Create a new default formatter
DefaultFormatter(); DefaultFormatter();

View File

@ -26,13 +26,13 @@ MTS_NAMESPACE_BEGIN
* \brief Current release of Mitsuba * \brief Current release of Mitsuba
* \ingroup libcore * \ingroup libcore
*/ */
#define MTS_VERSION "0.4.5" #define MTS_VERSION "0.5.0"
/** /**
* \brief Year of the current release * \brief Year of the current release
* \ingroup libcore * \ingroup libcore
*/ */
#define MTS_YEAR "2013" #define MTS_YEAR "2014"
/** /**
* \brief A simple data structure for representing and * \brief A simple data structure for representing and

View File

@ -28,7 +28,9 @@ MTS_NAMESPACE_BEGIN
* \brief Von Mises-Fisher distribution on the 2-sphere * \brief Von Mises-Fisher distribution on the 2-sphere
* *
* This is a basic implementation, which assumes that the * This is a basic implementation, which assumes that the
* distribution is centered around the Z-axis. * distribution is centered around the Z-axis. All provided
* functions are implemented in such a way that they avoid
* issues with numerical overflow.
* *
* \author Wenzel Jakob * \author Wenzel Jakob
* \ingroup libcore * \ingroup libcore
@ -39,13 +41,21 @@ public:
* \brief Create a new von Mises-Fisher distribution * \brief Create a new von Mises-Fisher distribution
* with the given concentration parameter * with the given concentration parameter
*/ */
VonMisesFisherDistr(Float kappa = 0); explicit inline VonMisesFisherDistr(Float kappa = 0) : m_kappa(kappa) { }
/// Return the concentration parameter kappa
inline void setKappa(Float kappa) {
m_kappa = kappa;
}
/// Return the concentration parameter kappa /// Return the concentration parameter kappa
inline Float getKappa() const { inline Float getKappa() const {
return m_kappa; return m_kappa;
} }
/// Return the mean cosine of the distribution
Float getMeanCosine() const;
/// Evaluate the distribution for a given value of cos(theta) /// Evaluate the distribution for a given value of cos(theta)
Float eval(Float cosTheta) const; Float eval(Float cosTheta) const;
@ -57,12 +67,21 @@ public:
*/ */
Vector sample(const Point2 &sample) const; Vector sample(const Point2 &sample) const;
/// Return a string representation
std::string toString() const;
/** /**
* \brief Compute an appropriate concentration parameter so that * \brief Compute an appropriate concentration parameter so that
* the associated vMF distribution takes on the value \c x at its peak * the associated vMF distribution takes on the value \c x at its peak
*/ */
static Float forPeakValue(Float x); static Float forPeakValue(Float x);
/**
* \brief Compute an appropriate concentration parameter so that
* the associated vMF distribution has the mean cosine \c g.
*/
static Float forMeanCosine(Float g);
/** /**
* \brief Compute an concentration parameter that approximately * \brief Compute an concentration parameter that approximately
* corresponds to the spherical convolution of two vMF distributions. * corresponds to the spherical convolution of two vMF distributions.

View File

@ -2198,6 +2198,21 @@ protected:
*newEventsLeftEnd = newEventsLeftStart, *newEventsLeftEnd = newEventsLeftStart,
*newEventsRightEnd = newEventsRightStart; *newEventsRightEnd = newEventsRightStart;
AABBType leftNodeAABB_enlarged(leftNodeAABB),
rightNodeAABB_enlarged(rightNodeAABB);
#if defined(DOUBLE_PRECISION)
int axis0 = (bestSplit.axis + 1)%3, axis1 = (bestSplit.axis + 2)%3;
leftNodeAABB_enlarged.min[axis0] = rightNodeAABB_enlarged.min[axis0] =
nextafterf((float) nodeAABB.min[axis0], -std::numeric_limits<float>::max());
leftNodeAABB_enlarged.max[axis0] = rightNodeAABB_enlarged.max[axis0] =
nextafterf((float) nodeAABB.max[axis0], std::numeric_limits<float>::max());
leftNodeAABB_enlarged.min[axis1] = rightNodeAABB_enlarged.min[axis1] =
nextafterf((float) nodeAABB.min[axis1], -std::numeric_limits<float>::max());
leftNodeAABB_enlarged.max[axis1] = rightNodeAABB_enlarged.max[axis1] =
nextafterf((float) nodeAABB.max[axis1], std::numeric_limits<float>::max());
#endif
for (EdgeEvent *event = eventStart; event<eventEnd; ++event) { for (EdgeEvent *event = eventStart; event<eventEnd; ++event) {
int classification = storage.get(event->index); int classification = storage.get(event->index);
@ -2212,11 +2227,11 @@ protected:
generate new events for each side */ generate new events for each side */
const IndexType index = event->index; const IndexType index = event->index;
AABBType clippedLeft = cast()->getClippedAABB(index, leftNodeAABB); AABBType clippedLeft = cast()->getClippedAABB(index, leftNodeAABB_enlarged);
AABBType clippedRight = cast()->getClippedAABB(index, rightNodeAABB); AABBType clippedRight = cast()->getClippedAABB(index, rightNodeAABB_enlarged);
KDAssert(leftNodeAABB.contains(clippedLeft)); KDAssert(leftNodeAABB_enlarged.contains(clippedLeft));
KDAssert(rightNodeAABB.contains(clippedRight)); KDAssert(rightNodeAABB_enlarged.contains(clippedRight));
if (clippedLeft.isValid() && clippedLeft.getSurfaceArea() > 0) { if (clippedLeft.isValid() && clippedLeft.getSurfaceArea() > 0) {
for (int axis=0; axis<PointType::dim; ++axis) { for (int axis=0; axis<PointType::dim; ++axis) {

View File

@ -206,7 +206,7 @@ public:
/// Create a clone of the entire image block /// Create a clone of the entire image block
ref<ImageBlock> clone() const { ref<ImageBlock> clone() const {
ref<ImageBlock> clone = new ImageBlock(m_bitmap->getPixelFormat(), ref<ImageBlock> clone = new ImageBlock(m_bitmap->getPixelFormat(),
m_bitmap->getSize() - Vector2i(2*m_borderSize, 2*m_borderSize), m_filter); m_bitmap->getSize() - Vector2i(2*m_borderSize, 2*m_borderSize), m_filter, m_bitmap->getChannelCount());
copyTo(clone); copyTo(clone);
return clone; return clone;
} }

View File

@ -196,8 +196,15 @@ public:
/* Potentially create a MIP map cache file */ /* Potentially create a MIP map cache file */
uint8_t *mmapData = NULL, *mmapPtr = NULL; uint8_t *mmapData = NULL, *mmapPtr = NULL;
if (!cacheFilename.empty()) { if (!cacheFilename.empty()) {
Log(EInfo, "Generating MIP map cache file \"%s\" ..", cacheFilename.c_str()); Log(EInfo, "Generating MIP map cache file \"%s\" ..", cacheFilename.string().c_str());
m_mmap = new MemoryMappedFile(cacheFilename, cacheSize); try {
m_mmap = new MemoryMappedFile(cacheFilename, cacheSize);
} catch (std::runtime_error &e) {
Log(EWarn, "Unable to create MIP map cache file \"%s\" -- "
"retrying with a temporary file. Error message was: %s",
cacheFilename.string().c_str(), e.what());
m_mmap = MemoryMappedFile::createTemporary(cacheSize);
}
mmapData = mmapPtr = (uint8_t *) m_mmap->getData(); mmapData = mmapPtr = (uint8_t *) m_mmap->getData();
} }
@ -313,7 +320,7 @@ public:
: m_weightLut(NULL), m_maxAnisotropy(maxAnisotropy) { : m_weightLut(NULL), m_maxAnisotropy(maxAnisotropy) {
m_mmap = new MemoryMappedFile(cacheFilename); m_mmap = new MemoryMappedFile(cacheFilename);
uint8_t *mmapPtr = (uint8_t *) m_mmap->getData(); uint8_t *mmapPtr = (uint8_t *) m_mmap->getData();
Log(EInfo, "Mapped MIP map cache file \"%s\" into memory (%s).", cacheFilename.c_str(), Log(EInfo, "Mapped MIP map cache file \"%s\" into memory (%s).", cacheFilename.string().c_str(),
memString(m_mmap->getSize()).c_str()); memString(m_mmap->getSize()).c_str());
stats::mipStorage += m_mmap->getSize(); stats::mipStorage += m_mmap->getSize();

View File

@ -85,8 +85,7 @@ public:
typedef std::map<std::string, ConfigurableObject *> NamedObjectMap; typedef std::map<std::string, ConfigurableObject *> NamedObjectMap;
typedef std::map<std::string, std::string, SimpleStringOrdering> ParameterMap; typedef std::map<std::string, std::string, SimpleStringOrdering> ParameterMap;
SceneHandler(const xercesc::SAXParser *parser, SceneHandler(const ParameterMap &params, NamedObjectMap *objects = NULL,
const ParameterMap &params, NamedObjectMap *objects = NULL,
bool isIncludedFile = false); bool isIncludedFile = false);
virtual ~SceneHandler(); virtual ~SceneHandler();
@ -115,6 +114,7 @@ public:
); );
virtual void endElement(const XMLCh* const name); virtual void endElement(const XMLCh* const name);
virtual void characters(const XMLCh* const chars, const XMLSize_t length); virtual void characters(const XMLCh* const chars, const XMLSize_t length);
virtual void setDocumentLocator(const xercesc::Locator* const locator);
inline const Scene *getScene() const { return m_scene.get(); } inline const Scene *getScene() const { return m_scene.get(); }
inline Scene *getScene() { return m_scene; } inline Scene *getScene() { return m_scene; }
@ -166,12 +166,7 @@ private:
typedef std::pair<ETag, const Class *> TagEntry; typedef std::pair<ETag, const Class *> TagEntry;
typedef boost::unordered_map<std::string, TagEntry> TagMap; typedef boost::unordered_map<std::string, TagEntry> TagMap;
#if defined(__clang__) const xercesc::Locator *m_locator;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-private-field"
#endif
const xercesc::SAXParser *m_parser;
xercesc::XMLTranscoder* m_transcoder; xercesc::XMLTranscoder* m_transcoder;
ref<Scene> m_scene; ref<Scene> m_scene;
ParameterMap m_params; ParameterMap m_params;
@ -182,10 +177,6 @@ private:
Transform m_transform; Transform m_transform;
ref<AnimatedTransform> m_animatedTransform; ref<AnimatedTransform> m_animatedTransform;
bool m_isIncludedFile; bool m_isIncludedFile;
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
}; };
MTS_NAMESPACE_END MTS_NAMESPACE_END

View File

@ -7,10 +7,7 @@ if hasCollada:
import platform import platform
colladaEnv = mainEnv.Clone() colladaEnv = mainEnv.Clone()
if platform.linux_distribution()[0] == 'Fedora': colladaEnv.Prepend(CXXFLAGS=['-DCOLLADA_DOM_2_4'])
pass # Use old COLLADA-DOM 2.3
else: # Everyone else uses 2.4
colladaEnv.Prepend(CXXFLAGS=['-DCOLLADA_DOM_2_4'])
# Build the COLLADA importer if COLLADA-DOM is vailable # Build the COLLADA importer if COLLADA-DOM is vailable
colladaEnv.Append(LIBS=['mitsuba-hw']) colladaEnv.Append(LIBS=['mitsuba-hw'])

View File

@ -215,7 +215,7 @@ public:
std::vector<std::string> pixelFormats = tokenize(boost::to_lower_copy( std::vector<std::string> pixelFormats = tokenize(boost::to_lower_copy(
props.getString("pixelFormat", "rgb")), " ,"); props.getString("pixelFormat", "rgb")), " ,");
std::vector<std::string> channelNames = tokenize( std::vector<std::string> channelNames = tokenize(
props.getString("channelNames", "rgb"), ", "); props.getString("channelNames", ""), ", ");
std::string componentFormat = boost::to_lower_copy( std::string componentFormat = boost::to_lower_copy(
props.getString("componentFormat", "float16")); props.getString("componentFormat", "float16"));
@ -227,58 +227,64 @@ public:
m_fileFormat = Bitmap::EPFM; m_fileFormat = Bitmap::EPFM;
} else { } else {
Log(EError, "The \"fileFormat\" parameter must either be " Log(EError, "The \"fileFormat\" parameter must either be "
"equal to \"openexr\" or \"rgbe\"!"); "equal to \"openexr\", \"pfm\", or \"rgbe\"!");
} }
if (pixelFormats.empty()) if (pixelFormats.empty())
Log(EError, "At least one pixel format must be specified!"); Log(EError, "At least one pixel format must be specified!");
if (m_pixelFormats.size() != 1 && m_channelNames.size() != m_pixelFormats.size()) if (pixelFormats.size() != 1 && channelNames.size() != pixelFormats.size())
Log(EError, "Number of channel names must match the number of specified pixel formats!"); Log(EError, "Number of channel names must match the number of specified pixel formats!");
if (pixelFormats.size() != 1 && m_fileFormat != Bitmap::EOpenEXR)
Log(EError, "General multi-channel output is only supported when writing OpenEXR files!");
for (size_t i=0; i<pixelFormats.size(); ++i) { for (size_t i=0; i<pixelFormats.size(); ++i) {
std::string pixelFormat = pixelFormats[i]; std::string pixelFormat = pixelFormats[i];
std::string name = i < channelNames.size() ? channelNames[i] : ""; std::string name = i < channelNames.size() ? (channelNames[i] + std::string(".")) : "";
if (pixelFormat == "luminance") { if (pixelFormat == "luminance") {
m_pixelFormats.push_back(Bitmap::ELuminance); m_pixelFormats.push_back(Bitmap::ELuminance);
m_channelNames.push_back(name + ".Y"); m_channelNames.push_back(name + "Y");
} else if (pixelFormat == "luminancealpha") { } else if (pixelFormat == "luminancealpha") {
m_pixelFormats.push_back(Bitmap::ELuminanceAlpha); m_pixelFormats.push_back(Bitmap::ELuminanceAlpha);
m_channelNames.push_back(name + ".Y"); m_channelNames.push_back(name + "Y");
m_channelNames.push_back(name + ".A"); m_channelNames.push_back(name + "A");
} else if (pixelFormat == "rgb") { } else if (pixelFormat == "rgb") {
m_pixelFormats.push_back(Bitmap::ERGB); m_pixelFormats.push_back(Bitmap::ERGB);
m_channelNames.push_back(name + ".R"); m_channelNames.push_back(name + "R");
m_channelNames.push_back(name + ".G"); m_channelNames.push_back(name + "G");
m_channelNames.push_back(name + ".B"); m_channelNames.push_back(name + "B");
} else if (pixelFormat == "rgba") { } else if (pixelFormat == "rgba") {
m_pixelFormats.push_back(Bitmap::ERGBA); m_pixelFormats.push_back(Bitmap::ERGBA);
m_channelNames.push_back(name + ".R"); m_channelNames.push_back(name + "R");
m_channelNames.push_back(name + ".G"); m_channelNames.push_back(name + "G");
m_channelNames.push_back(name + ".B"); m_channelNames.push_back(name + "B");
m_channelNames.push_back(name + ".A"); m_channelNames.push_back(name + "A");
} else if (pixelFormat == "xyz") { } else if (pixelFormat == "xyz") {
m_pixelFormats.push_back(Bitmap::EXYZ); m_pixelFormats.push_back(Bitmap::EXYZ);
if (m_pixelFormats.size() > 1) m_channelNames.push_back(name + "X");
Log(EError, "The XYZ pixel format is not supported for general multi-channel images!"); m_channelNames.push_back(name + "Y");
m_channelNames.push_back(name + "Z");
} else if (pixelFormat == "xyza") { } else if (pixelFormat == "xyza") {
m_pixelFormats.push_back(Bitmap::EXYZA); m_pixelFormats.push_back(Bitmap::EXYZA);
if (m_pixelFormats.size() > 1) m_channelNames.push_back(name + "X");
Log(EError, "The XYZA pixel format is not supported for general multi-channel images!"); m_channelNames.push_back(name + "Y");
m_channelNames.push_back(name + "Z");
m_channelNames.push_back(name + "A");
} else if (pixelFormat == "spectrum") { } else if (pixelFormat == "spectrum") {
m_pixelFormats.push_back(Bitmap::ESpectrum); m_pixelFormats.push_back(Bitmap::ESpectrum);
for (int i=0; i<SPECTRUM_SAMPLES; ++i) { for (int i=0; i<SPECTRUM_SAMPLES; ++i) {
std::pair<Float, Float> coverage = Spectrum::getBinCoverage(i); std::pair<Float, Float> coverage = Spectrum::getBinCoverage(i);
m_channelNames.push_back(name + formatString(".%.2f-%.2fnm", coverage.first, coverage.second)); m_channelNames.push_back(name + formatString("%.2f-%.2fnm", coverage.first, coverage.second));
} }
} else if (pixelFormat == "spectrumalpha") { } else if (pixelFormat == "spectrumalpha") {
m_pixelFormats.push_back(Bitmap::ESpectrumAlpha); m_pixelFormats.push_back(Bitmap::ESpectrumAlpha);
for (int i=0; i<SPECTRUM_SAMPLES; ++i) { for (int i=0; i<SPECTRUM_SAMPLES; ++i) {
std::pair<Float, Float> coverage = Spectrum::getBinCoverage(i); std::pair<Float, Float> coverage = Spectrum::getBinCoverage(i);
m_channelNames.push_back(name + formatString(".%.2f-%.2fnm", coverage.first, coverage.second)); m_channelNames.push_back(name + formatString("%.2f-%.2fnm", coverage.first, coverage.second));
} }
m_channelNames.push_back(name + ".A"); m_channelNames.push_back(name + "A");
} else { } else {
Log(EError, "The \"pixelFormat\" parameter must either be equal to " Log(EError, "The \"pixelFormat\" parameter must either be equal to "
"\"luminance\", \"luminanceAlpha\", \"rgb\", \"rgba\", \"xyz\", \"xyza\", " "\"luminance\", \"luminanceAlpha\", \"rgb\", \"rgba\", \"xyz\", \"xyza\", "
@ -529,13 +535,14 @@ public:
} }
bool hasAlpha() const { bool hasAlpha() const {
Assert(m_pixelFormats.size() > 0); for (size_t i=0; i<m_pixelFormats.size(); ++i) {
return if (m_pixelFormats[i] == Bitmap::ELuminanceAlpha ||
m_pixelFormats[0] == Bitmap::ELuminanceAlpha || m_pixelFormats[i] == Bitmap::ERGBA ||
m_pixelFormats[0] == Bitmap::ERGBA || m_pixelFormats[i] == Bitmap::EXYZA ||
m_pixelFormats[0] == Bitmap::EXYZA || m_pixelFormats[i] == Bitmap::ESpectrumAlpha)
m_pixelFormats[0] == Bitmap::ESpectrumAlpha || return true;
m_pixelFormats.size() > 1; }
return false;
} }
bool destinationExists(const fs::path &baseName) const { bool destinationExists(const fs::path &baseName) const {

View File

@ -101,37 +101,78 @@ MTS_NAMESPACE_BEGIN
class TiledHDRFilm : public Film { class TiledHDRFilm : public Film {
public: public:
TiledHDRFilm(const Properties &props) : Film(props), m_output(NULL), m_frameBuffer(NULL) { TiledHDRFilm(const Properties &props) : Film(props), m_output(NULL), m_frameBuffer(NULL) {
std::string pixelFormat = boost::to_lower_copy( std::vector<std::string> pixelFormats = tokenize(boost::to_lower_copy(
props.getString("pixelFormat", "rgb")); props.getString("pixelFormat", "rgb")), " ,");
std::vector<std::string> channelNames = tokenize(
props.getString("channelNames", ""), ", ");
std::string componentFormat = boost::to_lower_copy( std::string componentFormat = boost::to_lower_copy(
props.getString("componentFormat", "float16")); props.getString("componentFormat", "float16"));
if (pixelFormat == "luminance") { if (pixelFormats.empty())
m_pixelFormat = Bitmap::ELuminance; Log(EError, "At least one pixel format must be specified!");
} else if (pixelFormat == "luminancealpha") {
m_pixelFormat = Bitmap::ELuminanceAlpha; if (pixelFormats.size() != 1 && channelNames.size() != pixelFormats.size())
} else if (pixelFormat == "rgb") { Log(EError, "Number of channel names must match the number of specified pixel formats!");
m_pixelFormat = Bitmap::ERGB;
} else if (pixelFormat == "rgba") { for (size_t i=0; i<pixelFormats.size(); ++i) {
m_pixelFormat = Bitmap::ERGBA; std::string pixelFormat = pixelFormats[i];
} else if (pixelFormat == "xyz") { std::string name = i < channelNames.size() ? (channelNames[i] + std::string(".")) : "";
m_pixelFormat = Bitmap::EXYZ;
} else if (pixelFormat == "xyza") { if (pixelFormat == "luminance") {
m_pixelFormat = Bitmap::EXYZA; m_pixelFormats.push_back(Bitmap::ELuminance);
} else if (pixelFormat == "spectrum") { m_channelNames.push_back(name + "Y");
m_pixelFormat = Bitmap::ESpectrum; } else if (pixelFormat == "luminancealpha") {
} else if (pixelFormat == "spectrumalpha") { m_pixelFormats.push_back(Bitmap::ELuminanceAlpha);
m_pixelFormat = Bitmap::ESpectrumAlpha; m_channelNames.push_back(name + "Y");
} else { m_channelNames.push_back(name + "A");
Log(EError, "The \"pixelFormat\" parameter must either be equal to " } else if (pixelFormat == "rgb") {
"\"luminance\", \"luminanceAlpha\", \"rgb\", \"rgba\", \"xyz\", \"xyza\", " m_pixelFormats.push_back(Bitmap::ERGB);
"\"spectrum\", or \"spectrumAlpha\"!"); m_channelNames.push_back(name + "R");
m_channelNames.push_back(name + "G");
m_channelNames.push_back(name + "B");
} else if (pixelFormat == "rgba") {
m_pixelFormats.push_back(Bitmap::ERGBA);
m_channelNames.push_back(name + "R");
m_channelNames.push_back(name + "G");
m_channelNames.push_back(name + "B");
m_channelNames.push_back(name + "A");
} else if (pixelFormat == "xyz") {
m_pixelFormats.push_back(Bitmap::EXYZ);
m_channelNames.push_back(name + "X");
m_channelNames.push_back(name + "Y");
m_channelNames.push_back(name + "Z");
} else if (pixelFormat == "xyza") {
m_pixelFormats.push_back(Bitmap::EXYZA);
m_channelNames.push_back(name + "X");
m_channelNames.push_back(name + "Y");
m_channelNames.push_back(name + "Z");
m_channelNames.push_back(name + "A");
} else if (pixelFormat == "spectrum") {
m_pixelFormats.push_back(Bitmap::ESpectrum);
for (int i=0; i<SPECTRUM_SAMPLES; ++i) {
std::pair<Float, Float> coverage = Spectrum::getBinCoverage(i);
m_channelNames.push_back(name + formatString("%.2f-%.2fnm", coverage.first, coverage.second));
}
} else if (pixelFormat == "spectrumalpha") {
m_pixelFormats.push_back(Bitmap::ESpectrumAlpha);
for (int i=0; i<SPECTRUM_SAMPLES; ++i) {
std::pair<Float, Float> coverage = Spectrum::getBinCoverage(i);
m_channelNames.push_back(name + formatString("%.2f-%.2fnm", coverage.first, coverage.second));
}
m_channelNames.push_back(name + "A");
} else {
Log(EError, "The \"pixelFormat\" parameter must either be equal to "
"\"luminance\", \"luminanceAlpha\", \"rgb\", \"rgba\", \"xyz\", \"xyza\", "
"\"spectrum\", or \"spectrumAlpha\"!");
}
} }
if (SPECTRUM_SAMPLES == 3 && (m_pixelFormat == Bitmap::ESpectrum || m_pixelFormat == Bitmap::ESpectrumAlpha)) for (size_t i=0; i<m_pixelFormats.size(); ++i) {
Log(EError, "You requested to render a spectral image, but Mitsuba is currently " if (SPECTRUM_SAMPLES == 3 && (m_pixelFormats[i] == Bitmap::ESpectrum || m_pixelFormats[i] == Bitmap::ESpectrumAlpha))
"configured for a RGB flow (i.e. SPECTRUM_SAMPLES = 3). You will need to recompile " Log(EError, "You requested to render a spectral image, but Mitsuba is currently "
"it with a different configuration. Please see the documentation for details."); "configured for a RGB flow (i.e. SPECTRUM_SAMPLES = 3). You will need to recompile "
"it with a different configuration. Please see the documentation for details.");
}
if (componentFormat == "float16") { if (componentFormat == "float16") {
m_componentFormat = Bitmap::EFloat16; m_componentFormat = Bitmap::EFloat16;
@ -151,7 +192,12 @@ public:
TiledHDRFilm(Stream *stream, InstanceManager *manager) TiledHDRFilm(Stream *stream, InstanceManager *manager)
: Film(stream, manager), m_output(NULL), m_frameBuffer(NULL) { : Film(stream, manager), m_output(NULL), m_frameBuffer(NULL) {
m_pixelFormat = (Bitmap::EPixelFormat) stream->readUInt(); m_pixelFormats.resize((size_t) stream->readUInt());
for (size_t i=0; i<m_pixelFormats.size(); ++i)
m_pixelFormats[i] = (Bitmap::EPixelFormat) stream->readUInt();
m_channelNames.resize((size_t) stream->readUInt());
for (size_t i=0; i<m_channelNames.size(); ++i)
m_channelNames[i] = stream->readString();
m_componentFormat = (Bitmap::EComponentFormat) stream->readUInt(); m_componentFormat = (Bitmap::EComponentFormat) stream->readUInt();
} }
@ -161,7 +207,11 @@ public:
void serialize(Stream *stream, InstanceManager *manager) const { void serialize(Stream *stream, InstanceManager *manager) const {
Film::serialize(stream, manager); Film::serialize(stream, manager);
stream->writeUInt(m_pixelFormat); for (size_t i=0; i<m_pixelFormats.size(); ++i)
stream->writeUInt(m_pixelFormats[i]);
stream->writeUInt((uint32_t) m_channelNames.size());
for (size_t i=0; i<m_channelNames.size(); ++i)
stream->writeString(m_channelNames[i]);
stream->writeUInt(m_componentFormat); stream->writeUInt(m_componentFormat);
} }
@ -169,15 +219,6 @@ public:
if (m_output) if (m_output)
develop(NULL, 0); develop(NULL, 0);
Bitmap::EPixelFormat pixelFormat = m_pixelFormat;
#if SPECTRUM_SAMPLES == 3
if (pixelFormat == Bitmap::ESpectrum)
pixelFormat = Bitmap::ERGB;
if (pixelFormat == Bitmap::ESpectrumAlpha)
pixelFormat = Bitmap::ERGBA;
#endif
fs::path filename = destFile; fs::path filename = destFile;
std::string extension = boost::to_lower_copy(filename.extension().string()); std::string extension = boost::to_lower_copy(filename.extension().string());
if (extension != ".exr") if (extension != ".exr")
@ -189,19 +230,22 @@ public:
header.setTileDescription(Imf::TileDescription(blockSize, blockSize, Imf::ONE_LEVEL)); header.setTileDescription(Imf::TileDescription(blockSize, blockSize, Imf::ONE_LEVEL));
header.insert("generated-by", Imf::StringAttribute("Mitsuba version " MTS_VERSION)); header.insert("generated-by", Imf::StringAttribute("Mitsuba version " MTS_VERSION));
if (pixelFormat == Bitmap::EXYZ || pixelFormat == Bitmap::EXYZA) { if (m_pixelFormats.size() == 1) {
Imf::addChromaticities(header, Imf::Chromaticities( /* Write a chromaticity tag when this is possible */
Imath::V2f(1.0f, 0.0f), Bitmap::EPixelFormat pixelFormat = m_pixelFormats[0];
Imath::V2f(0.0f, 1.0f), if (pixelFormat == Bitmap::EXYZ || pixelFormat == Bitmap::EXYZA) {
Imath::V2f(0.0f, 0.0f), Imf::addChromaticities(header, Imf::Chromaticities(
Imath::V2f(1.0f/3.0f, 1.0f/3.0f))); Imath::V2f(1.0f, 0.0f),
} else if (pixelFormat == Bitmap::ERGB || pixelFormat == Bitmap::ERGBA) { Imath::V2f(0.0f, 1.0f),
Imf::addChromaticities(header, Imf::Chromaticities()); Imath::V2f(0.0f, 0.0f),
Imath::V2f(1.0f/3.0f, 1.0f/3.0f)));
} else if (pixelFormat == Bitmap::ERGB || pixelFormat == Bitmap::ERGBA) {
Imf::addChromaticities(header, Imf::Chromaticities());
}
} }
Imf::PixelType compType; Imf::PixelType compType;
size_t compStride; size_t compStride;
int channelCount;
if (m_componentFormat == Bitmap::EFloat16) { if (m_componentFormat == Bitmap::EFloat16) {
compType = Imf::HALF; compType = Imf::HALF;
@ -219,62 +263,34 @@ public:
} }
Imf::ChannelList &channels = header.channels(); Imf::ChannelList &channels = header.channels();
if (pixelFormat == Bitmap::ELuminance || pixelFormat == Bitmap::ELuminanceAlpha) { for (size_t i=0; i<m_channelNames.size(); ++i)
channels.insert("Y", Imf::Channel(compType)); channels.insert(m_channelNames[i].c_str(), Imf::Channel(compType));
channelCount = 1;
} else if (pixelFormat == Bitmap::ERGB || pixelFormat == Bitmap::ERGBA ||
pixelFormat == Bitmap::EXYZ || pixelFormat == Bitmap::EXYZA) {
channels.insert("R", Imf::Channel(compType));
channels.insert("G", Imf::Channel(compType));
channels.insert("B", Imf::Channel(compType));
channelCount = 3;
} else if (pixelFormat == Bitmap::ESpectrum || pixelFormat == Bitmap::ESpectrumAlpha) {
for (int i=0; i<SPECTRUM_SAMPLES; ++i) {
std::pair<Float, Float> coverage = Spectrum::getBinCoverage(i);
std::string name = formatString("%.2f-%.2fnm", coverage.first, coverage.second);
channels.insert(name.c_str(), Imf::Channel(compType));
}
channelCount = SPECTRUM_SAMPLES;
} else {
Log(EError, "Invalid pixel format!");
return;
}
if (m_pixelFormat == Bitmap::ELuminanceAlpha || m_pixelFormat == Bitmap::ERGBA ||
m_pixelFormat == Bitmap::ESpectrumAlpha) {
channels.insert("A", Imf::Channel(compType));
channelCount++;
}
m_output = new Imf::TiledOutputFile(filename.string().c_str(), header); m_output = new Imf::TiledOutputFile(filename.string().c_str(), header);
m_frameBuffer = new Imf::FrameBuffer(); m_frameBuffer = new Imf::FrameBuffer();
m_blockSize = (int) blockSize; m_blockSize = (int) blockSize;
m_tile = new Bitmap(m_pixelFormat, m_componentFormat, Vector2i(m_blockSize, m_blockSize));
m_blocksH = (m_size.x + blockSize - 1) / blockSize; m_blocksH = (m_size.x + blockSize - 1) / blockSize;
m_blocksV = (m_size.y + blockSize - 1) / blockSize; m_blocksV = (m_size.y + blockSize - 1) / blockSize;
m_pixelStride = channelCount * compStride; m_pixelStride = m_channelNames.size() * compStride;
m_rowStride = m_pixelStride * m_blockSize; m_rowStride = m_pixelStride * m_blockSize;
char *ptr = (char *) m_tile->getUInt8Data();
if (pixelFormat == Bitmap::ELuminance || pixelFormat == Bitmap::ELuminanceAlpha) { if (m_pixelFormats.size() == 1) {
m_frameBuffer->insert("Y", Imf::Slice(compType, ptr, m_pixelStride, m_rowStride)); ptr += compStride; m_tile = new Bitmap(m_pixelFormats[0], m_componentFormat,
} else if (pixelFormat == Bitmap::ERGB || pixelFormat == Bitmap::ERGBA || Vector2i(m_blockSize, m_blockSize));
pixelFormat == Bitmap::EXYZ || pixelFormat == Bitmap::EXYZA) { } else {
m_frameBuffer->insert("R", Imf::Slice(compType, ptr, m_pixelStride, m_rowStride)); ptr += compStride; m_tile = new Bitmap(Bitmap::EMultiChannel, m_componentFormat,
m_frameBuffer->insert("G", Imf::Slice(compType, ptr, m_pixelStride, m_rowStride)); ptr += compStride; Vector2i(m_blockSize, m_blockSize), m_channelNames.size());
m_frameBuffer->insert("B", Imf::Slice(compType, ptr, m_pixelStride, m_rowStride)); ptr += compStride; m_tile->setChannelNames(m_channelNames);
} else if (pixelFormat == Bitmap::ESpectrum || pixelFormat == Bitmap::ESpectrumAlpha) {
for (int i=0; i<SPECTRUM_SAMPLES; ++i) {
std::pair<Float, Float> coverage = Spectrum::getBinCoverage(i);
std::string name = formatString("%f-%fnm", coverage.first, coverage.second);
m_frameBuffer->insert(name.c_str(), Imf::Slice(compType, ptr, m_pixelStride, m_rowStride)); ptr += compStride;
}
} }
if (m_pixelFormat == Bitmap::ERGBA || m_pixelFormat == Bitmap::EXYZA || char *ptr = (char *) m_tile->getUInt8Data();
m_pixelFormat == Bitmap::ELuminanceAlpha)
m_frameBuffer->insert("A", Imf::Slice(compType, ptr, m_pixelStride, m_rowStride)); for (size_t i=0; i<m_channelNames.size(); ++i) {
m_frameBuffer->insert(m_channelNames[i].c_str(),
Imf::Slice(compType, ptr, m_pixelStride, m_rowStride));
ptr += compStride;
}
m_output->setFrameBuffer(*m_frameBuffer); m_output->setFrameBuffer(*m_frameBuffer);
m_peakUsage = 0; m_peakUsage = 0;
@ -316,7 +332,6 @@ public:
++m_peakUsage; ++m_peakUsage;
} }
uint32_t idx = (uint32_t) x + (uint32_t) y * m_blocksH; uint32_t idx = (uint32_t) x + (uint32_t) y * m_blocksH;
m_origBlocks[idx] = copy1; m_origBlocks[idx] = copy1;
m_mergedBlocks[idx] = copy2; m_mergedBlocks[idx] = copy2;
@ -388,6 +403,7 @@ public:
} }
const Bitmap *source = mergedBlock->getBitmap(); const Bitmap *source = mergedBlock->getBitmap();
size_t sourceBpp = source->getBytesPerPixel(); size_t sourceBpp = source->getBytesPerPixel();
size_t targetBpp = m_tile->getBytesPerPixel(); size_t targetBpp = m_tile->getBytesPerPixel();
@ -400,11 +416,15 @@ public:
); );
for (int i=0; i<m_blockSize; ++i) { for (int i=0; i<m_blockSize; ++i) {
cvt->convert(source->getPixelFormat(), 1.0f, sourceData, if (m_pixelFormats.size() == 1)
m_tile->getPixelFormat(), m_tile->getGamma(), targetData, cvt->convert(source->getPixelFormat(), 1.0f, sourceData,
m_tile->getWidth()); m_tile->getPixelFormat(), m_tile->getGamma(), targetData,
m_tile->getWidth());
else
Bitmap::convertMultiSpectrumAlphaWeight(source, sourceData,
m_tile, targetData, m_pixelFormats, m_componentFormat, m_tile->getWidth());
sourceData += source->getWidth() * sourceBpp; sourceData += source->getWidth() * sourceBpp;
targetData += m_tile->getWidth() * targetBpp; targetData += m_tile->getWidth() * targetBpp;
} }
@ -470,11 +490,14 @@ public:
void clear() { /* Do nothing */ } void clear() { /* Do nothing */ }
bool hasAlpha() const { bool hasAlpha() const {
return for (size_t i=0; i<m_pixelFormats.size(); ++i) {
m_pixelFormat == Bitmap::ELuminanceAlpha || if (m_pixelFormats[i] == Bitmap::ELuminanceAlpha ||
m_pixelFormat == Bitmap::ERGBA || m_pixelFormats[i] == Bitmap::ERGBA ||
m_pixelFormat == Bitmap::EXYZA || m_pixelFormats[i] == Bitmap::EXYZA ||
m_pixelFormat == Bitmap::ESpectrumAlpha; m_pixelFormats[i] == Bitmap::ESpectrumAlpha)
return true;
}
return false;
} }
bool destinationExists(const fs::path &baseName) const { bool destinationExists(const fs::path &baseName) const {
@ -488,7 +511,14 @@ public:
std::ostringstream oss; std::ostringstream oss;
oss << "TiledHDRFilm[" << endl oss << "TiledHDRFilm[" << endl
<< " size = " << m_size.toString() << "," << endl << " size = " << m_size.toString() << "," << endl
<< " pixelFormat = " << m_pixelFormat << "," << endl << " pixelFormat = ";
for (size_t i=0; i<m_pixelFormats.size(); ++i)
oss << m_pixelFormats[i] << ", ";
oss << endl
<< " channelNames = ";
for (size_t i=0; i<m_channelNames.size(); ++i)
oss << "\"" << m_channelNames[i] << "\"" << ", ";
oss << endl
<< " componentFormat = " << m_componentFormat << "," << endl << " componentFormat = " << m_componentFormat << "," << endl
<< " cropOffset = " << m_cropOffset.toString() << "," << endl << " cropOffset = " << m_cropOffset.toString() << "," << endl
<< " cropSize = " << m_cropSize.toString() << "," << endl << " cropSize = " << m_cropSize.toString() << "," << endl
@ -499,7 +529,8 @@ public:
MTS_DECLARE_CLASS() MTS_DECLARE_CLASS()
protected: protected:
Bitmap::EPixelFormat m_pixelFormat; std::vector<Bitmap::EPixelFormat> m_pixelFormats;
std::vector<std::string> m_channelNames;
Bitmap::EComponentFormat m_componentFormat; Bitmap::EComponentFormat m_componentFormat;
std::vector<ImageBlock *> m_freeBlocks; std::vector<ImageBlock *> m_freeBlocks;
std::map<uint32_t, ImageBlock *> m_origBlocks, m_mergedBlocks; std::map<uint32_t, ImageBlock *> m_origBlocks, m_mergedBlocks;

View File

@ -30,6 +30,7 @@ add_integrator(adaptive misc/adaptive.cpp)
add_integrator(irrcache misc/irrcache.cpp add_integrator(irrcache misc/irrcache.cpp
misc/irrcache_proc.h misc/irrcache_proc.cpp) misc/irrcache_proc.h misc/irrcache_proc.cpp)
add_integrator(multichannel misc/multichannel.cpp) add_integrator(multichannel misc/multichannel.cpp)
add_integrator(field misc/field.cpp)
# Bidirectional techniques # Bidirectional techniques
add_bidir(bdpt bdpt/bdpt.h bdpt/bdpt.cpp add_bidir(bdpt bdpt/bdpt.h bdpt/bdpt.cpp

View File

@ -17,6 +17,7 @@ plugins += env.SharedLibrary('vpl', ['vpl/vpl.cpp'])
plugins += env.SharedLibrary('adaptive', ['misc/adaptive.cpp']) plugins += env.SharedLibrary('adaptive', ['misc/adaptive.cpp'])
plugins += env.SharedLibrary('irrcache', ['misc/irrcache.cpp', 'misc/irrcache_proc.cpp']) plugins += env.SharedLibrary('irrcache', ['misc/irrcache.cpp', 'misc/irrcache_proc.cpp'])
plugins += env.SharedLibrary('multichannel', ['misc/multichannel.cpp']) plugins += env.SharedLibrary('multichannel', ['misc/multichannel.cpp'])
plugins += env.SharedLibrary('field', ['misc/field.cpp'])
# Bidirectional techniques # Bidirectional techniques
bidirEnv = env.Clone() bidirEnv = env.Clone()

View File

@ -0,0 +1,189 @@
/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2012 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/render/scene.h>
#include <mitsuba/render/renderproc.h>
MTS_NAMESPACE_BEGIN
/*!\plugin{field}{Field extraction integrator}
* \order{17}
* \parameters{
* \parameter{field}{\String}{Denotes the name of the field that should be extracted.
* The following choices are possible:
* \begin{itemize}
* \setlength{\itemsep}{1pt}
* \setlength{\parskip}{1pt}
* \item \code{position}: 3D position in world space
* \item \code{relPosition}: 3D position in camera space
* \item \code{distance}: Ray distance to the shading point
* \item \code{geoNormal}: Geometric surface normal
* \item \code{shNormal}: Shading surface normal
* \item \code{uv}: UV coordinate value
* \item \code{albedo}: Albedo value of the BSDF
* \item \code{shapeIndex}: Integer index of the high-level shape
* \item \code{primIndex}: Integer shape primitive index
* \end{itemize}
* }
* \parameter{undefined}{\Spectrum\Or\Float}{Value that should be returned when
* there is no intersection \default{0}}
* }
*
* This integrator extracts a requested field of from the intersection records of shading
* points and converts the resulting data into color values. It is meant to be used in conjunction with
* \pluginref{multichannel} to dump auxiliary information (such as depth or surface normals
* of surfaces seen by the camera) into extra channels of a rendered image, for instance to
* create benchmark data for computer vision applications.
* Please refer to the documentation of \pluginref{multichannel} for an example.
*/
class FieldIntegrator : public SamplingIntegrator {
public:
enum EField {
EPosition,
ERelativePosition,
EDistance,
EGeometricNormal,
EShadingNormal,
EUV,
EAlbedo,
EShapeIndex,
EPrimIndex
};
FieldIntegrator(const Properties &props) : SamplingIntegrator(props) {
std::string field = props.getString("field");
if (field == "position") {
m_field = EPosition;
} else if (field == "relPosition") {
m_field = ERelativePosition;
} else if (field == "distance") {
m_field = EDistance;
} else if (field == "geoNormal") {
m_field = EGeometricNormal;
} else if (field == "shNormal") {
m_field = EShadingNormal;
} else if (field == "uv") {
m_field = EUV;
} else if (field == "albedo") {
m_field = EAlbedo;
} else if (field == "shapeIndex") {
m_field = EShapeIndex;
} else if (field == "primIndex") {
m_field = EPrimIndex;
} else {
Log(EError, "Invalid 'field' parameter. Must be one of 'position', "
"'relPosition', 'distance', 'geoNormal', 'shNormal', "
"'primIndex', 'shapeIndex', or 'uv'!");
}
if (props.hasProperty("undefined")) {
if (props.getType("undefined") == Properties::EFloat)
m_undefined = Spectrum(props.getFloat("undefined"));
else
m_undefined = props.getSpectrum("undefined", Spectrum(0.0f));
}
if (SPECTRUM_SAMPLES != 3 && (m_field == EUV || m_field == EShadingNormal || m_field == EGeometricNormal
|| m_field == ERelativePosition || m_field == EPosition)) {
Log(EError, "The field integrator implementation requires renderings to be done in RGB when "
"extracting positional data or surface normals / UV coordinates.");
}
}
FieldIntegrator(Stream *stream, InstanceManager *manager)
: SamplingIntegrator(stream, manager) {
m_field = (EField) stream->readInt();
m_undefined = Spectrum(stream);
}
void serialize(Stream *stream, InstanceManager *manager) const {
SamplingIntegrator::serialize(stream, manager);
stream->writeInt((int) m_field);
m_undefined.serialize(stream);
}
Spectrum Li(const RayDifferential &ray, RadianceQueryRecord &rRec) const {
Spectrum result(m_undefined);
if (!rRec.rayIntersect(ray))
return result;
Intersection &its = rRec.its;
switch (m_field) {
case EPosition:
result.fromLinearRGB(its.p.x, its.p.y, its.p.z);
break;
case ERelativePosition: {
const Sensor *sensor = rRec.scene->getSensor();
const Transform &t = sensor->getWorldTransform()->eval(its.t).inverse();
Point p = t(its.p);
result.fromLinearRGB(p.x, p.y, p.z);
}
break;
case EDistance:
result = Spectrum(its.t);
break;
case EGeometricNormal:
result.fromLinearRGB(its.geoFrame.n.x, its.geoFrame.n.y, its.geoFrame.n.z);
break;
case EShadingNormal:
result.fromLinearRGB(its.shFrame.n.x, its.shFrame.n.y, its.shFrame.n.z);
break;
case EUV:
result.fromLinearRGB(its.uv.x, its.uv.y, 0);
break;
case EAlbedo:
result = its.shape->getBSDF()->getDiffuseReflectance(its);
break;
case EShapeIndex: {
const ref_vector<Shape> &shapes = rRec.scene->getShapes();
result = Spectrum((Float) -1);
for (size_t i=0; i<shapes.size(); ++i) {
if (shapes[i] == its.shape) {
result = Spectrum((Float) i);
break;
}
}
}
break;
case EPrimIndex:
result = Spectrum((int) its.primIndex);
break;
default:
Log(EError, "Internal error!");
}
return result;
}
std::string toString() const {
return "FieldIntegrator[]";
}
MTS_DECLARE_CLASS()
private:
EField m_field;
Spectrum m_undefined;
};
MTS_IMPLEMENT_CLASS_S(FieldIntegrator, false, SamplingIntegrator)
MTS_EXPORT_PLUGIN(FieldIntegrator, "Field extraction integrator");
MTS_NAMESPACE_END

View File

@ -21,9 +21,67 @@
MTS_NAMESPACE_BEGIN MTS_NAMESPACE_BEGIN
/*! \plugin{direct}{Multi-channel integrator} /*!\plugin{multichannel}{Multi-channel integrator}
* \order{16} * \order{16}
* \parameters{
* \parameter{\Unnamed}{\Integrator}{One or more sub-integrators whose output
* should be rendered into a combined multi-channel image}
* }
* *
* The multi-channel integrator groups several sub-integrators together
* and invokes them at the same time for each pixel; the result from each
* integrator is written into a separate channel of the output image.
* This could include things like surface normals or the distance
* from the camera (via the \pluginref{field} plugin) or ambient occlusion
* (via the \pluginref{ao} plugin).
* In this way, this integrator can be a powerful tool for unusual applications
* of Mitsuba, e.g. to create reference data for computer vision algorithms. Currently, it only
* works with a subset of the other plugins---see the red box for details.
*
* Thee \code{multichannel} plugin also disables certain checks for negative or infinite
* radiance values during rendering that normally cause warnings to be emitted.
* This is simply to process extracted fields for which it is fine
* to take on such values.
*
* The following example contains a typical setup for rendering an 7 channel EXR image:
* 3 for a path traced image (RGB), 3 for surface normals
* (encoded as RGB), and 1 channel for the ray distance measured from the camera.
*
* \vspace{2mm}
* \begin{xml}
* <scene>
* <integrator type="multichannel">
* <integrator type="path"/>
* <integrator type="field">
* <string name="field" value="shNormal"/>
* </integrator>
* <integrator type="field">
* <string name="field" value="distance"/>
* </integrator>
* </integrator>
*
* <sensor type="perspective">
* <sampler type="halton">
* <integer name="sampleCount" value="32"/>
* </sampler>
* <film type="hdrfilm">
* <string name="pixelFormat" value="rgb, rgb, luminance"/>
* <string name="channelNames" value="color, normal, distance"/>
* </film>
* </sensor>
* <!-- **** scene contents **** -->
* </scene>
* \end{xml}
*
* \remarks{
* \item Requires the \pluginref{hdrfilm} or \pluginref{tiledhdrfilm}.
* \item All nested integrators must
* conform to Mitsuba's basic \emph{SamplingIntegrator} interface.
* Currently, only a few of them do this, including:
* \pluginref{field}, \pluginref{ao}, \pluginref{direct}, \pluginref{path},
* \pluginref{volpath}, \pluginref[volpathsimple]{volpath\_simple},
* and \pluginref{irrcache}.
* }
*/ */
class MultiChannelIntegrator : public SamplingIntegrator { class MultiChannelIntegrator : public SamplingIntegrator {
@ -82,7 +140,9 @@ public:
ref<BlockedRenderProcess> proc = new BlockedRenderProcess(job, ref<BlockedRenderProcess> proc = new BlockedRenderProcess(job,
queue, scene->getBlockSize()); queue, scene->getBlockSize());
proc->setPixelFormat(Bitmap::EMultiSpectrumAlphaWeight, (int) (m_integrators.size() * SPECTRUM_SAMPLES + 2), false); proc->setPixelFormat(
m_integrators.size() > 1 ? Bitmap::EMultiSpectrumAlphaWeight : Bitmap::ESpectrumAlphaWeight,
(int) (m_integrators.size() * SPECTRUM_SAMPLES + 2), false);
int integratorResID = sched->registerResource(this); int integratorResID = sched->registerResource(this);
proc->bindResource("integrator", integratorResID); proc->bindResource("integrator", integratorResID);

View File

@ -269,12 +269,19 @@ public:
if (m_config.workUnits <= 0) { if (m_config.workUnits <= 0) {
const size_t desiredMutationsPerWorkUnit = 200000; const size_t desiredMutationsPerWorkUnit = 200000;
const size_t cropArea = (size_t) cropSize.x * cropSize.y; const size_t cropArea = (size_t) cropSize.x * cropSize.y;
const size_t workUnits = ((desiredMutationsPerWorkUnit - 1) + const size_t workUnits = ((desiredMutationsPerWorkUnit - 1) +
(cropArea * sampleCount)) / desiredMutationsPerWorkUnit; (cropArea * sampleCount)) / desiredMutationsPerWorkUnit;
Assert(workUnits <= (size_t) std::numeric_limits<int>::max()); Assert(workUnits <= (size_t) std::numeric_limits<int>::max());
m_config.workUnits = (int) std::max(workUnits, (size_t) 1); m_config.workUnits = (int) std::max(workUnits, (size_t) 1);
} }
size_t luminanceSamples = m_config.luminanceSamples;
if (luminanceSamples < (size_t) m_config.workUnits * 10) {
luminanceSamples = (size_t) m_config.workUnits * 10;
Log(EWarn, "Warning: increasing number of luminance samples to " SIZE_T_FMT,
luminanceSamples);
}
m_config.nMutations = (cropSize.x * cropSize.y * m_config.nMutations = (cropSize.x * cropSize.y *
sampleCount) / m_config.workUnits; sampleCount) / m_config.workUnits;
@ -295,7 +302,7 @@ public:
ref<MLTProcess> process = new MLTProcess(job, queue, ref<MLTProcess> process = new MLTProcess(job, queue,
m_config, directImage, pathSeeds); m_config, directImage, pathSeeds);
m_config.luminance = pathSampler->generateSeeds(m_config.luminanceSamples, m_config.luminance = pathSampler->generateSeeds(luminanceSamples,
m_config.workUnits, true, m_config.importanceMap, pathSeeds); m_config.workUnits, true, m_config.importanceMap, pathSeeds);
if (!nested) if (!nested)

View File

@ -328,6 +328,13 @@ public:
m_config.workUnits = (int) std::max(workUnits, (size_t) 1); m_config.workUnits = (int) std::max(workUnits, (size_t) 1);
} }
size_t luminanceSamples = m_config.luminanceSamples;
if (luminanceSamples < (size_t) m_config.workUnits * 10) {
luminanceSamples = (size_t) m_config.workUnits * 10;
Log(EWarn, "Warning: increasing number of luminance samples to " SIZE_T_FMT,
luminanceSamples);
}
m_config.nMutations = (cropSize.x * cropSize.y * m_config.nMutations = (cropSize.x * cropSize.y *
sampleCount) / m_config.workUnits; sampleCount) / m_config.workUnits;
@ -348,7 +355,7 @@ public:
ref<PSSMLTProcess> process = new PSSMLTProcess(job, queue, ref<PSSMLTProcess> process = new PSSMLTProcess(job, queue,
m_config, directImage, pathSeeds); m_config, directImage, pathSeeds);
m_config.luminance = pathSampler->generateSeeds(m_config.luminanceSamples, m_config.luminance = pathSampler->generateSeeds(luminanceSamples,
m_config.workUnits, false, m_config.importanceMap, pathSeeds); m_config.workUnits, false, m_config.importanceMap, pathSeeds);
if (!nested) if (!nested)

View File

@ -36,15 +36,15 @@ ref<Bitmap> BidirectionalUtils::renderDirectComponent(Scene *scene, int sceneRes
/* Render the direct illumination component separately */ /* Render the direct illumination component separately */
ref<Bitmap> directImage = new Bitmap(Bitmap::ERGBA, Bitmap::EFloat32, film->getCropSize()); ref<Bitmap> directImage = new Bitmap(Bitmap::ERGBA, Bitmap::EFloat32, film->getCropSize());
bool hasMedia = scene->getMedia().size() > 0; bool hasMedia = scene->getMedia().size() > 0;
bool hasDOF = scene->getSensor()->needsApertureSample();
size_t pixelSamples = directSamples; size_t pixelSamples = directSamples;
Properties integratorProps(hasMedia ? "volpath" : "direct"); Properties integratorProps(hasMedia ? "volpath" : "direct");
if (hasMedia) { if (hasMedia || hasDOF) {
/* Render with a volumetric path tracer */
integratorProps.setInteger("maxDepth", 2); integratorProps.setInteger("maxDepth", 2);
} else { } else {
/* No participating media-> we can use the 'direct' plugin, which has /* No participating media / DoF -> we can more carefully
somewhat better control over where to place shading/pixel samples */ distribute samples between shading and visibility */
int shadingSamples = 1; int shadingSamples = 1;
while (pixelSamples > 8) { while (pixelSamples > 8) {
pixelSamples /= 2; pixelSamples /= 2;

View File

@ -88,11 +88,12 @@ public:
EXRIStream(Stream *stream) : IStream(stream->toString().c_str()), EXRIStream(Stream *stream) : IStream(stream->toString().c_str()),
m_stream(stream) { m_stream(stream) {
m_offset = stream->getPos(); m_offset = stream->getPos();
m_size = stream->getSize();
} }
bool read(char *c, int n) { bool read(char *c, int n) {
m_stream->read(c, n); m_stream->read(c, n);
return m_stream->isEOF(); return m_stream->getPos() == m_size;
} }
Imf::Int64 tellg() { Imf::Int64 tellg() {
@ -106,7 +107,7 @@ public:
void clear() { } void clear() { }
private: private:
ref<Stream> m_stream; ref<Stream> m_stream;
size_t m_offset; size_t m_offset, m_size;
}; };
class EXROStream : public Imf::OStream { class EXROStream : public Imf::OStream {
@ -166,6 +167,12 @@ static void png_error_func(png_structp png_ptr, png_const_charp msg) {
SLog(EError, "Fatal libpng error: %s\n", msg); SLog(EError, "Fatal libpng error: %s\n", msg);
exit(-1); exit(-1);
} }
static void png_warn_func(png_structp png_ptr, png_const_charp msg) {
if (strstr(msg, "iCCP: known incorrect sRGB profile") != NULL)
return;
SLog(EWarn, "libpng warning: %s\n", msg);
}
#endif #endif
#if defined(MTS_HAS_LIBJPEG) #if defined(MTS_HAS_LIBJPEG)
@ -298,6 +305,8 @@ Bitmap::Bitmap(EFileFormat format, Stream *stream, const std::string &prefix) :
format = ERGBE; format = ERGBE;
} else if (start[0] == 'P' && (start[1] == 'F' || start[1] == 'f')) { } else if (start[0] == 'P' && (start[1] == 'F' || start[1] == 'f')) {
format = EPFM; format = EPFM;
} else if (start[0] == 'P' && start[1] == '6') {
format = EPPM;
#if defined(MTS_HAS_LIBJPEG) #if defined(MTS_HAS_LIBJPEG)
} else if (start[0] == 0xFF && start[1] == 0xD8) { } else if (start[0] == 0xFF && start[1] == 0xD8) {
format = EJPEG; format = EJPEG;
@ -327,6 +336,7 @@ Bitmap::Bitmap(EFileFormat format, Stream *stream, const std::string &prefix) :
case EOpenEXR: readOpenEXR(stream, prefix); break; case EOpenEXR: readOpenEXR(stream, prefix); break;
case ERGBE: readRGBE(stream); break; case ERGBE: readRGBE(stream); break;
case EPFM: readPFM(stream); break; case EPFM: readPFM(stream); break;
case EPPM: readPPM(stream); break;
case ETGA: readTGA(stream); break; case ETGA: readTGA(stream); break;
case EPNG: readPNG(stream); break; case EPNG: readPNG(stream); break;
default: default:
@ -349,6 +359,7 @@ void Bitmap::write(EFileFormat format, Stream *stream, int compression) const {
case EOpenEXR: writeOpenEXR(stream); break; case EOpenEXR: writeOpenEXR(stream); break;
case ERGBE: writeRGBE(stream); break; case ERGBE: writeRGBE(stream); break;
case EPFM: writePFM(stream); break; case EPFM: writePFM(stream); break;
case EPPM: writePPM(stream); break;
default: default:
Log(EError, "Bitmap::write(): Invalid file format!"); Log(EError, "Bitmap::write(): Invalid file format!");
} }
@ -1361,7 +1372,7 @@ void Bitmap::convert(Bitmap *target, Float multiplier, Spectrum::EConversionInte
cvt->convert(m_pixelFormat, m_gamma, m_data, cvt->convert(m_pixelFormat, m_gamma, m_data,
target->getPixelFormat(), target->getGamma(), target->getData(), target->getPixelFormat(), target->getGamma(), target->getData(),
(size_t) m_size.x * (size_t) m_size.y, multiplier, intent, (size_t) m_size.x * (size_t) m_size.y, multiplier, intent,
m_channelCount - (hasWeight() ? 1 : 0)); m_channelCount);
} }
ref<Bitmap> Bitmap::convert(EPixelFormat pixelFormat, ref<Bitmap> Bitmap::convert(EPixelFormat pixelFormat,
@ -1392,72 +1403,99 @@ ref<Bitmap> Bitmap::convert(EPixelFormat pixelFormat,
cvt->convert(m_pixelFormat, m_gamma, m_data, cvt->convert(m_pixelFormat, m_gamma, m_data,
pixelFormat, gamma, target->getData(), pixelFormat, gamma, target->getData(),
(size_t) m_size.x * (size_t) m_size.y, multiplier, intent, (size_t) m_size.x * (size_t) m_size.y, multiplier, intent,
m_channelCount - (hasWeight() ? 1 : 0)); m_channelCount);
return target; return target;
} }
ref<Bitmap> Bitmap::convertMultiSpectrumAlphaWeight(const std::vector<EPixelFormat> &pixelFormats, ref<Bitmap> Bitmap::convertMultiSpectrumAlphaWeight(const std::vector<EPixelFormat> &pixelFormats,
EComponentFormat componentFormat, const std::vector<std::string> &channelNames) const { EComponentFormat componentFormat, const std::vector<std::string> &channelNames) const {
if (m_componentFormat != EFloat && m_pixelFormat != EMultiSpectrumAlphaWeight)
Log(EError, "convertMultiSpectrumAlphaWeight(): unsupported!");
if (channelNames.size() > std::numeric_limits<uint8_t>::max()) if (channelNames.size() > std::numeric_limits<uint8_t>::max())
Log(EError, "convertMultiSpectrumAlphaWeight(): excessive number of channels!"); Log(EError, "convertMultiSpectrumAlphaWeight(): excessive number of channels!");
ref<Bitmap> bitmap = new Bitmap(Bitmap::EMultiChannel, Bitmap::EFloat, m_size, (uint8_t) channelNames.size()); ref<Bitmap> bitmap = new Bitmap(Bitmap::EMultiChannel, componentFormat,
m_size, (uint8_t) channelNames.size());
bitmap->setChannelNames(channelNames); bitmap->setChannelNames(channelNames);
convertMultiSpectrumAlphaWeight(this, getUInt8Data(), bitmap,
bitmap->getUInt8Data(), pixelFormats, componentFormat,
(size_t) m_size.x * (size_t) m_size.y);
return bitmap;
}
for (int y = 0; y<m_size.y; ++y) { void Bitmap::convertMultiSpectrumAlphaWeight(const Bitmap *source,
for (int x = 0; x<m_size.x; ++x) { const uint8_t *sourcePtr, const Bitmap *target, uint8_t *targetPtr,
const Float *srcData = getFloatData() + getChannelCount() * (x+y*m_size.x); const std::vector<EPixelFormat> &pixelFormats,
Float *dstData = bitmap->getFloatData() + bitmap->getChannelCount() * (x+y*m_size.x); EComponentFormat componentFormat, size_t count) {
Float weight = srcData[getChannelCount()-1], if (source->getComponentFormat() != EFloat && source->getPixelFormat() != EMultiSpectrumAlphaWeight)
invWeight = weight == 0 ? 0 : (Float) 1 / weight; Log(EError, "convertMultiSpectrumAlphaWeight(): unsupported!");
Float alpha = srcData[getChannelCount()-2] * invWeight;
for (size_t i=0; i<pixelFormats.size(); ++i) { Float *temp = new Float[count * target->getChannelCount()], *dst = temp;
Spectrum value = ((Spectrum *) srcData)[i] * invWeight;
Float r, g, b; for (size_t k = 0; k<count; ++k) {
switch (pixelFormats[i]) { const Float *srcData = (const Float *) sourcePtr + k * source->getChannelCount();
case Bitmap::ELuminance: Float weight = srcData[source->getChannelCount()-1],
*dstData++ = value.getLuminance(); invWeight = weight == 0 ? 0 : (Float) 1 / weight;
break; Float alpha = srcData[source->getChannelCount()-2] * invWeight;
case Bitmap::ELuminanceAlpha:
*dstData++ = value.getLuminance(); for (size_t i=0; i<pixelFormats.size(); ++i) {
*dstData++ = alpha; Spectrum value = ((Spectrum *) srcData)[i] * invWeight;
break; Float tmp0, tmp1, tmp2;
case Bitmap::ERGB: switch (pixelFormats[i]) {
value.toLinearRGB(r, g, b); case Bitmap::ELuminance:
*dstData++ = r; *dst++ = value.getLuminance();
*dstData++ = g; break;
*dstData++ = b; case Bitmap::ELuminanceAlpha:
break; *dst++ = value.getLuminance();
case Bitmap::ERGBA: *dst++ = alpha;
value.toLinearRGB(r, g, b); break;
*dstData++ = r; case Bitmap::EXYZ:
*dstData++ = g; value.toXYZ(tmp0, tmp1, tmp2);
*dstData++ = b; *dst++ = tmp0;
*dstData++ = alpha; *dst++ = tmp1;
break; *dst++ = tmp2;
case Bitmap::ESpectrum: break;
for (int j=0; j<SPECTRUM_SAMPLES; ++j) case Bitmap::EXYZA:
*dstData++ = value[j]; value.toXYZ(tmp0, tmp1, tmp2);
break; *dst++ = tmp0;
case Bitmap::ESpectrumAlpha: *dst++ = tmp1;
for (int j=0; j<SPECTRUM_SAMPLES; ++j) *dst++ = tmp2;
*dstData++ = value[j]; *dst++ = alpha;
*dstData++ = alpha; break;
break; case Bitmap::ERGB:
default: value.toLinearRGB(tmp0, tmp1, tmp2);
Log(EError, "Unknown pixel format!"); *dst++ = tmp0;
} *dst++ = tmp1;
*dst++ = tmp2;
break;
case Bitmap::ERGBA:
value.toLinearRGB(tmp0, tmp1, tmp2);
*dst++ = tmp0;
*dst++ = tmp1;
*dst++ = tmp2;
*dst++ = alpha;
break;
case Bitmap::ESpectrum:
for (int j=0; j<SPECTRUM_SAMPLES; ++j)
*dst++ = value[j];
break;
case Bitmap::ESpectrumAlpha:
for (int j=0; j<SPECTRUM_SAMPLES; ++j)
*dst++ = value[j];
*dst++ = alpha;
break;
default:
Log(EError, "Unknown pixel format!");
} }
} }
} }
if (componentFormat != Bitmap::EFloat) const FormatConverter *cvt = FormatConverter::getInstance(
bitmap = bitmap->convert(Bitmap::EMultiChannel, componentFormat); std::make_pair(EFloat, target->getComponentFormat())
);
return bitmap; cvt->convert(Bitmap::EMultiChannel, 1.0f, temp, Bitmap::EMultiChannel, 1.0f, targetPtr,
count, 1.0f, Spectrum::EReflectance, target->getChannelCount());
delete[] temp;
} }
void Bitmap::convert(void *target, EPixelFormat pixelFormat, void Bitmap::convert(void *target, EPixelFormat pixelFormat,
@ -1483,7 +1521,7 @@ void Bitmap::convert(void *target, EPixelFormat pixelFormat,
cvt->convert(m_pixelFormat, m_gamma, m_data, cvt->convert(m_pixelFormat, m_gamma, m_data,
pixelFormat, gamma, target, pixelFormat, gamma, target,
(size_t) m_size.x * (size_t) m_size.y, multiplier, intent, (size_t) m_size.x * (size_t) m_size.y, multiplier, intent,
m_channelCount - (hasWeight() ? 1 : 0)); m_channelCount);
} }
template <typename T> void tonemapReinhard(T *data, size_t pixels, Bitmap::EPixelFormat fmt, template <typename T> void tonemapReinhard(T *data, size_t pixels, Bitmap::EPixelFormat fmt,
@ -1990,7 +2028,7 @@ void Bitmap::readPNG(Stream *stream) {
volatile png_bytepp rows = NULL; volatile png_bytepp rows = NULL;
/* Create buffers */ /* Create buffers */
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, &png_error_func, NULL); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, &png_error_func, &png_warn_func);
if (png_ptr == NULL) { if (png_ptr == NULL) {
Log(EError, "readPNG(): Unable to create PNG data structure"); Log(EError, "readPNG(): Unable to create PNG data structure");
} }
@ -2114,7 +2152,7 @@ void Bitmap::writePNG(Stream *stream, int compression) const {
return; return;
} }
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, &png_error_func, NULL); png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, &png_error_func, &png_warn_func);
if (png_ptr == NULL) if (png_ptr == NULL)
Log(EError, "Error while creating PNG data structure"); Log(EError, "Error while creating PNG data structure");
@ -3368,6 +3406,54 @@ void Bitmap::writePFM(Stream *stream) const {
} }
} }
void Bitmap::readPPM(Stream *stream) {
int field = 0, nChars = 0;
std::string fields[4];
while (field < 4) {
char c = stream->readChar();
if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
if (nChars != 0) {
nChars = 0;
++field;
}
} else {
fields[field] += c;
++nChars;
}
}
if (fields[0] != "P6")
Log(EError, "readPPM(): invalid format!");
int intValues[3];
for (int i=0; i<3; ++i) {
char *end_ptr = NULL;
intValues[i] = strtol(fields[i+1].c_str(), &end_ptr, 10);
if (*end_ptr != '\0')
SLog(EError, "readPPM(): unable to parse the file header!");
}
m_size.x = intValues[0];
m_size.y = intValues[1];
m_pixelFormat = ERGB;
m_channelCount = 3;
m_gamma = -1.0f;
m_ownsData = true;
m_componentFormat = intValues[2] <= 0xFF ? EUInt8 : EUInt16;
size_t size = getBufferSize();
m_data = static_cast<uint8_t *>(allocAligned(size));
stream->read(m_data, size);
}
void Bitmap::writePPM(Stream *stream) const {
if (m_pixelFormat != ERGB || (m_componentFormat != EUInt8 && m_componentFormat != EUInt16))
Log(EError, "writePPM(): Only 8 or 16-bit RGB images are supported");
stream->writeLine(formatString("P6\n%i\n%i\n%i\n", m_size.x, m_size.y,
m_componentFormat == EUInt8 ? 0xFF : 0xFFFF).c_str());
stream->write(m_data, getBufferSize());
}
void Bitmap::staticInitialization() { void Bitmap::staticInitialization() {
#if defined(MTS_HAS_OPENEXR) #if defined(MTS_HAS_OPENEXR)
/* Prevent races during the OpenEXR initialization */ /* Prevent races during the OpenEXR initialization */

View File

@ -206,7 +206,7 @@ void FileStream::seek(size_t pos) {
pos, d->path.string().c_str(), lastErrorText().c_str()); pos, d->path.string().c_str(), lastErrorText().c_str());
} }
#else #else
if (fseek(d->file, pos, SEEK_SET)) { if (fseeko(d->file, (off_t) pos, SEEK_SET)) {
Log(EError, "Error while trying to seek to position %i in file \"%s\": %s", Log(EError, "Error while trying to seek to position %i in file \"%s\": %s",
pos, d->path.string().c_str(), strerror(errno)); pos, d->path.string().c_str(), strerror(errno));
} }
@ -223,8 +223,7 @@ size_t FileStream::getPos() const {
} }
return (size_t) pos; return (size_t) pos;
#else #else
long pos; off_t pos = ftello(d->file);
pos = ftell(d->file);
if (pos == -1) { if (pos == -1) {
Log(EError, "Error while looking up the position in file \"%s\": %s", Log(EError, "Error while looking up the position in file \"%s\": %s",
d->path.string().c_str(), strerror(errno)); d->path.string().c_str(), strerror(errno));

View File

@ -139,6 +139,11 @@ void Logger::log(ELogLevel level, const Class *theClass,
__debugbreak(); __debugbreak();
#endif #endif
DefaultFormatter fmt;
fmt.setHaveDate(false);
fmt.setHaveLogLevel(false);
text = fmt.format(level, theClass,
Thread::getThread(), msg, file, line);
throw std::runtime_error(text); throw std::runtime_error(text);
} }
} }

View File

@ -18,11 +18,11 @@
#include <mitsuba/core/vmf.h> #include <mitsuba/core/vmf.h>
#include <mitsuba/core/warp.h> #include <mitsuba/core/warp.h>
#include <mitsuba/core/brent.h>
#include <boost/bind.hpp>
MTS_NAMESPACE_BEGIN MTS_NAMESPACE_BEGIN
VonMisesFisherDistr::VonMisesFisherDistr(Float kappa): m_kappa(kappa) { }
Float VonMisesFisherDistr::eval(Float cosTheta) const { Float VonMisesFisherDistr::eval(Float cosTheta) const {
if (m_kappa == 0.0f) if (m_kappa == 0.0f)
return INV_FOURPI; return INV_FOURPI;
@ -63,22 +63,23 @@ Vector VonMisesFisherDistr::sample(const Point2 &sample) const {
sinPhi * sinTheta, cosTheta); sinPhi * sinTheta, cosTheta);
} }
Float VonMisesFisherDistr::forPeakValue(Float x) { Float VonMisesFisherDistr::getMeanCosine() const {
if (x < INV_FOURPI) { if (m_kappa == 0)
return 0.0f; return 0;
} else if (x > 0.795) { Float coth = m_kappa > 6 ? 1 : ((std::exp(2*m_kappa)+1)/(std::exp(2*m_kappa)-1));
return 2 * M_PI * x; return coth-1/m_kappa;
} else {
return std::max((Float) 0.0f,
(168.479f * x * x + 16.4585f * x - 2.39942f) /
(-1.12718f * x * x + 29.1433f * x + 1.0f));
}
} }
static Float A3(Float kappa) { static Float A3(Float kappa) {
return 1/ std::tanh(kappa) - 1 / kappa; return 1/ std::tanh(kappa) - 1 / kappa;
} }
std::string VonMisesFisherDistr::toString() const {
std::ostringstream oss;
oss << "VonMisesFisherDistr[kappa=" << m_kappa << "]";
return oss.str();
}
static Float dA3(Float kappa) { static Float dA3(Float kappa) {
Float csch = 2.0f / Float csch = 2.0f /
(math::fastexp(kappa)-math::fastexp(-kappa)); (math::fastexp(kappa)-math::fastexp(-kappa));
@ -110,4 +111,33 @@ Float VonMisesFisherDistr::convolve(Float kappa1, Float kappa2) {
return A3inv(A3(kappa1) * A3(kappa2), std::min(kappa1, kappa2)); return A3inv(A3(kappa1) * A3(kappa2), std::min(kappa1, kappa2));
} }
Float VonMisesFisherDistr::forPeakValue(Float x) {
if (x < INV_FOURPI) {
return 0.0f;
} else if (x > 0.795) {
return 2 * M_PI * x;
} else {
return std::max((Float) 0.0f,
(168.479f * x * x + 16.4585f * x - 2.39942f) /
(-1.12718f * x * x + 29.1433f * x + 1.0f));
}
}
static Float meanCosineFunctor(Float kappa, Float g) {
return VonMisesFisherDistr(kappa).getMeanCosine()-g;
}
Float VonMisesFisherDistr::forMeanCosine(Float g) {
if (g == 0)
return 0;
else if (g < 0)
SLog(EError, "Error: vMF distribution cannot be created for g<0.");
BrentSolver brentSolver(100, 1e-6f);
BrentSolver::Result result = brentSolver.solve(
boost::bind(&meanCosineFunctor, _1, g), 0, 1000);
SAssert(result.success);
return result.x;
}
MTS_NAMESPACE_END MTS_NAMESPACE_END

View File

@ -14,6 +14,8 @@ for ver in hasPython:
pythonEnv.Append(CPPDEFINES = [['MTS_BUILD_MODULE', 'MTS_MODULE_PYTHON']]) pythonEnv.Append(CPPDEFINES = [['MTS_BUILD_MODULE', 'MTS_MODULE_PYTHON']])
pythonEnv['SHLIBPREFIX']='' pythonEnv['SHLIBPREFIX']=''
pythonEnv.RelaxCompilerSettings() pythonEnv.RelaxCompilerSettings()
pythonEnv.Append(LIBS=['mitsuba-bidir'])
pythonEnv.Append(LIBPATH=['#src/libbidir'])
if pythonEnv.has_key('XERCESINCLUDE'): if pythonEnv.has_key('XERCESINCLUDE'):
pythonEnv.Prepend(CPPPATH=pythonEnv['XERCESINCLUDE']) pythonEnv.Prepend(CPPPATH=pythonEnv['XERCESINCLUDE'])

View File

@ -18,6 +18,7 @@
#include <mitsuba/core/mstream.h> #include <mitsuba/core/mstream.h>
#include <mitsuba/core/cstream.h> #include <mitsuba/core/cstream.h>
#include <mitsuba/core/qmc.h> #include <mitsuba/core/qmc.h>
#include <mitsuba/core/vmf.h>
#include <mitsuba/core/shvector.h> #include <mitsuba/core/shvector.h>
#include <mitsuba/core/sshstream.h> #include <mitsuba/core/sshstream.h>
#include <mitsuba/render/scenehandler.h> #include <mitsuba/render/scenehandler.h>
@ -506,6 +507,7 @@ bp::object cast(ConfigurableObject *obj) {
TryCast(Medium); TryCast(Medium);
TryCast(VolumeDataSource); TryCast(VolumeDataSource);
TryCast(Film); TryCast(Film);
TryCast(PerspectiveCamera);
TryCast(ProjectiveCamera); TryCast(ProjectiveCamera);
TryCast(Sensor); TryCast(Sensor);
TryCast(Emitter); TryCast(Emitter);
@ -525,13 +527,13 @@ static bp::object pluginmgr_createobject_2(PluginManager *mgr, const Class *cls,
return cast(mgr->createObject(cls, props)); return cast(mgr->createObject(cls, props));
} }
static ConfigurableObject *pluginmgr_create(PluginManager *manager, bp::dict dict) { static ConfigurableObject *pluginmgr_create_helper(PluginManager *manager, bp::dict dict, std::map<std::string, ConfigurableObject *> &objs) {
Properties properties; Properties properties;
bp::list list = dict.items(); bp::list items = dict.items();
std::map<std::string, ConfigurableObject *> children; std::map<std::string, ConfigurableObject *> children;
for (int i=0; i<bp::len(list); ++i) { for (bp::stl_input_iterator<bp::tuple> it(items), end; it!=end; ++it) {
bp::tuple tuple = bp::extract<bp::tuple>(list[i]); bp::tuple tuple = *it;
std::string name = bp::extract<std::string>(tuple[0]); std::string name = bp::extract<std::string>(tuple[0]);
bp::extract<bp::dict> extractDict(tuple[1]); bp::extract<bp::dict> extractDict(tuple[1]);
bp::extract<std::string> extractString(tuple[1]); bp::extract<std::string> extractString(tuple[1]);
@ -542,8 +544,13 @@ static ConfigurableObject *pluginmgr_create(PluginManager *manager, bp::dict dic
SLog(EError, "'type' property must map to a string!"); SLog(EError, "'type' property must map to a string!");
else else
properties.setPluginName(extractString()); properties.setPluginName(extractString());
} else if (name == "id") {
if (!extractString.check())
SLog(EError, "'id' property must map to a string!");
else
properties.setID(extractString());
} else if (extractDict.check()) { } else if (extractDict.check()) {
children[name] = pluginmgr_create(manager, extractDict()); children[name] = pluginmgr_create_helper(manager, extractDict(), objs);
} else if (extractConfigurableObject.check()) { } else if (extractConfigurableObject.check()) {
children[name] = extractConfigurableObject(); children[name] = extractConfigurableObject();
} else { } else {
@ -552,10 +559,23 @@ static ConfigurableObject *pluginmgr_create(PluginManager *manager, bp::dict dic
} }
ConfigurableObject *object; ConfigurableObject *object;
if (properties.getPluginName() == "scene") if (properties.getPluginName() == "scene") {
object = new Scene(properties); object = new Scene(properties);
else } else if (properties.getPluginName() == "ref") {
std::string id = properties.getID();
if (id == "unnamed")
SLog(EError, "id parameter of reference is missing!");
if (objs.find(id) == objs.end())
SLog(EError, "Could not find referenced object with id \"%s\"", id.c_str());
return objs[id];
} else {
object = manager->createObject(properties); object = manager->createObject(properties);
}
if (properties.getID() != "unnamed") {
objs[properties.getID()] = object;
object->incRef();
}
for (std::map<std::string, ConfigurableObject *>::iterator it = children.begin(); for (std::map<std::string, ConfigurableObject *>::iterator it = children.begin();
it != children.end(); ++it) { it != children.end(); ++it) {
@ -567,6 +587,15 @@ static ConfigurableObject *pluginmgr_create(PluginManager *manager, bp::dict dic
return object; return object;
} }
static ConfigurableObject *pluginmgr_create(PluginManager *manager, bp::dict dict) {
std::map<std::string, ConfigurableObject *> objs;
ConfigurableObject *result = pluginmgr_create_helper(manager, dict, objs);
for (std::map<std::string, ConfigurableObject *>::iterator it = objs.begin();
it != objs.end(); ++it)
it->second->decRef();
return result;
}
static bp::tuple mkCoordinateSystem(const Vector &n) { static bp::tuple mkCoordinateSystem(const Vector &n) {
Vector s, t; Vector s, t;
coordinateSystem(n, s, t); coordinateSystem(n, s, t);
@ -1030,6 +1059,9 @@ void export_core() {
coreModule.attr("Epsilon") = Epsilon; coreModule.attr("Epsilon") = Epsilon;
coreModule.attr("ShadowEpsilon") = ShadowEpsilon; coreModule.attr("ShadowEpsilon") = ShadowEpsilon;
coreModule.attr("DeltaEpsilon") = DeltaEpsilon; coreModule.attr("DeltaEpsilon") = DeltaEpsilon;
coreModule.attr("SPECTRUM_SAMPLES") = SPECTRUM_SAMPLES;
coreModule.attr("MTS_VERSION") = MTS_VERSION;
coreModule.attr("MTS_YEAR") = MTS_YEAR;
bp::class_<Class, boost::noncopyable>("Class", bp::no_init) bp::class_<Class, boost::noncopyable>("Class", bp::no_init)
.def("getName", &Class::getName, BP_RETURN_CONSTREF) .def("getName", &Class::getName, BP_RETURN_CONSTREF)
@ -1264,6 +1296,7 @@ void export_core() {
BP_CLASS(Bitmap, Object, (bp::init<Bitmap::EPixelFormat, Bitmap::EComponentFormat, const Vector2i &>())) BP_CLASS(Bitmap, Object, (bp::init<Bitmap::EPixelFormat, Bitmap::EComponentFormat, const Vector2i &>()))
.def(bp::init<Bitmap::EPixelFormat, Bitmap::EComponentFormat, const Vector2i &, int>()) .def(bp::init<Bitmap::EPixelFormat, Bitmap::EComponentFormat, const Vector2i &, int>())
.def(bp::init<Bitmap::EFileFormat, Stream *>()) .def(bp::init<Bitmap::EFileFormat, Stream *>())
.def(bp::init<Bitmap::EFileFormat, Stream *, std::string>())
.def("getPixelFormat", &Bitmap::getPixelFormat) .def("getPixelFormat", &Bitmap::getPixelFormat)
.def("getComponentFormat", &Bitmap::getComponentFormat) .def("getComponentFormat", &Bitmap::getComponentFormat)
.def("getSize", &Bitmap::getSize, BP_RETURN_VALUE) .def("getSize", &Bitmap::getSize, BP_RETURN_VALUE)
@ -1361,6 +1394,7 @@ void export_core() {
.value("EOpenEXR", Bitmap::EOpenEXR) .value("EOpenEXR", Bitmap::EOpenEXR)
.value("ETGA", Bitmap::ETGA) .value("ETGA", Bitmap::ETGA)
.value("EPFM", Bitmap::EPFM) .value("EPFM", Bitmap::EPFM)
.value("EPPM", Bitmap::EPPM)
.value("ERGBE", Bitmap::ERGBE) .value("ERGBE", Bitmap::ERGBE)
.value("EBMP", Bitmap::EBMP) .value("EBMP", Bitmap::EBMP)
.value("EJPEG", Bitmap::EJPEG) .value("EJPEG", Bitmap::EJPEG)
@ -2263,6 +2297,20 @@ void export_core() {
.def("getMillisecondsSinceStart", &Timer::getMillisecondsSinceStart) .def("getMillisecondsSinceStart", &Timer::getMillisecondsSinceStart)
.def("getSecondsSinceStart", &Timer::getSecondsSinceStart); .def("getSecondsSinceStart", &Timer::getSecondsSinceStart);
BP_STRUCT(VonMisesFisherDistr, bp::init<Float>())
.def("getKappa", &VonMisesFisherDistr::getKappa)
.def("setKappa", &VonMisesFisherDistr::setKappa)
.def("eval", &VonMisesFisherDistr::eval)
.def("getMeanCosine", &VonMisesFisherDistr::getMeanCosine)
.def("sample", &VonMisesFisherDistr::sample, BP_RETURN_VALUE)
.def("forMeanCosine", &VonMisesFisherDistr::forMeanCosine)
.def("forPeakValue", &VonMisesFisherDistr::forPeakValue)
.def("convolve", &VonMisesFisherDistr::convolve)
.def("__repr__", &VonMisesFisherDistr::toString)
.staticmethod("forMeanCosine")
.staticmethod("forPeakValue")
.staticmethod("convolve");
bp::detail::current_scope = oldScope; bp::detail::current_scope = oldScope;
} }

View File

@ -626,6 +626,14 @@ void export_render() {
.def("setFarClip", &ProjectiveCamera::setFarClip) .def("setFarClip", &ProjectiveCamera::setFarClip)
.def("setFocusDistance", &ProjectiveCamera::setFocusDistance); .def("setFocusDistance", &ProjectiveCamera::setFocusDistance);
BP_CLASS(PerspectiveCamera, ProjectiveCamera, bp::no_init)
.def("getXFov", &PerspectiveCamera::getXFov)
.def("setXFov", &PerspectiveCamera::setXFov)
.def("getYFov", &PerspectiveCamera::getYFov)
.def("setYFov", &PerspectiveCamera::setYFov)
.def("getDiagonalFov", &PerspectiveCamera::getDiagonalFov)
.def("setDiagonalFov", &PerspectiveCamera::setDiagonalFov);
BP_CLASS(Integrator, ConfigurableObject, bp::no_init) BP_CLASS(Integrator, ConfigurableObject, bp::no_init)
.def("preprocess", &Integrator::preprocess) .def("preprocess", &Integrator::preprocess)
.def("render", &Integrator::render) .def("render", &Integrator::render)

View File

@ -27,6 +27,7 @@
#include <xercesc/parsers/SAXParser.hpp> #include <xercesc/parsers/SAXParser.hpp>
#include <xercesc/framework/MemBufInputSource.hpp> #include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/util/TransService.hpp> #include <xercesc/util/TransService.hpp>
#include <xercesc/sax/Locator.hpp>
#include <mitsuba/render/scenehandler.h> #include <mitsuba/render/scenehandler.h>
#include <mitsuba/core/fresolver.h> #include <mitsuba/core/fresolver.h>
#include <mitsuba/render/scene.h> #include <mitsuba/render/scene.h>
@ -38,24 +39,21 @@ XERCES_CPP_NAMESPACE_USE
#define TRANSCODE_BLOCKSIZE 2048 #define TRANSCODE_BLOCKSIZE 2048
#if !defined(__OSX__) #define XMLLog(level, fmt, ...) Thread::getThread()->getLogger()->log(\
#define XMLLog(level, fmt, ...) Thread::getThread()->getLogger()->log(\ level, NULL, __FILE__, __LINE__, "In file \"%s\" (near line %i): " fmt, \
level, NULL, __FILE__, __LINE__, "Near file offset %i: " fmt, \ m_locator ? transcode(m_locator->getSystemId()).c_str() : "<unknown>", \
(int) m_parser->getSrcOffset(), ## __VA_ARGS__) m_locator ? m_locator->getLineNumber() : -1, \
#else ## __VA_ARGS__)
#define XMLLog(level, fmt, ...) Thread::getThread()->getLogger()->log(\
level, NULL, __FILE__, __LINE__, fmt, ## __VA_ARGS__)
#endif
typedef void (*CleanupFun) (); typedef void (*CleanupFun) ();
typedef boost::unordered_set<CleanupFun> CleanupSet; typedef boost::unordered_set<CleanupFun> CleanupSet;
static PrimitiveThreadLocal<CleanupSet> __cleanup_tls; static PrimitiveThreadLocal<CleanupSet> __cleanup_tls;
SceneHandler::SceneHandler(const SAXParser *parser, SceneHandler::SceneHandler(const ParameterMap &params,
const ParameterMap &params, NamedObjectMap *namedObjects, NamedObjectMap *namedObjects, bool isIncludedFile) : m_params(params),
bool isIncludedFile) : m_parser(parser), m_params(params),
m_namedObjects(namedObjects), m_isIncludedFile(isIncludedFile) { m_namedObjects(namedObjects), m_isIncludedFile(isIncludedFile) {
m_pluginManager = PluginManager::getInstance(); m_pluginManager = PluginManager::getInstance();
m_locator = NULL;
if (m_isIncludedFile) { if (m_isIncludedFile) {
SAssert(namedObjects != NULL); SAssert(namedObjects != NULL);
@ -119,6 +117,10 @@ SceneHandler::~SceneHandler() {
delete m_namedObjects; delete m_namedObjects;
} }
void SceneHandler::setDocumentLocator(const xercesc::Locator* const locator) {
m_locator = locator;
}
void SceneHandler::clear() { void SceneHandler::clear() {
if (!m_isIncludedFile) { if (!m_isIncludedFile) {
for (NamedObjectMap::iterator it = m_namedObjects->begin(); for (NamedObjectMap::iterator it = m_namedObjects->begin();
@ -665,14 +667,10 @@ void SceneHandler::endElement(const XMLCh* const xmlName) {
parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str()); parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str());
/* Set the handler and start parsing */ /* Set the handler and start parsing */
SceneHandler *handler = new SceneHandler(parser, m_params, m_namedObjects, true); SceneHandler *handler = new SceneHandler(m_params, m_namedObjects, true);
parser->setDoNamespaces(true); parser->setDoNamespaces(true);
parser->setDocumentHandler(handler); parser->setDocumentHandler(handler);
parser->setErrorHandler(handler); parser->setErrorHandler(handler);
#if !defined(__OSX__)
/// Not supported on OSX
parser->setCalculateSrcOfs(true);
#endif
fs::path path = resolver->resolve(context.attributes["filename"]); fs::path path = resolver->resolve(context.attributes["filename"]);
XMLLog(EInfo, "Parsing included file \"%s\" ..", path.filename().string().c_str()); XMLLog(EInfo, "Parsing included file \"%s\" ..", path.filename().string().c_str());
parser->parse(path.c_str()); parser->parse(path.c_str());
@ -741,7 +739,11 @@ void SceneHandler::endElement(const XMLCh* const xmlName) {
} }
} else { } else {
object = m_pluginManager->createObject(tag.second, props); try {
object = m_pluginManager->createObject(tag.second, props);
} catch (const std::exception &ex) {
XMLLog(EError, "Error while creating object: %s", ex.what());
}
} }
} }
break; break;
@ -831,9 +833,8 @@ ref<Scene> SceneHandler::loadScene(const fs::path &filename, const ParameterMap
parser->setValidationSchemaFullChecking(true); parser->setValidationSchemaFullChecking(true);
parser->setValidationScheme(SAXParser::Val_Always); parser->setValidationScheme(SAXParser::Val_Always);
parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str()); parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str());
parser->setCalculateSrcOfs(true);
SceneHandler *handler = new SceneHandler(parser, params); SceneHandler *handler = new SceneHandler(params);
parser->setDoNamespaces(true); parser->setDoNamespaces(true);
parser->setDocumentHandler(handler); parser->setDocumentHandler(handler);
parser->setErrorHandler(handler); parser->setErrorHandler(handler);
@ -858,9 +859,8 @@ ref<Scene> SceneHandler::loadSceneFromString(const std::string &content, const P
parser->setValidationSchemaFullChecking(true); parser->setValidationSchemaFullChecking(true);
parser->setValidationScheme(SAXParser::Val_Always); parser->setValidationScheme(SAXParser::Val_Always);
parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str()); parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str());
parser->setCalculateSrcOfs(true);
SceneHandler *handler = new SceneHandler(parser, params); SceneHandler *handler = new SceneHandler(params);
parser->setDoNamespaces(true); parser->setDoNamespaces(true);
parser->setDocumentHandler(handler); parser->setDocumentHandler(handler);
parser->setErrorHandler(handler); parser->setErrorHandler(handler);

View File

@ -48,42 +48,43 @@ static MaterialEntry materialData[] = {
/* From "Acquiring Scattering Properties of Participating Media by Dilution" /* From "Acquiring Scattering Properties of Participating Media by Dilution"
by Narasimhan, Gupta, Donner, Ramamoorthi, Nayar, Jensen (SIGGRAPH 2006) */ by Narasimhan, Gupta, Donner, Ramamoorthi, Nayar, Jensen (SIGGRAPH 2006) */
{ "Lowfat Milk", { 0.9124f, 1.0744f, 1.2492f }, { 0.0002f, 0.0004f, 0.0008f }, { 0.9320f, 0.9020f, 0.8590f }, 1.33f }, { "Lowfat Milk", { 13.1157f, 15.4445f, 17.9572f }, { 0.00287f, 0.00575f, 0.01150f }, { 0.93200f, 0.90200f, 0.85900f }, 1.33f },
{ "Reduced Milk", { 1.0748f, 1.2209f, 1.3931f }, { 0.0002f, 0.0004f, 0.0010f }, { 0.8190f, 0.7970f, 0.7460f }, 1.33f }, { "Reduced Milk", { 13.7335f, 15.6003f, 17.8007f }, { 0.00256f, 0.00511f, 0.01278f }, { 0.81900f, 0.79700f, 0.74600f }, 1.33f },
{ "Regular Milk", { 1.1873f, 1.3293f, 1.4589f }, { 0.0001f, 0.0003f, 0.0013f }, { 0.7500f, 0.7140f, 0.6810f }, 1.33f }, { "Regular Milk", { 18.2052f, 20.3826f, 22.3698f }, { 0.00153f, 0.00460f, 0.01993f }, { 0.75000f, 0.71400f, 0.68100f }, 1.33f },
{ "Espresso", { 0.2707f, 0.2828f, 0.2970f }, { 0.1669f, 0.2287f, 0.3078f }, { 0.9070f, 0.8960f, 0.8800f }, 1.33f }, { "Espresso", { 7.78262f, 8.13050f, 8.53875f }, { 4.79838f, 6.57512f, 8.84925f }, { 0.90700f, 0.89600f, 0.88000f }, 1.33f },
{ "Mint Mocha Coffee", { 0.0916f, 0.1081f, 0.1460f }, { 0.0984f, 0.1519f, 0.2040f }, { 0.9100f, 0.9070f, 0.9140f }, 1.33f }, { "Mint Mocha Coffee", { 3.51133f, 4.14383f, 5.59667f }, { 3.77200f, 5.82283f, 7.82000f }, { 0.91000f, 0.90700f, 0.91400f }, 1.33f },
{ "Lowfat Soy Milk", { 0.1418f, 0.1620f, 0.2715f }, { 0.0001f, 0.0005f, 0.0025f }, { 0.8500f, 0.8530f, 0.8420f }, 1.33f }, { "Lowfat Soy Milk", { 2.03838f, 2.32875f, 3.90281f }, { 0.00144f, 0.00719f, 0.03594f }, { 0.85000f, 0.85300f, 0.84200f }, 1.33f },
{ "Regular Soy Milk", { 0.2433f, 0.2714f, 0.4563f }, { 0.0001f, 0.0005f, 0.0034f }, { 0.8730f, 0.8580f, 0.8320f }, 1.33f }, { "Regular Soy Milk", { 4.66325f, 5.20183f, 8.74575f }, { 0.00192f, 0.00958f, 0.06517f }, { 0.87300f, 0.85800f, 0.83200f }, 1.33f },
{ "Lowfat Chocolate Milk", { 0.4277f, 0.4998f, 0.5723f }, { 0.0005f, 0.0016f, 0.0068f }, { 0.9340f, 0.9270f, 0.9160f }, 1.33f }, { "Lowfat Chocolate Milk", { 9.83710f, 11.4954f, 13.1629f }, { 0.01150f, 0.03680f, 0.15640f }, { 0.93400f, 0.92700f, 0.91600f }, 1.33f },
{ "Regular Chocolate Milk", { 0.7352f, 0.9142f, 1.0588f }, { 0.0007f, 0.0030f, 0.0100f }, { 0.8620f, 0.8380f, 0.8060f }, 1.33f }, { "Regular Chocolate Milk", { 10.5685f, 13.1416f, 15.2202f }, { 0.01006f, 0.04313f, 0.14375f }, { 0.86200f, 0.83800f, 0.80600f }, 1.33f },
{ "Coke", { 0.0177f, 0.0208f, 0.0000f }, { 0.6966f, 1.1480f, 1.7169f }, { 0.9650f, 0.9720f, 0.9685f }, 1.33f }, { "Coke", { 0.00254f, 0.00299f, 0.00000f }, { 0.10014f, 0.16503f, 0.24680f }, { 0.96500f, 0.97200f, 0.00000f }, 1.33f },
{ "Pepsi", { 0.0058f, 0.0141f, 0.0000f }, { 0.6375f, 0.9849f, 1.4420f }, { 0.9260f, 0.9790f, 0.9525f }, 1.33f }, { "Pepsi", { 0.00083f, 0.00203f, 0.00000f }, { 0.09164f, 0.14158f, 0.20729f }, { 0.92600f, 0.97900f, 0.00000f }, 1.33f },
{ "Sprite", { 0.0069f, 0.0089f, 0.0089f }, { 0.1230f, 0.1194f, 0.1306f }, { 0.9430f, 0.9530f, 0.9520f }, 1.33f }, { "Sprite", { 0.00011f, 0.00014f, 0.00014f }, { 0.00189f, 0.00183f, 0.00200f }, { 0.94300f, 0.95300f, 0.95200f }, 1.33f },
{ "Gatorade", { 0.2392f, 0.2927f, 0.3745f }, { 0.1617f, 0.1258f, 0.0579f }, { 0.9330f, 0.9330f, 0.9350f }, 1.33f }, { "Gatorade", { 0.03668f, 0.04488f, 0.05742f }, { 0.02479f, 0.01929f, 0.00888f }, { 0.93300f, 0.93300f, 0.93500f }, 1.33f },
{ "Chardonnay", { 0.0030f, 0.0047f, 0.0069f }, { 0.1547f, 0.1701f, 0.3443f }, { 0.9140f, 0.9580f, 0.9750f }, 1.33f }, { "Chardonnay", { 0.00021f, 0.00033f, 0.00048f }, { 0.01078f, 0.01186f, 0.02400f }, { 0.91400f, 0.95800f, 0.97500f }, 1.33f },
{ "White Zinfandel", { 0.0031f, 0.0048f, 0.0066f }, { 0.1732f, 0.2322f, 0.2847f }, { 0.9190f, 0.9430f, 0.9720f }, 1.33f }, { "White Zinfandel", { 0.00022f, 0.00033f, 0.00046f }, { 0.01207f, 0.01618f, 0.01984f }, { 0.91900f, 0.94300f, 0.97200f }, 1.33f },
{ "Merlot", { 0.0053f, 0.0000f, 0.0000f }, { 0.7586f, 1.6429f, 1.9196f }, { 0.9740f, 0.9740f, 0.9740f }, 1.33f }, { "Merlot", { 0.00081f, 0.00000f, 0.00000f }, { 0.11632f, 0.25191f, 0.29434f }, { 0.97400f, 0.00000f, 0.00000f }, 1.33f },
{ "Budweiser Beer", { 0.0037f, 0.0069f, 0.0074f }, { 0.1449f, 0.3141f, 0.7286f }, { 0.9170f, 0.9560f, 0.9820f }, 1.33f }, { "Budweiser Beder", { 0.00029f, 0.00055f, 0.00059f }, { 0.01149f, 0.02491f, 0.05779f }, { 0.91700f, 0.95600f, 0.98200f }, 1.33f },
{ "Coors Light Beer", { 0.0027f, 0.0055f, 0.0000f }, { 0.0268f, 0.0608f, 0.1521f }, { 0.9180f, 0.9660f, 0.9420f }, 1.33f }, { "Coors Light Beer", { 0.00062f, 0.00127f, 0.00000f }, { 0.00616f, 0.01398f, 0.03498f }, { 0.91800f, 0.96600f, 0.00000f }, 1.33f },
{ "Clorox", { 0.1425f, 0.1723f, 0.1928f }, { 0.0175f, 0.0777f, 0.1372f }, { 0.9120f, 0.9050f, 0.8920f }, 1.33f }, { "Clorox", { 0.02731f, 0.03302f, 0.03695f }, { 0.00335f, 0.01489f, 0.02630f }, { 0.91200f, 0.90500f, 0.89200f }, 1.33f },
{ "Apple Juice", { 0.0201f, 0.0243f, 0.0323f }, { 0.1014f, 0.1858f, 0.4084f }, { 0.9470f, 0.9490f, 0.9450f }, 1.33f }, { "Apple Juice", { 0.00257f, 0.00311f, 0.00413f }, { 0.01296f, 0.02374f, 0.05218f }, { 0.94700f, 0.94900f, 0.94500f }, 1.33f },
{ "Cranberry Juice", { 0.0128f, 0.0155f, 0.0196f }, { 0.2572f, 0.6145f, 0.8104f }, { 0.9470f, 0.9510f, 0.9740f }, 1.33f }, { "Cranberry Juice", { 0.00196f, 0.00238f, 0.00301f }, { 0.03944f, 0.09422f, 0.12426f }, { 0.94700f, 0.95100f, 0.97400f }, 1.33f },
{ "Grape Juice", { 0.0072f, 0.0000f, 0.0000f }, { 0.5428f, 1.2500f, 1.5300f }, { 0.9610f, 0.9610f, 0.9610f }, 1.33f }, { "Grape Juice", { 0.00138f, 0.00000f, 0.00000f }, { 0.10404f, 0.23958f, 0.29325f }, { 0.96100f, 0.00000f, 0.00000f }, 1.33f },
{ "Ruby Grapefruit Juice", { 0.1617f, 0.1606f, 0.1669f }, { 0.0896f, 0.1911f, 0.2636f }, { 0.9290f, 0.9290f, 0.9310f }, 1.33f }, { "Ruby Grapefruit Juice", { 0.15496f, 0.15391f, 0.15995f }, { 0.08587f, 0.18314f, 0.25262f }, { 0.92900f, 0.92900f, 0.93100f }, 1.33f },
{ "White Grapefruit Juice", { 0.3513f, 0.3669f, 0.5237f }, { 0.0096f, 0.0131f, 0.0395f }, { 0.5480f, 0.5450f, 0.5650f }, 1.33f }, { "White Grapefruit Juice", { 0.50499f, 0.52742f, 0.75282f }, { 0.01380f, 0.01883f, 0.05678f }, { 0.54800f, 0.54500f, 0.56500f }, 1.33f },
{ "Shampoo", { 0.0104f, 0.0114f, 0.0147f }, { 0.0184f, 0.0596f, 0.0805f }, { 0.9100f, 0.9050f, 0.9200f }, 1.33f }, { "Shampoo", { 0.00797f, 0.00874f, 0.01127f }, { 0.01411f, 0.04569f, 0.06172f }, { 0.91000f, 0.90500f, 0.92000f }, 1.33f },
{ "Strawberry Shampoo", { 0.0028f, 0.0032f, 0.0033f }, { 0.0189f, 0.0756f, 0.0989f }, { 0.9270f, 0.9350f, 0.9940f }, 1.33f }, { "Strawberry Shampoo", { 0.00215f, 0.00245f, 0.00253f }, { 0.01449f, 0.05796f, 0.07582f }, { 0.92700f, 0.93500f, 0.99400f }, 1.33f },
{ "Head & Shoulders Shampoo", { 0.2791f, 0.2890f, 0.3086f }, { 0.0883f, 0.1637f, 0.2125f }, { 0.9110f, 0.8960f, 0.8840f }, 1.33f }, { "Head & Shoulders Shampoo", { 0.26747f, 0.27696f, 0.29574f }, { 0.08462f, 0.15688f, 0.20365f }, { 0.91100f, 0.89600f, 0.88400f }, 1.33f },
{ "Lemon Tea Powder", { 0.0798f, 0.0898f, 0.1073f }, { 0.2602f, 0.4902f, 0.7727f }, { 0.9460f, 0.9460f, 0.9490f }, 1.33f }, { "Lemon Tea Powder", { 0.74489f, 0.83823f, 1.00158f }, { 2.42881f, 4.57573f, 7.21270f }, { 0.94600f, 0.94600f, 0.94900f }, 1.33f },
{ "Orange Juice Powder", { 0.1928f, 0.2132f, 0.2259f }, { 0.1449f, 0.3441f, 0.7863f }, { 0.9190f, 0.9180f, 0.9220f }, 1.33f }, { "Orange Juice Powder", { 0.00193f, 0.00213f, 0.00226f }, { 0.00145f, 0.00344f, 0.00786f }, { 0.91900f, 0.91800f, 0.92200f }, 1.33f },
{ "Pink Lemonade Powder", { 0.1235f, 0.1334f, 0.1305f }, { 0.1165f, 0.2366f, 0.3195f }, { 0.9020f, 0.9020f, 0.9040f }, 1.33f }, { "Pink Lemonade Powder", { 0.00123f, 0.00133f, 0.00131f }, { 0.00116f, 0.00237f, 0.00320f }, { 0.90200f, 0.90200f, 0.90400f }, 1.33f },
{ "Cappuccino Powder", { 0.0654f, 0.0882f, 0.1568f }, { 0.1920f, 0.2654f, 0.3272f }, { 0.8490f, 0.8430f, 0.9260f }, 1.33f }, { "Cappuccino Powder", { 12.2094f, 16.4659f, 29.2727f }, { 35.8441f, 49.5470f, 61.0844f }, { 0.84900f, 0.84300f, 0.92600f }, 1.33f },
{ "Salt Powder", { 0.2485f, 0.2822f, 0.3216f }, { 0.5115f, 0.5863f, 0.6147f }, { 0.8020f, 0.7930f, 0.8210f }, 1.33f }, { "Salt Powder", { 0.13805f, 0.15677f, 0.17865f }, { 0.28415f, 0.32570f, 0.34148f }, { 0.80200f, 0.79300f, 0.82100f }, 1.33f },
{ "Sugar Powder", { 0.0145f, 0.0162f, 0.0202f }, { 0.0650f, 0.1597f, 0.2578f }, { 0.9210f, 0.9190f, 0.9310f }, 1.33f }, { "Sugar Powder", { 0.00282f, 0.00315f, 0.00393f }, { 0.01264f, 0.03105f, 0.05012f }, { 0.92100f, 0.91900f, 0.93100f }, 1.33f },
{ "Suisse Mocha", { 0.3223f, 0.3583f, 0.4148f }, { 0.1875f, 0.2893f, 0.3796f }, { 0.9070f, 0.8940f, 0.8880f }, 1.33f }, { "Suisse Mocha Powder", { 30.0848f, 33.4452f, 38.7191f }, { 17.5020f, 27.0044f, 35.4334f }, { 0.90700f, 0.89400f, 0.88800f }, 1.33f },
{ "Pacific Ocean Surface Water", { 0.00180f, 0.00183f, 0.00228f }, { 0.03184f, 0.03132f, 0.03015f }, { 0.90200f, 0.82500f, 0.91400f }, 1.33f },
{ NULL, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, 0.0f } { NULL, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, 0.0f }
}; };
static void lookupMaterial(const Properties &props, Spectrum &sigmaS, Spectrum &sigmaA, Spectrum &g, Float *eta = NULL) { static void lookupMaterial(const Properties &props, Spectrum &sigmaS, Spectrum &sigmaA, Spectrum &g, Float *eta = NULL) {
@ -197,3 +198,4 @@ static void lookupMaterial(const Properties &props, Spectrum &sigmaS, Spectrum &
MTS_NAMESPACE_END MTS_NAMESPACE_END
#endif /* __MATERIAL_DATA_H */ #endif /* __MATERIAL_DATA_H */

View File

@ -328,13 +328,9 @@ int mitsuba_app(int argc, char **argv) {
parser->setValidationSchemaFullChecking(true); parser->setValidationSchemaFullChecking(true);
parser->setValidationScheme(SAXParser::Val_Always); parser->setValidationScheme(SAXParser::Val_Always);
parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str()); parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str());
#if !defined(__OSX__)
/// Not supported on OSX
parser->setCalculateSrcOfs(true);
#endif
/* Set the handler */ /* Set the handler */
SceneHandler *handler = new SceneHandler(parser, parameters); SceneHandler *handler = new SceneHandler(parameters);
parser->setDoNamespaces(true); parser->setDoNamespaces(true);
parser->setDocumentHandler(handler); parser->setDocumentHandler(handler);
parser->setErrorHandler(handler); parser->setErrorHandler(handler);
@ -375,6 +371,8 @@ int mitsuba_app(int argc, char **argv) {
thr->start(); thr->start();
renderQueue->waitLeft(numParallelScenes-1); renderQueue->waitLeft(numParallelScenes-1);
if (i+1 < argc && numParallelScenes == 1)
Statistics::getInstance()->resetAll();
} }
/* Wait for all render processes to finish */ /* Wait for all render processes to finish */

View File

@ -159,13 +159,6 @@ public:
} }
}; };
/* Collect zombie processes */
#if !defined(__WINDOWS__)
void collect_zombies(int s) {
while (waitpid(-1, NULL, WNOHANG) > 0);
}
#endif
#if defined(__OSX__) #if defined(__OSX__)
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif #endif
@ -213,13 +206,8 @@ int main(int argc, char *argv[]) {
#if !defined(__WINDOWS__) #if !defined(__WINDOWS__)
/* Avoid zombies processes when running the server */ /* Avoid zombies processes when running the server */
struct sigaction sa; if (signal(SIGCHLD, SIG_IGN) == SIG_ERR)
sa.sa_handler = collect_zombies; SLog(EWarn, "Error in signal(): %s!", strerror(errno));
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1)
SLog(EWarn, "Error in sigaction(): %s!", strerror(errno));
#endif #endif
qRegisterMetaType<ELogLevel>("ELogLevel"); qRegisterMetaType<ELogLevel>("ELogLevel");

View File

@ -585,8 +585,8 @@ void MainWindow::on_actionOpen_triggered() {
QSettings settings; QSettings settings;
QStringList fileNames = QFileDialog::getOpenFileNames(this, QString(), QStringList fileNames = QFileDialog::getOpenFileNames(this, QString(),
settings.value("fileDir").toString(), settings.value("fileDir").toString(),
tr("All supported formats (*.xml *.exr *.rgbe *.hdr *.pfm *.png *.jpg *.jpeg);;" tr("All supported formats (*.xml *.exr *.rgbe *.hdr *.pfm *.ppm *.png *.jpg *.jpeg);;"
"Mitsuba scenes (*.xml);;High dynamic-range images (*.exr *.rgbe *.hdr *.pfm);;" "Mitsuba scenes (*.xml);;High dynamic-range images (*.exr *.rgbe *.hdr *.pfm *.ppm);;"
"Low dynamic-range images (*.png *.jpg *.jpeg)")); "Low dynamic-range images (*.png *.jpg *.jpeg)"));
QStringList::ConstIterator it = fileNames.constBegin(); QStringList::ConstIterator it = fileNames.constBegin();
@ -605,8 +605,8 @@ void MainWindow::onOpenDialogClose(int reason) { /* unused */ }
void MainWindow::on_actionOpen_triggered() { void MainWindow::on_actionOpen_triggered() {
QFileDialog *dialog = new QFileDialog(this, Qt::Sheet); QFileDialog *dialog = new QFileDialog(this, Qt::Sheet);
dialog->setNameFilter(tr("All supported formats (*.xml *.exr *.rgbe *.hdr *.pfm *.png *.jpg *.jpeg);;" dialog->setNameFilter(tr("All supported formats (*.xml *.exr *.rgbe *.hdr *.pfm *.ppm *.png *.jpg *.jpeg);;"
"Mitsuba scenes (*.xml);;High dynamic-range images (*.exr *.rgbe *.hdr *.pfm);;Low " "Mitsuba scenes (*.xml);;High dynamic-range images (*.exr *.rgbe *.hdr *.pfm *.ppm);;Low "
"dynamic-range images (*.png *.jpg *.jpeg)")); "dynamic-range images (*.png *.jpg *.jpeg)"));
dialog->setAttribute(Qt::WA_DeleteOnClose); dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setAcceptMode(QFileDialog::AcceptOpen); dialog->setAcceptMode(QFileDialog::AcceptOpen);
@ -690,7 +690,7 @@ retry:
ret = QMessageBox::question(this, tr("Version mismatch -- update scene file?"), ret = QMessageBox::question(this, tr("Version mismatch -- update scene file?"),
QString("The requested scene file is from an older version of Mitsuba " QString("The requested scene file is from an older version of Mitsuba "
"(%1). To work with version %2, it will need to be updated. If you " "(%1). To work with version %2, it will need to be updated. If you "
"continue, Mitsuba will perform a fully automated upgrade (note that a " "continue, Mitsuba will perform a fully automated upgrade (a "
"backup copy will be made).\n\nProceed?") "backup copy will be made).\n\nProceed?")
.arg(version.toString().c_str()) .arg(version.toString().c_str())
.arg(MTS_VERSION), QMessageBox::Yes | QMessageBox::Cancel); .arg(MTS_VERSION), QMessageBox::Yes | QMessageBox::Cancel);
@ -825,6 +825,7 @@ void MainWindow::updateUI() {
ui->actionClose->setEnabled(hasTab); ui->actionClose->setEnabled(hasTab);
ui->actionDuplicateTab->setEnabled(hasTab); ui->actionDuplicateTab->setEnabled(hasTab);
ui->actionAdjustSize->setEnabled(hasTab); ui->actionAdjustSize->setEnabled(hasTab);
ui->actionCopyImage->setEnabled(hasTab);
ui->actionShowKDTree->setEnabled(hasScene); ui->actionShowKDTree->setEnabled(hasScene);
ui->actionShowKDTree->setChecked(hasScene && context->showKDTree); ui->actionShowKDTree->setChecked(hasScene && context->showKDTree);
ui->actionSceneDescription->setEnabled(hasScene); ui->actionSceneDescription->setEnabled(hasScene);
@ -888,6 +889,7 @@ void MainWindow::on_tabBar_customContextMenuRequested(const QPoint &pt) {
menu.addAction(ui->actionDuplicateTab); menu.addAction(ui->actionDuplicateTab);
if (tabIndex == ui->tabBar->currentIndex()) if (tabIndex == ui->tabBar->currentIndex())
menu.addAction(ui->actionAdjustSize); menu.addAction(ui->actionAdjustSize);
menu.addAction(ui->actionCopyImage);
menu.addAction(ui->actionClose); menu.addAction(ui->actionClose);
menu.exec(ui->tabBar->mapToGlobal(pt)); menu.exec(ui->tabBar->mapToGlobal(pt));
m_contextIndex = -1; m_contextIndex = -1;
@ -1482,6 +1484,10 @@ inline float toSRGB(float value) {
return 1.055f * std::pow(value, 0.41666f) - 0.055f; return 1.055f * std::pow(value, 0.41666f) - 0.055f;
} }
void MainWindow::on_actionCopyImage_triggered() {
exportImage("__clipboard__");
}
#if MTSGUI_STATIC_QFILEDIALOG #if MTSGUI_STATIC_QFILEDIALOG
void MainWindow::on_actionExportImage_triggered() { void MainWindow::on_actionExportImage_triggered() {
@ -1492,6 +1498,7 @@ void MainWindow::on_actionExportImage_triggered() {
"High dynamic range OpenEXR image (*.exr);;" "High dynamic range OpenEXR image (*.exr);;"
"High dynamic range Radiance RGBE image (*.rgbe *.hdr);;" "High dynamic range Radiance RGBE image (*.rgbe *.hdr);;"
"High dynamic range Portable Float Map image (*.pfm);;" "High dynamic range Portable Float Map image (*.pfm);;"
"High dynamic range Portable Pixel Map image (*.ppm);;"
"Tonemapped low dynamic range image (*.png *.jpg *.jpeg)")); "Tonemapped low dynamic range image (*.png *.jpg *.jpeg)"));
if (!fileName.isEmpty()) { if (!fileName.isEmpty()) {
QSettings settings; QSettings settings;
@ -1510,6 +1517,7 @@ void MainWindow::on_actionExportImage_triggered() {
"High dynamic range OpenEXR image (*.exr);;" "High dynamic range OpenEXR image (*.exr);;"
"High dynamic range Radiance RGBE image (*.rgbe *.hdr);;" "High dynamic range Radiance RGBE image (*.rgbe *.hdr);;"
"High dynamic range Portable Float Map image (*.pfm);;" "High dynamic range Portable Float Map image (*.pfm);;"
"High dynamic range Portable Pixel Map image (*.ppm);;"
"Tonemapped low dynamic range image (*.png *.jpg *.jpeg)")); "Tonemapped low dynamic range image (*.png *.jpg *.jpeg)"));
QSettings settings; QSettings settings;
@ -1548,29 +1556,30 @@ void MainWindow::onExportDialogClose(int reason) {
void MainWindow::exportImage(const QString &fileName) { void MainWindow::exportImage(const QString &fileName) {
if (!fileName.isEmpty()) { if (!fileName.isEmpty()) {
Bitmap::EComponentFormat compFormat = Bitmap::EInvalid;
Bitmap::EFileFormat format; Bitmap::EFileFormat format;
bool isHDR = true;
if (fileName.endsWith(".exr")) { if (fileName.endsWith(".exr")) {
format = Bitmap::EOpenEXR; format = Bitmap::EOpenEXR;
} else if (fileName.endsWith(".png")) { } else if (fileName.endsWith(".png") || fileName == "__clipboard__") {
format = Bitmap::EPNG; format = Bitmap::EPNG;
isHDR = false; compFormat = Bitmap::EUInt8;
} else if (fileName.endsWith(".hdr") || fileName.endsWith(".rgbe")) { } else if (fileName.endsWith(".hdr") || fileName.endsWith(".rgbe")) {
format = Bitmap::ERGBE; format = Bitmap::ERGBE;
} else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) { } else if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
format = Bitmap::EJPEG; format = Bitmap::EJPEG;
isHDR = false; compFormat = Bitmap::EUInt8;
} else if (fileName.endsWith(".pfm")) { } else if (fileName.endsWith(".pfm")) {
format = Bitmap::EPFM; format = Bitmap::EPFM;
} else if (fileName.endsWith(".ppm")) {
format = Bitmap::EPPM;
compFormat = Bitmap::EUInt16;
} else { } else {
SLog(EError, "Unknown file type -- the filename must end in either" SLog(EError, "Unknown file type -- the filename must end in either"
" .exr, .rgbe, .hdr, .pfm, .png, .jpg, or .jpeg"); " .exr, .rgbe, .hdr, .pfm, .ppm, .png, .jpg, or .jpeg");
return; return;
} }
ref<FileStream> fs = new FileStream(toFsPath(fileName),
FileStream::ETruncReadWrite);
const int currentIndex = ui->tabBar->currentIndex(); const int currentIndex = ui->tabBar->currentIndex();
const SceneContext *ctx = m_context[currentIndex]; const SceneContext *ctx = m_context[currentIndex];
@ -1578,7 +1587,7 @@ void MainWindow::exportImage(const QString &fileName) {
ui->glView->downloadFramebuffer(); ui->glView->downloadFramebuffer();
ref<Bitmap> bitmap = ctx->framebuffer; ref<Bitmap> bitmap = ctx->framebuffer;
if (!isHDR) { if (compFormat == Bitmap::EUInt8 || compFormat == Bitmap::EUInt16) {
/* Tonemap the image */ /* Tonemap the image */
if (ctx->toneMappingMethod == EReinhard) { if (ctx->toneMappingMethod == EReinhard) {
Float logAvgLuminance = 0, maxLuminance = 0; /* Unused */ Float logAvgLuminance = 0, maxLuminance = 0; /* Unused */
@ -1589,13 +1598,24 @@ void MainWindow::exportImage(const QString &fileName) {
ctx->reinhardKey, burn); ctx->reinhardKey, burn);
} }
bitmap = bitmap->convert(Bitmap::ERGB, Bitmap::EUInt8, bitmap = bitmap->convert(Bitmap::ERGB, compFormat,
ctx->srgb ? (Float) -1 : ctx->gamma, ctx->srgb ? (Float) -1 : ctx->gamma,
ctx->toneMappingMethod == EReinhard ctx->toneMappingMethod == EReinhard
? (Float) 1.0f : std::pow((Float) 2, ctx->exposure)); ? (Float) 1.0f : std::pow((Float) 2, ctx->exposure));
} }
bitmap->write(format, fs); if (fileName == "__clipboard__") {
QImage image(bitmap->getWidth(), bitmap->getHeight(), QImage::Format_RGB888);
size_t scanlineSize = (size_t) bitmap->getWidth() * 3 * sizeof(uint8_t);
for (int i=0; i<bitmap->getHeight(); ++i)
memcpy(image.scanLine(i), bitmap->getUInt8Data() + scanlineSize * i, scanlineSize);
QClipboard *clipboard = QApplication::clipboard();
clipboard->setPixmap(QPixmap::fromImage(image));
} else {
ref<FileStream> fs = new FileStream(toFsPath(fileName),
FileStream::ETruncReadWrite);
bitmap->write(format, fs);
}
} }
} }

View File

@ -172,6 +172,7 @@ private slots:
void on_actionFocusAll_triggered(); void on_actionFocusAll_triggered();
void on_actionSceneDescription_triggered(); void on_actionSceneDescription_triggered();
void on_actionEnableCommandLine_triggered(); void on_actionEnableCommandLine_triggered();
void on_actionCopyImage_triggered();
void on_tabBar_currentChanged(int index); void on_tabBar_currentChanged(int index);
bool on_tabBar_tabCloseRequested(int index); bool on_tabBar_tabCloseRequested(int index);
void on_tabBar_tabMoved(int from, int to); void on_tabBar_tabMoved(int from, int to);

View File

@ -128,6 +128,7 @@
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionSave"/> <addaction name="actionSave"/>
<addaction name="actionSaveAs"/> <addaction name="actionSaveAs"/>
<addaction name="actionCopyImage"/>
<addaction name="actionExportImage"/> <addaction name="actionExportImage"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionClose"/> <addaction name="actionClose"/>
@ -475,6 +476,14 @@
<string>Ctrl+F</string> <string>Ctrl+F</string>
</property> </property>
</action> </action>
<action name="actionCopyImage">
<property name="text">
<string>&amp;Copy image</string>
</property>
<property name="shortcut">
<string>Ctrl+C</string>
</property>
</action>
<action name="actionFeedback"> <action name="actionFeedback">
<property name="text"> <property name="text">
<string>Report &amp;Feedback</string> <string>Report &amp;Feedback</string>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 892 B

After

Width:  |  Height:  |  Size: 1008 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 B

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 568 B

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 376 B

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 929 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 708 B

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 518 B

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 504 B

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 642 B

After

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 911 B

After

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 775 B

After

Width:  |  Height:  |  Size: 967 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 566 B

After

Width:  |  Height:  |  Size: 755 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 B

After

Width:  |  Height:  |  Size: 682 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 964 B

After

Width:  |  Height:  |  Size: 1017 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 B

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 811 B

After

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 795 B

After

Width:  |  Height:  |  Size: 899 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 583 B

After

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 895 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 796 B

After

Width:  |  Height:  |  Size: 1000 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 649 B

After

Width:  |  Height:  |  Size: 629 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 652 B

After

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 B

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 682 B

After

Width:  |  Height:  |  Size: 744 B

View File

@ -48,7 +48,7 @@ void SceneLoader::run() {
QFileInfo fileInfo(m_filename); QFileInfo fileInfo(m_filename);
QString suffix = fileInfo.suffix().toLower(); QString suffix = fileInfo.suffix().toLower();
SceneHandler *handler = new SceneHandler(parser, m_parameters); SceneHandler *handler = new SceneHandler(m_parameters);
m_result = new SceneContext(); m_result = new SceneContext();
try { try {
QSettings settings; QSettings settings;
@ -67,7 +67,7 @@ void SceneLoader::run() {
m_result->diffuseReceivers = settings.value("preview_diffuseReceivers", false).toBool(); m_result->diffuseReceivers = settings.value("preview_diffuseReceivers", false).toBool();
if (suffix == "exr" || suffix == "png" || suffix == "jpg" || suffix == "jpeg" || if (suffix == "exr" || suffix == "png" || suffix == "jpg" || suffix == "jpeg" ||
suffix == "hdr" || suffix == "rgbe" || suffix == "pfm") { suffix == "hdr" || suffix == "rgbe" || suffix == "pfm" || suffix == "ppm") {
/* This is an image, not a scene */ /* This is an image, not a scene */
ref<FileStream> fs = new FileStream(toFsPath(m_filename), FileStream::EReadOnly); ref<FileStream> fs = new FileStream(toFsPath(m_filename), FileStream::EReadOnly);
ref<Bitmap> bitmap = new Bitmap(Bitmap::EAuto, fs); ref<Bitmap> bitmap = new Bitmap(Bitmap::EAuto, fs);
@ -87,10 +87,6 @@ void SceneLoader::run() {
parser->setValidationSchemaFullChecking(true); parser->setValidationSchemaFullChecking(true);
parser->setValidationScheme(SAXParser::Val_Always); parser->setValidationScheme(SAXParser::Val_Always);
parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str()); parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str());
#if !defined(__OSX__)
/// Not supported on OSX
parser->setCalculateSrcOfs(true);
#endif
/* Set the SAX handler */ /* Set the SAX handler */
parser->setDoNamespaces(true); parser->setDoNamespaces(true);

View File

@ -448,7 +448,7 @@ public:
std::string toString() const { std::string toString() const {
std::ostringstream oss; std::ostringstream oss;
oss << "PerspectiveCamera[" << endl oss << "PerspectiveCamera[" << endl
<< " xfov = " << m_xfov << "," << endl << " fov = [" << getXFov() << ", " << getYFov() << "]," << endl
<< " nearClip = " << m_nearClip << "," << endl << " nearClip = " << m_nearClip << "," << endl
<< " farClip = " << m_farClip << "," << endl << " farClip = " << m_farClip << "," << endl
<< " worldTransform = " << indent(m_worldTransform.toString()) << "," << endl << " worldTransform = " << indent(m_worldTransform.toString()) << "," << endl

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