New nodes implementation

Change-Id: I54649bd1b1f655439eb9eafee9c1402c097e2696
Reviewed-by: spyro-adb <adb@spyro-soft.com>
This commit is contained in:
Andrzej Biniek
2025-01-07 10:18:15 +01:00
committed by spyro-adb
parent 2fafba7f8f
commit 91ce0065ab
21 changed files with 1689 additions and 13 deletions

View File

@@ -3,12 +3,15 @@
import QtQuick
import QtQuick.Controls
import QtQuick3D as QtQuick3D
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
import Nodes as Nodes
import NewNodes as NewNodes
import QuickQanava as Qan
StudioControls.Menu {
id: contextMenu
@@ -27,6 +30,169 @@ StudioControls.Menu {
contextMenu.inputsModel = null;
}
StudioControls.Menu {
title: "NewNodes.ProviderNodes"
Component {
id: providerNode
NewNodes.ProviderNode {
}
}
Repeater {
model: [
{
text: "Color",
action: () => {
const node = internal.createNode(providerNode);
node.item.sourceComponent = node.item.components["colorPicker"];
node.item.text = "Color provider";
}
},
{
text: "CheckBox",
action: () => {
const node = internal.createNode(providerNode);
node.item.sourceComponent = node.item.components["checkBox"];
node.item.text = "Boolean provider";
}
},
{
text: "Number",
action: () => {
const node = internal.createNode(providerNode);
node.item.sourceComponent = node.item.components["realSpinBox"];
node.item.text = "Number provider";
}
},
{
text: "Texture Source",
action: () => {
const node = internal.createNode(providerNode);
node.item.sourceComponent = node.item.components["imageSource"];
node.item.text = "Texture Source provider";
}
},
{
text: "Texture Mapping Mode",
action: () => {
const node = internal.createNode(providerNode);
node.item.sourceComponent = node.item.components["textureMappingMode"];
node.item.text = "Texture Mapping Mode provider";
}
},
{
text: "Texture Tiling Mode",
action: () => {
const node = internal.createNode(providerNode);
node.item.sourceComponent = node.item.components["textureTilingMode"];
node.item.text = "Texture Tiling Mode provider";
}
},
{
text: "Texture Filtering",
action: () => {
const node = internal.createNode(providerNode);
node.item.sourceComponent = node.item.components["textureFiltering"];
node.item.text = "Texture Filtering provider";
}
},
{
text: "Material Alpha Mode",
action: () => {
const node = internal.createNode(providerNode);
node.item.sourceComponent = node.item.components["materialAlphaMode"];
node.item.text = "Material Alpha Mode provider";
}
},
{
text: "Material Blend Mode",
action: () => {
const node = internal.createNode(providerNode);
node.item.sourceComponent = node.item.components["materialBlendMode"];
node.item.text = "Material Blend Mode provider";
}
},
{
text: "Material Channel",
action: () => {
const node = internal.createNode(providerNode);
node.item.sourceComponent = node.item.components["materialChannel"];
node.item.text = "Material Channel provider";
}
},
{
text: "Material Lighting",
action: () => {
const node = internal.createNode(providerNode);
node.item.sourceComponent = node.item.components["materialLighting"];
node.item.text = "Material Lighting provider";
}
},
]
delegate: StudioControls.MenuItem {
text: modelData.text
onTriggered: () => {
modelData.action();
}
}
}
}
StudioControls.MenuItem {
text: qsTr("NewNodes.TextureNode")
onTriggered: () => {
let gnode = contextMenu.graph.insertGroup(textureNode);
gnode.item.x = contextMenu.newPosition.x;
gnode.item.y = contextMenu.newPosition.y;
gnode.label = "Texture";
}
Component {
id: textureNode
NewNodes.TextureNode {
}
}
}
StudioControls.MenuItem {
text: qsTr("NewNodes.PrincipledMaterialNode")
onTriggered: () => {
let gnode = contextMenu.graph.insertGroup(principledMaterialNode);
gnode.item.x = contextMenu.newPosition.x;
gnode.item.y = contextMenu.newPosition.y;
gnode.label = "PrincipledMaterial";
}
Component {
id: principledMaterialNode
NewNodes.PrincipledMaterialNode {
}
}
}
StudioControls.MenuItem {
text: qsTr("NewNodes.MaterialViewerNode")
onTriggered: () => {
const node = internal.createNode(materialViewerNode);
}
Component {
id: materialViewerNode
NewNodes.MaterialViewerNode {
}
}
}
StudioControls.MenuItem {
text: qsTr("BaseColor")
@@ -143,6 +309,7 @@ StudioControls.Menu {
const nodeItem = node.item;
nodeItem.x = contextMenu.newPosition.x;
nodeItem.y = contextMenu.newPosition.y;
return node;
}
}
}

