Merge with upstream

metadata
Edgar Velazquez-Armendariz 2013-01-21 17:40:21 -05:00
commit 40cfc60ee7
31 changed files with 742 additions and 216 deletions

View File

@ -20,7 +20,7 @@ if sys.platform == 'win32':
# Set an application icon on Windows # Set an application icon on Windows
resources += [ env.RES('data/windows/mitsuba_res.rc') ] resources += [ env.RES('data/windows/mitsuba_res.rc') ]
# Convert the command line args from UTF-8 to UTF-16 # Convert the command line args from UTF-8 to UTF-16
winstubs += [os.path.abspath('data/windows/wmain_stub.cpp')] winstubs += [ env.SharedObject('#data/windows/wmain_stub.cpp') ]
Export('winstubs') Export('winstubs')
def build(scriptFile, exports = [], duplicate = 0): def build(scriptFile, exports = [], duplicate = 0):

View File

@ -285,7 +285,7 @@ if needsBuildDependencies:
print '\nThe dependency directory and your Mitsuba codebase have different version' print '\nThe dependency directory and your Mitsuba codebase have different version'
print 'numbers! Your copy of Mitsuba has version %s, whereas the dependencies ' % MTS_VERSION print 'numbers! Your copy of Mitsuba has version %s, whereas the dependencies ' % MTS_VERSION
print 'have version %s. Please bring them into sync, either by running\n' % depVersion print 'have version %s. Please bring them into sync, either by running\n' % depVersion
print '$ hg update -r v%s\n' % depVersion print '$ hg update -r v%s\n' % depVersion
print 'in the Mitsuba directory, or by running\n' print 'in the Mitsuba directory, or by running\n'
print '$ cd dependencies' print '$ cd dependencies'
print '$ hg pull' print '$ hg pull'
@ -353,7 +353,7 @@ def configure_for_objective_cpp(env):
env.RemoveFlags(['-fstrict-aliasing', '-ftree-vectorize', env.RemoveFlags(['-fstrict-aliasing', '-ftree-vectorize',
'-std=c\+\+0x']) '-std=c\+\+0x'])
# Remove Intel compiler-specific optimization flags # Remove Intel compiler-specific optimization flags
env.RemoveFlags(['-x.*', '-ax.*', '-ipo', '-no-prec-div', env.RemoveFlags(['-x.*', '-ax.*', '-ipo', '-no-prec-div',
'-fp-model', 'fast=.*', '-wd.*', '-openmp']) '-fp-model', 'fast=.*', '-wd.*', '-openmp'])
env['CCFLAGS'] += ['-fno-strict-aliasing'] env['CCFLAGS'] += ['-fno-strict-aliasing']
# Enforce GCC usage (Intel compiler doesn't handle Objective C/C++) # Enforce GCC usage (Intel compiler doesn't handle Objective C/C++)
@ -374,7 +374,7 @@ env.__class__.ConfigureForObjectiveCPP = configure_for_objective_cpp
env.__class__.RelaxCompilerSettings = relax_compiler_settings env.__class__.RelaxCompilerSettings = relax_compiler_settings
if hasCollada: if hasCollada:
env.Append(CPPDEFINES = [['MTS_HAS_COLLADA', 1]] ) env.Append(CPPDEFINES = [['MTS_HAS_COLLADA', 1]])
env.SConsignFile() env.SConsignFile()

View File

@ -4,7 +4,7 @@ Priority: optional
Maintainer: Wenzel Jakob <wenzel@cs.cornell.edu> Maintainer: Wenzel Jakob <wenzel@cs.cornell.edu>
Build-Depends: debhelper (>= 7), build-essential, scons, qt4-dev-tools, Build-Depends: debhelper (>= 7), build-essential, scons, qt4-dev-tools,
libpng12-dev, libjpeg-dev, libilmbase-dev, libopenexr-dev, libpng12-dev, libjpeg-dev, libilmbase-dev, libopenexr-dev,
libxerces-c-dev, libboost-dev, libglewmx1.5-dev, libxxf86vm-dev, libxerces-c-dev, libboost-dev, libglewmx-dev, libxxf86vm-dev,
collada-dom-dev, libboost-system-dev, libboost-filesystem-dev, collada-dom-dev, libboost-system-dev, libboost-filesystem-dev,
libboost-python-dev, libboost-thread-dev, libgl1-mesa-dev, libboost-python-dev, libboost-thread-dev, libgl1-mesa-dev,
libglu1-mesa-dev, pkg-config, libeigen3-dev libglu1-mesa-dev, pkg-config, libeigen3-dev
@ -24,7 +24,7 @@ Description: Mitsuba renderer
Package: mitsuba-dev Package: mitsuba-dev
Architecture: any Architecture: any
Depends: qt4-dev-tools, libpng12-dev, libjpeg-dev, libilmbase-dev, Depends: qt4-dev-tools, libpng12-dev, libjpeg-dev, libilmbase-dev,
libopenexr-dev, libxerces-c-dev, libboost-dev, libglewmx1.5-dev, libopenexr-dev, libxerces-c-dev, libboost-dev, libglewmx-dev,
libxxf86vm-dev, collada-dom-dev, libboost-system-dev, libxxf86vm-dev, collada-dom-dev, libboost-system-dev,
libboost-filesystem-dev, libboost-python-dev, libboost-thread-dev, libboost-filesystem-dev, libboost-python-dev, libboost-thread-dev,
libeigen3-dev, mitsuba libeigen3-dev, mitsuba

View File

@ -42,7 +42,7 @@
#include <mitsuba/core/constants.h> #include <mitsuba/core/constants.h>
#include <mitsuba/core/fwd.h> #include <mitsuba/core/fwd.h>
#include <mitsuba/render/fwd.h> #include <mitsuba/render/fwd.h>
#include <mitsuba/core/stl.h> #include <mitsuba/core/math.h>
#include <mitsuba/core/object.h> #include <mitsuba/core/object.h>
#include <mitsuba/core/ref.h> #include <mitsuba/core/ref.h>
#include <mitsuba/core/tls.h> #include <mitsuba/core/tls.h>

View File

@ -2,11 +2,18 @@
\subsection{Subsurface scattering models} \subsection{Subsurface scattering models}
\label{sec:subsurface} \label{sec:subsurface}
There are two ways of simulating subsurface scattering within Mitsuba: There are two ways of simulating subsurface scattering within Mitsuba:
participating media and subsurface scattering models. The latter are described participating media and subsurface scattering models.
in this section and can be thought of as a first-order approximation of the
former. For this reason, subsurface scattering models should be preferred when \begin{description}
visually appealing output should be generated quickly and the demands on \item[Subsurface scattering models:] Described in this section. These can be thought
physical realism are secondary. of as a first-order approximation of what happens inside a participating medium.
They are preferable when visually appealing output should be generated
\emph{quickly} and the demands on accuracy are secondary.
At the moment, there is only one subsurface scattering model (the
\pluginref{dipole}), which is described on the next page.
\item[Participating media:] Described in Section~\ref{sec:media}. When modeling
subsurface scattering using a participating medium, Mitsuba performs a \emph{full}
radiative transport simulation, which correctly accounts for all scattering events.
This is more accurate but generally significantly slower.
\end{description}
At the moment, there is only one subsurface scattering model (the
\pluginref{dipole}), which is described on the next page.

View File

@ -393,17 +393,8 @@ public:
/// Draw a rectangle with the specified position and size /// Draw a rectangle with the specified position and size
void drawRect(const Point2i &offset, const Vector2i &size, const Spectrum &value); void drawRect(const Point2i &offset, const Vector2i &size, const Spectrum &value);
/**
* \brief Color balancing: apply the given scale factors to the
* red, green, and blue channels of the image
*
* When the image is not an \c EFloat16, \c EFloat32, or
* \c EFloat64-based RGB/RGBA image, the function throws an exception
*/
void colorBalance(Float r, Float g, Float b);
/// Draw a filled rectangle with the specified position and size /// Draw a filled rectangle with the specified position and size
void fill(const Point2i &offset, const Vector2i &size, const Spectrum &value); void fillRect(Point2i offset, Vector2i size, const Spectrum &value);
/// Bitmap equality operator (useful for unit-tests etc.) /// Bitmap equality operator (useful for unit-tests etc.)
bool operator==(const Bitmap &bitmap) const; bool operator==(const Bitmap &bitmap) const;
@ -699,7 +690,43 @@ public:
* use different component formats or channels, or when the * use different component formats or channels, or when the
* component format is \ref EBitmask. * component format is \ref EBitmask.
*/ */
void accumulate(const Bitmap *bitmap, const Point2i &offset); void accumulate(const Bitmap *bitmap, Point2i sourceOffset,
Point2i targetOffset, Vector2i size);
/**
* \brief Color balancing: apply the given scale factors to the
* red, green, and blue channels of the image
*
* When the image is not an \c EFloat16, \c EFloat32, or
* \c EFloat64-based RGB/RGBA image, the function throws an exception
*/
void colorBalance(Float r, Float g, Float b);
/**
* Apply a color transformation matrix to the contents of the bitmap
*
* The implementation assumes that the contents have the
* RGB, RGBA, XYZ, or XYZA pixel format and a floating point
* component format.
*/
void applyMatrix(Float matrix[3][3]);
/**
* \brief Accumulate the contents of another bitmap into the
* region of the specified offset
*
* This convenience function calls the main <tt>accumulate()</tt>
* implementation with <tt>size</tt> set to <tt>bitmap->getSize()</tt>
* and <tt>sourceOffset</tt> set to zero. Out-of-bounds regions are
* ignored. It is assumed that <tt>bitmap != this</tt>.
*
* \remark This function throws an exception when the bitmaps
* use different component formats or channels, or when the
* component format is \ref EBitmask.
*/
inline void accumulate(const Bitmap *bitmap, Point2i targetOffset) {
accumulate(bitmap, Point2i(0), targetOffset, bitmap->getSize());
}
/** /**
* \brief Up- or down-sample this image to a different resolution * \brief Up- or down-sample this image to a different resolution

View File

@ -189,6 +189,55 @@ extern MTS_EXPORT_CORE void __mts_set_appdefaults();
#define MTS_AUTORELEASE_BEGIN() #define MTS_AUTORELEASE_BEGIN()
#define MTS_AUTORELEASE_END() #define MTS_AUTORELEASE_END()
#endif #endif
MTS_NAMESPACE_END MTS_NAMESPACE_END
/// \cond
// Try to make MSVC++ behave a bit more like C++
// with an underlying C99 implementation
// (and dn't include this in the documentation)
#if defined(_MSC_VER)
#include <float.h>
#define snprintf _snprintf
#define vsnprintf _vsnprintf
namespace std {
inline char tolower(char c) {
return ::tolower(c);
}
inline char toupper(char c) {
return ::toupper(c);
}
inline bool isnan(float f) {
return _isnan(f);
}
inline bool isnan(double f) {
return _isnan(f);
}
inline bool isfinite(float f) {
return _finite(f);
}
inline bool isfinite(double f) {
return _finite(f);
}
inline bool isinf(float f) {
return !_finite(f);
}
inline bool isinf(double f) {
return !_finite(f);
}
};
#endif
#endif /* __MITSUBA_CORE_PLATFORM_H_ */ #endif /* __MITSUBA_CORE_PLATFORM_H_ */

