Added an XSLT-based scene 'upgrade' tool to handle content from old versions of Mitsuba.
Some of the documentation was improved, and there are now example bump map renderings.metadata
parent
17eb2166f0
commit
ef2c813b10
|
@ -201,7 +201,7 @@ env.Replace(CPPFLAGS=cppFlagsPrevious)
|
|||
env.Replace(CXXFLAGS=cxxFlagsPrevious)
|
||||
sys.stdout.write("Checking for Mitsuba version .. ")
|
||||
|
||||
file = open(env.GetBuildPath('#include/mitsuba/mitsuba.h'), 'r')
|
||||
file = open(env.GetBuildPath('#include/mitsuba/core/version.h'), 'r')
|
||||
MTS_VERSION=""
|
||||
for line in file:
|
||||
if line.startswith("#define MTS_VERSION "):
|
||||
|
|
|
@ -79,7 +79,7 @@ if sys.platform == 'win32':
|
|||
if hasQt:
|
||||
install('#dist', ['qtgui/mtsgui.exe'])
|
||||
install('#dist', ['QtCore4.dll', 'QtGui4.dll', 'QtXml4.dll',
|
||||
'QtNetwork4.dll', 'QtOpenGL4.dll'], prefix = env['QT4_BINPATH'])
|
||||
'QtNetwork4.dll', 'QtOpenGL4.dll', 'QtXmlPatterns4.dll'], prefix = env['QT4_BINPATH'])
|
||||
elif sys.platform == 'darwin':
|
||||
for i in plugins:
|
||||
installTargets += env.Install('#Mitsuba.app/plugins', i)
|
||||
|
@ -111,9 +111,11 @@ elif sys.platform == 'darwin':
|
|||
installTargets += env.OSXLibInst('#Mitsuba.app/Contents/Frameworks', '/Library/Frameworks/QtCore.framework/Versions/4/QtCore')
|
||||
opengl = env.OSXLibInst('#Mitsuba.app/Contents/Frameworks', '/Library/Frameworks/QtOpenGL.framework/Versions/4/QtOpenGL')
|
||||
xml = env.OSXLibInst('#Mitsuba.app/Contents/Frameworks', '/Library/Frameworks/QtXml.framework/Versions/4/QtXml')
|
||||
xmlpatterns = env.OSXLibInst('#Mitsuba.app/Contents/Frameworks', '/Library/Frameworks/QtXmlPatterns.framework/Versions/4/QtXmlPatterns')
|
||||
network = env.OSXLibInst('#Mitsuba.app/Contents/Frameworks', '/Library/Frameworks/QtNetwork.framework/Versions/4/QtNetwork')
|
||||
gui = env.OSXLibInst('#Mitsuba.app/Contents/Frameworks', '/Library/Frameworks/QtGui.framework/Versions/4/QtGui')
|
||||
installTargets += env.AddPostAction(xml, 'install_name_tool -change QtCore.framework/Versions/4/QtCore @executable_path/../Frameworks/QtCore $TARGET')
|
||||
installTargets += env.AddPostAction(xmlpatterns, 'install_name_tool -change QtCore.framework/Versions/4/QtCore @executable_path/../Frameworks/QtCore $TARGET')
|
||||
installTargets += env.AddPostAction(network, 'install_name_tool -change QtCore.framework/Versions/4/QtCore @executable_path/../Frameworks/QtCore $TARGET')
|
||||
installTargets += env.AddPostAction(gui, 'install_name_tool -change QtCore.framework/Versions/4/QtCore @executable_path/../Frameworks/QtCore $TARGET')
|
||||
installTargets += env.AddPostAction(opengl, 'install_name_tool -change QtCore.framework/Versions/4/QtCore @executable_path/../Frameworks/QtCore $TARGET')
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
|
||||
<!-- Stylesheet to upgrade pre-0.3.0 scenes -->
|
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
|
||||
<xsl:output method="xml" indent="yes" encoding="utf-8"/>
|
||||
<xsl:preserve-space elements="*"/>
|
||||
|
||||
<xsl:template match="scene">
|
||||
<scene>
|
||||
<xsl:attribute name="version">0.3.0</xsl:attribute>
|
||||
<xsl:apply-templates select="node()"/>
|
||||
</scene>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Replace the old version of the lookAt tag -->
|
||||
<xsl:template match="lookAt[@ox]">
|
||||
<scale x="-1"/>
|
||||
<lookAt>
|
||||
<xsl:attribute name="origin">
|
||||
<xsl:value-of select="@ox"/>
|
||||
<xsl:text>, </xsl:text>
|
||||
<xsl:value-of select="@oy"/>
|
||||
<xsl:text>, </xsl:text>
|
||||
<xsl:value-of select="@oz"/>
|
||||
</xsl:attribute>
|
||||
<xsl:attribute name="target">
|
||||
<xsl:value-of select="@tx"/>
|
||||
<xsl:text>, </xsl:text>
|
||||
<xsl:value-of select="@ty"/>
|
||||
<xsl:text>, </xsl:text>
|
||||
<xsl:value-of select="@tz"/>
|
||||
</xsl:attribute>
|
||||
<xsl:if test="@ux">
|
||||
<xsl:attribute name="up">
|
||||
<xsl:value-of select="@ux"/>
|
||||
<xsl:text>, </xsl:text>
|
||||
<xsl:value-of select="@uy"/>
|
||||
<xsl:text>, </xsl:text>
|
||||
<xsl:value-of select="@uz"/>
|
||||
</xsl:attribute>
|
||||
</xsl:if>
|
||||
</lookAt>
|
||||
</xsl:template>
|
||||
|
||||
<!-- There are no more 'diffuseAmount' or 'specularAmount' parameters in
|
||||
the microfacet/phong/ward plugins, and the default values have changed -->
|
||||
<xsl:template match="bsdf[@type='microfacet' or @type='phong' or @type='ward']">
|
||||
<xsl:variable name="diffuseAmount">
|
||||
<xsl:choose>
|
||||
<xsl:when test="float[@name='diffuseAmount']">
|
||||
<xsl:value-of select="float[@name='diffuseAmount']/@value"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>1.0</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="specularAmount">
|
||||
<xsl:choose>
|
||||
<xsl:when test="float[@name='specularAmount']">
|
||||
<xsl:value-of select="float[@name='specularAmount']/@value"/>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>1.0</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="specularReflectance">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@type='microfacet'">1.0</xsl:when>
|
||||
<xsl:when test="@type='phong'">0.2</xsl:when>
|
||||
<xsl:when test="@type='ward'">0.2</xsl:when>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="diffuseReflectance">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@type='microfacet'">0.0</xsl:when>
|
||||
<xsl:when test="@type='phong'">0.5</xsl:when>
|
||||
<xsl:when test="@type='ward'">0.5</xsl:when>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
|
||||
<bsdf>
|
||||
<xsl:apply-templates select="@*"/>
|
||||
|
||||
<xsl:choose>
|
||||
<xsl:when test="node()[@name='diffuseReflectance']">
|
||||
<xsl:apply-templates select="node()[@name='diffuseReflectance']" mode="scaled">
|
||||
<xsl:with-param name="scale" select="$diffuseAmount"/>
|
||||
</xsl:apply-templates>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<spectrum name="diffuseReflectance" value="{number($diffuseAmount)*number($diffuseReflectance)}"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
|
||||
<xsl:choose>
|
||||
<xsl:when test="node()[@name='specularReflectance']">
|
||||
<xsl:apply-templates select="node()[@name='specularReflectance']" mode="scaled">
|
||||
<xsl:with-param name="scale" select="$specularAmount"/>
|
||||
</xsl:apply-templates>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<spectrum name="specularReflectance" value="{number($specularAmount)*number($specularReflectance)}"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</bsdf>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="ref|texture|rgb|srgb|spectrum|blackbody" mode="scaled">
|
||||
<xsl:param name="scale"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="number($scale)!=1">
|
||||
<texture type="scale">
|
||||
<xsl:if test="@name">
|
||||
<xsl:attribute name="name">
|
||||
<xsl:value-of select="@name"/>
|
||||
</xsl:attribute>
|
||||
</xsl:if>
|
||||
<float name="scale" value="{$scale}"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="texture|ref">
|
||||
<xsl:copy>
|
||||
<xsl:attribute name="name">value</xsl:attribute>
|
||||
<xsl:apply-templates select="@*[local-name() != 'name']|node()"/>
|
||||
</xsl:copy>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:copy>
|
||||
<xsl:attribute name="name">value</xsl:attribute>
|
||||
<xsl:apply-templates select="@*[local-name() != 'name']|node()"/>
|
||||
</xsl:copy>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</texture>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="@*|node()"/>
|
||||
</xsl:copy>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Update the name of the lambertian plugin -->
|
||||
<xsl:template match="bsdf[@type='lambertian']/@type">
|
||||
<xsl:attribute name="type">diffuse</xsl:attribute>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Update the name of the microfacet plugin -->
|
||||
<xsl:template match="bsdf[@type='microfacet']/@type">
|
||||
<xsl:attribute name="type">roughplastic</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="bsdf[@type='microfacet']/float[@name='alphaB']/@name">
|
||||
<xsl:attribute name="name">alpha</xsl:attribute>
|
||||
</xsl:template>
|
||||
|
||||
<!-- There is no more 'mirror' plugin; replace with smooth chrome -->
|
||||
<xsl:template match="bsdf[@type='mirror']/@type">
|
||||
<xsl:attribute name="type">conductor</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="bsdf[@type='mirror']">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="@*|node()"/>
|
||||
<string name="material" value="Cr"/>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Update the name of the roughmetal plugin -->
|
||||
<xsl:template match="bsdf[@type='roughmetal']/@type">
|
||||
<xsl:attribute name="type">roughconductor</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="bsdf[@type='roughmetal']/float[@name='alphaB']/@name">
|
||||
<xsl:attribute name="name">alpha</xsl:attribute>
|
||||
</xsl:template>
|
||||
<xsl:template match="bsdf[@type='roughmetal']/float[@name='ior']/@name">
|
||||
<xsl:attribute name="name">eta</xsl:attribute>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Update the name of the composite plugin -->
|
||||
<xsl:template match="bsdf[@type='composite']/@type">
|
||||
<xsl:attribute name="type">mixture</xsl:attribute>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Update the name of the exrtexture plugin -->
|
||||
<xsl:template match="texture[@type='exrtexture']/@type">
|
||||
<xsl:attribute name="type">bitmap</xsl:attribute>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Update the name of the ldrtexture plugin -->
|
||||
<xsl:template match="texture[@type='ldrtexture']/@type">
|
||||
<xsl:attribute name="type">bitmap</xsl:attribute>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Default copy rule -->
|
||||
<xsl:template match="@*|node()">
|
||||
<xsl:copy>
|
||||
<xsl:apply-templates select="@*|node()"/>
|
||||
</xsl:copy>
|
||||
</xsl:template>
|
||||
</xsl:stylesheet>
|
Binary file not shown.
After Width: | Height: | Size: 172 KiB |
Binary file not shown.
After Width: | Height: | Size: 193 KiB |
|
@ -15,7 +15,7 @@
|
|||
\usepackage{color}
|
||||
\usepackage{colortbl}
|
||||
\usepackage{listings}
|
||||
\usepackage{subfigure}
|
||||
\usepackage[hang]{subfigure}
|
||||
\usepackage{enumerate}
|
||||
\usepackage{ragged2e} % Ragged-right columns with hyphenation
|
||||
\usepackage{macros}
|
||||
|
|
|
@ -53,6 +53,7 @@ class Plugin;
|
|||
class PluginManager;
|
||||
class ProgressReporter;
|
||||
class Properties;
|
||||
struct Version;
|
||||
class Random;
|
||||
struct Ray;
|
||||
struct RayDifferential;
|
||||
|
|
|
@ -21,14 +21,17 @@
|
|||
|
||||
#include <mitsuba/core/sched.h>
|
||||
|
||||
/// Default port of <tt>mtssrv</tt>
|
||||
#define MTS_DEFAULT_PORT 7554
|
||||
|
||||
/** How many work units should be sent to a remote worker
|
||||
at a time? This is a multiple of the worker's core count */
|
||||
#define BACKLOG_FACTOR 3
|
||||
#define MTS_BACKLOG_FACTOR 3
|
||||
|
||||
/** Once the back log factor drops below this value (also a
|
||||
multiple of the core size), the stream processor will
|
||||
continue sending batches of work units */
|
||||
#define CONTINUE_FACTOR 2
|
||||
#define MTS_CONTINUE_FACTOR 2
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
This file is part of Mitsuba, a physically based rendering system.
|
||||
|
||||
Copyright (c) 2007-2011 by Wenzel Jakob and others.
|
||||
|
||||
Mitsuba is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License Version 3
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
Mitsuba is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined(__PROGRAM_VERSION_H)
|
||||
#define __PROGRAM_VERSION_H
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
/// Current release of Mitsuba
|
||||
#define MTS_VERSION "0.3.0"
|
||||
|
||||
// Year of this release
|
||||
#define MTS_YEAR "2011"
|
||||
|
||||
/**
|
||||
* \brief A simple data structure for representing and comparing
|
||||
* Mitsuba version strings
|
||||
*/
|
||||
struct Version {
|
||||
public:
|
||||
/// Default constructor: initialize to an invalid version (0.0.0)
|
||||
inline Version() : m_major(0), m_minor(0), m_release(0) { }
|
||||
|
||||
/// Initialize with the specified version number
|
||||
inline Version(int major, int minor, int release)
|
||||
: m_major(major), m_minor(minor), m_release(release) { }
|
||||
|
||||
/**
|
||||
* \brief Parse a version string of the form "major.minor.release"
|
||||
* and turn it into a \ref Version structure
|
||||
*/
|
||||
Version(const std::string &versionString);
|
||||
|
||||
/// Check if this program version is \a older than \c other
|
||||
inline bool operator<(const Version &other) const {
|
||||
if (m_major < other.m_major)
|
||||
return true;
|
||||
else if (m_major > other.m_major)
|
||||
return false;
|
||||
else if (m_minor < other.m_minor)
|
||||
return true;
|
||||
else if (m_minor > other.m_minor)
|
||||
return false;
|
||||
else if (m_release < other.m_release)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Check if this program version is \a older than or equal to \c other
|
||||
inline bool operator<=(const Version &other) const {
|
||||
return *this < other || *this == other;
|
||||
}
|
||||
|
||||
/// Check if two program versions match
|
||||
inline bool operator==(const Version &other) const {
|
||||
return m_major == other.m_major
|
||||
&& m_minor == other.m_minor
|
||||
&& m_release == other.m_release;
|
||||
}
|
||||
|
||||
/// Is this a valid version number?
|
||||
bool isValid() {
|
||||
return m_major != 0 || m_minor != 0 || m_release != 0;
|
||||
}
|
||||
|
||||
/// Are the following two versions compatible?
|
||||
bool isCompatible(const Version &other) const {
|
||||
return m_major == other.m_major &&
|
||||
m_minor == other.m_minor;
|
||||
}
|
||||
|
||||
/// Turn into a string of the form "major.minor.release"
|
||||
std::string toString() const;
|
||||
|
||||
/// Return the major version
|
||||
inline int getMajorVersion() const { return m_major; }
|
||||
|
||||
/// Return the minor version
|
||||
inline int getMinorVersion() const { return m_minor; }
|
||||
|
||||
/// Return the release
|
||||
inline int getRelease() const { return m_release; }
|
||||
private:
|
||||
int m_major;
|
||||
int m_minor;
|
||||
int m_release;
|
||||
};
|
||||
|
||||
MTS_NAMESPACE_END
|
||||
|
||||
#endif /* __PROGRAM_VERSION_H */
|
|
@ -34,16 +34,6 @@
|
|||
#include <stdexcept>
|
||||
#include <limits>
|
||||
|
||||
/// Current release of Mitsuba
|
||||
#define MTS_VERSION "0.2.2"
|
||||
#define MTS_VERSION_CODE 000201
|
||||
|
||||
/// Year of this release
|
||||
#define MTS_YEAR "2011"
|
||||
|
||||
/// Default port of <tt>mtssrv</tt>
|
||||
#define MTS_DEFAULT_PORT 7554
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
@ -51,6 +41,7 @@ using std::endl;
|
|||
/**
|
||||
* Include a basic subset of the core classes
|
||||
*/
|
||||
#include <mitsuba/core/version.h>
|
||||
#include <mitsuba/core/constants.h>
|
||||
#include <mitsuba/core/fwd.h>
|
||||
#include <mitsuba/render/fwd.h>
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <xercesc/sax/AttributeList.hpp>
|
||||
#include <mitsuba/core/plugin.h>
|
||||
#include <mitsuba/core/properties.h>
|
||||
#include <mitsuba/core/version.h>
|
||||
#include <stack>
|
||||
#include <map>
|
||||
|
||||
|
@ -33,8 +34,20 @@ XERCES_CPP_NAMESPACE_END
|
|||
XERCES_CPP_NAMESPACE_USE
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
/// \brief This exception is thrown when attempting to load an outdated file
|
||||
class VersionException : public std::runtime_error {
|
||||
public:
|
||||
inline VersionException(const std::string &str, const Version &version)
|
||||
: std::runtime_error(str), m_version(version) { }
|
||||
|
||||
inline const Version &getVersion() const { return m_version; }
|
||||
private:
|
||||
Version m_version;
|
||||
};
|
||||
|
||||
/**
|
||||
* XML parser for mitsuba scene files. Uses Xerces-C and SAX
|
||||
* \brief XML parser for Mitsuba scene files. To be used with the
|
||||
* SAX interface Xerces-C++.
|
||||
*/
|
||||
class MTS_EXPORT_RENDER SceneHandler : public HandlerBase {
|
||||
public:
|
||||
|
|
|
@ -32,6 +32,10 @@ MTS_NAMESPACE_BEGIN
|
|||
* \parameter{\Unnamed}{\BSDF}{A BSDF model that should
|
||||
* be affected by the bump map}
|
||||
* }
|
||||
* \renderings{
|
||||
* \rendering{Bump map based on tileable diagonal lines}{bsdf_bump_1}
|
||||
* \rendering{An irregular bump map}{bsdf_bump_2}
|
||||
* }
|
||||
*
|
||||
* Bump mapping \cite{Blinn1978Simulation} is a simple technique for cheaply
|
||||
* adding surface detail to a rendering. This is done by perturbing the
|
||||
|
@ -41,15 +45,15 @@ MTS_NAMESPACE_BEGIN
|
|||
* without requiring any changes to the input geometry.
|
||||
*
|
||||
* The implementation in Mitsuba uses the common approach of ignoring
|
||||
* the normally negligible texture-space derivative of the base mesh
|
||||
* the usually negligible texture-space derivative of the base mesh
|
||||
* surface normal. As side effect of this decision, it is invariant
|
||||
* to constant offsets in the height field texture---only variations in
|
||||
* its luminance cause changes to the shading frame.
|
||||
*
|
||||
* Note that the magnitude of the height field variations influences
|
||||
* the strength of the displacement. If necessary, the \pluginref{scale}
|
||||
* texture plugin can be used to magnify the scale of an existing bump map.
|
||||
* \vspace{1cm}
|
||||
* the strength of the displacement. If desired, the \pluginref{scale}
|
||||
* texture plugin can be used to magnify or reduce the effect of a
|
||||
* bump map texture.
|
||||
* \begin{xml}[caption=A rough metal model with a scaled image-based bump map]
|
||||
* <bsdf type="bump">
|
||||
* <!-- The bump map is applied to a rough metal BRDF -->
|
||||
|
|
|
@ -39,7 +39,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* \medrendering{Air$\leftrightarrow$Water (IOR: 1.33) interface.
|
||||
* See \lstref{dielectric-water}.}{bsdf_dielectric_water}
|
||||
* \medrendering{Air$\leftrightarrow$Diamond (IOR: 2.419)}{bsdf_dielectric_diamond}
|
||||
* \medrendering{Air$\leftrightarrow$Glass (IOR: 1.504) interface and absorption within.
|
||||
* \medrendering{Air$\leftrightarrow$Glass (IOR: 1.504) interface with absorption.
|
||||
* See \lstref{dielectric-glass}.}{bsdf_dielectric_glass}
|
||||
* }
|
||||
*
|
||||
|
|
|
@ -64,6 +64,7 @@ public:
|
|||
props.getSpectrum("specularReflectance", Spectrum(0.2f)));
|
||||
m_exponent = new ConstantFloatTexture(
|
||||
props.getFloat("exponent", 30.0f));
|
||||
m_specularSamplingWeight = 0.0f;
|
||||
}
|
||||
|
||||
Phong(Stream *stream, InstanceManager *manager)
|
||||
|
|
|
@ -74,6 +74,7 @@ public:
|
|||
props.getSpectrum("specularReflectance", Spectrum(1.0f)));
|
||||
m_diffuseReflectance = new ConstantSpectrumTexture(
|
||||
props.getSpectrum("diffuseReflectance", Spectrum(0.5f)));
|
||||
m_specularSamplingWeight = 0.0f;
|
||||
}
|
||||
|
||||
SmoothPlastic(Stream *stream, InstanceManager *manager)
|
||||
|
|
|
@ -62,9 +62,8 @@ MTS_NAMESPACE_BEGIN
|
|||
* factor used to modulate the diffuse reflectance component\default{0.5}}
|
||||
* }
|
||||
* \renderings{
|
||||
* \medrendering{Beckmann, $\alpha=0.05$, diffuseReflectance=0}{bsdf_roughplastic_beckmann_lacquer}
|
||||
* \medrendering{Beckmann, $\alpha=0.1$}{bsdf_roughplastic_beckmann}
|
||||
* \medrendering{GGX, $\alpha=0.3$}{bsdf_roughplastic_ggx}
|
||||
* \rendering{Beckmann, $\alpha=0.1$}{bsdf_roughplastic_beckmann}
|
||||
* \rendering{GGX, $\alpha=0.3$}{bsdf_roughplastic_ggx}
|
||||
* }
|
||||
*
|
||||
* This plugin implements a realistic microfacet scattering model for rendering
|
||||
|
@ -72,6 +71,10 @@ MTS_NAMESPACE_BEGIN
|
|||
* be interpreted as a fancy version of the Cook-Torrance model and should be
|
||||
* preferred over empirical models like \pluginref{phong} and \pluginref{ward}
|
||||
* when possible.
|
||||
* \renderings{
|
||||
* \setcounter{subfigure}{2}
|
||||
* \rendering{Beckmann, $\alpha=0.05$, diffuseReflectance=0}{bsdf_roughplastic_beckmann_lacquer}
|
||||
* }
|
||||
*
|
||||
* Microfacet theory describes rough surfaces as an arrangement of unresolved and
|
||||
* ideally specular facets, whose normal directions are given by a specially
|
||||
|
@ -100,7 +103,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* the roughness cannot be textured, and anisotropic microfacet
|
||||
* distributions are not allowed.
|
||||
*
|
||||
* When no parameters are given, the plugin activates the default settings,
|
||||
* When no parameters are given, the plugin activates the defaults,
|
||||
* which describe a white polypropylene plastic material with a light amount
|
||||
* of roughness modeled using the Beckmann distribution.
|
||||
*
|
||||
|
@ -117,8 +120,7 @@ MTS_NAMESPACE_BEGIN
|
|||
* $\alpha$ roughness value into the Phong exponent.
|
||||
* This is done in a way, such that the different
|
||||
* distributions all produce a similar appearance for
|
||||
* the same value of $\alpha$.\vspace{5mm}
|
||||
*
|
||||
* the same value of $\alpha$.
|
||||
* \begin{xml}[caption={A material definition for rough, black laquer.}, label=lst:roughplastic-lacquer]
|
||||
* <bsdf type="roughplastic">
|
||||
* <string name="distribution" value="beckmann"/>
|
||||
|
@ -157,6 +159,7 @@ public:
|
|||
|
||||
m_alpha = m_distribution.transformRoughness(
|
||||
props.getFloat("alpha", 0.1f));
|
||||
m_specularSamplingWeight = 0.0f;
|
||||
}
|
||||
|
||||
RoughPlastic(Stream *stream, InstanceManager *manager)
|
||||
|
|
|
@ -121,6 +121,7 @@ public:
|
|||
m_alphaV = m_alphaU;
|
||||
else
|
||||
m_alphaV = new ConstantFloatTexture(alphaV);
|
||||
m_specularSamplingWeight = 0.0f;
|
||||
}
|
||||
|
||||
Ward(Stream *stream, InstanceManager *manager)
|
||||
|
|
|
@ -209,5 +209,25 @@ void PluginManager::staticShutdown() {
|
|||
m_instance = NULL;
|
||||
}
|
||||
|
||||
Version::Version(const std::string &versionString) {
|
||||
std::vector<std::string> tokens = tokenize(trim(versionString), ".");
|
||||
if (tokens.size() != 3)
|
||||
SLog(EError, "Unable to parse version string \"%s\"!", versionString.c_str());
|
||||
char *end_ptr = NULL;
|
||||
m_major = strtol(tokens[0].c_str(), &end_ptr, 10);
|
||||
if (*end_ptr != '\0')
|
||||
SLog(EError, "Unable to parse the major program version \"%i\"!", tokens[0].c_str());
|
||||
m_minor = strtol(tokens[1].c_str(), &end_ptr, 10);
|
||||
if (*end_ptr != '\0')
|
||||
SLog(EError, "Unable to parse the minor program version \"%i\"!", tokens[1].c_str());
|
||||
m_release = strtol(tokens[2].c_str(), &end_ptr, 10);
|
||||
if (*end_ptr != '\0')
|
||||
SLog(EError, "Unable to parse the release program version \"%i\"!", tokens[2].c_str());
|
||||
}
|
||||
|
||||
std::string Version::toString() const {
|
||||
return formatString("%i.%i.%i", m_major, m_minor, m_release);
|
||||
}
|
||||
|
||||
MTS_IMPLEMENT_CLASS(PluginManager, false, Object)
|
||||
MTS_NAMESPACE_END
|
||||
|
|
|
@ -57,7 +57,8 @@ bool Properties::getBoolean(const std::string &name) const {
|
|||
SLog(EError, "Property \"%s\" missing", name.c_str());
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EBoolean)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <boolean>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_boolean;
|
||||
}
|
||||
|
@ -67,7 +68,8 @@ bool Properties::getBoolean(const std::string &name, bool defVal) const {
|
|||
return defVal;
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EBoolean)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <boolean>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_boolean;
|
||||
}
|
||||
|
@ -85,7 +87,8 @@ int Properties::getInteger(const std::string &name) const {
|
|||
SLog(EError, "Property \"%s\" missing", name.c_str());
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EInteger)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <integer>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (int) (*it).second.v_long;
|
||||
}
|
||||
|
@ -95,7 +98,8 @@ int Properties::getInteger(const std::string &name, int defVal) const {
|
|||
return defVal;
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EInteger)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <integer>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (int) (*it).second.v_long;
|
||||
}
|
||||
|
@ -113,7 +117,8 @@ int64_t Properties::getLong(const std::string &name) const {
|
|||
SLog(EError, "Property \"%s\" missing", name.c_str());
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EInteger)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <integer>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_long;
|
||||
}
|
||||
|
@ -123,7 +128,8 @@ int64_t Properties::getLong(const std::string &name, int64_t defVal) const {
|
|||
return defVal;
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EInteger)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <integer>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_long;
|
||||
}
|
||||
|
@ -133,7 +139,8 @@ size_t Properties::getSize(const std::string &name) const {
|
|||
SLog(EError, "Property \"%s\" missing", name.c_str());
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EInteger)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <integer>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
if ((*it).second.v_long < 0)
|
||||
SLog(EError, "Size property \"%s\": expected a nonnegative value!");
|
||||
(*it).second.queried = true;
|
||||
|
@ -145,7 +152,8 @@ size_t Properties::getSize(const std::string &name, size_t defVal) const {
|
|||
return defVal;
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EInteger)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <integer>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
if ((*it).second.v_long < 0)
|
||||
SLog(EError, "Size property \"%s\": expected a nonnegative value!");
|
||||
(*it).second.queried = true;
|
||||
|
@ -166,7 +174,8 @@ Float Properties::getFloat(const std::string &name) const {
|
|||
SLog(EError, "Property \"%s\" missing", name.c_str());
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EFloat)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <float>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_float;
|
||||
}
|
||||
|
@ -176,7 +185,8 @@ Float Properties::getFloat(const std::string &name, Float defVal) const {
|
|||
return defVal;
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EFloat)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <float>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_float;
|
||||
}
|
||||
|
@ -194,7 +204,8 @@ Transform Properties::getTransform(const std::string &name) const {
|
|||
SLog(EError, "Property \"%s\" missing", name.c_str());
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != ETransform)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <transform>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_transform;
|
||||
}
|
||||
|
@ -204,7 +215,8 @@ Transform Properties::getTransform(const std::string &name, const Transform &def
|
|||
return defVal;
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != ETransform)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <transform>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_transform;
|
||||
}
|
||||
|
@ -222,7 +234,8 @@ Spectrum Properties::getSpectrum(const std::string &name) const {
|
|||
SLog(EError, "Property \"%s\" missing", name.c_str());
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != ESpectrum)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <spectrum>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_spectrum;
|
||||
}
|
||||
|
@ -232,7 +245,8 @@ Spectrum Properties::getSpectrum(const std::string &name, const Spectrum &defVal
|
|||
return defVal;
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != ESpectrum)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <spectrum>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_spectrum;
|
||||
}
|
||||
|
@ -250,7 +264,8 @@ std::string Properties::getString(const std::string &name) const {
|
|||
SLog(EError, "Property \"%s\" missing", name.c_str());
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EString)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <string>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_string;
|
||||
}
|
||||
|
@ -260,7 +275,8 @@ std::string Properties::getString(const std::string &name, const std::string &de
|
|||
return defVal;
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EString)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <string>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_string;
|
||||
}
|
||||
|
@ -286,7 +302,8 @@ Point Properties::getPoint(const std::string &name) const {
|
|||
SLog(EError, "Property \"%s\" missing", name.c_str());
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EPoint)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <point>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_point;
|
||||
}
|
||||
|
@ -296,7 +313,8 @@ Point Properties::getPoint(const std::string &name, const Point &defVal) const {
|
|||
return defVal;
|
||||
std::map<std::string, Element>::const_iterator it = m_elements.find(name);
|
||||
if ((*it).second.type != EPoint)
|
||||
SLog(EError, "Property \"%s\" has wrong type", name.c_str());
|
||||
SLog(EError, "The property \"%s\" has the wrong type (expected <point>). The detailed "
|
||||
"listing was:\n%s", name.c_str(), toString().c_str());
|
||||
(*it).second.queried = true;
|
||||
return (*it).second.v_point;
|
||||
}
|
||||
|
|
|
@ -198,12 +198,12 @@ void RemoteWorker::run() {
|
|||
m_memStream->writeInt(id);
|
||||
m_schedItem.workUnit->save(m_memStream);
|
||||
|
||||
if (++m_inFlight == BACKLOG_FACTOR * m_coreCount) {
|
||||
if (++m_inFlight == MTS_BACKLOG_FACTOR * m_coreCount) {
|
||||
flush();
|
||||
/* There are now too many packets in transit. Wait
|
||||
until this clears up a bit before attempting to
|
||||
send more work */
|
||||
while (m_inFlight > CONTINUE_FACTOR * m_coreCount)
|
||||
while (m_inFlight > MTS_CONTINUE_FACTOR * m_coreCount)
|
||||
m_finishCond->wait();
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ std::pair<Texture *, Texture *> BSDF::ensureEnergyConservation(
|
|||
<< "happening.";
|
||||
Log(EWarn, "%s", oss.str().c_str());
|
||||
Properties props("scale");
|
||||
props.setFloat("value", scale);
|
||||
props.setFloat("scale", scale);
|
||||
Texture *scaleTexture1 = static_cast<Texture *> (PluginManager::getInstance()->
|
||||
createObject(MTS_CLASS(Texture), props));
|
||||
Texture *scaleTexture2 = static_cast<Texture *> (PluginManager::getInstance()->
|
||||
|
|
|
@ -246,8 +246,10 @@ void Scene::configure() {
|
|||
m_camera->configure();
|
||||
m_sampler = m_camera->getSampler();
|
||||
} else {
|
||||
Log(EWarn, "Unable to set up a default camera -- does the scene "
|
||||
"contain anything at all?");
|
||||
m_camera = static_cast<Camera *> (PluginManager::getInstance()->
|
||||
createObject(MTS_CLASS(Camera), props));
|
||||
m_camera->configure();
|
||||
m_sampler = m_camera->getSampler();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -127,6 +127,34 @@ void SceneHandler::startElement(const XMLCh* const xmlName,
|
|||
if (name == "transform")
|
||||
m_transform = Transform();
|
||||
|
||||
if (name == "scene") {
|
||||
std::string versionString = context.attributes["version"];
|
||||
if (versionString == "")
|
||||
throw VersionException(formatString("The requested scene cannot be loaded, since it "
|
||||
"is missing version information! Since Mitsuba 0.3.0, it is "
|
||||
"mandatory that scene XML files specify the version of Mitsuba "
|
||||
"that was used at the time of their creation.\nThis makes it clear "
|
||||
"how to interpret them in the presence of a changing file format. "
|
||||
"The version should be specified within the 'scene' tag, "
|
||||
"e.g.\n\t<scene version=\"" MTS_VERSION "\">\n"
|
||||
"Please update your scene file with the right version number and try reloading it."),
|
||||
Version());
|
||||
Version fileVersion(versionString), currentVersion(MTS_VERSION);
|
||||
if (!fileVersion.isCompatible(currentVersion)) {
|
||||
if (fileVersion < currentVersion) {
|
||||
throw VersionException(formatString("The requested scene is from an older version of Mitsuba "
|
||||
"(file version: %s, current version: %s), hence the loading process was stopped. "
|
||||
"Please open the scene from within Mitsuba's graphical user interface (mtsgui) -- "
|
||||
"it will then be upgraded to the current format.",
|
||||
fileVersion.toString().c_str(), MTS_VERSION), fileVersion);
|
||||
} else {
|
||||
XMLLog(EError, "The requested scene is from an incompatible future version of Mitsuba "
|
||||
"(file version: %s, current version: %s). Giving up.",
|
||||
fileVersion.toString().c_str(), MTS_VERSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_context.push(context);
|
||||
}
|
||||
|
||||
|
@ -308,7 +336,7 @@ void SceneHandler::endElement(const XMLCh* const xmlName) {
|
|||
else if (intentString == "illuminant")
|
||||
intent = Spectrum::EIlluminant;
|
||||
else
|
||||
SLog(EError, "Invalid intent \"%s\", must be "
|
||||
XMLLog(EError, "Invalid intent \"%s\", must be "
|
||||
"\"reflectance\" or \"illuminant\"", intentString.c_str());
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ def scanFiles(dir, accept=["*.cpp"], reject=[]) :
|
|||
if hasQt:
|
||||
qtEnv = mainEnv.Clone()
|
||||
qtEnv.Append(CPPPATH=['#src/qtgui'])
|
||||
qtEnv.EnableQt4Modules(['QtGui', 'QtCore', 'QtOpenGL', 'QtXml', 'QtNetwork'])
|
||||
qtEnv.EnableQt4Modules(['QtGui', 'QtCore', 'QtOpenGL', 'QtXml', 'QtXmlPatterns', 'QtNetwork'])
|
||||
if sys.platform == 'win32':
|
||||
index = qtEnv['CXXFLAGS'].index('_CONSOLE')
|
||||
del qtEnv['CXXFLAGS'][index-1]
|
||||
|
|
|
@ -21,9 +21,11 @@
|
|||
|
||||
#include <mitsuba/core/platform.h>
|
||||
#include <QtGui>
|
||||
#include <QtXml>
|
||||
#include <mitsuba/render/scene.h>
|
||||
#include <mitsuba/render/vpl.h>
|
||||
#include <mitsuba/core/bitmap.h>
|
||||
#include <mitsuba/core/version.h>
|
||||
|
||||
using namespace mitsuba;
|
||||
|
||||
|
@ -193,6 +195,7 @@ struct SceneContext {
|
|||
int shownKDTreeLevel;
|
||||
ESelectionMode selectionMode;
|
||||
const Shape *selectedShape;
|
||||
QDomDocument doc;
|
||||
|
||||
/* Preview state */
|
||||
std::deque<VPL> vpls;
|
||||
|
@ -220,44 +223,4 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class ProgramVersion {
|
||||
public:
|
||||
inline ProgramVersion(const QString &versionString) {
|
||||
QStringList sl;
|
||||
sl = versionString.trimmed().split('.');
|
||||
SAssert(sl.size() == 3);
|
||||
major = sl[0].toInt();
|
||||
minor = sl[1].toInt();
|
||||
release = sl[2].toInt();
|
||||
}
|
||||
|
||||
inline bool operator<(const ProgramVersion &other) const {
|
||||
if (major < other.major)
|
||||
return true;
|
||||
if (major > other.major)
|
||||
return false;
|
||||
if (minor < other.minor)
|
||||
return true;
|
||||
if (minor > other.minor)
|
||||
return false;
|
||||
if (release < other.release)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool operator==(const ProgramVersion &other) const {
|
||||
return major == other.major
|
||||
&& minor == other.minor
|
||||
&& release == other.release;
|
||||
}
|
||||
|
||||
QString toString() const {
|
||||
return QString("%1.%2.%3").arg(major).arg(minor).arg(release);
|
||||
}
|
||||
private:
|
||||
int major;
|
||||
int minor;
|
||||
int release;
|
||||
};
|
||||
|
||||
#endif // QTGUI_COMMON_H
|
||||
|
|
|
@ -68,6 +68,15 @@ void LoadDialog::on_toggleButton_clicked() {
|
|||
}
|
||||
}
|
||||
|
||||
void LoadDialog::expand() {
|
||||
if (!ui->console->isVisible()) {
|
||||
ui->console->show();
|
||||
updateGeometry();
|
||||
resize(std::max(width(), 800), 500);
|
||||
ui->toggleButton->setText("-");
|
||||
}
|
||||
}
|
||||
|
||||
void LoadDialog::close() {
|
||||
Logger *logger = Thread::getThread()->getLogger();
|
||||
logger->setLogLevel(m_oldLogLevel);
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
void closeEvent(QCloseEvent *e) {
|
||||
e->ignore();
|
||||
}
|
||||
void expand();
|
||||
protected slots:
|
||||
void onTextMessage(ELogLevel level, const QString &message);
|
||||
void on_toggleButton_clicked();
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "updatedlg.h"
|
||||
#include "server.h"
|
||||
#include "save.h"
|
||||
#include "upgrade.h"
|
||||
#include <QtNetwork>
|
||||
#include <mitsuba/core/sched_remote.h>
|
||||
#include <mitsuba/core/sstream.h>
|
||||
|
@ -398,9 +399,9 @@ void MainWindow::onNetworkFinished(QNetworkReply *reply) {
|
|||
if (reply->error() == QNetworkReply::NoError) {
|
||||
try {
|
||||
QSettings settings("mitsuba-renderer.org", "qtgui");
|
||||
ProgramVersion remote(QString(reply->readAll()));
|
||||
ProgramVersion ignoredVersion(settings.value("ignoredVersion", "0.0.0").toString());
|
||||
ProgramVersion local(MTS_VERSION);
|
||||
Version remote(QString(reply->readAll()).toStdString());
|
||||
Version ignoredVersion(settings.value("ignoredVersion", "0.0.0").toString().toStdString());
|
||||
Version local(MTS_VERSION);
|
||||
|
||||
if (local < remote) {
|
||||
if (!m_manualUpdateCheck && remote == ignoredVersion)
|
||||
|
@ -413,7 +414,7 @@ void MainWindow::onNetworkFinished(QNetworkReply *reply) {
|
|||
QMessageBox::information(this, tr("Installed version is current"),
|
||||
QString("<p>You're up to date!</p>"
|
||||
"<p>Mitsuba <b>%1</b> is still the newest version available.</p>")
|
||||
.arg(local.toString()), QMessageBox::Ok);
|
||||
.arg(local.toString().c_str()), QMessageBox::Ok);
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
/* Got something weird and couldn't parse the version string --
|
||||
|
@ -618,14 +619,16 @@ SceneContext *MainWindow::loadScene(const QString &qFileName) {
|
|||
newResolver->addPath(filePath);
|
||||
for (int i=0; i<m_searchPaths.size(); ++i)
|
||||
newResolver->addPath(m_searchPaths[i].toStdString());
|
||||
|
||||
ref<SceneLoader> loadingThread
|
||||
= new SceneLoader(newResolver, filename.file_string());
|
||||
LoadDialog *loaddlg = new LoadDialog(this);
|
||||
SceneContext *result = NULL;
|
||||
ref<SceneLoader> loadingThread;
|
||||
loaddlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||
loaddlg->setWindowModality(Qt::ApplicationModal);
|
||||
loaddlg->setWindowTitle("Loading ..");
|
||||
loaddlg->show();
|
||||
|
||||
retry:
|
||||
loadingThread = new SceneLoader(newResolver, filename.file_string());
|
||||
loadingThread->start();
|
||||
|
||||
while (loadingThread->isRunning()) {
|
||||
|
@ -633,14 +636,55 @@ SceneContext *MainWindow::loadScene(const QString &qFileName) {
|
|||
loadingThread->wait(20);
|
||||
}
|
||||
loadingThread->join();
|
||||
loaddlg->close();
|
||||
|
||||
SceneContext *result = loadingThread->getResult();
|
||||
result = loadingThread->getResult();
|
||||
if (result == NULL) {
|
||||
QMessageBox::critical(this, tr("Unable to load %1").arg(qFileName),
|
||||
QString(loadingThread->getError().c_str()),
|
||||
QMessageBox::Ok);
|
||||
if (loadingThread->isVersionError()) {
|
||||
Version version = loadingThread->getVersion();
|
||||
int ret;
|
||||
if (version.isValid()) {
|
||||
ret = QMessageBox::question(this, tr("Version mismatch -- update scene file?"),
|
||||
QString("The requested scene file is from an older version of Mitsuba "
|
||||
"(%1). To work with version %2, it will need to be updated. If you "
|
||||
"continue, Mitsuba will attempt a fully automated upgrade (note that a "
|
||||
"backup copy will be made).\n\nProceed?")
|
||||
.arg(version.toString().c_str())
|
||||
.arg(MTS_VERSION), QMessageBox::Yes | QMessageBox::Cancel);
|
||||
} else {
|
||||
QMessageBox box(QMessageBox::Question, tr("Version mismatch -- update scene file?"),
|
||||
(loadingThread->getError() + "\n\nAlternatively, if this file is from version 0.2.1"
|
||||
"(the last release without explicit version numbers), you can perform a fully "
|
||||
"automated upgrade from this version. A backup copy will be made in this case.").c_str());
|
||||
QPushButton *version021Button = box.addButton(tr("Assume version 0.2.1?"), QMessageBox::YesRole);
|
||||
box.addButton(tr("Cancel"), QMessageBox::RejectRole);
|
||||
ret = box.exec();
|
||||
if (box.clickedButton() == version021Button) {
|
||||
version = Version(0, 2, 1);
|
||||
ret = QMessageBox::Yes;
|
||||
}
|
||||
}
|
||||
if (ret == QMessageBox::Yes) {
|
||||
loaddlg->expand();
|
||||
|
||||
UpgradeManager upgradeMgr(newResolver);
|
||||
try {
|
||||
upgradeMgr.performUpgrade(filename.file_string().c_str(), version);
|
||||
goto retry;
|
||||
} catch (const std::exception &ex) {
|
||||
QMessageBox::critical(this, tr("Unable to update %1").arg(qFileName),
|
||||
QString(ex.what()), QMessageBox::Ok);
|
||||
}
|
||||
} else {
|
||||
QMessageBox::critical(this, tr("Unable to load %1").arg(qFileName),
|
||||
QString("No upgrade was performed -- giving up."), QMessageBox::Ok);
|
||||
}
|
||||
} else {
|
||||
QMessageBox::critical(this, tr("Unable to load %1").arg(qFileName),
|
||||
QString(loadingThread->getError().c_str()),
|
||||
QMessageBox::Ok);
|
||||
}
|
||||
}
|
||||
loaddlg->close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
*/
|
||||
|
||||
#include "save.h"
|
||||
#include <QtXml>
|
||||
|
||||
static QDomElement findUniqueChild(QDomElement element, const char *tagName) {
|
||||
QDomElement result;
|
||||
|
@ -101,26 +100,7 @@ static void setProperties(QDomDocument &doc, QDomElement &element,
|
|||
}
|
||||
|
||||
void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
||||
QDomDocument doc("MitsubaScene");
|
||||
QFile file(ctx->fileName);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QMessageBox::critical(parent, parent->tr("Unable to save"),
|
||||
parent->tr("Unable to save changes: could not open the original scene file <b>%1</b>. "
|
||||
"Was this file moved or deleted in the meantime?").arg(ctx->fileName),
|
||||
QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
if (!doc.setContent(&file)) {
|
||||
QMessageBox::critical(parent, parent->tr("Unable to save"),
|
||||
parent->tr("Unable to save changes: could not parse the original scene file <b>%1</b>. "
|
||||
"Was this file modified in the meantime?").arg(ctx->fileName),
|
||||
QMessageBox::Ok);
|
||||
file.close();
|
||||
return;
|
||||
}
|
||||
file.close();
|
||||
|
||||
QDomElement root = doc.documentElement();
|
||||
QDomElement root = ctx->doc.documentElement();
|
||||
|
||||
// ====================================================================
|
||||
// Serialize the camera configuration
|
||||
|
@ -128,7 +108,7 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
|
||||
QDomElement camera = findUniqueChild(root, "camera");
|
||||
if (camera.isNull()) {
|
||||
camera = doc.createElement("camera");
|
||||
camera = ctx->doc.createElement("camera");
|
||||
camera.setAttribute("type", "perspective");
|
||||
root.insertAfter(camera, QDomNode());
|
||||
}
|
||||
|
@ -136,7 +116,7 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
|
||||
QDomElement fovProperty = findProperty(camera, "fov");
|
||||
if (fovProperty.isNull()) {
|
||||
fovProperty = doc.createElement("float");
|
||||
fovProperty = ctx->doc.createElement("float");
|
||||
fovProperty.setAttribute("name", "fov");
|
||||
camera.insertBefore(fovProperty, QDomNode());
|
||||
}
|
||||
|
@ -144,7 +124,7 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
|
||||
QDomElement focusDepthProperty = findProperty(camera, "focusDepth");
|
||||
if (focusDepthProperty.isNull()) {
|
||||
focusDepthProperty = doc.createElement("float");
|
||||
focusDepthProperty = ctx->doc.createElement("float");
|
||||
focusDepthProperty.setAttribute("name", "focusDepth");
|
||||
camera.insertBefore(focusDepthProperty, QDomNode());
|
||||
}
|
||||
|
@ -152,13 +132,13 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
|
||||
QDomElement cameraTransform = findUniqueChild(camera, "transform");
|
||||
if (cameraTransform.isNull()) {
|
||||
cameraTransform = doc.createElement("transform");
|
||||
cameraTransform = ctx->doc.createElement("transform");
|
||||
cameraTransform.setAttribute("name", "toWorld");
|
||||
camera.insertBefore(cameraTransform, QDomNode());
|
||||
}
|
||||
|
||||
removeChildren(cameraTransform);
|
||||
QDomElement lookAt = doc.createElement("lookAt");
|
||||
QDomElement lookAt = ctx->doc.createElement("lookAt");
|
||||
cameraTransform.insertAfter(lookAt, QDomNode());
|
||||
|
||||
Vector direction = sceneCamera->getInverseViewTransform()(Vector(0,0,1)),
|
||||
|
@ -166,7 +146,7 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
Point t, p = sceneCamera->getInverseViewTransform()(Point(0,0,0));
|
||||
|
||||
if (sceneCamera->getViewTransform().det3x3() < 0) {
|
||||
QDomElement scale = doc.createElement("scale");
|
||||
QDomElement scale = ctx->doc.createElement("scale");
|
||||
scale.setAttribute("x", "-1");
|
||||
cameraTransform.insertBefore(scale, lookAt);
|
||||
}
|
||||
|
@ -182,15 +162,15 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
|
||||
QDomElement newSampler, sampler = findUniqueChild(camera, "sampler");
|
||||
if (sampler.isNull()) {
|
||||
newSampler = doc.createElement("sampler");
|
||||
newSampler = ctx->doc.createElement("sampler");
|
||||
camera.appendChild(newSampler);
|
||||
} else {
|
||||
newSampler = doc.createElement("sampler");
|
||||
newSampler = ctx->doc.createElement("sampler");
|
||||
camera.insertAfter(newSampler, sampler);
|
||||
camera.removeChild(sampler);
|
||||
}
|
||||
|
||||
setProperties(doc, newSampler, ctx->scene->getSampler()->getProperties());
|
||||
setProperties(ctx->doc, newSampler, ctx->scene->getSampler()->getProperties());
|
||||
|
||||
// ====================================================================
|
||||
// Serialize the film configuration
|
||||
|
@ -198,7 +178,7 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
|
||||
QDomElement film = findUniqueChild(camera, "film");
|
||||
if (film.isNull()) {
|
||||
film = doc.createElement("film");
|
||||
film = ctx->doc.createElement("film");
|
||||
film.setAttribute("type", "exrfilm");
|
||||
camera.insertAfter(film, QDomNode());
|
||||
}
|
||||
|
@ -207,13 +187,13 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
QDomElement heightProperty = findProperty(film, "height");
|
||||
|
||||
if (widthProperty.isNull()) {
|
||||
widthProperty = doc.createElement("integer");
|
||||
widthProperty = ctx->doc.createElement("integer");
|
||||
widthProperty.setAttribute("name", "width");
|
||||
film.insertBefore(widthProperty, QDomNode());
|
||||
}
|
||||
|
||||
if (heightProperty.isNull()) {
|
||||
heightProperty = doc.createElement("integer");
|
||||
heightProperty = ctx->doc.createElement("integer");
|
||||
heightProperty.setAttribute("name", "height");
|
||||
film.insertBefore(heightProperty, QDomNode());
|
||||
}
|
||||
|
@ -227,14 +207,14 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
QDomElement gamma = findProperty(film, "gamma");
|
||||
|
||||
if (method.isNull()) {
|
||||
method = doc.createElement("string");
|
||||
method = ctx->doc.createElement("string");
|
||||
method.setAttribute("name", "toneMappingMethod");
|
||||
film.insertBefore(method, QDomNode());
|
||||
}
|
||||
method.setAttribute("value", ctx->toneMappingMethod == EReinhard ? "reinhard" : "gamma");
|
||||
|
||||
if (gamma.isNull()) {
|
||||
gamma = doc.createElement("float");
|
||||
gamma = ctx->doc.createElement("float");
|
||||
gamma.setAttribute("name", "gamma");
|
||||
film.insertBefore(gamma, QDomNode());
|
||||
}
|
||||
|
@ -242,7 +222,7 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
|
||||
if (ctx->toneMappingMethod == EGamma) {
|
||||
if (exposure.isNull()) {
|
||||
exposure = doc.createElement("float");
|
||||
exposure = ctx->doc.createElement("float");
|
||||
exposure.setAttribute("name", "exposure");
|
||||
film.insertBefore(exposure, QDomNode());
|
||||
}
|
||||
|
@ -253,12 +233,12 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
film.removeChild(reinhardBurn);
|
||||
} else {
|
||||
if (reinhardKey.isNull()) {
|
||||
reinhardKey = doc.createElement("float");
|
||||
reinhardKey = ctx->doc.createElement("float");
|
||||
reinhardKey.setAttribute("name", "reinhardKey");
|
||||
film.insertBefore(reinhardKey, QDomNode());
|
||||
}
|
||||
if (reinhardBurn.isNull()) {
|
||||
reinhardBurn = doc.createElement("float");
|
||||
reinhardBurn = ctx->doc.createElement("float");
|
||||
reinhardBurn.setAttribute("name", "reinhardBurn");
|
||||
film.insertBefore(reinhardBurn, QDomNode());
|
||||
}
|
||||
|
@ -279,15 +259,15 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
|
||||
QDomElement newRFilter, rfilter = findUniqueChild(film, "rfilter");
|
||||
if (rfilter.isNull()) {
|
||||
newRFilter = doc.createElement("rfilter");
|
||||
newRFilter = ctx->doc.createElement("rfilter");
|
||||
film.appendChild(rfilter);
|
||||
} else {
|
||||
newRFilter = doc.createElement("rfilter");
|
||||
newRFilter = ctx->doc.createElement("rfilter");
|
||||
film.insertAfter(newRFilter, rfilter);
|
||||
film.removeChild(rfilter);
|
||||
}
|
||||
|
||||
setProperties(doc, newRFilter, ctx->scene->getCamera()->
|
||||
setProperties(ctx->doc, newRFilter, ctx->scene->getCamera()->
|
||||
getFilm()->getReconstructionFilter()->getProperties());
|
||||
|
||||
// ====================================================================
|
||||
|
@ -295,16 +275,16 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
// ====================================================================
|
||||
|
||||
QDomElement oldIntegratorNode = findUniqueChild(root, "integrator");
|
||||
QDomElement newIntegratorNode = doc.createElement("integrator");
|
||||
QDomElement newIntegratorNode = ctx->doc.createElement("integrator");
|
||||
|
||||
const Integrator *integrator = ctx->scene->getIntegrator();
|
||||
setProperties(doc, newIntegratorNode, integrator->getProperties());
|
||||
setProperties(ctx->doc, newIntegratorNode, integrator->getProperties());
|
||||
QDomElement currentIntegratorNode = newIntegratorNode;
|
||||
|
||||
while (integrator->getSubIntegrator() != NULL) {
|
||||
integrator = integrator->getSubIntegrator();
|
||||
QDomElement childIntegratorNode = doc.createElement("integrator");
|
||||
setProperties(doc, childIntegratorNode, integrator->getProperties());
|
||||
QDomElement childIntegratorNode = ctx->doc.createElement("integrator");
|
||||
setProperties(ctx->doc, childIntegratorNode, integrator->getProperties());
|
||||
currentIntegratorNode.appendChild(childIntegratorNode);
|
||||
currentIntegratorNode = childIntegratorNode;
|
||||
}
|
||||
|
@ -312,6 +292,7 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
root.insertBefore(newIntegratorNode, oldIntegratorNode);
|
||||
root.removeChild(oldIntegratorNode);
|
||||
|
||||
QFile file;
|
||||
file.setFileName(targetFile);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) {
|
||||
QMessageBox::critical(parent, parent->tr("Unable to save"),
|
||||
|
@ -324,9 +305,14 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
is more suitable for human consumption ..
|
||||
Beware: the code below is tailored to Qt's
|
||||
output and won't work on arbitrary XML files */
|
||||
QString textContent = doc.toString();
|
||||
QString textContent = ctx->doc.toString();
|
||||
QTextStream input(&textContent);
|
||||
QTextStream output(&file);
|
||||
cleanupXML(input, output);
|
||||
file.close();
|
||||
}
|
||||
|
||||
void cleanupXML(QTextStream &input, QTextStream &output) {
|
||||
QRegExp
|
||||
filenameRegExp("filename=\"[^\"]*\""),
|
||||
nameRegExp("name=\"[^\"]*\""),
|
||||
|
@ -362,10 +348,15 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
int nameMatch = nameRegExp.indexIn(line),
|
||||
filenameMatch = filenameRegExp.indexIn(line),
|
||||
nameLength = nameRegExp.matchedLength();
|
||||
|
||||
if (tagMatch != -1 && nameMatch != -1 && filenameMatch == -1) {
|
||||
line = line.left(tagLength) + line.mid(nameMatch, nameLength) + " "
|
||||
+ line.mid(tagMatch+tagLength, nameMatch-(tagMatch+tagLength))
|
||||
+ line.mid(nameMatch+nameLength);
|
||||
QString a = line.mid(tagLength, nameMatch-tagLength).trimmed(),
|
||||
b = line.mid(nameMatch+nameLength).trimmed();
|
||||
line = line.left(tagLength) + line.mid(nameMatch, nameLength);
|
||||
if (a.length() > 0)
|
||||
line += " " + a;
|
||||
if (b.length() > 0)
|
||||
line += " " + b;
|
||||
}
|
||||
|
||||
/* Add an extra newline if this is an object tag, and if there
|
||||
|
@ -414,6 +405,8 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
hasContents = true;
|
||||
} else if (line.endsWith(" >")) {
|
||||
line = line.left(line.size()-2) + QString(">");
|
||||
} else if (line.endsWith("?>")) {
|
||||
hasContents = true;
|
||||
}
|
||||
|
||||
if (closeTag.indexIn(line) == 0)
|
||||
|
@ -421,6 +414,4 @@ void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile) {
|
|||
|
||||
output << line << endl;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
|
|
@ -19,3 +19,4 @@
|
|||
#include "common.h"
|
||||
|
||||
extern void saveScene(QWidget *parent, SceneContext *ctx, const QString &targetFile);
|
||||
extern void cleanupXML(QTextStream &input, QTextStream &output);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
SceneLoader::SceneLoader(FileResolver *resolver, const std::string &filename)
|
||||
: Thread("load"), m_resolver(resolver), m_filename(filename) {
|
||||
m_wait = new WaitFlag();
|
||||
m_versionError = false;
|
||||
}
|
||||
|
||||
SceneLoader::~SceneLoader() {
|
||||
|
@ -35,9 +36,7 @@ SceneLoader::~SceneLoader() {
|
|||
void SceneLoader::run() {
|
||||
Thread::getThread()->setFileResolver(m_resolver);
|
||||
SAXParser* parser = new SAXParser();
|
||||
std::string lowerCase = m_filename;
|
||||
for(size_t i=0; i<m_filename.size();++i)
|
||||
lowerCase[i] = std::tolower(m_filename[i]);
|
||||
std::string lowerCase = boost::to_lower_copy(m_filename);
|
||||
|
||||
SceneHandler *handler = new SceneHandler(parser,
|
||||
SceneHandler::ParameterMap());
|
||||
|
@ -90,7 +89,15 @@ void SceneLoader::run() {
|
|||
baseName = fs::basename(filename);
|
||||
|
||||
SLog(EInfo, "Parsing scene description from \"%s\" ..", m_filename.c_str());
|
||||
parser->parse(m_filename.c_str());
|
||||
|
||||
try {
|
||||
parser->parse(m_filename.c_str());
|
||||
} catch (const VersionException &ex) {
|
||||
m_versionError = true;
|
||||
m_version = ex.getVersion();
|
||||
throw;
|
||||
}
|
||||
|
||||
ref<Scene> scene = handler->getScene();
|
||||
|
||||
scene->setSourceFile(m_filename);
|
||||
|
@ -105,10 +112,19 @@ void SceneLoader::run() {
|
|||
SLog(EError, "Unable to load scene: no film found!");
|
||||
if (scene->getLuminaires().size() == 0)
|
||||
SLog(EError, "Unable to load scene: no light sources found!");
|
||||
|
||||
Vector2i size = scene->getFilm()->getSize();
|
||||
Camera *camera = scene->getCamera();
|
||||
|
||||
/* Also generate a DOM representation for the Qt-based GUI */
|
||||
QFile file(m_filename.c_str());
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
Log(EError, "Unable to open the file \"%s\"", m_filename.c_str());
|
||||
QString errorMsg;
|
||||
int line, column;
|
||||
if (!m_result->doc.setContent(&file, &errorMsg, &line, &column))
|
||||
SLog(EError, "Unable to parse file: error %s at line %i, colum %i",
|
||||
errorMsg.toStdString().c_str(), line, column);
|
||||
|
||||
m_result->scene = scene;
|
||||
m_result->sceneResID = Scheduler::getInstance()->registerResource(scene);
|
||||
m_result->renderJob = NULL;
|
||||
|
|
|
@ -35,6 +35,8 @@ public:
|
|||
|
||||
inline SceneContext *getResult() { return m_result; }
|
||||
inline const std::string &getError() const { return m_error; }
|
||||
inline bool isVersionError() const { return m_versionError; }
|
||||
inline const Version &getVersion() const { return m_version; }
|
||||
protected:
|
||||
virtual ~SceneLoader();
|
||||
private:
|
||||
|
@ -42,6 +44,8 @@ private:
|
|||
ref<WaitFlag> m_wait;
|
||||
SceneContext *m_result;
|
||||
std::string m_error, m_filename;
|
||||
bool m_versionError;
|
||||
Version m_version;
|
||||
};
|
||||
|
||||
#endif // __SCENELOADER_H
|
||||
|
|
|
@ -19,19 +19,19 @@
|
|||
#include "ui_updatedlg.h"
|
||||
#include "updatedlg.h"
|
||||
|
||||
UpdateDialog::UpdateDialog(QWidget *parent, const ProgramVersion &local,
|
||||
const ProgramVersion &remote) : QDialog(parent),
|
||||
UpdateDialog::UpdateDialog(QWidget *parent, const Version &local,
|
||||
const Version &remote) : QDialog(parent),
|
||||
ui(new Ui::UpdateDialog) {
|
||||
ui->setupUi(this);
|
||||
m_remoteVersion = remote.toString().c_str();
|
||||
ui->versionLabel->setText(QApplication::translate("UpdateDialog",
|
||||
"Version %1 has been released (you are using %2). Would you like to visit the download page?",
|
||||
0, QApplication::UnicodeUTF8).arg(remote.toString()).arg(local.toString()));
|
||||
0, QApplication::UnicodeUTF8).arg(m_remoteVersion).arg(local.toString().c_str()));
|
||||
ui->changeView->setHtml("Loading change log ..");
|
||||
m_networkManager = new QNetworkAccessManager(this);
|
||||
connect(m_networkManager, SIGNAL(finished(QNetworkReply *)),
|
||||
this, SLOT(onNetworkFinished(QNetworkReply *)));
|
||||
m_networkReply = m_networkManager->get(QNetworkRequest(QUrl("http://www.mitsuba-renderer.org/changelog.html")));
|
||||
m_remoteVersion = remote.toString();
|
||||
}
|
||||
|
||||
void UpdateDialog::onNetworkFinished(QNetworkReply *reply) {
|
||||
|
|
|
@ -29,8 +29,8 @@ namespace Ui {
|
|||
class UpdateDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
UpdateDialog(QWidget *parent, const ProgramVersion &local,
|
||||
const ProgramVersion &remote);
|
||||
UpdateDialog(QWidget *parent, const Version &local,
|
||||
const Version &remote);
|
||||
~UpdateDialog();
|
||||
protected slots:
|
||||
void on_skipButton_clicked();
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
This file is part of Mitsuba, a physically based rendering system.
|
||||
|
||||
Copyright (c) 2007-2011 by Wenzel Jakob and others.
|
||||
|
||||
Mitsuba is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License Version 3
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
Mitsuba is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "upgrade.h"
|
||||
#include "save.h"
|
||||
#include <mitsuba/core/fresolver.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <QtXmlPatterns>
|
||||
|
||||
struct VersionComparator {
|
||||
inline bool operator()(const std::pair<Version, fs::path> &s1,
|
||||
const std::pair<Version, fs::path> &s2) const {
|
||||
return s1.first < s2.first;
|
||||
}
|
||||
};
|
||||
|
||||
class XSLTMessageHandler : public QAbstractMessageHandler {
|
||||
public:
|
||||
XSLTMessageHandler() : m_fatalError(false) { }
|
||||
|
||||
void handleMessage(QtMsgType type, const QString &_descr, const QUrl &id, const QSourceLocation &loc) {
|
||||
QString descr(_descr);
|
||||
int paragraphStart = descr.indexOf("<p>");
|
||||
int paragraphEnd = descr.indexOf("</p>");
|
||||
if (paragraphStart != -1 && paragraphEnd != -1)
|
||||
descr = descr.mid(paragraphStart+3, paragraphEnd-paragraphStart-3);
|
||||
|
||||
if (loc.isNull())
|
||||
SLog(EWarn, "%s", descr.toStdString().c_str());
|
||||
else
|
||||
SLog(EWarn, "%s (line %i, column %i, url=%s)", descr.toStdString().c_str(),
|
||||
loc.line(), loc.column(), id.toString().toStdString().c_str());
|
||||
|
||||
if (type == QtFatalMsg)
|
||||
m_fatalError = true;
|
||||
}
|
||||
|
||||
inline bool fatalError() const { return m_fatalError; }
|
||||
private:
|
||||
bool m_fatalError;
|
||||
};
|
||||
|
||||
UpgradeManager::UpgradeManager(const FileResolver *resolver) : m_resolver(resolver){
|
||||
fs::path transformationPath =
|
||||
resolver->resolveAbsolute("data/schema/scene.xsd").parent_path();
|
||||
|
||||
fs::directory_iterator it(transformationPath), end;
|
||||
SLog(EInfo, "Searching for transformations..");
|
||||
|
||||
for (; it != end; ++it) {
|
||||
fs::path file = *it;
|
||||
if (boost::to_lower_copy(file.extension()) != ".xsl" ||
|
||||
!boost::starts_with(file.filename(), "upgrade_"))
|
||||
continue;
|
||||
std::string filename = file.filename();
|
||||
Version version(filename.substr(8, filename.length()-12));
|
||||
m_transformations.push_back(std::make_pair(version, file));
|
||||
}
|
||||
|
||||
std::sort(m_transformations.begin(), m_transformations.end(), VersionComparator());
|
||||
|
||||
for (size_t i=0; i<m_transformations.size(); ++i)
|
||||
SLog(EInfo, " - registered transformation \"%s\", which updates to version %s",
|
||||
m_transformations[i].second.filename().c_str(),
|
||||
m_transformations[i].first.toString().c_str());
|
||||
}
|
||||
|
||||
void UpgradeManager::performUpgrade(const QString &filename, const Version &version) {
|
||||
QString backupFilename = filename;
|
||||
if (backupFilename.endsWith(".xml", Qt::CaseInsensitive))
|
||||
backupFilename.replace(backupFilename.length()-4, 4, ".bak");
|
||||
SLog(EInfo, "Saving a backup copy of \"%s\" as \"%s\"",
|
||||
filename.toStdString().c_str(), backupFilename.toStdString().c_str());
|
||||
|
||||
QFile file(filename), backupFile(backupFilename);
|
||||
if (backupFile.exists())
|
||||
backupFile.remove();
|
||||
if (!file.copy(backupFilename))
|
||||
SLog(EError, "Could not create a backup copy -- "
|
||||
"stopping the upgrade operation!");
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
SLog(EError, "Unable to open \"%s\" with read access -- stopping "
|
||||
"the upgrade operation.", filename.toStdString().c_str());
|
||||
QByteArray inputArray = file.readAll(), outputArray;
|
||||
file.close();
|
||||
|
||||
QBuffer inputBuffer(&inputArray);
|
||||
QBuffer outputBuffer(&outputArray);
|
||||
|
||||
XSLTMessageHandler handler;
|
||||
|
||||
int nTransformations=0;
|
||||
for (size_t i=0; i<m_transformations.size(); ++i) {
|
||||
if (m_transformations[i].first <= version)
|
||||
continue;
|
||||
inputBuffer.open(QIODevice::ReadOnly);
|
||||
outputBuffer.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
||||
|
||||
SLog(EInfo, "Applying transformation \"%s\" ..",
|
||||
m_transformations[i].second.filename().c_str());
|
||||
std::string trafoFilename = m_transformations[i].second.file_string();
|
||||
QFile trafoFile(trafoFilename.c_str());
|
||||
if (!trafoFile.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
SLog(EError, "Unable to open the stylesheet \"%s\" -- stopping "
|
||||
"the upgrade operation.", trafoFilename.c_str());
|
||||
|
||||
QXmlQuery query(QXmlQuery::XSLT20);
|
||||
query.setMessageHandler(&handler);
|
||||
query.setFocus(&inputBuffer);
|
||||
query.setQuery(&trafoFile);
|
||||
if (!query.isValid())
|
||||
SLog(EError, "Unable to parse the stylesheet \"%s\" -- stopping "
|
||||
"the upgrade operation.", trafoFilename.c_str());
|
||||
|
||||
SLog(EInfo, "Transformation is ready, running it now..");
|
||||
QXmlFormatter formatter(query, &outputBuffer);
|
||||
formatter.setIndentationDepth(1);
|
||||
query.evaluateTo(&formatter);
|
||||
|
||||
if (handler.fatalError())
|
||||
SLog(EError, "A fatal error was encountered -- stopping "
|
||||
"the upgrade operation.");
|
||||
|
||||
/* Swap the outputs */
|
||||
inputBuffer.close();
|
||||
outputBuffer.close();
|
||||
inputArray = outputArray;
|
||||
++nTransformations;
|
||||
}
|
||||
|
||||
if (nTransformations == 0)
|
||||
SLog(EError, "Strange -- no transformations were applied? "
|
||||
"Stopping the upgrade operation.");
|
||||
|
||||
/* Done, write back to disk */
|
||||
SLog(EInfo, "Successfully applied %i transformations, writing the result "
|
||||
"to \"%s\" ..", nTransformations, filename.toStdString().c_str());
|
||||
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
SLog(EError, "Unable to open \"%s\" with write access -- stopping "
|
||||
"the upgrade operation.", filename.toStdString().c_str());
|
||||
}
|
||||
|
||||
QTextStream input(inputArray);
|
||||
QTextStream output(&file);
|
||||
output << "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
|
||||
<< endl << endl;
|
||||
cleanupXML(input, output);
|
||||
file.close();
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
This file is part of Mitsuba, a physically based rendering system.
|
||||
|
||||
Copyright (c) 2007-2011 by Wenzel Jakob and others.
|
||||
|
||||
Mitsuba is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License Version 3
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
Mitsuba is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined(__UPGRADEMGR_H)
|
||||
#define __UPGRADEMGR_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
class UpgradeManager : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
UpgradeManager(const FileResolver *resolver);
|
||||
|
||||
void performUpgrade(const QString &path, const Version &version);
|
||||
private:
|
||||
const FileResolver *m_resolver;
|
||||
std::vector<std::pair<Version, fs::path> > m_transformations;
|
||||
};
|
||||
|
||||
#endif // __UPGRADEMGR_H
|
|
@ -18,8 +18,7 @@
|
|||
|
||||
#include <mitsuba/render/texture.h>
|
||||
#include <mitsuba/render/shape.h>
|
||||
#include <mitsuba/core/properties.h>
|
||||
#include <mitsuba/hw/gpuprogram.h>
|
||||
#include <mitsuba/hw/basicshader.h>
|
||||
|
||||
MTS_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -31,6 +30,10 @@ MTS_NAMESPACE_BEGIN
|
|||
class ScalingTexture : public Texture {
|
||||
public:
|
||||
ScalingTexture(const Properties &props) : Texture(props) {
|
||||
if (props.hasProperty("value"))
|
||||
m_nested = new ConstantSpectrumTexture(
|
||||
props.getSpectrum("value"));
|
||||
|
||||
if (props.hasProperty("scale") && props.getType("scale") == Properties::EFloat)
|
||||
m_scale = Spectrum(props.getFloat("scale", 1.0f));
|
||||
else
|
||||
|
@ -49,11 +52,10 @@ public:
|
|||
}
|
||||
|
||||
void addChild(const std::string &name, ConfigurableObject *child) {
|
||||
if (child->getClass()->derivesFrom(MTS_CLASS(Texture))) {
|
||||
if (child->getClass()->derivesFrom(MTS_CLASS(Texture)))
|
||||
m_nested = static_cast<Texture *>(child);
|
||||
} else {
|
||||
else
|
||||
Texture::addChild(name, child);
|
||||
}
|
||||
}
|
||||
|
||||
Spectrum getValue(const Intersection &its) const {
|
||||
|
|
Loading…
Reference in New Issue