View File

@@ -16,8 +16,10 @@ Qan.Graph {
}
onConnectorRequestEdgeCreation: (srcNode, dstNode, srcPortItem, dstPortItem) => {
if (srcPortItem.dataType !== dstPortItem.dataType) {
return;
if (dstPortItem.dataType !== "Any") {
if (srcPortItem.dataType !== dstPortItem.dataType) {
return;
}
}
const edge = root.insertEdge(srcNode, dstNode);
@@ -35,7 +37,15 @@ Qan.Graph {
});
}
}
onNodeRemoved: node => {NodeGraphEditorBackend.nodeGraphEditorModel.hasUnsavedChanges = true;}
onEdgeInserted: {
NodeGraphEditorBackend.nodeGraphEditorModel.hasUnsavedChanges = true;
}
onNodeInserted: {
NodeGraphEditorBackend.nodeGraphEditorModel.hasUnsavedChanges = true;
}
onNodeRemoved: node => {
NodeGraphEditorBackend.nodeGraphEditorModel.hasUnsavedChanges = true;
}
onOnEdgeRemoved: edge => {
const srcNode = edge.getSource();
const dstNode = edge.getDestination();
@@ -43,14 +53,11 @@ Qan.Graph {
const dstPortItem = edge.item.destinationItem;
// TODO: add reset binding function
dstNode.item.value[dstPortItem.dataName] = dstNode.item.reset[dstPortItem.dataName];
NodeGraphEditorBackend.nodeGraphEditorModel.hasUnsavedChanges = true;
}
onEdgeInserted: {
NodeGraphEditorBackend.nodeGraphEditorModel.hasUnsavedChanges = true;
}
onNodeInserted: {
if (dstPortItem.dataReset) {
dstPortItem.dataReset();
} else {
dstNode.item.value[dstPortItem.dataName] = dstNode.item.reset[dstPortItem.dataName];
}
NodeGraphEditorBackend.nodeGraphEditorModel.hasUnsavedChanges = true;
}
}

View File

@@ -9,7 +9,8 @@ Qan.Port {
id: root
property var dataBinding: null
property string dataName: ""
property string dataType: ""
property string dataId: ""
property string dataName: ""
property var dataReset: null
property string dataType: ""
}

View File

