diff --git a/engine/includes/components/transform.h b/engine/includes/components/transform.h index 8926ff3f9..8e115c10d 100644 --- a/engine/includes/components/transform.h +++ b/engine/includes/components/transform.h @@ -83,7 +83,7 @@ class ENGINE_EXPORT Transform : public Component { mutable mutex m_mutex; - mutable int32_t m_hash; + mutable uint32_t m_hash; mutable bool m_dirty; }; diff --git a/engine/includes/editor/viewport/handletools.h b/engine/includes/editor/viewport/handletools.h index f84cca831..5c7a788d7 100644 --- a/engine/includes/editor/viewport/handletools.h +++ b/engine/includes/editor/viewport/handletools.h @@ -13,9 +13,6 @@ class ENGINE_EXPORT HandleTools { static float distanceToMesh(const Matrix4 &matrix, const IndexVector &indices, const Vector3Vector &vertices, const Vector2 &screen); -public: - static float s_Sense; - }; #endif // HANDLETOOLS_H diff --git a/engine/includes/resources/material.h b/engine/includes/resources/material.h index 646ebbf09..14919ace5 100644 --- a/engine/includes/resources/material.h +++ b/engine/includes/resources/material.h @@ -12,50 +12,39 @@ class ENGINE_EXPORT Material : public Resource { A_REGISTER(Material, Resource, Resources) A_PROPERTIES( - A_PROPERTY(bool, doubleSided, Material::doubleSided, Material::setDoubleSided), A_PROPERTY(int, materialType, Material::materialType, Material::setMaterialType), A_PROPERTY(int, lightModel, Material::lightModel, Material::setLightModel), + A_PROPERTY(bool, doubleSided, Material::doubleSided, Material::setDoubleSided), A_PROPERTY(bool, wireframe, Material::wireframe, Material::setWireframe) ) A_METHODS( A_METHOD(void, Material::setTexture) ) A_ENUMS( - A_ENUM(MaterialType, + A_ENUM(Type, A_VALUE(Surface), A_VALUE(PostProcess), A_VALUE(LightFunction)), - A_ENUM(LightModelType, + A_ENUM(LightModel, A_VALUE(Unlit), A_VALUE(Lit), - A_VALUE(Subsurface)), - - A_ENUM(BlendType, - A_VALUE(Opaque), - A_VALUE(Additive), - A_VALUE(Translucent)) + A_VALUE(Subsurface)) ) public: - enum MaterialType { + enum Type { Surface, PostProcess, LightFunction }; - enum LightModelType { + enum LightModel { Unlit, Lit, Subsurface }; - enum BlendType { - Opaque, - Additive, - Translucent - }; - enum SurfaceType { Static, Skinned, diff --git a/engine/src/components/transform.cpp b/engine/src/components/transform.cpp index c21750947..ab30a550d 100644 --- a/engine/src/components/transform.cpp +++ b/engine/src/components/transform.cpp @@ -251,7 +251,7 @@ void Transform::setParent(Object *parent, int32_t position, bool force) { \internal */ int Transform::hash() const { - return m_hash; + return static_cast(m_hash); } /*! \internal @@ -274,7 +274,7 @@ void Transform::cleanDirty() const { } m_hash = 16; for(int i = 0; i < 16; i++) { - m_hash ^= hash_float(m_worldTransform[i]) + 0x9e3779b9 + (m_hash << 6 ) + (m_hash >> 2); + Mathf::hashCombine(m_hash, m_worldTransform[i]); } m_dirty = false; } diff --git a/engine/src/editor/viewport/cameracontroller.cpp b/engine/src/editor/viewport/cameracontroller.cpp index eea523e8f..6013fa58c 100644 --- a/engine/src/editor/viewport/cameracontroller.cpp +++ b/engine/src/editor/viewport/cameracontroller.cpp @@ -20,6 +20,8 @@ #define DT 0.0625f +const float s_Sence = 0.04f; + namespace { const char *gCamera("Camera"); const char *gPosition("position"); @@ -384,7 +386,7 @@ void CameraController::drawHelpers(Object &object) { if(component && component->actor()->isEnabled()) { component->drawGizmos(); float distance = HandleTools::distanceToPoint(Matrix4(), component->transform()->worldPosition(), Handles::s_Mouse); - if(distance <= HandleTools::s_Sense) { + if(distance <= s_Sence) { select(object); } diff --git a/engine/src/editor/viewport/handles.cpp b/engine/src/editor/viewport/handles.cpp index a30f1eb56..1ee27b3c8 100644 --- a/engine/src/editor/viewport/handles.cpp +++ b/engine/src/editor/viewport/handles.cpp @@ -14,6 +14,8 @@ #define CONTROL_SIZE 90.0f +float s_Sense = 0.04f; + Vector4 Handles::s_Normal = Vector4(1.0f, 1.0f, 1.0f, 1.0f); Vector4 Handles::s_Grey = Vector4(0.3f, 0.3f, 0.3f, 0.6f); Vector4 Handles::s_Selected = Vector4(1.0f, 1.0f, 0.0f, 1.0f); @@ -140,22 +142,22 @@ Vector3 Handles::moveTool(const Vector3 &position, const Quaternion &rotation, b Matrix4 r(Vector3(), Quaternion(Vector3(0, 1, 0),-90), Vector3(1)); if(!locked) { - if(HandleTools::distanceToPoint(model, Vector3(), s_Mouse) <= HandleTools::s_Sense) { + if(HandleTools::distanceToPoint(model, Vector3(), s_Mouse) <= s_Sense) { s_Axes = AXIS_X | AXIS_Y | AXIS_Z; - } else if((HandleTools::distanceToMesh(x, s_Move->indices(), s_Move->vertices(), s_Mouse) <= HandleTools::s_Sense) || - (HandleTools::distanceToMesh(z * r, s_Move->indices(), s_Move->vertices(), s_Mouse) <= HandleTools::s_Sense)) { + } else if((HandleTools::distanceToMesh(x, s_Move->indices(), s_Move->vertices(), s_Mouse) <= s_Sense) || + (HandleTools::distanceToMesh(z * r, s_Move->indices(), s_Move->vertices(), s_Mouse) <= s_Sense)) { s_Axes = AXIS_X | AXIS_Z; - } else if((HandleTools::distanceToMesh(y, s_Move->indices(), s_Move->vertices(), s_Mouse) <= HandleTools::s_Sense) || - (HandleTools::distanceToMesh(x * r, s_Move->indices(), s_Move->vertices(), s_Mouse) <= HandleTools::s_Sense)) { + } else if((HandleTools::distanceToMesh(y, s_Move->indices(), s_Move->vertices(), s_Mouse) <= s_Sense) || + (HandleTools::distanceToMesh(x * r, s_Move->indices(), s_Move->vertices(), s_Mouse) <= s_Sense)) { s_Axes = AXIS_Y | AXIS_X; - } else if((HandleTools::distanceToMesh(z, s_Move->indices(), s_Move->vertices(), s_Mouse) <= HandleTools::s_Sense) || - (HandleTools::distanceToMesh(y * r, s_Move->indices(), s_Move->vertices(), s_Mouse) <= HandleTools::s_Sense)) { + } else if((HandleTools::distanceToMesh(z, s_Move->indices(), s_Move->vertices(), s_Mouse) <= s_Sense) || + (HandleTools::distanceToMesh(y * r, s_Move->indices(), s_Move->vertices(), s_Mouse) <= s_Sense)) { s_Axes = AXIS_Z | AXIS_Y; - } else if(HandleTools::distanceToMesh(x, s_Axis->indices(), s_Axis->vertices(), s_Mouse) <= HandleTools::s_Sense) { + } else if(HandleTools::distanceToMesh(x, s_Axis->indices(), s_Axis->vertices(), s_Mouse) <= s_Sense) { s_Axes = AXIS_X; - } else if(HandleTools::distanceToMesh(y, s_Axis->indices(), s_Axis->vertices(), s_Mouse) <= HandleTools::s_Sense) { + } else if(HandleTools::distanceToMesh(y, s_Axis->indices(), s_Axis->vertices(), s_Mouse) <= s_Sense) { s_Axes = AXIS_Y; - } else if(HandleTools::distanceToMesh(z, s_Axis->indices(), s_Axis->vertices(), s_Mouse) <= HandleTools::s_Sense) { + } else if(HandleTools::distanceToMesh(z, s_Axis->indices(), s_Axis->vertices(), s_Mouse) <= s_Sense) { s_Axes = AXIS_Z; } } @@ -282,16 +284,16 @@ float Handles::rotationTool(const Vector3 &position, const Quaternion &rotation, float yDist = HandleTools::distanceToMesh(y, a_indices, a_points, s_Mouse); float zDist = HandleTools::distanceToMesh(z, a_indices, a_points, s_Mouse); - if(xyzDist <= HandleTools::s_Sense) { + if(xyzDist <= s_Sense) { s_Axes = AXIS_X | AXIS_Y | AXIS_Z; } - if(xDist <= HandleTools::s_Sense && (xDist < yDist) && (xDist < zDist)) { + if(xDist <= s_Sense && (xDist < yDist) && (xDist < zDist)) { s_Axes = AXIS_X; } - if(yDist <= HandleTools::s_Sense && (yDist < xDist) && (yDist < zDist)) { + if(yDist <= s_Sense && (yDist < xDist) && (yDist < zDist)) { s_Axes = AXIS_Y; } - if(zDist <= HandleTools::s_Sense && (zDist < xDist) && (zDist < yDist)) { + if(zDist <= s_Sense && (zDist < xDist) && (zDist < yDist)) { s_Axes = AXIS_Z; } } @@ -391,22 +393,22 @@ Vector3 Handles::scaleTool(const Vector3 &position, const Quaternion &rotation, Matrix4 r(Vector3(), Quaternion(Vector3(0, 1, 0),-90), Vector3(1)); if(!locked) { - if(HandleTools::distanceToPoint(model, Vector3(), s_Mouse) <= HandleTools::s_Sense) { + if(HandleTools::distanceToPoint(model, Vector3(), s_Mouse) <= s_Sense) { s_Axes = AXIS_X | AXIS_Y | AXIS_Z; - } else if((HandleTools::distanceToMesh(x, s_Scale->indices(), s_Scale->vertices(), s_Mouse) <= HandleTools::s_Sense) || - (HandleTools::distanceToMesh(z * r, s_Scale->indices(), s_Scale->vertices(), s_Mouse) <= HandleTools::s_Sense)) { + } else if((HandleTools::distanceToMesh(x, s_Scale->indices(), s_Scale->vertices(), s_Mouse) <= s_Sense) || + (HandleTools::distanceToMesh(z * r, s_Scale->indices(), s_Scale->vertices(), s_Mouse) <= s_Sense)) { s_Axes = AXIS_X | AXIS_Z; - } else if((HandleTools::distanceToMesh(y, s_Scale->indices(), s_Scale->vertices(), s_Mouse) <= HandleTools::s_Sense) || - (HandleTools::distanceToMesh(x * r, s_Scale->indices(), s_Scale->vertices(), s_Mouse) <= HandleTools::s_Sense)) { + } else if((HandleTools::distanceToMesh(y, s_Scale->indices(), s_Scale->vertices(), s_Mouse) <= s_Sense) || + (HandleTools::distanceToMesh(x * r, s_Scale->indices(), s_Scale->vertices(), s_Mouse) <= s_Sense)) { s_Axes = AXIS_Y | AXIS_X; - } else if((HandleTools::distanceToMesh(z, s_Scale->indices(), s_Scale->vertices(), s_Mouse) <= HandleTools::s_Sense) || - (HandleTools::distanceToMesh(y * r, s_Scale->indices(), s_Scale->vertices(), s_Mouse) <= HandleTools::s_Sense)) { + } else if((HandleTools::distanceToMesh(z, s_Scale->indices(), s_Scale->vertices(), s_Mouse) <= s_Sense) || + (HandleTools::distanceToMesh(y * r, s_Scale->indices(), s_Scale->vertices(), s_Mouse) <= s_Sense)) { s_Axes = AXIS_Z | AXIS_Y; - } else if(HandleTools::distanceToMesh(x, s_Axis->indices(), s_Axis->vertices(), s_Mouse) <= HandleTools::s_Sense) { + } else if(HandleTools::distanceToMesh(x, s_Axis->indices(), s_Axis->vertices(), s_Mouse) <= s_Sense) { s_Axes = AXIS_X; - } else if(HandleTools::distanceToMesh(y, s_Axis->indices(), s_Axis->vertices(), s_Mouse) <= HandleTools::s_Sense) { + } else if(HandleTools::distanceToMesh(y, s_Axis->indices(), s_Axis->vertices(), s_Mouse) <= s_Sense) { s_Axes = AXIS_Y; - } else if(HandleTools::distanceToMesh(z, s_Axis->indices(), s_Axis->vertices(), s_Mouse) <= HandleTools::s_Sense) { + } else if(HandleTools::distanceToMesh(z, s_Axis->indices(), s_Axis->vertices(), s_Mouse) <= s_Sense) { s_Axes = AXIS_Z; } } @@ -567,7 +569,7 @@ Vector3 Handles::rectTool(const Vector3 &position, const Vector3 &box, int &axis Gizmos::drawBox(model * bl, Vector3(scale * 0.05f), s_zColor); if(!locked) { - float sence = HandleTools::s_Sense * 0.25f; + float sence = s_Sense * 0.25f; Handles::s_Axes = 0; if(HandleTools::distanceToPoint(model, tr, s_Mouse) <= sence) { diff --git a/engine/src/editor/viewport/handletools.cpp b/engine/src/editor/viewport/handletools.cpp index 1a8b7fbec..b7e0119ed 100644 --- a/engine/src/editor/viewport/handletools.cpp +++ b/engine/src/editor/viewport/handletools.cpp @@ -5,8 +5,6 @@ #include -float HandleTools::s_Sense = 0.02f; - float HandleTools::distanceToPoint(const Matrix4 &matrix, const Vector3 &point, const Vector2 &screen) { Vector2 ssp = Camera::current()->project(matrix * point); diff --git a/engine/src/resources/mesh.cpp b/engine/src/resources/mesh.cpp index 6ee309d03..f02658ee0 100644 --- a/engine/src/resources/mesh.cpp +++ b/engine/src/resources/mesh.cpp @@ -248,7 +248,7 @@ int Mesh::indexCount(int sub) const { if(sub < static_cast(m_offsets.size()) - 1) { return m_offsets[sub+1] - m_offsets[sub]; } - return m_indices.size() - m_offsets[sub]; + return m_indices.size() - (m_offsets.empty() ? 0 : m_offsets[sub]); } /*! Recalculates the normals of the Mesh from the triangles and vertices. diff --git a/modules/editor/grapheditor/editor/graph/abstractnodegraph.cpp b/modules/editor/grapheditor/editor/graph/abstractnodegraph.cpp index b41ecc48f..285c9d0c0 100644 --- a/modules/editor/grapheditor/editor/graph/abstractnodegraph.cpp +++ b/modules/editor/grapheditor/editor/graph/abstractnodegraph.cpp @@ -9,28 +9,46 @@ #include namespace { - const char *gNodes("Nodes"); - const char *gLinks("Links"); - const char *gValues("Values"); - - const char *gNode("Node"); - const char *gType("Type"); - const char *gName("Name"); - const char *gLink("Link"); - const char *gValue("Value"); - const char *gIndex("Index"); - - const char *gSender("Sender"); - const char *gReceiver("Receiver"); + // Old Format + const char *gOldNodes("Nodes"); + const char *gOldLinks("Links"); + const char *gOldValues("Values"); + + const char *gOldType("Type"); + const char *gOldIndex("Index"); + + const char *gOldSender("Sender"); + const char *gOldReceiver("Receiver"); const char *gIPort("IPort"); const char *gOPort("OPort"); - const char *gX("X"); - const char *gY("Y"); + const char *gOldX("X"); + const char *gOldY("Y"); + + // New Format + const char *gGraph("graph"); + const char *gNodes("nodes"); + const char *gNode("node"); + const char *gLinks("links"); + const char *gLink("link"); + const char *gValues("values"); + + const char *gType("type"); + const char *gIndex("index"); + const char *gName("name"); + + const char *gSender("sender"); + const char *gReceiver("receiver"); + const char *gIn("in"); + const char *gOut("out"); + + const char *gX("x"); + const char *gY("y"); } AbstractNodeGraph::AbstractNodeGraph() : - m_rootNode(nullptr) { + m_rootNode(nullptr), + m_version(0) { } GraphNode *AbstractNodeGraph::rootNode() const { @@ -229,31 +247,51 @@ void AbstractNodeGraph::load(const QString &path) { loadFile.close(); if(data.at(0) == '{') { // Load old json format - m_data = QJsonDocument::fromJson(data).toVariant().toMap(); - loadGraph(m_data); + loadGraphV0(QJsonDocument::fromJson(data).toVariant().toMap()); save(path); // Need to save in new xml format } else if(data.at(0) == '<') { // Load new xml format - m_data = loadXmlData(data); - loadGraph(m_data); + QDomDocument doc; + doc.setContent(data); + + QDomElement document = doc.documentElement(); + int version = document.attribute("version", "0").toInt(); + + if(version == 0) { + loadGraphV0(loadXmlMap(document)); + } else { + QDomNode p = document.firstChild(); + while(!p.isNull()) { + QDomElement element = p.toElement(); + if(!element.isNull()) { + loadGraphV11(element); + } + + p = p.nextSiblingElement(); + } + + emit graphUpdated(); + } + + if(version != m_version) { + save(path); + } } } void AbstractNodeGraph::save(const QString &path) { - QVariantList nodes; - QVariantList links; + QDomDocument xml; - for(GraphNode *it : qAsConst(m_nodes)) { - if(it != m_rootNode) { - nodes.push_back(saveNode(it)); - } - links.append(saveLinks(it)); - } - m_data[gNodes] = nodes; - m_data[gLinks] = links; + QDomElement document = xml.createElement("document"); + + document.setAttribute("version", m_version); + + saveGraph(document, xml); + + xml.appendChild(document); QFile saveFile(path); if(saveFile.open(QIODevice::WriteOnly)) { - saveFile.write(saveXmlData(m_data)); + saveFile.write(xml.toByteArray(4)); saveFile.close(); } } @@ -270,13 +308,6 @@ Texture *AbstractNodeGraph::preview(GraphNode *node) { return nullptr; } -QVariantMap AbstractNodeGraph::loadXmlData(const QByteArray &data) { - QDomDocument doc; - doc.setContent(data); - - return loadXmlMap(doc.documentElement()); -} - QVariantMap AbstractNodeGraph::loadXmlMap(const QDomElement &parent) { QVariantMap result; @@ -284,30 +315,16 @@ QVariantMap AbstractNodeGraph::loadXmlMap(const QDomElement &parent) { while(!n.isNull()) { QDomElement e = n.toElement(); if(!e.isNull()) { - switch(e.attribute(gType).toInt()) { - case QMetaType::Bool: { - bool value = (e.text() == "true"); - result[e.attribute(gName)] = value; - } break; - case QMetaType::Int: { - int value = e.text().toInt(); - result[e.attribute(gName)] = value; - } break; + QString key = e.attribute("Name"); + + switch(e.attribute(gOldType).toInt()) { + case QMetaType::Bool: result[key] = (e.text() == "true"); break; + case QMetaType::Int: result[key] = e.text().toInt(); break; case QMetaType::Float: - case QMetaType::Double: { - float value = e.text().toFloat(); - result[e.attribute(gName)] = value; - } break; - case QMetaType::QString: { - QString value = e.text(); - result[e.attribute(gName)] = value; - } break; - case QVariant::Map: { - result[e.attribute(gName)] = loadXmlMap(e); - } break; - case QVariant::List: { - result[e.attribute(gName)] = loadXmlList(e); - } break; + case QMetaType::Double: result[key] = e.text().toFloat(); break; + case QMetaType::QString: result[key] = e.text(); break; + case QVariant::Map: result[key] = loadXmlMap(e); break; + case QVariant::List: result[key] = loadXmlList(e); break; default: break; } } @@ -324,32 +341,15 @@ QVariantList AbstractNodeGraph::loadXmlList(const QDomElement &parent) { while(!n.isNull()) { QDomElement e = n.toElement(); if(!e.isNull()) { - switch(e.attribute(gType).toInt()) { - case QMetaType::Bool: { - bool value = (e.text() == "true"); - result.push_back(value); - } break; - case QMetaType::Int: { - result.push_back(e.text().toInt()); - } break; - case QMetaType::UInt: { - result.push_back(e.text().toUInt()); - } break; + switch(e.attribute(gOldType).toInt()) { + case QMetaType::Bool: result.push_back(e.text() == "true"); break; + case QMetaType::Int: result.push_back(e.text().toInt()); break; + case QMetaType::UInt: result.push_back(e.text().toUInt()); break; case QMetaType::Float: - case QMetaType::Double: { - float value = e.text().toFloat(); - result.push_back(value); - } break; - case QMetaType::QString: { - QString value = e.text(); - result.push_back(value); - } break; - case QMetaType::QVariantMap: { - result.push_back(loadXmlMap(e)); - } break; - case QMetaType::QVariantList: { - result.push_back(loadXmlList(e)); - } break; + case QMetaType::Double: result.push_back(e.text().toFloat()); break; + case QMetaType::QString: result.push_back(e.text()); break; + case QMetaType::QVariantMap: result.push_back(loadXmlMap(e)); break; + case QMetaType::QVariantList: result.push_back(loadXmlList(e)); break; default: break; } } @@ -359,69 +359,26 @@ QVariantList AbstractNodeGraph::loadXmlList(const QDomElement &parent) { return result; } -QByteArray AbstractNodeGraph::saveXmlData(const QVariantMap &data) { - QDomDocument xml; - QDomElement graph = xml.createElement("Graph"); - saveXmlMap(data, xml, graph); - xml.appendChild(graph); - - return xml.toByteArray(4); -} - -void AbstractNodeGraph::saveXmlMap(const QVariantMap &data, QDomDocument &xml, QDomElement &parent) { - for(auto &it : data.keys()) { - QDomElement value = xml.createElement(gValue); - value.setAttribute(gName, it); - QVariant variant = data.value(it); - value.setAttribute(gType, variant.type()); - if(variant.type() == QVariant::List) { - saveXmlList(variant.toList(), xml, value); - } else if(variant.type() == QVariant::Map) { - saveXmlMap(variant.toMap(), xml, value); - } else { - QString str = variant.toString(); - if(variant.type() == QVariant::String) { - value.appendChild(xml.createCDATASection(str)); - } else { - value.appendChild(xml.createTextNode(str)); - } - } - parent.appendChild(value); - } -} - -void AbstractNodeGraph::saveXmlList(const QVariantList &data, QDomDocument &xml, QDomElement &parent) { - for(auto &it : data) { - QDomElement value = xml.createElement(gValue); - value.setAttribute(gType, it.type()); - if(it.type() == QVariant::List) { - saveXmlList(it.toList(), xml, value); - } else if(it.type() == QVariant::Map) { - saveXmlMap(it.toMap(), xml, value); - } else { - value.appendChild( xml.createTextNode(it.toString()) ); - } - parent.appendChild(value); - } -} - -void AbstractNodeGraph::loadGraph(const QVariantMap &data) { - QVariantList nodes = data[gNodes].toList(); +void AbstractNodeGraph::loadGraphV0(const QVariantMap &data) { + QVariantList nodes = data[gOldNodes].toList(); for(int i = 0; i < nodes.size(); ++i) { QVariantMap n = nodes[i].toMap(); - int32_t index = n[gIndex].isValid() ? n[gIndex].toInt() : -1; - QString type = n[gType].toString(); + int32_t index = n[gOldIndex].isValid() ? n[gOldIndex].toInt() : -1; + QString type = n[gOldType].toString(); GraphNode *node = nodeCreate(type, index); - node->setPosition(Vector2(n[gX].toInt(), n[gY].toInt())); - loadUserValues(node, n[gValues].toMap()); + if(node) { + node->setPosition(Vector2(n[gOldX].toInt(), n[gOldY].toInt())); + loadUserValues(node, n[gOldValues].toMap()); + } } - QVariantList links = data[gLinks].toList(); + QVariantList links = data[gOldLinks].toList(); for(int i = 0; i < links.size(); ++i) { QVariantMap l = links[i].toMap(); - GraphNode *snd = node(l[gSender].toInt()); - GraphNode *rcv = node(l[gReceiver].toInt()); + GraphNode *snd = node(l[gOldSender].toInt()); + GraphNode *rcv = node(l[gOldReceiver].toInt()); + if(snd && rcv) { int index1 = l[gOPort].toInt(); NodePort *op = (index1 > -1) ? snd->port(index1) : nullptr; @@ -435,7 +392,151 @@ void AbstractNodeGraph::loadGraph(const QVariantMap &data) { emit graphUpdated(); } -QVariantMap AbstractNodeGraph::saveNode(GraphNode *node) { +void AbstractNodeGraph::loadGraphV11(const QDomElement &parent) { + if(parent.tagName() == gGraph) { + QDomElement nodes = parent.firstChildElement(gNodes); + if(!nodes.isNull()) { + QDomElement nodeElement = nodes.firstChildElement(); + while(!nodeElement.isNull()) { + int32_t index = nodeElement.attribute(gIndex, "-1").toInt(); + QString type = nodeElement.attribute(gType); + GraphNode *node = nodeCreate(type, index); + if(node) { + node->setPosition(Vector2(nodeElement.attribute(gX).toInt(), + nodeElement.attribute(gY).toInt())); + + QVariantMap values; + QDomElement valueElement = nodeElement.firstChildElement("value"); + while(!valueElement.isNull()) { + QString type = valueElement.attribute(gType); + QString name = valueElement.attribute(gName); + if(type == "bool") { + values[name] = (valueElement.text() == "true"); + } else if(type == "int") { + values[name] = valueElement.text().toInt(); + } else if(type == "float") { + values[name] = valueElement.text().toFloat(); + } else if(type == "string") { + values[name] = valueElement.text(); + } else if(type == "Vector2" || type == "Vector3" || type == "Vector4") { + QVariantList list; + list.push_back(type); + for(auto &it : valueElement.text().split(", ")) { + list.push_back(it.toFloat()); + } + values[name] = list; + } else if(type == "Template") { + QVariantList list; + list.push_back(type); + for(auto &it : valueElement.text().split(", ")) { + list.push_back(it); + } + values[name] = list; + } + + valueElement = valueElement.nextSiblingElement(); + } + + loadUserValues(node, values); + } + + nodeElement = nodeElement.nextSiblingElement(); + } + } + + QDomElement links = parent.firstChildElement(gLinks); + if(!links.isNull()) { + QDomElement linkElement = links.firstChildElement(); + while(!linkElement.isNull()) { + GraphNode *snd = node(linkElement.attribute(gSender).toInt()); + GraphNode *rcv = node(linkElement.attribute(gReceiver).toInt()); + + if(snd && rcv) { + int index1 = linkElement.attribute(gOut).toInt(); + NodePort *op = (index1 > -1) ? snd->port(index1) : nullptr; + int index2 = linkElement.attribute(gIn).toInt(); + NodePort *ip = (index2 > -1) ? rcv->port(index2) : nullptr; + + linkCreate(snd, op, rcv, ip); + } + + linkElement = linkElement.nextSiblingElement(); + } + } + } +} + +void AbstractNodeGraph::saveGraph(QDomElement parent, QDomDocument xml) const { + QDomElement graph = xml.createElement(gGraph); + + QVariantList nodes; + QVariantList links; + + for(GraphNode *it : qAsConst(m_nodes)) { + if(it != m_rootNode) { + nodes.push_back(saveNode(it)); + } + + links.append(saveLinks(it)); + } + + QDomElement nodesElement = xml.createElement(gNodes); + for(auto &node : nodes) { + QDomElement nodeElement = xml.createElement(gNode); + + QVariantMap fields = node.toMap(); + for(auto &key : fields.keys()) { + if(key.toLower() == gValues) { + QVariantMap values = fields.value(key).toMap(); + + for(auto &value : values.keys()) { + QDomElement valueElement = xml.createElement("value"); + valueElement.setAttribute(gName, value); + + QVariant v = values.value(value); + if(v.type() == QVariant::List) { + QVariantList list = v.toList(); + valueElement.setAttribute(gType, list.front().toString()); + list.pop_front(); + QString pack; + for(auto &it : list) { + pack += it.toString() + ", "; + } + pack.resize(pack.size() - 2); + valueElement.appendChild(xml.createTextNode(pack)); + } else { + valueElement.setAttribute(gType, v.typeName()); + valueElement.appendChild(xml.createTextNode(v.toString())); + } + + nodeElement.appendChild(valueElement); + } + } else { + nodeElement.setAttribute(key, fields.value(key).toString()); + } + } + nodesElement.appendChild(nodeElement); + } + + QDomElement linksElement = xml.createElement(gLinks); + for(auto &link : links) { + QDomElement linkElement = xml.createElement(gLink); + + QVariantMap fields = link.toMap(); + for(auto &key : fields.keys()) { + linkElement.setAttribute(key, fields.value(key).toString()); + } + + linksElement.appendChild(linkElement); + } + + graph.appendChild(nodesElement); + graph.appendChild(linksElement); + + parent.appendChild(graph); +} + +QVariantMap AbstractNodeGraph::saveNode(GraphNode *node) const { QVariantMap result; result[gType] = node->typeName().c_str(); result[gX] = (int)node->position().x; @@ -449,15 +550,15 @@ QVariantMap AbstractNodeGraph::saveNode(GraphNode *node) { return result; } -QVariantList AbstractNodeGraph::saveLinks(GraphNode *node) { +QVariantList AbstractNodeGraph::saveLinks(GraphNode *node) const { QVariantList result; for(auto l : findLinks(node)) { QVariantMap link; link[gSender] = AbstractNodeGraph::node(l->sender); - link[gOPort] = (l->oport != nullptr) ? l->sender->portPosition(l->oport) : -1; + link[gOut] = (l->oport != nullptr) ? l->sender->portPosition(l->oport) : -1; link[gReceiver] = AbstractNodeGraph::node(l->receiver); - link[gIPort] = (l->iport != nullptr) ? l->receiver->portPosition(l->iport) : -1; + link[gIn] = (l->iport != nullptr) ? l->receiver->portPosition(l->iport) : -1; result.push_back(link); } @@ -581,7 +682,7 @@ DeleteNodes::DeleteNodes(const vector &selection, AbstractNodeGraph *mo } void DeleteNodes::undo() { - m_graph->loadGraph(m_document); + m_graph->loadGraphV0(m_document); } void DeleteNodes::redo() { QVariantList links; diff --git a/modules/editor/grapheditor/editor/graph/abstractnodegraph.h b/modules/editor/grapheditor/editor/graph/abstractnodegraph.h index 78916d36f..3b38db021 100644 --- a/modules/editor/grapheditor/editor/graph/abstractnodegraph.h +++ b/modules/editor/grapheditor/editor/graph/abstractnodegraph.h @@ -58,8 +58,8 @@ class NODEGRAPH_EXPORT AbstractNodeGraph : public QObject { int node(GraphNode *node) const; int link(Link *link) const; - virtual void load(const QString &path); - virtual void save(const QString &path); + void load(const QString &path); + void save(const QString &path); virtual QStringList nodeList() const; @@ -89,22 +89,20 @@ class NODEGRAPH_EXPORT AbstractNodeGraph : public QObject { protected: virtual void loadUserValues(GraphNode *node, const QVariantMap &values) = 0; - virtual void saveUserValues(GraphNode *node, QVariantMap &values) = 0; + virtual void saveUserValues(GraphNode *node, QVariantMap &values) const = 0; virtual GraphNode *createRoot() = 0; - QVariantMap loadXmlData(const QByteArray &data); QVariantMap loadXmlMap(const QDomElement &parent); QVariantList loadXmlList(const QDomElement &parent); - QByteArray saveXmlData(const QVariantMap &data); - void saveXmlMap(const QVariantMap &data, QDomDocument &xml, QDomElement &parent); - void saveXmlList(const QVariantList &data, QDomDocument &xml, QDomElement &parent); + virtual void loadGraphV0(const QVariantMap &data); + virtual void loadGraphV11(const QDomElement &parent); - virtual void loadGraph(const QVariantMap &data); + virtual void saveGraph(QDomElement parent, QDomDocument xml) const; - QVariantMap saveNode(GraphNode *node); - QVariantList saveLinks(GraphNode *node); + QVariantMap saveNode(GraphNode *node) const; + QVariantList saveLinks(GraphNode *node) const; friend class PasteNodes; friend class DeleteNodes; @@ -115,7 +113,8 @@ class NODEGRAPH_EXPORT AbstractNodeGraph : public QObject { GraphNode *m_rootNode; - QVariantMap m_data; + uint32_t m_version; + }; class UndoGraph : public UndoCommand { diff --git a/modules/editor/motiontools/converter/animationcontrollergraph.cpp b/modules/editor/motiontools/converter/animationcontrollergraph.cpp index efb52a9f2..1faeb5715 100644 --- a/modules/editor/motiontools/converter/animationcontrollergraph.cpp +++ b/modules/editor/motiontools/converter/animationcontrollergraph.cpp @@ -5,48 +5,69 @@ #include "basestate.h" #include -#define ENTRY "Entry" -#define NAME "Name" -#define CLIP "Clip" -#define LOOP "Loop" +namespace { + const char *gEntry("Entry"); + const char *gName("Name"); + const char *gClip("Clip"); + const char *gLoop("Loop"); -#define MACHINE "Machine" + const char *gMachine("Machine"); + + const char *gBaseState("BaseState"); + + const char *gUser("user"); +}; AnimationControllerGraph::AnimationControllerGraph() { m_entry = nullptr; - qRegisterMetaType("BaseState"); + qRegisterMetaType(gBaseState); - m_functions << "BaseState"; + m_functions << gBaseState; } -void AnimationControllerGraph::load(const QString &path) { - AbstractNodeGraph::load(path); +void AnimationControllerGraph::loadGraphV0(const QVariantMap &data) { + AbstractNodeGraph::loadGraphV0(data); + + int32_t entry = data[gEntry].toInt(); + if(entry > -1) { + m_entry = m_nodes.at(entry); + } if(m_entry) { linkCreate(m_rootNode, nullptr, m_entry, nullptr); } } -void AnimationControllerGraph::loadGraph(const QVariantMap &data) { - AbstractNodeGraph::loadGraph(data); +void AnimationControllerGraph::loadGraphV11(const QDomElement &parent) { + AbstractNodeGraph::loadGraphV11(parent); - int32_t entry = m_data[ENTRY].toInt(); - if(entry > -1) { - m_entry = m_nodes.at(entry); + if(parent.tagName() == gUser) { + int32_t entry = parent.attribute(gEntry).toInt(); + if(entry > -1) { + m_entry = m_nodes.at(entry); + } + + if(m_entry) { + linkCreate(m_rootNode, nullptr, m_entry, nullptr); + } } } -void AnimationControllerGraph::save(const QString &path) { - m_data[ENTRY] = m_nodes.indexOf(m_entry); +void AnimationControllerGraph::saveGraph(QDomElement parent, QDomDocument xml) const { + AbstractNodeGraph::saveGraph(parent, xml); + + QDomElement user = xml.createElement(gUser); + + user.setAttribute(gEntry, QString::number(m_nodes.indexOf(m_entry))); - AbstractNodeGraph::save(path); + parent.appendChild(user); } GraphNode *AnimationControllerGraph::createRoot() { EntryState *result = new EntryState; - result->setObjectName(ENTRY); + result->setObjectName(gEntry); result->setGraph(this); return result; @@ -89,20 +110,20 @@ AnimationControllerGraph::Link *AnimationControllerGraph::linkCreate(GraphNode * void AnimationControllerGraph::loadUserValues(GraphNode *node, const QVariantMap &values) { BaseState *ptr = reinterpret_cast(node); - node->setObjectName(values[NAME].toString()); + node->setObjectName(values[gName].toString()); Template tpl; - tpl.path = values[CLIP].toString(); + tpl.path = values[gClip].toString(); tpl.type = ptr->clip().type; ptr->setClip(tpl); - ptr->setLoop(values[LOOP].toBool()); + ptr->setLoop(values[gLoop].toBool()); } -void AnimationControllerGraph::saveUserValues(GraphNode *node, QVariantMap &values) { +void AnimationControllerGraph::saveUserValues(GraphNode *node, QVariantMap &values) const { BaseState *ptr = reinterpret_cast(node); - values[NAME] = node->objectName(); - values[CLIP] = ptr->clip().path; - values[LOOP] = ptr->loop(); + values[gName] = node->objectName(); + values[gClip] = ptr->clip().path; + values[gLoop] = ptr->loop(); } Variant AnimationControllerGraph::object() const { @@ -185,6 +206,6 @@ Variant AnimationControllerGraph::data() const { } machine.push_back(qPrintable(entry)); - result[MACHINE] = machine; + result[gMachine] = machine; return result; } diff --git a/modules/editor/motiontools/converter/animationcontrollergraph.h b/modules/editor/motiontools/converter/animationcontrollergraph.h index 5eaacf1d9..906269f96 100644 --- a/modules/editor/motiontools/converter/animationcontrollergraph.h +++ b/modules/editor/motiontools/converter/animationcontrollergraph.h @@ -9,10 +9,9 @@ class AnimationControllerGraph : public AbstractNodeGraph { public: AnimationControllerGraph(); - void load(const QString &path) Q_DECL_OVERRIDE; - void save(const QString &path) Q_DECL_OVERRIDE; - - void loadGraph(const QVariantMap &data) Q_DECL_OVERRIDE; + void loadGraphV0(const QVariantMap &data) override; + void loadGraphV11(const QDomElement &parent) override; + void saveGraph(QDomElement parent, QDomDocument xml) const override; Variant object() const; @@ -20,11 +19,11 @@ class AnimationControllerGraph : public AbstractNodeGraph { private: GraphNode *createRoot() Q_DECL_OVERRIDE; - GraphNode *nodeCreate(const QString &path, int &index) Q_DECL_OVERRIDE; - Link *linkCreate(GraphNode *sender, NodePort *oport, GraphNode *receiver, NodePort *iport) Q_DECL_OVERRIDE; + GraphNode *nodeCreate(const QString &path, int &index) override; + Link *linkCreate(GraphNode *sender, NodePort *oport, GraphNode *receiver, NodePort *iport) override; - void loadUserValues(GraphNode *node, const QVariantMap &values) Q_DECL_OVERRIDE; - void saveUserValues(GraphNode *node, QVariantMap &values) Q_DECL_OVERRIDE; + void loadUserValues(GraphNode *node, const QVariantMap &values) override; + void saveUserValues(GraphNode *node, QVariantMap &values) const override; protected: Variant data() const; diff --git a/modules/editor/pipelinetools/converter/pipelinetaskgraph.cpp b/modules/editor/pipelinetools/converter/pipelinetaskgraph.cpp index eb7a10b20..6585bdd10 100644 --- a/modules/editor/pipelinetools/converter/pipelinetaskgraph.cpp +++ b/modules/editor/pipelinetools/converter/pipelinetaskgraph.cpp @@ -80,7 +80,7 @@ void PipelineTaskGraph::loadUserValues(GraphNode *node, const QVariantMap &value } -void PipelineTaskGraph::saveUserValues(GraphNode *node, QVariantMap &values) { +void PipelineTaskGraph::saveUserValues(GraphNode *node, QVariantMap &values) const { } diff --git a/modules/editor/pipelinetools/converter/pipelinetaskgraph.h b/modules/editor/pipelinetools/converter/pipelinetaskgraph.h index 034bc6338..04146727c 100644 --- a/modules/editor/pipelinetools/converter/pipelinetaskgraph.h +++ b/modules/editor/pipelinetools/converter/pipelinetaskgraph.h @@ -92,8 +92,8 @@ private slots: void onNodeUpdated(); private: - void loadUserValues(GraphNode *node, const QVariantMap &values) Q_DECL_OVERRIDE; - void saveUserValues(GraphNode *node, QVariantMap &values) Q_DECL_OVERRIDE; + void loadUserValues(GraphNode *node, const QVariantMap &values) override; + void saveUserValues(GraphNode *node, QVariantMap &values) const override; GraphNode *nodeCreate(const QString &path, int &index) Q_DECL_OVERRIDE; GraphNode *createRoot() Q_DECL_OVERRIDE; diff --git a/modules/editor/shadertools/converter/rootnode.h b/modules/editor/shadertools/converter/rootnode.h index 080ad7ced..b0a75f2db 100644 --- a/modules/editor/shadertools/converter/rootnode.h +++ b/modules/editor/shadertools/converter/rootnode.h @@ -9,31 +9,95 @@ class ShaderRootNode : public GraphNode { Q_OBJECT - Q_PROPERTY(Type Material_Type READ materialType WRITE setMaterialType NOTIFY graphUpdated DESIGNABLE true USER true) - Q_PROPERTY(Blend Blending_Mode READ blend WRITE setBlend NOTIFY graphUpdated DESIGNABLE true USER true) - Q_PROPERTY(LightModel Lighting_Model READ lightModel WRITE setLightModel NOTIFY graphUpdated DESIGNABLE true USER true) - Q_PROPERTY(bool Two_Sided READ isDoubleSided WRITE setDoubleSided NOTIFY graphUpdated DESIGNABLE true USER true) - Q_PROPERTY(bool Depth_Test READ isDepthTest WRITE setDepthTest NOTIFY graphUpdated DESIGNABLE true USER true) - Q_PROPERTY(bool Depth_Write READ isDepthWrite WRITE setDepthWrite NOTIFY graphUpdated DESIGNABLE true USER true) - Q_PROPERTY(bool Wireframe READ isWireframe WRITE setWireframe NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(Type materialType READ materialType WRITE setMaterialType NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(LightModel lightingModel READ lightModel WRITE setLightModel NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(bool wireFrame READ isWireframe WRITE setWireframe NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(bool twoSided READ isDoubleSided WRITE setDoubleSided NOTIFY graphUpdated DESIGNABLE true USER true) + + Q_PROPERTY(BlendOp blendColorOperation READ blendColorOperation WRITE setBlendColorOperation NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(BlendOp blendAlphaOperation READ blendAlphaOperation WRITE setBlendAlphaOperation NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(BlendFactor blendSourceColor READ blendSourceColor WRITE setBlendSourceColor NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(BlendFactor blendSourceAlpha READ blendSourceAlpha WRITE setBlendSourceAlpha NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(BlendFactor blendDestinationColor READ blendDestinationColor WRITE setBlendDestinationColor NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(BlendFactor blendDestinationAlpha READ blendDestinationAlpha WRITE setBlendDestinationAlpha NOTIFY graphUpdated DESIGNABLE true USER true) + + Q_PROPERTY(bool depthTest READ depthTest WRITE setDepthTest NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(bool depthWrite READ depthWrite WRITE setDepthWrite NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(TestFunction depthCompare READ depthCompare WRITE setDepthCompare NOTIFY graphUpdated DESIGNABLE true USER true) + + Q_PROPERTY(bool stencilTest READ stencilTest WRITE setDepthTest NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(int stencilReadMask READ stencilReadMask WRITE setStencilReadMask NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(int stencilWriteMask READ stencilWriteMask WRITE setStencilWriteMask NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(int stencilReference READ stencilReference WRITE setStencilReference NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(TestFunction stencilCompareBack READ stencilTestCompareBack WRITE setStencilTestCompareBack NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(TestFunction stencilCompareFront READ stencilTestCompareFront WRITE setStencilTestCompareFront NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(ActionType stencilFailBack READ stencilFailOperationBack WRITE setStencilFailOperationBack NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(ActionType stencilFailFront READ stencilFailOperationFront WRITE setStencilFailOperationFront NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(ActionType stencilPassBack READ stencilPassOperationBack WRITE setStencilPassOperationBack NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(ActionType stencilPassFront READ stencilPassOperationFront WRITE setStencilPassOperationFront NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(ActionType stencilZFailBack READ stencilZFailOperationBack WRITE setStencilZFailOperationBack NOTIFY graphUpdated DESIGNABLE true USER true) + Q_PROPERTY(ActionType stencilZFailFront READ stencilZFailOperationFront WRITE setStencilZFailOperationFront NOTIFY graphUpdated DESIGNABLE true USER true) public: + + enum Type { + Surface, + PostProcess, + LightFunction + }; + enum LightModel { Unlit, Lit, Subsurface }; - enum Blend { - Opaque, - Additive, - Translucent + enum BlendOp { + Add, + Subtract, + ReverseSubtract, + Min, + Max }; - enum Type { - Surface, - PostProcess, - LightFunction + enum BlendFactor { + Zero, + One, + SourceColor, + OneMinusSourceColor, + DestinationColor, + OneMinusDestinationColor, + SourceAlpha, + OneMinusSourceAlpha, + DestinationAlpha, + OneMinusDestinationAlpha, + SourceAlphaSaturate, + ConstantColor, + OneMinusConstantColor, + ConstantAlpha, + OneMinusConstantAlpha + }; + + enum ActionType { + Keep, + Clear, + Replace, + Increment, + IncrementWrap, + Decrement, + DecrementWrap, + Invert + }; + + enum TestFunction { + Never, + Less, + LessOrEqual, + Greater, + GreaterOrEqual, + Equal, + NotEqual, + Always }; enum Flags { @@ -43,48 +107,115 @@ class ShaderRootNode : public GraphNode { Q_ENUM(Type) Q_ENUM(LightModel) - Q_ENUM(Blend) + Q_ENUM(BlendOp) + Q_ENUM(BlendFactor) + Q_ENUM(ActionType) + Q_ENUM(TestFunction) ShaderRootNode() : - m_blendMode(Opaque), - m_lightModel(Lit), - m_materialType(Surface), - m_doubleSided(false), - m_depthTest(true), - m_depthWrite(true), - m_viewSpace(true), - m_wireframe(false) { + m_lightModel(Lit), + m_materialType(Surface), + m_doubleSided(false), + m_wireframe(false) { } bool isDoubleSided() const { return m_doubleSided; } void setDoubleSided(bool value) { m_doubleSided = value; emit graphUpdated(); } - bool isDepthTest() const { return m_depthTest; } - void setDepthTest(bool value) { m_depthTest = value; emit graphUpdated(); } - - bool isDepthWrite() const { return m_depthWrite; } - void setDepthWrite(bool value) { m_depthWrite = value; emit graphUpdated(); } - bool isWireframe() const { return m_wireframe; } void setWireframe(bool value) { m_wireframe = value; emit graphUpdated(); } Type materialType() const { return m_materialType; } void setMaterialType(Type type) { m_materialType = type; emit graphUpdated(); } - Blend blend() const { return m_blendMode; } - void setBlend(Blend mode) { m_blendMode = mode; emit graphUpdated(); } - LightModel lightModel() const { return m_lightModel; } void setLightModel(LightModel model) { m_lightModel = model; emit graphUpdated(); } + BlendOp blendAlphaOperation() const { return static_cast(m_blendState.alphaOperation); } + void setBlendAlphaOperation(BlendOp operation) { m_blendState.alphaOperation = operation; emit graphUpdated(); } + + BlendOp blendColorOperation() const { return static_cast(m_blendState.colorOperation); } + void setBlendColorOperation(BlendOp operation) { m_blendState.colorOperation = operation; emit graphUpdated(); } + + BlendFactor blendSourceAlpha() const { return static_cast(m_blendState.sourceAlphaBlendMode); } + void setBlendSourceAlpha(BlendFactor factor) { m_blendState.sourceAlphaBlendMode = factor; emit graphUpdated(); } + + BlendFactor blendSourceColor() const { return static_cast(m_blendState.sourceColorBlendMode); } + void setBlendSourceColor(BlendFactor factor) { m_blendState.sourceColorBlendMode = factor; emit graphUpdated(); } + + BlendFactor blendDestinationAlpha() const { return static_cast(m_blendState.destinationAlphaBlendMode); } + void setBlendDestinationAlpha(BlendFactor factor) { m_blendState.destinationAlphaBlendMode = factor; emit graphUpdated(); } + + BlendFactor blendDestinationColor() const { return static_cast(m_blendState.destinationColorBlendMode); } + void setBlendDestinationColor(BlendFactor factor) { m_blendState.destinationColorBlendMode = factor; emit graphUpdated(); } + + Material::BlendState blendState() const { return m_blendState; }; + void setBlendState(const Material::BlendState &state) { m_blendState = state; } + + bool depthTest() const { return m_depthState.enabled; } + void setDepthTest(bool value) { m_depthState.enabled = value; emit graphUpdated(); } + + bool depthWrite() const { return m_depthState.writeEnabled; } + void setDepthWrite(bool value) { m_depthState.writeEnabled = value; emit graphUpdated(); } + + TestFunction depthCompare() const { return static_cast(m_depthState.compareFunction); } + void setDepthCompare(TestFunction value) { m_depthState.compareFunction = value; emit graphUpdated(); } + + Material::DepthState depthState() const { return m_depthState; } + void setDepthState(const Material::DepthState &state) { m_depthState = state; } + + bool stencilTest() const { return m_stencilState.enabled; } + void setStencilTest(bool value) { m_stencilState.enabled = value; emit graphUpdated(); } + + int32_t stencilReadMask() const { return m_stencilState.readMask; } + void setStencilReadMask(int32_t value) { m_stencilState.readMask = value; emit graphUpdated(); } + + int32_t stencilWriteMask() const { return m_stencilState.writeMask; } + void setStencilWriteMask(int32_t value) { m_stencilState.writeMask = value; emit graphUpdated(); } + + int32_t stencilReference() const { return m_stencilState.reference; } + void setStencilReference(int32_t value) { m_stencilState.reference = value; emit graphUpdated(); } + + TestFunction stencilTestCompareBack() const { return static_cast(m_stencilState.compareFunctionBack); } + void setStencilTestCompareBack(TestFunction value) { m_stencilState.compareFunctionBack = value; emit graphUpdated(); } + + TestFunction stencilTestCompareFront() const { return static_cast(m_stencilState.compareFunctionFront); } + void setStencilTestCompareFront(TestFunction value) { m_stencilState.compareFunctionFront = value; emit graphUpdated(); } + + ActionType stencilFailOperationBack() const { return static_cast(m_stencilState.failOperationBack); } + void setStencilFailOperationBack(ActionType value) { m_stencilState.failOperationBack = value; emit graphUpdated(); } + + ActionType stencilFailOperationFront() const { return static_cast(m_stencilState.failOperationFront); } + void setStencilFailOperationFront(ActionType value) { m_stencilState.failOperationFront = value; emit graphUpdated(); } + + ActionType stencilPassOperationBack() const { return static_cast(m_stencilState.passOperationBack); } + void setStencilPassOperationBack(ActionType value) { m_stencilState.passOperationBack = value; emit graphUpdated(); } + + ActionType stencilPassOperationFront() const { return static_cast(m_stencilState.passOperationFront); } + void setStencilPassOperationFront(ActionType value) { m_stencilState.passOperationFront = value; emit graphUpdated(); } + + ActionType stencilZFailOperationBack() const { return static_cast(m_stencilState.zFailOperationBack); } + void setStencilZFailOperationBack(ActionType value) { m_stencilState.zFailOperationBack = value; emit graphUpdated(); } + + ActionType stencilZFailOperationFront() const { return static_cast(m_stencilState.zFailOperationFront); } + void setStencilZFailOperationFront(ActionType value) { m_stencilState.zFailOperationFront = value; emit graphUpdated(); } + + + Material::StencilState stencilState() const { return m_stencilState; } + void setStencilState(const Material::StencilState &state) { m_stencilState = state; } + Vector4 color() const override { return Vector4(0.141f, 0.384f, 0.514f, 1.0f); } signals: void graphUpdated(); private: - Blend m_blendMode; + Material::BlendState m_blendState; + + Material::DepthState m_depthState; + + Material::StencilState m_stencilState; LightModel m_lightModel; @@ -92,18 +223,11 @@ class ShaderRootNode : public GraphNode { bool m_doubleSided; - bool m_depthTest; - - bool m_depthWrite; - - bool m_viewSpace; - bool m_wireframe; }; -Q_DECLARE_METATYPE(ShaderRootNode::LightModel) -Q_DECLARE_METATYPE(ShaderRootNode::Blend) -Q_DECLARE_METATYPE(ShaderRootNode::Type) +Q_DECLARE_METATYPE(Material::LightModel) +Q_DECLARE_METATYPE(Material::Type) #endif // ROOTNODE_H diff --git a/modules/editor/shadertools/converter/shaderbuilder.cpp b/modules/editor/shadertools/converter/shaderbuilder.cpp index f2790713d..479d7005a 100644 --- a/modules/editor/shadertools/converter/shaderbuilder.cpp +++ b/modules/editor/shadertools/converter/shaderbuilder.cpp @@ -22,7 +22,7 @@ #include -#define FORMAT_VERSION 11 +#define FORMAT_VERSION 12 namespace { const char *gValue("value"); @@ -41,8 +41,16 @@ namespace { const char *gWireFrame("wireFrame"); const char *gOperation("op"); + const char *gColorOperation("colorOp"); + const char *gAlphaOperation("alphaOp"); + const char *gDestination("dst"); + const char *gColorDestination("colorDst"); + const char *gAlphaDestination("alphaDst"); + const char *gSource("src"); + const char *gColorSource("colorSrc"); + const char *gAlphaSource("alphaSrc"); const char *gTest("test"); const char *gWrite("write"); @@ -313,7 +321,7 @@ bool ShaderBuilder::parseShaderFormat(const QString &path, VariantMap &user, boo if(version == 0) { parsePassV0(element, user); - } else if(version <= 11) { + } else if(version >= 11) { parsePassV11(element, user); } } @@ -329,7 +337,7 @@ bool ShaderBuilder::parseShaderFormat(const QString &path, VariantMap &user, boo const PragmaMap pragmas; if(compute) { - string str = shaders[gCompute].c_str(); + string str = shaders[gCompute]; if(!str.empty()) { user[FRAGMENT] = loadShader(str, define, pragmas); } @@ -343,19 +351,24 @@ bool ShaderBuilder::parseShaderFormat(const QString &path, VariantMap &user, boo } string str; - str = shaders[gFragment].c_str(); + str = shaders[gFragment]; if(!str.empty()) { user[FRAGMENT] = loadShader(str, define, pragmas); } else { user[FRAGMENT] = loadIncludes("Default.frag", define, pragmas); } - str = shaders[gVertex].c_str(); + str = shaders[gVertex]; if(!str.empty()) { user[STATIC] = loadShader(str, define, pragmas); } else { user[STATIC] = loadIncludes("Default.vert", define, pragmas); } + + str = shaders[gGeometry]; + if(!str.empty()) { + user[STATIC] = loadShader(GEOMETRY, define, pragmas); + } } } } @@ -507,48 +520,46 @@ bool ShaderBuilder::saveShaderFormat(const QString &path, const mapsecond.toList(); auto field = fields.begin(); - blend.setAttribute(gOperation, toBlendOp(field->toInt()).c_str()); + Material::BlendState state; + state.alphaOperation = field->toInt(); ++field; + state.colorOperation = field->toInt(); ++field; - blend.setAttribute(gDestination, toBlendFactor(field->toInt()).c_str()); + state.destinationAlphaBlendMode = field->toInt(); ++field; + state.destinationColorBlendMode = field->toInt(); ++field; - blend.setAttribute(gSource, toBlendFactor(field->toInt()).c_str()); + state.sourceAlphaBlendMode = field->toInt(); ++field; + state.sourceColorBlendMode = field->toInt(); ++field; - if(field->toBool()) { - pass.appendChild(blend); - } + state.enabled = field->toBool(); + + saveBlendState(state, xml, pass); } it = user.find(DEPTHSTATE); if(it != user.end()) { - QDomElement depth(xml.createElement("depth")); + Material::DepthState state; VariantList fields = it->second.toList(); auto field = fields.begin(); - - depth.setAttribute(gCompare, toTestFunction(field->toInt()).c_str()); + state.compareFunction = field->toInt(); ++field; - depth.setAttribute(gWrite, field->toBool() ? "true" : "false"); + state.writeEnabled = field->toBool(); ++field; - bool enabled = field->toBool(); - depth.setAttribute(gTest, enabled ? "true" : "false"); + state.enabled = field->toBool(); - if(enabled) { - pass.appendChild(depth); + if(state.enabled) { + saveDepthState(state, xml, pass); } } it = user.find(STENCILSTATE); if(it != user.end()) { - QDomElement stencil(xml.createElement("stencil")); - Material::StencilState state; VariantList fields = it->second.toList(); @@ -578,40 +589,7 @@ bool ShaderBuilder::saveShaderFormat(const QString &path, const maptoBool(); if(state.enabled) { - if(state.compareFunctionBack == state.compareFunctionFront) { - stencil.setAttribute(gCompare, toTestFunction(state.compareFunctionBack).c_str()); - } else { - stencil.setAttribute(gCompBack, toTestFunction(state.compareFunctionBack).c_str()); - stencil.setAttribute(gCompFront, toTestFunction(state.compareFunctionFront).c_str()); - } - - if(state.failOperationBack == state.failOperationFront) { - stencil.setAttribute(gFail, toTestFunction(state.failOperationBack).c_str()); - } else { - stencil.setAttribute(gFailBack, toActionType(state.failOperationBack).c_str()); - stencil.setAttribute(gFailFront, toActionType(state.failOperationFront).c_str()); - } - - if(state.passOperationBack == state.passOperationFront) { - stencil.setAttribute(gPass, toTestFunction(state.passOperationBack).c_str()); - } else { - stencil.setAttribute(gPassBack, toActionType(state.passOperationBack).c_str()); - stencil.setAttribute(gPassFront, toActionType(state.passOperationFront).c_str()); - } - - if(state.zFailOperationBack == state.zFailOperationFront) { - stencil.setAttribute(gZFail, toTestFunction(state.zFailOperationBack).c_str()); - } else { - stencil.setAttribute(gZFailBack, toActionType(state.zFailOperationBack).c_str()); - stencil.setAttribute(gZFailFront, toActionType(state.zFailOperationFront).c_str()); - } - - stencil.setAttribute(gReadMask, state.readMask); - stencil.setAttribute(gWriteMask, state.writeMask); - stencil.setAttribute(gReference, state.reference); - stencil.setAttribute(gTest, state.enabled ? "true" : "false"); - - pass.appendChild(stencil); + saveStencilState(state, xml, pass); } } @@ -738,12 +716,12 @@ VariantList ShaderBuilder::parsePassProperties(const QDomElement &element, int & void ShaderBuilder::parsePassV0(const QDomElement &element, VariantMap &user) { static const QMap blend = { - {"Opaque", Material::Opaque}, - {"Additive", Material::Additive}, - {"Translucent", Material::Translucent}, + {"Opaque", OldBlendType::Opaque}, + {"Additive", OldBlendType::Additive}, + {"Translucent", OldBlendType::Translucent}, }; - Material::BlendState blendState = fromBlendMode(blend.value(element.attribute("blendMode"), Material::Opaque)); + Material::BlendState blendState = fromBlendMode(blend.value(element.attribute("blendMode"), OldBlendType::Opaque)); user[BLENDSTATE] = toVariant(blendState); Material::DepthState depthState; @@ -760,54 +738,11 @@ void ShaderBuilder::parsePassV11(const QDomElement &element, VariantMap &user) { QDomElement element = p.toElement(); if(!element.isNull()) { if(element.tagName() == "blend") { - Material::BlendState blendState; - - blendState.enabled = true; - blendState.alphaOperation = toBlendOp(element.attribute(gOperation, "Add").toStdString()); - blendState.colorOperation = blendState.alphaOperation; - blendState.destinationAlphaBlendMode = toBlendFactor(element.attribute(gDestination, "One").toStdString()); - blendState.destinationColorBlendMode = blendState.destinationAlphaBlendMode; - blendState.sourceAlphaBlendMode = toBlendFactor(element.attribute(gSource, "Zero").toStdString()); - blendState.sourceColorBlendMode = blendState.sourceAlphaBlendMode; - - user[BLENDSTATE] = toVariant(blendState); + user[BLENDSTATE] = toVariant(loadBlendState(element)); } else if(element.tagName() == "depth") { - Material::DepthState depthState; - - depthState.enabled = (element.attribute(gTest, "true") == "true"); - depthState.writeEnabled = (element.attribute(gWrite, "true") == "true"); - depthState.compareFunction = toTestFunction(element.attribute(gCompare, "Less").toStdString()); - - user[DEPTHSTATE] = toVariant(depthState); + user[DEPTHSTATE] = toVariant(loadDepthState(element)); } else if(element.tagName() == "stencil") { - Material::StencilState stencilState; - - stencilState.compareFunctionBack = toTestFunction(element.attribute(gCompare, "Always").toStdString()); - stencilState.compareFunctionFront = stencilState.compareFunctionBack; - - stencilState.failOperationBack = toTestFunction(element.attribute(gFail, "Keep").toStdString()); - stencilState.failOperationFront = stencilState.compareFunctionBack; - - stencilState.passOperationBack = toTestFunction(element.attribute(gPass, "Keep").toStdString()); - stencilState.passOperationFront = stencilState.passOperationBack; - - stencilState.zFailOperationBack = toTestFunction(element.attribute(gZFail, "Keep").toStdString()); - stencilState.zFailOperationFront = stencilState.zFailOperationBack; - - stencilState.compareFunctionBack = toTestFunction(element.attribute(gCompBack, "Always").toStdString()); - stencilState.compareFunctionFront = toTestFunction(element.attribute(gCompFront, "Always").toStdString()); - stencilState.failOperationBack = toActionType(element.attribute(gFailBack, "Keep").toStdString()); - stencilState.failOperationFront = toActionType(element.attribute(gFailFront, "Keep").toStdString()); - stencilState.passOperationBack = toActionType(element.attribute(gPassBack, "Keep").toStdString()); - stencilState.passOperationFront = toActionType(element.attribute(gPassFront, "Keep").toStdString()); - stencilState.zFailOperationBack = toActionType(element.attribute(gZFailBack, "Keep").toStdString()); - stencilState.zFailOperationFront = toActionType(element.attribute(gZFailFront, "Keep").toStdString()); - stencilState.readMask = element.attribute(gReadMask, "1").toInt(); - stencilState.writeMask = element.attribute(gWriteMask, "1").toInt(); - stencilState.reference = element.attribute(gReference, "0").toInt(); - stencilState.enabled = (element.attribute(gTest, "true") == "true"); - - user[STENCILSTATE] = toVariant(stencilState); + user[STENCILSTATE] = toVariant(loadStencilState(element)); } } @@ -815,6 +750,10 @@ void ShaderBuilder::parsePassV11(const QDomElement &element, VariantMap &user) { } } +uint32_t ShaderBuilder::version() { + return FORMAT_VERSION; +} + string ShaderBuilder::loadIncludes(const string &path, const string &define, const PragmaMap &pragmas) { QStringList paths; paths << ProjectSettings::instance()->contentPath() + "/"; @@ -1075,7 +1014,7 @@ Material::BlendState ShaderBuilder::fromBlendMode(uint32_t mode) { Material::BlendState blendState; switch(mode) { - case ShaderRootNode::Opaque: { + case OldBlendType::Opaque: { blendState.enabled = false; blendState.sourceColorBlendMode = Material::BlendFactor::One; blendState.sourceAlphaBlendMode = Material::BlendFactor::One; @@ -1083,7 +1022,7 @@ Material::BlendState ShaderBuilder::fromBlendMode(uint32_t mode) { blendState.destinationColorBlendMode = Material::BlendFactor::Zero; blendState.destinationAlphaBlendMode = Material::BlendFactor::Zero; } break; - case ShaderRootNode::Additive: { + case OldBlendType::Additive: { blendState.enabled = true; blendState.sourceColorBlendMode = Material::BlendFactor::One; blendState.sourceAlphaBlendMode = Material::BlendFactor::One; @@ -1091,7 +1030,7 @@ Material::BlendState ShaderBuilder::fromBlendMode(uint32_t mode) { blendState.destinationColorBlendMode = Material::BlendFactor::One; blendState.destinationAlphaBlendMode = Material::BlendFactor::One; } break; - case ShaderRootNode::Translucent: { + case OldBlendType::Translucent: { blendState.enabled = true; blendState.sourceColorBlendMode = Material::BlendFactor::SourceAlpha; blendState.sourceAlphaBlendMode = Material::BlendFactor::SourceAlpha; @@ -1104,3 +1043,169 @@ Material::BlendState ShaderBuilder::fromBlendMode(uint32_t mode) { return blendState; } + +Material::BlendState ShaderBuilder::loadBlendState(const QDomElement &element) { + Material::BlendState blendState; + + if(!element.isNull()) { + blendState.enabled = true; + if(element.hasAttribute(gOperation)) { + blendState.alphaOperation = toBlendOp(element.attribute(gOperation, "Add").toStdString()); + blendState.colorOperation = blendState.alphaOperation; + } else { + blendState.alphaOperation = toBlendOp(element.attribute(gAlphaOperation, "Add").toStdString()); + blendState.colorOperation = toBlendOp(element.attribute(gColorOperation, "Add").toStdString()); + } + + if(element.hasAttribute(gDestination)) { + blendState.destinationAlphaBlendMode = toBlendFactor(element.attribute(gDestination, "One").toStdString()); + blendState.destinationColorBlendMode = blendState.destinationAlphaBlendMode; + } else { + blendState.destinationAlphaBlendMode = toBlendFactor(element.attribute(gAlphaDestination, "One").toStdString()); + blendState.destinationColorBlendMode = toBlendFactor(element.attribute(gColorDestination, "One").toStdString()); + } + + if(element.hasAttribute(gSource)) { + blendState.sourceAlphaBlendMode = toBlendFactor(element.attribute(gSource, "Zero").toStdString()); + blendState.sourceColorBlendMode = blendState.sourceAlphaBlendMode; + } else { + blendState.sourceAlphaBlendMode = toBlendFactor(element.attribute(gAlphaSource, "Zero").toStdString()); + blendState.sourceColorBlendMode = toBlendFactor(element.attribute(gColorSource, "Zero").toStdString()); + } + } + + return blendState; +} + +void ShaderBuilder::saveBlendState(const Material::BlendState &state, QDomDocument &document, QDomElement &parent) { + QDomElement blend(document.createElement("blend")); + + if(state.colorOperation == state.alphaOperation) { + blend.setAttribute(gOperation, toBlendOp(state.colorOperation).c_str()); + } else { + blend.setAttribute(gAlphaOperation, toBlendOp(state.alphaOperation).c_str()); + blend.setAttribute(gColorOperation, toBlendOp(state.colorOperation).c_str()); + } + + if(state.destinationColorBlendMode == state.destinationAlphaBlendMode) { + blend.setAttribute(gDestination, toBlendFactor(state.destinationColorBlendMode).c_str()); + } else { + blend.setAttribute(gAlphaDestination, toBlendFactor(state.destinationAlphaBlendMode).c_str()); + blend.setAttribute(gColorDestination, toBlendFactor(state.destinationColorBlendMode).c_str()); + } + + if(state.sourceColorBlendMode == state.sourceAlphaBlendMode) { + blend.setAttribute(gSource, toBlendFactor(state.sourceColorBlendMode).c_str()); + } else { + blend.setAttribute(gAlphaSource, toBlendFactor(state.sourceAlphaBlendMode).c_str()); + blend.setAttribute(gColorSource, toBlendFactor(state.sourceColorBlendMode).c_str()); + } + + parent.appendChild(blend); +} + +Material::DepthState ShaderBuilder::loadDepthState(const QDomElement &element) { + Material::DepthState depthState; + + if(!element.isNull()) { + depthState.enabled = (element.attribute(gTest, "true") == "true"); + depthState.writeEnabled = (element.attribute(gWrite, "true") == "true"); + depthState.compareFunction = toTestFunction(element.attribute(gCompare, "Less").toStdString()); + } + + return depthState; +} + +void ShaderBuilder::saveDepthState(const Material::DepthState &state, QDomDocument &document, QDomElement &parent) { + QDomElement depth(document.createElement("depth")); + + depth.setAttribute(gCompare, toTestFunction(state.compareFunction).c_str()); + depth.setAttribute(gWrite, state.writeEnabled ? "true" : "false"); + depth.setAttribute(gTest, state.enabled ? "true" : "false"); + + parent.appendChild(depth); +} + +Material::StencilState ShaderBuilder::loadStencilState(const QDomElement &element) { + Material::StencilState stencilState; + + if(!element.isNull()) { + if(element.hasAttribute(gCompare)) { + stencilState.compareFunctionBack = toTestFunction(element.attribute(gCompare, "Always").toStdString()); + stencilState.compareFunctionFront = stencilState.compareFunctionBack; + } else { + stencilState.compareFunctionBack = toTestFunction(element.attribute(gCompBack, "Always").toStdString()); + stencilState.compareFunctionFront = toTestFunction(element.attribute(gCompFront, "Always").toStdString()); + } + + if(element.hasAttribute(gFail)) { + stencilState.failOperationBack = toTestFunction(element.attribute(gFail, "Keep").toStdString()); + stencilState.failOperationFront = stencilState.compareFunctionBack; + } else { + stencilState.failOperationBack = toActionType(element.attribute(gFailBack, "Keep").toStdString()); + stencilState.failOperationFront = toActionType(element.attribute(gFailFront, "Keep").toStdString()); + } + + if(element.hasAttribute(gPass)) { + stencilState.passOperationBack = toTestFunction(element.attribute(gPass, "Keep").toStdString()); + stencilState.passOperationFront = stencilState.passOperationBack; + } else { + stencilState.passOperationBack = toActionType(element.attribute(gPassBack, "Keep").toStdString()); + stencilState.passOperationFront = toActionType(element.attribute(gPassFront, "Keep").toStdString()); + } + + if(element.hasAttribute(gPass)) { + stencilState.zFailOperationBack = toTestFunction(element.attribute(gZFail, "Keep").toStdString()); + stencilState.zFailOperationFront = stencilState.zFailOperationBack; + } else { + stencilState.zFailOperationBack = toActionType(element.attribute(gZFailBack, "Keep").toStdString()); + stencilState.zFailOperationFront = toActionType(element.attribute(gZFailFront, "Keep").toStdString()); + } + + stencilState.readMask = element.attribute(gReadMask, "1").toInt(); + stencilState.writeMask = element.attribute(gWriteMask, "1").toInt(); + stencilState.reference = element.attribute(gReference, "0").toInt(); + stencilState.enabled = (element.attribute(gTest, "true") == "true"); + } + + return stencilState; +} + +void ShaderBuilder::saveStencilState(const Material::StencilState &state, QDomDocument &document, QDomElement &parent) { + QDomElement stencil(document.createElement("stencil")); + + if(state.compareFunctionBack == state.compareFunctionFront) { + stencil.setAttribute(gCompare, toTestFunction(state.compareFunctionBack).c_str()); + } else { + stencil.setAttribute(gCompBack, toTestFunction(state.compareFunctionBack).c_str()); + stencil.setAttribute(gCompFront, toTestFunction(state.compareFunctionFront).c_str()); + } + + if(state.failOperationBack == state.failOperationFront) { + stencil.setAttribute(gFail, toTestFunction(state.failOperationBack).c_str()); + } else { + stencil.setAttribute(gFailBack, toActionType(state.failOperationBack).c_str()); + stencil.setAttribute(gFailFront, toActionType(state.failOperationFront).c_str()); + } + + if(state.passOperationBack == state.passOperationFront) { + stencil.setAttribute(gPass, toTestFunction(state.passOperationBack).c_str()); + } else { + stencil.setAttribute(gPassBack, toActionType(state.passOperationBack).c_str()); + stencil.setAttribute(gPassFront, toActionType(state.passOperationFront).c_str()); + } + + if(state.zFailOperationBack == state.zFailOperationFront) { + stencil.setAttribute(gZFail, toTestFunction(state.zFailOperationBack).c_str()); + } else { + stencil.setAttribute(gZFailBack, toActionType(state.zFailOperationBack).c_str()); + stencil.setAttribute(gZFailFront, toActionType(state.zFailOperationFront).c_str()); + } + + stencil.setAttribute(gReadMask, state.readMask); + stencil.setAttribute(gWriteMask, state.writeMask); + stencil.setAttribute(gReference, state.reference); + stencil.setAttribute(gTest, state.enabled ? "true" : "false"); + + parent.appendChild(stencil); +} diff --git a/modules/editor/shadertools/converter/shaderbuilder.h b/modules/editor/shadertools/converter/shaderbuilder.h index f7e4aeadb..319632a11 100644 --- a/modules/editor/shadertools/converter/shaderbuilder.h +++ b/modules/editor/shadertools/converter/shaderbuilder.h @@ -17,15 +17,10 @@ #define PARTICLE "Particle" #define FULLSCREEN "Fullscreen" +#define GEOMETRY "Geometry" + #define ATTRIBUTES "Attributes" -#define TYPE "Type" -#define BLEND "Blend" -#define MODEL "Model" -#define SIDE "Side" -#define DEPTH "Depth" -#define DEPTHWRITE "DepthWrite" -#define WIREFRAME "Wireframe" #define TEXTURES "Textures" #define UNIFORMS "Uniforms" #define PROPERTIES "Properties" @@ -74,6 +69,8 @@ class ShaderBuilder : public AssetConverter { public: ShaderBuilder(); + static uint32_t version(); + static string loadIncludes(const string &path, const string &define, const PragmaMap &pragmas); static ShaderBuilderSettings::Rhi currentRhi(); @@ -96,6 +93,15 @@ class ShaderBuilder : public AssetConverter { static Material::BlendState fromBlendMode(uint32_t mode); + static Material::BlendState loadBlendState(const QDomElement &element); + static void saveBlendState(const Material::BlendState &state, QDomDocument &document, QDomElement &parent); + + static Material::DepthState loadDepthState(const QDomElement &element); + static void saveDepthState(const Material::DepthState &state, QDomDocument &document, QDomElement &parent); + + static Material::StencilState loadStencilState(const QDomElement &element); + static void saveStencilState(const Material::StencilState &state, QDomDocument &document, QDomElement &parent); + private: QString templatePath() const Q_DECL_OVERRIDE; diff --git a/modules/editor/shadertools/converter/shadernodegraph.cpp b/modules/editor/shadertools/converter/shadernodegraph.cpp index 3d2b7cb4d..baa54daa7 100644 --- a/modules/editor/shadertools/converter/shadernodegraph.cpp +++ b/modules/editor/shadertools/converter/shadernodegraph.cpp @@ -37,6 +37,24 @@ #include "shaderbuilder.h" +namespace { + const char *gUser("user"); + const char *gValue("value"); + + const char *gType("type"); + + const char *gDomain("domain"); + const char *gModel("model"); + const char *gSide("side"); + const char *gWireFrame("wireframe"); + + const char *gDepthWrite("depthwrite"); + + const char *gBlend("blend"); + const char *gDepth("depth"); + const char *gStencil("stencil"); +}; + map ShaderNode::m_portColors = { { QMetaType::Void, Vector4(0.6f, 0.6f, 0.6f, 1.0f) }, { QMetaType::Int, Vector4(0.22f, 0.46, 0.11f, 1.0f) }, @@ -50,6 +68,8 @@ map ShaderNode::m_portColors = { }; ShaderNodeGraph::ShaderNodeGraph() { + m_version = ShaderBuilder::version(); + scanForCustomFunctions(); // Constants @@ -218,7 +238,6 @@ ShaderNodeGraph::ShaderNodeGraph() { m_inputs.push_back({ "Position Offset", QVector3D(0.0, 0.0, 0.0), true }); m_previewSettings.setMaterialType(ShaderRootNode::Surface); - m_previewSettings.setBlend(ShaderRootNode::Translucent); m_previewSettings.setLightModel(ShaderRootNode::Unlit); m_previewSettings.setDoubleSided(true); } @@ -359,36 +378,112 @@ QStringList ShaderNodeGraph::nodeList() const { return result; } -void ShaderNodeGraph::loadGraph(const QVariantMap &data) { - AbstractNodeGraph::loadGraph(data); +void ShaderNodeGraph::loadGraphV0(const QVariantMap &data) { + AbstractNodeGraph::loadGraphV0(data); - blockSignals(true); ShaderRootNode *root = static_cast(m_rootNode); + root->blockSignals(true); + + root->setMaterialType(static_cast(data[gType].toInt())); + root->setLightModel(static_cast(data[gModel].toInt())); + root->setDoubleSided(data[gSide].toBool()); + root->setDepthTest(data.contains(gDepth) ? data[gDepth].toBool() : true); + root->setDepthWrite(data.contains(gDepthWrite) ? data[gDepthWrite].toBool() : true); + root->setWireframe(data.contains(gWireFrame) ? data[gWireFrame].toBool() : false); + + root->setBlendState(ShaderBuilder::fromBlendMode(data[gBlend].toInt())); - root->setMaterialType(static_cast(m_data[TYPE].toInt())); - root->setBlend(static_cast(m_data[BLEND].toInt())); - root->setLightModel(static_cast(m_data[MODEL].toInt())); - root->setDoubleSided(m_data[SIDE].toBool()); - root->setDepthTest(m_data.contains(DEPTH) ? m_data[DEPTH].toBool() : true); - root->setDepthWrite(m_data.contains(DEPTHWRITE) ? m_data[DEPTHWRITE].toBool() : true); - root->setWireframe(m_data.contains(WIREFRAME) ? m_data[WIREFRAME].toBool() : false); - blockSignals(false); + root->blockSignals(false); emit graphUpdated(); } -void ShaderNodeGraph::save(const QString &path) { +void ShaderNodeGraph::loadGraphV11(const QDomElement &parent) { + AbstractNodeGraph::loadGraphV11(parent); + + if(parent.tagName() == gUser) { + ShaderRootNode *root = static_cast(m_rootNode); + + const QMetaObject *meta = root->metaObject(); + + QDomElement type = parent.firstChildElement(gType); + if(!type.isNull()) { + int32_t index = meta->indexOfEnumerator("Type"); + if(index > -1) { + QMetaEnum metaEnum = meta->enumerator(index); + root->setMaterialType( static_cast(metaEnum.keyToValue(qPrintable(type.attribute(gValue)))) ); + } + } + + QDomElement model = parent.firstChildElement(gModel); + if(!model.isNull()) { + int32_t index = meta->indexOfEnumerator("LightModel"); + if(index > -1) { + QMetaEnum metaEnum = meta->enumerator(index); + root->setLightModel( static_cast(metaEnum.keyToValue(qPrintable(model.attribute(gValue))))); + } + } + + QDomElement side = parent.firstChildElement(gSide); + if(!side.isNull()) { + root->setDoubleSided(side.attribute(gValue) == "true"); + } + + QDomElement wire = parent.firstChildElement(gWireFrame); + if(!wire.isNull()) { + root->setDoubleSided(wire.attribute(gValue) == "true"); + } + + root->setBlendState(ShaderBuilder::loadBlendState(parent.firstChildElement("blend"))); + root->setDepthState(ShaderBuilder::loadDepthState(parent.firstChildElement("depth"))); + root->setStencilState(ShaderBuilder::loadStencilState(parent.firstChildElement("stencil"))); + } +} + +void ShaderNodeGraph::saveGraph(QDomElement parent, QDomDocument xml) const { + AbstractNodeGraph::saveGraph(parent, xml); + ShaderRootNode *root = static_cast(m_rootNode); - m_data[TYPE] = root->materialType(); - m_data[BLEND] = root->blend(); - m_data[MODEL] = root->lightModel(); - m_data[SIDE] = root->isDoubleSided(); - m_data[DEPTH] = root->isDepthTest(); - m_data[DEPTHWRITE] = root->isDepthWrite(); - m_data[WIREFRAME] = root->isWireframe(); + QDomElement user = xml.createElement(gUser); + + const QMetaObject *meta = root->metaObject(); + + int32_t index = meta->indexOfEnumerator("Type"); + if(index > -1) { + QDomElement type = xml.createElement(gType); + QMetaEnum metaEnum = meta->enumerator(index); + type.setAttribute(gValue, metaEnum.key(root->materialType())); + user.appendChild(type); + } + + index = meta->indexOfEnumerator("LightModel"); + if(index > -1) { + QMetaEnum metaEnum = meta->enumerator(index); + QDomElement model = xml.createElement(gModel); + model.setAttribute(gValue, metaEnum.key(root->lightModel())); + user.appendChild(model); + } + + QDomElement side = xml.createElement(gSide); + side.setAttribute(gValue, root->isDoubleSided() ? "true" : "false"); + user.appendChild(side); + + QDomElement wire = xml.createElement(gWireFrame); + wire.setAttribute(gValue, root->isWireframe() ? "true" : "false"); + user.appendChild(wire); + + ShaderBuilder::saveBlendState(root->blendState(), xml, user); - AbstractNodeGraph::save(path); + if(root->depthTest()) { + ShaderBuilder::saveDepthState(root->depthState(), xml, user); + } + + if(root->stencilTest()) { + ShaderBuilder::saveStencilState(root->stencilState(), xml, user); + } + + parent.appendChild(user); } void ShaderNodeGraph::loadUserValues(GraphNode *node, const QVariantMap &values) { @@ -397,7 +492,7 @@ void ShaderNodeGraph::loadUserValues(GraphNode *node, const QVariantMap &values) node->blockSignals(false); } -void ShaderNodeGraph::saveUserValues(GraphNode *node, QVariantMap &values) { +void ShaderNodeGraph::saveUserValues(GraphNode *node, QVariantMap &values) const { node->saveUserData(values); } @@ -471,12 +566,9 @@ VariantMap ShaderNodeGraph::data(bool editor, ShaderRootNode *root) const { properties.push_back(root->isWireframe()); user[PROPERTIES] = properties; - user[BLENDSTATE] = ShaderBuilder::toVariant(ShaderBuilder::fromBlendMode(root->blend())); - - Material::DepthState depthState; - depthState.enabled = root->isDepthTest(); - depthState.writeEnabled = root->isDepthWrite(); - user[DEPTHSTATE] = ShaderBuilder::toVariant(depthState); + user[BLENDSTATE] = ShaderBuilder::toVariant(root->blendState()); + user[DEPTHSTATE] = ShaderBuilder::toVariant(root->depthState()); + user[STENCILSTATE] = ShaderBuilder::toVariant(root->stencilState()); VariantList textures; uint16_t i = 0; @@ -511,18 +603,20 @@ VariantMap ShaderNodeGraph::data(bool editor, ShaderRootNode *root) const { } user[UNIFORMS] = uniforms; + Material::BlendState blend = root->blendState(); + string define; - switch(root->blend()) { - case ShaderRootNode::Additive: { - define = "#define BLEND_ADDITIVE 1"; - } break; - case ShaderRootNode::Translucent: { - define = "#define BLEND_TRANSLUCENT 1"; - } break; - default: { - define = "#define BLEND_OPAQUE 1"; - } break; + if(blend.sourceColorBlendMode == Material::BlendFactor::One && + blend.destinationColorBlendMode == Material::BlendFactor::One) { + define = "#define BLEND_ADDITIVE 1"; + } else if(blend.sourceColorBlendMode == Material::BlendFactor::SourceAlpha && + blend.destinationColorBlendMode == Material::BlendFactor::OneMinusSourceAlpha) { + define = "#define BLEND_TRANSLUCENT 1"; + } else if(blend.sourceColorBlendMode == Material::BlendFactor::One && + blend.destinationColorBlendMode == Material::BlendFactor::Zero) { + define = "#define BLEND_OPAQUE 1"; } + switch(root->lightModel()) { case ShaderRootNode::Lit: { define += "\n#define MODEL_LIT 1"; @@ -551,7 +645,7 @@ VariantMap ShaderNodeGraph::data(bool editor, ShaderRootNode *root) const { user[FRAGMENT] = data; } } - if(root->materialType() == ShaderRootNode::Surface && !editor) { + if(root->materialType() == Material::Surface && !editor) { define += "\n#define VISIBILITY_BUFFER 1"; Variant data = ShaderBuilder::loadIncludes(fragment, define, m_pragmas); if(data.isValid()) { @@ -572,7 +666,7 @@ VariantMap ShaderNodeGraph::data(bool editor, ShaderRootNode *root) const { user[STATIC] = data; } } - if(root->materialType() == ShaderRootNode::Surface && !editor) { + if(root->materialType() == Material::Surface && !editor) { { string localDefine = define + "\n#define INSTANCING"; Variant data = ShaderBuilder::loadIncludes("Static.vert", localDefine, m_pragmas); diff --git a/modules/editor/shadertools/converter/shadernodegraph.h b/modules/editor/shadertools/converter/shadernodegraph.h index 9d2ee872f..8fb41f49b 100644 --- a/modules/editor/shadertools/converter/shadernodegraph.h +++ b/modules/editor/shadertools/converter/shadernodegraph.h @@ -11,6 +11,12 @@ class RenderTarget; class CommandBuffer; +enum OldBlendType { + Opaque, + Additive, + Translucent +}; + class ShaderNodeGraph : public AbstractNodeGraph { Q_OBJECT @@ -33,13 +39,13 @@ class ShaderNodeGraph : public AbstractNodeGraph { void addFunction(const QString &name, QString &code); - QStringList nodeList() const Q_DECL_OVERRIDE; - - void save(const QString &path) Q_DECL_OVERRIDE; + QStringList nodeList() const override; - void loadGraph(const QVariantMap &data) Q_DECL_OVERRIDE; + void loadGraphV0(const QVariantMap &data) override; + void loadGraphV11(const QDomElement &parent) override; + void saveGraph(QDomElement parent, QDomDocument xml) const override; - void setPreviewVisible(GraphNode *node, bool visible) Q_DECL_OVERRIDE; + void setPreviewVisible(GraphNode *node, bool visible) override; void updatePreviews(CommandBuffer &buffer); private slots: @@ -47,16 +53,16 @@ private slots: private: void markDirty(GraphNode *node); - Texture *preview(GraphNode *node) Q_DECL_OVERRIDE; + Texture *preview(GraphNode *node) override; QString buildFrom(GraphNode *node, Stage stage); - void loadUserValues(GraphNode *node, const QVariantMap &values) Q_DECL_OVERRIDE; - void saveUserValues(GraphNode *node, QVariantMap &values) Q_DECL_OVERRIDE; + void loadUserValues(GraphNode *node, const QVariantMap &values) override; + void saveUserValues(GraphNode *node, QVariantMap &values) const override; - GraphNode *nodeCreate(const QString &path, int &index) Q_DECL_OVERRIDE; - GraphNode *createRoot() Q_DECL_OVERRIDE; - void nodeDelete(GraphNode *node) Q_DECL_OVERRIDE; + GraphNode *nodeCreate(const QString &path, int &index) override; + GraphNode *createRoot() override; + void nodeDelete(GraphNode *node) override; Variant compile(int32_t rhi, const QString &source, const string &define, int stage) const; diff --git a/modules/renders/rendergl/includes/resources/materialgl.h b/modules/renders/rendergl/includes/resources/materialgl.h index 5cdbdf42b..60d0ae1c9 100644 --- a/modules/renders/rendergl/includes/resources/materialgl.h +++ b/modules/renders/rendergl/includes/resources/materialgl.h @@ -78,7 +78,7 @@ class MaterialGL : public Material { protected: uint32_t buildShader(uint16_t type, const string &src = string()); - uint32_t buildProgram(uint32_t vertex, uint32_t fragment, uint32_t geometry = 0); + uint32_t buildProgram(const vector &shaders); bool checkShader(uint32_t shader); bool checkProgram(uint32_t program); diff --git a/modules/renders/rendergl/src/resources/materialgl.cpp b/modules/renders/rendergl/src/resources/materialgl.cpp index bba0044c6..70ef03cfb 100644 --- a/modules/renders/rendergl/src/resources/materialgl.cpp +++ b/modules/renders/rendergl/src/resources/materialgl.cpp @@ -64,10 +64,11 @@ uint32_t MaterialGL::getProgram(uint16_t type) { } m_programs.clear(); + uint32_t geometry = 0; auto itg = m_shaderSources.find(GeometryDefault); if(itg != m_shaderSources.end()) { - geometry = buildShader(itg->first, itg->second); + buildShader(itg->first, itg->second); } for(uint16_t v = Static; v < VertexLast; v++) { @@ -78,8 +79,13 @@ uint32_t MaterialGL::getProgram(uint16_t type) { if(itf != m_shaderSources.end()) { uint32_t vertex = buildShader(itv->first, itv->second); uint32_t fragment = buildShader(itf->first, itf->second); - uint32_t index = v * f; - m_programs[index] = buildProgram(vertex, fragment, geometry); + + vector shaders = {vertex, fragment}; + if(geometry > 0) { + shaders.push_back(geometry); + } + + m_programs[v * f] = buildProgram(shaders); } } } @@ -145,7 +151,7 @@ uint32_t MaterialGL::buildShader(uint16_t type, const string &src) { return shader; } -uint32_t MaterialGL::buildProgram(uint32_t vertex, uint32_t fragment, uint32_t geometry) { +uint32_t MaterialGL::buildProgram(const vector &shaders) { uint32_t result = glCreateProgram(); if(result) { #ifndef THUNDER_MOBILE @@ -153,24 +159,15 @@ uint32_t MaterialGL::buildProgram(uint32_t vertex, uint32_t fragment, uint32_t g CommandBufferGL::setObjectName(GL_PROGRAM, result, name()); } #endif - - glAttachShader(result, vertex); - glAttachShader(result, fragment); - if(geometry > 0) { - glAttachShader(result, geometry); + for(auto it : shaders) { + glAttachShader(result, it); } glLinkProgram(result); - glDetachShader(result, vertex); - glDeleteShader(vertex); - - glDetachShader(result, fragment); - glDeleteShader(fragment); - - if(geometry > 0) { - glDetachShader(result, geometry); - glDeleteShader(geometry); + for(auto it : shaders) { + glDetachShader(result, it); + glDeleteShader(it); } checkProgram(result); diff --git a/thirdparty/next/inc/math/amath.h b/thirdparty/next/inc/math/amath.h index 8eed2d7fa..fd83dd069 100644 --- a/thirdparty/next/inc/math/amath.h +++ b/thirdparty/next/inc/math/amath.h @@ -75,6 +75,12 @@ class NEXT_LIBRARY_EXPORT Mathf { static int gausianKernel(areal radius, areal *samples, uint8_t maxSamples); static areal perlinNoise(areal x, areal y); + template + static void hashCombine(uint32_t &seed, const T &v) { + std::hash hash; + seed ^= hash(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); + } + template static float distanceToSegment(const T &a, const T &b, const T &p) { T v = b - a; diff --git a/worldeditor/bin/engine/materials/DefaultMesh.mtl b/worldeditor/bin/engine/materials/DefaultMesh.mtl index 604c9b4a5..949b235ea 100644 --- a/worldeditor/bin/engine/materials/DefaultMesh.mtl +++ b/worldeditor/bin/engine/materials/DefaultMesh.mtl @@ -1,35 +1,21 @@ - - 0 - true - true - - - 4 - 0 - 0 - 1 - - - 4 - 0 - 0 - 1 - - - 1 - - - 1 - - - 0.8999999761581421 - - -200 - 0 - - - false - 0 - true - false - + + + + + 0.8999999761581421 + + + + + + + + + + + + + + + + diff --git a/worldeditor/bin/engine/materials/DefaultMesh.mtl.set b/worldeditor/bin/engine/materials/DefaultMesh.mtl.set index 7027fe2b1..8e0d80e28 100644 --- a/worldeditor/bin/engine/materials/DefaultMesh.mtl.set +++ b/worldeditor/bin/engine/materials/DefaultMesh.mtl.set @@ -1,11 +1,11 @@ { "guid": "{00000000-0402-0000-0000-000000000000}", - "md5": "{588a0351-665f-23b9-1e79-523de67a9364}", + "md5": "{d8524e94-637d-71e1-1a8c-feaf2c6b3a0e}", "settings": { "CurrentRHI": 1 }, "subitems": { }, "type": 48, - "version": 10 + "version": 12 } diff --git a/worldeditor/bin/engine/materials/DefaultSprite.mtl b/worldeditor/bin/engine/materials/DefaultSprite.mtl index 7c1490703..ccbd9640f 100644 --- a/worldeditor/bin/engine/materials/DefaultSprite.mtl +++ b/worldeditor/bin/engine/materials/DefaultSprite.mtl @@ -1,153 +1,45 @@ - - 2 - true - false - - - 1 - 0 - 0 - 3 - - - 5 - 0 - 0 - 5 - - - 1 - 0 - 3 - 1 - - - 1 - 4 - 5 - 1 - - - 2 - 0 - 3 - 2 - - - 1 - 0 - 4 - 2 - - - 1 - 0 - 0 - 3 - - - 1 - 0 - 3 - 1 - - - 2 - 0 - 3 - 2 - - - 1 - 0 - 4 - 2 - - - 2 - 0 - 5 - 4 - - - 5 - 0 - 0 - 5 - - - 1 - 4 - 5 - 1 - - - 2 - 0 - 5 - 4 - - - 0 - - - 1 - - - - Template - .embedded/invalid.png - Texture - - - -624 - 112 - - - 2 - - - - Vector4 - 1 - 1 - 1 - 1 - - - - -624 - -16 - - - 3 - - - -192 - 32 - - - 4 - - - true - false - false - false - - -400 - 160 - - - 5 - - - -192 - 160 - - - true - 0 - true - false - + + + + + .embedded/invalid.png, Texture + + + 1, 1, 1, 1 + color0 + + + + true + false + false + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/worldeditor/bin/engine/materials/DefaultSprite.mtl.set b/worldeditor/bin/engine/materials/DefaultSprite.mtl.set index abce0ec8c..3db489f06 100644 --- a/worldeditor/bin/engine/materials/DefaultSprite.mtl.set +++ b/worldeditor/bin/engine/materials/DefaultSprite.mtl.set @@ -1,11 +1,11 @@ { "guid": "{00000000-0401-0000-0000-000000000000}", - "md5": "{871d40af-8c64-46f9-da8c-2fc9e665609a}", + "md5": "{88802af5-3600-d8ca-c387-67c3d2bdd510}", "settings": { "CurrentRHI": 1 }, "subitems": { }, "type": 48, - "version": 10 + "version": 12 }