View File

@ -493,6 +493,14 @@ public:
return value; return value;
} }
/// Component-wise square root
inline TSpectrum safe_sqrt() const {
TSpectrum value;
for (int i=0; i<N; i++)
value.s[i] = math::safe_sqrt(s[i]);
return value;
}
/// Component-wise exponentation /// Component-wise exponentation
inline TSpectrum exp() const { inline TSpectrum exp() const {
TSpectrum value; TSpectrum value;

View File

@ -20,90 +20,6 @@
#if !defined(__MITSUBA_CORE_STL_H_) #if !defined(__MITSUBA_CORE_STL_H_)
#define __MITSUBA_CORE_STL_H_ #define __MITSUBA_CORE_STL_H_
/* Include some SGI STL extensions, which might be missing */
#ifdef __GNUC__
#include <ext/functional>
using __gnu_cxx::select2nd;
using __gnu_cxx::compose1;
#else
#include <functional>
/// \cond
// (Don't include in the documentation)
namespace std {
template <class _Pair> struct _Select1st : public unary_function<_Pair, typename _Pair::first_type> {
const typename _Pair::first_type& operator()(const _Pair& __x) const {
return __x.first;
}
};
template <class _Pair> struct _Select2nd : public unary_function<_Pair, typename _Pair::second_type> {
const typename _Pair::second_type& operator()(const _Pair& __x) const {
return __x.second;
}
};
template <class _Pair> struct select1st : public _Select1st<_Pair> {};
template <class _Pair> struct select2nd : public _Select2nd<_Pair> {};
template <class _Operation1, class _Operation2> class unary_compose : public unary_function<typename _Operation2::argument_type, typename _Operation1::result_type> {
protected:
_Operation1 _M_fn1;
_Operation2 _M_fn2;
public:
unary_compose(const _Operation1& __x, const _Operation2& __y) : _M_fn1(__x), _M_fn2(__y) {}
typename _Operation1::result_type operator()(const typename _Operation2::argument_type& __x) const {
return _M_fn1(_M_fn2(__x));
}
};
template <class _Operation1, class _Operation2> inline unary_compose<_Operation1,_Operation2> compose1(const _Operation1& __fn1, const _Operation2& __fn2) {
return unary_compose<_Operation1,_Operation2>(__fn1, __fn2);
}
#if defined(_MSC_VER)
#include <float.h>
#define snprintf _snprintf
#define vsnprintf _vsnprintf
inline char tolower(char c) {
return ::tolower(c);
}
inline char toupper(char c) {
return ::toupper(c);
}
inline bool isnan(float f) {
return _isnan(f);
}
inline bool isnan(double f) {
return _isnan(f);
}
inline bool isfinite(float f) {
return _finite(f);
}
inline bool isfinite(double f) {
return _finite(f);
}
inline bool isinf(float f) {
return !_finite(f);
}
inline bool isinf(double f) {
return !_finite(f);
}
#endif
};
using std::select2nd;
using std::compose1;
#endif
namespace mitsuba { namespace mitsuba {
namespace math { namespace math {
#if defined(__LINUX__) && defined(__x86_64__) #if defined(__LINUX__) && defined(__x86_64__)

View File

@ -507,22 +507,99 @@ inline Float fresnelDielectricExt(Float cosThetaI, Float eta) { Float cosThetaT;
return fresnelDielectricExt(cosThetaI, cosThetaT, eta); } return fresnelDielectricExt(cosThetaI, cosThetaT, eta); }
/** /**
* \brief Calculates the unpolarized fresnel reflection coefficient * \brief Calculates the unpolarized Fresnel reflection coefficient
* at a planar interface between vacuum and a conductor. * at a planar interface having a complex-valued relative index of
* refraction (approximate scalar version)
*
* The implementation of this function relies on a simplified expression
* that becomes increasingly accurate as k grows.
*
* The name of this function is a slight misnomer, since it supports
* the general case of a complex-valued relative index of refraction
* (rather than being restricted to conductors)
* *
* \param cosThetaI * \param cosThetaI
* Cosine of the angle between the normal and the incident ray * Cosine of the angle between the normal and the incident ray
* \param eta * \param eta
* Real refractive index (wavelength-dependent) * Relative refractive index (real component)
* \param k * \param k
* Imaginary refractive index (wavelength-dependent) * Relative refractive index (imaginary component)
* \ingroup libpython * \ingroup libpython
*/ */
extern MTS_EXPORT_CORE Spectrum fresnelConductor(Float cosThetaI, extern MTS_EXPORT_CORE Float fresnelConductorApprox(Float cosThetaI,
Float eta, Float k);
/**
* \brief Calculates the unpolarized Fresnel reflection coefficient
* at a planar interface having a complex-valued relative index of
* refraction (approximate vectorized version)
*
* The implementation of this function relies on a simplified expression
* that becomes increasingly accurate as k grows.
*
* The name of this function is a slight misnomer, since it supports
* the general case of a complex-valued relative index of refraction
* (rather than being restricted to conductors)
*
* \param cosThetaI
* Cosine of the angle between the normal and the incident ray
* \param eta
* Relative refractive index (real component)
* \param k
* Relative refractive index (imaginary component)
* \ingroup libpython
*/
extern MTS_EXPORT_CORE Spectrum fresnelConductorApprox(Float cosThetaI,
const Spectrum &eta, const Spectrum &k); const Spectrum &eta, const Spectrum &k);
/** /**
* \brief Calculates the diffuse unpolarized fresnel reflectance of * \brief Calculates the unpolarized Fresnel reflection coefficient
* at a planar interface having a complex-valued relative index of
* refraction (accurate scalar version)
*
* The implementation of this function computes the exact unpolarized
* Fresnel reflectance for a complex index of refraction change.
*
* The name of this function is a slight misnomer, since it supports
* the general case of a complex-valued relative index of refraction
* (rather than being restricted to conductors)
*
* \param cosThetaI
* Cosine of the angle between the normal and the incident ray
* \param eta
* Relative refractive index (real component)
* \param k
* Relative refractive index (imaginary component)
* \ingroup libpython
*/
extern MTS_EXPORT_CORE Float fresnelConductorExact(Float cosThetaI,
Float eta, Float k);
/**
* \brief Calculates the unpolarized Fresnel reflection coefficient
* at a planar interface having a complex-valued relative index of
* refraction (accurate vectorized version)
*
* The implementation of this function computes the exact unpolarized
* Fresnel reflectance for a complex index of refraction change.
*
* The name of this function is a slight misnomer, since it supports
* the general case of a complex-valued relative index of refraction
* (rather than being restricted to conductors)
*
* \param cosThetaI
* Cosine of the angle between the normal and the incident ray
* \param eta
* Relative refractive index (real component)
* \param k
* Relative refractive index (imaginary component)
* \ingroup libpython
*/
extern MTS_EXPORT_CORE Spectrum fresnelConductorExact(Float cosThetaI,
const Spectrum &eta, const Spectrum &k);
/**
* \brief Calculates the diffuse unpolarized Fresnel reflectance of
* a dielectric material (sometimes referred to as "Fdr"). * a dielectric material (sometimes referred to as "Fdr").
* *
* This value quantifies what fraction of diffuse incident illumination * This value quantifies what fraction of diffuse incident illumination

View File

@ -76,12 +76,22 @@ public:
/// Allocate memory for a certain font /// Allocate memory for a certain font
Font(EFont font); Font(EFont font);
/// Draw text to the specified bitmap
void drawText(Bitmap *dest, Point2i pos, const std::string &text) const;
/// Compute the size covered by the given string when rendered using this font
Vector2i getSize(const std::string &text) const;
/// Upload the font to the GPU /// Upload the font to the GPU
void init(Renderer *renderer); void init(Renderer *renderer);
/// Free the GPU memory /// Free the GPU memory
void cleanup(); void cleanup();
/// Convert the underlying bitmap to a different pixel format
void convert(Bitmap::EPixelFormat pixelFormat,
Bitmap::EComponentFormat componentFormat, Float gamma);
/// Return the name of this font /// Return the name of this font
inline const std::string &getName() const { return m_name; } inline const std::string &getName() const { return m_name; }

View File

@ -74,6 +74,9 @@ public:
/// Serialize to a binary data stream /// Serialize to a binary data stream
virtual void serialize(Stream *stream, InstanceManager *manager) const; virtual void serialize(Stream *stream, InstanceManager *manager) const;
/// Return the underlying bitmap representation (if any)
virtual ref<Bitmap> getBitmap() const;
MTS_DECLARE_CLASS() MTS_DECLARE_CLASS()
protected: protected:
Texture(const Properties &props); Texture(const Properties &props);

View File

@ -20,6 +20,7 @@
#include <mitsuba/core/fresolver.h> #include <mitsuba/core/fresolver.h>
#include <mitsuba/hw/basicshader.h> #include <mitsuba/hw/basicshader.h>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include "ior.h"
MTS_NAMESPACE_BEGIN MTS_NAMESPACE_BEGIN
@ -29,11 +30,12 @@ MTS_NAMESPACE_BEGIN
* \parameters{ * \parameters{
* \parameter{material}{\String}{Name of a material preset, see * \parameter{material}{\String}{Name of a material preset, see
* \tblref{conductor-iors}.\!\default{\texttt{Cu} / copper}} * \tblref{conductor-iors}.\!\default{\texttt{Cu} / copper}}
* \parameter{eta}{\Spectrum}{Real part of the material's index * \parameter{eta, k}{\Spectrum}{Real and imaginary components of the material's index of
* of refraction \default{based on the value of \texttt{material}}} * refraction \default{based on the value of \texttt{material}}}
* \parameter{k}{\Spectrum}{Imaginary part of the material's index of * \parameter{extEta}{\Float\Or\String}{
* refraction, also known as absorption coefficient. * Real-valued index of refraction of the surrounding dielectric,
* \default{based on the value of \texttt{material}}} * or a material name of a dielectric \default{\code{air}}
* }
* \parameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional * \parameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional
* factor that can be used to modulate the specular reflection component. Note * factor that can be used to modulate the specular reflection component. Note
* that for physical realism, this parameter should never be touched. \default{1.0}} * that for physical realism, this parameter should never be touched. \default{1.0}}
@ -154,21 +156,23 @@ public:
m_specularReflectance = new ConstantSpectrumTexture( m_specularReflectance = new ConstantSpectrumTexture(
props.getSpectrum("specularReflectance", Spectrum(1.0f))); props.getSpectrum("specularReflectance", Spectrum(1.0f)));
std::string material = props.getString("material", "Cu"); std::string materialName = props.getString("material", "Cu");
Spectrum materialEta, materialK; Spectrum intEta, intK;
if (boost::to_lower_copy(material) == "none") { if (boost::to_lower_copy(materialName) == "none") {
materialEta = Spectrum(0.0f); intEta = Spectrum(0.0f);
materialK = Spectrum(1.0f); intK = Spectrum(1.0f);
} else { } else {
materialEta.fromContinuousSpectrum(InterpolatedSpectrum( intEta.fromContinuousSpectrum(InterpolatedSpectrum(
fResolver->resolve("data/ior/" + material + ".eta.spd"))); fResolver->resolve("data/ior/" + materialName + ".eta.spd")));
materialK.fromContinuousSpectrum(InterpolatedSpectrum( intK.fromContinuousSpectrum(InterpolatedSpectrum(
fResolver->resolve("data/ior/" + material + ".k.spd"))); fResolver->resolve("data/ior/" + materialName + ".k.spd")));
} }
m_eta = props.getSpectrum("eta", materialEta); Float extEta = lookupIOR(props, "extEta", "air");
m_k = props.getSpectrum("k", materialK);
m_eta = props.getSpectrum("eta", intEta) / extEta;
m_k = props.getSpectrum("k", intK) / extEta;
} }
SmoothConductor(Stream *stream, InstanceManager *manager) SmoothConductor(Stream *stream, InstanceManager *manager)
@ -229,7 +233,7 @@ public:
return Spectrum(0.0f); return Spectrum(0.0f);
return m_specularReflectance->eval(bRec.its) * return m_specularReflectance->eval(bRec.its) *
fresnelConductor(Frame::cosTheta(bRec.wi), m_eta, m_k); fresnelConductorExact(Frame::cosTheta(bRec.wi), m_eta, m_k);
} }
Float pdf(const BSDFSamplingRecord &bRec, EMeasure measure) const { Float pdf(const BSDFSamplingRecord &bRec, EMeasure measure) const {
@ -260,7 +264,7 @@ public:
bRec.eta = 1.0f; bRec.eta = 1.0f;
return m_specularReflectance->eval(bRec.its) * return m_specularReflectance->eval(bRec.its) *
fresnelConductor(Frame::cosTheta(bRec.wi), m_eta, m_k); fresnelConductorExact(Frame::cosTheta(bRec.wi), m_eta, m_k);
} }
Spectrum sample(BSDFSamplingRecord &bRec, Float &pdf, const Point2 &sample) const { Spectrum sample(BSDFSamplingRecord &bRec, Float &pdf, const Point2 &sample) const {
@ -277,7 +281,7 @@ public:
pdf = 1; pdf = 1;
return m_specularReflectance->eval(bRec.its) * return m_specularReflectance->eval(bRec.its) *
fresnelConductor(Frame::cosTheta(bRec.wi), m_eta, m_k); fresnelConductorExact(Frame::cosTheta(bRec.wi), m_eta, m_k);
} }
Float getRoughness(const Intersection &its, int component) const { Float getRoughness(const Intersection &its, int component) const {
@ -320,7 +324,7 @@ public:
m_specularReflectanceShader = renderer->registerShaderForResource(m_specularReflectance.get()); m_specularReflectanceShader = renderer->registerShaderForResource(m_specularReflectance.get());
/* Compute the reflectance at perpendicular incidence */ /* Compute the reflectance at perpendicular incidence */
m_R0 = fresnelConductor(1.0f, eta, k); m_R0 = fresnelConductorExact(1.0f, eta, k);
m_alpha = 0.4f; m_alpha = 0.4f;
} }

View File

@ -20,6 +20,7 @@
#include <mitsuba/render/bsdf.h> #include <mitsuba/render/bsdf.h>
#include <mitsuba/hw/basicshader.h> #include <mitsuba/hw/basicshader.h>
#include "microfacet.h" #include "microfacet.h"
#include "ior.h"
MTS_NAMESPACE_BEGIN MTS_NAMESPACE_BEGIN
@ -32,15 +33,15 @@ MTS_NAMESPACE_BEGIN
* used to model the surface roughness. * used to model the surface roughness.
* \begin{enumerate}[(i)] * \begin{enumerate}[(i)]
* \item \code{beckmann}: Physically-based distribution derived from * \item \code{beckmann}: Physically-based distribution derived from
* Gaussian random surfaces. This is the default. * Gaussian random surfaces. This is the default.\vspace{-1mm}
* \item \code{ggx}: New distribution proposed by * \item \code{ggx}: New distribution proposed by
* Walter et al. \cite{Walter07Microfacet}, which is meant to better handle * Walter et al. \cite{Walter07Microfacet}, which is meant to better handle
* the long tails observed in measurements of ground surfaces. * the long tails observed in measurements of ground surfaces.
* Renderings with this distribution may converge slowly. * Renderings with this distribution may converge slowly.\vspace{-1mm}
* \item \code{phong}: Classical $\cos^p\theta$ distribution. * \item \code{phong}: Classical $\cos^p\theta$ distribution.
* Due to the underlying microfacet theory, * Due to the underlying microfacet theory,
* the use of this distribution here leads to more realistic * the use of this distribution here leads to more realistic
* behavior than the separately available \pluginref{phong} plugin. * behavior than the separately available \pluginref{phong} plugin.\vspace{-1mm}
* \item \code{as}: Anisotropic Phong-style microfacet distribution proposed by * \item \code{as}: Anisotropic Phong-style microfacet distribution proposed by
* Ashikhmin and Shirley \cite{Ashikhmin2005Anisotropic}.\vspace{-3mm} * Ashikhmin and Shirley \cite{Ashikhmin2005Anisotropic}.\vspace{-3mm}
* \end{enumerate} * \end{enumerate}
@ -59,11 +60,12 @@ MTS_NAMESPACE_BEGIN
* } * }
* \parameter{material}{\String}{Name of a material preset, see * \parameter{material}{\String}{Name of a material preset, see
* \tblref{conductor-iors}.\!\default{\texttt{Cu} / copper}} * \tblref{conductor-iors}.\!\default{\texttt{Cu} / copper}}
* \parameter{eta}{\Spectrum}{Real part of the material's index * \parameter{eta, k}{\Spectrum}{Real and imaginary components of the material's index of
* of refraction \default{based on the value of \texttt{material}}} * refraction \default{based on the value of \texttt{material}}}
* \parameter{k}{\Spectrum}{Imaginary part of the material's index of * \parameter{extEta}{\Float\Or\String}{
* refraction (the absorption coefficient). * Real-valued index of refraction of the surrounding dielectric,
* \default{based on \texttt{material}}} * or a material name of a dielectric \default{\code{air}}
* }
* \parameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional * \parameter{specular\showbreak Reflectance}{\Spectrum\Or\Texture}{Optional
* factor that can be used to modulate the specular reflection component. Note * factor that can be used to modulate the specular reflection component. Note
* that for physical realism, this parameter should never be touched. \default{1.0}} * that for physical realism, this parameter should never be touched. \default{1.0}}
@ -158,21 +160,23 @@ public:
m_specularReflectance = new ConstantSpectrumTexture( m_specularReflectance = new ConstantSpectrumTexture(
props.getSpectrum("specularReflectance", Spectrum(1.0f))); props.getSpectrum("specularReflectance", Spectrum(1.0f)));
std::string material = props.getString("material", "Cu"); std::string materialName = props.getString("material", "Cu");
Spectrum materialEta, materialK;
if (boost::to_lower_copy(material) == "none") { Spectrum intEta, intK;
materialEta = Spectrum(0.0f); if (boost::to_lower_copy(materialName) == "none") {
materialK = Spectrum(1.0f); intEta = Spectrum(0.0f);
intK = Spectrum(1.0f);
} else { } else {
materialEta.fromContinuousSpectrum(InterpolatedSpectrum( intEta.fromContinuousSpectrum(InterpolatedSpectrum(
fResolver->resolve("data/ior/" + material + ".eta.spd"))); fResolver->resolve("data/ior/" + materialName + ".eta.spd")));
materialK.fromContinuousSpectrum(InterpolatedSpectrum( intK.fromContinuousSpectrum(InterpolatedSpectrum(
fResolver->resolve("data/ior/" + material + ".k.spd"))); fResolver->resolve("data/ior/" + materialName + ".k.spd")));
} }
m_eta = props.getSpectrum("eta", materialEta); Float extEta = lookupIOR(props, "extEta", "air");
m_k = props.getSpectrum("k", materialK);
m_eta = props.getSpectrum("eta", intEta) / extEta;
m_k = props.getSpectrum("k", intK) / extEta;
m_distribution = MicrofacetDistribution( m_distribution = MicrofacetDistribution(
props.getString("distribution", "beckmann") props.getString("distribution", "beckmann")
@ -262,7 +266,7 @@ public:
return Spectrum(0.0f); return Spectrum(0.0f);
/* Fresnel factor */ /* Fresnel factor */
const Spectrum F = fresnelConductor(dot(bRec.wi, H), m_eta, m_k); const Spectrum F = fresnelConductorExact(dot(bRec.wi, H), m_eta, m_k);
/* Smith's shadow-masking function */ /* Smith's shadow-masking function */
const Float G = m_distribution.G(bRec.wi, bRec.wo, H, alphaU, alphaV); const Float G = m_distribution.G(bRec.wi, bRec.wo, H, alphaU, alphaV);
@ -324,7 +328,7 @@ public:
if (Frame::cosTheta(bRec.wo) <= 0) if (Frame::cosTheta(bRec.wo) <= 0)
return Spectrum(0.0f); return Spectrum(0.0f);
const Spectrum F = fresnelConductor(dot(bRec.wi, m), const Spectrum F = fresnelConductorExact(dot(bRec.wi, m),
m_eta, m_k); m_eta, m_k);
Float numerator = m_distribution.eval(m, alphaU, alphaV) Float numerator = m_distribution.eval(m, alphaU, alphaV)
@ -367,7 +371,7 @@ public:
if (Frame::cosTheta(bRec.wo) <= 0) if (Frame::cosTheta(bRec.wo) <= 0)
return Spectrum(0.0f); return Spectrum(0.0f);
const Spectrum F = fresnelConductor(dot(bRec.wi, m), const Spectrum F = fresnelConductorExact(dot(bRec.wi, m),
m_eta, m_k); m_eta, m_k);
Float numerator = m_distribution.eval(m, alphaU, alphaV) Float numerator = m_distribution.eval(m, alphaU, alphaV)
@ -460,7 +464,7 @@ public:
m_alphaVShader = renderer->registerShaderForResource(m_alphaV.get()); m_alphaVShader = renderer->registerShaderForResource(m_alphaV.get());
/* Compute the reflectance at perpendicular incidence */ /* Compute the reflectance at perpendicular incidence */
m_R0 = fresnelConductor(1.0f, eta, k); m_R0 = fresnelConductorExact(1.0f, eta, k);
} }
bool isComplete() const { bool isComplete() const {

View File

@ -20,6 +20,7 @@
#include <mitsuba/core/fstream.h> #include <mitsuba/core/fstream.h>
#include <mitsuba/core/bitmap.h> #include <mitsuba/core/bitmap.h>
#include <mitsuba/core/statistics.h> #include <mitsuba/core/statistics.h>
#include <mitsuba/hw/font.h>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include "banner.h" #include "banner.h"
@ -114,7 +115,33 @@ MTS_NAMESPACE_BEGIN
* <boolean name="banner" value="false"/> * <boolean name="banner" value="false"/>
* </film> * </film>
* \end{xml} * \end{xml}
*
* \subsubsection*{Annotations:}
* \label{sec:film-annotations}
* The \pluginref{ldrfilm} and \pluginref{hdrfilm} plugins support an additional
* feature referred to as \emph{annotations}, which can be quite useful under
* certain circumstances.
*
* Annotations are used to embed useful information inside a rendered image so
* that this information is later available to anyone viewing the image.
* Exemplary uses of this feature might be to store the frame or take number,
* camera parameters, or other relevant scene information.
*
* Annotations can either be created by means of a \emph{tag}, which is an entry
* in the metadata table of the image file (does not modify the actual image data),
* or a \emph{text} label which is ``burned'' into the image.
*
* The syntax of this looks as follows:
*
* \begin{xml}
* <film type="ldrfilm">
* <!-- Create a new metadata entry 'my_tag_name' and set it to the value 'my_tag_value' -->
* <string name="tag('my_tag_name')" value="my_tag_value"/>
*
* <!-- Add the label 'Hello' at the image position X=50, Y=80 -->
* <string name="text(50,80)" value="Hello!"/>
* </film>
* \end{xml}
*/ */
class HDRFilm : public Film { class HDRFilm : public Film {
public: public:
@ -204,6 +231,25 @@ public:
} }
std::vector<std::string> keys = props.getPropertyNames();
for (size_t i=0; i<keys.size(); ++i) {
std::string key = boost::to_lower_copy(keys[i]);
if (boost::starts_with(key, "tag('") && boost::ends_with(key, "')")) {
m_tags[keys[i].substr(5, key.length()-7)] = props.getString(keys[i]);
} else if (boost::starts_with(key, "text(") && boost::ends_with(key, ")")) {
std::vector<std::string> args = tokenize(key.substr(5, key.length()-6), " ,");
if (args.size() != 2)
Log(EError, "Text command '%s' has an invalid number of arguments!", key.c_str());
Annotation annotation;
annotation.offset = Point2i(atoi(args[0].c_str()), atoi(args[1].c_str()));
annotation.text = props.getString(keys[i]);
m_annotations.push_back(annotation);
}
}
m_storage = new ImageBlock(Bitmap::ESpectrumAlphaWeight, m_cropSize); m_storage = new ImageBlock(Bitmap::ESpectrumAlphaWeight, m_cropSize);
} }
@ -321,6 +367,23 @@ public:
} }
} }
if (!m_annotations.empty()) {
ref<Font> font = new Font(Font::EBitstreamVeraMono14);
font->convert(bitmap->getPixelFormat(), bitmap->getComponentFormat(), 1.0f);
for (size_t i=0; i<m_annotations.size(); ++i) {
const Point2i &offset = m_annotations[i].offset;
const std::string &text = m_annotations[i].text;
Vector2i size = font->getSize(text);
bitmap->fillRect(offset-Vector2i(4, 4), size + Vector2i(8, 8), Spectrum(0.0f));
font->drawText(bitmap, offset, text);
}
}
for (std::map<std::string, std::string>::const_iterator it = m_tags.begin();
it != m_tags.end(); ++it)
bitmap->getMetadata()[it->first] = it->second;
fs::path filename = m_destFile; fs::path filename = m_destFile;
std::string extension = boost::to_lower_copy(filename.extension().string()); std::string extension = boost::to_lower_copy(filename.extension().string());
std::string properExtension = (m_fileFormat == Bitmap::EOpenEXR) ? ".exr" : ".rgbe"; std::string properExtension = (m_fileFormat == Bitmap::EOpenEXR) ? ".exr" : ".rgbe";
@ -367,6 +430,11 @@ public:
MTS_DECLARE_CLASS() MTS_DECLARE_CLASS()
protected: protected:
struct Annotation {
Point2i offset;
std::string text;
};
Bitmap::EFileFormat m_fileFormat; Bitmap::EFileFormat m_fileFormat;
Bitmap::EPixelFormat m_pixelFormat; Bitmap::EPixelFormat m_pixelFormat;
Bitmap::EComponentFormat m_componentFormat; Bitmap::EComponentFormat m_componentFormat;
@ -374,6 +442,9 @@ protected:
bool m_attachLog; bool m_attachLog;
fs::path m_destFile; fs::path m_destFile;
ref<ImageBlock> m_storage; ref<ImageBlock> m_storage;
std::vector<Annotation> m_annotations;
std::map<std::string, std::string> m_tags;
}; };
MTS_IMPLEMENT_CLASS_S(HDRFilm, false, Film) MTS_IMPLEMENT_CLASS_S(HDRFilm, false, Film)

