summaryrefslogtreecommitdiffstats
path: root/src/runtime/q3dscustommaterial.cpp
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@qt.io>2017-11-29 12:10:10 +0100
committerAndy Nichols <andy.nichols@qt.io>2017-11-29 15:40:03 +0000
commit587a2bd1e4d35b8950c882876410d9ac374fb2fa (patch)
treef8214cd805a7bc7d43711dfedd4135eeaaaedceb /src/runtime/q3dscustommaterial.cpp
parentb186a9d4005f7c4eea74ae52e6a42ddd4cdff526 (diff)
Improve custom material parsing
Parse Passes completely, with the exception of Buffer that is to be added later. Task-number: QT3DS-586 Change-Id: I5e4d94f0c824d5ce7cf406c1b9320efbb10f2710 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'src/runtime/q3dscustommaterial.cpp')
-rw-r--r--src/runtime/q3dscustommaterial.cpp265
1 files changed, 214 insertions, 51 deletions
diff --git a/src/runtime/q3dscustommaterial.cpp b/src/runtime/q3dscustommaterial.cpp
index c883196..9326c11 100644
--- a/src/runtime/q3dscustommaterial.cpp
+++ b/src/runtime/q3dscustommaterial.cpp
@@ -42,11 +42,11 @@
QT_BEGIN_NAMESPACE
Q3DSCustomMaterial::Q3DSCustomMaterial()
- : m_hasTransparency(false)
+ : m_alwaysDirty(false)
+ , m_layerCount(0)
+ , m_hasTransparency(false)
, m_hasRefraction(false)
- , m_alwaysDirty(false)
, m_shaderKey(0)
- , m_layerCount(0)
{
}
@@ -94,6 +94,11 @@ QVector<Q3DSMaterial::Shader> Q3DSCustomMaterial::shaders() const
return m_shaders;
}
+QVector<Q3DSMaterial::Pass> Q3DSCustomMaterial::passes() const
+{
+ return m_passes;
+}
+
Qt3DRender::QMaterial *Q3DSCustomMaterial::generateMaterial()
{
auto material = new Qt3DRender::QMaterial();
@@ -327,26 +332,65 @@ quint32 Q3DSCustomMaterial::layerCount() const
return m_layerCount;
}
-quint32 Q3DSCustomMaterial::shaderKey() const
+bool Q3DSCustomMaterial::isAlwaysDirty() const
{
- return m_shaderKey;
+ return m_alwaysDirty;
}
-bool Q3DSCustomMaterial::alwaysDirty() const
+bool Q3DSCustomMaterial::shaderIsDielectric() const
{
- return m_alwaysDirty;
+ return m_shaderKey & Diffuse;
}
-bool Q3DSCustomMaterial::hasRefraction() const
+bool Q3DSCustomMaterial::shaderIsSpecular() const
{
- return m_hasRefraction;
+ return m_shaderKey & Specular;
+}
+
+bool Q3DSCustomMaterial::shaderIsGlossy() const
+{
+ return m_shaderKey & Glossy;
+}
+
+bool Q3DSCustomMaterial::shaderIsCutoutEnabled() const
+{
+ return m_shaderKey & Cutout;
+}
+
+bool Q3DSCustomMaterial::shaderHasRefraction() const
+{
+ return m_shaderKey & Refraction;
}
-bool Q3DSCustomMaterial::hasTransparency() const
+bool Q3DSCustomMaterial::shaderHasTransparency() const
+{
+ return m_shaderKey & Transparent;
+}
+
+bool Q3DSCustomMaterial::shaderIsDisplaced() const
+{
+ return m_shaderKey & Displace;
+}
+
+bool Q3DSCustomMaterial::shaderIsVolumetric() const
+{
+ return m_shaderKey & Volumetric;
+}
+
+bool Q3DSCustomMaterial::shaderIsTransmissive() const
+{
+ return m_shaderKey & Transmissive;
+}
+
+bool Q3DSCustomMaterial::materialHasTransparency() const
{
return m_hasTransparency;
}
+bool Q3DSCustomMaterial::materialHasRefraction() const
+{
+ return m_hasRefraction;
+}
Q3DSCustomMaterial Q3DSCustomMaterialParser::parse(const QString &filename, bool *ok)
{
@@ -356,12 +400,12 @@ Q3DSCustomMaterial Q3DSCustomMaterialParser::parse(const QString &filename, bool
return Q3DSCustomMaterial();
}
- Q3DSCustomMaterial customMaterial;
+ m_material = Q3DSCustomMaterial();
QXmlStreamReader *r = reader();
if (r->readNextStartElement()) {
if (r->name() == QStringLiteral("Material") && r->attributes().value(QLatin1String("version")) == QStringLiteral("1.0"))
- parseMaterial(customMaterial);
+ parseMaterial();
else
r->raiseError(QObject::tr("Not a valid version 1.0 .material file"));
}
@@ -375,33 +419,34 @@ Q3DSCustomMaterial Q3DSCustomMaterialParser::parse(const QString &filename, bool
if (ok != nullptr)
*ok = true;
- return customMaterial;
+
+ return m_material;
}
-void Q3DSCustomMaterialParser::parseMaterial(Q3DSCustomMaterial &customMaterial)
+void Q3DSCustomMaterialParser::parseMaterial()
{
QXmlStreamReader *r = reader();
for (auto attribute : r->attributes()) {
if (attribute.name() == QStringLiteral("name"))
- customMaterial.m_name = attribute.value().toString();
+ m_material.m_name = attribute.value().toString();
else if (attribute.name() == QStringLiteral("description"))
- customMaterial.m_description = attribute.value().toString();
+ m_material.m_description = attribute.value().toString();
else if (attribute.name() == QStringLiteral("always-dirty"))
- customMaterial.m_alwaysDirty = true;
+ m_material.m_alwaysDirty = true;
}
- if (customMaterial.m_name.isEmpty()) // Use filename (minus extension)
- customMaterial.m_name = sourceInfo()->baseName();
+ if (m_material.m_name.isEmpty()) // Use filename (minus extension)
+ m_material.m_name = sourceInfo()->baseName();
int shadersCount = 0;
while (r->readNextStartElement()) {
if (r->name() == QStringLiteral("MetaData")) {
- parseMetaData(customMaterial);
+ parseMetaData();
} else if (r->name() == QStringLiteral("Shaders")) {
- parseShaders(customMaterial);
+ parseShaders();
shadersCount++;
} else if (r->name() == QStringLiteral("Passes")) {
- parsePasses(customMaterial);
+ parsePasses();
} else {
r->skipCurrentElement();
}
@@ -411,44 +456,44 @@ void Q3DSCustomMaterialParser::parseMaterial(Q3DSCustomMaterial &customMaterial)
r->raiseError(QObject::tr("A Shaders element is required for a valid Material"));
}
-void Q3DSCustomMaterialParser::parseMetaData(Q3DSCustomMaterial &customMaterial)
+void Q3DSCustomMaterialParser::parseMetaData()
{
QXmlStreamReader *r = reader();
for (auto attribute : r->attributes()) {
if (attribute.name() == QStringLiteral("author"))
- customMaterial.m_author = attribute.value().toString();
+ m_material.m_author = attribute.value().toString();
else if (attribute.name() == QStringLiteral("created"))
- customMaterial.m_created = attribute.value().toString();
+ m_material.m_created = attribute.value().toString();
else if (attribute.name() == QStringLiteral("modified"))
- customMaterial.m_modified = attribute.value().toString();
+ m_material.m_modified = attribute.value().toString();
}
while (r->readNextStartElement()) {
if (r->name() == QStringLiteral("Property"))
- parseProperty(customMaterial);
+ parseProperty();
else
r->skipCurrentElement();
}
}
-void Q3DSCustomMaterialParser::parseShaders(Q3DSCustomMaterial &customMaterial)
+void Q3DSCustomMaterialParser::parseShaders()
{
QXmlStreamReader *r = reader();
for (auto attribute : r->attributes()) {
if (attribute.name() == QStringLiteral("type"))
- customMaterial.m_shaderType = attribute.value().toString();
+ m_material.m_shaderType = attribute.value().toString();
else if (attribute.name() == QStringLiteral("version"))
- customMaterial.m_shadersVersion = attribute.value().toString();
+ m_material.m_shadersVersion = attribute.value().toString();
}
int shaderCount = 0;
while (r->readNextStartElement()) {
if (r->name() == QStringLiteral("Shared")) {
- if ( r->readNext() == QXmlStreamReader::Characters)
- customMaterial.m_shadersSharedCode = r->text().toString().trimmed();
+ if (r->readNext() == QXmlStreamReader::Characters)
+ m_material.m_shadersSharedCode = r->text().toString().trimmed();
r->skipCurrentElement();
} else if (r->name() == QStringLiteral("Shader")) {
- parseShader(customMaterial);
+ parseShader();
shaderCount++;
} else {
r->skipCurrentElement();
@@ -458,12 +503,12 @@ void Q3DSCustomMaterialParser::parseShaders(Q3DSCustomMaterial &customMaterial)
r->raiseError(QObject::tr("At least one Shader is required for a valid Material"));
}
-void Q3DSCustomMaterialParser::parseProperty(Q3DSCustomMaterial &customMaterial)
+void Q3DSCustomMaterialParser::parseProperty()
{
QXmlStreamReader *r = reader();
Q3DSMaterial::PropertyElement property = Q3DSMaterial::parserPropertyElement(r);
- if (property.name.isEmpty() || !isPropertyNameUnique(property.name, customMaterial)) {
+ if (property.name.isEmpty() || !isPropertyNameUnique(property.name)) {
// name can not be empty
r->raiseError(QObject::tr("Property elements must have a unique name"));
}
@@ -471,36 +516,32 @@ void Q3DSCustomMaterialParser::parseProperty(Q3DSCustomMaterial &customMaterial)
if (property.formalName.isEmpty())
property.formalName = property.name;
- customMaterial.m_properties.insert(property.name, property);
+ m_material.m_properties.insert(property.name, property);
- while (r->readNextStartElement()) {
+ while (r->readNextStartElement())
r->skipCurrentElement();
- }
}
-void Q3DSCustomMaterialParser::parseShader(Q3DSCustomMaterial &customMaterial)
+void Q3DSCustomMaterialParser::parseShader()
{
QXmlStreamReader *r = reader();
Q3DSMaterial::Shader shader = Q3DSMaterial::parserShaderElement(r);
- customMaterial.m_shaders.append(shader);
+ m_material.m_shaders.append(shader);
}
-void Q3DSCustomMaterialParser::parsePasses(Q3DSCustomMaterial &customMaterial)
+void Q3DSCustomMaterialParser::parsePasses()
{
QXmlStreamReader *r = reader();
while (r->readNextStartElement()) {
if (r->name() == QStringLiteral("Pass")) {
- //TODO: Parse Pass (not used as far as I know) UICDMMetaData.cpp: LoadMaterialClassXML(...)
- while (r->readNextStartElement()) {
- r->skipCurrentElement();
- }
+ parsePass();
} else if (r->name() == QStringLiteral("ShaderKey")) {
for (auto attribute : r->attributes()) {
if (attribute.name() == QStringLiteral("value")) {
qint32 value;
if (Q3DS::convertToInt32(attribute.value(), &value, "shaderkey value", r))
- customMaterial.m_shaderKey = value;
+ m_material.m_shaderKey = value;
}
}
while (r->readNextStartElement()) {
@@ -510,15 +551,15 @@ void Q3DSCustomMaterialParser::parsePasses(Q3DSCustomMaterial &customMaterial)
for (auto attribute : r->attributes()) {
if (attribute.name() == QStringLiteral("count")) {
qint32 count;
- if (Q3DS::convertToInt32(attribute.value(), &count, "shaderkey value", r))
- customMaterial.m_layerCount = count;
+ if (Q3DS::convertToInt32(attribute.value(), &count, "layerkey value", r))
+ m_material.m_layerCount = count;
}
}
while (r->readNextStartElement()) {
r->skipCurrentElement();
}
} else if (r->name() == QStringLiteral("Buffer")) {
- // TODO: parse Buffer (not used as far as I know) UICDMMetaData.cpp: LoadMaterialClassXML(...)
+ // ### parse Buffer
while (r->readNextStartElement()) {
r->skipCurrentElement();
}
@@ -528,9 +569,131 @@ void Q3DSCustomMaterialParser::parsePasses(Q3DSCustomMaterial &customMaterial)
}
}
-bool Q3DSCustomMaterialParser::isPropertyNameUnique(const QString &name, const Q3DSCustomMaterial &customMaterial)
+void Q3DSCustomMaterialParser::parsePass()
+{
+ /* A complex example would be:
+ <Passes>
+ <ShaderKey value="20"/>
+ <LayerKey count="1"/>
+ <Buffer name="frame_buffer" format="source" filter="linear" wrap="clamp" size="1.0" lifetime="frame"/>
+ <Buffer name="dummy_buffer" type="ubyte" format="rgba" wrap="clamp" size="1.0" lifetime="frame"/>
+ <Buffer name="temp_buffer" type="fp16" format="rgba" filter="linear" wrap="clamp" size="0.5" lifetime="frame"/>
+ <Buffer name="temp_blurX" type="fp16" format="rgba" filter="linear" wrap="clamp" size="0.5" lifetime="frame"/>
+ <Buffer name="temp_blurY" type="fp16" format="rgba" filter="linear" wrap="clamp" size="0.5" lifetime="frame"/>
+ <Pass shader="NOOP" output="dummy_buffer">
+ <BufferBlit dest="frame_buffer"/>
+ </Pass>
+ <Pass shader="PREBLUR" output="temp_buffer">
+ <BufferInput value="frame_buffer" param="OriginBuffer"/>
+ </Pass>
+ <Pass shader="BLURX" output="temp_blurX">
+ <BufferInput value="temp_buffer" param="BlurBuffer"/>
+ </Pass>
+ <Pass shader="BLURY" output="temp_blurY">
+ <BufferInput value="temp_blurX" param="BlurBuffer"/>
+ <BufferInput value="temp_buffer" param="OriginBuffer"/>
+ </Pass>
+ <Pass shader="MAIN">
+ <BufferInput value="temp_blurY" param="refractiveTexture"/>
+ <Blending source="SrcAlpha" dest="OneMinusSrcAlpha"/>
+ </Pass>
+ </Passes>
+ */
+
+ QXmlStreamReader *r = reader();
+ QXmlStreamAttributes passAttrs = r->attributes();
+
+ // skip when type != "render"
+ QStringRef passType = passAttrs.value(QLatin1String("type"));
+ if (!passType.isEmpty() && passType != QStringLiteral("render")) {
+ r->skipCurrentElement();
+ return;
+ }
+
+ Q3DSMaterial::Pass pass; // sets defaults like [source], [dest], RGBA8, ...
+
+ for (auto attribute : passAttrs) {
+ if (attribute.name() == QStringLiteral("shader")) {
+ // The old runtime prefixes shader names with the custom material
+ // ID and " - ". This is skipped here since the shaders are stored
+ // per Q3DSCustomMaterial anyway.
+ pass.shaderName = attribute.value().toString();
+ } else if (attribute.name() == QStringLiteral("input")) {
+ pass.input = attribute.value().toString();
+ } else if (attribute.name() == QStringLiteral("output")) {
+ pass.output = attribute.value().toString();
+ } else if (attribute.name() == QStringLiteral("clear")) {
+ bool needsClear = false;
+ if (Q3DS::convertToBool(attribute.value(), &needsClear, "bool", r))
+ pass.needsClear = needsClear;
+ } else if (attribute.name() == QStringLiteral("format")) {
+ Q3DSMaterial::TextureFormat fmt;
+ if (Q3DSMaterial::convertToTextureFormat(attribute.value(), QLatin1String("ubyte"), &fmt, "texture format", r))
+ pass.outputFormat = fmt;
+ }
+ }
+
+ while (r->readNextStartElement()) {
+ // Commands with unspecified attributes leave the corresponding
+ // PassCommand::Data fields unset (e.g. empty string). This is
+ // different from Pass::input, output, etc. that do get a default value.
+ if (r->name() == QStringLiteral("BufferBlit")) {
+ Q3DSMaterial::PassCommand bufferBlit(Q3DSMaterial::PassCommand::BufferBlitType);
+ for (auto attribute : r->attributes()) {
+ if (attribute.name() == QStringLiteral("source"))
+ bufferBlit.data()->source = attribute.value().toString();
+ else if (attribute.name() == QStringLiteral("dest"))
+ bufferBlit.data()->destination = attribute.value().toString();
+ }
+ pass.commands.append(bufferBlit);
+ m_material.m_hasRefraction = true; // "We use buffer blits to simulate glass refraction"
+ while (r->readNextStartElement())
+ r->skipCurrentElement();
+ } else if (r->name() == QStringLiteral("BufferInput")) {
+ Q3DSMaterial::PassCommand bufferInput(Q3DSMaterial::PassCommand::BufferInputType);
+ for (auto attribute : r->attributes()) {
+ if (attribute.name() == QStringLiteral("param"))
+ bufferInput.data()->param = attribute.value().toString();
+ else if (attribute.name() == QStringLiteral("value"))
+ bufferInput.data()->value = attribute.value().toString();
+ }
+ pass.commands.append(bufferInput);
+ while (r->readNextStartElement())
+ r->skipCurrentElement();
+ } else if (r->name() == QStringLiteral("Blending")) {
+ Q3DSMaterial::PassCommand blending(Q3DSMaterial::PassCommand::BlendingType);
+ for (auto attribute : r->attributes()) {
+ if (attribute.name() == QStringLiteral("source"))
+ blending.data()->source = attribute.value().toString();
+ else if (attribute.name() == QStringLiteral("dest"))
+ blending.data()->destination = attribute.value().toString();
+ }
+ pass.commands.append(blending);
+ m_material.m_hasTransparency = true; // if we have blending we have transparency
+ while (r->readNextStartElement())
+ r->skipCurrentElement();
+ } else if (r->name() == QStringLiteral("RenderState")) {
+ Q3DSMaterial::PassCommand renderState(Q3DSMaterial::PassCommand::RenderStateType);
+ for (auto attribute : r->attributes()) {
+ if (attribute.name() == QStringLiteral("name"))
+ renderState.data()->name = attribute.value().toString();
+ else if (attribute.name() == QStringLiteral("value"))
+ renderState.data()->value = attribute.value().toString();
+ }
+ pass.commands.append(renderState);
+ while (r->readNextStartElement())
+ r->skipCurrentElement();
+ } else {
+ r->skipCurrentElement();
+ }
+ }
+
+ m_material.m_passes.append(pass);
+}
+
+bool Q3DSCustomMaterialParser::isPropertyNameUnique(const QString &name)
{
- for (auto property : customMaterial.m_properties) {
+ for (auto property : m_material.m_properties) {
if (property.name == name)
return false;
}