From 43223d78d385ed592e0f4eb35af700794237e9a2 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Sat, 23 Nov 2013 14:46:35 +0100 Subject: [PATCH] Python plugin improvements, cleanups --- include/mitsuba/core/fwd.h | 3 + include/mitsuba/core/mstream.h | 3 + include/mitsuba/core/qmc.h | 44 ++- include/mitsuba/core/quad.h | 3 + include/mitsuba/core/sched_remote.h | 38 +- include/mitsuba/core/shvector.h | 147 ++++++-- src/libbidir/util.cpp | 2 + src/libcore/shvector.cpp | 31 +- src/libpython/SConscript | 9 +- src/libpython/core.cpp | 547 ++++++++++++++++++++++++---- src/libpython/render.cpp | 72 ++-- 11 files changed, 711 insertions(+), 188 deletions(-) diff --git a/include/mitsuba/core/fwd.h b/include/mitsuba/core/fwd.h index 8e7b8d16..a69c82d7 100644 --- a/include/mitsuba/core/fwd.h +++ b/include/mitsuba/core/fwd.h @@ -46,6 +46,8 @@ class InterpolatedSpectrum; class LocalWorker; class Logger; template struct Matrix; +struct Matrix2x2; +struct Matrix3x3; struct Matrix4x4; class MemoryStream; class MemoryMappedFile; @@ -144,6 +146,7 @@ typedef TPoint4 Point4i; typedef TPoint4 Point4u; typedef TPoint4 Point4f; typedef TPoint4 Point4d; +/// \ingroup libpython typedef TQuaternion Quaternion; typedef TVector2 Size2; typedef TVector3 Size3; diff --git a/include/mitsuba/core/mstream.h b/include/mitsuba/core/mstream.h index 947b403c..5439c1a4 100644 --- a/include/mitsuba/core/mstream.h +++ b/include/mitsuba/core/mstream.h @@ -30,6 +30,7 @@ MTS_NAMESPACE_BEGIN * as data is written to the stream. * * \ingroup libcore + * \ingroup libpython */ class MTS_EXPORT_CORE MemoryStream : public Stream { public: @@ -47,6 +48,8 @@ public: * A memory stream created in this way will never resize the * underlying buffer. An exception is thrown e.g. when attempting * to extend its size + * + * \remark This constructor is not available in the python bindings */ MemoryStream(void *ptr, size_t size); diff --git a/include/mitsuba/core/qmc.h b/include/mitsuba/core/qmc.h index 2df77ca4..940667af 100644 --- a/include/mitsuba/core/qmc.h +++ b/include/mitsuba/core/qmc.h @@ -24,8 +24,10 @@ MTS_NAMESPACE_BEGIN -/*! \addtogroup libcore */ -/*! @{ */ +/** \addtogroup libcore + * \addtogroup libpython + * @{ + */ // ----------------------------------------------------------------------- //! @{ \name Elementary Quasi-Monte Carlo number sequences @@ -154,6 +156,23 @@ inline uint64_t sampleTEA(uint32_t v0, uint32_t v1, int rounds = 4) { } #if defined(DOUBLE_PRECISION) +/** + * \brief Generate fast and reasonably good pseudorandom numbers using the + * Tiny Encryption Algorithm (TEA) by David Wheeler and Roger Needham. + * + * This function uses \ref sampleTEA to return single precision floating point + * numbers on the interval [0, 1) + * + * \param v0 + * First input value to be encrypted (could be the sample index) + * \param v1 + * Second input value to be encrypted (e.g. the requested random number dimension) + * \param rounds + * How many rounds should be executed? The default for random number + * generation is 4. + * \return + * A uniformly distributed floating point number on the interval [0, 1) + */ inline Float sampleTEAFloat(uint32_t v0, uint32_t v1, int rounds = 4) { /* Trick from MTGP: generate an uniformly distributed single precision number in [1,2) and subtract 1. */ @@ -166,6 +185,23 @@ inline Float sampleTEAFloat(uint32_t v0, uint32_t v1, int rounds = 4) { } #else +/** + * \brief Generate fast and reasonably good pseudorandom numbers using the + * Tiny Encryption Algorithm (TEA) by David Wheeler and Roger Needham. + * + * This function uses \ref sampleTEA to return single precision floating point + * numbers on the interval [0, 1) + * + * \param v0 + * First input value to be encrypted (could be the sample index) + * \param v1 + * Second input value to be encrypted (e.g. the requested random number dimension) + * \param rounds + * How many rounds should be executed? The default for random number + * generation is 4. + * \return + * A uniformly distributed floating point number on the interval [0, 1) + */ inline Float sampleTEAFloat(uint32_t v0, uint32_t v1, int rounds = 4) { /* Trick from MTGP: generate an uniformly distributed single precision number in [1,2) and subtract 1. */ @@ -196,6 +232,8 @@ extern MTS_EXPORT_CORE Float radicalInverse(int base, uint64_t index); * radical inverse function \ref radicalInverse(), except that every digit * is run through an extra scrambling permutation specified as array * of size \c base. + * + * \remark This function is not available in the Python API */ extern MTS_EXPORT_CORE Float scrambledRadicalInverse(int base, uint64_t index, uint16_t *perm); @@ -231,6 +269,8 @@ extern MTS_EXPORT_CORE Float radicalInverseFast(uint16_t baseIndex, uint64_t ind * Halton and Hammersley sequence variants. It works like the fast * radical inverse function \ref radicalInverseFast(), except that every * digit is run through an extra scrambling permutation. + * + * \remark This function is not available in the Python API */ extern MTS_EXPORT_CORE Float scrambledRadicalInverseFast(uint16_t baseIndex, uint64_t index, uint16_t *perm); diff --git a/include/mitsuba/core/quad.h b/include/mitsuba/core/quad.h index ea042717..671300e9 100644 --- a/include/mitsuba/core/quad.h +++ b/include/mitsuba/core/quad.h @@ -26,6 +26,8 @@ MTS_NAMESPACE_BEGIN // ----------------------------------------------------------------------- +//! \ingroup libcore +//! \ingroup libpython //! @{ \name Basic tools for non-adaptive quadrature // ----------------------------------------------------------------------- @@ -125,6 +127,7 @@ extern MTS_EXPORT_CORE void gaussLobatto(int n, Float *nodes, Float *weights); * analysts and developers - http://quantlib.org/ * * \ingroup libcore + * \ingroup libpython */ class MTS_EXPORT_CORE GaussLobattoIntegrator { public: diff --git a/include/mitsuba/core/sched_remote.h b/include/mitsuba/core/sched_remote.h index a42acac5..30e1cd98 100644 --- a/include/mitsuba/core/sched_remote.h +++ b/include/mitsuba/core/sched_remote.h @@ -196,25 +196,9 @@ private: */ class MTS_EXPORT_CORE StreamBackend : public Thread { friend class RemoteProcess; + friend class RemoteWorker; + friend class RemoteWorkerReader; public: - enum EMessage { - EUnknown = 0, - ENewProcess, - ENewResource, - ENewMultiResource, - EBindResource, - EWorkUnit, - EWorkResult, - ECancelledWorkResult, - EProcessTerminated, - EProcessCancelled, - EEnsurePluginLoaded, - EResourceExpired, - EQuit, - EIncompatible, - EHello = 0x1bcd - }; - /** * \brief Create a new stream backend * @@ -234,6 +218,24 @@ public: MTS_DECLARE_CLASS() protected: + enum EMessage { + EUnknown = 0, + ENewProcess, + ENewResource, + ENewMultiResource, + EBindResource, + EWorkUnit, + EWorkResult, + ECancelledWorkResult, + EProcessTerminated, + EProcessCancelled, + EEnsurePluginLoaded, + EResourceExpired, + EQuit, + EIncompatible, + EHello = 0x1bcd + }; + /// Virtual destructor virtual ~StreamBackend(); virtual void run(); diff --git a/include/mitsuba/core/shvector.h b/include/mitsuba/core/shvector.h index 615d9dc5..cf709fbc 100644 --- a/include/mitsuba/core/shvector.h +++ b/include/mitsuba/core/shvector.h @@ -22,16 +22,13 @@ #include #include -#include -#include +#include MTS_NAMESPACE_BEGIN /* Precompute normalization coefficients for the first 10 bands */ #define SH_NORMTBL_SIZE 10 -namespace ublas = boost::numeric::ublas; - struct SHVector; /** @@ -39,15 +36,18 @@ struct SHVector; * rotation matrix * * \ingroup libcore + * \ingroup libpython */ struct MTS_EXPORT_CORE SHRotation { - std::vector > blocks; + typedef Eigen::Matrix Matrix; + + std::vector blocks; /// Construct a new rotation storage for the given number of bands inline SHRotation(int bands) : blocks(bands) { for (int i=0; i(dim, dim); + blocks[i] = Matrix(dim, dim); } } @@ -79,6 +79,7 @@ struct MTS_EXPORT_CORE SHRotation { * \endcode * * \ingroup libcore + * \ingroup libpython */ struct MTS_EXPORT_CORE SHVector { public: @@ -126,51 +127,105 @@ public: /// Set all coefficients to zero inline void clear() { - for (size_t i=0; i m_coeffs.size()) - m_coeffs.resize(v.m_coeffs.size(), 0); - for (size_t i=0; i 0) { + m_coeffs.conservativeResize(v.m_coeffs.rows()); + m_coeffs.tail(extendBy).setZero(); + m_bands = v.m_bands; + } + m_coeffs.head(m_coeffs.size()) += v.m_coeffs.head(m_coeffs.size()); return *this; } + /// Component-wise addition + inline SHVector operator+(const SHVector &v) const { + SHVector vec(std::max(m_bands, v.m_bands)); + if (m_bands > v.m_bands) { + vec.m_coeffs = m_coeffs; + vec.m_coeffs.head(v.m_coeffs.size()) += v.m_coeffs; + } else { + vec.m_coeffs = v.m_coeffs; + vec.m_coeffs.head(m_coeffs.size()) += m_coeffs; + } + return vec; + } + /// Component-wise subtraction inline SHVector& operator-=(const SHVector &v) { - if (v.m_coeffs.size() > m_coeffs.size()) - m_coeffs.resize(v.m_coeffs.size(), 0); - for (size_t i=0; i 0) { + m_coeffs.conservativeResize(v.m_coeffs.rows()); + m_coeffs.tail(extendBy).setZero(); + m_bands = v.m_bands; + } + m_coeffs.head(m_coeffs.size()) -= v.m_coeffs.head(m_coeffs.size()); + return *this; + } + + /// Component-wise subtraction + inline SHVector operator-(const SHVector &v) const { + SHVector vec(std::max(m_bands, v.m_bands)); + if (m_bands > v.m_bands) { + vec.m_coeffs = m_coeffs; + vec.m_coeffs.head(v.m_coeffs.size()) -= v.m_coeffs; + } else { + vec.m_coeffs = -v.m_coeffs; + vec.m_coeffs.head(m_coeffs.size()) += m_coeffs; + } + return vec; + } + + /// Add a scalar multiple of another vector + inline SHVector& madd(Float f, const SHVector &v) { + ptrdiff_t extendBy = v.m_coeffs.size() - m_coeffs.size(); + if (extendBy > 0) { + m_coeffs.conservativeResize(v.m_coeffs.rows()); + m_coeffs.tail(extendBy).setZero(); + m_bands = v.m_bands; + } + m_coeffs.head(m_coeffs.size()) += v.m_coeffs.head(m_coeffs.size()) * f; + return *this; } /// Scalar multiplication inline SHVector &operator*=(Float f) { - std::transform(m_coeffs.begin(), m_coeffs.end(), m_coeffs.begin(), - std::bind2nd(std::multiplies(), f)); + m_coeffs *= f; return *this; } - /// Add a scalar multiple of another vector - inline void madd(Float f, const SHVector &v) { - if (v.m_coeffs.size() > m_coeffs.size()) - m_coeffs.resize(v.m_coeffs.size(), 0); - for (size_t i=0; i(), inv)); + m_coeffs *= (Float) 1 / f; return *this; } + /// Scalar division + inline SHVector operator/(Float f) const { + SHVector vec(m_bands); + vec.m_coeffs = m_coeffs * (1/f); + return vec; + } + + /// Negation operator + inline SHVector operator-() const { + SHVector vec(m_bands); + vec.m_coeffs = -m_coeffs; + return vec; + } + /// Access coefficient m (in {-l, ..., l}) on band l inline Float &operator()(int l, int m) { return m_coeffs[l*(l+1) + m]; @@ -206,29 +261,30 @@ public: /// Check if this function is azumuthally invariant bool isAzimuthallyInvariant() const; - /// Turn into a string representation - std::string toString() const; + /// Equality comparison operator + inline bool operator==(const SHVector &v) const { + return m_bands == v.m_bands && m_coeffs == v.m_coeffs; + } + + /// Equality comparison operator + inline bool operator!=(const SHVector &v) const { + return !operator==(v); + } /// Dot product - inline friend Float dot(const SHVector &v1, const SHVector &v2) { - const size_t size = std::min(v1.m_coeffs.size(), v2.m_coeffs.size()); - return std::inner_product( - v1.m_coeffs.begin(), v1.m_coeffs.begin() + size, - v2.m_coeffs.begin(), Float() - ); - } + inline friend Float dot(const SHVector &v1, const SHVector &v2); /// Normalize so that the represented function becomes a valid distribution void normalize(); /// Compute the second spherical moment (analytic) - ublas::matrix mu2() const; + Matrix3x3 mu2() const; /// Brute-force search for the minimum value over the sphere Float findMinimum(int res) const; /// Add a constant value - void offset(Float value); + void addOffset(Float value); /** * \brief Convolve the SH representation with the supplied kernel. @@ -322,6 +378,9 @@ public: return error/denom; } + /// Turn into a string representation + std::string toString() const; + /// Return a normalization coefficient inline static Float normalization(int l, int m) { if (l < SH_NORMTBL_SIZE) @@ -346,19 +405,27 @@ public: static void staticShutdown(); protected: /// Helper function for rotation() -- computes a diagonal block based on the previous level - static void rotationBlock(const ublas::matrix &M1, const ublas::matrix &Mp, ublas::matrix &Mn); + static void rotationBlock(const SHRotation::Matrix &M1, const SHRotation::Matrix &Mp, SHRotation::Matrix &Mn); /// Compute a normalization coefficient static Float computeNormalization(int l, int m); private: int m_bands; - std::vector m_coeffs; + Eigen::Matrix m_coeffs; static Float *m_normalization; }; +inline Float dot(const SHVector &v1, const SHVector &v2) { + const size_t size = std::min(v1.m_coeffs.size(), v2.m_coeffs.size()); + return v1.m_coeffs.head(size).dot(v2.m_coeffs.head(size)); +} + /** * \brief Implementation of 'Importance Sampling Spherical Harmonics' * by W. Jarsz, N. Carr and H. W. Jensen (EUROGRAPHICS 2009) + * + * \ingroup libcore + * \ingroup libpython */ class MTS_EXPORT_CORE SHSampler : public Object { public: diff --git a/src/libbidir/util.cpp b/src/libbidir/util.cpp index 70f0bf5b..4561c3a2 100644 --- a/src/libbidir/util.cpp +++ b/src/libbidir/util.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include MTS_NAMESPACE_BEGIN diff --git a/src/libcore/shvector.cpp b/src/libcore/shvector.cpp index 3a19bbff..272345d3 100644 --- a/src/libcore/shvector.cpp +++ b/src/libcore/shvector.cpp @@ -87,7 +87,7 @@ Float SHVector::findMinimum(int res = 32) const { return minimum; } -void SHVector::offset(Float value) { +void SHVector::addOffset(Float value) { operator()(0, 0) += 2 * value * (Float) std::sqrt(M_PI); } @@ -146,14 +146,13 @@ void SHVector::convolve(const SHVector &kernel) { } } -ublas::matrix SHVector::mu2() const { +Matrix3x3 SHVector::mu2() const { const Float sqrt5o3 = std::sqrt((Float) 5/ (Float) 3); const Float sqrto3 = std::sqrt((Float) 1/ (Float) 3); - ublas::matrix result(3, 3); + Matrix3x3 result; + result.setZero(); SAssert(m_bands > 0); - - result.clear(); result(0, 0) = result(1, 1) = result(2, 2) = sqrt5o3*operator()(0,0); @@ -211,16 +210,16 @@ void SHVector::staticShutdown() { } struct RotationBlockHelper { - const ublas::matrix &M1, &Mp; - ublas::matrix &Mn; + const SHRotation::Matrix &M1, &Mp; + SHRotation::Matrix &Mn; int prevLevel, level; inline RotationBlockHelper( - const ublas::matrix &M1, - const ublas::matrix &Mp, - ublas::matrix &Mn) - : M1(M1), Mp(Mp), Mn(Mn), prevLevel((int) Mp.size1()/2), - level((int) Mp.size1()/2+1) { } + const SHRotation::Matrix &M1, + const SHRotation::Matrix &Mp, + SHRotation::Matrix &Mn) + : M1(M1), Mp(Mp), Mn(Mn), prevLevel((int) Mp.rows()/2), + level((int) Mp.rows()/2+1) { } inline Float delta(int i, int j) const { return (i == j) ? (Float) 1 : (Float) 0; @@ -310,9 +309,9 @@ struct RotationBlockHelper { }; void SHVector::rotationBlock( - const ublas::matrix &M1, - const ublas::matrix &Mp, - ublas::matrix &Mn) { + const SHRotation::Matrix &M1, + const SHRotation::Matrix &Mp, + SHRotation::Matrix &Mn) { RotationBlockHelper rbh(M1, Mp, Mn); rbh.compute(); } @@ -343,7 +342,7 @@ void SHVector::rotation(const Transform &t, SHRotation &rot) { void SHRotation::operator()(const SHVector &source, SHVector &target) const { SAssert(source.getBands() == target.getBands()); for (int l=0; l &M = blocks[l]; + const SHRotation::Matrix &M = blocks[l]; for (int m1=-l; m1<=l; ++m1) { Float result = 0; for (int m2=-l; m2<=l; ++m2) diff --git a/src/libpython/SConscript b/src/libpython/SConscript index 82b062d9..cbf03d06 100644 --- a/src/libpython/SConscript +++ b/src/libpython/SConscript @@ -24,8 +24,8 @@ for ver in hasPython: if sys.platform != 'win32': # Python has serious aliasing issues. Disable -fstrict-aliasing only for this library - pythonEnv.Append(CXXFLAGS = ['-fno-strict-aliasing']); - pythonEnv.RemoveFlags(['-fstrict-aliasing', '-ftree-vectorize']); + pythonEnv.Append(CXXFLAGS = ['-fno-strict-aliasing']) + pythonEnv.RemoveFlags(['-fstrict-aliasing', '-ftree-vectorize']) else: # Create an OBJ file with many addressable sections (or compilation may fail on Windows) pythonEnv.Append(CPPFLAGS = ['/bigobj']) @@ -36,4 +36,7 @@ for ver in hasPython: if hasPython: libcore_obj = pythonEnv.SharedObject('core_'+ver, 'core.cpp') librender_obj = pythonEnv.SharedObject('render_'+ver, 'render.cpp') - libpython = pythonEnv.SharedLibrary('mitsuba_python'+ver, [libcore_obj, librender_obj]); + libpython = pythonEnv.SharedLibrary('mitsuba_python'+ver, [libcore_obj, librender_obj]) + + if sys.platform == 'darwin': + env.AddPostAction(libpython, 'strip -u -r $TARGET') diff --git a/src/libpython/core.cpp b/src/libpython/core.cpp index e55c8a4b..277b9502 100644 --- a/src/libpython/core.cpp +++ b/src/libpython/core.cpp @@ -15,8 +15,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -24,7 +26,7 @@ using namespace mitsuba; -void initializeFramework() { +static void initializeFramework() { /* Initialize the core framework */ Class::staticInitialization(); Object::staticInitialization(); @@ -40,7 +42,7 @@ void initializeFramework() { SceneHandler::staticInitialization(); } -void shutdownFramework() { +static void shutdownFramework() { /* Shutdown the core framework */ SceneHandler::staticShutdown(); SHVector::staticShutdown(); @@ -152,6 +154,28 @@ struct TSpectrum_to_Spectrum { } }; +static Matrix4x4 *Matrix4x4_fromList(bp::list list) { + if (bp::len(list) == 4) { + Float buf[4][4]; + for (int i=0; i<4; ++i) { + bp::list subList = bp::extract(list[i]); + if (bp::len(subList) != 4) + SLog(EError, "Matrix4x4 list constructor: invalid argument"); + for (int j=0; j<4; ++j) + buf[i][j] = bp::extract(subList[j]); + } + return new Matrix4x4(buf); + } else if (bp::len(list) == 16) { + Float buf[16]; + for (int i=0; i<16; ++i) + buf[i] = bp::extract(list[i]); + return new Matrix4x4(buf); + } else { + SLog(EError, "Matrix4x4 list constructor: invalid argument"); + return NULL; + } +} + static void Matrix4x4_setItem(Matrix4x4 *matrix, bp::tuple tuple, Float value) { if (bp::len(tuple) != 2) SLog(EError, "Invalid matrix indexing operation, required a tuple of length 2"); @@ -176,15 +200,97 @@ static Float Matrix4x4_getItem(Matrix4x4 *matrix, bp::tuple tuple) { return matrix->operator()(i, j); } -Class *object_getClass(Object *object) { +static Matrix4x4 Matrix4x4_transpose(Matrix4x4 *matrix) { + Matrix4x4 result; + matrix->transpose(result); + return result; +} + +static Matrix4x4 Matrix4x4_invert(Matrix4x4 *matrix) { + Matrix4x4 result; + matrix->invert(result); + return result; +} + +static bp::tuple Matrix4x4_symEig(Matrix4x4 *matrix) { + Matrix4x4 Q; + Float d[4]; + matrix->symEig(Q, d); + + bp::list list; + for (int i=0; i<4; ++i) + list.append(d[i]); + + return bp::make_tuple(Q, list); +} + +static bp::tuple Matrix4x4_lu(Matrix4x4 *matrix) { + Matrix4x4 LU; + int piv[4]; + int pivsign; + matrix->lu(LU, piv, pivsign); + + bp::list list; + for (int i=0; i<4; ++i) + list.append(piv[i]); + + return bp::make_tuple(LU, list, pivsign); +} + +static Vector4 Matrix4x4_cholSolve(Matrix4x4 *matrix, Vector B) { + typedef Matrix<4, 1, Float> Matrix4x1; + Vector4 X; + matrix->cholSolve<1>((Matrix4x1 &) B, (Matrix4x1 &) X); + return X; +} + +static Vector4 Matrix4x4_luSolve(Matrix4x4 *matrix, Vector B, bp::list pivList) { + typedef Matrix<4, 1, Float> Matrix4x1; + Vector4 X; + int piv[4]; + + if (bp::len(pivList) != 4) + SLog(EError, "Matrix4x4 list constructor: invalid argument"); + for (int i=0; i<4; ++i) + piv[i] = bp::extract(pivList[i]); + + matrix->luSolve<1>((Matrix4x1 &) B, (Matrix4x1 &) X, piv); + return X; +} + +static void SHVector_setItem(SHVector *v, bp::tuple tuple, Float value) { + if (bp::len(tuple) != 2) + SLog(EError, "Invalid v indexing operation, required a tuple of length 2"); + int i = bp::extract(tuple[0]); + int j = bp::extract(tuple[1]); + + if (i < 0 || i >= v->getBands() || i < -i || j > i) + SLog(EError, "Index (%i, %i) is out of bounds!", i, j); + + v->operator()(i, j) = value; +} + +static Float SHVector_getItem(SHVector *v, bp::tuple tuple) { + if (bp::len(tuple) != 2) + SLog(EError, "Invalid v indexing operation, required a tuple of length 2"); + int i = bp::extract(tuple[0]); + int j = bp::extract(tuple[1]); + + if (i < 0 || i >= v->getBands() || i < -i || j > i) + SLog(EError, "Index (%i, %i) is out of bounds!", i, j); + + return v->operator()(i, j); +} + +static Class *object_getClass(Object *object) { return const_cast(object->getClass()); } -Class *class_forName(const char *name) { +static Class *class_forName(const char *name) { return const_cast(Class::forName(name)); } -Class *class_getSuperClass(Class *theClass) { +static Class *class_getSuperClass(Class *theClass) { return const_cast(theClass->getSuperClass()); } @@ -197,12 +303,12 @@ void appender_logProgress(Appender *appender, Float progress, const std::string appender->logProgress(progress, name, formatted, eta, NULL); } -void logger_logProgress(Logger *logger, Float progress, const std::string &name, +static void logger_logProgress(Logger *logger, Float progress, const std::string &name, const std::string &formatted, const std::string &eta) { logger->logProgress(progress, name, formatted, eta, NULL); } -void mts_log(ELogLevel level, const std::string &msg) { +static void mts_log(ELogLevel level, const std::string &msg) { bp::object traceback(bp::import("traceback")); bp::object extract_stack(traceback.attr("extract_stack")); bp::object stack = extract_stack(); @@ -294,7 +400,7 @@ static bp::tuple spectrum_toIPT(const Spectrum &s) { return bp::make_tuple(I, P, T); } -bp::object bsphere_rayIntersect(BSphere *bsphere, const Ray &ray) { +static bp::object bsphere_rayIntersect(BSphere *bsphere, const Ray &ray) { Float nearT, farT; if (bsphere->rayIntersect(ray, nearT, farT)) return bp::make_tuple(nearT, farT); @@ -303,7 +409,7 @@ bp::object bsphere_rayIntersect(BSphere *bsphere, const Ray &ray) { } -bp::object aabb_rayIntersect(AABB *aabb, const Ray &ray) { +static bp::object aabb_rayIntersect(AABB *aabb, const Ray &ray) { Float nearT, farT; if (aabb->rayIntersect(ray, nearT, farT)) return bp::make_tuple(nearT, farT); @@ -312,7 +418,7 @@ bp::object aabb_rayIntersect(AABB *aabb, const Ray &ray) { } -bp::object logger_readLog(Logger *logger) { +static bp::object logger_readLog(Logger *logger) { std::string string; if (logger->readLog(string)) return bp::object(string); @@ -320,7 +426,7 @@ bp::object logger_readLog(Logger *logger) { return bp::object(); } -bp::object aabb_rayIntersect2(AABB *aabb, const Ray &ray, Float nearT, Float farT) { +static bp::object aabb_rayIntersect2(AABB *aabb, const Ray &ray, Float nearT, Float farT) { Point nearP, farP; if (aabb->rayIntersect(ray, nearT, farT, nearP, farP)) return bp::make_tuple(nearT, farT, nearP, farP); @@ -328,12 +434,12 @@ bp::object aabb_rayIntersect2(AABB *aabb, const Ray &ray, Float nearT, Float far return bp::object(); } -Vector transform_mul_vector(Transform *transform, const Vector &vector) { return transform->operator()(vector); } -Vector4 transform_mul_vector4(Transform *transform, const Vector4 &vector) { return transform->operator()(vector); } -Normal transform_mul_normal(Transform *transform, const Normal &normal) { return transform->operator()(normal); } -Point transform_mul_point(Transform *transform, const Point &point) { return transform->operator()(point); } -Ray transform_mul_ray(Transform *transform, const Ray &ray) { return transform->operator()(ray); } -Transform transform_mul_transform(Transform *transform, const Transform &other) { return *transform * other; } +static Vector transform_mul_vector(Transform *transform, const Vector &vector) { return transform->operator()(vector); } +static Vector4 transform_mul_vector4(Transform *transform, const Vector4 &vector) { return transform->operator()(vector); } +static Normal transform_mul_normal(Transform *transform, const Normal &normal) { return transform->operator()(normal); } +static Point transform_mul_point(Transform *transform, const Point &point) { return transform->operator()(point); } +static Ray transform_mul_ray(Transform *transform, const Ray &ray) { return transform->operator()(ray); } +static Transform transform_mul_transform(Transform *transform, const Transform &other) { return *transform * other; } bp::object cast(ConfigurableObject *obj) { const Class *cls = obj->getClass(); @@ -359,15 +465,15 @@ bp::object cast(ConfigurableObject *obj) { return bp::object(); } -bp::object pluginmgr_createobject_1(PluginManager *mgr, const Properties &props) { +static bp::object pluginmgr_createobject_1(PluginManager *mgr, const Properties &props) { return cast(mgr->createObject(props)); } -bp::object pluginmgr_createobject_2(PluginManager *mgr, const Class *cls, const Properties &props) { +static bp::object pluginmgr_createobject_2(PluginManager *mgr, const Class *cls, const Properties &props) { return cast(mgr->createObject(cls, props)); } -ConfigurableObject *pluginmgr_create(PluginManager *manager, bp::dict dict) { +static ConfigurableObject *pluginmgr_create(PluginManager *manager, bp::dict dict) { Properties properties; bp::list list = dict.items(); std::map children; @@ -401,39 +507,39 @@ ConfigurableObject *pluginmgr_create(PluginManager *manager, bp::dict dict) { return object; } -bp::tuple mkCoordinateSystem(const Vector &n) { +static bp::tuple mkCoordinateSystem(const Vector &n) { Vector s, t; coordinateSystem(n, s, t); return bp::make_tuple(s, t); } -bp::tuple fresnelDielectricExt1(Float cosThetaI, Float eta) { +static bp::tuple fresnelDielectricExt1(Float cosThetaI, Float eta) { Float cosThetaT; Float result = fresnelDielectricExt(cosThetaI, cosThetaT, eta); return bp::make_tuple(result, cosThetaT); } -Float fresnelDielectricExt2(Float cosThetaI, Float eta) { +static Float fresnelDielectricExt2(Float cosThetaI, Float eta) { return fresnelDielectricExt(cosThetaI, eta); } -Vector refract1(const Vector &wi, const Normal &n, Float eta, Float cosThetaT) { +static Vector refract1(const Vector &wi, const Normal &n, Float eta, Float cosThetaT) { return refract(wi, n, eta, cosThetaT); } -bp::tuple refract2(const Vector &wi, const Normal &n, Float eta) { +static bp::tuple refract2(const Vector &wi, const Normal &n, Float eta) { Float cosThetaT, F; Vector result = refract(wi, n, eta, cosThetaT, F); return bp::make_tuple(result, cosThetaT, F); } -Vector refract3(const Vector &wi, const Normal &n, Float eta) { +static Vector refract3(const Vector &wi, const Normal &n, Float eta) { return refract(wi, n, eta); } -void bitmap_applyMatrix(Bitmap *bitmap, bp::list list) { +static 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!"); @@ -448,30 +554,30 @@ void bitmap_applyMatrix(Bitmap *bitmap, bp::list list) { bitmap->applyMatrix(matrix); } -void bitmap_write(Bitmap *bitmap, Bitmap::EFileFormat fmt, Stream *stream) { +static void bitmap_write(Bitmap *bitmap, Bitmap::EFileFormat fmt, Stream *stream) { bitmap->write(fmt, stream); } -ref bitmap_convert_1(Bitmap *bitmap, Bitmap::EPixelFormat pixelFormat, Bitmap::EComponentFormat componentFormat, +static ref 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_convert_2(Bitmap *bitmap, Bitmap::EPixelFormat pixelFormat, Bitmap::EComponentFormat componentFormat, +static ref bitmap_convert_2(Bitmap *bitmap, Bitmap::EPixelFormat pixelFormat, Bitmap::EComponentFormat componentFormat, Float gamma, Float multiplier) { return bitmap->convert(pixelFormat, componentFormat, gamma, multiplier); } -ref bitmap_convert_3(Bitmap *bitmap, Bitmap::EPixelFormat pixelFormat, Bitmap::EComponentFormat componentFormat, +static ref bitmap_convert_3(Bitmap *bitmap, Bitmap::EPixelFormat pixelFormat, Bitmap::EComponentFormat componentFormat, Float gamma) { return bitmap->convert(pixelFormat, componentFormat, gamma); } -ref bitmap_convert_4(Bitmap *bitmap, Bitmap::EPixelFormat pixelFormat, Bitmap::EComponentFormat componentFormat) { +static ref bitmap_convert_4(Bitmap *bitmap, Bitmap::EPixelFormat pixelFormat, Bitmap::EComponentFormat componentFormat) { return bitmap->convert(pixelFormat, componentFormat); } -void bitmap_fromByteArray(Bitmap *bitmap, bp::object obj) { +static void bitmap_fromByteArray(Bitmap *bitmap, bp::object obj) { if (PyByteArray_Check(obj.ptr())) { uint8_t *ptr = (uint8_t *) PyByteArray_AsString(obj.ptr()); size_t size = PyByteArray_Size(obj.ptr()); @@ -483,7 +589,7 @@ void bitmap_fromByteArray(Bitmap *bitmap, bp::object obj) { } } -void bitmap_toByteArray_1(const Bitmap *bitmap, bp::object obj) { +static void bitmap_toByteArray_1(const Bitmap *bitmap, bp::object obj) { if (PyByteArray_Check(obj.ptr())) { uint8_t *ptr = (uint8_t *) PyByteArray_AsString(obj.ptr()); size_t size = PyByteArray_Size(obj.ptr()); @@ -495,17 +601,17 @@ void bitmap_toByteArray_1(const Bitmap *bitmap, bp::object obj) { } } -bp::object bitmap_toByteArray_2(const Bitmap *bitmap) { +static bp::object bitmap_toByteArray_2(const Bitmap *bitmap) { return bp::object(bp::handle<>(PyByteArray_FromStringAndSize( (char *) bitmap->getUInt8Data(), bitmap->getBufferSize()))); } -bp::tuple bitmap_tonemapReinhard(Bitmap *bitmap, Float logAvgLuminance, Float maxLuminance, Float key, Float burn) { +static bp::tuple bitmap_tonemapReinhard(Bitmap *bitmap, Float logAvgLuminance, Float maxLuminance, Float key, Float burn) { bitmap->tonemapReinhard(logAvgLuminance, maxLuminance, key, burn); return bp::make_tuple(logAvgLuminance, maxLuminance); } -bp::object bitmap_join(Bitmap::EPixelFormat fmt, bp::list list) { +static bp::object bitmap_join(Bitmap::EPixelFormat fmt, bp::list list) { std::vector bitmaps(bp::len(list)); for (int i=0; i paths = fres->resolveAll(path); @@ -534,6 +640,88 @@ bp::list fileresolver_resolveAll(const FileResolver *fres, const fs::path &path) return result; } +static bp::tuple DiscreteDistribution_sample(DiscreteDistribution *d, Float sampleValue) { + Float pdf; + size_t index = d->sample(sampleValue, pdf); + return bp::make_tuple(index, pdf); +} + +static bp::tuple DiscreteDistribution_sampleReuse(DiscreteDistribution *d, Float sampleValue) { + Float pdf; + size_t index = d->sampleReuse(sampleValue, pdf); + return bp::make_tuple(index, pdf, sampleValue); +} + +static Float DiscreteDistribution_getitem(DiscreteDistribution *d, int i) { + if (i < 0 || i >= d->size()) { + SLog(EError, "Index %i is out of range!", i); + return 0.0f; + } + return d->operator[](i); +} + +static bp::tuple legendrePD_double(int l, double x) { + std::pair result = legendrePD(l, x); + return bp::make_tuple(result.first, result.second); +} + +static bp::tuple gaussLegendre_(int n) { + Float *nodes = new Float[n]; + Float *weights= new Float[n]; + gaussLegendre(n, nodes, weights); + + bp::list nodeList, weightList; + for (int i=0; i owner; void *ptr; @@ -643,7 +831,7 @@ struct NativeBuffer { } }; -NativeBuffer bitmap_getNativeBuffer(Bitmap *bitmap) { +static NativeBuffer bitmap_getNativeBuffer(Bitmap *bitmap) { return NativeBuffer(bitmap, bitmap->getFloat32Data(), bitmap->getPixelCount() * bitmap->getChannelCount(), bitmap->getComponentFormat()); } @@ -662,10 +850,50 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(fromIPT_overloads, fromIPT, 3, 4) .def("getValue", &Name::getValue, BP_RETURN_VALUE) \ .def("append", &Name::append) +struct PythonIntegrand { + PythonIntegrand(bp::object integrand) : integrand(integrand) {} + + Float operator()(Float value) { + bp::object obj = integrand(value); + bp::extract extract(obj); + return (Float) extract(); + } + + bp::object integrand; +}; + +struct PythonIntegrandFromPythonCallable { + PythonIntegrandFromPythonCallable() { + bp::converter::registry::push_back(&convertible, + &construct, bp::type_id()); + } + + static void* convertible(PyObject* obj) { + if(!PyCallable_Check(obj)) + return 0; + return obj; + } + + static void construct(PyObject* obj, bp::converter::rvalue_from_python_stage1_data* data) { + bp::object callable(bp::handle<>(bp::borrowed(obj))); + void* storage = ((bp::converter::rvalue_from_python_storage*) data)->storage.bytes; + new (storage) GaussLobattoIntegrator::Integrand(PythonIntegrand(callable)); + data->convertible = storage; + } +}; + +bp::tuple GaussLobattoIntegrator_integrate(GaussLobattoIntegrator *integrator, + const GaussLobattoIntegrator::Integrand &integrand, Float a, Float b) { + size_t nEvals = 0; + Float result = integrator->integrate(integrand, a, b, &nEvals); + return bp::make_tuple(result, nEvals); +} + void export_core() { bp::to_python_converter(); bp::to_python_converter, TSpectrum_to_Spectrum>(); bp::implicitly_convertible(); + PythonIntegrandFromPythonCallable(); bp::object coreModule( bp::handle<>(bp::borrowed(PyImport_AddModule("mitsuba.core")))); @@ -797,6 +1025,9 @@ void export_core() { .export_values(); BP_SETSCOPE(coreModule); + BP_CLASS(MemoryStream, Stream, (bp::init >())) + .def("reset", &MemoryStream::reset); + BP_CLASS(SerializableObject, Object, bp::no_init) .def("serialize", &SerializableObject::serialize); @@ -1042,6 +1273,37 @@ void export_core() { BP_SETSCOPE(coreModule); + /* Native buffers for bitmaps */ + bp::class_("NativeBuffer", bp::no_init); + + const bp::converter::registration& fb_reg( + bp::converter::registry::lookup(bp::type_id())); + PyTypeObject* fb_type = fb_reg.get_class_object(); + + static PyBufferProcs NativeBuffer_buffer_procs = { + #if PY_MAJOR_VERSION < 3 + NULL, NULL, NULL, NULL, + #endif + &NativeBuffer::getbuffer, + &NativeBuffer::releasebuffer + }; + + // partial sequence protocol support + static PySequenceMethods NativeBuffer_as_sequence = { + &NativeBuffer::len, + NULL, + NULL, + &NativeBuffer::item + }; + + fb_type->tp_as_sequence = &NativeBuffer_as_sequence; + fb_type->tp_as_buffer = &NativeBuffer_buffer_procs; + + #if PY_MAJOR_VERSION < 3 + fb_type->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; + #endif + + BP_CLASS(FileResolver, Object, bp::init<>()) .def("getPathCount", &FileResolver::getPathCount) .def("getPath", &FileResolver::getPath, BP_RETURN_VALUE) @@ -1066,6 +1328,7 @@ void export_core() { .def("nextUInt", &Random::nextUInt) .def("nextSize", &Random::nextSize) .def("nextFloat", &Random::nextFloat) + .def("nextStandardNormal", &Random::nextStandardNormal) .def("serialize", &Random::serialize); BP_CLASS(PluginManager, Object, bp::no_init) @@ -1165,6 +1428,8 @@ void export_core() { .def("getSize", &AbstractAnimationTrack::getSize) .def("clone", &AbstractAnimationTrack::clone, BP_RETURN_VALUE); + BP_CLASS_DECL(StreamBackend, Thread, (bp::init())); + IMPLEMENT_ANIMATION_TRACK(FloatTrack); IMPLEMENT_ANIMATION_TRACK(VectorTrack); IMPLEMENT_ANIMATION_TRACK(PointTrack); @@ -1481,14 +1746,31 @@ void export_core() { bp::scope().attr("Vector") = bp::scope().attr("Vector3"); bp::scope().attr("Point") = bp::scope().attr("Point3"); - bp::class_("Matrix4x4", bp::init()) + bp::class_("Matrix4x4", bp::init<>()) + .def(bp::init()) + .def(bp::init()) + .def(bp::init()) + .def(bp::init()) + .def("__init__", bp::make_constructor(Matrix4x4_fromList)) .def(bp::init()) .def("__setitem__", &Matrix4x4_setItem) .def("__getitem__", &Matrix4x4_getItem) .def("setIdentity", &Matrix4x4::setIdentity) + .def("setZero", &Matrix4x4::setZero) .def("isZero", &Matrix4x4::isZero) + .def("isIdentity", &Matrix4x4::isIdentity) .def("trace", &Matrix4x4::trace) + .def("frob", &Matrix4x4::frob) .def("det", &Matrix4x4::det) + .def("cholDet", &Matrix4x4::cholDet) + .def("luDet", &Matrix4x4::luDet) + .def("chol", &Matrix4x4::chol) + .def("symEig", &Matrix4x4_symEig) + .def("lu", &Matrix4x4_lu) + .def("cholSolve", &Matrix4x4_cholSolve) + .def("luSolve", &Matrix4x4_luSolve) + .def("transpose", &Matrix4x4_transpose) + .def("invert", &Matrix4x4_invert) .def("serialize", &Matrix4x4::serialize) .def(bp::self != bp::self) .def(bp::self == bp::self) @@ -1510,6 +1792,19 @@ void export_core() { .def(bp::self /= Float()) .def("__repr__", &Matrix4x4::toString); + bp::class_("DiscreteDistribution", bp::init >()) + .def("clear", &DiscreteDistribution::clear) + .def("reserve", &DiscreteDistribution::reserve) + .def("append", &DiscreteDistribution::append) + .def("isNormalized", &DiscreteDistribution::isNormalized) + .def("getSum", &DiscreteDistribution::getSum) + .def("normalize", &DiscreteDistribution::normalize) + .def("size", &DiscreteDistribution::size) + .def("sample", &DiscreteDistribution_sample) + .def("sampleReuse", &DiscreteDistribution_sampleReuse) + .def("__getitem__", &DiscreteDistribution_getitem) + .def("__repr__", &DiscreteDistribution::toString); + bp::class_("Ray", bp::init<>()) .def(bp::init()) .def(bp::init()) @@ -1527,6 +1822,18 @@ void export_core() { .def("eval", &ray_eval, BP_RETURN_VALUE) .def("__repr__", &Ray::toString); + bp::class_ >("RayDifferential", bp::init<>()) + .def(bp::init()) + .def(bp::init()) + .def(bp::init()) + .def_readwrite("rxOrigin", &RayDifferential::rxOrigin) + .def_readwrite("ryOrigin", &RayDifferential::ryOrigin) + .def_readwrite("rxDirection", &RayDifferential::rxDirection) + .def_readwrite("ryDirection", &RayDifferential::ryDirection) + .def_readwrite("hasDifferentials", &RayDifferential::hasDifferentials) + .def("scaleDifferential", &RayDifferential::scaleDifferential) + .def("__repr__", &RayDifferential::toString); + bp::class_("BSphere", bp::init<>()) .def(bp::init()) .def(bp::init()) @@ -1667,39 +1974,149 @@ void export_core() { bp::def("sobol2Single", sobol2Single); bp::def("sobol2Double", sobol2Double); bp::def("sobol2", sobol2Double); + bp::def("sample02Single", sample02Single); + bp::def("sample02Double", sample02Double); + bp::def("sample02", sample02); bp::def("sampleTEA", sampleTEA); + bp::def("sampleTEAFloat", sampleTEAFloat); bp::def("radicalInverse", radicalInverse); bp::def("radicalInverseFast", radicalInverseFast); bp::def("radicalInverseIncremental", radicalInverseIncremental); - bp::class_("NativeBuffer", bp::no_init); + /* Functions from quad.h */ + double (*legendreP1)(int, double) = &legendreP; + double (*legendreP2)(int, int, double) = &legendreP; - const bp::converter::registration& fb_reg( - bp::converter::registry::lookup(bp::type_id())); - PyTypeObject* fb_type = fb_reg.get_class_object(); + bp::def("legendreP", legendreP1); + bp::def("legendreP", legendreP2); + bp::def("legendrePD", legendrePD_double); + bp::def("gaussLegendre", gaussLegendre_); + bp::def("gaussLobatto", gaussLobatto_); - static PyBufferProcs NativeBuffer_buffer_procs = { - #if PY_MAJOR_VERSION < 3 - NULL, NULL, NULL, NULL, - #endif - &NativeBuffer::getbuffer, - &NativeBuffer::releasebuffer - }; + bp::class_("GaussLobattoIntegrator", (bp::init >())) + .def("integrate", GaussLobattoIntegrator_integrate); - // partial sequence protocol support - static PySequenceMethods NativeBuffer_as_sequence = { - &NativeBuffer::len, - NULL, - NULL, - &NativeBuffer::item - }; + BP_STRUCT(Quaternion, bp::init<>()) + .def(bp::init()) + .def(bp::init()) + .def_readwrite("v", &Quaternion::v) + .def_readwrite("w", &Quaternion::w) + .def(bp::self != bp::self) + .def(bp::self == bp::self) + .def(-bp::self) + .def(bp::self + bp::self) + .def(bp::self += bp::self) + .def(bp::self - bp::self) + .def(bp::self -= bp::self) + .def(bp::self *= Float()) + .def(bp::self * Float()) + .def(bp::self *= bp::self) + .def(bp::self * bp::self) + .def(bp::self *= bp::self) + .def(bp::self * bp::self) + .def(bp::self / Float()) + .def(bp::self /= Float()) + .def("isIdentity", &Quaternion::isIdentity) + .def("axis", &Quaternion::axis) + .def("angle", &Quaternion::angle) + .def("exp", &Quaternion::exp) + .def("log", &Quaternion::log) + .def("toTransform", &Quaternion::toTransform) + .def("serialize", &Quaternion::serialize) + .def("fromAxisAngle", &Quaternion::fromAxisAngle) + .def("fromTransform", &Quaternion::fromTransform) + .def("fromDirectionPair", &Quaternion::fromDirectionPair) + .def("fromMatrix", &Quaternion::fromMatrix) + .def("fromEulerAngles", &Quaternion::fromEulerAngles) + .def("__repr__", &Quaternion::toString) + .staticmethod("fromAxisAngle") + .staticmethod("fromDirectionPair") + .staticmethod("fromTransform") + .staticmethod("fromMatrix") + .staticmethod("fromEulerAngles"); - fb_type->tp_as_sequence = &NativeBuffer_as_sequence; - fb_type->tp_as_buffer = &NativeBuffer_buffer_procs; + BP_SETSCOPE(Quaternion_struct); - #if PY_MAJOR_VERSION < 3 - fb_type->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; - #endif + bp::enum_("EEulerAngleConvention") + .value("EEulerXYZ", Quaternion::EEulerXYZ) + .value("EEulerXZY", Quaternion::EEulerXZY) + .value("EEulerYXZ", Quaternion::EEulerYXZ) + .value("EEulerYZX", Quaternion::EEulerYZX) + .value("EEulerZXY", Quaternion::EEulerZXY) + .value("EEulerZYX", Quaternion::EEulerZYX) + .export_values(); + BP_SETSCOPE(coreModule); + + Float (*dotQ)(const Quaternion &, const Quaternion &) = ˙ + Quaternion (*normalizeQ)(const Quaternion &) = &normalize; + Quaternion (*slerpQ)(const Quaternion &, const Quaternion &, Float) = &slerp; + + bp::def("dot", dotQ); + bp::def("normalize", normalizeQ); + bp::def("slerp", slerpQ); + + BP_CLASS(ReconstructionFilter, ConfigurableObject, bp::no_init) + .def("eval", &ReconstructionFilter::eval) + .def("evalDiscretized", &ReconstructionFilter::evalDiscretized) + .def("getRadius", &ReconstructionFilter::getRadius) + .def("getBorderSize", &ReconstructionFilter::getBorderSize); + + BP_SETSCOPE(ReconstructionFilter_class); + bp::enum_("EBoundaryCondition") + .value("EClamp", ReconstructionFilter::EClamp) + .value("ERepeat", ReconstructionFilter::ERepeat) + .value("EMirror", ReconstructionFilter::EMirror) + .value("EZero", ReconstructionFilter::EZero) + .value("EOne", ReconstructionFilter::EOne) + .export_values(); + BP_SETSCOPE(coreModule); + + Float (SHVector::*shvector_eval1)(Float, Float) const = &SHVector::eval; + Float (SHVector::*shvector_eval2)(const Vector &) const = &SHVector::eval; + Float (SHVector::*shvector_evalAzimuthallyInvariant1)(Float, Float) const = &SHVector::evalAzimuthallyInvariant; + Float (SHVector::*shvector_evalAzimuthallyInvariant2)(const Vector &) const = &SHVector::evalAzimuthallyInvariant; + + BP_STRUCT(SHVector, bp::init<>()) + .def(bp::init()) + .def(bp::init()) + .def(bp::init()) + .def(bp::self != bp::self) + .def(bp::self == bp::self) + .def(-bp::self) + .def(bp::self + bp::self) + .def(bp::self += bp::self) + .def(bp::self - bp::self) + .def(bp::self -= bp::self) + .def(bp::self *= Float()) + .def(bp::self * Float()) + .def(bp::self / Float()) + .def(bp::self /= Float()) + .def("getBands", &SHVector::getBands) + .def("serialize", &SHVector::serialize) + .def("energy", &SHVector::energy) + .def("eval", shvector_eval1) + .def("eval", shvector_eval2) + .def("evalAzimuthallyInvariant", shvector_evalAzimuthallyInvariant1) + .def("evalAzimuthallyInvariant", shvector_evalAzimuthallyInvariant2) + .def("normalize", &SHVector::normalize) + .def("mu2", &SHVector::mu2) + .def("findMinimum", &SHVector::findMinimum) + .def("addOffset", &SHVector::addOffset) + .def("convolve", &SHVector::convolve) + .def("__repr__", &SHVector::toString) + .def("__getitem__", SHVector_getItem) + .def("__setitem__", SHVector_setItem) + .def("rotation", &SHVector::rotation) + .staticmethod("rotation"); + + Float (*dotSH)(const SHVector &, const SHVector &) = &mitsuba::dot; + bp::def("dot", dotSH); + + BP_CLASS(SHSampler, Object, bp::init()) + .def("warp", &SHSampler::warp); + + BP_STRUCT(SHRotation, bp::init()) + .def("__call__", &SHRotation::operator()); bp::detail::current_scope = oldScope; } diff --git a/src/libpython/render.cpp b/src/libpython/render.cpp index 03c9f5a3..3f718c9a 100644 --- a/src/libpython/render.cpp +++ b/src/libpython/render.cpp @@ -7,30 +7,30 @@ using namespace mitsuba; -bool intersection_get_hasUVPartials(const Intersection &its) { return its.hasUVPartials; } -void intersection_set_hasUVPartials(Intersection &its, bool value) { its.hasUVPartials = value; } -uint32_t intersection_get_primIndex(const Intersection &its) { return its.primIndex; } -void intersection_set_primIndex(Intersection &its, uint32_t value) { its.primIndex = value; } +static bool intersection_get_hasUVPartials(const Intersection &its) { return its.hasUVPartials; } +static void intersection_set_hasUVPartials(Intersection &its, bool value) { its.hasUVPartials = value; } +static uint32_t intersection_get_primIndex(const Intersection &its) { return its.primIndex; } +static void intersection_set_primIndex(Intersection &its, uint32_t value) { its.primIndex = value; } -const Intersection &bsdfsamplingrecord_get_its(const BSDFSamplingRecord &bRec) { +static const Intersection &bsdfsamplingrecord_get_its(const BSDFSamplingRecord &bRec) { return bRec.its; } -unsigned int bsdf_getType_1(const BSDF *bsdf) { +static unsigned int bsdf_getType_1(const BSDF *bsdf) { return bsdf->getType(); } -unsigned int bsdf_getType_2(const BSDF *bsdf, int index) { +static unsigned int bsdf_getType_2(const BSDF *bsdf, int index) { return bsdf->getType(index); } -bp::tuple bsdf_sample(const BSDF *bsdf, BSDFSamplingRecord &bRec, const Point2 &sample) { +static bp::tuple bsdf_sample(const BSDF *bsdf, BSDFSamplingRecord &bRec, const Point2 &sample) { Float pdf; Spectrum result = bsdf->sample(bRec, pdf, sample); return bp::make_tuple(result, pdf); } -bp::object shape_rayIntersect(const Shape *shape, const Ray &ray, Float mint, Float maxt) { +static bp::object shape_rayIntersect(const Shape *shape, const Ray &ray, Float mint, Float maxt) { uint8_t temp[MTS_KD_INTERSECTION_TEMP]; Float t; @@ -45,7 +45,7 @@ bp::object shape_rayIntersect(const Shape *shape, const Ray &ray, Float mint, Fl return bp::object(its); } -bp::object scene_rayIntersect(const Scene *scene, const Ray &ray) { +static bp::object scene_rayIntersect(const Scene *scene, const Ray &ray) { Intersection its; if (!scene->rayIntersect(ray, its)) @@ -54,7 +54,7 @@ bp::object scene_rayIntersect(const Scene *scene, const Ray &ray) { return bp::object(its); } -bp::object scene_rayIntersectAll(const Scene *scene, const Ray &ray) { +static bp::object scene_rayIntersectAll(const Scene *scene, const Ray &ray) { Intersection its; if (!scene->rayIntersectAll(ray, its)) @@ -63,26 +63,26 @@ bp::object scene_rayIntersectAll(const Scene *scene, const Ray &ray) { return bp::object(its); } -bp::tuple shape_getCurvature(const Shape *shape, const Intersection &its, bool shadingFrame) { +static bp::tuple shape_getCurvature(const Shape *shape, const Intersection &its, bool shadingFrame) { Float H, K; shape->getCurvature(its, H, K, shadingFrame); return bp::make_tuple(H, K); } -bp::tuple shape_getNormalDerivative(const Shape *shape, const Intersection &its, bool shadingFrame) { +static bp::tuple shape_getNormalDerivative(const Shape *shape, const Intersection &its, bool shadingFrame) { Vector dpdu, dpdv; shape->getNormalDerivative(its, dpdu, dpdv, shadingFrame); return bp::make_tuple(dpdu, dpdv); } -ref loadScene(const fs::path &filename, const StringMap ¶ms) { +static ref loadScene(const fs::path &filename, const StringMap ¶ms) { SceneHandler::ParameterMap pmap; for (StringMap::const_iterator it = params.begin(); it != params.end(); ++it) pmap[it->first]=it->second; return SceneHandler::loadScene(filename, pmap); } -bp::list scene_getSensors(Scene *scene) { +static bp::list scene_getSensors(Scene *scene) { bp::list list; ref_vector &sensors = scene->getSensors(); for (size_t i=0; igetSensor()); } -bp::object scene_getIntegrator(Scene *scene) { return cast(scene->getIntegrator()); } +static bp::object scene_getSensor(Scene *scene) { return cast(scene->getSensor()); } +static bp::object scene_getIntegrator(Scene *scene) { return cast(scene->getIntegrator()); } -bp::list scene_getMeshes(Scene *scene) { +static bp::list scene_getMeshes(Scene *scene) { bp::list list; std::vector &meshes = scene->getMeshes(); for (size_t i=0; i &shapes = scene->getShapes(); for (size_t i=0; i &emitters = scene->getEmitters(); for (size_t i=0; i &media = scene->getMedia(); for (size_t i=0; i InternalPoint2Array; typedef InternalArray InternalColor3Array; typedef InternalArray InternalTangentSpaceArray; -InternalUInt32Array trimesh_getTriangles(TriMesh *triMesh) { +static InternalUInt32Array trimesh_getTriangles(TriMesh *triMesh) { BOOST_STATIC_ASSERT(sizeof(Triangle) == 3*sizeof(uint32_t)); return InternalUInt32Array(triMesh, (uint32_t *) triMesh->getTriangles(), triMesh->getTriangleCount()*3); } -InternalPoint3Array trimesh_getVertexPositions(TriMesh *triMesh) { +static InternalPoint3Array trimesh_getVertexPositions(TriMesh *triMesh) { return InternalPoint3Array(triMesh, triMesh->getVertexPositions(), triMesh->getVertexCount()); } -InternalNormalArray trimesh_getVertexNormals(TriMesh *triMesh) { +static InternalNormalArray trimesh_getVertexNormals(TriMesh *triMesh) { return InternalNormalArray(triMesh, triMesh->getVertexNormals(), triMesh->getVertexCount()); } -InternalPoint2Array trimesh_getVertexTexcoords(TriMesh *triMesh) { +static InternalPoint2Array trimesh_getVertexTexcoords(TriMesh *triMesh) { return InternalPoint2Array(triMesh, triMesh->getVertexTexcoords(), triMesh->getVertexCount()); } -InternalColor3Array trimesh_getVertexColors(TriMesh *triMesh) { +static InternalColor3Array trimesh_getVertexColors(TriMesh *triMesh) { return InternalColor3Array(triMesh, triMesh->getVertexColors(), triMesh->getVertexCount()); } -InternalTangentSpaceArray trimesh_getUVTangents(TriMesh *triMesh) { +static InternalTangentSpaceArray trimesh_getUVTangents(TriMesh *triMesh) { return InternalTangentSpaceArray(triMesh, triMesh->getUVTangents(), triMesh->getVertexCount()); } -ref trimesh_fromBlender(const std::string &name, +static ref trimesh_fromBlender(const std::string &name, size_t faceCount, size_t facePtr, size_t vertexCount, size_t vertexPtr, size_t uvPtr, size_t colPtr, short matID) { return TriMesh::fromBlender(name, faceCount, reinterpret_cast(facePtr), vertexCount, reinterpret_cast(vertexPtr), reinterpret_cast(uvPtr), @@ -255,22 +255,6 @@ void export_render() { .def("request1DArray", &Sampler::request1DArray) .def("request2DArray", &Sampler::request2DArray); - BP_CLASS(ReconstructionFilter, ConfigurableObject, bp::no_init) - .def("eval", &ReconstructionFilter::eval) - .def("evalDiscretized", &ReconstructionFilter::evalDiscretized) - .def("getRadius", &ReconstructionFilter::getRadius) - .def("getBorderSize", &ReconstructionFilter::getBorderSize); - - BP_SETSCOPE(ReconstructionFilter_class); - bp::enum_("EBoundaryCondition") - .value("EClamp", ReconstructionFilter::EClamp) - .value("ERepeat", ReconstructionFilter::ERepeat) - .value("EMirror", ReconstructionFilter::EMirror) - .value("EZero", ReconstructionFilter::EZero) - .value("EOne", ReconstructionFilter::EOne) - .export_values(); - BP_SETSCOPE(renderModule); - bp::class_("SceneHandler", bp::no_init) .def("loadScene", &loadScene, BP_RETURN_VALUE) .staticmethod("loadScene");