added fancy annotations to ldrfilm
parent
aaa16f129c
commit
89c1caed9b
|
@ -8,8 +8,8 @@ macro(add_film)
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
add_film(mfilm mfilm.cpp)
|
add_film(mfilm mfilm.cpp)
|
||||||
add_film(ldrfilm ldrfilm.cpp banner.h MTS_HW)
|
add_film(ldrfilm ldrfilm.cpp annotations.h banner.h MTS_HW)
|
||||||
add_film(hdrfilm hdrfilm.cpp banner.h MTS_HW)
|
add_film(hdrfilm hdrfilm.cpp annotations.h banner.h MTS_HW)
|
||||||
|
|
||||||
if (OPENEXR_FOUND)
|
if (OPENEXR_FOUND)
|
||||||
include_directories(${ILMBASE_INCLUDE_DIRS} ${OPENEXR_INCLUDE_DIRS})
|
include_directories(${ILMBASE_INCLUDE_DIRS} ${OPENEXR_INCLUDE_DIRS})
|
||||||
|
|
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
This file is part of Mitsuba, a physically based rendering system.
|
||||||
|
|
||||||
|
Copyright (c) 2007-2012 by Wenzel Jakob and others.
|
||||||
|
|
||||||
|
Mitsuba is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License Version 3
|
||||||
|
as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
Mitsuba is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#if !defined(__ANNOTATIONS_H)
|
||||||
|
#define __ANNOTATIONS_H
|
||||||
|
|
||||||
|
#include <mitsuba/hw/font.h>
|
||||||
|
#include <mitsuba/render/scene.h>
|
||||||
|
|
||||||
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function implements a parser for the 'label[]' and 'metadata[]'
|
||||||
|
* annotations supported by the ldrfilm and hdrfilm plugins
|
||||||
|
*/
|
||||||
|
void annotate(const Scene *scene, const Properties &properties,
|
||||||
|
Bitmap *bitmap, Float renderTime, Float gamma) {
|
||||||
|
/* Attach the custom annotations */
|
||||||
|
Properties &metadata = bitmap->getMetadata();
|
||||||
|
std::vector<std::string> keys = properties.getPropertyNames();
|
||||||
|
ref<Font> font;
|
||||||
|
|
||||||
|
for (size_t i=0; i<keys.size(); ++i) {
|
||||||
|
std::string key = keys[i];
|
||||||
|
key.erase(std::remove_if(key.begin(), key.end(), ::isspace), key.end());
|
||||||
|
std::string lkey = boost::to_lower_copy(key);
|
||||||
|
Point2i offset(0, 0);
|
||||||
|
bool labelAnnotation = false;
|
||||||
|
|
||||||
|
if (boost::starts_with(lkey, "metadata['") && boost::ends_with(lkey, "']")) {
|
||||||
|
key = key.substr(10, key.length()-12);
|
||||||
|
} else if (boost::starts_with(lkey, "label[") && boost::ends_with(lkey, "]")) {
|
||||||
|
std::vector<std::string> args = tokenize(key.substr(6, key.length()-7), " ,");
|
||||||
|
if (args.size() != 2)
|
||||||
|
SLog(EError, "Label command '%s' has an invalid number of arguments!", key.c_str());
|
||||||
|
char *end_ptr = NULL;
|
||||||
|
offset.x = strtol(args[0].c_str(), &end_ptr, 10);
|
||||||
|
if (*end_ptr != '\0')
|
||||||
|
SLog(EError, "Label command '%s' has an invalid position argument!", key.c_str());
|
||||||
|
offset.y = strtol(args[1].c_str(), &end_ptr, 10);
|
||||||
|
if (*end_ptr != '\0')
|
||||||
|
SLog(EError, "Label command '%s' has an invalid position argument!", key.c_str());
|
||||||
|
labelAnnotation = true;
|
||||||
|
|
||||||
|
if (font == NULL) {
|
||||||
|
font = new Font(Font::EBitstreamVeraMono14);
|
||||||
|
font->convert(bitmap->getPixelFormat(), bitmap->getComponentFormat(), gamma);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Properties::EPropertyType type = properties.getType(keys[i]);
|
||||||
|
if (type == Properties::EString) {
|
||||||
|
std::string value = properties.getString(keys[i]);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
char *strt;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
std::string replacement;
|
||||||
|
if (propKey == "type")
|
||||||
|
replacement = source->getProperties().getPluginName();
|
||||||
|
else
|
||||||
|
replacement = source->getProperties().getAsString(propKey);
|
||||||
|
|
||||||
|
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));
|
||||||
|
font->drawText(bitmap, offset, value);
|
||||||
|
} else {
|
||||||
|
metadata.setString(key, value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (labelAnnotation)
|
||||||
|
SLog(EError, "Only string-valued label annotations are supported!");
|
||||||
|
metadata.copyAttribute(properties, keys[i], key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MTS_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif /* __ANNOTATIONS_H */
|
|
@ -20,10 +20,9 @@
|
||||||
#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 <mitsuba/render/scene.h>
|
|
||||||
#include "banner.h"
|
#include "banner.h"
|
||||||
|
#include "annotations.h"
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
@ -369,107 +368,7 @@ public:
|
||||||
Log(EInfo, "Writing image to \"%s\" ..", filename.string().c_str());
|
Log(EInfo, "Writing image to \"%s\" ..", filename.string().c_str());
|
||||||
ref<FileStream> stream = new FileStream(filename, FileStream::ETruncWrite);
|
ref<FileStream> stream = new FileStream(filename, FileStream::ETruncWrite);
|
||||||
|
|
||||||
/* Attach the custom annotations */
|
annotate(scene, m_properties, bitmap, renderTime, 1.0f);
|
||||||
Properties &metadata = bitmap->getMetadata();
|
|
||||||
std::vector<std::string> keys = m_properties.getPropertyNames();
|
|
||||||
ref<Font> font;
|
|
||||||
Float gamma = 1.0f; /// XXX
|
|
||||||
|
|
||||||
for (size_t i=0; i<keys.size(); ++i) {
|
|
||||||
std::string key = keys[i];
|
|
||||||
key.erase(std::remove_if(key.begin(), key.end(), ::isspace), key.end());
|
|
||||||
std::string lkey = boost::to_lower_copy(key);
|
|
||||||
Point2i offset(0, 0);
|
|
||||||
bool labelAnnotation = false;
|
|
||||||
|
|
||||||
if (boost::starts_with(lkey, "metadata['") && boost::ends_with(lkey, "']")) {
|
|
||||||
key = key.substr(10, key.length()-12);
|
|
||||||
} else if (boost::starts_with(lkey, "label[") && boost::ends_with(lkey, "]")) {
|
|
||||||
std::vector<std::string> args = tokenize(key.substr(6, key.length()-7), " ,");
|
|
||||||
if (args.size() != 2)
|
|
||||||
Log(EError, "Label command '%s' has an invalid number of arguments!", key.c_str());
|
|
||||||
char *end_ptr = NULL;
|
|
||||||
offset.x = strtol(args[0].c_str(), &end_ptr, 10);
|
|
||||||
if (*end_ptr != '\0')
|
|
||||||
Log(EError, "Label command '%s' has an invalid position argument!", key.c_str());
|
|
||||||
offset.y = strtol(args[1].c_str(), &end_ptr, 10);
|
|
||||||
if (*end_ptr != '\0')
|
|
||||||
Log(EError, "Label command '%s' has an invalid position argument!", key.c_str());
|
|
||||||
labelAnnotation = true;
|
|
||||||
|
|
||||||
if (font == NULL) {
|
|
||||||
font = new Font(Font::EBitstreamVeraMono14);
|
|
||||||
font->convert(bitmap->getPixelFormat(), bitmap->getComponentFormat(), gamma);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Properties::EPropertyType type = m_properties.getType(keys[i]);
|
|
||||||
if (type == Properties::EString) {
|
|
||||||
std::string value = m_properties.getString(keys[i]);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
char *strt;
|
|
||||||
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;
|
|
||||||
|
|
||||||
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, "'"))
|
|
||||||
Log(EError, "Encountered invalid key '%s'", propKey.c_str());
|
|
||||||
|
|
||||||
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
|
|
||||||
Log(EError, "Unknown data source '%s' (must be film/sampler/sensor/integrator)", propSource.c_str());
|
|
||||||
|
|
||||||
std::string replacement;
|
|
||||||
if (propKey == "type")
|
|
||||||
replacement = source->getProperties().getPluginName();
|
|
||||||
else
|
|
||||||
replacement = source->getProperties().getAsString(propKey);
|
|
||||||
|
|
||||||
value.replace(strt-value.c_str(), par2-strt+1, replacement);
|
|
||||||
}
|
|
||||||
cout << value << endl;
|
|
||||||
}
|
|
||||||
if (labelAnnotation) {
|
|
||||||
Vector2i size = font->getSize(value);
|
|
||||||
bitmap->fillRect(offset-Vector2i(4, 4), size + Vector2i(8, 8), Spectrum(0.0f));
|
|
||||||
font->drawText(bitmap, offset, value);
|
|
||||||
} else {
|
|
||||||
metadata.setString(key, value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (labelAnnotation)
|
|
||||||
Log(EError, "Only string-valued label annotations are supported!");
|
|
||||||
metadata.copyAttribute(m_properties, keys[i], key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Attach the log file to the image if this is requested */
|
/* Attach the log file to the image if this is requested */
|
||||||
Logger *logger = Thread::getThread()->getLogger();
|
Logger *logger = Thread::getThread()->getLogger();
|
||||||
|
@ -477,7 +376,7 @@ public:
|
||||||
if (m_attachLog && logger->readLog(log)) {
|
if (m_attachLog && logger->readLog(log)) {
|
||||||
log += "\n\n";
|
log += "\n\n";
|
||||||
log += Statistics::getInstance()->getStats();
|
log += Statistics::getInstance()->getStats();
|
||||||
metadata.setString("log", log);
|
bitmap->setMetadataString("log", log);
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap->write(m_fileFormat, stream);
|
bitmap->write(m_fileFormat, stream);
|
||||||
|
@ -516,11 +415,6 @@ 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;
|
||||||
|
|
|
@ -20,9 +20,9 @@
|
||||||
#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"
|
||||||
|
#include "annotations.h"
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
@ -185,20 +185,11 @@ public:
|
||||||
std::vector<std::string> keys = props.getPropertyNames();
|
std::vector<std::string> keys = props.getPropertyNames();
|
||||||
for (size_t i=0; i<keys.size(); ++i) {
|
for (size_t i=0; i<keys.size(); ++i) {
|
||||||
std::string key = boost::to_lower_copy(keys[i]);
|
std::string key = boost::to_lower_copy(keys[i]);
|
||||||
|
key.erase(std::remove_if(key.begin(), key.end(), ::isspace), key.end());
|
||||||
|
|
||||||
if (boost::starts_with(key, "tag('") && boost::ends_with(key, "')")) {
|
if ((boost::starts_with(key, "tag('") && boost::ends_with(key, "')")) ||
|
||||||
m_tags[keys[i].substr(5, key.length()-7)] = props.getString(keys[i]);
|
(boost::starts_with(key, "text(") && boost::ends_with(key, ")")))
|
||||||
} else if (boost::starts_with(key, "text(") && boost::ends_with(key, ")")) {
|
props.markQueried(keys[i]);
|
||||||
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);
|
||||||
|
@ -338,23 +329,6 @@ 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->setMetadataString(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;
|
||||||
|
@ -370,6 +344,8 @@ public:
|
||||||
Log(EInfo, "Writing image to \"%s\" ..", filename.string().c_str());
|
Log(EInfo, "Writing image to \"%s\" ..", filename.string().c_str());
|
||||||
ref<FileStream> stream = new FileStream(filename, FileStream::ETruncWrite);
|
ref<FileStream> stream = new FileStream(filename, FileStream::ETruncWrite);
|
||||||
|
|
||||||
|
annotate(scene, m_properties, bitmap, renderTime, m_gamma);
|
||||||
|
|
||||||
bitmap->write(m_fileFormat, stream);
|
bitmap->write(m_fileFormat, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -415,11 +391,6 @@ 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;
|
||||||
|
@ -428,9 +399,6 @@ 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)
|
||||||
|
|
Loading…
Reference in New Issue