diff --git a/.hgignore b/.hgignore
index 0d6d76d8..313c65b5 100644
--- a/.hgignore
+++ b/.hgignore
@@ -1,10 +1,11 @@
# Documentation
-^doc/doxygen/.*$
+^doc/apidocs/.*$
^doc/.*\.aux$
^doc/.*\.log$
^doc/.*\.out$
^doc/.*\.pdf$
^doc/.*\.toc$
+^doc/plugins_generated.tex$
# Build-related
^\.sconf_temp/.*$
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 4b74373c..e94a0d74 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NUMBER = 0.2.0
# If a relative path is entered, it will be relative to the location
# where doxygen was started. If left blank the current directory will be used.
-OUTPUT_DIRECTORY = doc/doxygen
+OUTPUT_DIRECTORY = doc/apidocs
# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
# 4096 sub-directories (in 2 levels) under the output directory of each output
@@ -789,7 +789,7 @@ GENERATE_HTML = YES
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
# put in front of it. If left blank `html' will be used as the default path.
-HTML_OUTPUT = html
+HTML_OUTPUT = .
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
@@ -1198,7 +1198,7 @@ MAN_LINKS = NO
# generate an XML file that captures the structure of
# the code including all documentation.
-GENERATE_XML = YES
+GENERATE_XML = NO
# The XML_OUTPUT tag is used to specify where the XML pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be
diff --git a/doc/gendoc.py b/doc/gendoc.py
new file mode 100755
index 00000000..cbeabbb4
--- /dev/null
+++ b/doc/gendoc.py
@@ -0,0 +1,48 @@
+#! /usr/bin/python
+#
+# This script walks through all plugin files and
+# extracts documentation that should go into the
+# reference manual
+
+import os, re
+
+def process(target, filename):
+ f = open(filename)
+ inheader = False
+ for line in f.readlines():
+ match = re.match(r'^/\*!(.*)$', line)
+ if match != None:
+ print("Processing %s" % filename)
+ line = match.group(1).replace('%', '\%')
+ target.write(line + '\n')
+ inheader = True
+ continue
+ if not inheader:
+ continue
+ if re.search(r'^[\s\*]*\*/$', line):
+ inheader = False
+ continue
+ match = re.match(r'^\s*\**(.*)$', line)
+ if match != None:
+ line = match.group(1).replace('%', '\%')
+ target.write(line + '\n')
+ f.close()
+
+# Traverse all source directories and find any plugin code
+def traverse(target, dirname, files):
+ suffix = os.path.split(dirname)[1]
+ if 'lib' in suffix or suffix == 'tests' \
+ or suffix == 'mitsuba' or suffix == 'utils' \
+ or suffix == 'converter' or suffix == 'qtgui':
+ return
+
+ for filename in files:
+ if '.cpp' == os.path.splitext(filename)[1]:
+ process(target,os.path.join(dirname, filename))
+
+os.chdir(os.path.dirname(__file__))
+f = open('plugins_generated.tex', 'w')
+f.write('\section{Plugin reference}\n')
+os.path.walk('../src', traverse, f)
+f.close()
+os.system('pdflatex main.tex')
diff --git a/doc/main.tex b/doc/main.tex
index 2dc3af17..11ba9479 100644
--- a/doc/main.tex
+++ b/doc/main.tex
@@ -62,9 +62,12 @@
% Cite a figure/listing
\newcommand{\cfig}[1]{\mbox{Figure \ref{fig:#1}}}
\newcommand{\clst}[1]{\mbox{Listing \ref{lst:#1}}}
-
\newcommand{\code}[1]{\texttt{#1}}
+% Macros for plugin documentation
+\newcommand{\plugin}[2]{\subsection{#2 (\texttt{#1})}\label{plg:#1}}
+\newcommand{\pluginref}[1]{\texttt{\hyperref[plg:#1]{#1}}}
+
% Listings settings
\lstset{
mathescape = true,
@@ -107,16 +110,16 @@
\tableofcontents
-\include{introduction}
-\include{compiling}
-\include{basics}
-\include{format}
-\include{plugins}
-\include{import}
-\include{development}
-\include{integrator}
-\include{parallelization}
-\include{acknowledgements}
+%\include{introduction}
+%\include{compiling}
+%\include{basics}
+%\include{format}
+\IfFileExists{plugins_generated.tex}{\include{plugins_generated}}{}
+%\include{import}
+%\include{development}
+%\include{integrator}
+%\include{parallelization}
+%\include{acknowledgements}
\end{document}
diff --git a/doc/plugins.tex b/doc/plugins.tex
deleted file mode 100644
index bfb266de..00000000
--- a/doc/plugins.tex
+++ /dev/null
@@ -1,2 +0,0 @@
-\section{Plugin reference}
-TBD
diff --git a/src/bsdfs/lambertian.cpp b/src/bsdfs/lambertian.cpp
index 020bcdc2..91a90026 100644
--- a/src/bsdfs/lambertian.cpp
+++ b/src/bsdfs/lambertian.cpp
@@ -23,20 +23,24 @@
MTS_NAMESPACE_BEGIN
-/*!
-The Lambertian material represents a one-sided ideal diffuse material
-with the specified amount of reflectance. Optionally, a texture map may
-be applied. If no extra information is provided, the material will revert to
-the default of uniform 50% reflectance.
-
-Seen from the back side, this material will appear completely black.
-
-\verbatim
-
-
-
-\endverbatim
-*/
+/*! \plugin{lambertian}{Ideally diffuse / Lambertian material}
+ *
+ * The Lambertian material represents an ideally diffuse material
+ * with the specified amount of reflectance. When nothing is specified,
+ * the default of 50% reflectance is used.
+ *
+ * Optionally, a texture map may be applied.
+ *
+ * Note that this material is one-sided --- that is, observed from the
+ * back side, it will be completely black. If this is undesirable,
+ * consider using the \pluginref{twosided} BRDF adapter plugin.
+ *
+ * \begin{xml}
+ *
+ *
+ *
+ * \end{xml}
+ */
class Lambertian : public BSDF {
public:
Lambertian(const Properties &props)
diff --git a/src/bsdfs/twosided.cpp b/src/bsdfs/twosided.cpp
index 58d02d82..c0324aa0 100644
--- a/src/bsdfs/twosided.cpp
+++ b/src/bsdfs/twosided.cpp
@@ -22,10 +22,16 @@
MTS_NAMESPACE_BEGIN
-/**
- * Turns a one-sided BRDF onto a two-sided one that
- * can be used to render meshes where the back-side
- * is visible.
+/*! \plugin{twosided}{Two-sided BRDF adapter}
+ *
+ * Turns a nested one-sided BRDF onto a two-sided version that
+ * can be used to render meshes where the back-side is visible.
+ *
+ * \begin{xml}
+ *
+ *
+ *
+ * \end{xml}
*/
class TwoSidedBRDF : public BSDF {
public: