merged with main branch

metadata
Wenzel Jakob 2010-09-02 22:39:27 +02:00
commit dc8aed1aaf
39 changed files with 1322 additions and 1093 deletions

View File

@ -277,6 +277,12 @@ env.Append(LIBPATH=['src/libcore'])
# Rendering-specific library
renderEnv = env.Clone()
renderEnv.Append(CPPDEFINES = {'MTS_BUILD_MODULE' : 'MTS_MODULE_RENDER'} )
if renderEnv.has_key('XERCESINCLUDE'):
renderEnv.Append(CPPPATH=renderEnv['XERCESINCLUDE'])
if renderEnv.has_key('XERCESLIBDIR'):
renderEnv.Append(LIBPATH=renderEnv['XERCESLIBDIR'])
if renderEnv.has_key('XERCESLIB'):
renderEnv.Append(LIBS=renderEnv['XERCESLIB'])
librender = renderEnv.SharedLibrary('src/librender/mitsuba-render', [
'src/librender/bsdf.cpp', 'src/librender/camera.cpp',
'src/librender/film.cpp', 'src/librender/integrator.cpp',
@ -295,7 +301,8 @@ librender = renderEnv.SharedLibrary('src/librender/mitsuba-render', [
'src/librender/preview.cpp', 'src/librender/photonmap.cpp',
'src/librender/gatherproc.cpp', 'src/librender/mipmap3d.cpp',
'src/librender/volume.cpp', 'src/librender/vpl.cpp',
'src/librender/shader.cpp'
'src/librender/shader.cpp', 'src/librender/shandler.cpp',
'src/librender/util.cpp'
])
if sys.platform == "darwin":
@ -353,12 +360,6 @@ env['SHLIBPREFIX']=''
# Environment with Xerces + wxWidgets
mainEnv = env.Clone()
if mainEnv.has_key('XERCESINCLUDE'):
mainEnv.Append(CPPPATH=mainEnv['XERCESINCLUDE'])
if mainEnv.has_key('XERCESLIBDIR'):
mainEnv.Append(LIBPATH=mainEnv['XERCESLIBDIR'])
if mainEnv.has_key('XERCESLIB'):
mainEnv.Append(LIBS=mainEnv['XERCESLIB'])
if mainEnv.has_key('GLLIB'):
mainEnv.Append(LIBS=mainEnv['GLLIB'])
if mainEnv.has_key('GLLIBDIR'):
@ -374,12 +375,11 @@ darwinStub = []
if sys.platform == 'win32':
resources += [env.RES('tools/windows/mitsuba_res.rc'),
env.StaticObject('src/mitsuba/getopt.c')]
shandler = mainEnv.StaticObject('src/mitsuba/shandler.cpp')
# Build the command-line+GUI interface
mainEnv.Program('mtssrv', resources + ['src/mitsuba/mtssrv.cpp'])
mainEnv.Program('mitsuba', resources + ['src/mitsuba/mitsuba.cpp', shandler])
mainEnv.Program('mtsutil', resources + ['src/mitsuba/mtsutil.cpp', shandler])
mainEnv.Program('mitsuba', resources + ['src/mitsuba/mitsuba.cpp'])
mainEnv.Program('mtsutil', resources + ['src/mitsuba/mtsutil.cpp'])
if sys.platform == 'darwin':
mainEnv_osx = mainEnv.Clone();
@ -388,10 +388,7 @@ if sys.platform == 'darwin':
mainEnv_osx['CXXFLAGS'].append('-fno-strict-aliasing');
darwinStub += [mainEnv_osx.StaticObject('src/mitsuba/darwin_stub.mm')]
env.Program('src/utils/utils_test', ['src/utils/utils_test.cpp'])
env.Program('src/utils/joinrgb', ['src/utils/joinrgb.cpp'])
env.Program('src/utils/ssalbedo', ['src/utils/ssalbedo.cpp'])
env.Program('src/utils/dumpimage', ['src/utils/dumpimage.cpp'])
env.Program('src/utils/ttest', ['src/utils/ttest.cpp'])
env.Program('src/utils/createvol', ['src/utils/createvol.cpp'])
@ -435,7 +432,7 @@ if hasQt:
qtInterfaces = [qtEnv.Uic4(uic) for uic in scanFiles('src/qtgui', ['*.ui'])]
qtResources = [qtEnv.Qrc(qrc) for qrc in scanFiles('src/qtgui', ['*.qrc'])]
qtgui_files = scanFiles('src/qtgui', ['*.cpp']) + qtResources + shandler + resources
qtgui_files = scanFiles('src/qtgui', ['*.cpp']) + qtResources + resources
if hasCollada:
qtgui_files += converter_objects
@ -601,6 +598,11 @@ plugins += env.SharedLibrary('plugins/vpl', ['src/integrators/vpl/vpl.cpp'])
# pathvertex_mlt, path_mlt
#])
# Testcases
for plugin in glob.glob('src/tests/test_*.cpp'):
name = os.path.basename(plugin)
plugins += env.SharedLibrary('plugins/' + name[0:len(name)-4], plugin)
installTargets = []
# Windows build?

View File

@ -36,17 +36,14 @@ MTS_NAMESPACE_BEGIN
class ROT13Encoder : public Utility {
public:
ROT13Encoder(UtilityServices *us) : Utility(us) { }
int run(int argc, char **argv) {
cout << "Hello world!" << endl;
return 0;
}
MTS_DECLARE_CLASS()
MTS_DECLARE_UTILITY()
};
MTS_IMPLEMENT_CLASS(ROT13Encoder, false, Utility)
MTS_EXPORT_UTILITY(ROT13Encoder, "Perform a ROT13 encryption of a string")
MTS_NAMESPACE_END
\end{cpp}

View File

@ -6,7 +6,6 @@
MTS_NAMESPACE_BEGIN
class Utility;
class UtilityServices;
/**
* Abstract plugin class -- can represent loadable configurable objects
@ -15,7 +14,7 @@ class UtilityServices;
*/
class MTS_EXPORT_CORE Plugin {
typedef void *(*CreateInstanceFunc)(const Properties &props);
typedef void *(*CreateUtilityFunc)(UtilityServices *us);
typedef void *(*CreateUtilityFunc)();
typedef char *(*GetDescriptionFunc)();
public:
/// Load a plugin from the supplied path
@ -31,7 +30,7 @@ public:
ConfigurableObject *createInstance(const Properties &props) const;
/// Return an utility instance (if this is an utility plugin)
Utility *createUtility(UtilityServices *us) const;
Utility *createUtility() const;
/// Return a description of this plugin
std::string getDescription() const;

View File

@ -234,7 +234,7 @@ public:
Float value = f(sphericalDirection(theta, phi))*std::sin(theta)
* weightExt*weightInt;
for (int l=0; l<m_bands; ++l) {
for (int m=1; m<=l; ++m) {
Float L = legendre(l, m, cosTheta) * normalization(l, m);

View File

@ -36,6 +36,9 @@ extern MTS_EXPORT_CORE std::string toUpperCase(const std::string &string);
/// Trim spaces (' ', '\n', '\r', '\t') from the ends of a string
extern MTS_EXPORT_CORE std::string trim(const std::string& str);
/// Determines whether a string starts with the string given as second parameter
extern MTS_EXPORT_CORE bool startsWith(const std::string& str, const std::string& start);
/// Determines whether a string ends with the string given as second parameter
extern MTS_EXPORT_CORE bool endsWith(const std::string& str, const std::string& end);
@ -86,6 +89,12 @@ extern MTS_EXPORT_CORE Float lanczosSinc(Float t, Float tau = 2);
*/
extern MTS_EXPORT_CORE bool solveQuadratic(Float a, Float b, Float c, Float &x0, Float &x1);
/**
* \brief Similar to solveQuadratic(), but always uses double precision independent
* of the chosen compile-time precision.
*/
extern MTS_EXPORT_CORE bool solveQuadraticDouble(double a, double b, double c, double &x0, double &x1);
/**
* \brief Solve a 2x2 linear equation system using basic linear algebra
*/

View File

@ -108,9 +108,7 @@ public:
/// Cast a shadow ray
inline bool isOccluded(const Point &p1, const Point &p2) const {
Intersection its;
Vector direction = p2 - p1;
Ray ray(p1, direction);
Ray ray(p1, p2-p1);
ray.mint = ShadowEpsilon;
ray.maxt = 1-ShadowEpsilon;
return m_kdtree->rayIntersect(ray);

View File

@ -11,7 +11,7 @@
#include <map>
XERCES_CPP_NAMESPACE_USE
using namespace mitsuba;
MTS_NAMESPACE_BEGIN
/**
* XML parser for mitsuba scene files. Uses Xerces-C and SAX
@ -72,4 +72,6 @@ private:
bool m_isIncludedFile;
};
MTS_NAMESPACE_END
#endif /* __SHANDLER_H */

View File

@ -1,10 +1,45 @@
#if !defined(__TESTCASE_H)
#define __TESTCASE_H
#include <mitsuba/mitsuba.h>
#include <mitsuba/render/util.h>
MTS_NAMESPACE_BEGIN
/** \brief Base class of all testcases. Implementations of this
* interface can be executed using the 'mtsutil' command. The execution
* order is as follows: after initializaiton using init(), any tests
* declared using the MTS_DECLARE_TEST() macro are executed. Finally,
* the shutdown() method is called. See the files in 'mitsuba/src/tests'
* for examples.
*/
class MTS_EXPORT_RENDER TestCase : public Utility {
public:
/**
* Perform any required initializations. The default
* implementation simply returns
*/
virtual void init();
/**
* Execute any required shutdown code. The default
* implementation simply returns
*/
virtual void shutdown();
/// Return the number of executed testcases
inline int getExecuted() const { return m_executed; }
/// Return the number of successfully executed testcases
inline int getSucceeded() const { return m_succeeded; }
MTS_DECLARE_CLASS()
protected:
/// Virtual destructor
virtual ~TestCase() { }
protected:
int m_executed, m_succeeded;
};
/**
* The test supervisor is used when rendering a collection of testcases in the
* form of scenes with analytic solutions. Reference output is compared against
@ -40,4 +75,40 @@ private:
MTS_NAMESPACE_END
#define EXECUTE_GUARDED(name) \
try { \
Log(EInfo, "Executing test \"%s\" ..", #name); \
m_executed++;\
name();\
m_succeeded++;\
} catch (std::exception &e) {\
Log(EInfo, "Testcase failed with error: %s", e.what());\
}
#define MTS_BEGIN_TESTCASE() \
MTS_DECLARE_CLASS() \
int run(int argc, char **argv) {\
init(); \
Log(EInfo, "Executing testcase \"%s\" ..", getClass()->getName().c_str()); \
m_executed = m_succeeded = 0;
#define MTS_DECLARE_TEST(name) \
EXECUTE_GUARDED(name)
#define MTS_END_TESTCASE()\
shutdown();\
return 0;\
}
#define MTS_EXPORT_TESTCASE(name, descr) \
MTS_IMPLEMENT_CLASS(name, false, TestCase) \
extern "C" { \
void MTS_EXPORT *CreateUtility() { \
return new name(); \
} \
const char MTS_EXPORT *GetDescription() { \
return descr; \
} \
}
#endif /* __TESTCASE_H */

View File

@ -5,24 +5,12 @@
MTS_NAMESPACE_BEGIN
/**
* Contains functionality provided to utility plugins,
* such as loading a scene from an XML file.
*/
class MTS_EXPORT_RENDER UtilityServices {
public:
virtual ref<Scene> loadScene(const std::string &filename) = 0;
};
/** \brief Abstract utility class -- can be used to implement
* loadable utility plugins that perform various actions. They
* can be started using the 'mtsutil' launcher.
*/
class MTS_EXPORT_RENDER Utility : public Object {
public:
inline Utility(UtilityServices *services)
: m_utilityServices(services) { }
/**
* Run the utility. The supplied <tt>argc</tt>
* and <tt>argv</tt> parameters contain any
@ -38,17 +26,17 @@ protected:
virtual ~Utility() { }
/// Load a scene
inline ref<Scene> loadScene(const std::string &fname) {
return m_utilityServices->loadScene(fname);
}
private:
UtilityServices *m_utilityServices;
ref<Scene> loadScene(const std::string &fname);
};
#define MTS_DECLARE_UTILITY() \
MTS_DECLARE_CLASS()
#define MTS_EXPORT_UTILITY(name, descr) \
MTS_IMPLEMENT_CLASS(name, false, Utility) \
extern "C" { \
void MTS_EXPORT *CreateUtility(UtilityServices *us) { \
return new name(us); \
void MTS_EXPORT *CreateUtility() { \
return new name(); \
} \
const char MTS_EXPORT *GetDescription() { \
return descr; \

View File

@ -76,8 +76,8 @@ ConfigurableObject *Plugin::createInstance(const Properties &props) const {
return (ConfigurableObject *) m_createInstance(props);
}
Utility *Plugin::createUtility(UtilityServices *us) const {
return (Utility *) m_createUtility(us);
Utility *Plugin::createUtility() const {
return (Utility *) m_createUtility();
}
std::string Plugin::getDescription() const {

View File

@ -177,6 +177,10 @@ bool endsWith(const std::string& str, const std::string& end) {
return (pos == str.size() - end.size()) && str.length() >= end.length();
}
bool startsWith(const std::string& str, const std::string& start) {
return str.find(start) == 0;
}
void * __restrict allocAligned(size_t size) {
#if defined(WIN32)
return _aligned_malloc(size, L1_CACHE_LINE_SIZE);
@ -370,6 +374,46 @@ bool solveQuadratic(Float a, Float b, Float c, Float &x0, Float &x1) {
return true;
}
bool solveQuadraticDouble(double a, double b, double c, double &x0, double &x1) {
/* Linear case */
if (a == 0) {
if (b != 0) {
x0 = x1 = -c / b;
return true;
}
return false;
}
double discrim = b*b - 4.0f*a*c;
/* Leave if there is no solution */
if (discrim < 0)
return false;
double temp, sqrtDiscrim = std::sqrt(discrim);
/* Numerically stable version of (-b (+/-) sqrtDiscrim) / (2 * a)
*
* Based on the observation that one solution is always
* accurate while the other is not. Finds the solution of
* greater magnitude which does not suffer from loss of
* precision and then uses the identity x1 * x2 = c / a
*/
if (b < 0)
temp = -0.5f * (b - sqrtDiscrim);
else
temp = -0.5f * (b + sqrtDiscrim);
x0 = temp / a;
x1 = c / temp;
/* Return the results so that x0 < x1 */
if (x0 > x1)
std::swap(x0, x1);
return true;
}
bool solveLinearSystem2x2(const Float a[2][2], const Float b[2], Float x[2]) {
Float det = a[0][0] * a[1][1] - a[0][1] * a[1][0];

View File

@ -211,8 +211,15 @@ bool KDTree::rayIntersect(const Ray &ray, Intersection &its) const {
++raysTraced;
if (m_rootBounds.rayIntersect(ray, mint, maxt)) {
its.t = std::numeric_limits<Float>::infinity();
if (ray.mint > mint)
mint = ray.mint;
/* Adaptive ray epsilon */
Float rayMinT = ray.mint;
if (rayMinT == Epsilon)
rayMinT *= std::max(std::max(std::abs(ray.o.x),
std::abs(ray.o.y)), std::abs(ray.o.z));
if (rayMinT > mint)
mint = rayMinT;
if (ray.maxt < maxt)
maxt = ray.maxt;
if (maxt <= mint)
@ -245,20 +252,6 @@ bool KDTree::rayIntersect(const Ray &ray, Intersection &its) const {
}
#endif
#if 0
/* Slightly offset along the normal to avoid surface acne.
The offset is dependent on the magnitude of each component */
if (dot(faceNormal, ray.d) < 0) {
its.p.x += faceNormal.x * std::abs(its.p.x) * 1e-6f;
its.p.y += faceNormal.y * std::abs(its.p.y) * 1e-6f;
its.p.z += faceNormal.z * std::abs(its.p.z) * 1e-6f;
} else {
its.p.x -= faceNormal.x * std::abs(its.p.x) * 1e-6f;
its.p.y -= faceNormal.y * std::abs(its.p.y) * 1e-6f;
its.p.z -= faceNormal.z * std::abs(its.p.z) * 1e-6f;
}
#endif
const Vector b(1 - its.uv.x - its.uv.y,
its.uv.x, its.uv.y);

View File

@ -635,5 +635,4 @@ std::string Scene::toString() const {
}
MTS_IMPLEMENT_CLASS_S(Scene, false, ConfigurableObject)
MTS_IMPLEMENT_CLASS(Utility, true, Object)
MTS_NAMESPACE_END

View File

@ -1,6 +1,8 @@
#include <mitsuba/core/platform.h>
#include <xercesc/parsers/SAXParser.hpp>
#include "shandler.h"
#include <mitsuba/render/shandler.h>
MTS_NAMESPACE_BEGIN
SceneHandler::SceneHandler() : m_isIncludedFile(false) {
m_pluginManager = PluginManager::getInstance();
@ -399,3 +401,4 @@ void SceneHandler::fatalError(const SAXParseException& e) {
transcode(e.getMessage()).c_str());
}
MTS_NAMESPACE_END

View File

@ -5,6 +5,9 @@
MTS_NAMESPACE_BEGIN
void TestCase::init() { }
void TestCase::shutdown() { }
struct Sample {
Float value;
Float variance;
@ -169,4 +172,5 @@ void TestSupervisor::printSummary() const {
}
MTS_IMPLEMENT_CLASS(TestSupervisor, false, Object)
MTS_IMPLEMENT_CLASS(TestCase, false, Utility)
MTS_NAMESPACE_END

36
src/librender/util.cpp Normal file
View File

@ -0,0 +1,36 @@
#include <mitsuba/core/platform.h>
#include <xercesc/parsers/SAXParser.hpp>
#include <mitsuba/render/util.h>
#include <mitsuba/render/shandler.h>
MTS_NAMESPACE_BEGIN
ref<Scene> Utility::loadScene(const std::string &filename) {
/* Prepare for parsing scene descriptions */
FileResolver *resolver = FileResolver::getInstance();
SAXParser* parser = new SAXParser();
std::string schemaPath = resolver->resolveAbsolute("schema/scene.xsd");
/* Check against the 'scene.xsd' XML Schema */
parser->setDoSchema(true);
parser->setValidationSchemaFullChecking(true);
parser->setValidationScheme(SAXParser::Val_Always);
parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str());
std::map<std::string, std::string> parameters;
SceneHandler *handler = new SceneHandler(parameters);
parser->setDoNamespaces(true);
parser->setDocumentHandler(handler);
parser->setErrorHandler(handler);
parser->parse(filename.c_str());
ref<Scene> scene = handler->getScene();
delete parser;
delete handler;
return scene;
}
MTS_IMPLEMENT_CLASS(Utility, true, Object)
MTS_NAMESPACE_END

View File

@ -5,9 +5,9 @@
#include <mitsuba/core/sshstream.h>
#include <mitsuba/core/shvector.h>
#include <mitsuba/render/renderjob.h>
#include <mitsuba/render/shandler.h>
#include <fstream>
#include <stdexcept>
#include "shandler.h"
#if defined(WIN32)
#include "getopt.h"

View File

@ -6,10 +6,10 @@
#include <mitsuba/core/shvector.h>
#include <mitsuba/render/util.h>
#include <mitsuba/render/renderjob.h>
#include <mitsuba/render/shandler.h>
#include <fstream>
#include <stdexcept>
#include <sys/types.h>
#include "shandler.h"
#if !defined(WIN32)
#include <dlfcn.h>
@ -24,36 +24,6 @@
using namespace mitsuba;
class UtilityServicesImpl : public UtilityServices {
public:
ref<Scene> loadScene(const std::string &filename) {
/* Prepare for parsing scene descriptions */
FileResolver *resolver = FileResolver::getInstance();
SAXParser* parser = new SAXParser();
std::string schemaPath = resolver->resolveAbsolute("schema/scene.xsd");
/* Check against the 'scene.xsd' XML Schema */
parser->setDoSchema(true);
parser->setValidationSchemaFullChecking(true);
parser->setValidationScheme(SAXParser::Val_Always);
parser->setExternalNoNamespaceSchemaLocation(schemaPath.c_str());
std::map<std::string, std::string> parameters;
SceneHandler *handler = new SceneHandler(parameters);
parser->setDoNamespaces(true);
parser->setDocumentHandler(handler);
parser->setErrorHandler(handler);
parser->parse(filename.c_str());
ref<Scene> scene = handler->getScene();
delete parser;
delete handler;
return scene;
}
};
void help() {
cout << "Mitsuba version " MTS_VERSION ", Copyright (c) " MTS_YEAR " Wenzel Jakob" << endl;
cout << "Usage: mtsutil [mtsutil options] <utility name> [arguments]" << endl;
@ -74,10 +44,14 @@ void help() {
cout << " -s file Connect to additional Mitsuba servers specified in a file" << endl;
cout << " with one name per line (same format as in -c)" << endl<< endl;
cout << " -n name Assign a node name to this instance (Default: host name)" << endl << endl;
cout << " -t Execute all testcases" << endl << endl;
cout << " -v Be more verbose" << endl << endl;
FileResolver *resolver = FileResolver::getInstance();
cout << "The following utilities are available:" << endl << endl;
std::ostringstream utilities, testcases;
testcases << "The following testcases are available:" << endl << endl;
utilities << endl << "The following utilities are available:" << endl << endl;
std::vector<std::string> dirPaths = resolver->resolveAllAbsolute("plugins");
std::set<std::string> seen;
@ -115,10 +89,17 @@ void help() {
Plugin utility(shortName, fullName);
if (!utility.isUtility())
continue;
cout << "\t" << shortName;
for (int i=0; i<22-(int) shortName.length(); ++i)
cout << ' ';
cout << utility.getDescription() << endl;
if (startsWith(shortName, "test_")) {
testcases << "\t" << shortName;
for (int i=0; i<22-(int) shortName.length(); ++i)
testcases << ' ';
testcases << utility.getDescription() << endl;
} else {
utilities << "\t" << shortName;
for (int i=0; i<22-(int) shortName.length(); ++i)
utilities << ' ';
utilities << utility.getDescription() << endl;
}
#if !defined(WIN32)
}
#else
@ -126,6 +107,8 @@ void help() {
FindClose(hFind);
#endif
}
cout << testcases.str() << utilities.str();
}
@ -140,6 +123,7 @@ int ubi_main(int argc, char **argv) {
bool quietMode = false;
ELogLevel logLevel = EInfo;
FileResolver *resolver = FileResolver::getInstance();
bool testCaseMode = false;
if (argc < 2) {
help();
@ -148,7 +132,7 @@ int ubi_main(int argc, char **argv) {
optind = 1;
/* Parse command-line arguments */
while ((optchar = getopt(argc, argv, "a:c:s:n:p:qhv")) != -1) {
while ((optchar = getopt(argc, argv, "a:c:s:n:p:qhvt")) != -1) {
switch (optchar) {
case 'a': {
std::vector<std::string> paths = tokenize(optarg, ";");
@ -159,6 +143,9 @@ int ubi_main(int argc, char **argv) {
case 'c':
networkHosts = networkHosts + std::string(";") + std::string(optarg);
break;
case 't':
testCaseMode = true;
break;
case 's': {
std::ifstream is(optarg);
if (is.fail())
@ -261,36 +248,96 @@ int ubi_main(int argc, char **argv) {
scheduler->start();
if (argc <= optind) {
std::cerr << "A utility name must be supplied!" << endl;
return -1;
}
if (testCaseMode) {
std::vector<std::string> dirPaths = resolver->resolveAllAbsolute("plugins");
std::set<std::string> seen;
int executed = 0, succeeded = 0;
/* Build the full plugin file name */
#if defined(WIN32)
std::string shortName = std::string("plugins/") + argv[optind] + std::string(".dll");
#elif defined(__OSX__)
std::string shortName = std::string("plugins/") + argv[optind] + std::string(".dylib");
for (size_t i=0; i<dirPaths.size(); ++i) {
std::string dirPath = dirPaths[i];
#if !defined(WIN32)
DIR *directory;
struct dirent *dirinfo;
if ((directory = opendir(dirPath.c_str())) == NULL)
SLog(EInfo, "Could not open plugin directory");
while ((dirinfo = readdir(directory)) != NULL) {
std::string fname(dirinfo->d_name);
if (!endsWith(fname, ".dylib") && !endsWith(fname, ".so"))
continue;
std::string fullName = dirPath + "/" + fname;
#else
std::string shortName = std::string("plugins/") + argv[optind] + std::string(".so");
HANDLE hFind;
WIN32_FIND_DATA findFileData;
if ((hFind = FindFirstFile((dirPath + "\\*.dll").c_str(), &findFileData)) == INVALID_HANDLE_VALUE)
SLog(EInfo, "Could not open plugin directory");
do {
std::string fname = findFileData.cFileName;
std::string fullName = dirPath + "\\" + fname;
#endif
std::string fullName = resolver->resolve(shortName);
std::string shortName = fname.substr(0, strrchr(fname.c_str(), '.') - fname.c_str());
if (!startsWith(shortName, "test_") || seen.find(shortName) != seen.end())
continue;
seen.insert(shortName);
Plugin plugin(shortName, fullName);
if (!plugin.isUtility())
continue;
if (!FileStream::exists(fullName)) {
/* Plugin not found! */
SLog(EError, "Utility \"%s\" not found (run \"mtsutil\" without arguments to "
"see a list of available utilities)", fullName.c_str());
ref<Utility> utility = plugin.createUtility();
TestCase *testCase = static_cast<TestCase *>(utility.get());
if (!utility->getClass()->derivesFrom(TestCase::m_theClass))
SLog(EError, "This is not a test case!");
if (testCase->run(argc-optind, argv+optind) != 0)
SLog(EError, "Testcase unexpectedly returned with a nonzero value.");
executed += testCase->getExecuted();
succeeded += testCase->getSucceeded();
#if !defined(WIN32)
}
#else
} while (FindNextFile(hFind, &findFileData));
FindClose(hFind);
#endif
}
SLog(EInfo, "Ran %i tests, %i succeeded, %i failed.", executed, succeeded, executed-succeeded);
} else {
if (argc <= optind) {
std::cerr << "A utility name must be supplied!" << endl;
return -1;
}
/* Build the full plugin file name */
#if defined(WIN32)
std::string shortName = std::string("plugins/") + argv[optind] + std::string(".dll");
#elif defined(__OSX__)
std::string shortName = std::string("plugins/") + argv[optind] + std::string(".dylib");
#else
std::string shortName = std::string("plugins/") + argv[optind] + std::string(".so");
#endif
std::string fullName = resolver->resolve(shortName);
if (!FileStream::exists(fullName)) {
/* Plugin not found! */
SLog(EError, "Utility \"%s\" not found (run \"mtsutil\" without arguments to "
"see a list of available utilities)", fullName.c_str());
}
SLog(EInfo, "Loading utility \"%s\" ..", argv[optind]);
Plugin *plugin = new Plugin(argv[optind], fullName);
if (!plugin->isUtility())
SLog(EError, "This plugin does not implement the 'Utility' interface!");
Statistics::getInstance()->logPlugin(argv[optind], plugin->getDescription());
ref<Utility> utility = plugin->createUtility();
return utility->run(argc-optind, argv+optind);
}
SLog(EInfo, "Loading utility \"%s\" ..", argv[optind]);
Plugin *plugin = new Plugin(argv[optind], fullName);
if (!plugin->isUtility())
SLog(EError, "This plugin does not implement the 'Utility' interface!");
Statistics::getInstance()->logPlugin(argv[optind], plugin->getDescription());
UtilityServices *utilityServices = new UtilityServicesImpl();
Utility *utility = plugin->createUtility(utilityServices);
return utility->run(argc-optind, argv+optind);
} catch (const std::exception &e) {
std::cerr << "Caught a critical exeption: " << e.what() << std::endl;
} catch (...) {

View File

@ -10,10 +10,15 @@
using namespace mitsuba;
enum EConnectionType {
ESSHConnection,
ESSHConnection = 0,
EDirectConnection
};
enum ENavigationMode {
EFlythroughFixedYaw = 0,
EFlythrough
};
namespace mitsuba {
class RemoteWorker;
};
@ -123,7 +128,7 @@ struct SceneContext {
float progress;
QString eta, progressName;
ref<Bitmap> framebuffer;
EMode mode;
EMode mode, cancelMode;
Float gamma, exposure, clamping;
bool srgb;
int pathLength, shadowMapResolution;

View File

@ -29,6 +29,7 @@ GLWidget::GLWidget(QWidget *parent) :
connect(m_preview, SIGNAL(statusMessage(const QString &)),
this, SIGNAL(statusMessage(const QString &)), Qt::QueuedConnection);
m_invertMouse = false;
m_navigationMode = EFlythroughFixedYaw;
m_ignoreMouseEvent = QPoint(0, 0);
m_didSetCursor = false;
m_softwareFallback = false;
@ -456,9 +457,12 @@ void GLWidget::timerImpulse() {
if (m_context->renderJob) {
m_context->renderJob->cancel();
m_context->cancelled = true;
m_context->cancelMode = EPreview;
return;
} else {
} else if (m_context->mode != EPreview) {
m_context->mode = EPreview;
// causes updateUI to be called in the main window
emit stopRendering();
}
resetPreview();
@ -468,7 +472,7 @@ void GLWidget::resetPreview() {
if (!m_context || !m_context->scene || !m_preview->isRunning())
return;
bool motion = m_leftKeyDown || m_rightKeyDown ||
m_upKeyDown || m_downKeyDown || m_mouseButtonDown;
m_upKeyDown || m_downKeyDown || m_mouseButtonDown;
m_preview->setSceneContext(m_context, false, motion);
updateGL();
}
@ -555,6 +559,14 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
PinholeCamera *camera = static_cast<PinholeCamera *>(m_context->scene->getCamera());
Point p = camera->getInverseViewTransform()(Point(0,0,0));
Vector direction = camera->getInverseViewTransform()(Vector(0,0,1));
Vector up;
if (m_navigationMode == EFlythrough)
up = camera->getInverseViewTransform()(Vector(0,1,0));
else if (m_navigationMode == EFlythroughFixedYaw)
up = m_context->up;
else
SLog(EError, "Unknown navigation mode encountered!");
bool didMove = false;
@ -570,10 +582,10 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
direction = trafo.inverse()(Vector(0,0,1));
if (camera->getViewTransform().det3x3() < 0) {
camera->setInverseViewTransform(Transform::lookAt(p, p+direction, m_context->up));
camera->setInverseViewTransform(Transform::lookAt(p, p+direction, up));
} else {
camera->setInverseViewTransform(
Transform::lookAt(p, p+direction, m_context->up) *
Transform::lookAt(p, p+direction, up) *
Transform::scale(Vector(-1,1,1))
);
}
@ -585,10 +597,10 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event) {
Float fovChange = rel.y() * m_mouseSensitivity * .03f;
if (camera->getViewTransform().det3x3() < 0) {
m_context->up = Transform::rotate(direction, roll)(m_context->up);
m_context->up = Transform::rotate(direction, roll)(up);
camera->setInverseViewTransform(Transform::lookAt(p, p+direction, m_context->up));
} else {
m_context->up = Transform::rotate(direction, -roll)(m_context->up);
m_context->up = Transform::rotate(direction, -roll)(up);
camera->setInverseViewTransform(
Transform::lookAt(p, p+direction, m_context->up) *
Transform::scale(Vector(-1,1,1))
@ -630,7 +642,7 @@ void GLWidget::wheelEvent(QWheelEvent *event) {
if (!bar->isVisible() || !m_preview->isRunning())
return;
int oldStep = bar->singleStep();
bar->setSingleStep(event->delta()/4);
#if defined(__OSX__)
@ -658,8 +670,8 @@ void GLWidget::mouseReleaseEvent(QMouseEvent *event) {
if (!m_preview->isRunning())
return;
if (event->buttons() == 0) {
m_mouseButtonDown = false;
if (m_didSetCursor) {
m_mouseButtonDown = false;
resetPreview();
QApplication::restoreOverrideCursor();
QCursor::setPos(m_initialMousePos);

View File

@ -32,6 +32,8 @@ public:
inline bool getInvertMouse() const { return m_invertMouse; }
void setInvertMouse(bool invert) { m_invertMouse = invert; }
inline ENavigationMode getNavigationMode() const { return m_navigationMode; }
void setNavigationMode(ENavigationMode mode) { m_navigationMode = mode; }
inline int getMouseSensitivity() const { return m_mouseSensitivity; }
void setMouseSensitivity(int sensitivity) { m_mouseSensitivity = sensitivity; }
void setScrollBars(QScrollBar *hScroll, QScrollBar *vScroll);
@ -119,6 +121,7 @@ private:
QTimer *m_movementTimer, *m_redrawTimer;
QScrollBar *m_hScroll, *m_vScroll;
ref<Timer> m_clock;
ENavigationMode m_navigationMode;
bool m_invertMouse, m_didSetCursor;
bool m_ignoreScrollEvents, m_ignoreResizeEvents;
int m_mouseSensitivity, m_softwareFallback;

View File

@ -146,6 +146,8 @@ MainWindow::MainWindow(QWidget *parent) :
/* Load defaults from app settings file */
ui->glView->setInvertMouse(settings.value("invertMouse", false).toBool());
ui->glView->setMouseSensitivity(settings.value("mouseSensitivity", 3).toInt());
ui->glView->setNavigationMode((ENavigationMode) settings.value("navigationMode",
EFlythroughFixedYaw).toInt());
m_searchPaths = settings.value("searchPaths", QStringList()).toStringList();
m_blockSize = settings.value("blockSize", 32).toInt();
m_listenPort = settings.value("listenPort", MTS_DEFAULT_PORT).toInt();
@ -181,7 +183,7 @@ MainWindow::MainWindow(QWidget *parent) :
ui->toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
QToolButton *previewButton = static_cast<QToolButton *>(ui->toolBar->widgetForAction(ui->actionPreviewSettings));
previewButton->setStyleSheet("margin-left: -5px; margin-right:-5px");
/* Weird Qt/OSX bug -- moving while a window while it is invisible causes
it to appear move up by 65 pixels (this is related to the unified toolbar) */
move(windowPos + QPoint(0, 65));
@ -499,6 +501,7 @@ void MainWindow::onProgressMessage(const RenderJob *job, const QString &name,
context->progressName = name + ": ";
updateUI();
}
void MainWindow::on_actionOpen_triggered() {
QFileDialog *dialog = new QFileDialog(this, Qt::Sheet);
dialog->setNameFilter(tr("Mitsuba scenes (*.xml);;EXR images (*.exr)"));
@ -662,23 +665,10 @@ void MainWindow::updateUI() {
bool fallback = ui->glView->isUsingSoftwareFallback();
ui->actionStop->setEnabled(isShowingRendering);
if (isShowingRendering && !isRendering) {
if (ui->actionStop->text() != tr("Preview")) {
QIcon icon;
ui->actionStop->setText(tr("Preview"));
ui->actionStop->setToolTip(tr("Return to the realtime preview"));
icon.addFile(QString::fromUtf8(":/resources/fpreview.png"), QSize(), QIcon::Normal, QIcon::Off);
ui->actionStop->setIcon(icon);
}
} else {
if (ui->actionStop->text() != tr("Stop")) {
QIcon icon;
ui->actionStop->setText(tr("Stop"));
ui->actionStop->setToolTip(tr("Stop rendering"));
icon.addFile(QString::fromUtf8(":/resources/stop.png"), QSize(), QIcon::Normal, QIcon::Off);
ui->actionStop->setIcon(icon);
}
}
if (isShowingRendering && !isRendering)
ui->actionStop->setToolTip(tr("Return to the realtime preview"));
else
ui->actionStop->setToolTip(tr("Stop rendering"));
ui->actionRender->setEnabled(isInactiveScene);
ui->actionRefresh->setEnabled(isInactiveScene);
@ -972,6 +962,8 @@ void MainWindow::on_actionPreviewSettings_triggered() {
connect(m_previewSettings, SIGNAL(previewMethodChanged(EPreviewMethod)), ui->glView, SLOT(setPreviewMethod(EPreviewMethod)));
connect(m_previewSettings, SIGNAL(toneMappingMethodChanged(EToneMappingMethod)), ui->glView, SLOT(setToneMappingMethod(EToneMappingMethod)));
connect(m_previewSettings, SIGNAL(close()), this, SLOT(onPreviewSettingsClose()));
connect(m_previewSettings, SIGNAL(diffuseReceiversChanged(bool)), ui->glView, SLOT(setDiffuseReceivers(bool)));
connect(m_previewSettings, SIGNAL(diffuseSourcesChanged(bool)), ui->glView, SLOT(setDiffuseSources(bool)));
}
SceneContext *ctx = NULL;
if (ui->tabBar->currentIndex() != -1)
@ -1026,6 +1018,7 @@ void MainWindow::on_actionSettings_triggered() {
d.setWindowModality(Qt::ApplicationModal);
d.setLogLevel(logger->getLogLevel());
d.setInvertMouse(ui->glView->getInvertMouse());
d.setNavigationMode(ui->glView->getNavigationMode());
d.setMouseSensitivity(ui->glView->getMouseSensitivity());
d.setBlockSize(m_blockSize);
d.setSearchPaths(m_searchPaths);
@ -1052,10 +1045,12 @@ void MainWindow::on_actionSettings_triggered() {
settings.setValue("mouseSensitivity", d.getMouseSensitivity());
settings.setValue("listenPort", d.getListenPort());
settings.setValue("nodeName", d.getNodeName());
settings.setValue("navigationMode", (int) d.getNavigationMode());
logger->setLogLevel(d.getLogLevel());
ui->glView->setInvertMouse(d.getInvertMouse());
ui->glView->setMouseSensitivity(d.getMouseSensitivity());
ui->glView->setNavigationMode(d.getNavigationMode());
m_blockSize = d.getBlockSize();
m_searchPaths = d.getSearchPaths();
m_checkForUpdates = d.getCheckForUpdates();
@ -1131,6 +1126,7 @@ void MainWindow::on_actionRender_triggered() {
scene->setBlockSize(m_blockSize);
context->renderJob = new RenderJob("rend", scene, m_renderQueue, NULL,
context->sceneResID, -1, -1, false);
context->cancelMode = ERender;
if (context->mode != ERender)
ui->glView->downloadFramebuffer();
context->cancelled = false;
@ -1356,6 +1352,7 @@ void MainWindow::onJobFinished(const RenderJob *job, bool cancelled) {
tr("The rendering job did not complete successfully. Please check the log."),
QMessageBox::Ok);
} else {
context->mode = context->cancelMode;
if (ui->tabBar->currentIndex() != -1 &&
m_context[ui->tabBar->currentIndex()] == context)
ui->glView->resumePreview();

View File

@ -19,6 +19,8 @@ class PreviewSettingsDlg;
IBOutlet BWTransparentSlider *exposure;
IBOutlet BWTransparentSlider *gamma;
IBOutlet BWTransparentCheckbox *sRGB;
IBOutlet BWTransparentCheckbox *diffuseSourcesBox;
IBOutlet BWTransparentCheckbox *diffuseReceiversBox;
IBOutlet NSTextField *shadowMapLabel;
IBOutlet NSTextField *reinhardKeyLabel;
IBOutlet NSTextField *gammaLabel;
@ -40,6 +42,8 @@ class PreviewSettingsDlg;
- (IBAction) exposureChanged: (id) sender;
- (IBAction) gammaChanged: (id) sender;
- (IBAction) sRGBChanged: (id) sender;
- (IBAction) diffuseSourcesChanged: (id) sender;
- (IBAction) diffuseReceiversChanged: (id) sender;
- (IBAction) reset: (id) sender;
- (void) updateUI;
- (void) showAt: (NSPoint) point;
@ -87,6 +91,12 @@ public:
void triggerReinhardBurnChanged(float burn) {
emit reinhardBurnChanged(burn);
}
void triggerDiffuseReceiversChanged(bool value) {
emit diffuseReceiversChanged(value);
}
void triggerDiffuseSourcesChanged(bool value) {
emit diffuseSourcesChanged(value);
}
void triggerClose() {
emit close();
}
@ -101,6 +111,8 @@ signals:
void reinhardKeyChanged(Float key);
void reinhardBurnChanged(Float burn);
void close();
void diffuseReceiversChanged(bool);
void diffuseSourcesChanged(bool);
private:
CocoaRenderSettingsDlg *m_dlg;
};

View File

@ -54,6 +54,7 @@
bool hasShadowMaps = (sel_previewMethod == EOpenGL || sel_previewMethod == EOpenGLSinglePass);
bool hasKey = (sel_toneMappingMethod == EReinhard);
bool hasGamma = [sRGB state] == NSOffState;
bool hasDiffuseSources = [diffuseSourcesBox state] == NSOnState;
std::string gammaStr = formatString("%.1f", [gamma floatValue]);
std::string exposureStr = formatString("%.1f", [exposure floatValue]);
@ -69,6 +70,8 @@
[[gamma animator] setAlphaValue: hasGamma ? 1.0f : 0.5f];
[gammaValueLabel setStringValue: [NSString stringWithCString: gammaStr.c_str() encoding: NSASCIIStringEncoding]];
[exposureValueLabel setStringValue: [NSString stringWithCString: exposureStr.c_str() encoding: NSASCIIStringEncoding]];
[diffuseReceiversBox setEnabled: (BOOL) hasDiffuseSources];
[[diffuseReceiversBox animator] setAlphaValue: hasDiffuseSources ? 1.0f : 0.5f];
}
- (IBAction) previewMethodChanged: (id) sender {
@ -110,6 +113,15 @@
[self updateUI];
}
- (IBAction) diffuseSourcesChanged: (id) sender {
delegate->triggerDiffuseSourcesChanged([diffuseSourcesBox state] == NSOnState);
[self updateUI];
}
- (IBAction) diffuseReceiversChanged: (id) sender {
delegate->triggerDiffuseReceiversChanged([diffuseReceiversBox state] == NSOnState);
}
- (IBAction) shadowMapResolutionChanged: (id) sender {
int res, index = [shadowMapResolution indexOfSelectedItem];
switch (index) {
@ -144,6 +156,8 @@
[exposure setFloatValue: 0.0];
[reinhardKey setFloatValue: 0.18];
[sRGB setState: NSOnState];
[diffuseSourcesBox setState: NSOnState];
[diffuseReceiversBox setState: NSOffState];
[self previewMethodChanged: self];
[self toneMappingMethodChanged: self];
[self shadowMapResolutionChanged: self];
@ -151,6 +165,8 @@
[self exposureChanged: self];
[self clampingChanged: self];
[self gammaChanged: self];
[self diffuseSourcesChanged: self];
[self diffuseReceiversChanged: self];
}
- (void) setContext: (SceneContext *) ctx {
@ -161,6 +177,8 @@
[clamping setFloatValue: (float) ctx->clamping];
[gamma setFloatValue: (float) ctx->gamma];
[sRGB setState: ctx->srgb ? NSOnState : NSOffState];
[diffuseSourcesBox setState: ctx->diffuseSources ? NSOnState : NSOffState];
[diffuseReceiversBox setState: ctx->diffuseReceivers ? NSOnState : NSOffState];
if (ctx->toneMappingMethod == EGamma)
[exposure setFloatValue: (float) ctx->exposure];

View File

@ -37,6 +37,14 @@ public:
return ui->invertMouseBox->checkState() == Qt::Checked;
}
inline ENavigationMode getNavigationMode() const {
return (ENavigationMode) ui->navigationModeBox->currentIndex();
}
inline void setNavigationMode(ENavigationMode mode) const {
ui->navigationModeBox->setCurrentIndex(mode);
}
inline void setInvertMouse(bool value) {
ui->invertMouseBox->setCheckState(value ? Qt::Checked : Qt::Unchecked);
}

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>354</width>
<height>485</height>
<width>377</width>
<height>500</height>
</rect>
</property>
<property name="sizePolicy">
@ -51,7 +51,7 @@
<attribute name="title">
<string>General</string>
</attribute>
<layout class="QGridLayout" name="gridLayout1" rowstretch="0,0,0,0,0,0,0,0,0,0,0,0,0" columnstretch="0,0,0,1">
<layout class="QGridLayout" name="gridLayout1" rowstretch="0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" columnstretch="0,0,0,1">
<property name="leftMargin">
<number>15</number>
</property>
@ -186,7 +186,7 @@ system load, especially when much of the work is done over the network.</string>
</property>
</widget>
</item>
<item row="10" column="0" colspan="4">
<item row="13" column="0" colspan="4">
<widget class="QLabel" name="label_3">
<property name="font">
<font>
@ -199,7 +199,7 @@ system load, especially when much of the work is done over the network.</string>
</property>
</widget>
</item>
<item row="12" column="1" colspan="3">
<item row="15" column="1" colspan="3">
<layout class="QHBoxLayout" name="buttonsLayout1" stretch="0,0,0">
<property name="spacing">
<number>6</number>
@ -286,50 +286,6 @@ system load, especially when much of the work is done over the network.</string>
</item>
</layout>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_5">
<property name="toolTip">
<string>Specifies the threshold for displaying log messages.
For instance, setting this to &quot;Info&quot; means that everything
above and including &quot;Info&quot; is written to the console.</string>
</property>
<property name="text">
<string>Log verbosity :</string>
</property>
<property name="buddy">
<cstring>logVerbosityBox</cstring>
</property>
</widget>
</item>
<item row="8" column="2" colspan="2">
<widget class="QComboBox" name="logVerbosityBox">
<property name="toolTip">
<string>Specifies the threshold for displaying log messages.
For instance, setting this to &quot;Info&quot; means that everything
above and including &quot;Info&quot; is written to the console.</string>
</property>
<item>
<property name="text">
<string>Trace</string>
</property>
</item>
<item>
<property name="text">
<string>Debug</string>
</property>
</item>
<item>
<property name="text">
<string>Info</string>
</property>
</item>
<item>
<property name="text">
<string>Warn</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0" colspan="3">
<widget class="QLabel" name="label_11">
<property name="font">
@ -343,7 +299,7 @@ above and including &quot;Info&quot; is written to the console.</string>
</property>
</widget>
</item>
<item row="11" column="1" colspan="3">
<item row="14" column="1" colspan="3">
<widget class="QListWidget" name="searchPathList">
<property name="enabled">
<bool>true</bool>
@ -415,7 +371,7 @@ release via Internet every time it is started.</string>
</property>
</widget>
</item>
<item row="7" column="2" colspan="2">
<item row="10" column="2" colspan="2">
<widget class="QSlider" name="sensitivitySlider">
<property name="toolTip">
<string>Specifies how sensitive the mouse should react to
@ -450,7 +406,7 @@ movements while navigating in the realt-time preview.</string>
</property>
</widget>
</item>
<item row="7" column="1">
<item row="10" column="1">
<widget class="QLabel" name="label_8">
<property name="toolTip">
<string>Specifies how sensitive the mouse should react to
@ -461,7 +417,7 @@ movements while navigating in the realt-time preview.</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="8" column="1">
<widget class="QLabel" name="label_12">
<property name="toolTip">
<string>Should the preview navigation flip the Y axis of the mouse?</string>
@ -474,7 +430,7 @@ movements while navigating in the realt-time preview.</string>
</property>
</widget>
</item>
<item row="6" column="2">
<item row="8" column="2">
<widget class="QCheckBox" name="invertMouseBox">
<property name="toolTip">
<string>Should the preview navigation flip the Y axis of the mouse?</string>
@ -493,6 +449,96 @@ movements while navigating in the realt-time preview.</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_15">
<property name="toolTip">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This option specifies the camera behavior when navigating within the realtime preview.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Fly-through (Fix yaw)&lt;/span&gt;: Always yaw around a fixed &amp;quot;up&amp;quot; axis, which is determined when a scene is loaded. This is intuitive and similar to a person walking through a scene, but assumes that the camera has already been set up correctly.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Fly-through&lt;/span&gt;: Always yaw around the current camera &amp;quot;up&amp;quot; axis.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Navigation :</string>
</property>
<property name="buddy">
<cstring>navigationModeBox</cstring>
</property>
</widget>
</item>
<item row="7" column="2" colspan="2">
<widget class="QComboBox" name="navigationModeBox">
<property name="toolTip">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;This option specifies the camera behavior when navigating within the realtime preview.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Fly-through (Fix yaw)&lt;/span&gt;: Always yaw around a fixed &amp;quot;up&amp;quot; axis, which is determined when a scene is loaded. This is intuitive and similar to a person walking through a scene, but assumes that the camera has already been set up correctly.&lt;/p&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Fly-through&lt;/span&gt;: Always yaw around the current camera &amp;quot;up&amp;quot; axis.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<item>
<property name="text">
<string>Fly-through (Fix yaw)</string>
</property>
</item>
<item>
<property name="text">
<string>Fly-through</string>
</property>
</item>
</widget>
</item>
<item row="6" column="2" colspan="2">
<widget class="QComboBox" name="logVerbosityBox">
<property name="toolTip">
<string>Specifies the threshold for displaying log messages.
For instance, setting this to &quot;Info&quot; means that everything
above and including &quot;Info&quot; is written to the console.</string>
</property>
<item>
<property name="text">
<string>Trace</string>
</property>
</item>
<item>
<property name="text">
<string>Debug</string>
</property>
</item>
<item>
<property name="text">
<string>Info</string>
</property>
</item>
<item>
<property name="text">
<string>Warn</string>
</property>
</item>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_5">
<property name="toolTip">
<string>Specifies the threshold for displaying log messages.
For instance, setting this to &quot;Info&quot; means that everything
above and including &quot;Info&quot; is written to the console.</string>
</property>
<property name="text">
<string>Log verbosity :</string>
</property>
<property name="buddy">
<cstring>logVerbosityBox</cstring>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab2">
@ -757,9 +803,10 @@ connections. The default setting is 7554.</string>
<tabstop>blockSizeBox</tabstop>
<tabstop>localWorkerBox</tabstop>
<tabstop>checkForUpdatesBox</tabstop>
<tabstop>logVerbosityBox</tabstop>
<tabstop>navigationModeBox</tabstop>
<tabstop>invertMouseBox</tabstop>
<tabstop>sensitivitySlider</tabstop>
<tabstop>logVerbosityBox</tabstop>
<tabstop>searchPathList</tabstop>
<tabstop>removePathButton</tabstop>
<tabstop>addPathButton</tabstop>
@ -782,8 +829,8 @@ connections. The default setting is 7554.</string>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>280</x>
<y>412</y>
<x>286</x>
<y>475</y>
</hint>
<hint type="destinationlabel">
<x>141</x>
@ -798,8 +845,8 @@ connections. The default setting is 7554.</string>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>309</x>
<y>412</y>
<x>315</x>
<y>475</y>
</hint>
<hint type="destinationlabel">
<x>318</x>
@ -831,7 +878,7 @@ connections. The default setting is 7554.</string>
<hints>
<hint type="sourcelabel">
<x>175</x>
<y>100</y>
<y>90</y>
</hint>
<hint type="destinationlabel">
<x>26</x>
@ -846,8 +893,8 @@ connections. The default setting is 7554.</string>
<slot>refresh()</slot>
<hints>
<hint type="sourcelabel">
<x>224</x>
<y>74</y>
<x>175</x>
<y>62</y>
</hint>
<hint type="destinationlabel">
<x>291</x>

View File

@ -1,7 +1,7 @@
#include <xercesc/parsers/SAXParser.hpp>
#include "glwidget.h"
#include "sceneloader.h"
#include "../mitsuba/shandler.h"
#include <mitsuba/render/shandler.h>
SceneLoader::SceneLoader(FileResolver *resolver, const std::string &filename)
: Thread("load"), m_resolver(resolver), m_filename(filename) {

View File

@ -69,29 +69,35 @@ public:
}
bool rayIntersect(const Ray &_ray, Float start, Float end, Float &t) const {
Float nearT, farT; Ray ray;
double nearT, farT; Ray ray;
/* Transform into the local coordinate system and normalize */
m_worldToObject(_ray, ray);
const double
ox = ray.o.x,
oy = ray.o.y,
dx = ray.d.x,
dy = ray.d.y;
const Float A = ray.d.x*ray.d.x + ray.d.y*ray.d.y;
const Float B = 2 * (ray.d.x*ray.o.x + ray.d.y*ray.o.y);
const Float C = ray.o.x*ray.o.x + ray.o.y*ray.o.y - m_radius*m_radius;
const double A = dx*dx + dy*dy;
const double B = 2 * (dx*ox + dy*oy);
const double C = ox*ox + oy*oy - m_radius*m_radius;
if (!solveQuadratic(A, B, C, nearT, farT))
if (!solveQuadraticDouble(A, B, C, nearT, farT))
return false;
if (nearT > end || farT < start)
return false;
const Float zPosNear = ray.o.z + ray.d.z * nearT;
const Float zPosFar = ray.o.z + ray.d.z * farT;
const double zPosNear = ray.o.z + ray.d.z * nearT;
const double zPosFar = ray.o.z + ray.d.z * farT;
if (zPosNear >= 0 && zPosNear <= m_length && nearT >= start) {
t = nearT;
t = (Float) nearT;
} else if (zPosFar >= 0 && zPosFar <= m_length) {
if (farT > end)
return false;
t = farT;
t = (Float) farT;
} else {
return false;
}
@ -124,20 +130,6 @@ public:
its.hasUVPartials = false;
its.shape = this;
/* Intersection refinement step */
Vector2 localDir(normalize(Vector2(local.x, local.y)));
Vector rel = its.p - m_objectToWorld(Point(m_radius * localDir.x,
m_radius * localDir.y, local.z));
Float correction = -dot(rel, its.geoFrame.n)/dot(ray.d, its.geoFrame.n);
its.t += correction;
if (its.t < ray.mint || its.t > ray.maxt) {
its.t = std::numeric_limits<Float>::infinity();
return false;
}
its.p += ray.d * correction;
return true;
}

View File

@ -38,14 +38,16 @@ public:
bool rayIntersect(const Ray &ray, Float start, Float end, Float &t) const {
/* Transform into the local coordinate system and normalize */
Float nearT, farT;
const Float ox = ray.o.x - m_center.x, oy = ray.o.y - m_center.y,
oz = ray.o.z - m_center.z;
const Float A = ray.d.x*ray.d.x + ray.d.y*ray.d.y + ray.d.z*ray.d.z;
const Float B = 2 * (ray.d.x*ox + ray.d.y*oy + ray.d.z*oz);
const Float C = ox*ox + oy*oy + oz*oz - m_radius * m_radius;
double nearT, farT;
const double ox = (double) ray.o.x - (double) m_center.x,
oy = (double) ray.o.y - (double) m_center.y,
oz = (double) ray.o.z - (double) m_center.z;
const double dx = ray.d.x, dy = ray.d.y, dz = ray.d.z;
const double A = dx*dx + dy*dy + dz*dz;
const double B = 2 * (dx*ox + dy*oy + dz*oz);
const double C = ox*ox + oy*oy + oz*oz - m_radius * m_radius;
if (!solveQuadratic(A, B, C, nearT, farT))
if (!solveQuadraticDouble(A, B, C, nearT, farT))
return false;
if (nearT > end || farT < start)
@ -53,9 +55,9 @@ public:
if (nearT < start) {
if (farT > end)
return false;
t = farT;
t = (Float) farT;
} else {
t = nearT;
t = (Float) nearT;
}
return true;
}
@ -99,19 +101,6 @@ public:
coordinateSystem(its.geoFrame.n, its.geoFrame.s, its.geoFrame.t);
}
/* Intersection refinement step */
Vector rel = its.p - (m_center + its.geoFrame.n * m_radius);
Float correction = -dot(rel, its.geoFrame.n)/dot(ray.d, its.geoFrame.n);
/* Move outside of the object */
its.t += correction;
if (its.t < ray.mint || its.t > ray.maxt) {
its.t = std::numeric_limits<Float>::infinity();
return false;
}
its.p += ray.d * correction;
its.shFrame = its.geoFrame;
its.wi = its.toLocal(-ray.d);
its.hasUVPartials = false;

View File

@ -0,0 +1,72 @@
#include <mitsuba/render/testcase.h>
#include <mitsuba/core/plugin.h>
MTS_NAMESPACE_BEGIN
class TestSamplers : public TestCase {
public:
MTS_BEGIN_TESTCASE()
MTS_DECLARE_TEST(test01_Halton)
MTS_DECLARE_TEST(test02_Hammersley)
MTS_DECLARE_TEST(test03_radicalInverseIncr)
MTS_END_TESTCASE()
void test01_Halton() {
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
createObject(Sampler::m_theClass, Properties("halton")));
/* MATLAB: p = haltonset(5); net(p,5) */
Float comparison[] = {
0, 0, 0, 0, 0,
0.500000000000000, 0.333333333333333, 0.200000000000000, 0.142857142857143, 0.090909090909091,
0.250000000000000, 0.666666666666667, 0.400000000000000, 0.285714285714286, 0.181818181818182,
0.750000000000000, 0.111111111111111, 0.600000000000000, 0.428571428571429, 0.272727272727273,
0.125000000000000, 0.444444444444444, 0.800000000000000, 0.571428571428571, 0.363636363636364
};
int pos = 0;
sampler->generate();
for (int i=0; i<5; ++i) {
for (int j=0; j<5; ++j)
Assert(std::abs(sampler->next1D() - comparison[pos++]) < 1e-7);
sampler->advance();
}
}
void test02_Hammersley() {
Properties props("hammersley");
props.setInteger("sampleCount", 5);
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
createObject(Sampler::m_theClass, props));
Float comparison[] = {
0.0, 0, 0, 0, 0, 0,
1.0/5.0, 0.500000000000000, 0.333333333333333, 0.200000000000000, 0.142857142857143, 0.090909090909091,
2.0/5.0, 0.250000000000000, 0.666666666666667, 0.400000000000000, 0.285714285714286, 0.181818181818182,
3.0/5.0, 0.750000000000000, 0.111111111111111, 0.600000000000000, 0.428571428571429, 0.272727272727273,
4.0/5.0, 0.125000000000000, 0.444444444444444, 0.800000000000000, 0.571428571428571, 0.363636363636364
};
int pos = 0;
sampler->generate();
for (int i=0; i<5; ++i) {
for (int j=0; j<6; ++j)
Assert(std::abs(sampler->next1D() - comparison[pos++]) < 1e-7);
sampler->advance();
}
}
void test03_radicalInverseIncr() {
Float x = 0.0f;
for (int i=0; i<20; ++i) {
Assert(x == radicalInverse(2, i));
x = radicalInverseIncremental(2, x);
}
}
};
MTS_EXPORT_TESTCASE(TestSamplers, "Testcase for Sampler implementations")
MTS_NAMESPACE_END

84
src/tests/test_sh.cpp Normal file
View File

@ -0,0 +1,84 @@
#include <mitsuba/render/testcase.h>
#include <mitsuba/core/shvector.h>
MTS_NAMESPACE_BEGIN
class TestSphericalHarmonics : public TestCase {
public:
MTS_BEGIN_TESTCASE()
MTS_DECLARE_TEST(test01_shRotation)
MTS_DECLARE_TEST(test02_shSampler)
MTS_END_TESTCASE()
void test01_shRotation() {
/* Generate a random SH expansion, rotate it and
spot-check 100 times against the original */
ref<Random> random = new Random();
int bands = 8;
SHVector vec1(bands);
for (int l=0; l<bands; ++l)
for (int m=-l; m<=l; ++m)
vec1(l, m) = random->nextFloat();
Vector axis(squareToSphere(Point2(random->nextFloat(), random->nextFloat())));
Transform trafo = Transform::rotate(axis, random->nextFloat()*360);
Transform inv = trafo.inverse();
SHRotation rot(vec1.getBands());
SHVector::rotation(trafo, rot);
SHVector vec2(bands);
rot(vec1, vec2);
for (int i=0; i<100; ++i) {
Vector dir1(squareToSphere(Point2(random->nextFloat(), random->nextFloat()))), dir2;
trafo(dir1, dir2);
Float value1 = vec1.eval(dir2);
Float value2 = vec2.eval(dir1);
Assert(std::abs(value1-value2) < Epsilon);
}
}
struct ClampedCos {
Vector axis;
ClampedCos(Vector axis) : axis(axis) { }
Float operator()(const Vector &w) const { return std::max((Float) 0, dot(w, axis)); }
};
void test02_shSampler() {
/* Draw 100 samples from a SH expansion of a clamped cosine-shaped
distribution and verify the returned probabilities */
int bands = 13, numSamples = 100, depth = 12;
Vector v = normalize(Vector(1, 2, 3));
ref<Random> random = new Random();
SHVector clampedCos = SHVector(bands);
clampedCos.project(ClampedCos(v), numSamples);
//Float clampedCosError = clampedCos.l2Error(ClampedCos(v), numSamples);
clampedCos.normalize();
//cout << "Projection error = " << clampedCosError << endl;
//cout << "Precomputing mip-maps" << endl;
ref<SHSampler> sampler = new SHSampler(bands, depth);
//cout << "Done: "<< sampler->toString() << endl;
Float accum = 0;
int nsamples = 100, nInAvg = 0;
for (int i=0; i<=nsamples; ++i) {
Point2 sample(random->nextFloat(), random->nextFloat());
Float pdf1 = sampler->warp(clampedCos, sample);
Float pdf2 = dot(v, sphericalDirection(sample.x, sample.y))/M_PI;
Float relerr = std::abs(pdf1-pdf2)/pdf2;
if (pdf2 > 0.01) {
accum += relerr; ++nInAvg;
Assert(relerr < 0.08);
}
}
Assert(accum / nInAvg < 0.01);
}
};
MTS_EXPORT_TESTCASE(TestSphericalHarmonics, "Testcase for Spherical Harmonics code")
MTS_NAMESPACE_END

View File

@ -5,8 +5,6 @@ MTS_NAMESPACE_BEGIN
class AddImages : public Utility {
public:
AddImages(UtilityServices *us) : Utility(us) { }
int run(int argc, char **argv) {
if (argc != 6) {
cout << "Add the weighted pixel values of two EXR images to produce a new one" << endl;
@ -53,9 +51,8 @@ public:
return 0;
}
MTS_DECLARE_CLASS()
MTS_DECLARE_UTILITY()
};
MTS_IMPLEMENT_CLASS(AddImages, false, Utility)
MTS_EXPORT_UTILITY(AddImages, "Generate linear combinations of EXR images")
MTS_NAMESPACE_END

View File

@ -1,80 +0,0 @@
#include <mitsuba/core/bitmap.h>
#include <mitsuba/core/fstream.h>
#include <iomanip>
using namespace mitsuba;
Bitmap *downsample(const Bitmap *in) {
Bitmap *result = new Bitmap(in->getWidth()/2, in->getHeight()/2, 128);
const float *data = in->getFloatData();
float *out = result->getFloatData();
result->clear();
for (int y=0; y<in->getWidth()/2; ++y) {
for (int x=0; x<in->getWidth()/2; ++x) {
Float value1 = data[(2*x + 2*y * in->getWidth()) * 4];
Float value2 = data[(2*x + (2*y+1) * in->getWidth()) * 4];
Float value3 = data[(2*x+1 + 2*y * in->getWidth()) * 4];
Float value4 = data[(2*x+1 + (2*y+1) * in->getWidth()) * 4];
Float avg = (value1+value2+value3+value4)/4;
out[(x + y * result->getWidth()) * 4 + 0] = avg;
out[(x + y * result->getWidth()) * 4 + 1] = avg;
out[(x + y * result->getWidth()) * 4 + 2] = avg;
out[(x + y * result->getWidth()) * 4 + 3] = 1;
}
}
return result;
}
void dumpImage(const std::string &s1) {
ref<FileStream> stream = new FileStream(s1, FileStream::EReadOnly);
ref<Bitmap> bitmap = new Bitmap(Bitmap::EEXR, stream);
// bitmap = downsample(bitmap);
// bitmap = downsample(bitmap);
stream = new FileStream("downsampled.exr", FileStream::ETruncReadWrite);
bitmap->save(Bitmap::EEXR, stream);
float *data = bitmap->getFloatData();
cout << "A={" << endl;
cout << std::fixed << endl;
cout << std::setprecision(12)<< endl;
for (int y=0; y<bitmap->getWidth(); ++y) {
cout << "\t{";
for (int x=0; x<bitmap->getWidth(); ++x) {
cout << data[(x + y * bitmap->getWidth()) * 4];
if (x+1 < bitmap->getWidth())
cout << ", ";
}
cout << "}";
if (y+1 < bitmap->getHeight())
cout << ",";
cout << endl;
}
cout << "};";
}
int main(int argc, char **argv) {
Class::staticInitialization();
Thread::staticInitialization();
Logger::staticInitialization();
Spectrum::staticInitialization();
try {
if (argc < 2) {
cout << "dumpimage <image.exr>" << endl;
} else {
dumpImage(argv[1]);
}
} catch (const std::exception &e) {
std::cerr << "Caught a critical exeption: " << e.what() << std::endl;
exit(-1);
} catch (...) {
std::cerr << "Caught a critical exeption of unknown type! " << std::endl;
exit(-1);
}
Spectrum::staticShutdown();
Logger::staticShutdown();
Thread::staticShutdown();
Class::staticShutdown();
return 0;
}

View File

@ -1,94 +0,0 @@
#include <mitsuba/core/aabb.h>
#include <mitsuba/core/fstream.h>
using namespace mitsuba;
Float solveSSAlbedo(Float diffAlbedo) {
if (diffAlbedo == 1 || diffAlbedo == 0)
return diffAlbedo;
if (diffAlbedo < 0 || diffAlbedo > 1) {
cout << "Overflow: "<< diffAlbedo << "!" << endl;
diffAlbedo = std::max((Float) 0, std::min((Float) 1, diffAlbedo));
}
Float l = 0, r = 1;
while (true) {
Float m = (l+r)/2,
fm = m/2*(1+std::exp(-4.0/3.0*std::sqrt(3*(1-m))))*std::exp(-std::sqrt(3*(1-m)));
if (fm < diffAlbedo)
l = m;
else
r = m;
if (std::abs(fm-diffAlbedo) < 1e-3)
return m;
}
}
void computeSSAlbedo(const std::string &filename, const std::string target) {
ref<FileStream> stream = new FileStream(filename, FileStream::EReadOnly);
stream->setByteOrder(Stream::ELittleEndian);
int xres = stream->readInt(), yres=stream->readInt(), zres=stream->readInt();
Vector3i res = Vector3i(xres, yres, zres);
int channels = stream->readInt();
size_t nEntries = res.x*res.y*res.z*channels;
Float xmin = stream->readSingle(), ymin = stream->readSingle(), zmin = stream->readSingle();
Float xmax = stream->readSingle(), ymax = stream->readSingle(), zmax = stream->readSingle();
AABB aabb(Point(xmin, ymin, zmin), Point(xmax, ymax, zmax));
SLog(EInfo, "Loading \"%s\": %ix%ix%i (%i channels), %i KiB, %s", filename.c_str(),
res.x, res.y, res.z, channels, nEntries*sizeof(float)/1024,
aabb.toString().c_str());
float *data = new float[nEntries];
stream->read(data, nEntries*sizeof(float));
stream->close();
SLog(EInfo, "Computing single scattering albedo ..");
for (size_t i=0; i<nEntries; ++i)
data[i] = solveSSAlbedo(data[i]);
SLog(EInfo, "Saving \"%s\": %ix%ix%i (%i channels), %i KiB, %s", target.c_str(),
res.x, res.y, res.z, channels, nEntries*sizeof(float)/1024,
aabb.toString().c_str());
ref<FileStream> targetStream = new FileStream(target, FileStream::ETruncReadWrite);
targetStream->setByteOrder(Stream::ELittleEndian);
res.serialize(targetStream);
targetStream->writeInt(channels);
targetStream->writeSingle(xmin); targetStream->writeSingle(ymin); targetStream->writeSingle(zmin);
targetStream->writeSingle(xmax); targetStream->writeSingle(ymax); targetStream->writeSingle(zmax);
targetStream->write(data, nEntries*sizeof(float));
targetStream->close();
}
int main(int argc, char **argv) {
Class::staticInitialization();
Thread::staticInitialization();
Logger::staticInitialization();
Spectrum::staticInitialization();
try {
if (argc != 3) {
cout << "Converts a volume of diffuse color values to " << endl;
cout << "a single scattering albedo volume by numerically" << endl;
cout << "inverting (2.4) in the Jensen et al. BSSRDF paper" << endl;
cout << "Syntax: ssalbedo <source.vol> <target.vol>" << endl;
} else {
computeSSAlbedo(argv[1], argv[2]);
}
} catch (const std::exception &e) {
std::cerr << "Caught a critical exeption: " << e.what() << std::endl;
exit(-1);
} catch (...) {
std::cerr << "Caught a critical exeption of unknown type! " << std::endl;
exit(-1);
}
Spectrum::staticShutdown();
Logger::staticShutdown();
Thread::staticShutdown();
Class::staticShutdown();
return 0;
}

View File

@ -1,611 +0,0 @@
#include <mitsuba/mitsuba.h>
#include <mitsuba/core/plugin.h>
#include <mitsuba/render/scene.h>
#include <mitsuba/render/photonmap.h>
#include <mitsuba/core/wavelet.h>
#include <mitsuba/core/shvector.h>
#include <mitsuba/core/grid.h>
#include "../medium/maxexp.h"
#include <fstream>
using namespace mitsuba;
void testHalton() {
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
createObject(Sampler::m_theClass, Properties("halton")));
/* MATLAB: p = haltonset(5); net(p,5) */
Float comparison[] = {
0, 0, 0, 0, 0,
0.500000000000000, 0.333333333333333, 0.200000000000000, 0.142857142857143, 0.090909090909091,
0.250000000000000, 0.666666666666667, 0.400000000000000, 0.285714285714286, 0.181818181818182,
0.750000000000000, 0.111111111111111, 0.600000000000000, 0.428571428571429, 0.272727272727273,
0.125000000000000, 0.444444444444444, 0.800000000000000, 0.571428571428571, 0.363636363636364
};
int pos = 0;
sampler->generate();
for (int i=0; i<5; ++i) {
for (int j=0; j<5; ++j)
SAssert(std::abs(sampler->next1D() - comparison[pos++]) < 1e-7);
sampler->advance();
}
}
void testHammersley() {
Properties props("hammersley");
props.setInteger("sampleCount", 5);
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
createObject(Sampler::m_theClass, props));
Float comparison[] = {
0.0, 0, 0, 0, 0, 0,
1.0/5.0, 0.500000000000000, 0.333333333333333, 0.200000000000000, 0.142857142857143, 0.090909090909091,
2.0/5.0, 0.250000000000000, 0.666666666666667, 0.400000000000000, 0.285714285714286, 0.181818181818182,
3.0/5.0, 0.750000000000000, 0.111111111111111, 0.600000000000000, 0.428571428571429, 0.272727272727273,
4.0/5.0, 0.125000000000000, 0.444444444444444, 0.800000000000000, 0.571428571428571, 0.363636363636364
};
int pos = 0;
sampler->generate();
for (int i=0; i<5; ++i) {
for (int j=0; j<6; ++j)
SAssert(std::abs(sampler->next1D() - comparison[pos++]) < 1e-7);
sampler->advance();
}
}
void testRadicalInverseIncr() {
Float x = 0.0f;
for (int i=0; i<20; ++i) {
SAssert(x == radicalInverse(2, i));
x = radicalInverseIncremental(2, x);
}
}
void testSpotLuminaire() {
Properties props("spot");
props.setFloat("beamWidth", 20);
props.setFloat("cutoffAngle", 25);
ref<Luminaire> spot = static_cast<Luminaire *> (PluginManager::getInstance()->
createObject(Luminaire::m_theClass, props));
ref<Random> random = new Random();
Spectrum power;
EmissionRecord eRec;
const int nSamples = 1000000;
for (int i=0; i<nSamples; ++i) {
Point2 areaSample(random->nextFloat(), random->nextFloat());
Point2 dirSample(random->nextFloat(), random->nextFloat());
spot->sampleEmission(eRec, areaSample, dirSample);
power += eRec.P / (eRec.pdfArea*eRec.pdfDir);
}
power /= (Float) nSamples;
cout << "Estimated power: " << power.toString() << endl;
cout << "Actual power: " << spot->getPower().toString() << endl;
}
void testHG1() {
Properties props("hg");
props.setFloat("g", .8);
ref<PhaseFunction> hg = static_cast<PhaseFunction *> (PluginManager::getInstance()->
createObject(PhaseFunction::m_theClass, props));
ref<Random> random = new Random();
Float sum = 0;
Vector dir1(0, 0, 1);
const int nSamples = 100000;
MediumSamplingRecord mRec;
for (int i=0; i<nSamples; ++i) {
Vector dir2(squareToSphere(Point2(random->nextFloat(), random->nextFloat())));
sum += hg->f(mRec, dir2, dir2)[0];
}
sum *= (4 * M_PI) / nSamples;
cout << sum << endl;
}
void testHG2() {
const int res = 8;
Float buf[res][res];
Properties props("hg");
props.setFloat("g", -.2);
MediumSamplingRecord mRec;
ref<PhaseFunction> hg = static_cast<PhaseFunction *> (PluginManager::getInstance()->
createObject(PhaseFunction::m_theClass, props));
ref<Random> random = new Random();
const Vector dir1(0, 0, 1);
memset(buf, 0, sizeof(Float)*res*res);
Vector dir2;
PhaseFunction::ESampledType sampledType;
const int nSamples = 10000000;
for (int i=0; i<nSamples; ++i) {
Point2 sample(random->nextFloat(), random->nextFloat());
hg->sample(mRec, dir1, dir2, sampledType, sample);
Float pdf = hg->f(mRec, dir1, dir2)[0];
Float dir2Phi = (std::atan2(dir2.y, dir2.x) + (Float) M_PI) / (2 * (Float) M_PI);
Float dir2CosTheta = (dir2.z + 1) / (Float) 2;
int pos1 = std::max(0, std::min((int) (dir2Phi * res), res-1));
int pos2 = std::max(0, std::min((int) (dir2CosTheta* res), res-1));
buf[pos1][pos2] += 1/pdf;
}
cout << "A=[";
for (int y=0; y<res; ++y) {
for (int x=0; x<res; ++x)
cout << buf[y][x] / nSamples << " ";
cout << ";" << endl;
}
cout << "];" << endl;
}
void testMATLAB() {
int count = 256;
int dim1 = 17, dim2 = 19;
cout << "x=[";
for (int i=1; i<=count; ++i) {
cout << radicalInverse(dim1, i);
if (i+1<=count)
cout << " ";
}
cout << "];" << endl;
cout << "y=[";
for (int i=1; i<=count; ++i) {
cout << radicalInverse(dim2, i);
if (i+1<=count)
cout << " ";
}
cout << "];" << endl;
}
Float sample(Float *sigma, int n, Float u, Float &prob) {
SAssert(n >= 2);
Float cdf[4], intervalStart[3];
cdf[0] = 0;
/* Requires the coefficients to be sorted in descending order */
for (int i=0; i<n; ++i) {
/* Integrate max(f_1(t), .., f_n(t)) on [0, \infty]*/
Float lower = (i==0) ? -1 : -std::pow((sigma[i]/sigma[i-1]),
-sigma[i] / (sigma[i]-sigma[i-1]));
Float upper = (i==n-1) ? 0 : -std::pow((sigma[i+1]/sigma[i]),
-sigma[i] / (sigma[i+1]-sigma[i]));
cdf[i+1] = cdf[i] + (upper - lower);
/* Store the interval covered by each f_i */
intervalStart[i] = (i == 0) ? 0
: std::log(sigma[i]/sigma[i-1]) / (sigma[i]-sigma[i-1]);
}
/* Turn into a discrete CDF and keep the normalization factor */
Float normFactor = cdf[n];
for (int i=0; i<=n; ++i)
cdf[i] /= normFactor;
/* Find the f_i for this sample */
Float *lowerBound = std::lower_bound(&cdf[0], &cdf[n+1], u);
int index = std::max(0, (int) (lowerBound - &cdf[0]) - 1);
SAssert(index >= 0 && index < n);
/* Sample according to f_i */
Float t = -std::log(std::exp(-intervalStart[index] * sigma[index])
- normFactor * (u - cdf[index])) / sigma[index];
/* Compute the probability of this sample */
prob = sigma[index] * std::exp(-sigma[index] * t) / normFactor;
/* CDF computation
Float *lowerBound = std::lower_bound(&intervalStart[0], &intervalStart[n], t);
int index = std::max(0, (int) (lowerBound - &intervalStart[0]) - 1);
Float lower = (index==0) ? -1 : -std::pow((sigma[index]/sigma[index-1]),
-sigma[index] / (sigma[index]-sigma[index-1]));
Float upper = -std::exp(-sigma[index] * t);
Float integral = cdf[index] + (upper - lower) / normFactor;
*/
return t;
}
void testVariance() {
ref<Random> random = new Random();
Spectrum mean, meanSqr, variance;
Spectrum sigmaT;
sigmaT[0] = 0.7014;
sigmaT[1] = 1.2225;
sigmaT[2] = 1.9142;
int nSamples = 100000;
for (int chan=0; chan<3; ++chan) {
cout << "Sampling with respect to channel " << chan << endl;
mean = Spectrum(0.0f); meanSqr = Spectrum(0.0f);
for (int i=0; i<nSamples; ++i) {
Float desiredAttenuation = 1-random->nextFloat();
Float t = -std::log(desiredAttenuation)/sigmaT[chan];
Float prob = sigmaT[chan] * std::exp(-sigmaT[chan] * t);
Spectrum value = (sigmaT * (-t)).exp() / prob;
Spectrum delta = value - mean;
mean += delta / (Float) (i+1);
meanSqr += delta * (value - mean);
variance = meanSqr / (Float) i;
}
cout << "Expectation : " << (Spectrum(1)/sigmaT).toString() << endl;
cout << "Mean : " << mean.toString() << endl;
cout << "Sample variance : " << variance.toString() << endl << endl;
}
cout << "Random sampling test" << endl;
mean = Spectrum(0.0f); meanSqr = Spectrum(0.0f);
for (int i=0; i<nSamples; ++i) {
Float desiredAttenuation = 1-random->nextFloat();
int chan = random->nextInteger(3);
Float t = -std::log(desiredAttenuation)/sigmaT[chan];
Spectrum prob = sigmaT * (-sigmaT * t).exp();
Spectrum value = (sigmaT * (-t)).exp() / (prob[chan]);
Spectrum delta = value - mean;
mean += delta / (Float) (i+1);
meanSqr += delta * (value - mean);
variance = meanSqr / (Float) i;
}
cout << "Expectation : " << (Spectrum(1)/sigmaT).toString() << endl;
cout << "Mean : " << mean.toString() << endl;
cout << "Sample variance : " << variance.toString() << endl << endl;
cout << "Single sample test" << endl;
mean = Spectrum(0.0f); meanSqr = Spectrum(0.0f);
for (int i=0; i<nSamples; ++i) {
Float desiredAttenuation = 1-random->nextFloat();
int chan = random->nextInteger(3);
Float t = -std::log(desiredAttenuation)/sigmaT[chan];
Spectrum prob = sigmaT * (-sigmaT * t).exp();
Float weight = prob[chan] / (prob[0] + prob[1] + prob[2]);
Spectrum value = (sigmaT * (-t)).exp() / (prob[chan] * 1/(Float) 3) * weight;
Spectrum delta = value - mean;
mean += delta / (Float) (i+1);
meanSqr += delta * (value - mean);
variance = meanSqr / (Float) i;
}
cout << "Expectation : " << (Spectrum(1)/sigmaT).toString() << endl;
cout << "Mean : " << mean.toString() << endl;
cout << "Sample variance : " << variance.toString() << endl << endl;
cout << "New distribution test" << endl;
mean = Spectrum(0.0f); meanSqr = Spectrum(0.0f);
Float extinction[] = {1.9142, 1.2225, 0.7014};
for (int i=0; i<nSamples; ++i) {
Float prob;
Float t = sample(extinction, 3, random->nextFloat(), prob);
Spectrum value = (sigmaT * (-t)).exp() / prob;
Spectrum delta = value - mean;
mean += delta / (Float) (i+1);
meanSqr += delta * (value - mean);
variance = meanSqr / (Float) i;
}
cout << "Expectation : " << (Spectrum(1)/sigmaT).toString() << endl;
cout << "Mean : " << mean.toString() << endl;
cout << "Sample variance : " << variance.toString() << endl << endl;
}
void testPhotonMap() {
int nPhotons = 3000000;
ref<PhotonMap> map = new PhotonMap(nPhotons);
Spectrum power;
ref<Random> random = new Random();
power.fromLinearRGB(1, 2, 3);
power *= M_PI;
bool storePhoton(const Point &pos, const Vector &dir, const Spectrum &power);
for (int i=0; i<nPhotons; ++i) {
Point2 disk = squareToDisk(Point2(random->nextFloat(), random->nextFloat()));
map->storePhoton(Point(disk.x,disk.y,0), Normal(0,0,1), Vector(0, 0, -1), power, 1);
}
map->setScale(1/(Float) nPhotons);
map->balance();
for (int i=1; i<10; ++i) {
Point2 disk = squareToDisk(Point2(random->nextFloat(), random->nextFloat())) * .2;
cout << map->estimateIrradiance(Point(disk.x, disk.y, 0), Normal(0, 0, 1), .3, 10000).toString() << endl;
cout << map->estimateIrradianceFiltered(Point(disk.x, disk.y, 0), Normal(0, 0, 1), .3, 10000).toString() << endl;
}
}
void testMaxExp() {
std::vector<Float> sigmaT;
sigmaT.push_back(0.7014);
sigmaT.push_back(1.2225);
sigmaT.push_back(1.9142);
MaxExpDist dist(sigmaT);
for (int i=0; i<9; ++i) {
Float U=.01f + i/10.0f, t, pdf, cdf;
t = dist.sample(U, pdf);
cdf = dist.cdf(t);
cout << "Sampled U=" << U << " => t = " << t << ", pdf=" << pdf << ", cdf=" << cdf << endl;
}
}
void testHeterogeneous() {
ref<Sampler> sampler = static_cast<Sampler *> (PluginManager::getInstance()->
createObject(Sampler::m_theClass, Properties("independent")));
Properties props("heterogeneous");
props.setString("filename", "scenes/cornell/smoke-density.65.vol");
props.setSpectrum("sigmaS", Spectrum(2.62));
props.setSpectrum("sigmaA", Spectrum(.05f));
props.setString("strategy", "standard");
props.setFloat("sizeMultiplier", 10);
ref<Medium> standardMedium = static_cast<Medium *> (PluginManager::getInstance()->
createObject(Medium::m_theClass, props));
standardMedium->configure();
props = Properties("heterogeneous");
props.setString("filename", "scenes/cornell/smoke-density.65.vol");
props.setString("strategy", "coleman");
props.setSpectrum("sigmaS", Spectrum(2.62));
props.setSpectrum("sigmaA", Spectrum(.05f));
props.setFloat("sizeMultiplier", 10);
ref<Medium> colemanMedium = static_cast<Medium *> (PluginManager::getInstance()->
createObject(Medium::m_theClass, props));
colemanMedium->configure();
Ray ray(Point(0, 1, .4), Vector(1, 0, 0));
MediumSamplingRecord mRec;
std::ofstream distr("distr.m");
int res = 300000, failures = 0;
distr << "samplesStandard=[" << endl;
for (int i=0; i<res; ++i) {
if (standardMedium->sampleDistance(ray, std::numeric_limits<Float>::infinity(), mRec, sampler)) {
// distr << mRec.t << " ";
distr << mRec.sigmaS[0] * mRec.attenuation[0] / mRec.pdf << " " << endl;
} else {
++failures;
}
}
distr << "];" << endl;
cout << failures/(Float)res << endl;
failures = 0;
cout << failures/(Float)res << endl;
distr << "samplesColeman=[" << endl;
for (int i=0; i<res; ++i) {
if (colemanMedium->sampleDistance(ray, std::numeric_limits<Float>::infinity(), mRec, sampler)) {
// distr << mRec.t << " ";
distr << mRec.sigmaS[0] * mRec.attenuation[0] / mRec.pdf << " " << endl;
} else {
++failures;
}
}
distr << "];" << endl;
distr << "hist(samplesStandard, 300);" << endl;
distr << "title('Standard');" << endl;
distr << "figure;" << endl;
distr << "hist(samplesColeman, 300);" << endl;
distr.close();
cout << failures/(Float)res << endl;
}
void testWavelet() {
ref<FileStream> stream = new FileStream("cat.png", FileStream::EReadOnly);
ref<Bitmap> bitmap = new Bitmap(Bitmap::EPNG, stream);
ref<Wavelet2D> wavelet = new Wavelet2D(bitmap);
cout << "2D compression ratio: " << wavelet->compress(.015) << endl;
ref<SparseWavelet2D> sw = wavelet->toSparseWavelet();
ref<FileStream> stream3 = new FileStream("cat2.raw", FileStream::ETruncReadWrite);
sw->serialize(stream3, NULL);
stream3->close();
ref<FileStream> stream4 = new FileStream("cat2.raw", FileStream::EReadOnly);
ref<SparseWavelet2D> sw2 = new SparseWavelet2D(stream4, NULL);
ref<Wavelet2D> wavelet2 = new Wavelet2D(sw2);
ref<Bitmap> bitmap2 = new Bitmap(bitmap->getWidth(), bitmap->getHeight(), 8);
wavelet2->decode(bitmap2);
size_t nEntries = 512*512;
Float mean = 0, sqrError = 0;
for (size_t i=0; i<nEntries; ++i) {
mean += bitmap->getData()[i] / (255.0f * nEntries);
sqrError += std::pow(bitmap->getData()[i]/(255.0f)-bitmap2->getData()[i]/(255.0f), 2)/nEntries;
}
cout << "Mean: " << mean << ", error:" << std::sqrt(sqrError)/mean<< endl;
ref<FileStream> stream2 = new FileStream("cat2.png", FileStream::ETruncReadWrite);
bitmap2->save(Bitmap::EPNG, stream2);
}
void testLineIntegral() {
ref<FileStream> stream = new FileStream("cat.png", FileStream::EReadOnly);
ref<Bitmap> bitmap = new Bitmap(Bitmap::EPNG, stream);
Point2 start(0.121, 0.566);
Point2 end(0.815, 0.318);
Vector2 dir = Vector2(end-start);
for (int i=3; i<18; ++i) {
size_t nsteps = (int) std::ldexp((Float) 1, i);
uint8_t *data = bitmap->getData();
double accum = 0;
for (size_t i=0; i<nsteps; ++i) {
Vector2 p = (start + dir * (i / (Float) (nsteps-1)));
p *= 512;
int x = (int) p.x, y = (int) p.y;
accum += data[x+512*y] / 255.0f;
}
accum /= nsteps;
accum *= dir.length();
printf("%i steps=%f\n", (int) nsteps, accum);
}
}
void testLineIntegralWavelet() {
ref<FileStream> stream = new FileStream("cat.png", FileStream::EReadOnly);
ref<Bitmap> bitmap = new Bitmap(Bitmap::EPNG, stream);
ref<Wavelet2D> wavelet = new Wavelet2D(bitmap);
ref<SparseWavelet2D> sparse = wavelet->toSparseWavelet();
Point2 start(0.121, 0.566);
Point2 end(0.815, 0.318);
start*=512; end *= 512;
cout << sparse->lineIntegral(start, end) << endl;
}
void testSHRotation() {
ref<Random> random = new Random();
int bands = 8;
SHVector vec1(bands);
for (int l=0; l<bands; ++l)
for (int m=-l; m<=l; ++m)
vec1(l, m) = random->nextFloat();
Vector axis(squareToSphere(Point2(random->nextFloat(), random->nextFloat())));
Transform trafo = Transform::rotate(axis, random->nextFloat()*360);
Transform inv = trafo.inverse();
SHRotation rot(vec1.getBands());
SHVector::rotation(trafo, rot);
SHVector vec2(bands);
rot(vec1, vec2);
for (int i=0; i<100; ++i) {
Vector dir1(squareToSphere(Point2(random->nextFloat(), random->nextFloat()))), dir2;
trafo(dir1, dir2);
Float value1 = vec1.eval(dir2);
Float value2 = vec2.eval(dir1);
SAssert(std::abs(value1-value2) < Epsilon);
}
cout << "Passed." << endl;
}
struct ClampedCos {
Vector axis;
ClampedCos(Vector axis) : axis(axis) { }
Float operator()(const Vector &w) const { return std::max((Float) 0, dot(w, axis)); }
};
void testSHSampler() {
int bands = 25, numSamples = 100, depth = 12;
Vector v = normalize(Vector(1, 2, 3));
ref<Random> random = new Random();
SHVector clampedCos = SHVector(bands);
clampedCos.project(ClampedCos(v), numSamples);
Float clampedCosError = clampedCos.l2Error(ClampedCos(v), numSamples);
clampedCos.normalize();
cout << "Projection error = " << clampedCosError << endl;
cout << "Precomputing mip-maps" << endl;
ref<SHSampler> sampler = new SHSampler(bands, depth);
cout << "Done: "<< sampler->toString() << endl;
Float accum = 0;
int nsamples = 100;
for (int i=0; i<=nsamples; ++i) {
Point2 sample(random->nextFloat(), random->nextFloat());
Float pdf1 = sampler->warp(clampedCos, sample);
Float pdf2 = dot(v, sphericalDirection(sample.x, sample.y))/M_PI;
Float relerr = std::abs(pdf1-pdf2)/pdf2;
accum += relerr;
SAssert(relerr < 0.04);
}
SAssert(accum / nsamples < 1);
}
struct GridFunctor {
Float operator()(Float value, Float length) const {
cout << "functor(value=" << value << ", length=" << length << ")" << endl;
return 0;
}
};
void testGrid() {
Grid<Float> grid(Vector3i(3, 3, 1), AABB(Point(10, 0, 0), Point(11,1,1)));
Ray ray(Point(10 + 1.0f/6.0f, .5, .5), Vector(1, 0, 0), 0, 2.0f/3.0f);
grid(0, 1, 0) = 1;
grid(1, 1, 0) = 2;
grid(2, 1, 0) = 3;
SAssert(std::abs(grid.lookup(Point(10 + 1.0/3.0f, .5, .5))-1.5) < 1e-6);
GridFunctor functor;
grid.rasterize(ray, functor);
cout << "Expected: functor(value=1, length=" << 1.0f/6.0f << ")" << endl;
cout << "Expected: functor(value=2, length=" << 1.0f/3.0f << ")" << endl;
cout << "Expected: functor(value=3, length=" << 1.0f/6.0f << ")" << endl;
SAssert(grid(0,1,0) == 0);
SAssert(grid(1,1,0) == 0);
SAssert(grid(2,1,0) == 0);
}
int main(int argc, char **argv) {
Class::staticInitialization();
Thread::staticInitialization();
Logger::staticInitialization();
Spectrum::staticInitialization();
SHVector::staticInitialization();
try {
/*
testHalton();
testHammersley();
testRadicalInverseIncr();
testSpotLuminaire();
testHG1();
testHG2();
testVariance();
testPhotonMap();
testMaxExp();
testHeterogeneous();
testLineIntegral();
testLineIntegralWavelet();
testWaveletBasic();
testWavelet();
testWavelet3D();
testGrid();
testSHRotation();
testSHSampler();
*/
} catch (const std::exception &e) {
std::cerr << "Caught a critical exeption: " << e.what() << std::endl;
exit(-1);
} catch (...) {
std::cerr << "Caught a critical exeption of unknown type! " << std::endl;
exit(-1);
}
SHVector::staticShutdown();
Spectrum::staticShutdown();
Logger::staticShutdown();
Thread::staticShutdown();
Class::staticShutdown();
return 0;
}

View File

@ -124,6 +124,18 @@ public:
m_filename = filename;
m_fromStream = false;
char header[3];
stream->read(header, 3);
if (header[0] != 'V' || header[1] != 'O' || header[2] != 'L')
Log(EError, "Encountered an invalid volume data file (incorrect header identifier)");
uint8_t version;
stream->read(&version, 1);
if (version != 3)
Log(EError, "Encountered an invalid volume data file (incorrect file version)");
int type = stream->readInt();
if (type != 1)
Log(EError, "Encountered an invalid volume data file (incorrect data type)");
int xres = stream->readInt(), yres=stream->readInt(), zres=stream->readInt();
m_res = Vector3i(xres, yres, zres);
m_channels = stream->readInt();
@ -142,11 +154,11 @@ public:
int fd = open(resolved.c_str(), O_RDONLY);
if (fd == -1)
Log(EError, "Could not open \"%s\"!", m_filename.c_str());
m_mmapSize = (nEntries+10)*sizeof(float);
m_mmapSize = (nEntries+12)*sizeof(float);
m_mmapPtr = mmap(NULL, m_mmapSize, PROT_READ, MAP_SHARED, fd, 0);
if (m_mmapPtr == NULL)
Log(EError, "Could not map \"%s\" to memory!", m_filename.c_str());
m_data = ((float *) m_mmapPtr) + 10;
m_data = ((float *) m_mmapPtr) + 12;
if (close(fd) != 0)
Log(EError, "close(): unable to close file!");
#elif defined(WIN32)

View File

@ -3,7 +3,7 @@
<data>
<int key="IBDocument.SystemTarget">1060</int>
<string key="IBDocument.SystemVersion">10F569</string>
<string key="IBDocument.InterfaceBuilderVersion">762</string>
<string key="IBDocument.InterfaceBuilderVersion">788</string>
<string key="IBDocument.AppKitVersion">1038.29</string>
<string key="IBDocument.HIToolboxVersion">461.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
@ -15,7 +15,7 @@
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>762</string>
<string>788</string>
<string>1.2.5</string>
</object>
</object>
@ -51,7 +51,7 @@
<object class="NSWindowTemplate" id="175893971">
<int key="NSWindowStyleMask">8211</int>
<int key="NSWindowBacking">2</int>
<string key="NSWindowRect">{{157, 148}, {303, 313}}</string>
<string key="NSWindowRect">{{157, 123}, {303, 338}}</string>
<int key="NSWTFlags">-461896704</int>
<string key="NSWindowTitle">Preview settings</string>
<string key="NSWindowClass">NSPanel</string>
@ -65,7 +65,7 @@
<object class="NSTextField" id="58071968">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{17, 291}, {124, 14}}</string>
<string key="NSFrame">{{17, 316}, {124, 14}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -103,7 +103,7 @@
<object class="NSTextField" id="509807381">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{40, 267}, {52, 14}}</string>
<string key="NSFrame">{{40, 292}, {52, 14}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -124,7 +124,7 @@
<object class="BWTransparentPopUpButton" id="790524869">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{137, 261}, {147, 22}}</string>
<string key="NSFrame">{{137, 286}, {147, 22}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -212,7 +212,7 @@
<object class="BWTransparentButton" id="1013100074">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{128, 6}, {74, 28}}</string>
<string key="NSFrame">{{128, 5}, {74, 28}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -233,7 +233,7 @@
<object class="BWTransparentButton" id="616244705">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{210, 6}, {74, 28}}</string>
<string key="NSFrame">{{210, 5}, {74, 28}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -254,7 +254,7 @@
<object class="BWTransparentSlider" id="1014746031">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{136, 238}, {149, 17}}</string>
<string key="NSFrame">{{136, 263}, {149, 17}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -277,7 +277,7 @@
<object class="NSTextField" id="318481058">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{40, 240}, {72, 14}}</string>
<string key="NSFrame">{{40, 265}, {72, 14}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -294,7 +294,7 @@
<object class="NSTextField" id="58212005">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{40, 213}, {72, 14}}</string>
<string key="NSFrame">{{40, 238}, {72, 14}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -311,7 +311,7 @@
<object class="BWTransparentSlider" id="369415728">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{136, 212}, {150, 15}}</string>
<string key="NSFrame">{{136, 237}, {150, 15}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -334,7 +334,7 @@
<object class="NSTextField" id="576758915">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{40, 186}, {85, 14}}</string>
<string key="NSFrame">{{40, 185}, {85, 14}}</string>
<reference key="NSSuperview" ref="554226948"/>
<bool key="NSViewIsLayerTreeHost">YES</bool>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
@ -355,7 +355,7 @@
<object class="BWTransparentPopUpButton" id="330179">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{137, 180}, {147, 22}}</string>
<string key="NSFrame">{{137, 179}, {147, 22}}</string>
<reference key="NSSuperview" ref="554226948"/>
<bool key="NSViewIsLayerTreeHost">YES</bool>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
@ -456,7 +456,7 @@
<object class="NSTextField" id="643717735">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{17, 157}, {124, 14}}</string>
<string key="NSFrame">{{17, 156}, {124, 14}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -474,7 +474,7 @@
<object class="NSTextField" id="724311289">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{40, 133}, {52, 14}}</string>
<string key="NSFrame">{{40, 132}, {52, 14}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -491,7 +491,7 @@
<object class="BWTransparentPopUpButton" id="89867967">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{137, 127}, {147, 22}}</string>
<string key="NSFrame">{{137, 126}, {147, 22}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -548,7 +548,7 @@
<object class="NSTextField" id="200482882">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{40, 106}, {72, 14}}</string>
<string key="NSFrame">{{40, 105}, {72, 14}}</string>
<reference key="NSSuperview" ref="554226948"/>
<bool key="NSViewIsLayerTreeHost">YES</bool>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
@ -566,7 +566,7 @@
<object class="NSTextField" id="76538083">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{40, 79}, {96, 14}}</string>
<string key="NSFrame">{{40, 78}, {96, 14}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -583,7 +583,7 @@
<object class="BWTransparentSlider" id="326022836">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{136, 79}, {118, 15}}</string>
<string key="NSFrame">{{136, 78}, {118, 15}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -606,7 +606,7 @@
<object class="NSTextField" id="999583789">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{40, 52}, {85, 14}}</string>
<string key="NSFrame">{{40, 51}, {85, 14}}</string>
<reference key="NSSuperview" ref="554226948"/>
<bool key="NSViewIsLayerTreeHost">YES</bool>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
@ -624,7 +624,7 @@
<object class="NSTextField" id="429887621">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{201, 52}, {50, 14}}</string>
<string key="NSFrame">{{201, 51}, {33, 14}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -643,7 +643,7 @@
<object class="BWTransparentCheckbox" id="997380554">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{232, 50}, {95, 18}}</string>
<string key="NSFrame">{{232, 49}, {95, 18}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -655,11 +655,11 @@
<reference key="NSControlView" ref="997380554"/>
<int key="NSButtonFlags">1211912703</int>
<int key="NSButtonFlags2">130</int>
<object class="NSCustomResource" key="NSNormalImage">
<object class="NSCustomResource" key="NSNormalImage" id="188585807">
<string key="NSClassName">NSImage</string>
<string key="NSResourceName">NSSwitch</string>
</object>
<object class="NSButtonImageSource" key="NSAlternateImage">
<object class="NSButtonImageSource" key="NSAlternateImage" id="157035591">
<string key="NSImageName">NSSwitch</string>
</object>
<string key="NSAlternateContents"/>
@ -671,7 +671,7 @@
<object class="BWTransparentSlider" id="796129183">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{136, 105}, {150, 15}}</string>
<string key="NSFrame">{{136, 104}, {150, 15}}</string>
<reference key="NSSuperview" ref="554226948"/>
<bool key="NSViewIsLayerTreeHost">YES</bool>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
@ -695,7 +695,7 @@
<object class="NSTextField" id="629261074">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{256, 79}, {50, 14}}</string>
<string key="NSFrame">{{256, 78}, {50, 14}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
@ -714,7 +714,7 @@
<object class="BWTransparentSlider" id="437850691">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{136, 52}, {59, 15}}</string>
<string key="NSFrame">{{136, 51}, {59, 15}}</string>
<reference key="NSSuperview" ref="554226948"/>
<bool key="NSViewIsLayerTreeHost">YES</bool>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
@ -735,8 +735,71 @@
<bool key="NSVertical">NO</bool>
</object>
</object>
<object class="BWTransparentCheckbox" id="961464918">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{136, 210}, {66, 18}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
<object class="BWTransparentCheckboxCell" key="NSCell" id="466598751">
<int key="NSCellFlags">-2080244224</int>
<int key="NSCellFlags2">131072</int>
<string key="NSContents">Sources</string>
<reference key="NSSupport" ref="802523303"/>
<reference key="NSControlView" ref="961464918"/>
<int key="NSButtonFlags">1211912703</int>
<int key="NSButtonFlags2">130</int>
<reference key="NSNormalImage" ref="188585807"/>
<reference key="NSAlternateImage" ref="157035591"/>
<string key="NSAlternateContents"/>
<string key="NSKeyEquivalent"/>
<int key="NSPeriodicDelay">200</int>
<int key="NSPeriodicInterval">25</int>
</object>
</object>
<object class="BWTransparentCheckbox" id="494408824">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{209, 210}, {76, 18}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
<object class="BWTransparentCheckboxCell" key="NSCell" id="785052653">
<int key="NSCellFlags">-2080244224</int>
<int key="NSCellFlags2">131072</int>
<string key="NSContents">Receivers</string>
<reference key="NSSupport" ref="802523303"/>
<reference key="NSControlView" ref="494408824"/>
<int key="NSButtonFlags">1211912703</int>
<int key="NSButtonFlags2">130</int>
<reference key="NSNormalImage" ref="188585807"/>
<reference key="NSAlternateImage" ref="157035591"/>
<string key="NSAlternateContents"/>
<string key="NSKeyEquivalent"/>
<int key="NSPeriodicDelay">200</int>
<int key="NSPeriodicInterval">25</int>
</object>
</object>
<object class="NSTextField" id="410218067">
<reference key="NSNextResponder" ref="554226948"/>
<int key="NSvFlags">268</int>
<string key="NSFrame">{{40, 212}, {80, 14}}</string>
<reference key="NSSuperview" ref="554226948"/>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
<bool key="NSEnabled">YES</bool>
<object class="BWTransparentTextFieldCell" key="NSCell" id="20993774">
<int key="NSCellFlags">68288064</int>
<int key="NSCellFlags2">272761856</int>
<string key="NSContents">Force diffuse :</string>
<reference key="NSSupport" ref="26"/>
<reference key="NSControlView" ref="410218067"/>
<reference key="NSBackgroundColor" ref="788086777"/>
<reference key="NSTextColor" ref="400574078"/>
</object>
</object>
</object>
<string key="NSFrameSize">{303, 313}</string>
<string key="NSFrameSize">{303, 338}</string>
<reference key="NSSuperview"/>
<bool key="NSViewIsLayerTreeHost">YES</bool>
<int key="NSViewLayerContentsRedrawPolicy">2</int>
@ -964,6 +1027,38 @@
</object>
<int key="connectionID">311</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">diffuseSourcesBox</string>
<reference key="source" ref="1001"/>
<reference key="destination" ref="961464918"/>
</object>
<int key="connectionID">320</int>
</object>
<object class="IBConnectionRecord">
<object class="IBOutletConnection" key="connection">
<string key="label">diffuseReceiversBox</string>
<reference key="source" ref="1001"/>
<reference key="destination" ref="494408824"/>
</object>
<int key="connectionID">321</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">diffuseReceiversChanged:</string>
<reference key="source" ref="1001"/>
<reference key="destination" ref="494408824"/>
</object>
<int key="connectionID">322</int>
</object>
<object class="IBConnectionRecord">
<object class="IBActionConnection" key="connection">
<string key="label">diffuseSourcesChanged:</string>
<reference key="source" ref="1001"/>
<reference key="destination" ref="961464918"/>
</object>
<int key="connectionID">323</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
@ -1011,7 +1106,6 @@
<reference ref="318481058"/>
<reference ref="58212005"/>
<reference ref="576758915"/>
<reference ref="330179"/>
<reference ref="1014746031"/>
<reference ref="369415728"/>
<reference ref="643717735"/>
@ -1029,6 +1123,10 @@
<reference ref="429887621"/>
<reference ref="616244705"/>
<reference ref="1013100074"/>
<reference ref="961464918"/>
<reference ref="494408824"/>
<reference ref="410218067"/>
<reference ref="330179"/>
</object>
<reference key="parent" ref="175893971"/>
</object>
@ -1462,6 +1560,48 @@
<reference key="object" ref="652627433"/>
<reference key="parent" ref="437850691"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">312</int>
<reference key="object" ref="961464918"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="466598751"/>
</object>
<reference key="parent" ref="554226948"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">313</int>
<reference key="object" ref="466598751"/>
<reference key="parent" ref="961464918"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">314</int>
<reference key="object" ref="494408824"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="785052653"/>
</object>
<reference key="parent" ref="554226948"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">315</int>
<reference key="object" ref="785052653"/>
<reference key="parent" ref="494408824"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">316</int>
<reference key="object" ref="410218067"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="20993774"/>
</object>
<reference key="parent" ref="554226948"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">317</int>
<reference key="object" ref="20993774"/>
<reference key="parent" ref="410218067"/>
</object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
@ -1478,12 +1618,14 @@
<string>12.IBPluginDependency</string>
<string>13.IBPluginDependency</string>
<string>14.IBPluginDependency</string>
<string>142.IBAttributePlaceholdersKey</string>
<string>142.IBPluginDependency</string>
<string>142.IBViewIntegration.shadowBlurRadius</string>
<string>142.IBViewIntegration.shadowColor</string>
<string>142.IBViewIntegration.shadowOffsetHeight</string>
<string>142.IBViewIntegration.shadowOffsetWidth</string>
<string>143.IBPluginDependency</string>
<string>144.IBAttributePlaceholdersKey</string>
<string>144.IBPluginDependency</string>
<string>144.IBViewIntegration.shadowBlurRadius</string>
<string>144.IBViewIntegration.shadowColor</string>
@ -1503,7 +1645,9 @@
<string>17.IBPluginDependency</string>
<string>18.IBPluginDependency</string>
<string>213.IBPluginDependency</string>
<string>214.IBAttributePlaceholdersKey</string>
<string>214.IBPluginDependency</string>
<string>215.IBAttributePlaceholdersKey</string>
<string>215.IBPluginDependency</string>
<string>215.IBViewIntegration.shadowBlurRadius</string>
<string>215.IBViewIntegration.shadowColor</string>
@ -1513,6 +1657,7 @@
<string>218.IBPluginDependency</string>
<string>219.IBPluginDependency</string>
<string>220.IBPluginDependency</string>
<string>23.IBAttributePlaceholdersKey</string>
<string>23.IBPluginDependency</string>
<string>230.IBPluginDependency</string>
<string>231.IBPluginDependency</string>
@ -1528,30 +1673,49 @@
<string>242.IBPluginDependency</string>
<string>245.IBPluginDependency</string>
<string>246.IBPluginDependency</string>
<string>247.IBAttributePlaceholdersKey</string>
<string>247.IBPluginDependency</string>
<string>248.IBPluginDependency</string>
<string>260.IBPluginDependency</string>
<string>261.IBPluginDependency</string>
<string>262.IBPluginDependency</string>
<string>263.IBPluginDependency</string>
<string>290.IBAttributePlaceholdersKey</string>
<string>290.IBPluginDependency</string>
<string>291.IBPluginDependency</string>
<string>3.IBEditorWindowLastContentRect</string>
<string>3.IBPluginDependency</string>
<string>3.IBWindowTemplateEditedContentRect</string>
<string>3.NSWindowTemplate.visibleAtLaunch</string>
<string>31.IBAttributePlaceholdersKey</string>
<string>31.IBPluginDependency</string>
<string>312.IBAttributePlaceholdersKey</string>
<string>312.IBPluginDependency</string>
<string>313.IBPluginDependency</string>
<string>314.IBAttributePlaceholdersKey</string>
<string>314.IBPluginDependency</string>
<string>315.IBPluginDependency</string>
<string>316.IBAttributePlaceholdersKey</string>
<string>316.IBPluginDependency</string>
<string>317.IBPluginDependency</string>
<string>32.IBPluginDependency</string>
<string>35.IBAttributePlaceholdersKey</string>
<string>35.IBPluginDependency</string>
<string>36.IBPluginDependency</string>
<string>37.IBAttributePlaceholdersKey</string>
<string>37.IBPluginDependency</string>
<string>38.IBAttributePlaceholdersKey</string>
<string>38.IBPluginDependency</string>
<string>4.IBAttributePlaceholdersKey</string>
<string>4.IBPluginDependency</string>
<string>4.IBUserGuides</string>
<string>43.IBPluginDependency</string>
<string>5.IBPluginDependency</string>
<string>6.IBPluginDependency</string>
<string>7.IBAttributePlaceholdersKey</string>
<string>7.IBPluginDependency</string>
<string>8.IBPluginDependency</string>
<string>9.IBAttributePlaceholdersKey</string>
<string>9.IBPluginDependency</string>
<string>9.IBViewIntegration.shadowBlurRadius</string>
<string>9.IBViewIntegration.shadowColor</string>
@ -1576,12 +1740,28 @@
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="576758915"/>
<string key="toolTip">The two OpenGL preview techniques use shadow mapping to compute the light transport in a scene. This parameter allows choosing the resolution of the associated shadow maps, which is useful when the shadow quality is too low (for example when jagged edges are visible in the image). The higher this value, the slower the preview will converge. A value of 256 or 512 is usually a good start.</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<real value="0.0"/>
<reference ref="1050575761"/>
<real value="0.0"/>
<real value="0.0"/>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="330179"/>
<string key="toolTip">The two OpenGL preview techniques use shadow mapping to compute the light transport in a scene. This parameter allows choosing the resolution of the associated shadow maps, which is useful when the shadow quality is too low (for example when jagged edges are visible in the image). The higher this value, the slower the preview will converge. A value of 256 or 512 is usually a good start.</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<real value="0.0"/>
<reference ref="1050575761"/>
@ -1601,7 +1781,43 @@
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="724311289"/>
<string type="base64-UTF8" key="toolTip">QSB0b25lbWFwcGluZyBtZXRob2QgaXMgbmVjZXNzYXJ5IHRvIHRyYW5zbGF0ZSBwaHlzaWNhbCByYWRp
YW5jZSB2YWx1ZXMgaW50byBwaXhlbCBpbnRlbnNpdGllcy4gVGhlIHRlY2huaXF1ZSBjaG9zZW4gaGVy
ZSBpcyB1c2VkIGJvdGggZm9yIHRoZSBwcmV2aWV3IGFuZCByZW5kZXJlZCBpbWFnZXMuCgpHYW1tYSBj
b3JyZWN0aW9uIGlzIHRoZSBkZWZhdWx0IGFuZCB3ZWxsLXN1aXRlZCBpZiB0aGUgZHluYW1pYyByYW5n
ZSBvZiB5b3VyIHNjZW5lIGlzIG5vdCB0b28gZ3JlYXQuCgpbUmVpbmhhcmQuIGV0IGFsIDIwMDJdIHdv
cmtzIHdlbGwgZm9yIHNjZW5lcyB3aXRoIGEgaGlnaCBkeW5hbWljIHJhbmdlLiBOb3RlIHRoYXQgdGhp
cyB0ZWNobmlxdWUgY29udGludWFsbHkgYWRhcHRzIHRvIHRoZSBvdmVyYWxsIGltYWdlIGJyaWdodG5l
c3MsIHdoaWNoIG1heSBwcm9kdWNlIHVuZXhwZWN0ZWQgYmVoYXZpb3IgdG9nZXRoZXIgd2l0aCB0aGUg
cmVhbHRpbWUgcHJldmlldzogd2hlbiB0dXJuaW5nIHRvIGZhY2UgYSBkYXJrIHJlZ2lvbiBvZiB0aGUg
c2NlbmUsIHRoZSB0b25lbWFwcGVyIHdpbGwgY2hhbmdlIHRoZSBleHBvc3VyZSB0byBtYWludGFpbiB0
aGUgc2FtZSBvdmVyYWxsIGJyaWdodG5lc3MuA</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="89867967"/>
<string type="base64-UTF8" key="toolTip">QSB0b25lbWFwcGluZyBtZXRob2QgaXMgbmVjZXNzYXJ5IHRvIHRyYW5zbGF0ZSBwaHlzaWNhbCByYWRp
YW5jZSB2YWx1ZXMgaW50byBwaXhlbCBpbnRlbnNpdGllcy4gVGhlIHRlY2huaXF1ZSBjaG9zZW4gaGVy
ZSBpcyB1c2VkIGJvdGggZm9yIHRoZSBwcmV2aWV3IGFuZCByZW5kZXJlZCBpbWFnZXMuCgpHYW1tYSBj
b3JyZWN0aW9uIGlzIHRoZSBkZWZhdWx0IGFuZCB3ZWxsLXN1aXRlZCBpZiB0aGUgZHluYW1pYyByYW5n
ZSBvZiB5b3VyIHNjZW5lIGlzIG5vdCB0b28gZ3JlYXQuCgpbUmVpbmhhcmQuIGV0IGFsIDIwMDJdIHdv
cmtzIHdlbGwgZm9yIHNjZW5lcyB3aXRoIGEgaGlnaCBkeW5hbWljIHJhbmdlLiBOb3RlIHRoYXQgdGhp
cyB0ZWNobmlxdWUgY29udGludWFsbHkgYWRhcHRzIHRvIHRoZSBvdmVyYWxsIGltYWdlIGJyaWdodG5l
c3MsIHdoaWNoIG1heSBwcm9kdWNlIHVuZXhwZWN0ZWQgYmVoYXZpb3IgdG9nZXRoZXIgd2l0aCB0aGUg
cmVhbHRpbWUgcHJldmlldzogd2hlbiB0dXJuaW5nIHRvIGZhY2UgYSBkYXJrIHJlZ2lvbiBvZiB0aGUg
c2NlbmUsIHRoZSB0b25lbWFwcGVyIHdpbGwgY2hhbmdlIHRoZSBleHBvc3VyZSB0byBtYWludGFpbiB0
aGUgc2FtZSBvdmVyYWxsIGJyaWdodG5lc3MuA</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<real value="0.0"/>
<reference ref="1050575761"/>
@ -1611,6 +1827,14 @@
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="1014746031"/>
<string key="toolTip">Highest path length to visualize in the preview. The lowest value corresponds to direct illumination and the highest one is 4-bounce global illumination.</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
@ -1626,30 +1850,206 @@
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="997380554"/>
<string key="toolTip">Does the viewing device have an sRGB response curve? For most monitors and LCD screens on the market, this is the case.</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="437850691"/>
<string key="toolTip">Gamma of the viewing device (usually 2.2). When sRGB is selected, this value is ignored.</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>{{204, 75}, {303, 313}}</string>
<string>{{703, 287}, {303, 338}}</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>{{204, 75}, {303, 313}}</string>
<string>{{703, 287}, {303, 338}}</string>
<boolean value="NO"/>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="318481058"/>
<string key="toolTip">Highest path length to visualize in the preview. The lowest value corresponds to direct illumination and the highest one is 4-bounce global illumination.</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="961464918"/>
<string type="base64-UTF8" key="toolTip">V2hlbiBhIHNjZW5lIGNvbnRhaW5zIG1hbnkgZ2xvc3N5IHN1cmZhY2VzLCB0aGUgcmVhbC10aW1lIHZp
c3VhbGl6YXRpb24gY2FuIHNvbWV0aW1lcyBwcm9kdWNlIGRpc3R1cmJpbmcgaW1hZ2UgYXJ0aWZhY3Rz
IChicmlnaHQgYmxvdGNoZXMpLiBUaGVzZSBldmVudHVhbGx5IGRpc2FwcGVhciBhcyB0aGUgcHJldmll
dyBjb252ZXJnZXMsIGJ1dCB3YWl0aW5nIGZvciBhIGxvbmcgdGltZSBtYXkgYmUgdW5kZXNpcmFibGUu
IFRoZSBmb2xsb3dpbmcgb3B0aW9ucyBhcmUgbWVhbnQgdG8gcmVkdWNlIHN1Y2ggaXNzdWVzOgoKRGlm
ZnVzZSBzb3VyY2VzOiB0cmVhdCBnbG9zc3kgc3VyZmFjZXMgYXQgdGhlIHNlY29uZCBib3VuY2UgYXMg
aWYgdGhleSB3ZXJlIGRpZmZ1c2UuIFRoaXMgaXMgdXN1YWxseSBwZXJmZWN0bHkgZmluZSBmb3IgcHJl
dmlld2luZyBwdXJwb3NlcyBhbmQgaXMgdGh1cyB0dXJuZWQgb24gYnkgZGVmYXVsdC4KCkRpZmZ1c2Ug
cmVjZWl2ZXJzOiB0cmVhdCBkaXJlY3RseSB2aXNpYmxlIHN1cmZhY2VzIGFzIGlmIHRoZXkgd2VyZSBk
aWZmdXNlLiBUaGlzIGlzIGxlYWRzIHRvIGEgbXVjaCBtb3JlIGFwcHJveGltYXRlIHJlc3VsdCDigJQg
ZXNzZW50aWFsbHksIGEgY2xheSB2ZXJzaW9uIG9mIHRoZSBzY2VuZSBpcyBiZWluZyByZW5kZXJlZC4</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="494408824"/>
<string type="base64-UTF8" key="toolTip">V2hlbiBhIHNjZW5lIGNvbnRhaW5zIG1hbnkgZ2xvc3N5IHN1cmZhY2VzLCB0aGUgcmVhbC10aW1lIHZp
c3VhbGl6YXRpb24gY2FuIHNvbWV0aW1lcyBwcm9kdWNlIGRpc3R1cmJpbmcgaW1hZ2UgYXJ0aWZhY3Rz
IChicmlnaHQgYmxvdGNoZXMpLiBUaGVzZSBldmVudHVhbGx5IGRpc2FwcGVhciBhcyB0aGUgcHJldmll
dyBjb252ZXJnZXMsIGJ1dCB3YWl0aW5nIGZvciBhIGxvbmcgdGltZSBtYXkgYmUgdW5kZXNpcmFibGUu
IFRoZSBmb2xsb3dpbmcgb3B0aW9ucyBhcmUgbWVhbnQgdG8gcmVkdWNlIHN1Y2ggaXNzdWVzOgoKRGlm
ZnVzZSBzb3VyY2VzOiB0cmVhdCBnbG9zc3kgc3VyZmFjZXMgYXQgdGhlIHNlY29uZCBib3VuY2UgYXMg
aWYgdGhleSB3ZXJlIGRpZmZ1c2UuIFRoaXMgaXMgdXN1YWxseSBwZXJmZWN0bHkgZmluZSBmb3IgcHJl
dmlld2luZyBwdXJwb3NlcyBhbmQgaXMgdGh1cyB0dXJuZWQgb24gYnkgZGVmYXVsdC4KCkRpZmZ1c2Ug
cmVjZWl2ZXJzOiB0cmVhdCBkaXJlY3RseSB2aXNpYmxlIHN1cmZhY2VzIGFzIGlmIHRoZXkgd2VyZSBk
aWZmdXNlLiBUaGlzIGlzIGxlYWRzIHRvIGEgbXVjaCBtb3JlIGFwcHJveGltYXRlIHJlc3VsdCAtLSBl
c3NlbnRpYWxseSwgYSBjbGF5IHZlcnNpb24gb2YgdGhlIHNjZW5lIGlzIGJlaW5nIHJlbmRlcmVkLg</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="410218067"/>
<string type="base64-UTF8" key="toolTip">V2hlbiBhIHNjZW5lIGNvbnRhaW5zIG1hbnkgZ2xvc3N5IHN1cmZhY2VzLCB0aGUgcmVhbC10aW1lIHZp
c3VhbGl6YXRpb24gY2FuIHNvbWV0aW1lcyBwcm9kdWNlIGRpc3R1cmJpbmcgaW1hZ2UgYXJ0aWZhY3Rz
IChicmlnaHQgYmxvdGNoZXMpLiBUaGVzZSBldmVudHVhbGx5IGRpc2FwcGVhciBhcyB0aGUgcHJldmll
dyBjb252ZXJnZXMsIGJ1dCB3YWl0aW5nIGZvciBhIGxvbmcgdGltZSBtYXkgYmUgdW5kZXNpcmFibGUu
IFRoZSBmb2xsb3dpbmcgb3B0aW9ucyBhcmUgbWVhbnQgdG8gcmVkdWNlIHN1Y2ggaXNzdWVzOgoKRGlm
ZnVzZSBzb3VyY2VzOiB0cmVhdCBnbG9zc3kgc3VyZmFjZXMgYXQgdGhlIHNlY29uZCBib3VuY2UgYXMg
aWYgdGhleSB3ZXJlIGRpZmZ1c2UuIFRoaXMgaXMgdXN1YWxseSBwZXJmZWN0bHkgZmluZSBmb3IgcHJl
dmlld2luZyBwdXJwb3NlcyBhbmQgaXMgdGh1cyB0dXJuZWQgb24gYnkgZGVmYXVsdC4KCkRpZmZ1c2Ug
cmVjZWl2ZXJzOiB0cmVhdCBkaXJlY3RseSB2aXNpYmxlIHN1cmZhY2VzIGFzIGlmIHRoZXkgd2VyZSBk
aWZmdXNlLiBUaGlzIGlzIGxlYWRzIHRvIGEgbXVjaCBtb3JlIGFwcHJveGltYXRlIHJlc3VsdCDigJQg
ZXNzZW50aWFsbHksIGEgY2xheSB2ZXJzaW9uIG9mIHRoZSBzY2VuZSBpcyBiZWluZyByZW5kZXJlZC4</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="58212005"/>
<string type="base64-UTF8" key="toolTip">Q2xhbXBpbmcgY2hhbmdlcyB0aGUgaW5mbHVlbmNlIHJhZGl1cyBvZiBwaG90b25zIHVzZWQgdG8gcmVu
ZGVyIHRoZSBwcmV2aWV3LiBBIHRvbyBzbWFsbCB2YWx1ZSB3aWxsIGNhdXNlIGJyaWdodCBibG90Y2hl
cyB0byBhcHBlYXIgaW4gdGhlIHByZXZpZXcsIHdoZXJlYXMgYSB0b28gbGFyZ2UgdmFsdWUgd2lsbCBh
cnRpZmljaWFsbHkgZGFya2VuIHRoZSBpbWFnZS4KCkEgZ29vZCBhcHByb2FjaCBpcyB0byBzZXQgdGhp
cyBzbGlkZXIgYXMgbG93IGFzIHBvc3NpYmxlIHdpdGhvdXQgc2VlaW5nIGRpc3R1cmJpbmcgYmxvdGNo
ZXMgaW4gdGhlIGltYWdlLg</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="369415728"/>
<string type="base64-UTF8" key="toolTip">Q2xhbXBpbmcgY2hhbmdlcyB0aGUgaW5mbHVlbmNlIHJhZGl1cyBvZiBwaG90b25zIHVzZWQgdG8gcmVu
ZGVyIHRoZSBwcmV2aWV3LiBBIHRvbyBzbWFsbCB2YWx1ZSB3aWxsIGNhdXNlIGJyaWdodCBibG90Y2hl
cyB0byBhcHBlYXIgaW4gdGhlIHByZXZpZXcsIHdoZXJlYXMgYSB0b28gbGFyZ2UgdmFsdWUgd2lsbCBh
cnRpZmljaWFsbHkgZGFya2VuIHRoZSBpbWFnZS4KCkEgZ29vZCBhcHByb2FjaCBpcyB0byBzZXQgdGhp
cyBzbGlkZXIgYXMgbG93IGFzIHBvc3NpYmxlIHdpdGhvdXQgc2VlaW5nIGRpc3R1cmJpbmcgYmxvdGNo
ZXMgaW4gdGhlIGltYWdlLg</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="1036662978"/>
<string type="base64-UTF8" key="toolTip">Q2xhbXBpbmcgY2hhbmdlcyB0aGUgaW5mbHVlbmNlIHJhZGl1cyBvZiBwaG90b25zIHVzZWQgdG8gcmVu
ZGVyIHRoZSBwcmV2aWV3LiBBIHRvbyBzbWFsbCB2YWx1ZSB3aWxsIGNhdXNlIGJyaWdodCBibG90Y2hl
cyB0byBhcHBlYXIgaW4gdGhlIHByZXZpZXcsIHdoZXJlYXMgYSB0b28gbGFyZ2UgdmFsdWUgd2lsbCBh
cnRpZmljaWFsbHkgZGFya2VuIHRoZSBpbWFnZS4KCkEgZ29vZCBhcHByb2FjaCBpcyB0byBzZXQgdGhp
cyBzbGlkZXIgYXMgbG93IGFzIHBvc3NpYmxlIHdpdGhvdXQgc2VlaW5nIGRpc3R1cmJpbmcgYmxvdGNo
ZXMgaW4gdGhlIGltYWdlLg</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="554226948"/>
<string type="base64-UTF8" key="toolTip">V2hlbiBhIHNjZW5lIGNvbnRhaW5zIG1hbnkgZ2xvc3N5IHN1cmZhY2VzLCB0aGUgcmVhbC10aW1lIHZp
c3VhbGl6YXRpb24gY2FuIHNvbWV0aW1lcyBwcm9kdWNlIGRpc3R1cmJpbmcgaW1hZ2UgYXJ0aWZhY3Rz
IChicmlnaHQgYmxvdGNoZXMpLiBUaGVzZSBldmVudHVhbGx5IGRpc2FwcGVhciBhcyB0aGUgcHJldmll
dyBjb252ZXJnZXMsIGJ1dCB3YWl0aW5nIGZvciBhIGxvbmcgdGltZSBtYXkgYmUgdW5kZXNpcmFibGUu
IFRoZSBmb2xsb3dpbmcgb3B0aW9ucyBhcmUgbWVhbnQgdG8gcmVkdWNlIHN1Y2ggaXNzdWVzOgoKRGlm
ZnVzZSBzb3VyY2VzOiB0cmVhdCBnbG9zc3kgc3VyZmFjZXMgYXQgdGhlIHNlY29uZCBib3VuY2UgYXMg
aWYgdGhleSB3ZXJlIGRpZmZ1c2UuIFRoaXMgaXMgdXN1YWxseSBwZXJmZWN0bHkgZmluZSBmb3IgcHJl
dmlld2luZyBwdXJwb3NlcyBhbmQgaXMgdGh1cyB0dXJuZWQgb24gYnkgZGVmYXVsdC4KCkRpZmZ1c2Ug
cmVjZWl2ZXJzOiB0cmVhdCBkaXJlY3RseSB2aXNpYmxlIHN1cmZhY2VzIGFzIGlmIHRoZXkgd2VyZSBk
aWZmdXNlLiBUaGlzIGlzIGxlYWRzIHRvIGEgbXVjaCBtb3JlIGFwcHJveGltYXRlIHJlc3VsdCDigJQg
ZXNzZW50aWFsbHksIGEgY2xheSB2ZXJzaW9uIG9mIHRoZSBzY2VuZSBpcyBiZWluZyByZW5kZXJlZC4</string>
</object>
</object>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<reference ref="0"/>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="509807381"/>
<string type="base64-UTF8" key="toolTip">T3BlbkdMIGFuZCBPcGVuR0wgKHNpbmdsZSBwYXNzKSB1c2UgdGhlIGdyYXBoaWNzIGNhcmQgdG8gZHJh
dyBhbiBhcHByb3hpbWF0ZSBwcmV2aWV3IG9mIHRoZSBzY2VuZSwgd2hpY2ggaXMgdXN1YWxseSBwcmVm
ZXJhYmxlIGZvciBwZXJmb3JtYW5jZSByZWFzb25zLiBUaGUgc2luZ2xlIHBhc3MgdmFyaWFudCBtYWtl
cyBoZWF2eSB1c2Ugb24gZ2VvbWV0cnkgc2hhZGVycyB0byBmdXJ0aGVyIGFjY2VsZXJhdGUgcmVuZGVy
aW5nLCBidXQgZm9yIHRoaXMgdG8gYmUgYWN0dWFsbHkgZmFzdGVyLCB0aGUgY2FyZCBtdXN0IGJlIHZl
cnkgcmVjZW50IChlLmcuIEZlcm1pIGFuZCBhYm92ZSkuCgpUaGUgUmF5IFRyYWNpbmcgc3RyYXRlZ2ll
cyBhcmUgcHJlZmVyYWJsZSB3aGVuIHRoZSBzY2VuZSBjb250YWlucyBub24tdHJpYW5ndWxhciBzaGFw
ZXMsIHdoaWNoIGNhbm5vdCBlYXNpbHkgYmUgcmVuZGVyZWQgYnkgZ3JhcGhpY3MgaGFyZHdhcmUsIHN1
Y2ggYXMgcXVhZHJpY3MuIFRoZSBDb2hlcmVudCBSYXkgVHJhY2luZyB0ZWNobmlxdWUgdHJhY2VzIGZv
dXIgcmF5cyBhdCBhIHRpbWUgdXNpbmcgU1NFMi4</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<string>com.brandonwalkin.BWToolkit</string>
<object class="NSMutableDictionary">
<string key="NS.key.0">ToolTip</string>
<object class="IBToolTipAttribute" key="NS.object.0">
<string key="name">ToolTip</string>
<reference key="object" ref="790524869"/>
<string type="base64-UTF8" key="toolTip">T3BlbkdMIGFuZCBPcGVuR0wgKHNpbmdsZSBwYXNzKSB1c2UgdGhlIGdyYXBoaWNzIGNhcmQgdG8gZHJh
dyBhbiBhcHByb3hpbWF0ZSBwcmV2aWV3IG9mIHRoZSBzY2VuZSwgd2hpY2ggaXMgdXN1YWxseSBwcmVm
ZXJhYmxlIGZvciBwZXJmb3JtYW5jZSByZWFzb25zLiBUaGUgc2luZ2xlIHBhc3MgdmFyaWFudCBtYWtl
cyBoZWF2eSB1c2Ugb24gZ2VvbWV0cnkgc2hhZGVycyB0byBmdXJ0aGVyIGFjY2VsZXJhdGUgcmVuZGVy
aW5nLCBidXQgZm9yIHRoaXMgdG8gYmUgYWN0dWFsbHkgZmFzdGVyLCB0aGUgY2FyZCBtdXN0IGJlIHZl
cnkgcmVjZW50IChlLmcuIEZlcm1pIGFuZCBhYm92ZSkuCgpUaGUgUmF5IFRyYWNpbmcgc3RyYXRlZ2ll
cyBhcmUgcHJlZmVyYWJsZSB3aGVuIHRoZSBzY2VuZSBjb250YWlucyBub24tdHJpYW5ndWxhciBzaGFw
ZXMsIHdoaWNoIGNhbm5vdCBlYXNpbHkgYmUgcmVuZGVyZWQgYnkgZ3JhcGhpY3MgaGFyZHdhcmUsIHN1
Y2ggYXMgcXVhZHJpY3MuIFRoZSBDb2hlcmVudCBSYXkgVHJhY2luZyB0ZWNobmlxdWUgdHJhY2VzIGZv
dXIgcmF5cyBhdCBhIHRpbWUgdXNpbmcgU1NFMi4</string>
</object>
</object>
<string>com.brandonwalkin.BWToolkit</string>
<real value="0.0"/>
<reference ref="1050575761"/>
@ -1673,7 +2073,7 @@
</object>
</object>
<nil key="sourceID"/>
<int key="maxID">311</int>
<int key="maxID">323</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@ -1686,9 +2086,10 @@
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>clampingChanged:</string>
<string>diffuseReceiversChanged:</string>
<string>diffuseSourcesChanged:</string>
<string>exposureChanged:</string>
<string>gammaChanged:</string>
<string>myAction1:</string>
<string>pathLengthChanged:</string>
<string>previewMethodChanged:</string>
<string>reinhardKeyChanged:</string>
@ -1710,6 +2111,76 @@
<string>id</string>
<string>id</string>
<string>id</string>
<string>id</string>
</object>
</object>
<object class="NSMutableDictionary" key="actionInfosByName">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>clampingChanged:</string>
<string>diffuseReceiversChanged:</string>
<string>diffuseSourcesChanged:</string>
<string>exposureChanged:</string>
<string>gammaChanged:</string>
<string>pathLengthChanged:</string>
<string>previewMethodChanged:</string>
<string>reinhardKeyChanged:</string>
<string>reset:</string>
<string>sRGBChanged:</string>
<string>shadowMapResolutionChanged:</string>
<string>toneMappingMethodChanged:</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBActionInfo">
<string key="name">clampingChanged:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo">
<string key="name">diffuseReceiversChanged:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo">
<string key="name">diffuseSourcesChanged:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo">
<string key="name">exposureChanged:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo">
<string key="name">gammaChanged:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo">
<string key="name">pathLengthChanged:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo">
<string key="name">previewMethodChanged:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo">
<string key="name">reinhardKeyChanged:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo">
<string key="name">reset:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo">
<string key="name">sRGBChanged:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo">
<string key="name">shadowMapResolutionChanged:</string>
<string key="candidateClassName">id</string>
</object>
<object class="IBActionInfo">
<string key="name">toneMappingMethodChanged:</string>
<string key="candidateClassName">id</string>
</object>
</object>
</object>
<object class="NSMutableDictionary" key="outlets">
@ -1717,6 +2188,8 @@
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>clamping</string>
<string>diffuseReceiversBox</string>
<string>diffuseSourcesBox</string>
<string>exposure</string>
<string>exposureLabel</string>
<string>exposureValueLabel</string>
@ -1736,6 +2209,8 @@
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>BWTransparentSlider</string>
<string>BWTransparentCheckbox</string>
<string>BWTransparentCheckbox</string>
<string>BWTransparentSlider</string>
<string>NSTextField</string>
<string>NSTextField</string>
@ -1753,6 +2228,105 @@
<string>BWTransparentPopUpButton</string>
</object>
</object>
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>clamping</string>
<string>diffuseReceiversBox</string>
<string>diffuseSourcesBox</string>
<string>exposure</string>
<string>exposureLabel</string>
<string>exposureValueLabel</string>
<string>gamma</string>
<string>gammaLabel</string>
<string>gammaValueLabel</string>
<string>panel</string>
<string>pathLength</string>
<string>previewMethod</string>
<string>reinhardKey</string>
<string>reinhardKeyLabel</string>
<string>sRGB</string>
<string>shadowMapLabel</string>
<string>shadowMapResolution</string>
<string>toneMappingMethod</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBToOneOutletInfo">
<string key="name">clamping</string>
<string key="candidateClassName">BWTransparentSlider</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">diffuseReceiversBox</string>
<string key="candidateClassName">BWTransparentCheckbox</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">diffuseSourcesBox</string>
<string key="candidateClassName">BWTransparentCheckbox</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">exposure</string>
<string key="candidateClassName">BWTransparentSlider</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">exposureLabel</string>
<string key="candidateClassName">NSTextField</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">exposureValueLabel</string>
<string key="candidateClassName">NSTextField</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">gamma</string>
<string key="candidateClassName">BWTransparentSlider</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">gammaLabel</string>
<string key="candidateClassName">NSTextField</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">gammaValueLabel</string>
<string key="candidateClassName">NSTextField</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">panel</string>
<string key="candidateClassName">NSPanel</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">pathLength</string>
<string key="candidateClassName">BWTransparentSlider</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">previewMethod</string>
<string key="candidateClassName">BWTransparentPopUpButton</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">reinhardKey</string>
<string key="candidateClassName">BWTransparentSlider</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">reinhardKeyLabel</string>
<string key="candidateClassName">NSTextField</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">sRGB</string>
<string key="candidateClassName">BWTransparentCheckbox</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">shadowMapLabel</string>
<string key="candidateClassName">NSTextField</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">shadowMapResolution</string>
<string key="candidateClassName">BWTransparentPopUpButton</string>
</object>
<object class="IBToOneOutletInfo">
<string key="name">toneMappingMethod</string>
<string key="candidateClassName">BWTransparentPopUpButton</string>
</object>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>

Binary file not shown.

View File

@ -203,9 +203,9 @@ def _detect(env):
moc = env.WhereIs('moc-qt4') or env.WhereIs('moc4') or env.WhereIs('moc')
if moc:
QTDIR = os.path.dirname(os.path.dirname(moc))
SCons.Warnings.warn(
QtdirNotFound,
"QTDIR variable is not defined, using moc executable as a hint (QTDIR=%s)" % QTDIR)
#SCons.Warnings.warn(
# QtdirNotFound,
# "QTDIR variable is not defined, using moc executable as a hint (QTDIR=%s)" % QTDIR)
return QTDIR
raise SCons.Errors.StopError(