View File

@ -20,6 +20,7 @@
#include <mitsuba/core/fstream.h> #include <mitsuba/core/fstream.h>
#include <mitsuba/core/bitmap.h> #include <mitsuba/core/bitmap.h>
#include <mitsuba/core/statistics.h> #include <mitsuba/core/statistics.h>
#include <mitsuba/hw/font.h>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include "banner.h" #include "banner.h"
@ -113,6 +114,9 @@ MTS_NAMESPACE_BEGIN
* The RGB values exported by this plugin correspond to the ITU-R Rec. BT. 709-3 * The RGB values exported by this plugin correspond to the ITU-R Rec. BT. 709-3
* primaries with a D65 white point. When $\texttt{gamma}$ is set to $\code{-1}$ (the default), * primaries with a D65 white point. When $\texttt{gamma}$ is set to $\code{-1}$ (the default),
* the output is in the sRGB color space and will display as intended on compatible devices. * the output is in the sRGB color space and will display as intended on compatible devices.
*
* Note that this plugin supports render-time \emph{annotations}, which
* are described on page~\pageref{sec:film-annotations}.
*/ */
class LDRFilm : public Film { class LDRFilm : public Film {
public: public:
@ -176,6 +180,25 @@ public:
m_reinhardKey = props.getFloat("key", 0.18f); m_reinhardKey = props.getFloat("key", 0.18f);
m_reinhardBurn = props.getFloat("burn", 0.0); m_reinhardBurn = props.getFloat("burn", 0.0);
std::vector<std::string> keys = props.getPropertyNames();
for (size_t i=0; i<keys.size(); ++i) {
std::string key = boost::to_lower_copy(keys[i]);
if (boost::starts_with(key, "tag('") && boost::ends_with(key, "')")) {
m_tags[keys[i].substr(5, key.length()-7)] = props.getString(keys[i]);
} else if (boost::starts_with(key, "text(") && boost::ends_with(key, ")")) {
std::vector<std::string> args = tokenize(key.substr(5, key.length()-6), " ,");
if (args.size() != 2)
Log(EError, "Text command '%s' has an invalid number of arguments!", key.c_str());
Annotation annotation;
annotation.offset = Point2i(atoi(args[0].c_str()), atoi(args[1].c_str()));
annotation.text = props.getString(keys[i]);
m_annotations.push_back(annotation);
}
}
m_storage = new ImageBlock(Bitmap::ESpectrumAlphaWeight, m_cropSize); m_storage = new ImageBlock(Bitmap::ESpectrumAlphaWeight, m_cropSize);
} }
@ -313,6 +336,23 @@ public:
} }
} }
if (!m_annotations.empty()) {
ref<Font> font = new Font(Font::EBitstreamVeraMono14);
font->convert(bitmap->getPixelFormat(), bitmap->getComponentFormat(), m_gamma);
for (size_t i=0; i<m_annotations.size(); ++i) {
const Point2i &offset = m_annotations[i].offset;
const std::string &text = m_annotations[i].text;
Vector2i size = font->getSize(text);
bitmap->fillRect(offset-Vector2i(4, 4), size + Vector2i(8, 8), Spectrum(0.0f));
font->drawText(bitmap, offset, text);
}
}
for (std::map<std::string, std::string>::const_iterator it = m_tags.begin();
it != m_tags.end(); ++it)
bitmap->getMetadata()[it->first] = it->second;
fs::path filename = m_destFile; fs::path filename = m_destFile;
std::string extension = boost::to_lower_copy(filename.extension().string()); std::string extension = boost::to_lower_copy(filename.extension().string());
std::string expectedExtension; std::string expectedExtension;
@ -367,6 +407,11 @@ public:
MTS_DECLARE_CLASS() MTS_DECLARE_CLASS()
protected: protected:
struct Annotation {
Point2i offset;
std::string text;
};
Bitmap::EFileFormat m_fileFormat; Bitmap::EFileFormat m_fileFormat;
Bitmap::EPixelFormat m_pixelFormat; Bitmap::EPixelFormat m_pixelFormat;
bool m_hasBanner; bool m_hasBanner;
@ -375,6 +420,9 @@ protected:
ref<ImageBlock> m_storage; ref<ImageBlock> m_storage;
ETonemapMethod m_tonemapMethod; ETonemapMethod m_tonemapMethod;
Float m_exposure, m_reinhardKey, m_reinhardBurn; Float m_exposure, m_reinhardKey, m_reinhardBurn;
std::vector<Annotation> m_annotations;
std::map<std::string, std::string> m_tags;
}; };
MTS_IMPLEMENT_CLASS_S(LDRFilm, false, Film) MTS_IMPLEMENT_CLASS_S(LDRFilm, false, Film)

