python binding improvements

metadata
Wenzel Jakob 2011-08-20 03:36:40 -04:00
parent 0a766c8c22
commit e58a0fa338
10 changed files with 241 additions and 76 deletions

View File

@ -95,7 +95,7 @@ If all goes well, SCons should finish successfully within a few minutes:
\begin{shell} \begin{shell}
scons: $\texttt{done}$ building targets. scons: $\texttt{done}$ building targets.
\end{shell} \end{shell}
To be able to run the renderer from the command line, you will also have to import it into your path: To be able to run the renderer from the command line, you will first have to import it into your path:
\begin{shell} \begin{shell}
$\text{\$}$ . setpath.sh $\text{\$}$ . setpath.sh
\end{shell} \end{shell}
@ -173,7 +173,7 @@ If all goes well, SCons should finish successfully within a few minutes:
\begin{shell} \begin{shell}
scons: $\texttt{done}$ building targets. scons: $\texttt{done}$ building targets.
\end{shell} \end{shell}
To be able to run the renderer from the command line, you will also have to import it into your path: To be able to run the renderer from the command line, you will first have to import it into your path:
\begin{shell} \begin{shell}
$\text{\$}$ . setpath.sh $\text{\$}$ . setpath.sh
\end{shell} \end{shell}
@ -199,71 +199,42 @@ $\text{\$}$ rpmbuild -bb mitsuba-$\code{\MitsubaVersion}$/data/linux/fedora/mits
\end{shell} \end{shell}
After this command finishes, its output can be found in the directory \code{rpmbuild/RPMS}. After this command finishes, its output can be found in the directory \code{rpmbuild/RPMS}.
\subsection{Building on Arch Linux} \subsection{Building on Arch Linux}
You'll first need to install a number of dependencies. You'll first need to install a number of dependencies: run
First, run
\begin{shell} \begin{shell}
$\text{\$}$ sudo pacman -S gcc xerces-c glew openexr boost libpng libjpeg qt scons mercurial python $\text{\$}$ sudo pacman -S gcc xerces-c glew openexr boost libpng libjpeg qt scons mercurial python
\end{shell} \end{shell}
For COLLADA support, you will also have to install the \code{collada-dom}
library. For this, you can either install the binary package available on
There are two ways to install Mitsuba on Archlinux, the Arch way, and the other way. the Mitsuba website, or you can compile it yourself using the \code{PKGBUILD}
supplied with Mitsuba, i.e.
The Arch Way is to use the Aur software repository.
Accessing software in the Aur repository is easiest when using a script called \texttt{packer}.
First download packer then use \texttt{makepkg} to build and install it.
The \texttt{-is} flags will prompt you for your sudo password and then install the package after it has finished building as well as install any needed dependencies.
\begin{shell} \begin{shell}
$\text{\$}$ mkdir packer && cd packer $\text{\$}$ cd <some-temporary-directory>
$\text{\$}$ wget http://aur.archlinux.org/packages/packer/packer/PKGBUILD $\text{\$}$ cp <path-to-mitsuba>/data/linux/arch/collada-dom/PKGBUILD .
$\text{\$}$ makepkg -is $\text{\$}$ makepkg PKGBUILD
<..compiling..>
$\text{\$}$ sudo pacman -U <generated package file>
\end{shell} \end{shell}
Once all dependencies are taken care of, simply run
Next, use packer to automatically download, build, and install Mitsuba as well as any needed dependencies.
The optional \code{--noedit} flag is used if you do not wish to edit the files after they are downloaded.
The optional \code{--noconfirm} flag is used if you do not wish to confirm each step of the installation.
\begin{shell} \begin{shell}
$\text{\$}$ sudo packer -S --noedit --noconfirm mitsuba-hg glewmx collada-dom $\text{\$}$ scons
\end{shell} \end{shell}
inside the Mitsuba directory. In the case that you have multiple processors, you might want to parallelize the build by appending \code{-j }\emph{core count} to the command.
Periodically you may wish to update Mitsuba to the latest version. If all goes well, SCons should finish successfully within a few minutes:
To do this simply reinstall it and packer will pull and build the latest version.
\begin{shell} \begin{shell}
$\text{\$}$ sudo packer -S --noedit --noconfirm mitsuba-hg scons: $\texttt{done}$ building targets.
\end{shell} \end{shell}
To be able to run the renderer from the command line, you will first have to import it into your path:
Alternatively you can skip using packer and manually download the files and install them one at a time yourself.
First install glewmx
\begin{shell} \begin{shell}
$\text{\$}$ mkdir glewmx && cd glewmx $\text{\$}$ . setpath.sh
$\text{\$}$ wget http://aur.archlinux.org/packages/glewmx/glewmx/PKGBUILD
$\text{\$}$ makepkg -is
\end{shell} \end{shell}
(note the period at the beginning -- this assumes that you are using \code{bash}).
And then collada-dom
\begin{shell}
$\text{\$}$ mkdir collada-dom && cd collada-dom
$\text{\$}$ wget http://aur.archlinux.org/packages/collada-dom/collada-dom/PKGBUILD
$\text{\$}$ makepkg -is
\end{shell}
And finally Mitsuba
\begin{shell}
$\text{\$}$ mkdir mitsuba-hg && cd mitsuba-hg
$\text{\$}$ wget http://aur.archlinux.org/packages/mitsuba-hg/mitsuba-hg/PKGBUILD
$\text{\$}$ makepkg -is
\end{shell}
To uninstall do this
\begin{shell}
$\text{\$}$ sudo pacman -R mitsuba-hg glewmx collada-dom
\end{shell}
After installing you will be able to run the renderer from the command line.
Having set up everything, you can now move on to \secref{basics}. Having set up everything, you can now move on to \secref{basics}.
\subsubsection{Creating Arch Linux packages}
If for some reason you are unable access the Aur files, they are also hosted at Mitsuba ships with a \code{PKGBUILD} file, which automatically builds
(\url{https://www.mitsuba-renderer.org/releases/contrib/archlinux/}). a package from the most recent repository version:
\begin{shell}
$\text{\$}$ makepkg data/linux/arch/mitsuba/PKGBUILD
\end{shell}
\subsection{Building on Windows} \subsection{Building on Windows}
On the Windows platform, Mitsuba already includes most of the dependencies in precompiled form. On the Windows platform, Mitsuba already includes most of the dependencies in precompiled form.

View File

@ -39,4 +39,41 @@ print(myVector * 2)
Log(EInfo, "" +) Log(EInfo, "" +)
\end{python} \end{python}
\subsection{Taking control of the logging system}
Many operations in Mitsuba will print one or more log messages
during their execution. By default, they will be printed to the console,
which may be undesirable. Similar to the C++ side, it is possible to define
custom \code{Formatter} and \code{Appender} classes to interpret and direct
the flow of these messages.
Roughly, a \code{Formatter} turns detailed
information about a logging event into a human-readable string, and a
\code{Appender} routes it to some destination (e.g. by appending it to
a file or a log viewer in a graphical user interface). Here is an example
of how to activate such extensions:
\begin{python}
import mitsuba
from mitsuba.core import *
class MyFormatter(Formatter):
def format(self, logLevel, sourceClass, sourceThread, message, filename, line):
return "%s (log level: %s, thread: %s, class %s, file %s, line %i)" % \
(message, str(logLevel), sourceThread.getName(), sourceClass,
filename, line)
class MyAppender(Appender):
def append(self, logLevel, message):
print(message)
def logProgress(self, progress, name, formatted, eta):
print("Progress message: " + formatted)
# Get the logger associated with the current thread
logger = Thread.getThread().getLogger()
logger.setFormatter(MyFormatter())
logger.clearAppenders()
logger.addAppender(MyAppender())
logger.setLogLevel(EDebug)
Log(EInfo, "Test message")
\end{python}

View File

@ -67,7 +67,7 @@ public:
void save(EFileFormat format, Stream *stream, int compression = 5) const; void save(EFileFormat format, Stream *stream, int compression = 5) const;
/// Return the image's title identifier /// Return the image's title identifier
inline const std::string &getTile() const { return m_title; } inline const std::string &getTitle() const { return m_title; }
/// Return the image's author identifier /// Return the image's author identifier
inline const std::string &getAuthor() const { return m_author; } inline const std::string &getAuthor() const { return m_author; }
@ -90,16 +90,28 @@ public:
/// Set the image's gamma identifier (-1: sRGB) /// Set the image's gamma identifier (-1: sRGB)
inline void setGamma(Float gamma) { m_gamma = gamma; } inline void setGamma(Float gamma) { m_gamma = gamma; }
/// Access the underlying raster /**
* \brief Access the underlying raster
* \remark This function is not exposed in the Python bindings
*/
inline unsigned char *getData() { return m_data; } inline unsigned char *getData() { return m_data; }
/// Access the underlying bit raster /**
* \brief Access the underlying raster
* \remark This function is not exposed in the Python bindings
*/
inline const unsigned char *getData() const { return m_data; } inline const unsigned char *getData() const { return m_data; }
/// Access the underlying raster (only meant for 128bpp images) /**
* \brief Access the underlying raster (128bpp images)
* \remark This function is not exposed in the Python bindings
*/
inline float *getFloatData() { return (float *) m_data; } inline float *getFloatData() { return (float *) m_data; }
/// Access the underlying raster (only meant for 128bpp images) /**
* \brief Access the underlying raster (128bpp images)
* \remark This function is not exposed in the Python bindings
*/
inline const float *getFloatData() const { return (const float *) m_data; } inline const float *getFloatData() const { return (const float *) m_data; }
/// Return the bitmap width /// Return the bitmap width

View File

@ -24,7 +24,6 @@ MTS_NAMESPACE_BEGIN
/** /**
* \headerfile mitsuba/core/class.h mitsuba/mitsuba.h * \headerfile mitsuba/core/class.h mitsuba/mitsuba.h
* \brief Stores meta-information about \ref Object instances. * \brief Stores meta-information about \ref Object instances.
* \ingroup libcore
* *
* This class provides a thin layer of RTTI (run-time type information), * This class provides a thin layer of RTTI (run-time type information),
* which is useful for doing things like: * which is useful for doing things like:
@ -37,6 +36,8 @@ MTS_NAMESPACE_BEGIN
* </ul> * </ul>
* *
* \sa ref, Object * \sa ref, Object
* \ingroup libcore
* \ingroup librender
*/ */
class MTS_EXPORT_CORE Class { class MTS_EXPORT_CORE Class {
public: public:

View File

@ -62,6 +62,8 @@ public:
* *
* In comparison to \ref resolve(), this funtion returns all * In comparison to \ref resolve(), this funtion returns all
* matches instead of only the first one. * matches instead of only the first one.
*
* \remark This function is not exposed in the Python bindings
*/ */
std::vector<fs::path> resolveAll(const fs::path &path) const; std::vector<fs::path> resolveAll(const fs::path &path) const;

View File

@ -24,10 +24,12 @@
MTS_NAMESPACE_BEGIN MTS_NAMESPACE_BEGIN
/** /**
* Basic memory pool -- allows repeated allocation & deallocation * \brief Basic memory pool for efficient allocation and deallocation
* of objects of the same type, while attempting to keep them * of objects of the same type.
* contiguous in memory and having only minimal interaction with the *
* underlying allocator. * This class attempts to keep most instances contiguous in memory, while
* having only minimal interaction with the underlying allocator.
*
* \ingroup libcore * \ingroup libcore
*/ */
template <typename T> class MemoryPool { template <typename T> class MemoryPool {

View File

@ -122,7 +122,11 @@ public:
/// Seed the random generator from another random generator /// Seed the random generator from another random generator
void seed(Random *random); void seed(Random *random);
/// Seed the random generator from an array /**
* \brief Seed the random generator from an array
* \remark This function is currently not exposed
* by the Python bindings
*/
void seed(uint64_t *values, uint64_t length); void seed(uint64_t *values, uint64_t length);
/// Return an integer on the [0, 2^63-1]-interval /// Return an integer on the [0, 2^63-1]-interval
@ -142,6 +146,9 @@ public:
* given STL container. * given STL container.
* *
* See Knuth, TAoCP Vol. 2 (3rd 3d), Section 3.4.2. * See Knuth, TAoCP Vol. 2 (3rd 3d), Section 3.4.2.
*
* \remark This function is currently not exposed
* by the Python bindings
*/ */
template <typename Iterator> void shuffle(Iterator it1, Iterator it2) { template <typename Iterator> void shuffle(Iterator it1, Iterator it2) {
for (Iterator it = it2 - 1; it > it1; --it) for (Iterator it = it2 - 1; it > it1; --it)

View File

@ -108,7 +108,13 @@ struct Ray {
#endif #endif
} }
/// Return 3d coordinates of a point on the ray /**
* \brief Return 3D coordinates of a point along the ray
*
* \remark In the Python bindings, this operator is
* exposed as a function named \c eval -- i.e.
* position lookups should be written as \c ray.eval(t)
*/
inline Point operator() (Float t) const { return o + t * d; } inline Point operator() (Float t) const { return o + t * d; }
/// Return a string representation of this ray /// Return a string representation of this ray

View File

@ -86,8 +86,12 @@ std::string FileResolver::toString() const {
std::ostringstream oss; std::ostringstream oss;
oss << "FileResolver[" << endl oss << "FileResolver[" << endl
<< " paths = {" << endl; << " paths = {" << endl;
for (size_t i=0; i<m_paths.size(); ++i) for (size_t i=0; i<m_paths.size(); ++i) {
oss << " \"" << m_paths[i].file_string() << "\"," << endl; oss << " \"" << m_paths[i].file_string() << "\"";
if (i+1 < m_paths.size())
oss << ",";
oss << endl;
}
oss << " }" << endl oss << " }" << endl
<< "]"; << "]";
return oss.str(); return oss.str();

View File

@ -8,6 +8,8 @@
#include <mitsuba/core/transform.h> #include <mitsuba/core/transform.h>
#include <mitsuba/core/properties.h> #include <mitsuba/core/properties.h>
#include <mitsuba/core/appender.h> #include <mitsuba/core/appender.h>
#include <mitsuba/core/bitmap.h>
#include <mitsuba/core/random.h>
using namespace mitsuba; using namespace mitsuba;
@ -140,6 +142,18 @@ static Float Matrix4x4_getItem(Matrix4x4 *matrix, bp::tuple tuple) {
return matrix->operator()(i, j); return matrix->operator()(i, j);
} }
Class *object_getClass(Object *object) {
return const_cast<Class *>(object->getClass());
}
Class *class_forName(const char *name) {
return const_cast<Class *>(Class::forName(name));
}
Class *class_getSuperClass(Class *theClass) {
return const_cast<Class *>(theClass->getSuperClass());
}
static ref<SerializableObject> instance_manager_getinstance(InstanceManager *manager, Stream *stream) { static ref<SerializableObject> instance_manager_getinstance(InstanceManager *manager, Stream *stream) {
return manager->getInstance(stream); return manager->getInstance(stream);
} }
@ -167,6 +181,25 @@ void mts_log(ELogLevel level, const std::string &msg) {
msg.c_str()); msg.c_str());
} }
class FormatterWrapper : public Formatter {
public:
FormatterWrapper(PyObject *self) : m_self(self) { Py_INCREF(m_self); }
std::string format(ELogLevel logLevel, const Class *theClass,
const Thread *thread, const std::string &text,
const char *file, int line) {
return bp::call_method<std::string>(m_self, "format", logLevel,
bp::ptr(const_cast<Class *>(theClass)),
bp::ptr(const_cast<Thread *>(thread)), text, file, line);
}
virtual ~FormatterWrapper() {
Py_DECREF(m_self);
}
private:
PyObject *m_self;
};
class AppenderWrapper : public Appender { class AppenderWrapper : public Appender {
public: public:
AppenderWrapper(PyObject *self) : m_self(self) { Py_INCREF(m_self); } AppenderWrapper(PyObject *self) : m_self(self) { Py_INCREF(m_self); }
@ -199,12 +232,16 @@ static Spectrum *spectrum_array_constructor(bp::list list) {
return new Spectrum(spec); return new Spectrum(spec);
} }
static Point ray_eval(const Ray &ray, Float t) {
return ray(t);
}
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(fromLinearRGB_overloads, fromLinearRGB, 3, 4) BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(fromLinearRGB_overloads, fromLinearRGB, 3, 4)
BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(fromXYZ_overloads, fromXYZ, 3, 4) BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(fromXYZ_overloads, fromXYZ, 3, 4)
void export_core() { void export_core() {
boost::python::to_python_converter< bp::to_python_converter<fs::path, path_to_python_str>();
fs::path, path_to_python_str>(); bp::implicitly_convertible<std::string, fs::path>();
bp::object coreModule( bp::object coreModule(
bp::handle<>(bp::borrowed(PyImport_AddModule("mitsuba.core")))); bp::handle<>(bp::borrowed(PyImport_AddModule("mitsuba.core"))));
@ -223,8 +260,22 @@ void export_core() {
bp::def("Log", &mts_log); bp::def("Log", &mts_log);
bp::class_<Class, boost::noncopyable>("Class", bp::no_init)
.def("getName", &Class::getName, BP_RETURN_CONSTREF)
.def("isAbstract", &Class::isAbstract)
.def("isInstantiable", &Class::isInstantiable)
.def("isSerializable", &Class::isSerializable)
.def("derivesFrom", &Class::derivesFrom)
.def("getSuperClass", &class_getSuperClass, BP_RETURN_INTREF)
.def("forName", &class_forName, BP_RETURN_INTREF)
.def("unserialize", &Class::unserialize, BP_RETURN_VALUE)
.def("instantiate", &Class::instantiate, BP_RETURN_VALUE)
.staticmethod("forName");
bp::register_ptr_to_python<Class*>();
bp::class_<Object, ref<Object>, boost::noncopyable>("Object", bp::no_init) bp::class_<Object, ref<Object>, boost::noncopyable>("Object", bp::no_init)
.def("getRefCount", &Object::getRefCount) .def("getRefCount", &Object::getRefCount)
.def("getClass", &object_getClass, BP_RETURN_INTREF)
.def("__str__", &Object::toString); .def("__str__", &Object::toString);
bp::register_ptr_to_python<Object*>(); bp::register_ptr_to_python<Object*>();
@ -338,6 +389,9 @@ void export_core() {
.def("append", &Appender::append) .def("append", &Appender::append)
.def("logProgress", &appender_logProgress); .def("logProgress", &appender_logProgress);
BP_WRAPPED_CLASS(Formatter, FormatterWrapper, Object, bp::init<>())
.def("format", &Formatter::format);
Appender *(Logger::*logger_get_appender)(size_t) = &Logger::getAppender; Appender *(Logger::*logger_get_appender)(size_t) = &Logger::getAppender;
BP_CLASS(Logger, Object, bp::init<ELogLevel>()) BP_CLASS(Logger, Object, bp::init<ELogLevel>())
.def("logProgress", logger_logProgress) .def("logProgress", logger_logProgress)
@ -350,6 +404,8 @@ void export_core() {
.def("clearAppenders", &Logger::clearAppenders) .def("clearAppenders", &Logger::clearAppenders)
.def("getAppenderCount", &Logger::getAppenderCount) .def("getAppenderCount", &Logger::getAppenderCount)
.def("getAppender", logger_get_appender, BP_RETURN_VALUE) .def("getAppender", logger_get_appender, BP_RETURN_VALUE)
.def("getFormatter", &Logger::getFormatter, BP_RETURN_VALUE)
.def("setFormatter", &Logger::setFormatter)
.def("getWarningCount", &Logger::getWarningCount); .def("getWarningCount", &Logger::getWarningCount);
BP_CLASS(InstanceManager, Object, bp::init<>()) BP_CLASS(InstanceManager, Object, bp::init<>())
@ -369,6 +425,56 @@ void export_core() {
.def("clear", &InterpolatedSpectrum::clear) .def("clear", &InterpolatedSpectrum::clear)
.def("zeroExtend", &InterpolatedSpectrum::zeroExtend); .def("zeroExtend", &InterpolatedSpectrum::zeroExtend);
BP_CLASS(Bitmap, Object, (bp::init<int, int, int>()))
.def(bp::init<Bitmap::EFileFormat, Stream *>())
.def("clone", &Bitmap::clone, BP_RETURN_VALUE)
.def("clear", &Bitmap::clear)
.def("save", &Bitmap::save)
.def("setTitle", &Bitmap::setTitle)
.def("getTitle", &Bitmap::getTitle, BP_RETURN_INTREF)
.def("setAuthor", &Bitmap::setAuthor)
.def("getAuthor", &Bitmap::getAuthor, BP_RETURN_INTREF)
.def("setComment", &Bitmap::setComment)
.def("getComment", &Bitmap::getComment, BP_RETURN_INTREF)
.def("setGamma", &Bitmap::setGamma)
.def("getGamma", &Bitmap::getGamma)
.def("getWidth", &Bitmap::getWidth)
.def("getHeight", &Bitmap::getHeight)
.def("getBitsPerPixel", &Bitmap::getBitsPerPixel)
.def("getSize", &Bitmap::getSize);
BP_SETSCOPE(Bitmap_class);
bp::enum_<Bitmap::EFileFormat>("EFileFormat")
.value("EPNG", Bitmap::EPNG)
.value("EEXR", Bitmap::EEXR)
.value("ETGA", Bitmap::ETGA)
.value("EBMP", Bitmap::EBMP)
.value("EJPEG", Bitmap::EJPEG)
.export_values();
BP_SETSCOPE(coreModule);
BP_CLASS(FileResolver, Object, bp::init<>())
.def("resolve", &FileResolver::resolve, BP_RETURN_VALUE)
.def("resolveAbsolute", &FileResolver::resolveAbsolute, BP_RETURN_VALUE)
.def("clone", &FileResolver::clone, BP_RETURN_VALUE)
.def("addPath", &FileResolver::addPath)
.def("clear", &FileResolver::clear);
void (Random::*random_seed_random)(Random *) = &Random::seed;
void (Random::*random_seed_uint64_t)(uint64_t) = &Random::seed;
BP_CLASS(Random, Object, bp::init<>())
.def(bp::init<uint64_t>())
.def(bp::init<Random *>())
.def(bp::init<Stream *, InstanceManager *>())
.def("set", &Random::set)
.def("seed", random_seed_random)
.def("seed", random_seed_uint64_t)
.def("nextULong", &Random::nextULong)
.def("nextUInt", &Random::nextUInt)
.def("nextSize", &Random::nextSize)
.def("nextFloat", &Random::nextFloat)
.def("serialize", &Random::serialize);
BP_STRUCT(Spectrum, bp::init<>()) BP_STRUCT(Spectrum, bp::init<>())
.def("__init__", bp::make_constructor(spectrum_array_constructor)) .def("__init__", bp::make_constructor(spectrum_array_constructor))
.def(bp::init<Float>()) .def(bp::init<Float>())
@ -610,6 +716,23 @@ void export_core() {
.def(bp::self /= Float()) .def(bp::self /= Float())
.def("__str__", &Matrix4x4::toString); .def("__str__", &Matrix4x4::toString);
bp::class_<Ray>("Ray", bp::init<>())
.def(bp::init<Ray &>())
.def(bp::init<Ray &, Float, Float>())
.def(bp::init<Point, Vector, Float>())
.def(bp::init<Point, Vector, Float, Float, Float>())
.def_readwrite("o", &Ray::o)
.def_readwrite("d", &Ray::d)
.def_readwrite("dRcp", &Ray::dRcp)
.def_readwrite("mint", &Ray::mint)
.def_readwrite("maxt", &Ray::maxt)
.def_readwrite("time", &Ray::time)
.def("setOrigin", &Ray::setOrigin)
.def("setDirection", &Ray::setDirection)
.def("setTime", &Ray::setTime)
.def("eval", &ray_eval, BP_RETURN_VALUE)
.def("__str__", &Ray::toString);
bp::detail::current_scope = oldScope; bp::detail::current_scope = oldScope;
} }