@@ -0,0 +1,102 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QuickQanava as Qan
import StudioControls as StudioControls
import NodeGraphEditorBackend
Qan.GroupItem {
id: root
property QtObject metadata: QtObject {
property var nodes: []
}
readonly property string uuid: NodeGraphEditorBackend.widget.generateUUID()
acceptDrops: false
container: content
droppable: false
height: c.visible ? content.height + header.height : header.height
resizable: false
width: content.width
Component.onCompleted: {
internal.initialize();
}
Component.onDestruction: {
internal.terminate();
}
ColumnLayout {
anchors.fill: parent
spacing: 0
Rectangle {
id: header
Layout.fillWidth: true
Layout.preferredHeight: 35
color: "green"
RowLayout {
anchors.fill: parent
StudioControls.AbstractButton {
id: buttonAlignTop
buttonIcon: "\u0187"
onClicked: {
c.visible = !c.visible;
}
}
Text {
text: root.node.label
}
}
}
Rectangle {
id: c
Layout.fillHeight: true
Layout.fillWidth: true
color: "white"
Column {
id: content
spacing: 3
}
}
}
QtObject {
id: internal
readonly property QtObject data: QtObject {
readonly property var instances: []
}
readonly property var initialize: () => {
const graph = root.graph;
root.metadata.nodes.forEach(data => {
const metadata = Components[data.metadata];
const node = metadata.constructor(graph, root, data);
graph.groupNode(root.node, node, null, false);
internal.data.instances.push(node);
});
}
readonly property var terminate: () => {
internal.data.instances.forEach(n => {
graph.removeNode(n);
});
}
}
}

View File

@@ -0,0 +1,52 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
Qan.NodeItem {
id: root
default property alias data: content.data
property QtObject metadata: QtObject {
property var ports: []
}
readonly property string uuid: NodeGraphEditorBackend.widget.generateUUID()
connectable: Qan.NodeItem.UnConnectable
height: 35
resizable: false
width: 350
Component.onCompleted: {
internal.initialize();
}
QtObject {
id: internal
readonly property var initialize: () => {
const graph = root.graph;
root.metadata.ports.forEach(data => {
const port = graph.insertPort(root.node, data.dock, data.type, data.text, data.id);
port.dataBinding = data.binding;
port.dataReset = data.reset;
port.dataType = "Any";
});
}
}
Item {
id: content
anchors.fill: parent
}
}

View File

@@ -0,0 +1,62 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
StudioControls.PopupDialog {
id: colorPopup
required property color currentColor
property QtObject loaderItem: loader.item
property color originalColor
signal activateColor(color: color)
function open(showItem) {
loader.ensureActive();
colorPopup.show(showItem);
loader.updateOriginalColor();
}
width: 260
onClosing: loader.active = false
onOriginalColorChanged: loader.updateOriginalColor()
Loader {
id: loader
function ensureActive() {
if (!loader.active)
loader.active = true;
}
function updateOriginalColor() {
if (loader.status === Loader.Ready)
loader.item.originalColor = colorPopup.originalColor;
}
sourceComponent: StudioControls.ColorEditorPopup {
visible: colorPopup.visible
width: colorPopup.contentWidth
onActivateColor: color => {
colorPopup.activateColor(color);
}
}
onLoaded: {
loader.updateOriginalColor();
colorPopup.titleBar = loader.item.titleBarContent;
}
Binding {
property: "color"
target: loader.item
value: colorPopup.currentColor
when: loader.status === Loader.Ready
}
}
}

View File

@@ -0,0 +1,52 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QtQuick3D as QtQuick3D
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
BaseGroup {
id: root
readonly property QtObject value: QtObject {
property int channel
property color color
property QtQuick3D.Texture map
property bool singleChannelEnabled
}
metadata: QtObject {
property var nodes: [
{
metadata: "input",
text: "Color",
sourceComponent: "colorPicker",
value: "color"
},
{
metadata: "input",
text: "Map",
value: "map",
resetValue: null
},
{
metadata: "input",
text: "Use Single Channel",
sourceComponent: "checkBox",
value: "singleChannelEnabled"
},
{
metadata: "input",
text: "Channel",
sourceComponent: "materialChannel",
value: "channel"
},
]
}
}

View File