View File

@ -432,7 +432,7 @@ public:
bool develop(const Point2i &sourceOffset, const Vector2i &size, bool develop(const Point2i &sourceOffset, const Vector2i &size,
const Point2i &targetOffset, Bitmap *target) const { const Point2i &targetOffset, Bitmap *target) const {
target->fill(targetOffset, size, Spectrum(0.0f)); target->fillRect(targetOffset, size, Spectrum(0.0f));
return false; /* Not supported by the tiled EXR film! */ return false; /* Not supported by the tiled EXR film! */
} }

View File

@ -130,8 +130,7 @@ public:
if (phaseVal != 0) { if (phaseVal != 0) {
/* Calculate prob. of having sampled that direction using /* Calculate prob. of having sampled that direction using
phase function sampling */ phase function sampling */
Float phasePdf = (emitter->isOnSurface() && dRec.measure == ESolidAngle Float phasePdf = (emitter->isOnSurface() && dRec.measure == ESolidAngle)
&& interactions == 0)
? phase->pdf(pRec) : (Float) 0.0f; ? phase->pdf(pRec) : (Float) 0.0f;
/* Weight using the power heuristic */ /* Weight using the power heuristic */

View File

@ -430,47 +430,59 @@ void Bitmap::flipVertically() {
} }
} }
void Bitmap::accumulate(const Bitmap *bitmap, const Point2i &offset) {
void Bitmap::accumulate(const Bitmap *bitmap, Point2i sourceOffset,
Point2i targetOffset, Vector2i size) {
Assert(getPixelFormat() == bitmap->getPixelFormat() && Assert(getPixelFormat() == bitmap->getPixelFormat() &&
getComponentFormat() == bitmap->getComponentFormat() && getComponentFormat() == bitmap->getComponentFormat() &&
getChannelCount() == bitmap->getChannelCount()); getChannelCount() == bitmap->getChannelCount());
const int Vector2i offsetIncrease(
offsetX = std::max(offset.x, 0), std::max(0, std::max(-sourceOffset.x, -targetOffset.x)),
offsetY = std::max(offset.y, 0), std::max(0, std::max(-sourceOffset.y, -targetOffset.y))
endX = std::min(offset.x + bitmap->getSize().x, m_size.x), );
endY = std::min(offset.y + bitmap->getSize().y, m_size.y);
if (offsetX >= endX || offsetY >= endY) sourceOffset += offsetIncrease;
targetOffset += offsetIncrease;
size -= offsetIncrease;
Vector2i sizeDecrease(
std::max(0, std::max(sourceOffset.x + size.x - bitmap->getWidth(), targetOffset.x + size.x - getWidth())),
std::max(0, std::max(sourceOffset.y + size.y - bitmap->getHeight(), targetOffset.y + size.y - getHeight())));
size -= sizeDecrease;
if (size.x <= 0 || size.y <= 0)
return; return;
const size_t const size_t
columns = (endX - offsetX) * m_channelCount, columns = size.x * m_channelCount,
pixelStride = getBytesPerPixel(), pixelStride = getBytesPerPixel(),
sourceStride = bitmap->getSize().x * pixelStride, sourceStride = bitmap->getWidth() * pixelStride,
targetStride = m_size.x * pixelStride; targetStride = getWidth() * pixelStride;
const uint8_t *source = bitmap->getUInt8Data() + const uint8_t *source = bitmap->getUInt8Data() +
(offsetX - offset.x + (offsetY - offset.y) * bitmap->getSize().x) * pixelStride; (sourceOffset.x + sourceOffset.y * (size_t) bitmap->getWidth()) * pixelStride;
uint8_t *target = m_data + uint8_t *target = m_data +
(offsetX + offsetY * m_size.x) * pixelStride; (targetOffset.x + targetOffset.y * (size_t) m_size.x) * pixelStride;
for (int y = offsetY; y < endY; ++y) { for (int y = 0; y < size.y; ++y) {
switch (m_componentFormat) { switch (m_componentFormat) {
case EUInt8: case EUInt8:
for (size_t i = 0; i < columns; ++i) for (size_t i = 0; i < columns; ++i)
((uint8_t *) target)[i] += ((uint8_t *) source)[i]; ((uint8_t *) target)[i] = (uint8_t) std::min(0xFF, ((uint8_t *) source)[i] + ((uint8_t *) target)[i]);
break; break;
case EUInt16: case EUInt16:
for (size_t i = 0; i < columns; ++i) for (size_t i = 0; i < columns; ++i)
((uint16_t *) target)[i] += ((uint16_t *) source)[i]; ((uint16_t *) target)[i] = (uint16_t) std::min(0xFFFF, ((uint16_t *) source)[i] + ((uint16_t *) target)[i]);
break; break;
case EUInt32: case EUInt32:
for (size_t i = 0; i < columns; ++i) for (size_t i = 0; i < columns; ++i)
((uint32_t *) target)[i] += ((uint32_t *) source)[i]; ((uint32_t *) target)[i] = std::min((uint32_t) 0xFFFFFFFFUL, ((uint32_t *) source)[i] + ((uint32_t *) target)[i]);
break; break;
case EFloat16: case EFloat16:
@ -554,8 +566,9 @@ void Bitmap::setPixel(const Point2i &pos, const Spectrum &value) {
} }
void Bitmap::drawHLine(int y, int x1, int x2, const Spectrum &value) { void Bitmap::drawHLine(int y, int x1, int x2, const Spectrum &value) {
AssertEx( y >= 0 && y < m_size.y && if (y < 0 || y >= m_size.y)
x1 >= 0 && x2 < m_size.x, "Bitmap::drawVLine(): out of bounds!"); return;
x1 = std::max(x1, 0); x2 = std::min(x2, m_size.x-1);
const FormatConverter *cvt = FormatConverter::getInstance( const FormatConverter *cvt = FormatConverter::getInstance(
std::make_pair(EFloat, m_componentFormat) std::make_pair(EFloat, m_componentFormat)
@ -574,8 +587,9 @@ void Bitmap::drawHLine(int y, int x1, int x2, const Spectrum &value) {
} }
void Bitmap::drawVLine(int x, int y1, int y2, const Spectrum &value) { void Bitmap::drawVLine(int x, int y1, int y2, const Spectrum &value) {
AssertEx( x >= 0 && x < m_size.x && if (x < 0 || x >= m_size.x)
y1 >= 0 && y2 < m_size.y, "Bitmap::drawVLine(): out of bounds!"); return;
y1 = std::max(y1, 0); y2 = std::min(y2, m_size.y-1);
const FormatConverter *cvt = FormatConverter::getInstance( const FormatConverter *cvt = FormatConverter::getInstance(
std::make_pair(EFloat, m_componentFormat) std::make_pair(EFloat, m_componentFormat)
@ -601,9 +615,12 @@ void Bitmap::drawRect(const Point2i &offset, const Vector2i &size, const Spectru
drawVLine(offset.x + size.x - 1, offset.y, offset.y + size.y - 1, value); drawVLine(offset.x + size.x - 1, offset.y, offset.y + size.y - 1, value);
} }
void Bitmap::fill(const Point2i &offset, const Vector2i &size, const Spectrum &value) { void Bitmap::fillRect(Point2i offset, Vector2i size, const Spectrum &value) {
AssertEx(offset.x >= 0 && offset.x + size.x <= m_size.x && int sx = std::max(0, -offset.x), sy = std::max(0, -offset.y);
offset.y >= 0 && offset.y + size.y <= m_size.y, "Bitmap::fill(): out of bounds!"); size.x -= sx; size.y -= sy; offset.x += sx; offset.y += sy;
size.x -= std::max(0, offset.x + size.x - m_size.x);
size.y -= std::max(0, offset.y + size.y - m_size.y);
const FormatConverter *cvt = FormatConverter::getInstance( const FormatConverter *cvt = FormatConverter::getInstance(
std::make_pair(EFloat, m_componentFormat) std::make_pair(EFloat, m_componentFormat)
@ -995,6 +1012,79 @@ ref<Bitmap> Bitmap::crop(const Point2i &offset, const Vector2i &size) const {
return result; return result;
} }
void Bitmap::applyMatrix(Float matrix_[3][3]) {
int stride = 0;
if (m_pixelFormat == ERGB || m_pixelFormat == EXYZ)
stride = 3;
else if (m_pixelFormat == ERGBA || m_pixelFormat == EXYZA)
stride = 4;
else
Log(EError, "Bitmap::applyMatrix(): unsupported pixel format!");
size_t pixels = (size_t) m_size.x * (size_t) m_size.y;
switch (m_componentFormat) {
case EFloat16: {
float matrix[3][3];
half *data = getFloat16Data();
for (int i=0; i<3; ++i)
for (int j=0; j<3; ++j)
matrix[i][j] = (float) matrix_[i][j];
for (size_t i=0; i<pixels; ++i) {
float result[3] = { 0.0f, 0.0f, 0.0f };
for (int i=0; i<3; ++i)
for (int j=0; j<3; ++j)
result[i] += matrix[i][j] * (float) data[j];
for (int i=0; i<3; ++i)
data[i] = (half) result[i];
data += stride;
}
}
break;
case EFloat32: {
float matrix[3][3], *data = getFloat32Data();
for (int i=0; i<3; ++i)
for (int j=0; j<3; ++j)
matrix[i][j] = (float) matrix_[i][j];
for (size_t i=0; i<pixels; ++i) {
float result[3] = { 0.0f, 0.0f, 0.0f };
for (int i=0; i<3; ++i)
for (int j=0; j<3; ++j)
result[i] += matrix[i][j] * data[j];
for (int i=0; i<3; ++i)
data[i] = result[i];
data += stride;
}
}
break;
case EFloat64: {
double matrix[3][3], *data = getFloat64Data();
for (int i=0; i<3; ++i)
for (int j=0; j<3; ++j)
matrix[i][j] = (double) matrix_[i][j];
for (size_t i=0; i<pixels; ++i) {
double result[3] = { 0.0, 0.0, 0.0 };
for (int i=0; i<3; ++i)
for (int j=0; j<3; ++j)
result[i] += matrix[i][j] * data[j];
for (int i=0; i<3; ++i)
data[i] = result[i];
data += stride;
}
}
break;
default:
Log(EError, "Bitmap::applyMatrix(): unsupported component format!");
}
}
/// Bitmap resampling utility function /// Bitmap resampling utility function
template <typename Scalar> static void resample(const ReconstructionFilter *rfilter, template <typename Scalar> static void resample(const ReconstructionFilter *rfilter,
ReconstructionFilter::EBoundaryCondition bch, ReconstructionFilter::EBoundaryCondition bch,

View File

@ -78,9 +78,9 @@ void Class::initializeOnce(Class *theClass) {
} }
void Class::staticInitialization() { void Class::staticInitialization() {
std::for_each(__classes->begin(), __classes->end(), for (ClassMap::iterator it = __classes->begin();
compose1(std::ptr_fun(initializeOnce), it != __classes->end(); ++it)
select2nd<ClassMap::value_type>())); initializeOnce(it->second);
m_isInitialized = true; m_isInitialized = true;
} }

View File

@ -586,18 +586,84 @@ Float fresnelDielectricExt(Float cosThetaI_, Float &cosThetaT_, Float eta) {
return 0.5f * (Rs * Rs + Rp * Rp); return 0.5f * (Rs * Rs + Rp * Rp);
} }
Spectrum fresnelConductor(Float cosThetaI, const Spectrum &eta, const Spectrum &k) { Float fresnelConductorApprox(Float cosThetaI, Float eta, Float k) {
Spectrum tmp = (eta*eta + k*k) * (cosThetaI * cosThetaI); Float cosThetaI2 = cosThetaI*cosThetaI;
Spectrum rParl2 = (tmp - (eta * (2.0f * cosThetaI)) + Spectrum(1.0f)) Float tmp = (eta*eta + k*k) * cosThetaI2;
/ (tmp + (eta * (2.0f * cosThetaI)) + Spectrum(1.0f));
Float Rp2 = (tmp - (eta * (2 * cosThetaI)) + 1)
/ (tmp + (eta * (2 * cosThetaI)) + 1);
Float tmpF = eta*eta + k*k;
Float Rs2 = (tmpF - (eta * (2 * cosThetaI)) + cosThetaI2) /
(tmpF + (eta * (2 * cosThetaI)) + cosThetaI2);
return 0.5f * (Rp2 + Rs2);
}
Spectrum fresnelConductorApprox(Float cosThetaI, const Spectrum &eta, const Spectrum &k) {
Float cosThetaI2 = cosThetaI*cosThetaI;
Spectrum tmp = (eta*eta + k*k) * cosThetaI2;
Spectrum Rp2 = (tmp - (eta * (2 * cosThetaI)) + Spectrum(1.0f))
/ (tmp + (eta * (2 * cosThetaI)) + Spectrum(1.0f));
Spectrum tmpF = eta*eta + k*k; Spectrum tmpF = eta*eta + k*k;
Spectrum rPerp2 = (tmpF - (eta * (2.0f * cosThetaI)) + Spectrum(cosThetaI*cosThetaI)) / Spectrum Rs2 = (tmpF - (eta * (2 * cosThetaI)) + Spectrum(cosThetaI2)) /
(tmpF + (eta * (2.0f * cosThetaI)) + Spectrum(cosThetaI*cosThetaI)); (tmpF + (eta * (2 * cosThetaI)) + Spectrum(cosThetaI2));
return (rParl2 + rPerp2) / 2.0f; return 0.5f * (Rp2 + Rs2);
}
Float fresnelConductorExact(Float cosThetaI, Float eta, Float k) {
/* Modified from "Optics" by K.D. Moeller, University Science Books, 1988 */
Float cosThetaI2 = cosThetaI*cosThetaI,
sinThetaI2 = 1-cosThetaI2,
sinThetaI4 = sinThetaI2*sinThetaI2;
Float temp1 = eta*eta - k*k - sinThetaI2,
a2pb2 = math::safe_sqrt(temp1*temp1 + 4*k*k*eta*eta),
a = math::safe_sqrt(0.5f * (a2pb2 + temp1));
Float term1 = a2pb2 + cosThetaI2,
term2 = 2*a*cosThetaI;
Float Rs2 = (term1 - term2) / (term1 + term2);
Float term3 = a2pb2*cosThetaI2 + sinThetaI4,
term4 = term2*sinThetaI2;
Float Rp2 = Rs2 * (term3 - term4) / (term3 + term4);
return 0.5f * (Rp2 + Rs2);
}
Spectrum fresnelConductorExact(Float cosThetaI, const Spectrum &eta, const Spectrum &k) {
/* Modified from "Optics" by K.D. Moeller, University Science Books, 1988 */
Float cosThetaI2 = cosThetaI*cosThetaI,
sinThetaI2 = 1-cosThetaI2,
sinThetaI4 = sinThetaI2*sinThetaI2;
Spectrum temp1 = eta*eta - k*k - Spectrum(sinThetaI2),
a2pb2 = (temp1*temp1 + k*k*eta*eta*4).safe_sqrt(),
a = ((a2pb2 + temp1) * 0.5f).safe_sqrt();
Spectrum term1 = a2pb2 + Spectrum(cosThetaI2),
term2 = a*(2*cosThetaI);
Spectrum Rs2 = (term1 - term2) / (term1 + term2);
Spectrum term3 = a2pb2*cosThetaI2 + Spectrum(sinThetaI4),
term4 = term2*sinThetaI2;
Spectrum Rp2 = Rs2 * (term3 - term4) / (term3 + term4);
return 0.5f * (Rp2 + Rs2);
} }
Vector reflect(const Vector &wi, const Normal &n) { Vector reflect(const Vector &wi, const Normal &n) {

View File

@ -74,6 +74,70 @@ Font::Font(EFont font) {
dscStream->read(m_kerningMatrix, 256*256); dscStream->read(m_kerningMatrix, 256*256);
} }
void Font::convert(Bitmap::EPixelFormat pixelFormat, Bitmap::EComponentFormat componentFormat, Float gamma) {
m_bitmap = m_bitmap->convert(pixelFormat, componentFormat, gamma);
}
void Font::drawText(Bitmap *dest, Point2i pos, const std::string &text) const {
int initial = pos.x;
for (size_t i=0; i<text.length(); i++) {
char character = text[i];
if (character == '\r')
continue;
if (character == '\n') {
pos.x = initial;
pos.y += (int) (getMaxVerticalBearing()*4.0/3.0);
continue;
}
const Font::Glyph &glyph = getGlyph(character);
Point2i targetOffset = pos + Vector2i(
glyph.horizontalBearing,
getMaxVerticalBearing() - glyph.verticalBearing - 1
);
Point2i sourceOffset(
glyph.tx.x * m_bitmap->getWidth(),
glyph.tx.y * m_bitmap->getHeight());
dest->accumulate(m_bitmap.get(), sourceOffset, targetOffset, glyph.size);
pos.x += glyph.horizontalAdvance;
if (i+1 < text.length())
pos.x += getKerning(character, text[i+1]);
}
}
Vector2i Font::getSize(const std::string &text) const {
Vector2i size(0, getMaxVerticalBearing());
int pos = 0;
for (size_t i=0; i<text.length(); i++) {
char character = text[i];
if (character == '\r')
continue;
if (character == '\n') {
size.y += getMaxVerticalBearing()*(4.0 / 3.0);
size.x = std::max(size.x, pos);
pos = 0;
continue;
}
const Font::Glyph &glyph = getGlyph(character);
pos += glyph.horizontalAdvance;
if (i+1 < text.length())
pos += getKerning(character, text[i+1]);
}
size.x = std::max(size.x, pos);
return size;
}
void Font::init(Renderer *renderer) { void Font::init(Renderer *renderer) {
m_texture = renderer->createGPUTexture(m_name, m_bitmap); m_texture = renderer->createGPUTexture(m_name, m_bitmap);
m_texture->setFilterType(GPUTexture::ENearest); m_texture->setFilterType(GPUTexture::ENearest);

View File

@ -79,10 +79,10 @@ void initializeFramework() {
if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) &initializeFramework, &hm)) { GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCSTR) &initializeFramework, &hm)) {
std::vector<WCHAR> lpFilename(MAX_PATH); std::vector<WCHAR> lpFilename(MAX_PATH);
// Try to get the path with the default MAX_PATH length (260 chars) // Try to get the path with the default MAX_PATH length (260 chars)
DWORD nSize = GetModuleFileNameW(hm, &lpFilename[0], MAX_PATH); DWORD nSize = GetModuleFileNameW(hm, &lpFilename[0], MAX_PATH);
// Adjust the buffer size in case if was too short // Adjust the buffer size in case if was too short
while (nSize == lpFilename.size()) { while (nSize == lpFilename.size()) {
lpFilename.resize(nSize * 2); lpFilename.resize(nSize * 2);
@ -175,7 +175,7 @@ public:
bp::extract<Transform> extractTransform(value); bp::extract<Transform> extractTransform(value);
bp::extract<Spectrum> extractSpectrum(value); bp::extract<Spectrum> extractSpectrum(value);
if (extractString.check()) { if (extractString.check()){
props.setString(name, extractString()); props.setString(name, extractString());
} else if (extractBoolean.check() && PyObject_IsInstance(value.ptr(), (PyObject *) &PyBool_Type)) { } else if (extractBoolean.check() && PyObject_IsInstance(value.ptr(), (PyObject *) &PyBool_Type)) {
props.setBoolean(name, extractBoolean()); props.setBoolean(name, extractBoolean());
@ -205,6 +205,12 @@ struct path_to_python_str {
}; };
struct TSpectrum_to_Spectrum {
static PyObject* convert(const TSpectrum<Float, 3> &spectrum) {
return bp::incref(bp::object(Spectrum(spectrum)).ptr());
}
};
static void Matrix4x4_setItem(Matrix4x4 *matrix, bp::tuple tuple, Float value) { static void Matrix4x4_setItem(Matrix4x4 *matrix, bp::tuple tuple, Float value) {
if (bp::len(tuple) != 2) if (bp::len(tuple) != 2)
SLog(EError, "Invalid matrix indexing operation, required a tuple of length 2"); SLog(EError, "Invalid matrix indexing operation, required a tuple of length 2");
@ -472,6 +478,43 @@ Vector refract3(const Vector &wi, const Normal &n, Float eta) {
return refract(wi, n, eta); return refract(wi, n, eta);
} }
void bitmap_applyMatrix(Bitmap *bitmap, bp::list list) {
int length = bp::len(list);
if (length != 9)
SLog(EError, "Require a color matrix specified as a list with 9 entries!");
Float matrix[3][3];
int idx = 0;
for (int i=0; i<3; ++i)
for (int j=0; j<3; ++j)
matrix[i][j] = bp::extract<Float>(list[idx++]);
bitmap->applyMatrix(matrix);
}
void bitmap_write(Bitmap *bitmap, Bitmap::EFileFormat fmt, Stream *stream) {
bitmap->write(fmt, stream);
}
ref<Bitmap> bitmap_convert_1(Bitmap *bitmap, Bitmap::EPixelFormat pixelFormat, Bitmap::EComponentFormat componentFormat,
Float gamma, Float multiplier, Spectrum::EConversionIntent intent) {
return bitmap->convert(pixelFormat, componentFormat, gamma, multiplier, intent);
}
ref<Bitmap> bitmap_convert_2(Bitmap *bitmap, Bitmap::EPixelFormat pixelFormat, Bitmap::EComponentFormat componentFormat,
Float gamma, Float multiplier) {
return bitmap->convert(pixelFormat, componentFormat, gamma, multiplier);
}
ref<Bitmap> bitmap_convert_3(Bitmap *bitmap, Bitmap::EPixelFormat pixelFormat, Bitmap::EComponentFormat componentFormat,
Float gamma) {
return bitmap->convert(pixelFormat, componentFormat, gamma);
}
ref<Bitmap> bitmap_convert_4(Bitmap *bitmap, Bitmap::EPixelFormat pixelFormat, Bitmap::EComponentFormat componentFormat) {
return bitmap->convert(pixelFormat, componentFormat);
}
Transform transform_glOrthographic1(Float clipNear, Float clipFar) { Transform transform_glOrthographic1(Float clipNear, Float clipFar) {
return Transform::glOrthographic(clipNear, clipFar); return Transform::glOrthographic(clipNear, clipFar);
@ -489,6 +532,7 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(fromXYZ_overloads, fromXYZ, 3, 4)
void export_core() { void export_core() {
bp::to_python_converter<fs::path, path_to_python_str>(); bp::to_python_converter<fs::path, path_to_python_str>();
bp::to_python_converter<TSpectrum<Float, 3>, TSpectrum_to_Spectrum>();
bp::implicitly_convertible<std::string, fs::path>(); bp::implicitly_convertible<std::string, fs::path>();
bp::object coreModule( bp::object coreModule(
@ -708,17 +752,23 @@ void export_core() {
.def("clear", &InterpolatedSpectrum::clear) .def("clear", &InterpolatedSpectrum::clear)
.def("zeroExtend", &InterpolatedSpectrum::zeroExtend); .def("zeroExtend", &InterpolatedSpectrum::zeroExtend);
void (Bitmap::*accumulate_1)(const Bitmap *bitmap, Point2i sourceOffset, Point2i targetOffset, Vector2i size) = &Bitmap::accumulate;
void (Bitmap::*accumulate_2)(const Bitmap *bitmap, Point2i targetOffset) = &Bitmap::accumulate;
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("clone", &Bitmap::clone, BP_RETURN_VALUE) .def("clone", &Bitmap::clone, BP_RETURN_VALUE)
.def("clear", &Bitmap::clear)
.def("separateChannel", &Bitmap::separateChannel, BP_RETURN_VALUE) .def("separateChannel", &Bitmap::separateChannel, BP_RETURN_VALUE)
.def("expand", &Bitmap::expand, BP_RETURN_VALUE) .def("expand", &Bitmap::expand, BP_RETURN_VALUE)
.def("flipVertically", &Bitmap::flipVertically) .def("flipVertically", &Bitmap::flipVertically)
.def("crop", &Bitmap::crop) .def("crop", &Bitmap::crop)
.def("accumulate", &Bitmap::accumulate) .def("applyMatrix", &bitmap_applyMatrix)
.def("clear", &Bitmap::clear) .def("colorBalance", &Bitmap::colorBalance)
.def("write", &Bitmap::write) .def("accumulate", accumulate_1)
.def("accumulate", accumulate_2)
.def("write", &bitmap_write)
.def("setString", &Bitmap::setString) .def("setString", &Bitmap::setString)
.def("getString", &Bitmap::getString, BP_RETURN_VALUE) .def("getString", &Bitmap::getString, BP_RETURN_VALUE)
.def("setGamma", &Bitmap::setGamma) .def("setGamma", &Bitmap::setGamma)
@ -732,9 +782,18 @@ void export_core() {
.def("getBitsPerComponent", &Bitmap::getBitsPerComponent) .def("getBitsPerComponent", &Bitmap::getBitsPerComponent)
.def("getBytesPerComponent", &Bitmap::getBytesPerComponent) .def("getBytesPerComponent", &Bitmap::getBytesPerComponent)
.def("getBytesPerPixel", &Bitmap::getBytesPerPixel) .def("getBytesPerPixel", &Bitmap::getBytesPerPixel)
.def("getBufferSize", &Bitmap::getBufferSize)
.def("getPixel", &Bitmap::getPixel, BP_RETURN_VALUE) .def("getPixel", &Bitmap::getPixel, BP_RETURN_VALUE)
.def("setPixel", &Bitmap::setPixel) .def("setPixel", &Bitmap::setPixel)
.def("getSize", &Bitmap::getSize, BP_RETURN_VALUE); .def("drawHLine", &Bitmap::drawHLine)
.def("drawVLine", &Bitmap::drawVLine)
.def("drawRect", &Bitmap::drawRect)
.def("fillRect", &Bitmap::fillRect)
.def("getSize", &Bitmap::getSize, BP_RETURN_VALUE)
.def("convert", &bitmap_convert_1, BP_RETURN_VALUE)
.def("convert", &bitmap_convert_2, BP_RETURN_VALUE)
.def("convert", &bitmap_convert_3, BP_RETURN_VALUE)
.def("convert", &bitmap_convert_4, BP_RETURN_VALUE);
BP_SETSCOPE(Bitmap_class); BP_SETSCOPE(Bitmap_class);
bp::enum_<Bitmap::EPixelFormat>("EPixelFormat") bp::enum_<Bitmap::EPixelFormat>("EPixelFormat")
@ -745,7 +804,8 @@ void export_core() {
.value("ESpectrum", Bitmap::ESpectrum) .value("ESpectrum", Bitmap::ESpectrum)
.value("ESpectrumAlpha", Bitmap::ESpectrumAlpha) .value("ESpectrumAlpha", Bitmap::ESpectrumAlpha)
.value("ESpectrumAlphaWeight", Bitmap::ESpectrumAlphaWeight) .value("ESpectrumAlphaWeight", Bitmap::ESpectrumAlphaWeight)
.value("EMultiChannel", Bitmap::EMultiChannel); .value("EMultiChannel", Bitmap::EMultiChannel)
.export_values();
bp::enum_<Bitmap::EComponentFormat>("EComponentFormat") bp::enum_<Bitmap::EComponentFormat>("EComponentFormat")
.value("EBitmask", Bitmap::EBitmask) .value("EBitmask", Bitmap::EBitmask)
@ -763,10 +823,13 @@ void export_core() {
.value("EPNG", Bitmap::EPNG) .value("EPNG", Bitmap::EPNG)
.value("EOpenEXR", Bitmap::EOpenEXR) .value("EOpenEXR", Bitmap::EOpenEXR)
.value("ETGA", Bitmap::ETGA) .value("ETGA", Bitmap::ETGA)
.value("EPFM", Bitmap::EPFM)
.value("ERGBE", Bitmap::ERGBE)
.value("EBMP", Bitmap::EBMP) .value("EBMP", Bitmap::EBMP)
.value("EJPEG", Bitmap::EJPEG) .value("EJPEG", Bitmap::EJPEG)
.value("EAuto", Bitmap::EAuto) .value("EAuto", Bitmap::EAuto)
.export_values(); .export_values();
BP_SETSCOPE(coreModule); BP_SETSCOPE(coreModule);
BP_CLASS(FileResolver, Object, bp::init<>()) BP_CLASS(FileResolver, Object, bp::init<>())
@ -1261,11 +1324,19 @@ void export_core() {
.staticmethod("glOrthographic") .staticmethod("glOrthographic")
.staticmethod("fromFrame"); .staticmethod("fromFrame");
Float (*fresnelConductorApprox1)(Float, Float, Float) = &fresnelConductorApprox;
Float (*fresnelConductorExact1)(Float, Float, Float) = &fresnelConductorExact;
Spectrum (*fresnelConductorApprox2)(Float, const Spectrum &, const Spectrum &) = &fresnelConductorApprox;
Spectrum (*fresnelConductorExact2)(Float, const Spectrum &, const Spectrum &) = &fresnelConductorExact;
/* Functions from utility.h */ /* Functions from utility.h */
bp::def("fresnelDielectric", &fresnelDielectric); bp::def("fresnelDielectric", &fresnelDielectric);
bp::def("fresnelDielectricExt", &fresnelDielectricExt1); bp::def("fresnelDielectricExt", &fresnelDielectricExt1);
bp::def("fresnelDielectricExt", &fresnelDielectricExt2); bp::def("fresnelDielectricExt", &fresnelDielectricExt2);
bp::def("fresnelConductor", &fresnelConductor, BP_RETURN_VALUE); bp::def("fresnelConductorApprox", fresnelConductorApprox1, BP_RETURN_VALUE);
bp::def("fresnelConductorApprox", fresnelConductorApprox2, BP_RETURN_VALUE);
bp::def("fresnelConductorExact", fresnelConductorExact1, BP_RETURN_VALUE);
bp::def("fresnelConductorExact", fresnelConductorExact2, BP_RETURN_VALUE);
bp::def("fresnelDiffuseReflectance", &fresnelDiffuseReflectance); bp::def("fresnelDiffuseReflectance", &fresnelDiffuseReflectance);
bp::def("reflect", &reflect); bp::def("reflect", &reflect);
bp::def("refract", &refract1); bp::def("refract", &refract1);

View File

@ -47,6 +47,7 @@ Spectrum Texture::getMinimum() const { NotImplementedError("getMinimum"); }
Spectrum Texture::getMaximum() const { NotImplementedError("getMaximum"); } Spectrum Texture::getMaximum() const { NotImplementedError("getMaximum"); }
bool Texture::isConstant() const { NotImplementedError("isConstant"); } bool Texture::isConstant() const { NotImplementedError("isConstant"); }
bool Texture::usesRayDifferentials() const { NotImplementedError("usesRayDifferentials"); } bool Texture::usesRayDifferentials() const { NotImplementedError("usesRayDifferentials"); }
ref<Bitmap> Texture::getBitmap() const { return NULL; }
ref<Texture> Texture::expand() { ref<Texture> Texture::expand() {
return this; return this;

View File

@ -33,9 +33,8 @@ if hasQt:
del qtEnv['CXXFLAGS'][index-1] del qtEnv['CXXFLAGS'][index-1]
index = qtEnv['LINKFLAGS'].index('/SUBSYSTEM:CONSOLE') index = qtEnv['LINKFLAGS'].index('/SUBSYSTEM:CONSOLE')
del qtEnv['LINKFLAGS'][index] del qtEnv['LINKFLAGS'][index]
qtEnv.Append(CXXFLAGS=['/D', '_WINDOWS']) qtEnv.Append(CXXFLAGS=['/D', '_WINDOWS', '/D', 'MTS_CUSTOM_QTMAIN', '/D', 'MTSGUI_STATIC_QFILEDIALOG=1'])
qtEnv.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS']) qtEnv.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
qtEnv.Append(LIBS=['qtmain'])
if hasBreakpad: if hasBreakpad:
qtEnv.Append(CPPPATH=['#dependencies/include/breakpad']) qtEnv.Append(CPPPATH=['#dependencies/include/breakpad'])
qtEnv.Append(LIBS=['breakpad_common', 'breakpad_exception_handler', 'breakpad_crash_generation_client', qtEnv.Append(LIBS=['breakpad_common', 'breakpad_exception_handler', 'breakpad_crash_generation_client',
@ -72,6 +71,10 @@ if hasQt:
qtSources += qtEnv_osx.StaticObject('breakpad.mm') qtSources += qtEnv_osx.StaticObject('breakpad.mm')
else: else:
qtSources = [x for x in qtSources if (not isinstance(x, str) or 'cocoa' not in x)] qtSources = [x for x in qtSources if (not isinstance(x, str) or 'cocoa' not in x)]
if sys.platform == 'win32':
qtSources += qtEnv.StaticObject('qtmain_win.cpp')
mtsgui = qtEnv.Program('mtsgui', qtSources) mtsgui = qtEnv.Program('mtsgui', qtSources)
if sys.platform == 'darwin': if sys.platform == 'darwin':
qtEnv.AddPostAction(mtsgui, 'install_name_tool -change QtGui.framework/Versions/4/QtGui @rpath/QtGui $TARGET') qtEnv.AddPostAction(mtsgui, 'install_name_tool -change QtGui.framework/Versions/4/QtGui @rpath/QtGui $TARGET')

View File

@ -558,6 +558,8 @@ void MainWindow::on_actionOpen_triggered() {
} }
} }
void MainWindow::onOpenDialogClose(int reason) { /* unused */ }
#else // MTSGUI_STATIC_QFILEDIALOG #else // MTSGUI_STATIC_QFILEDIALOG
void MainWindow::on_actionOpen_triggered() { void MainWindow::on_actionOpen_triggered() {
@ -1447,6 +1449,8 @@ void MainWindow::on_actionExportImage_triggered() {
} }
} }
void MainWindow::onExportDialogClose(int reason) { /* unused */ }
#else // MTSGUI_STATIC_QFILEDIALOG #else // MTSGUI_STATIC_QFILEDIALOG
void MainWindow::on_actionExportImage_triggered() { void MainWindow::on_actionExportImage_triggered() {
@ -1563,6 +1567,8 @@ void MainWindow::on_actionSaveAs_triggered() {
} }
} }
void MainWindow::onSaveAsDialogClose(int reason) { /* unused */ }
#else // MTSGUI_STATIC_QFILEDIALOG #else // MTSGUI_STATIC_QFILEDIALOG
void MainWindow::on_actionSaveAs_triggered() { void MainWindow::on_actionSaveAs_triggered() {

View File

@ -192,11 +192,9 @@ private slots:
void updateUI(); void updateUI();
void updateStatus(); void updateStatus();
void onPreviewSettingsClose(); void onPreviewSettingsClose();
#if !MTSGUI_STATIC_QFILEDIALOG
void onOpenDialogClose(int reason); void onOpenDialogClose(int reason);
void onExportDialogClose(int reason); void onExportDialogClose(int reason);
void onSaveAsDialogClose(int reason); void onSaveAsDialogClose(int reason);
#endif
void onRenderSettingsClose(int reason); void onRenderSettingsClose(int reason);
void onImportDialogClose(int reason); void onImportDialogClose(int reason);
void onSceneInformationClose(int reason); void onSceneInformationClose(int reason);

View File

@ -44,12 +44,12 @@
# error This source file can only be used in Windows builds # error This source file can only be used in Windows builds
#endif #endif
#include <QVector> #include <QtCore/QVector>
#include <QByteArray> #include <QtCore/QByteArray>
#include <QString> #include <QtCore/QString>
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <windows.h>
/* /*
This file contains the code in the qtmain library for Windows. This file contains the code in the qtmain library for Windows.

View File

@ -208,9 +208,9 @@ static int irrOctreeIndex = 0;
* rendered using diffusion theory and radiative transport, respectively. * rendered using diffusion theory and radiative transport, respectively.
* The former produces an incorrect result, since the assumption of * The former produces an incorrect result, since the assumption of
* many scattering events breaks down. * many scattering events breaks down.
* \textbf{(c)}: When the number of irradiance samples is too low, the * \textbf{(c)}: When the number of irradiance samples is too low when rendering
* resulting noise becomes visible as ``blotchy'' artifacts in the * with the dipole model, the resulting noise becomes visible as ``blotchy'' artifacts
* rendering.} * in the rendering.}
* } * }
* *
* \subsubsection*{Typical material setup} * \subsubsection*{Typical material setup}

View File

@ -400,6 +400,10 @@ public:
return result; return result;
} }
ref<Bitmap> getBitmap() const {
return m_mipmap1.get() ? m_mipmap1->toBitmap() : m_mipmap3->toBitmap();
}
Spectrum eval(const Point2 &uv, const Vector2 &d0, const Vector2 &d1) const { Spectrum eval(const Point2 &uv, const Vector2 &d0, const Vector2 &d1) const {
stats::filteredLookups.incrementBase(); stats::filteredLookups.incrementBase();
++stats::filteredLookups; ++stats::filteredLookups;

View File

@ -93,7 +93,7 @@ MTS_NAMESPACE_BEGIN
* *
* When using this data source to represent floating point density volumes, * When using this data source to represent floating point density volumes,
* please ensure that the values are all normalized to lie in the * please ensure that the values are all normalized to lie in the
* range $[0, 1]$---otherwise, the Woocock-Tracking integration method in * range $[0, 1]$---otherwise, the Woodcock-Tracking integration method in
* \pluginref{heterogeneous} will produce incorrect results. * \pluginref{heterogeneous} will produce incorrect results.
*/ */
class GridDataSource : public VolumeDataSource { class GridDataSource : public VolumeDataSource {