Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// Created by blues on 2026/3/10.
//

#pragma once

#include <framework/asset/AssetManager.h>
#include <shader/shadergraph/ShaderGraph.h>

namespace sky {
class JsonInputArchive;
class JsonOutputArchive;

struct ShaderGraphAssetData {
uint32_t version = 1;
sg::ShaderGraph graph;

void LoadJson(JsonInputArchive& archive);
void SaveJson(JsonOutputArchive& archive) const;
};

// Placeholder type tag for the shader graph asset
struct ShaderGraphAssetTag {};

template <>
struct AssetTraits<ShaderGraphAssetTag> {
using DataType = ShaderGraphAssetData;
static constexpr std::string_view ASSET_TYPE = "ShaderGraph";
static constexpr SerializeType SERIALIZE_TYPE = SerializeType::JSON;
};

} // namespace sky
28 changes: 28 additions & 0 deletions engine/render/adaptor/src/assets/ShaderGraphAsset.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Created by blues on 2026/3/10.
//

#include <render/adaptor/assets/ShaderGraphAsset.h>
#include <framework/serialization/JsonArchive.h>

namespace sky {

void ShaderGraphAssetData::LoadJson(JsonInputArchive& archive)
{
archive.LoadKeyValue("Version", version);
if (archive.Start("Graph")) {
graph.LoadJson(archive);
archive.End();
}
}

void ShaderGraphAssetData::SaveJson(JsonOutputArchive& archive) const
{
archive.StartObject();
archive.SaveValueObject("Version", version);
archive.Key("Graph");
graph.SaveJson(archive);
archive.EndObject();
}

} // namespace sky
21 changes: 21 additions & 0 deletions engine/render/editor/include/render/editor/ShaderGraphCreator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// Created by blues on 2026/3/10.
//

#pragma once

#include <editor/framework/AssetCreator.h>

namespace sky::editor {

class ShaderGraphCreator : public AssetCreatorBase {
public:
ShaderGraphCreator() = default;
~ShaderGraphCreator() override = default;

private:
void CreateAsset(const FilePath& path) override;
std::string GetExtension() const override { return ".shadergraph"; }
};

} // namespace sky::editor
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Created by blues on 2026/3/10.
//

#pragma once

#include <editor/framework/AssetBrowserWidget.h>

namespace sky::editor {

class ShaderGraphEditWindow : public IAssetPreviewWndFactory {
public:
ShaderGraphEditWindow() = default;
~ShaderGraphEditWindow() override = default;

bool SetupWidget(AssetPreviewWidget& widget, const AssetSourcePtr& src) override;
};

} // namespace sky::editor
5 changes: 5 additions & 0 deletions engine/render/editor/src/RenderEditorModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
#include <render/editor/animation/SkeletonPreviewWindow.h>
#include <render/editor/MaterialCreator.h>
#include <render/editor/AnimationCreator.h>
#include <render/editor/ShaderGraphCreator.h>
#include <render/editor/animation/GraphEditWindow.h>
#include <render/editor/shadergraph/ShaderGraphEditWindow.h>

#include <editor/framework/AssetBrowserWidget.h>
#include <editor/framework/AssetCreator.h>

#include <render/adaptor/assets/SkeletonAsset.h>
#include <render/adaptor/assets/AnimationAsset.h>
#include <render/adaptor/assets/ShaderGraphAsset.h>


