From 6e85b430882b25d119802ba08c154bb9917fa812 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sun, 3 Mar 2024 19:24:49 +0000 Subject: [PATCH] backup before connections everything in shaderEditor now finished only thing left to add is the connections. --- .../gui/shaderEditor/guiShaderEditor.cpp | 536 +++++++++++++++++- .../source/gui/shaderEditor/guiShaderEditor.h | 33 +- .../gui/shaderEditor/nodes/shaderNode.cpp | 13 +- .../gui/shaderEditor/nodes/shaderNode.h | 4 +- 4 files changed, 577 insertions(+), 9 deletions(-) diff --git a/Engine/source/gui/shaderEditor/guiShaderEditor.cpp b/Engine/source/gui/shaderEditor/guiShaderEditor.cpp index 5cb7dc4c5..71ff0b6c6 100644 --- a/Engine/source/gui/shaderEditor/guiShaderEditor.cpp +++ b/Engine/source/gui/shaderEditor/guiShaderEditor.cpp @@ -40,37 +40,142 @@ ConsoleDocClass(GuiShaderEditor, ); GuiShaderEditor::GuiShaderEditor() + : mDragBeginPoint(-1, -1), + mViewOffset(0,0), + mZoomScale(1.0f), + mFullBoxSelection(false), + mDragAddSelection(false), + mDragMoveUndo(false) { + VECTOR_SET_ASSOCIATION(mCurrNodes); + VECTOR_SET_ASSOCIATION(mSelectedNodes); + VECTOR_SET_ASSOCIATION(mDragBeginPoints); + + mActive = true; + mMouseDownMode = GuiShaderEditor::Selecting; + + mTrash = NULL; + mSelectedSet = NULL; } bool GuiShaderEditor::onWake() { - return false; + if (!Parent::onWake()) + return false; + + return true; } void GuiShaderEditor::onSleep() { + Parent::onSleep(); } void GuiShaderEditor::initPersistFields() { + docsURL; + addGroup("Selection"); + addField("fullBoxSelection", TypeBool, Offset(mFullBoxSelection, GuiShaderEditor), + "If true, rectangle selection will only select controls fully inside the drag rectangle."); + endGroup("Selection"); + Parent::initPersistFields(); } bool GuiShaderEditor::onAdd() { - return false; + if (!Parent::onAdd()) + return false; + + mTrash = new SimGroup(); + mSelectedSet = new SimSet(); + + if (!mTrash->registerObject()) + return false; + if (!mSelectedSet->registerObject()) + return false; + + return true; } void GuiShaderEditor::onRemove() { + mTrash->deleteObject(); + mSelectedSet->deleteObject(); + + mTrash = NULL; + mSelectedSet = NULL; } void GuiShaderEditor::onPreRender() { + setUpdate(); +} + +void GuiShaderEditor::renderNodes(Point2I offset, const RectI& updateRect) +{ + // Save the current clip rect + // so we can restore it at the end of this method. + RectI savedClipRect = GFX->getClipRect(); + + // offset is the upper-left corner of this control in screen coordinates + // updateRect is the intersection rectangle in screen coords of the control + // hierarchy. This can be set as the clip rectangle in most cases. + RectI clipRect = updateRect; + + GFXDrawUtil* drawer = GFX->getDrawUtil(); + + for (ShaderNode* node : mCurrNodes) + { + // this is useful for sub node graphs. + if (node->isVisible()) + { + Point2I childPos = offset + node->getPosition(); + RectI childClip(childPos, node->getExtent() + Point2I(1, 1)); + + if (childClip.intersect(clipRect)) + { + GFX->setClipRect(childClip); + GFX->setStateBlock(mDefaultGuiSB); + node->onRender(offset, childClip); + } + + if (selectionContains(node)) + { + GFX->setClipRect(clipRect); + childClip.inset(1, 1); + drawer->drawRect(childClip, ColorI(255, 255, 0, 128)); + } + } + } + + // Restore the clip rect to what it was at the start + // of this method. + GFX->setClipRect(savedClipRect); } void GuiShaderEditor::onRender(Point2I offset, const RectI& updateRect) { + offset += mViewOffset * mZoomScale; + + GFXDrawUtil* drawer = GFX->getDrawUtil(); + + // render our nodes. + renderNodes(offset, updateRect); + + // Draw selection rectangle last so it is rendered on top. + if (mActive && mMouseDownMode == DragSelecting) + { + RectI b; + getDragRect(b); + b.point += offset; + + // Draw outline. + drawer->drawRect(b, ColorI(100, 100, 100, 128)); + + // Draw fill. + b.inset(1, 1); + drawer->drawRectFill(b, ColorI(150, 150, 150, 128)); + } } bool GuiShaderEditor::onKeyDown(const GuiEvent& event) @@ -80,26 +185,449 @@ bool GuiShaderEditor::onKeyDown(const GuiEvent& event) void GuiShaderEditor::onMouseDown(const GuiEvent& event) { + if (!mActive) + { + Parent::onMouseDown(event); + return; + } + + setFirstResponder(); + + // lock mouse + mouseLock(); + + // get mouse pos with our view offset and scale. + mLastMousePos = globalToLocalCoord(event.mousePoint) + mViewOffset * mZoomScale; + + ShaderNode* node = findHitNode(mLastMousePos); + + if (event.modifier & SI_SHIFT) + { + startDragRectangle(mLastMousePos); + mDragAddSelection = true; + } + else if (selectionContains(node)) + { + if (event.modifier & SI_MULTISELECT) + { + removeSelection(node); + setMouseMode(Selecting); + } + else if (event.modifier & SI_PRIMARY_ALT) + { + startDragClone(mLastMousePos); + } + else + { + startDragMove(mLastMousePos); + } + } + else + { + if (node == NULL) + { + startDragRectangle(mLastMousePos); + mDragAddSelection = false; + } + else if (event.modifier & SI_PRIMARY_ALT && node != NULL) + { + // Alt is down. Start a drag clone. + clearSelection(); + addSelection(node); + startDragClone(mLastMousePos); + } + else if (event.modifier & SI_MULTISELECT) + { + addSelection(node); + } + else + { + // Clicked on node. Start move. + clearSelection(); + addSelection(node); + startDragMove(mLastMousePos); + } + } + } void GuiShaderEditor::onMouseUp(const GuiEvent& event) { + if (!mActive) + { + Parent::onMouseUp(event); + return; + } + + ShaderNode* node = findHitNode(mLastMousePos); + + //unlock the mouse + mouseUnlock(); + + // Reset Drag Axis Alignment Information + mDragBeginPoint.set(-1, -1); + mDragBeginPoints.clear(); + + // get mouse pos with our view offset and scale. + mLastMousePos = globalToLocalCoord(event.mousePoint) + mViewOffset * mZoomScale; + + if (mMouseDownMode == DragSelecting) + { + if (!(event.modifier & SI_MULTISELECT) && !mDragAddSelection) + clearSelection(); + + RectI rect; + getDragRect(rect); + + if (rect.extent.x <= 2 && rect.extent.y <= 2) + { + addSelectionAtPoint(rect.point); + } + else + { + Vector< ShaderNode* > hits; + findNodesInRect(rect, hits); + + for (ShaderNode* node : hits) + { + addSelection(node); + } + } + } + + if (mMouseDownMode == MovingSelection && mDragMoveUndo) + { + + } + + //reset the mouse mode + setFirstResponder(); + setMouseMode(Selecting); } -void GuiShaderEditor::onMouseMove(const GuiEvent& event) +void GuiShaderEditor::onMouseDragged(const GuiEvent& event) { + if (!mActive) + { + Parent::onMouseDragged(event); + return; + } + + // get mouse pos with our view offset and scale. + Point2I mousePoint = globalToLocalCoord(event.mousePoint) + mViewOffset * mZoomScale; + + if (mMouseDownMode == DragClone) + { + // If we haven't yet crossed the mouse delta to actually start the + // clone, check if we have now. + + S32 delta = mAbs((mousePoint - mDragBeginPoint).len()); + if (delta >= 4) + { + cloneSelection(); + mLastMousePos = mDragBeginPoint; + mDragMoveUndo = false; + + setMouseMode(MovingSelection); + } + } + + if (mMouseDownMode == MovingSelection && mSelectedNodes.size()) + { + Point2I delta = mousePoint - mLastMousePos; + RectI selBounds = getSelectionBounds(); + + if (delta.x || delta.y) + moveSelection(delta, mDragMoveUndo); + + mLastMousePos += delta; + } + else + mLastMousePos = mousePoint; } void GuiShaderEditor::onMiddleMouseDown(const GuiEvent& event) { + if (!mActive) + { + Parent::onMiddleMouseDown(event); + return; + } + + setFirstResponder(); + + // lock mouse + mouseLock(); + + // get mouse pos with our view offset and scale. + mLastMousePos = globalToLocalCoord(event.mousePoint) + mViewOffset * mZoomScale; + + setMouseMode(DragPanning); + +} + +void GuiShaderEditor::onMiddleMouseUp(const GuiEvent& event) +{ + if (!mActive) + { + Parent::onMiddleMouseUp(event); + return; + } + + //unlock the mouse + mouseUnlock(); + + // Reset Drag Axis Alignment Information + mDragBeginPoint.set(-1, -1); + mDragBeginPoints.clear(); + + // get mouse pos with our view offset and scale. + mLastMousePos = globalToLocalCoord(event.mousePoint) + mViewOffset * mZoomScale; + + setFirstResponder(); + setMouseMode(Selecting); +} + +void GuiShaderEditor::onMiddleMouseDragged(const GuiEvent& event) +{ + if (!mActive) + { + Parent::onMiddleMouseDragged(event); + return; + } + + // get mouse pos with our view offset and scale. + Point2I mousePoint = globalToLocalCoord(event.mousePoint) + mViewOffset * mZoomScale; + + if (mMouseDownMode == DragPanning) + { + Point2I delta = mousePoint - mLastMousePos; + RectI selBounds = getSelectionBounds(); + + // invert it + if (delta.x || delta.y) + mViewOffset += -delta; + + mLastMousePos += delta; + } + else + mLastMousePos = mousePoint; } bool GuiShaderEditor::onMouseWheelUp(const GuiEvent& event) { - return false; + if (!mActive || !mAwake || !mVisible) + return Parent::onMouseWheelUp(event); + + mZoomScale *= 1.1; + + return true; } bool GuiShaderEditor::onMouseWheelDown(const GuiEvent& event) { + if (!mActive || !mAwake || !mVisible) + return Parent::onMouseWheelDown(event); + + mZoomScale *= 0.9; + + return true; +} + +RectI GuiShaderEditor::getSelectionBounds() +{ + + Vector::const_iterator i = mSelectedNodes.begin(); + + Point2I minPos = (*i)->localToGlobalCoord(Point2I(0, 0)) + mViewOffset * mZoomScale; + Point2I maxPos = minPos; + + for (; i != mSelectedNodes.end(); i++) + { + Point2I iPos = (**i).localToGlobalCoord(Point2I(0, 0)) + mViewOffset * mZoomScale; + + minPos.x = getMin(iPos.x, minPos.x); + minPos.y = getMin(iPos.y, minPos.y); + + Point2I iExt = (**i).getExtent(); + + iPos.x += iExt.x; + iPos.y += iExt.y; + + maxPos.x = getMax(iPos.x, maxPos.x); + maxPos.y = getMax(iPos.y, maxPos.y); + } + + minPos = globalToLocalCoord(minPos) + mViewOffset * mZoomScale; + maxPos = globalToLocalCoord(maxPos) + mViewOffset * mZoomScale; + + return RectI(minPos.x, minPos.y, (maxPos.x - minPos.x), (maxPos.y - minPos.y)); +} + +void GuiShaderEditor::deleteSelection() +{ + for (ShaderNode* node : mSelectedNodes) + { + mTrash->addObject(node); + } + + clearSelection(); +} + +void GuiShaderEditor::moveSelection(const Point2I& delta, bool callback) +{ + for (ShaderNode* node : mSelectedNodes) + { + node->setPosition(node->getPosition() + delta); + } +} + +void GuiShaderEditor::clearSelection() +{ + mSelectedNodes.clear(); +} + +void GuiShaderEditor::cloneSelection() +{ + Vector newSelection; + + for (ShaderNode* node : mSelectedNodes) + { + ShaderNode* clone = dynamic_cast(node->deepClone()); + if (clone) + newSelection.push_back(clone); + } + + clearSelection(); + + for (ShaderNode* cloneNode : newSelection) + { + addSelection(cloneNode); + } +} + +void GuiShaderEditor::addSelectionAtPoint(const Point2I& pos) +{ + // turn hit off on already selected nodes. + canHitSelectedNodes(false); + + ShaderNode* node = findHitNode(pos); + + // reset hit status. + canHitSelectedNodes(); + + if (node) + addSelection(node); +} + +void GuiShaderEditor::addSelection(ShaderNode* inNode) +{ + if (inNode != NULL && !selectionContains(inNode)) + { + mSelectedNodes.push_back(inNode); + } +} + +bool GuiShaderEditor::selectionContains(ShaderNode* inNode) +{ + for (ShaderNode* node : mSelectedNodes) + { + if (node == inNode) + return true; + } + return false; } + +void GuiShaderEditor::removeSelection(ShaderNode* inNode) +{ + if (selectionContains(inNode)) + { + Vector< ShaderNode* >::iterator i = T3D::find(mSelectedNodes.begin(), mSelectedNodes.end(), inNode); + if (i != mSelectedNodes.end()) + mSelectedNodes.erase(i); + } +} + +void GuiShaderEditor::canHitSelectedNodes(bool state) +{ + for (ShaderNode* node : mSelectedNodes) + node->setCanHit(state); +} + +//----------------------------------------------------------------------------- +// Input handling +//----------------------------------------------------------------------------- + +ShaderNode* GuiShaderEditor::findHitNode(const Point2I& pt) +{ + for (ShaderNode* node : mCurrNodes) + { + if (node->pointInControl(pt)) + { + return node; + } + } + + return nullptr; +} + +void GuiShaderEditor::findNodesInRect(const RectI& rect, Vector& outResult) +{ + canHitSelectedNodes(false); + for (ShaderNode* node : mCurrNodes) + { + if (node->getBounds().overlaps(rect)) + { + outResult.push_back(node); + } + } + + canHitSelectedNodes(); +} + +void GuiShaderEditor::getDragRect(RectI& box) +{ + box.point.x = getMin(mLastMousePos.x, mSelectionAnchor.x); + box.extent.x = getMax(mLastMousePos.x, mSelectionAnchor.x) - box.point.x + 1; + box.point.y = getMin(mLastMousePos.y, mSelectionAnchor.y); + box.extent.y = getMax(mLastMousePos.y, mSelectionAnchor.y) - box.point.y + 1; +} + +void GuiShaderEditor::startDragMove(const Point2I& startPoint) +{ + mDragMoveUndo = true; + + mDragBeginPoint = startPoint; + + mDragBeginPoints.reserve(mSelectedNodes.size()); + + for (ShaderNode* node : mSelectedNodes) + { + mDragBeginPoints.push_back(node->getPosition()); + } + + setMouseMode(MovingSelection); + +} + +void GuiShaderEditor::startDragRectangle(const Point2I& startPoint) +{ + mSelectionAnchor = startPoint; + setMouseMode(DragSelecting); +} + +void GuiShaderEditor::startDragClone(const Point2I& startPoint) +{ + mDragBeginPoint = startPoint; + setMouseMode(DragClone); +} + +void GuiShaderEditor::setMouseMode(mouseModes mode) +{ + if (mMouseDownMode != mode) + { + mMouseDownMode = mode; + } +} + diff --git a/Engine/source/gui/shaderEditor/guiShaderEditor.h b/Engine/source/gui/shaderEditor/guiShaderEditor.h index 3d0773f62..efed5659a 100644 --- a/Engine/source/gui/shaderEditor/guiShaderEditor.h +++ b/Engine/source/gui/shaderEditor/guiShaderEditor.h @@ -43,7 +43,7 @@ public: typedef GuiControl Parent; - enum mouseModes { Selecting, MovingSelection, DragConnection, DragSelecting, DragClone }; + enum mouseModes { Selecting, MovingSelection, DragPanning, DragConnection, DragSelecting, DragClone }; protected: @@ -56,6 +56,9 @@ protected: SimGroup* mTrash; SimSet* mSelectedSet; + // view controls + Point2I mViewOffset; + F32 mZoomScale; // mouse interaction mouseModes mMouseDownMode; Point2I mLastMousePos; @@ -65,8 +68,21 @@ protected: Vector mDragBeginPoints; bool mDragAddSelection; bool mDragMoveUndo; + bool mFullBoxSelection; ShaderNodeVector mSelectedNodes; + void renderNodes(Point2I offset, const RectI& updateRect); + + // functions for handling mouse events. + ShaderNode* findHitNode(const Point2I& pt); + void findNodesInRect(const RectI& rect, Vector& outResult); + + void getDragRect(RectI& box); + void startDragMove(const Point2I& startPoint); + void startDragRectangle(const Point2I& startPoint); + void startDragClone(const Point2I& startPoint); + void setMouseMode(mouseModes mode); + public: GuiShaderEditor(); @@ -87,10 +103,23 @@ public: virtual bool onKeyDown(const GuiEvent& event) override; virtual void onMouseDown(const GuiEvent& event) override; virtual void onMouseUp(const GuiEvent& event) override; - virtual void onMouseMove(const GuiEvent& event) override; + virtual void onMouseDragged(const GuiEvent& event) override; virtual void onMiddleMouseDown(const GuiEvent& event) override; + virtual void onMiddleMouseUp(const GuiEvent& event) override; + virtual void onMiddleMouseDragged(const GuiEvent& event) override; virtual bool onMouseWheelUp(const GuiEvent& event) override; virtual bool onMouseWheelDown(const GuiEvent& event) override; + + RectI getSelectionBounds(); + void deleteSelection(); + void moveSelection(const Point2I& delta, bool callback = true); + void clearSelection(); + void cloneSelection(); + void addSelectionAtPoint(const Point2I& pos); + void addSelection(ShaderNode* inNode); + bool selectionContains(ShaderNode* inNode); + void removeSelection(ShaderNode* inNode); + void canHitSelectedNodes(bool state = true); }; #endif _GUISHADEREDITOR_H_ diff --git a/Engine/source/gui/shaderEditor/nodes/shaderNode.cpp b/Engine/source/gui/shaderEditor/nodes/shaderNode.cpp index c14561ada..8b48d40bc 100644 --- a/Engine/source/gui/shaderEditor/nodes/shaderNode.cpp +++ b/Engine/source/gui/shaderEditor/nodes/shaderNode.cpp @@ -39,20 +39,29 @@ ShaderNode::ShaderNode() bool ShaderNode::onWake() { - return false; + if (!Parent::onWake()) + return false; + + return true; } void ShaderNode::onSleep() { + Parent::onSleep(); } void ShaderNode::initPersistFields() { + docsURL; + Parent::initPersistFields(); } bool ShaderNode::onAdd() { - return false; + if (!Parent::onAdd()) + return false; + + return true; } void ShaderNode::onRemove() diff --git a/Engine/source/gui/shaderEditor/nodes/shaderNode.h b/Engine/source/gui/shaderEditor/nodes/shaderNode.h index 7f01865f5..a5bb46937 100644 --- a/Engine/source/gui/shaderEditor/nodes/shaderNode.h +++ b/Engine/source/gui/shaderEditor/nodes/shaderNode.h @@ -38,11 +38,13 @@ enum class NodeTypes Output, TextureSampler, MathOperation, - Procedural + Procedural, + Generator }; enum class DataDimensions { + Dynamic, // can be any dimension, usually defined by what was connected to it. Scalar, Vector2, Vector3,