@@ -0,0 +1,152 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
pragma Singleton
import QtQuick
QtObject {
readonly property QtObject color: QtObject {
id: color
readonly property Component component: Component {
ColorNode {
}
}
readonly property var constructor: (graph, self, data) => {
const node = graph.insertGroup(color.component);
node.item.draggable = false;
node.label = data.text;
data.bindings(node.item.value);
return node;
}
}
readonly property QtObject input: QtObject {
id: input
readonly property Component component: Component {
InputNode {
}
}
readonly property var constructor: (graph, self, data) => {
const node = graph.insertNode(input.component);
node.item.draggable = false;
node.item.text = data.text;
node.item.sourceComponent = node.item.components[data.sourceComponent];
node.item.value.data = self.value[data.value];
node.item.value.reset = data.resetValue;
self.value[data.value] = Qt.binding(() => {
return node.item.value.data;
});
return node;
}
}
readonly property QtObject metalness: QtObject {
id: metalness
readonly property Component component: Component {
MetalnessNode {
}
}
readonly property var constructor: (graph, self, data) => {
const node = graph.insertGroup(metalness.component);
node.item.draggable = false;
node.label = data.text;
data.bindings(node.item.value);
return node;
}
}
readonly property QtObject normal: QtObject {
id: normal
readonly property Component component: Component {
NormalNode {
}
}
readonly property var constructor: (graph, self, data) => {
const node = graph.insertGroup(normal.component);
node.item.draggable = false;
node.label = data.text;
data.bindings(node.item.value);
return node;
}
}
readonly property QtObject occlusion: QtObject {
id: occlusion
readonly property Component component: Component {
OcclusionNode {
}
}
readonly property var constructor: (graph, self, data) => {
const node = graph.insertGroup(occlusion.component);
node.item.draggable = false;
node.label = data.text;
data.bindings(node.item.value);
return node;
}
}
readonly property QtObject opacity: QtObject {
id: opacity
readonly property Component component: Component {
OpacityNode {
}
}
readonly property var constructor: (graph, self, data) => {
const node = graph.insertGroup(opacity.component);
node.item.draggable = false;
node.label = data.text;
data.bindings(node.item.value);
return node;
}
}
readonly property QtObject output: QtObject {
id: output
readonly property Component component: Component {
OutputNode {
}
}
readonly property var constructor: (graph, self, data) => {
const node = graph.insertNode(output.component);
node.item.draggable = false;
node.item.text = data.text;
node.item.value.data = self.value;
// self.value = Qt.binding(() => {
// return node.item.value;
// });
return node;
}
}
readonly property QtObject roughness: QtObject {
id: roughness
readonly property Component component: Component {
RoughnessNode {
}
}
readonly property var constructor: (graph, self, data) => {
const node = graph.insertGroup(roughness.component);
node.item.draggable = false;
node.label = data.text;
data.bindings(node.item.value);
return node;
}
}
}

View File