namespace sky::editor {
Expand All @@ -26,13 +29,15 @@ namespace sky::editor {
// asset
AssetCreatorManager::Get()->RegisterTool(Name("Material"), new MaterialInstanceCreator());
AssetCreatorManager::Get()->RegisterTool(Name("Animation Graph"), new AnimationGraphCreator());
AssetCreatorManager::Get()->RegisterTool(Name("Shader Graph"), new ShaderGraphCreator());

// create
RegisterActorCreators<RenderCubeActorCreator>(BuiltinGeometryType::CUBE);

// preview
AssetPreviewManager::Get()->Register(AssetTraits<Skeleton>::ASSET_TYPE, new SkeletonPreviewWindow());
AssetPreviewManager::Get()->Register(AssetTraits<Animation>::ASSET_TYPE, new GraphEditWindow());
AssetPreviewManager::Get()->Register(AssetTraits<ShaderGraphAssetTag>::ASSET_TYPE, new ShaderGraphEditWindow());
return true;
}

Expand Down
30 changes: 30 additions & 0 deletions engine/render/editor/src/ShaderGraphCreator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// Created by blues on 2026/3/10.
//

#include <render/editor/ShaderGraphCreator.h>
#include <render/adaptor/assets/ShaderGraphAsset.h>
#include <framework/asset/AssetDataBase.h>
#include <framework/serialization/JsonArchive.h>

namespace sky::editor {

void ShaderGraphCreator::CreateAsset(const FilePath& path)
{
AssetSourcePath sourcePath = {};
sourcePath.bundle = SourceAssetBundle::WORKSPACE;
sourcePath.path = path;

auto file = AssetDataBase::Get()->CreateOrOpenFile(sourcePath);

ShaderGraphAssetData data = {};
data.version = 1;

auto archive = file->WriteAsArchive();
JsonOutputArchive json(*archive);
data.SaveJson(json);

AssetDataBase::Get()->RegisterAsset(sourcePath);
}

} // namespace sky::editor
22 changes: 22 additions & 0 deletions engine/render/editor/src/shadergraph/ShaderGraphEditWindow.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// Created by blues on 2026/3/10.
//

#include <render/editor/shadergraph/ShaderGraphEditWindow.h>
#include "ShaderGraphWidget.h"

#include <framework/asset/AssetDataBase.h>

namespace sky::editor {

bool ShaderGraphEditWindow::SetupWidget(AssetPreviewWidget& widget, const AssetSourcePtr& src)
{
auto file = AssetDataBase::Get()->OpenFile(src);
if (file) {
widget.SetWidget(new ShaderGraphWidget(file));
return true;
}
return false;
}

} // namespace sky::editor
201 changes: 201 additions & 0 deletions engine/render/editor/src/shadergraph/ShaderGraphNodeModel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
//
// Created by blues on 2026/3/10.
//

#include "ShaderGraphNodeModel.h"
#include <shader/shadergraph/ShaderGraphMathNodes.h>
#include <shader/shadergraph/ShaderGraphInputNodes.h>
#include <shader/shadergraph/ShaderGraphOutputNode.h>
#include <QVBoxLayout>
#include <QLabel>
#include <algorithm>

namespace sky::editor {

// ---- SGNodeModel ----

SGNodeModel::SGNodeModel(sg::SGNodePtr n) : node(std::move(n))
{
}

QString SGNodeModel::caption() const
{
return QString::fromStdString(node->GetDisplayName());
}

QString SGNodeModel::name() const
{
return QString::fromStdString(node->GetTypeName());
}

unsigned int SGNodeModel::nPorts(QtNodes::PortType portType) const
{
if (portType == QtNodes::PortType::In) {
return static_cast<unsigned int>(node->GetInputPins().size());
}
return static_cast<unsigned int>(node->GetOutputPins().size());
}

QtNodes::NodeDataType SGNodeModel::dataType(QtNodes::PortType portType,
QtNodes::PortIndex portIndex) const
{
const auto* pins = (portType == QtNodes::PortType::In)
? &node->GetInputPins()
: &node->GetOutputPins();

if (portIndex < static_cast<int>(pins->size())) {
const auto& pin = (*pins)[portIndex];
return {sg::SGDataTypeToString(pin.type).c_str(),
pin.name.c_str()};
}
return {"float", "Value"};
}

std::shared_ptr<QtNodes::NodeData> SGNodeModel::outData(QtNodes::PortIndex port)
{
const auto& outPins = node->GetOutputPins();
if (port < static_cast<int>(outPins.size())) {
return std::make_shared<SGNodeData>(outPins[port].type);
}
return nullptr;
}

void SGNodeModel::setInData(std::shared_ptr<QtNodes::NodeData> /*data*/,
QtNodes::PortIndex /*portIndex*/)
{
// Data flow is handled at graph level; nothing to update here
}

// ---- SGConstantFloatNodeModel ----

SGConstantFloatNodeModel::SGConstantFloatNodeModel()
: SGNodeModel(std::make_shared<sg::SGConstantFloatNode>())
{
}

QWidget* SGConstantFloatNodeModel::embeddedWidget()
{
if (!spinBox) {
spinBox = new QDoubleSpinBox();
spinBox->setRange(-1e6, 1e6);
spinBox->setDecimals(4);
spinBox->setValue(0.0);
spinBox->setFixedWidth(100);

connect(spinBox, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
this, [this](double v) {
auto* n = static_cast<sg::SGConstantFloatNode*>(node.get());
n->SetValue(static_cast<float>(v));
emit OnValueChanged(v);
});
}
return spinBox;
}

// ---- SGConstantVec3NodeModel ----

SGConstantVec3NodeModel::SGConstantVec3NodeModel()
: SGNodeModel(std::make_shared<sg::SGConstantVec3Node>())
{
}

QWidget* SGConstantVec3NodeModel::embeddedWidget()
{
if (!container) {
container = new QWidget();
auto* layout = new QVBoxLayout(container);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(2);

spinX = new QDoubleSpinBox();
spinY = new QDoubleSpinBox();
spinZ = new QDoubleSpinBox();

for (auto* spin : {spinX, spinY, spinZ}) {
spin->setRange(-1e6, 1e6);
spin->setDecimals(4);
spin->setValue(0.0);
spin->setFixedWidth(100);
layout->addWidget(spin);
}

auto updateNode = [this]() {
auto* n = static_cast<sg::SGConstantVec3Node*>(node.get());
n->SetValue(static_cast<float>(spinX->value()),
static_cast<float>(spinY->value()),
static_cast<float>(spinZ->value()));
};

connect(spinX, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
this, [updateNode](double) { updateNode(); });
connect(spinY, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
this, [updateNode](double) { updateNode(); });
connect(spinZ, static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged),
this, [updateNode](double) { updateNode(); });

container->setLayout(layout);
}
return container;
}

// ---- SGScalarParamNodeModel ----

SGScalarParamNodeModel::SGScalarParamNodeModel()
: SGNodeModel(std::make_shared<sg::SGScalarParamNode>())
{
}

QWidget* SGScalarParamNodeModel::embeddedWidget()
{
if (!nameEdit) {
nameEdit = new QLineEdit("Param");
nameEdit->setFixedWidth(100);
connect(nameEdit, &QLineEdit::textChanged, this, [this](const QString& text) {
auto* n = static_cast<sg::SGScalarParamNode*>(node.get());
n->SetParamName(text.toStdString());
});
}
return nameEdit;
}

// ---- SGVectorParamNodeModel ----

SGVectorParamNodeModel::SGVectorParamNodeModel()
: SGNodeModel(std::make_shared<sg::SGVectorParamNode>())
{
}

QWidget* SGVectorParamNodeModel::embeddedWidget()
{
if (!nameEdit) {
nameEdit = new QLineEdit("VecParam");
nameEdit->setFixedWidth(100);
connect(nameEdit, &QLineEdit::textChanged, this, [this](const QString& text) {
auto* n = static_cast<sg::SGVectorParamNode*>(node.get());
n->SetParamName(text.toStdString());
});
}
return nameEdit;
}

// ---- SGTextureParamNodeModel ----

SGTextureParamNodeModel::SGTextureParamNodeModel()
: SGNodeModel(std::make_shared<sg::SGTextureParamNode>())
{
}

QWidget* SGTextureParamNodeModel::embeddedWidget()
{
if (!nameEdit) {
nameEdit = new QLineEdit("Texture");
nameEdit->setFixedWidth(100);
connect(nameEdit, &QLineEdit::textChanged, this, [this](const QString& text) {
auto* n = static_cast<sg::SGTextureParamNode*>(node.get());
n->SetParamName(text.toStdString());
});
}
return nameEdit;
}

} // namespace sky::editor
Loading