diff --git a/doc/main.tex b/doc/main.tex index f4b3c7a0..3d96ac41 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -27,6 +27,7 @@ \usepackage{ifthen} \usepackage{longtable} \usepackage{wrapfig} +\usepackage{footnote} % savenotes environment % Make sure that ligatures remain searchable in the PDF \input glyphtounicode diff --git a/include/mitsuba/core/util.h b/include/mitsuba/core/util.h index 7bd67cb6..37b7c8db 100644 --- a/include/mitsuba/core/util.h +++ b/include/mitsuba/core/util.h @@ -58,7 +58,7 @@ extern MTS_EXPORT_CORE std::string formatString(const char *pFmt, ...); extern MTS_EXPORT_CORE std::string timeString(Float time, bool precise = false); /// Turn a memory size into a human-readable string -extern MTS_EXPORT_CORE std::string memString(size_t size); +extern MTS_EXPORT_CORE std::string memString(size_t size, bool precise = false); /// Return a string representation of a list of objects template std::string containerToString(const Iterator &start, const Iterator &end) { diff --git a/include/mitsuba/mitsuba.h b/include/mitsuba/mitsuba.h index d097e798..246b724e 100644 --- a/include/mitsuba/mitsuba.h +++ b/include/mitsuba/mitsuba.h @@ -45,7 +45,6 @@ using std::endl; #include #include #include -#include #include #include #include diff --git a/src/films/annotations.h b/src/films/annotations.h index 6d041e03..3ae47777 100644 --- a/src/films/annotations.h +++ b/src/films/annotations.h @@ -75,48 +75,68 @@ void annotate(const Scene *scene, const Properties &properties, if (!(strt = strchr((char *) value.c_str(), '$'))) break; - if (strncasecmp(strt, "$rendertime", 11) == 0) { - value.replace(strt-value.c_str(), 11, timeString(renderTime)); - } else if (strncasecmp(strt, "$memusage", 11) == 0) { - value.replace(strt-value.c_str(), 11, memString(getPrivateMemoryUsage())); - } else { - char *par1, *par2; - if (!(par1 = strchr(strt, '['))) - break; - if (!(par2 = strchr(par1, ']'))) - break; + char *par1, *par2; + if (!(par1 = strchr(strt, '['))) + break; + if (!(par2 = strchr(par1, ']'))) + break; - std::string propSource = value.substr(strt-value.c_str()+1, par1-strt-1); - std::string propKey = value.substr(par1-value.c_str()+1, par2-par1-1); - propSource.erase(std::remove_if(propSource.begin(), propSource.end(), ::isspace), propSource.end()); - propKey.erase(std::remove_if(propKey.begin(), propKey.end(), ::isspace), propKey.end()); + std::string propSource = value.substr(strt-value.c_str()+1, par1-strt-1); + std::string propKey = value.substr(par1-value.c_str()+1, par2-par1-1); + propSource.erase(std::remove_if(propSource.begin(), propSource.end(), ::isspace), propSource.end()); + propKey.erase(std::remove_if(propKey.begin(), propKey.end(), ::isspace), propKey.end()); - if (!boost::starts_with(propKey, "'") || !boost::ends_with(propKey, "'")) - SLog(EError, "Encountered invalid key '%s'", propKey.c_str()); + if (!boost::starts_with(propKey, "'") || !boost::ends_with(propKey, "'")) + SLog(EError, "Encountered invalid key '%s'", propKey.c_str()); - propKey = propKey.substr(1, propKey.length()-2); + propKey = propKey.substr(1, propKey.length()-2); - const ConfigurableObject *source = NULL; - if (propSource == "film") - source = scene->getFilm(); - else if (propSource == "sampler") - source = scene->getSampler(); - else if (propSource == "sensor") - source = scene->getSensor(); - else if (propSource == "integrator") - source = scene->getIntegrator(); - else - SLog(EError, "Unknown data source '%s' (must be film/sampler/sensor/integrator)", propSource.c_str()); + const ConfigurableObject *source = NULL; + if (propSource == "scene") + source = scene; + else if (propSource == "film") + source = scene->getFilm(); + else if (propSource == "sampler") + source = scene->getSampler(); + else if (propSource == "sensor") + source = scene->getSensor(); + else if (propSource == "integrator") + source = scene->getIntegrator(); + else + SLog(EError, "Unknown data source '%s' (must be film/sampler/sensor/integrator)", propSource.c_str()); - std::string replacement; + std::string replacement; + + if (source == scene) { + if (propKey == "renderTime") { + replacement = timeString(renderTime); + } else if (propKey == "renderTimePrecise") { + replacement = timeString(renderTime, true); + } else if (propKey == "memUsage") { + replacement = memString(getPrivateMemoryUsage()); + } else if (propKey == "memUsagePrecise") { + replacement = memString(getPrivateMemoryUsage(), true); + } else if (propKey == "coreCount") { + replacement = formatString("%i", Scheduler::getInstance()->getCoreCount()); + } else if (propKey == "blockSize") { + replacement = formatString("%i", scene->getBlockSize()); + } else if (propKey == "sourceFile") { + replacement = scene->getSourceFile().string(); + } else if (propKey == "destFile") { + replacement = scene->getDestinationFile().string(); + } + } + + if (replacement.empty()) { if (propKey == "type") replacement = source->getProperties().getPluginName(); else replacement = source->getProperties().getAsString(propKey); - - value.replace(strt-value.c_str(), par2-strt+1, replacement); } + + value.replace(strt-value.c_str(), par2-strt+1, replacement); } + if (labelAnnotation) { Vector2i size = font->getSize(value); bitmap->fillRect(offset-Vector2i(4, 4), size + Vector2i(8, 8), Spectrum(0.0f)); diff --git a/src/films/hdrfilm.cpp b/src/films/hdrfilm.cpp index 8bb01a3c..c72facab 100644 --- a/src/films/hdrfilm.cpp +++ b/src/films/hdrfilm.cpp @@ -117,33 +117,64 @@ MTS_NAMESPACE_BEGIN * * \end{xml} * - * \subsubsection*{Annotations:} + * \subsubsection*{Render-time 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. - * + * The \pluginref{ldrfilm} and \pluginref{hdrfilm} plugins support a + * feature referred to as \emph{render-time annotations} to facilitate + * record keeping. * 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. + * rendering time, memory usage, camera parameters, or other relevant scene + * information. * + * Currently, two different types are supported: a \code{metadata} annotation + * creates an entry in the metadata table of the image, which is preferable + * when the image contents should not be touched. Alternatively, a \code{label} + * annotation creates a line of text that is overlaid on top of the image. Note + * that this is only visible when opening the output file (i.e. the line is not + * shown in the interactive viewer). * The syntax of this looks as follows: * * \begin{xml} - * - * - * + * + * + * * * - * + * * * \end{xml} + * + * The \code{value="..."} argument may also include certain identifiers that will be + * evaluated and substituted when the rendered image is written to disk. These include + * \begin{center} + * \begin{savenotes} + * \begin{tabular}{ll} + * \toprule + * \code{\$scene['renderTime']}& Render time of the image, \code{renderTimePrecise} for more digits.\\ + * \code{\$scene['memUsage']}& Mitsuba memory usage\footnote{The definition of this quantity unfortunately + * varies a bit from platform to platform. On Linux and Windows, it denotes the total + * amount of allocated RAM and disk-based memory that is private to the process (i.e. not + * shared or shareable), which most intuitively captures the amount of memory required for + * rendering. On OSX, it denotes the working set size---roughly speaking, this is the + * amount of RAM apportioned to the process (i.e. excluding disk-based memory).}. + * Use \code{memUsagePrecise} for more digits.\\ + * \code{\$scene['coreCount']}& Number of local and remote cores working on the rendering job\\ + * \code{\$scene['blockSize']}& Block size used to parallelize up the rendering workload\\ + * \code{\$scene['sourceFile']}& Source file name\\ + * \code{\$scene['destFile']}& Destination file name\\ + * \code{\$integrator['..']}& Copy a named integrator parameter\\ + * \code{\$sensor['..']}& Copy a named sensor parameter\\ + * \code{\$sampler['..']}& Copy a named sampler parameter\\ + * \code{\$film['..']}& Copy a named film parameter\\ + * \bottomrule + * \end{tabular} + * \end{savenotes} + * \end{center} */ + class HDRFilm : public Film { public: HDRFilm(const Properties &props) : Film(props) { diff --git a/src/libcore/util.cpp b/src/libcore/util.cpp index c0cbb270..afe999ac 100644 --- a/src/libcore/util.cpp +++ b/src/libcore/util.cpp @@ -123,19 +123,6 @@ std::string indent(const std::string &string, int amount) { return oss.str(); } -std::string memString(size_t size) { - Float value = (Float) size; - const char *prefixes[] = { - "B", "KiB", "MiB", "GiB", "TiB", "PiB" - }; - int prefix = 0; - while (prefix < 5 && value > 1024.0f) { - value /= 1024.0f; ++prefix; - } - return formatString(prefix == 0 ? - "%.0f %s" : "%.2f %s", value, prefixes[prefix]); -} - void * __restrict allocAligned(size_t size) { #if defined(__WINDOWS__) return _aligned_malloc(size, L1_CACHE_LINE_SIZE); @@ -809,8 +796,6 @@ Float fresnelDiffuseReflectance(Float eta, bool fast) { } std::string timeString(Float time, bool precise) { - std::ostringstream os; - if (std::isnan(time) || std::isinf(time)) return "inf"; @@ -825,12 +810,31 @@ std::string timeString(Float time, bool precise) { } } + std::ostringstream os; os << std::setprecision(precise ? 4 : 1) << std::fixed << time << suffix; return os.str(); } +std::string memString(size_t size, bool precise) { + Float value = (Float) size; + const char *suffixes[] = { + "B", "KiB", "MiB", "GiB", "TiB", "PiB" + }; + int suffix = 0; + while (suffix < 5 && value > 1024.0f) { + value /= 1024.0f; ++suffix; + } + + std::ostringstream os; + os << std::setprecision(suffix == 0 ? 0 : (precise ? 4 : 1)) + << std::fixed << value << suffixes[suffix]; + + return os.str(); +} + + Float hypot2(Float a, Float b) { Float r; if (std::abs(a) > std::abs(b)) { diff --git a/src/shapes/instance.cpp b/src/shapes/instance.cpp index 3604d319..c240fbb2 100644 --- a/src/shapes/instance.cpp +++ b/src/shapes/instance.cpp @@ -37,7 +37,7 @@ MTS_NAMESPACE_BEGIN * A visualization of a fractal surface by Irving and Segerman. * (a 2D Gospel curve developed up to level 5 along the third * dimension). This scene makes use of instancing to replicate - * similar structures to cheaply render a structure that effectively + * similar structures to cheaply render a shape that effectively * consists of several hundred millions of triangles. * } * }