@@ -0,0 +1,70 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
ValueNode {
id: root
property alias sourceComponent: loader.sourceComponent
property alias text: label.text
metadata: QtObject {
property var ports: [
{
dock: Qan.NodeItem.Left,
type: Qan.PortItem.In,
text: "",
id: "value_input",
binding: value => {
loader.visible = false;
root.value.data = Qt.binding(() => {
return value.data;
});
},
reset: () => {
loader.visible = true;
root.value.data = (root.value.reset !== undefined) ? root.value.reset : root.value.data;
}
}
]
}
RowLayout {
anchors.fill: parent
anchors.margins: 3
spacing: 0
Item {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.margins: 2
Text {
id: label
anchors.verticalCenter: parent.verticalCenter
text: "{{placeholder}}"
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.margins: 2
Loader {
id: loader
anchors.centerIn: parent
}
}
}
}

View File

@@ -0,0 +1,115 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QtQuick3D as QtQuick3D
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
BaseNode {
id: root
readonly property QtObject value: QtObject {
property QtQuick3D.PrincipledMaterial data: QtQuick3D.PrincipledMaterial {
}
property string type: "undefined"
}
height: 150
width: 150
metadata: QtObject {
property var ports: [
{
dock: Qan.NodeItem.Left,
type: Qan.PortItem.In,
text: "",
id: "value_input",
binding: value => {
root.value.data = Qt.binding(() => {
return value.data;
});
},
reset: () => {
root.value.data = null;
}
}
]
}
Rectangle {
anchors.fill: parent
color: "white"
ColumnLayout {
anchors.fill: parent
anchors.margins: 3
spacing: 0
Item {
Layout.fillWidth: true
Layout.margins: 2
Layout.preferredHeight: 35
Text {
id: label
anchors.centerIn: parent
text: "Material Viewer"
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.margins: 2
QtQuick3D.View3D {
id: view3D
anchors.fill: parent
camera: QtQuick3D.PerspectiveCamera {
clipFar: 1000
clipNear: 1
eulerRotation.x: -5.71
y: 70
z: 200
}
environment: QtQuick3D.SceneEnvironment {
antialiasingMode: QtQuick3D.SceneEnvironment.MSAA
antialiasingQuality: QtQuick3D.SceneEnvironment.High
backgroundMode: QtQuick3D.SceneEnvironment.Transparent
clearColor: "#000000"
}
QtQuick3D.Node {
QtQuick3D.DirectionalLight {
brightness: 1
eulerRotation.x: -26
eulerRotation.y: -50
}
QtQuick3D.Node {
y: 60
QtQuick3D.Model {
id: model
eulerRotation.y: 45
materials: root.value.data
scale: Qt.vector3d(1.7, 1.7, 1.7)
source: "#Sphere"
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,45 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QtQuick3D as QtQuick3D
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
BaseGroup {
id: root
readonly property QtObject value: QtObject {
property int channel
property QtQuick3D.Texture map
property real metalness
}
metadata: QtObject {
property var nodes: [
{
metadata: "input",
text: "Metalness",
sourceComponent: "realSpinBox",
value: "metalness"
},
{
metadata: "input",
text: "Map",
value: "map",
resetValue: null
},
{
metadata: "input",
text: "Channel",
sourceComponent: "materialChannel",
value: "channel"
},
]
}
}

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QtQuick3D as QtQuick3D
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
BaseGroup {
id: root
readonly property QtObject value: QtObject {
property QtQuick3D.Texture map
property real strength: 1.0
}
metadata: QtObject {
property var nodes: [
{
metadata: "input",
text: "Map",
value: "map",
resetValue: null
},
{
metadata: "input",
text: "Strength",
sourceComponent: "realSpinBox",
value: "strength"
},
]
}
}

View File

@@ -0,0 +1,45 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QtQuick3D as QtQuick3D
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
BaseGroup {
id: root
readonly property QtObject value: QtObject {
property int channel
property QtQuick3D.Texture map
property real occlusion
}
metadata: QtObject {
property var nodes: [
{
metadata: "input",
text: "Occlusion",
sourceComponent: "realSpinBox",
value: "occlusion"
},
{
metadata: "input",
text: "Map",
value: "map",
resetValue: null
},
{
metadata: "input",
text: "Channel",
sourceComponent: "materialChannel",
value: "channel"
},
]
}
}

View File

@@ -0,0 +1,45 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QtQuick3D as QtQuick3D
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
BaseGroup {
id: root
readonly property QtObject value: QtObject {
property int channel
property QtQuick3D.Texture map
property real opacity: 1.0
}
metadata: QtObject {
property var nodes: [
{
metadata: "input",
text: "Opacity",
sourceComponent: "realSpinBox",
value: "opacity"
},
{
metadata: "input",
text: "Map",
value: "map",
resetValue: null
},
{
metadata: "input",
text: "Channel",
sourceComponent: "materialChannel",
value: "channel"
},
]
}
}

View File

@@ -0,0 +1,48 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
ValueNode {
id: root
property alias text: label.text
metadata: QtObject {
property var ports: [
{
dock: Qan.NodeItem.Right,
type: Qan.PortItem.Out,
text: "",
id: "value_output"
}
]
}
RowLayout {
anchors.fill: parent
anchors.margins: 3
spacing: 0
Item {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.margins: 2
Text {
id: label
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: "{{placeholder}}"
}
}
}
}

View File

@@ -0,0 +1,136 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QtQuick3D as QtQuick3D
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
BaseGroup {
id: root
readonly property QtQuick3D.PrincipledMaterial value: QtQuick3D.PrincipledMaterial {
}
metadata: QtObject {
property var nodes: [
{
metadata: "output",
text: "Output"
},
{
metadata: "input",
text: "Alpha Mode",
sourceComponent: "materialAlphaMode",
value: "alphaMode"
},
{
metadata: "input",
text: "Blend Mode",
sourceComponent: "materialBlendMode",
value: "blendMode"
},
{
metadata: "input",
text: "Lighting",
sourceComponent: "materialLighting",
value: "lighting"
},
{
metadata: "color",
text: "Base Color",
bindings: values => {
value.baseColor = Qt.binding(() => {
return values.color;
});
value.baseColorChannel = Qt.binding(() => {
return values.channel;
});
value.baseColorMap = Qt.binding(() => {
return values.map;
});
value.baseColorSingleChannelEnabled = Qt.binding(() => {
return values.singleChannelEnabled;
});
}
},
{
metadata: "metalness",
text: "Metalness",
bindings: values => {
value.metalness = Qt.binding(() => {
return values.metalness;
});
value.metalnessChannel = Qt.binding(() => {
return values.channel;
});
value.metalnessMap = Qt.binding(() => {
return values.map;
});
}
},
{
metadata: "roughness",
text: "Roughness",
bindings: values => {
value.roughness = Qt.binding(() => {
return values.roughness;
});
value.roughnessChannel = Qt.binding(() => {
return values.channel;
});
value.roughnessMap = Qt.binding(() => {
return values.map;
});
}
},
{
metadata: "normal",
text: "Normal",
bindings: values => {
value.normalMap = Qt.binding(() => {
return values.map;
});
value.normalStrength = Qt.binding(() => {
return values.strength;
});
}
},
{
metadata: "occlusion",
text: "Occlusion",
bindings: values => {
value.occlusionAmount = Qt.binding(() => {
return values.occlusion;
});
value.occlusionChannel = Qt.binding(() => {
return values.channel;
});
value.occlusionMap = Qt.binding(() => {
return values.map;
});
}
},
{
metadata: "opacity",
text: "Opacity",
bindings: values => {
value.opacity = Qt.binding(() => {
return values.opacity;
});
value.opacityChannel = Qt.binding(() => {
return values.channel;
});
value.opacityMap = Qt.binding(() => {
return values.map;
});
}
},
]
}
}

View File

@@ -0,0 +1,68 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
ValueNode {
id: root
property alias sourceComponent: loader.sourceComponent
property alias text: label.text
height: 100
width: 150
metadata: QtObject {
property var ports: [
{
dock: Qan.NodeItem.Right,
type: Qan.PortItem.Out,
text: "",
id: "value_output"
}
]
}
Rectangle {
anchors.fill: parent
color: "white"
ColumnLayout {
anchors.fill: parent
anchors.margins: 3
spacing: 0
Item {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.margins: 2
Text {
id: label
anchors.centerIn: parent
text: "{{placeholder}}"
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.margins: 2
Loader {
id: loader
anchors.centerIn: parent
}
}
}
}
}

View File

@@ -0,0 +1,45 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QtQuick3D as QtQuick3D
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
BaseGroup {
id: root
readonly property QtObject value: QtObject {
property int channel
property QtQuick3D.Texture map
property real roughness
}
metadata: QtObject {
property var nodes: [
{
metadata: "input",
text: "Roughness",
sourceComponent: "realSpinBox",
value: "roughness"
},
{
metadata: "input",
text: "Map",
value: "map",
resetValue: null
},
{
metadata: "input",
text: "Channel",
sourceComponent: "materialChannel",
value: "channel"
},
]
}
}

View File

@@ -0,0 +1,108 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QtQuick3D as QtQuick3D
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
BaseGroup {
id: root
readonly property QtQuick3D.Texture value: QtQuick3D.Texture {
sourceItem: image
}
metadata: QtObject {
property var nodes: [
{
metadata: "output",
text: "Output"
},
{
metadata: "input",
text: "Source",
sourceComponent: "imageSource",
value: "source"
},
{
metadata: "input",
text: "Scale.U",
sourceComponent: "realSpinBox",
value: "scaleU"
},
{
metadata: "input",
text: "Scale.V",
sourceComponent: "realSpinBox",
value: "scaleV"
},
{
metadata: "input",
text: "Flip.U",
sourceComponent: "checkBox",
value: "flipU"
},
{
metadata: "input",
text: "Flip.V",
sourceComponent: "checkBox",
value: "flipV"
},
{
metadata: "input",
text: "Auto Orientation",
sourceComponent: "checkBox",
value: "autoOrientation"
},
{
metadata: "input",
text: "Mapping Mode",
sourceComponent: "textureMappingMode",
value: "mappingMode"
},
{
metadata: "input",
text: "Tiling.U",
sourceComponent: "textureTilingMode",
value: "tilingModeHorizontal"
},
{
metadata: "input",
text: "Tiling.V",
sourceComponent: "textureTilingMode",
value: "tilingModeVertical"
},
{
metadata: "input",
text: "Mag Filter",
sourceComponent: "textureFiltering",
value: "magFilter"
},
{
metadata: "input",
text: "Min Filter",
sourceComponent: "textureFiltering",
value: "minFilter"
},
{
metadata: "input",
text: "Mip Filter",
sourceComponent: "textureFiltering",
value: "mipFilter"
},
]
}
Image {
id: image
source: root.value.source
visible: false
}
}

View File

@@ -0,0 +1,295 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick
import QtQuick.Layouts
import QuickQanava as Qan
import HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import NodeGraphEditorBackend
BaseNode {
id: root
readonly property QtObject components: QtObject {
readonly property Component checkBox: Component {
StudioControls.CheckBox {
id: checkBox
actionIndicatorVisible: false
//checked: root.value.data
onCheckedChanged: () => {
root.value.data = checkBox.checked;
}
}
}
readonly property Component colorPicker: Component {
Rectangle {
id: colorPicker
border.color: "black"
border.width: 2
color: root.value.data
height: 32
width: 32
Component.onCompleted: {
if (!root.value.data) {
root.value.data = "red";
}
}
MouseArea {
anchors.fill: parent
onClicked: colorEditorPopup.open(colorPicker)
}
ColorEditorPopup {
id: colorEditorPopup
currentColor: root.value.data
onActivateColor: color => {
root.value.data = color;
}
}
}
}
readonly property Component imageSource: Component {
StudioControls.ComboBox {
id: imageSource
actionIndicatorVisible: false
model: fileModel.model
textRole: "fileName"
valueRole: "relativeFilePath"
onCurrentValueChanged: () => {
root.value.data = `image://qmldesigner_nodegrapheditor/${imageSource.currentValue}`;
}
HelperWidgets.FileResourcesModel {
id: fileModel
filter: "*.png *.gif *.jpg *.bmp *.jpeg *.svg *.pbm *.pgm *.ppm *.xbm *.xpm *.hdr *.ktx *.webp"
modelNodeBackendProperty: modelNodeBackend
}
}
}
readonly property Component materialAlphaMode: Component {
StudioControls.ComboBox {
id: materialAlphaMode
actionIndicatorVisible: false
model: [
{
text: "Default",
value: 0
},
{
text: "Blend",
value: 2
},
{
text: "Opaque",
value: 3
},
{
text: "Mask",
value: 1
},
]
textRole: "text"
valueRole: "value"
onCurrentValueChanged: () => {
root.value.data = materialAlphaMode.currentValue;
}
}
}
readonly property Component materialBlendMode: Component {
StudioControls.ComboBox {
id: materialBlendMode
actionIndicatorVisible: false
model: [
{
text: "SourceOver",
value: 0
},
{
text: "Screen",
value: 1
},
{
text: "Multiply",
value: 2
},
]
textRole: "text"
valueRole: "value"
onCurrentValueChanged: () => {
root.value.data = materialBlendMode.currentValue;
}
}
}
readonly property Component materialChannel: Component {
StudioControls.ComboBox {
id: materialChannel
actionIndicatorVisible: false
model: [
{
text: "R",
value: 0
},
{
text: "G",
value: 1
},
{
text: "B",
value: 2
},
{
text: "A",
value: 3
},
]
textRole: "text"
valueRole: "value"
onCurrentValueChanged: () => {
root.value.data = materialChannel.currentValue;
}
}
}
readonly property Component materialLighting: Component {
StudioControls.ComboBox {
id: materialLighting
actionIndicatorVisible: false
model: [
{
text: "NoLighting",
value: 0
},
{
text: "FragmentLighting",
value: 1
},
]
textRole: "text"
valueRole: "value"
onCurrentValueChanged: () => {
root.value.data = materialLighting.currentValue;
}
}
}
readonly property Component realSpinBox: Component {
StudioControls.RealSpinBox {
id: realSpinBox
actionIndicatorVisible: false
realValue: root.value.data
onRealValueModified: () => {
root.value.data = realSpinBox.realValue;
}
}
}
readonly property Component textureFiltering: Component {
StudioControls.ComboBox {
id: textureFiltering
actionIndicatorVisible: false
model: [
{
text: "None",
value: 0
},
{
text: "Nearest",
value: 1
},
{
text: "Linear",
value: 2
},
]
textRole: "text"
valueRole: "value"
onCurrentValueChanged: () => {
root.value.data = textureFiltering.currentValue;
}
}
}
readonly property Component textureMappingMode: Component {
StudioControls.ComboBox {
id: textureMappingMode
actionIndicatorVisible: false
model: [
{
text: "UV",
value: 0
},
{
text: "Environment",
value: 1
},
{
text: "LightProbe",
value: 2
},
]
textRole: "text"
valueRole: "value"
onCurrentValueChanged: () => {
root.value.data = textureMappingMode.currentValue;
}
}
}
readonly property Component textureTilingMode: Component {
StudioControls.ComboBox {
id: textureTilingMode
actionIndicatorVisible: false
model: [
{
text: "Repeat",
value: 3
},
{
text: "ClampToEdge",
value: 1
},
{
text: "MirroredRepeat",
value: 2
},
]
textRole: "text"
valueRole: "value"
onCurrentValueChanged: () => {
root.value.data = textureTilingMode.currentValue;
}
}
}
}
readonly property QtObject value: QtObject {
property var data: undefined
property var reset: undefined
property string type: "undefined"
}
}

View File

@@ -0,0 +1,23 @@
module NewNodes
BaseGroup 1.0 BaseGroup.qml
BaseNode 1.0 BaseNode.qml
ValueNode 1.0 ValueNode.qml
OutputNode 1.0 OutputNode.qml
InputNode 1.0 InputNode.qml
ProviderNode 1.0 ProviderNode.qml
ColorNode 1.0 ColorNode.qml
MetalnessNode 1.0 MetalnessNode.qml
RoughnessNode 1.0 RoughnessNode.qml
NormalNode 1.0 NormalNode.qml
OcclusionNode 1.0 OcclusionNode.qml
OpacityNode 1.0 OpacityNode.qml
TextureNode 1.0 TextureNode.qml
PrincipledMaterialNode 1.0 PrincipledMaterialNode.qml
MaterialViewerNode 1.0 MaterialViewerNode.qml
singleton Components 1.0 Components.qml