├── .gitignore ├── .gitmodules ├── README.md ├── gplay-editor.pro └── src ├── GplayDevice.cpp ├── GplayDevice.h ├── GraphView.cpp ├── GraphView.h ├── MainWindow.cpp ├── MainWindow.h ├── benchmark.h ├── gp3d ├── GPRenderer.cpp ├── GPRenderer.h ├── PlatformQt.cpp ├── PlatformQt.h ├── QtImGui.cpp ├── QtImGui.h └── helpers │ ├── Events.h │ ├── FirstPersonCamera.cpp │ ├── FirstPersonCamera.h │ ├── Grid.cpp │ └── Grid.h ├── main.cpp └── node-editor ├── common ├── BaseNode.cpp ├── BaseNode.h ├── Color.cpp ├── Color.h ├── CommentGraphicsItem.cpp ├── CommentGraphicsItem.h ├── CustomFlowScene.cpp ├── CustomFlowScene.h ├── CustomWidgets.cpp ├── CustomWidgets.h ├── Nodestyle.h ├── ParamWidget.cpp ├── ParamWidget.h ├── Parameter.cpp ├── Parameter.h ├── Path.cpp ├── Path.h ├── TrackEdit.cpp ├── Trackedit.h ├── Types.cpp └── Types.h └── spark-nodes ├── SparkNodeRender.cpp ├── SparkNodeRender.h ├── SparkNodesRegistry.cpp ├── SparkNodesRegistry.h ├── SpkEmitters.cpp ├── SpkEmitters.h ├── SpkInterpolators.cpp ├── SpkInterpolators.h ├── SpkModifiers.cpp ├── SpkModifiers.h ├── SpkSystem.cpp ├── SpkSystem.h ├── SpkUtils.cpp ├── SpkUtils.h ├── SpkZones.cpp ├── SpkZones.h └── spark-nodes.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.pro.user -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "3rdparty/nodeeditor"] 2 | path = 3rdparty/nodeeditor 3 | url = https://github.com/fredakilla/nodeeditor.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gplay-editor 2 | gplay-editor is a game editor for [**GPlayEngine**](https://github.com/fredakilla/GPlayEngine) 3 | 4 | It extends the internal in-game editor of GPlayengine, based on Imgui, with an additionnal GUI using Qt to enjoy advanced widgets and other Qt features. 5 | 6 | A node editor is integrated and can easily be extended to create any kind of content based on a nodal generation (particles, material, shaders, texture, etc ...) 7 | 8 | Currently a particle generator for the spark particle engine is fully integrated and can be used to create and export particles effects for games using the SPARK particle library. 9 | 10 | 11 | 12 | ## Screenshots 13 | 14 | 15 | ## Current status 16 | gplay-editor is in developpement and is not yet fully functional. 17 | Development is done on linux. 18 | Building on another system is not currently supported however final release should be cross-platform. 19 | 20 | 21 | ## Features 22 | - C++ and Qt based interface. 23 | - gplay-editor internally use [**GPlayEngine**](https://github.com/fredakilla/GPlayEngine) for rendering particles and bind the SPARK particle engine. 24 | - node core system is provided by the external qt [**nodeeditor**](https://github.com/paceholder/nodeeditor) library. 25 | 26 | TODO 27 | - [x] implement genric nodes classes 28 | - [x] automatic node's parameters widgets creation from simple declaration 29 | - [x] show 3D debug zones geometries 30 | - [x] serialize node widget's parameters 31 | - [ ] ~~add +,- buttons to add/remove dynamic inputs on some nodes using lists (emitters, groups)~~ 32 | - [x] graph plot editor widget for spark graph interpolators (WIP but maybe do this using imgui) 33 | - [ ] complete all spark nodes (95% done) 34 | - [x] interact with 3D view (camera move...) + use the in-game editor 35 | - [ ] multiple scenes managment 36 | - [ ] possibility to attach result effect to scene nodes (static node, node in motion, trow bullet, ...) 37 | - [ ] ~~add pliable parameters button to show/hide parameters widgets~~ 38 | - [x] comments items on node view 39 | - [ ] set styles 40 | - [ ] add shortcuts on node view : copy/paste nodes, repeat last created node,... 41 | 42 | ## Build 43 | 44 | gplay-editor developpement is done with Qt 5.11.1 + QtCharts module for tgraph plot editor widget. 45 | 46 | WARNING : Do not use Qt 5.11.2, I experienced some bugs with FileDialogs on linux... 47 | 48 | 49 | ##### 1. Place the gplay-editor directory at same top level of gplay-engine : 50 | (build gplay-engine using GP_CUSTOM_PLATFORM define) 51 | ```bash 52 | ├── YourDirectory 53 | │ ├── GPlayEngine 54 | │ ├── gplay-editor 55 | ``` 56 | 57 | ##### 2. Get submodules 58 | ``` 59 | git submodule init 60 | git submodule update 61 | ``` 62 | 63 | ##### 3. Build the external nodeeditor Qt library 64 | ``` 65 | cd 3rdparty/nodeeditor 66 | mkdir BUILD 67 | cd BUILD 68 | make 69 | ``` 70 | 71 | ##### 4. Build editor 72 | ``` 73 | - Open gplay-editor.pro with QtCreator. 74 | - Build and Run. 75 | ``` -------------------------------------------------------------------------------- /gplay-editor.pro: -------------------------------------------------------------------------------- 1 | #-------------------------------------------------------------------- 2 | # path to gplay engine 3 | #-------------------------------------------------------------------- 4 | PRE_TARGETDEPS += $$PWD/../GPlayEngine/setup.pri 5 | include($$PWD/../GPlayEngine/setup.pri) 6 | 7 | #-------------------------------------------------------------------- 8 | # project 9 | #-------------------------------------------------------------------- 10 | QT += core gui widgets charts 11 | TARGET = gplay-editor 12 | TEMPLATE = app 13 | CONFIG += c++14 14 | CONFIG -= console 15 | CONFIG += windows 16 | CONFIG += no_keywords 17 | 18 | DESTDIR = $$GPLAY_OUTPUT_DIR/bin 19 | QMAKE_CLEAN += $$DESTDIR/$$TARGET 20 | 21 | CONFIG(debug, debug|release): 22 | DEFINES += _DEBUG QT_NO_KEYWORDS 23 | #DEFINES += GP_USE_MEM_LEAK_DETECTION 24 | 25 | INCLUDEPATH += $$GPLAY_OUTPUT_DIR/include/gplayengine/ 26 | INCLUDEPATH += $$GPLAY_OUTPUT_DIR/include/gplayengine/thirdparty 27 | 28 | # nodes editor library 29 | # build nodeeditor with : cmake .. -DCMAKE_PREFIX_PATH=/opt/Qt5.11.1/5.11.1/gcc_64 -DBUILD_TESTING=OFF -DBUILD_EXAMPLES=OFF 30 | DEFINES += NODE_EDITOR_STATIC 31 | INCLUDEPATH += 3rdparty/nodeeditor/include 32 | LIBS += -L$$PWD/3rdparty/nodeeditor/BUILD/lib -lnodes 33 | 34 | #-------------------------------------------------------------------- 35 | # platform specific 36 | #-------------------------------------------------------------------- 37 | linux: { 38 | QT += x11extras 39 | DEFINES += __linux__ 40 | PRE_TARGETDEPS += $$GPLAY_OUTPUT_DIR/lib/libgplay-deps.a 41 | PRE_TARGETDEPS += $$GPLAY_OUTPUT_DIR/lib/libgplay.a 42 | LIBS += -L$$GPLAY_OUTPUT_DIR/lib/ -lgplay 43 | LIBS += -L$$GPLAY_OUTPUT_DIR/lib/thirdparty/ -lgplay-deps 44 | LIBS += -lm -lGL -lrt -ldl -lX11 -lpthread -lsndio 45 | QMAKE_CXXFLAGS += -Wno-unused-parameter 46 | } 47 | 48 | # force qmake 49 | #qmakeforce.target = dummy 50 | #qmakeforce.commands = rm -f Makefile ##to force rerun of qmake 51 | #qmakeforce.depends = FORCE 52 | #PRE_TARGETDEPS += $$qmakeforce.target 53 | #QMAKE_EXTRA_TARGETS += qmakeforce 54 | 55 | 56 | 57 | #-------------------------------------------------------------------- 58 | # files 59 | #-------------------------------------------------------------------- 60 | SOURCES += \ 61 | src/node-editor/common/BaseNode.cpp \ 62 | src/node-editor/common/Color.cpp \ 63 | src/node-editor/common/CommentGraphicsItem.cpp \ 64 | src/node-editor/common/CustomFlowScene.cpp \ 65 | src/node-editor/common/CustomWidgets.cpp \ 66 | src/node-editor/common/Parameter.cpp \ 67 | src/node-editor/common/ParamWidget.cpp \ 68 | src/node-editor/common/Path.cpp \ 69 | src/node-editor/common/TrackEdit.cpp \ 70 | src/node-editor/common/Types.cpp \ 71 | src/node-editor/spark-nodes/SpkEmitters.cpp \ 72 | src/node-editor/spark-nodes/SpkInterpolators.cpp \ 73 | src/node-editor/spark-nodes/SpkModifiers.cpp \ 74 | src/node-editor/spark-nodes/SpkSystem.cpp \ 75 | src/node-editor/spark-nodes/SpkZones.cpp \ 76 | src/node-editor/spark-nodes/SparkNodesRegistry.cpp \ 77 | src/GraphView.cpp \ 78 | src/main.cpp \ 79 | src/MainWindow.cpp \ 80 | src/gp3d/helpers/FirstPersonCamera.cpp \ 81 | src/gp3d/helpers/Grid.cpp \ 82 | src/gp3d/GPRenderer.cpp \ 83 | src/gp3d/PlatformQt.cpp \ 84 | src/gp3d/QtImGui.cpp \ 85 | src/GplayDevice.cpp \ 86 | src/node-editor/spark-nodes/SpkUtils.cpp \ 87 | src/node-editor/spark-nodes/SparkNodeRender.cpp 88 | 89 | HEADERS += \ 90 | src/node-editor/common/BaseNode.h \ 91 | src/node-editor/common/Color.h \ 92 | src/node-editor/common/CommentGraphicsItem.h \ 93 | src/node-editor/common/CustomFlowScene.h \ 94 | src/node-editor/common/CustomWidgets.h \ 95 | src/node-editor/common/Nodestyle.h \ 96 | src/node-editor/common/Parameter.h \ 97 | src/node-editor/common/ParamWidget.h \ 98 | src/node-editor/common/Path.h \ 99 | src/node-editor/common/Trackedit.h \ 100 | src/node-editor/common/Types.h \ 101 | src/node-editor/spark-nodes/SpkEmitters.h \ 102 | src/node-editor/spark-nodes/SpkInterpolators.h \ 103 | src/node-editor/spark-nodes/SpkModifiers.h \ 104 | src/node-editor/spark-nodes/SpkSystem.h \ 105 | src/node-editor/spark-nodes/SpkZones.h \ 106 | src/node-editor/spark-nodes/SparkNodesRegistry.h \ 107 | src/benchmark.h \ 108 | src/GraphView.h \ 109 | src/MainWindow.h \ 110 | src/node-editor/spark-nodes/spark-nodes.h \ 111 | src/gp3d/helpers/FirstPersonCamera.h \ 112 | src/gp3d/helpers/Grid.h \ 113 | src/gp3d/helpers/Events.h \ 114 | src/gp3d/GPRenderer.h \ 115 | src/gp3d/QtImGui.h \ 116 | src/gp3d/PlatformQt.h \ 117 | src/GplayDevice.h \ 118 | src/node-editor/spark-nodes/SpkUtils.h \ 119 | src/node-editor/spark-nodes/SparkNodeRender.h 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /src/GplayDevice.cpp: -------------------------------------------------------------------------------- 1 | #include "GplayDevice.h" 2 | #include "node-editor/common/BaseNode.h" 3 | #include "gp3d/QtImGui.h" 4 | #include "gp3d/helpers/Events.h" 5 | #include "node-editor/spark-nodes/SparkNodeRender.h" 6 | #include "gp3d/GPRenderer.h" 7 | 8 | ISubRenderer* _curentSubRenderer; 9 | 10 | 11 | GplayDeviceGame::GplayDeviceGame() : 12 | _platform(nullptr) 13 | { 14 | 15 | } 16 | 17 | GplayDeviceGame::~GplayDeviceGame() 18 | { 19 | 20 | } 21 | 22 | void GplayDeviceGame::createRenderWindow(void* hwnd) 23 | { 24 | _platform = gplay::Platform::create(this, hwnd); 25 | GP_ASSERT(_platform); 26 | _platform->start(); 27 | 28 | // create default view 29 | View::create(0, Rectangle(200, 200), View::ClearFlags::COLOR_DEPTH, 0x556677ff, 1.0f, 0); 30 | 31 | 32 | SparkNodeRender* spkRenderer = new SparkNodeRender(); 33 | _curentSubRenderer = spkRenderer; 34 | } 35 | 36 | void GplayDeviceGame::runFrame() 37 | { 38 | // begin frame 39 | Renderer::getInstance().beginFrame(); 40 | QtImGui::newFrame(); 41 | 42 | // call gplay frame that will invoke update and render methods. 43 | frame(); 44 | 45 | // end frame 46 | //ImGui::Render(); 47 | QtImGui::endFrame(); 48 | Renderer::getInstance().endFrame(); 49 | } 50 | 51 | void GplayDeviceGame::stop() 52 | { 53 | _platform->stop(); 54 | } 55 | 56 | void GplayDeviceGame::keyEvent(Keyboard::KeyEvent evt, int key) 57 | { 58 | // send key event 59 | std::shared_ptr keyEvent = KeyEvent::create(); 60 | keyEvent.get()->event = evt; 61 | keyEvent.get()->key = key; 62 | EventManager::getInstance()->queueEvent(keyEvent); 63 | } 64 | 65 | bool GplayDeviceGame::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta) 66 | { 67 | // when right button is pressed set on mouse captured to interact with fps camera 68 | if(evt == Mouse::MOUSE_PRESS_RIGHT_BUTTON) 69 | setMouseCaptured(true); 70 | else if(evt == Mouse::MOUSE_RELEASE_RIGHT_BUTTON) 71 | setMouseCaptured(false); 72 | 73 | // send mouse event 74 | std::shared_ptr mouseEvent = MouseEvent::create(); 75 | mouseEvent.get()->event = evt; 76 | mouseEvent.get()->mousePos = Vector2(x, y); 77 | EventManager::getInstance()->queueEvent(mouseEvent); 78 | 79 | return true; 80 | } 81 | 82 | void GplayDeviceGame::resizeRenderView(int width, int height) 83 | { 84 | // resize game engine window 85 | _platform->setWindowSize(width, height); 86 | 87 | // resize default view 88 | View::getView(0)->setViewRect(Rectangle(width, height)); 89 | 90 | // resize current renderer 91 | _curentSubRenderer->resize(width, height); 92 | } 93 | 94 | void GplayDeviceGame::initialize() 95 | { 96 | 97 | } 98 | 99 | void GplayDeviceGame::finalize() 100 | { 101 | 102 | } 103 | 104 | void GplayDeviceGame::update(float elapsedTime) 105 | { 106 | _curentSubRenderer->update(elapsedTime); 107 | } 108 | 109 | void GplayDeviceGame::render(float elapsedTime) 110 | { 111 | bgfx::touch(0); 112 | _curentSubRenderer->render(elapsedTime); 113 | } 114 | 115 | void GplayDeviceGame::setCurentParticleSystem(SPK::Ref sparkSystem) 116 | { 117 | SparkNodeRender* _spkRenderer = dynamic_cast(_curentSubRenderer); 118 | if(_spkRenderer) 119 | _spkRenderer->setCurentParticleSystem(sparkSystem); 120 | } 121 | -------------------------------------------------------------------------------- /src/GplayDevice.h: -------------------------------------------------------------------------------- 1 | #ifndef GPDEVICE_H 2 | #define GPDEVICE_H 3 | 4 | #include 5 | #include 6 | 7 | using namespace gplay; 8 | 9 | class GplayDeviceGame : public Game 10 | { 11 | public: 12 | 13 | GplayDeviceGame(); 14 | ~GplayDeviceGame(); 15 | 16 | void createRenderWindow(void* hwnd); 17 | void runFrame(); 18 | void stop(); 19 | void resizeRenderView(int width, int height); 20 | void setCurentParticleSystem(SPK::Ref sparkSystem); 21 | 22 | private: 23 | void initialize() override; 24 | void finalize() override; 25 | void update(float elapsedTime) override; 26 | void render(float elapsedTime) override; 27 | 28 | void keyEvent(Keyboard::KeyEvent evt, int key) override; 29 | bool mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta) override; 30 | 31 | // bool drawScene(gplay::Node* node); 32 | // bool updateEmitters(gplay::Node* node, float elapsedTime); 33 | 34 | private: 35 | Platform* _platform; 36 | //Scene* _scene; 37 | //bool _isShowDebug; // show debug shapes in effects 38 | }; 39 | 40 | typedef Singleton GplayDevice; 41 | 42 | #endif // GPDEVICE_H 43 | -------------------------------------------------------------------------------- /src/GraphView.cpp: -------------------------------------------------------------------------------- 1 | #include "GraphView.h" 2 | #include 3 | #include 4 | #include 5 | 6 | QT_CHARTS_USE_NAMESPACE 7 | 8 | GraphView::GraphView(QWidget *parent) 9 | : QChartView(new QChart(), parent), 10 | m_scatter(nullptr), 11 | m_lines(nullptr), 12 | m_mouseCoordX(nullptr), 13 | m_mouseCoordY(nullptr) 14 | { 15 | setRenderHint(QPainter::Antialiasing); 16 | setInteractive(true); 17 | //setRubberBand(RectangleRubberBand); 18 | 19 | m_zoomFactorX = 1.0f; 20 | m_zoomFactorY = 1.0f; 21 | 22 | _isPointSelected = false; 23 | _isClicked = false; 24 | _splineResolution = 250.0f; 25 | 26 | chart()->setTitle("Path Editor"); 27 | 28 | // create line serie for drawing curve 29 | m_lines = new QLineSeries(); 30 | m_lines->setName("path"); 31 | m_lines->setColor(Qt::red); 32 | QPen pen(Qt::red); 33 | pen.setWidth(2); 34 | m_lines->setPen(pen); 35 | 36 | // create scatter serie for drawing key points on curve 37 | m_scatter = new QScatterSeries(); 38 | m_scatter->setName("keys"); 39 | m_scatter->setColor(Qt::red); 40 | m_scatter->setMarkerSize(10.0); 41 | m_scatter->setMarkerShape(QScatterSeries::MarkerShapeCircle); 42 | 43 | // create scatter serie for drawing selected keys 44 | m_scatterSelected = new QScatterSeries(); 45 | m_scatterSelected->setName("keys selected"); 46 | m_scatterSelected->setColor(Qt::black); 47 | m_scatterSelected->setMarkerSize(12.0); 48 | m_scatterSelected->setMarkerShape(QScatterSeries::MarkerShapeCircle); 49 | 50 | chart()->legend()->hide(); 51 | chart()->addSeries(m_scatter); 52 | chart()->addSeries(m_scatterSelected); 53 | chart()->createDefaultAxes(); 54 | chart()->axisX()->setRange(0.0f, 5.0f); 55 | chart()->axisY()->setRange(-1.0f, 1.0f); 56 | 57 | m_zoom = chart()->plotArea(); 58 | 59 | m_mouseCoordX = new QGraphicsSimpleTextItem(chart()); 60 | m_mouseCoordX->setPos(chart()->size().width()/2 - 50, chart()->size().height()); 61 | m_mouseCoordX->setText("X: "); 62 | m_mouseCoordX->font().setPointSize(8); 63 | 64 | m_mouseCoordY = new QGraphicsSimpleTextItem(chart()); 65 | m_mouseCoordY->setPos(chart()->size().width()/2 + 50, chart()->size().height()); 66 | m_mouseCoordY->setText("Y: "); 67 | m_mouseCoordY->font().setPointSize(8); 68 | 69 | 70 | 71 | 72 | //connect(m_scatter, &QScatterSeries::clicked, this, &ChartView::handleClickedPoint); 73 | 74 | 75 | chart()->setMargins(QMargins(0,0,0,0)); 76 | chart()->setBackgroundRoundness(0.0f); 77 | 78 | /* 79 | 80 | // Customize chart title 81 | QFont font; 82 | font.setPixelSize(18); 83 | chart()->setTitleFont(font); 84 | chart()->setTitleBrush(QBrush(Qt::white)); 85 | chart()->setTitle("Customchart example"); 86 | 87 | // Customize chart background 88 | QLinearGradient backgroundGradient; 89 | backgroundGradient.setStart(QPointF(0, 0)); 90 | backgroundGradient.setFinalStop(QPointF(0, 1)); 91 | backgroundGradient.setColorAt(0.0, QRgb(0x353535)); 92 | backgroundGradient.setColorAt(1.0, QRgb(0x2c2c2c)); 93 | backgroundGradient.setCoordinateMode(QGradient::ObjectBoundingMode); 94 | chart()->setBackgroundBrush(backgroundGradient); 95 | 96 | // Customize plot area background 97 | QLinearGradient plotAreaGradient; 98 | plotAreaGradient.setStart(QPointF(0, 1)); 99 | plotAreaGradient.setFinalStop(QPointF(1, 0)); 100 | plotAreaGradient.setColorAt(0.0, QRgb(0x555555)); 101 | plotAreaGradient.setColorAt(1.0, QRgb(0x55aa55)); 102 | plotAreaGradient.setCoordinateMode(QGradient::ObjectBoundingMode); 103 | chart()->setPlotAreaBackgroundBrush(plotAreaGradient); 104 | chart()->setPlotAreaBackgroundVisible(true); 105 | 106 | 107 | QAbstractAxis *axisX = chart()->axisX(); 108 | QAbstractAxis *axisY = chart()->axisY(); 109 | 110 | QFont labelsFont; 111 | labelsFont.setPixelSize(12); 112 | axisX->setLabelsFont(labelsFont); 113 | axisY->setLabelsFont(labelsFont); 114 | 115 | // Customize axis colors 116 | QPen axisPen(QRgb(0xd18952)); 117 | axisPen.setWidth(2); 118 | axisX->setLinePen(axisPen); 119 | axisY->setLinePen(axisPen); 120 | 121 | // Customize axis label colors 122 | QBrush axisBrush(Qt::white); 123 | axisX->setLabelsBrush(axisBrush); 124 | axisY->setLabelsBrush(axisBrush); 125 | 126 | // Customize grid lines and shades 127 | axisX->setGridLineVisible(false); 128 | axisY->setGridLineVisible(false); 129 | axisY->setShadesPen(Qt::NoPen); 130 | axisY->setShadesBrush(QBrush(QColor(0x99, 0xcc, 0xcc, 0x55))); 131 | axisY->setShadesVisible(true);*/ 132 | } 133 | 134 | GraphView::~GraphView() 135 | { 136 | } 137 | 138 | void GraphView::setPathNode(NodePath* node) 139 | { 140 | Q_ASSERT(node); 141 | 142 | _pathNode = node; 143 | _currentPath = node->getResult(); 144 | 145 | m_scatter->clear(); 146 | m_scatterSelected->clear(); 147 | 148 | for(size_t i=0; i<_currentPath->getKeyCount(); i++) 149 | { 150 | PathKey pathkey = _currentPath->getKeyByIndex(i); 151 | *m_scatter << QPointF(pathkey.time, pathkey.value); 152 | } 153 | 154 | plot(); 155 | } 156 | 157 | void GraphView::resizeEvent(QResizeEvent *event) 158 | { 159 | if (scene()) 160 | { 161 | //scene()->setSceneRect(QRect(QPoint(0, 0), event->size())); 162 | //chart()->resize(event->size()); 163 | m_mouseCoordX->setPos(chart()->size().width()/2 - 50, chart()->size().height() - 20); 164 | m_mouseCoordY->setPos(chart()->size().width()/2 + 50, chart()->size().height() - 20); 165 | } 166 | QChartView::resizeEvent(event); 167 | } 168 | 169 | void GraphView::keyPressEvent(QKeyEvent *event) 170 | { 171 | switch (event->key()) 172 | { 173 | case Qt::Key_Plus: 174 | chart()->zoomIn(); 175 | break; 176 | case Qt::Key_Minus: 177 | //chart()->zoomOut(); 178 | deleteSelectedKeys(); 179 | break; 180 | case Qt::Key_Delete: 181 | deleteSelectedKeys(); 182 | break; 183 | } 184 | } 185 | 186 | void GraphView::keyReleaseEvent(QKeyEvent *event) 187 | { 188 | 189 | } 190 | 191 | static bool xPointLessThan(const QPointF &p1, const QPointF &p2) 192 | { 193 | return p1.x() < p2.x(); 194 | } 195 | 196 | void GraphView::addNewPoint(QPointF newPoint) 197 | { 198 | if(!_currentPath) 199 | return; 200 | 201 | // don't add new point behind x origin 202 | if(newPoint.x() <= 0.0f) 203 | return; 204 | 205 | m_scatter->append(newPoint); 206 | 207 | rebuildKeys(); 208 | plot(); 209 | } 210 | 211 | void GraphView::rebuildKeys() 212 | { 213 | // sort points by x value 214 | QList listPoints = m_scatter->points(); 215 | std::sort(listPoints.begin(), listPoints.end(), xPointLessThan); 216 | 217 | // clear and replace all points 218 | m_scatter->clear(); 219 | *m_scatter << listPoints; 220 | 221 | // rebuild spline data 222 | 223 | _currentPath->clear(); 224 | //_currentPath.resize(m_scatter->count()); 225 | for(int i=0; icount(); ++i) 226 | { 227 | _currentPath->addKey(m_scatter->at(i).x(), m_scatter->at(i).y()); 228 | } 229 | } 230 | 231 | void GraphView::mousePressEvent(QMouseEvent *event) 232 | { 233 | QChartView::mousePressEvent(event); 234 | 235 | // add new key 236 | if ((event->modifiers() == Qt::ControlModifier)) 237 | { 238 | addNewPoint(chart()->mapToValue(event->pos())); 239 | return; 240 | } 241 | 242 | m_scatterSelected->clear(); 243 | _isClicked = true; 244 | handleClickedPoint(chart()->mapToValue(event->pos())); 245 | } 246 | 247 | void GraphView::mouseMoveEvent(QMouseEvent *event) 248 | { 249 | m_mouseCoordX->setText(QString("X: %1").arg(chart()->mapToValue(event->pos()).x())); 250 | m_mouseCoordY->setText(QString("Y: %1").arg(chart()->mapToValue(event->pos()).y())); 251 | 252 | if(_isPointSelected && _isClicked) 253 | { 254 | // get index of selected point 255 | int pointIndex = m_scatter->points().indexOf(_selectedPoint); 256 | if(pointIndex == -1) 257 | return; 258 | 259 | // get new point coord 260 | QPointF newPoint = chart()->mapToValue(event->pos()); 261 | 262 | // stick first key at 0.0f on x axis 263 | if(pointIndex == 0) 264 | newPoint.setX(0.0f); 265 | 266 | if(isKeyMovable(newPoint.x(), pointIndex) == false) 267 | return; 268 | 269 | // replace point at index 270 | _currentPath->setAtIndex(pointIndex, newPoint.x(), newPoint.y()); 271 | 272 | // replace point (simulate moving) 273 | m_scatter->replace(_selectedPoint, newPoint); 274 | m_scatterSelected->replace(0, newPoint); 275 | 276 | _selectedPoint = newPoint; 277 | 278 | plot(); 279 | } 280 | 281 | QChartView::mouseMoveEvent(event); 282 | } 283 | 284 | void GraphView::mouseReleaseEvent(QMouseEvent *event) 285 | { 286 | QChartView::mouseReleaseEvent(event); 287 | 288 | _isClicked = false; 289 | _isPointSelected = false; 290 | } 291 | 292 | void GraphView::zoom() 293 | { 294 | chart()->zoomReset(); 295 | 296 | QRectF rect = chart()->plotArea(); 297 | QPointF center = chart()->plotArea().center(); 298 | qreal left = chart()->plotArea().left(); 299 | 300 | rect.setWidth(m_zoomFactorX*rect.width()); 301 | rect.setHeight(m_zoomFactorY*rect.height()); 302 | 303 | rect.moveCenter(center); 304 | rect.moveLeft(left); 305 | 306 | chart()->zoomIn(rect); 307 | m_zoom = rect; 308 | } 309 | 310 | void GraphView::wheelEvent(QWheelEvent *event) 311 | { 312 | // zoom 313 | 314 | float delta = event->angleDelta().y() > 0 ? 0.5f : 2.0f; 315 | if (event->modifiers() || event->modifiers()&Qt::ControlModifier) 316 | m_zoomFactorX *= delta; 317 | else 318 | m_zoomFactorY *= delta; 319 | 320 | zoom(); 321 | 322 | QChartView::wheelEvent(event); 323 | } 324 | 325 | 326 | void GraphView::handleClickedPoint(const QPointF &point) 327 | { 328 | _isPointSelected = false; 329 | 330 | QPointF clickedPoint = point; 331 | // Find the closest point from series 1 332 | QPointF closest(INT_MAX, INT_MAX); 333 | qreal distance(INT_MAX); 334 | const auto points = m_scatter->points(); 335 | for (const QPointF ¤tPoint : points) 336 | { 337 | qreal currentDistance = qSqrt((currentPoint.x() - clickedPoint.x()) 338 | * (currentPoint.x() - clickedPoint.x()) 339 | + (currentPoint.y() - clickedPoint.y()) 340 | * (currentPoint.y() - clickedPoint.y())); 341 | if (currentDistance < distance) 342 | { 343 | distance = currentDistance; 344 | closest = currentPoint; 345 | 346 | _isPointSelected = true; 347 | _selectedPoint = closest; 348 | 349 | // add point to selection 350 | m_scatterSelected->clear(); 351 | m_scatterSelected->append(closest); 352 | } 353 | } 354 | } 355 | 356 | bool GraphView::isKeyMovable(double newTime, int index) 357 | { 358 | Q_ASSERT(index >= 0 || index < m_scatter->count()-1); 359 | 360 | const double keytime = m_scatter->at(index).x(); 361 | for (int i=0; icount(); i++) 362 | { 363 | const double curKeytime = m_scatter->at(i).x(); 364 | if (keytime != curKeytime) 365 | { 366 | if ((keytime <= curKeytime && newTime >= curKeytime) || 367 | (keytime >= curKeytime && newTime <= curKeytime) 368 | ) 369 | { 370 | return false; 371 | } 372 | } 373 | } 374 | 375 | return true; 376 | } 377 | 378 | void GraphView::plot() 379 | { 380 | if(!_pathNode || !_currentPath || _currentPath->getKeyCount() <= 1) 381 | return; 382 | 383 | // rebuild path 384 | _currentPath->build(); 385 | 386 | // regenerate spline for drawing 387 | m_lines->clear(); 388 | chart()->removeSeries(m_lines); 389 | for(size_t i=0; i<_splineResolution; i++) 390 | { 391 | double max = _currentPath->getEndTime(); 392 | double x = i*max/_splineResolution; 393 | *m_lines << QPointF( x, _currentPath->evaluate(x)); 394 | } 395 | chart()->addSeries(m_lines); 396 | 397 | // need to setup axes after new added serie 398 | chart()->createDefaultAxes(); 399 | chart()->axisX()->setRange(0.0f, 5.0f); 400 | chart()->axisY()->setRange(-1.0f, 1.0f); 401 | 402 | chart()->zoomIn(m_zoom); 403 | 404 | // trigger node connections and updates in flow graph 405 | _pathNode->dataUpdated(0); 406 | } 407 | 408 | void GraphView::deleteSelectedKeys() 409 | { 410 | if(!_currentPath) 411 | return; 412 | 413 | for(int i=0; icount(); ++i) 414 | { 415 | QPointF p = m_scatterSelected->at(i); 416 | int index = m_scatter->points().indexOf(p); 417 | if(index > 0 && index < m_scatter->count()-1) 418 | { 419 | m_scatter->remove(index); 420 | } 421 | } 422 | 423 | m_scatterSelected->clear(); 424 | 425 | rebuildKeys(); 426 | plot(); 427 | } 428 | -------------------------------------------------------------------------------- /src/GraphView.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the Qt Charts module of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:GPL$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see https://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at https://www.qt.io/contact-us. 16 | ** 17 | ** GNU General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU 19 | ** General Public License version 3 or (at your option) any later version 20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by 21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 22 | ** included in the packaging of this file. Please review the following 23 | ** information to ensure the GNU General Public License requirements will 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 25 | ** 26 | ** $QT_END_LICENSE$ 27 | ** 28 | ****************************************************************************/ 29 | 30 | #ifndef PATHEDITOR_H 31 | #define PATHEDITOR_H 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #include "node-editor/spark-nodes/SpkInterpolators.h" 40 | 41 | 42 | QT_CHARTS_USE_NAMESPACE 43 | 44 | class GraphView : public QChartView 45 | { 46 | Q_OBJECT 47 | 48 | public: 49 | GraphView(QWidget *parent = 0); 50 | ~GraphView(); 51 | 52 | void resizeEvent(QResizeEvent *event) override; 53 | void keyPressEvent(QKeyEvent *event) override; 54 | void keyReleaseEvent(QKeyEvent *event) override; 55 | void mousePressEvent(QMouseEvent *event) override; 56 | void mouseMoveEvent(QMouseEvent *event) override; 57 | void mouseReleaseEvent(QMouseEvent *event) override; 58 | void wheelEvent(QWheelEvent *event) override; 59 | 60 | public Q_SLOTS: 61 | void setPathNode(NodePath* node); 62 | 63 | private Q_SLOTS: 64 | void handleClickedPoint(const QPointF &point); 65 | 66 | private: 67 | void zoom(); 68 | void addNewPoint(QPointF newPoint); 69 | void deleteSelectedKeys(); 70 | void rebuildKeys(); 71 | bool isKeyMovable(double newTime, int index); 72 | void plot(); 73 | 74 | NodePath* _pathNode; 75 | Path* _currentPath; 76 | QScatterSeries* m_scatter; 77 | QScatterSeries* m_scatterSelected; 78 | QLineSeries* m_lines; 79 | QRectF m_zoom; 80 | qreal m_zoomFactorX; 81 | qreal m_zoomFactorY; 82 | QGraphicsSimpleTextItem* m_mouseCoordX; 83 | QGraphicsSimpleTextItem* m_mouseCoordY; 84 | 85 | bool _isPointSelected; 86 | bool _isClicked; 87 | QPointF _selectedPoint; 88 | double _splineResolution; 89 | }; 90 | 91 | #endif // PATHEDITOR_H 92 | -------------------------------------------------------------------------------- /src/MainWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | #include "GplayDevice.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "node-editor/common/Nodestyle.h" 12 | #include "node-editor/spark-nodes/SparkNodesRegistry.h" 13 | 14 | 15 | MainWindow::MainWindow(QWidget* parent) 16 | : QMainWindow(parent) 17 | { 18 | //setNodeStyle(); 19 | createWidgets(); 20 | createActions(); 21 | createMenus(); 22 | 23 | // create Nodes registry 24 | _sparkNodesRegistry = registerSparkNodesDataModels(); 25 | _nodeFlowScene->setRegistry(_sparkNodesRegistry); 26 | 27 | // create gplay render view into _renderView widget 28 | GplayDevice::getInstance()->createRenderWindow((void*)_renderView); 29 | 30 | _gameLoopTimerId = startTimer(0); 31 | } 32 | 33 | MainWindow::~MainWindow() 34 | { 35 | delete _nodeFlowScene; 36 | delete _nodeFlowView; 37 | delete _renderView; 38 | delete _viewportContainer; 39 | delete _dockView; 40 | delete _dockNodeFlowView; 41 | } 42 | 43 | void MainWindow::createWidgets() 44 | { 45 | // create gplay viewport widget 46 | _renderView = new QWidget(this); 47 | _renderView->setMouseTracking(true); 48 | _renderView->setFocusPolicy(Qt::StrongFocus); 49 | 50 | _viewportContainer = new QWidget(this); 51 | _viewportContainer->setLayout(new QVBoxLayout()); 52 | _viewportContainer->layout()->addWidget(_renderView); 53 | 54 | _dockView = new QDockWidget("Viewport", this); 55 | _dockView->setWidget(_viewportContainer); 56 | _dockView->setAllowedAreas(Qt::AllDockWidgetAreas); 57 | addDockWidget(Qt::TopDockWidgetArea, _dockView); 58 | 59 | _nodeFlowScene = new CustomFlowScene(); 60 | 61 | _nodeFlowView = new FlowView(_nodeFlowScene); 62 | _nodeFlowView->setWindowTitle("Node-based flow editor"); 63 | _nodeFlowView->resize(800, 600); 64 | _nodeFlowView->show(); 65 | _nodeFlowView->scale(0.9, 0.9); 66 | 67 | _dockNodeFlowView = new QDockWidget("NodeGraph", this); 68 | _dockNodeFlowView->setWidget(_nodeFlowView); 69 | _dockNodeFlowView->setAllowedAreas(Qt::AllDockWidgetAreas); 70 | addDockWidget(Qt::BottomDockWidgetArea, _dockNodeFlowView); 71 | 72 | _pathView = new GraphView(this); 73 | 74 | _dockGraph = new QDockWidget("Graph", this); 75 | _dockGraph->setWidget(_pathView); 76 | _dockGraph->setAllowedAreas(Qt::AllDockWidgetAreas); 77 | addDockWidget(Qt::TopDockWidgetArea, _dockGraph); 78 | 79 | 80 | // make some connections 81 | 82 | connect(_nodeFlowScene, &CustomFlowScene::showPathNodeRequest, _pathView, &GraphView::setPathNode); 83 | 84 | // connect to FlowView deleteSelectionAction a method to delete comments graphics items. 85 | QAction* deleteAction = _nodeFlowView->deleteSelectionAction(); 86 | connect(deleteAction, &QAction::triggered, _nodeFlowScene, &CustomFlowScene::deleteSelectedComments); 87 | } 88 | 89 | void MainWindow::createActions() 90 | { 91 | _newAct = new QAction(tr("&New"), this); 92 | _newAct->setShortcuts(QKeySequence::New); 93 | _newAct->setStatusTip(tr("New")); 94 | connect(_newAct, &QAction::triggered, this, &MainWindow::newFile); 95 | 96 | _openAct = new QAction(tr("&Open"), this); 97 | _openAct->setShortcuts(QKeySequence::Open); 98 | _openAct->setStatusTip(tr("Open")); 99 | connect(_openAct, &QAction::triggered, this, &MainWindow::open); 100 | 101 | _saveAct = new QAction(tr("&Save"), this); 102 | _saveAct->setShortcuts(QKeySequence::Save); 103 | _saveAct->setStatusTip(tr("Save")); 104 | connect(_saveAct, &QAction::triggered, this, &MainWindow::save); 105 | } 106 | 107 | void MainWindow::createMenus() 108 | { 109 | _fileMenu = menuBar()->addMenu(tr("&File")); 110 | _fileMenu->addAction(_newAct); 111 | _fileMenu->addAction(_openAct); 112 | _fileMenu->addAction(_saveAct); 113 | } 114 | 115 | void MainWindow::newFile() 116 | { 117 | _nodeFlowScene->clearScene(); 118 | _nodeFlowScene->clearComments(); 119 | } 120 | 121 | void MainWindow::open() 122 | { 123 | _nodeFlowScene->load(); 124 | } 125 | 126 | void MainWindow::save() 127 | { 128 | _nodeFlowScene->save(); 129 | } 130 | 131 | void MainWindow::closeEvent(QCloseEvent* event) 132 | { 133 | QMessageBox::StandardButton resBtn = QMessageBox::question( this, qApp->applicationName(), 134 | tr("Are you sure?\n"), 135 | QMessageBox::No | QMessageBox::Yes, 136 | QMessageBox::Yes); 137 | if(resBtn != QMessageBox::Yes) 138 | { 139 | event->ignore(); 140 | } 141 | else 142 | { 143 | event->accept(); 144 | shutdown(); 145 | } 146 | } 147 | 148 | void MainWindow::shutdown() 149 | { 150 | killTimer(_gameLoopTimerId); 151 | GplayDevice::getInstance()->stop(); 152 | } 153 | 154 | void MainWindow::timerEvent(QTimerEvent* event) 155 | { 156 | QMainWindow::timerEvent(event); 157 | GplayDevice::getInstance()->runFrame(); 158 | } 159 | -------------------------------------------------------------------------------- /src/MainWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | 7 | #include "node-editor/common/CustomFlowScene.h" 8 | #include "GraphView.h" 9 | 10 | class MainWindow : public QMainWindow 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit MainWindow(QWidget *parent = nullptr); 16 | ~MainWindow(); 17 | 18 | private Q_SLOTS: 19 | void newFile(); 20 | void open(); 21 | void save(); 22 | 23 | private: 24 | void shutdown(); 25 | void createWidgets(); 26 | void createActions(); 27 | void createMenus(); 28 | void closeEvent(QCloseEvent* event) override; 29 | void timerEvent(QTimerEvent* event) override; 30 | 31 | 32 | std::shared_ptr _sparkNodesRegistry; 33 | 34 | // GUI stuff 35 | 36 | QMenu* _fileMenu; 37 | QAction* _newAct; 38 | QAction* _openAct; 39 | QAction* _saveAct; 40 | 41 | CustomFlowScene* _nodeFlowScene; 42 | FlowView* _nodeFlowView; 43 | QWidget* _viewportContainer; 44 | QWidget* _renderView; 45 | GraphView* _pathView; 46 | QDockWidget* _dockView; 47 | QDockWidget* _dockNodeFlowView; 48 | QDockWidget* _dockGraph; 49 | int _gameLoopTimerId; 50 | }; 51 | 52 | #endif // MAINWINDOW_H 53 | -------------------------------------------------------------------------------- /src/benchmark.h: -------------------------------------------------------------------------------- 1 | #ifndef BENCHMARK_H 2 | #define BENCHMARK_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /****************************************************************************/ 9 | /*** ***/ 10 | /*** Basic Benchmark Macros for performance tests ***/ 11 | /*** ***/ 12 | /****************************************************************************/ 13 | 14 | #ifndef GP_NO_BENCHMARK 15 | struct BENCHMARK_TEST 16 | { 17 | BENCHMARK_TEST() 18 | { 19 | BENCHMARK_LOOPS = 1; 20 | BENCHMARK_FUNC_NAME = "NO NAME"; 21 | BENCHMARK_IS_BLOCK = true; 22 | BENCHMARK_IS_FINISHED = false; 23 | } 24 | 25 | bool BENCHMARK_IS_BLOCK; 26 | unsigned int BENCHMARK_LOOPS; 27 | std::chrono::high_resolution_clock::time_point BENCHMARK_TIME_START; 28 | std::chrono::high_resolution_clock::time_point BENCHMARK_TIME_END; 29 | const char* BENCHMARK_FUNC_NAME; 30 | bool BENCHMARK_IS_FINISHED; 31 | }; 32 | 33 | static std::vector BENCHMARK_ARRAY; 34 | 35 | //--------------------------------------------------------------------------------------------- 36 | // benchmark a function with one or multiple iterations 37 | //--------------------------------------------------------------------------------------------- 38 | #define GP_BENCHMARK_FUNC(func, nb_loop) \ 39 | { \ 40 | BENCHMARK_TEST * bench = new BENCHMARK_TEST(); \ 41 | bench->BENCHMARK_LOOPS = nb_loop; \ 42 | bench->BENCHMARK_IS_BLOCK = false; \ 43 | bench->BENCHMARK_FUNC_NAME = #func; \ 44 | bench->BENCHMARK_TIME_START = std::chrono::high_resolution_clock::now(); \ 45 | for (unsigned int i=0; iBENCHMARK_TIME_END = std::chrono::high_resolution_clock::now(); \ 47 | bench->BENCHMARK_IS_FINISHED = true; \ 48 | BENCHMARK_ARRAY.push_back(bench); \ 49 | } 50 | 51 | //--------------------------------------------------------------------------------------------- 52 | // benchmark block begin, put code to test between block begin/end macros 53 | //--------------------------------------------------------------------------------------------- 54 | #define GP_BENCHMARK_BLOCK_BEGIN(blockName) \ 55 | { \ 56 | BENCHMARK_ARRAY.push_back(new BENCHMARK_TEST); \ 57 | BENCHMARK_ARRAY.back()->BENCHMARK_FUNC_NAME = blockName; \ 58 | BENCHMARK_ARRAY.back()->BENCHMARK_IS_FINISHED = false; \ 59 | BENCHMARK_ARRAY.back()->BENCHMARK_TIME_START = std::chrono::high_resolution_clock::now(); \ 60 | } 61 | 62 | //--------------------------------------------------------------------------------------------- 63 | // benchmark block end 64 | //--------------------------------------------------------------------------------------------- 65 | #define GP_BENCHMARK_BLOCK_END() \ 66 | { \ 67 | auto end = std::chrono::high_resolution_clock::now(); \ 68 | if(BENCHMARK_ARRAY.size() > 0 && BENCHMARK_ARRAY.back()->BENCHMARK_IS_BLOCK && \ 69 | BENCHMARK_ARRAY.back()->BENCHMARK_IS_FINISHED == false) { \ 70 | BENCHMARK_ARRAY.back()->BENCHMARK_TIME_END = end; \ 71 | BENCHMARK_ARRAY.back()->BENCHMARK_IS_FINISHED = true; \ 72 | } \ 73 | else printf("WARNING: BENCHMARK_BLOCK_END (missing BENCHMARK_BLOCK_BEGIN ?) !!!\n");\ 74 | } 75 | 76 | //--------------------------------------------------------------------------------------------- 77 | // report benchmark measures 78 | //--------------------------------------------------------------------------------------------- 79 | #define GP_BENCHMARK_REPORT() \ 80 | { \ 81 | printf("=================== BENCHMARK REPORT ==================================\n"); \ 82 | printf("num\tseconds\t\tloop\tdescription\n"); \ 83 | for (size_t i=0; iBENCHMARK_IS_FINISHED && BENCHMARK_ARRAY[i]->BENCHMARK_IS_BLOCK) {\ 86 | printf("%d: WARNING: MISSING nBENCHMARK_BLOCK_END!!!\n", i); \ 87 | break; \ 88 | }\ 89 | else { \ 90 | auto time_span = std::chrono::duration_cast>(BENCHMARK_ARRAY[i]->BENCHMARK_TIME_END - BENCHMARK_ARRAY[i]->BENCHMARK_TIME_START); \ 91 | printf("%d\t[%lf s]\t%8d\t%s\n" \ 92 | ,i \ 93 | ,time_span.count() \ 94 | ,BENCHMARK_ARRAY[i]->BENCHMARK_LOOPS \ 95 | ,BENCHMARK_ARRAY[i]->BENCHMARK_FUNC_NAME \ 96 | ); \ 97 | } \ 98 | } \ 99 | printf("=======================================================================\n"); \ 100 | BENCHMARK_ARRAY.clear(); \ 101 | } 102 | 103 | #else 104 | #define GP_BENCHMARK_FUNC(f,l) f 105 | #define GP_BENCHMARK_BLOCK_BEGIN(n) 106 | #define GP_BENCHMARK_BLOCK_END() 107 | #define GP_BENCHMARK_REPORT() 108 | #endif 109 | 110 | 111 | #endif // BENCHMARK_H 112 | -------------------------------------------------------------------------------- /src/gp3d/GPRenderer.cpp: -------------------------------------------------------------------------------- 1 | #include "GPRenderer.h" 2 | #include "helpers/Events.h" 3 | 4 | GPRenderer3D::GPRenderer3D() : 5 | _scene(nullptr) 6 | { 7 | // Create a new empty scene. 8 | _scene = Scene::create(); 9 | 10 | // set fps camera 11 | Vector3 cameraPosition(0, 1, 5); 12 | _fpCamera.initialize(1.0, 10000.0f); 13 | _fpCamera.setPosition(cameraPosition); 14 | _scene->addNode(_fpCamera.getRootNode()); 15 | _scene->setActiveCamera(_fpCamera.getCamera()); 16 | _scene->getActiveCamera()->setAspectRatio(4/3); 17 | 18 | // load 3d grid 19 | loadGrid(_scene); 20 | 21 | // Add listeners for events 22 | EventManager::getInstance()->addListener(GP_EVENT_LISTENER(this, GPRenderer3D::onMouseEvent), MouseEvent::ID()); 23 | EventManager::getInstance()->addListener(GP_EVENT_LISTENER(this, GPRenderer3D::onKeyEvent), KeyEvent::ID()); 24 | } 25 | 26 | void GPRenderer3D::loadGrid(Scene* scene) 27 | { 28 | assert(scene); 29 | Model* gridModel = createGridModel(); 30 | assert(gridModel); 31 | gridModel->setMaterial("res/data/materials/grid.material"); 32 | Node* node = scene->addNode("grid"); 33 | node->setDrawable(gridModel); 34 | SAFE_RELEASE(gridModel); 35 | } 36 | 37 | void GPRenderer3D::resize(int width, int height) 38 | { 39 | if(_scene) 40 | { 41 | Camera* camera = _scene->getActiveCamera(); 42 | if(camera) 43 | { 44 | float ratio = (float)width / (float)height; 45 | camera->setAspectRatio(ratio); 46 | } 47 | } 48 | } 49 | 50 | void GPRenderer3D::update(float elapsedTime) 51 | { 52 | if(Game::getInstance()->isMouseCaptured()) 53 | _fpCamera.updateCamera(elapsedTime); 54 | } 55 | 56 | void GPRenderer3D::onMouseEvent(EventDataRef eventData) 57 | { 58 | auto mouseEvent = std::dynamic_pointer_cast(eventData); 59 | if(!mouseEvent) 60 | return; 61 | 62 | if(Game::getInstance()->isMouseCaptured()) 63 | _fpCamera.mouseEvent(mouseEvent->event, mouseEvent->mousePos.x, mouseEvent->mousePos.y, 0); 64 | else 65 | { 66 | // force to clear camera movement if key press event was not sent before releasing mouse capture 67 | _fpCamera.clearMoveFlag(); 68 | } 69 | } 70 | 71 | void GPRenderer3D::onKeyEvent(EventDataRef eventData) 72 | { 73 | auto keyEvent = std::dynamic_pointer_cast(eventData); 74 | if(!keyEvent) 75 | return; 76 | 77 | if(Game::getInstance()->isMouseCaptured()) 78 | _fpCamera.keyEvent(keyEvent->event, keyEvent->key); 79 | } 80 | -------------------------------------------------------------------------------- /src/gp3d/GPRenderer.h: -------------------------------------------------------------------------------- 1 | #ifndef GPRENDERER_H 2 | #define GPRENDERER_H 3 | 4 | #include 5 | #include "helpers/FirstPersonCamera.h" 6 | #include "helpers/Grid.h" 7 | 8 | /** 9 | * Interface class for sub-renderers 10 | * A subrenderer manage it's own scene. 11 | */ 12 | class ISubRenderer 13 | { 14 | public: 15 | virtual ~ISubRenderer() {} 16 | virtual void resize(int width, int height) = 0; 17 | virtual void update(float elapsedTime) = 0; 18 | virtual void render(float elapsedTime) = 0; 19 | }; 20 | 21 | 22 | /** 23 | * Base subrenderer for 3D view, with scene, fps camera and 3d grid. 24 | */ 25 | class GPRenderer3D : public ISubRenderer 26 | { 27 | 28 | public: 29 | GPRenderer3D(); 30 | 31 | void update(float elapsedTime) override; 32 | void resize(int width, int height) override; 33 | 34 | void onMouseEvent(EventDataRef eventData); 35 | void onKeyEvent(EventDataRef eventData); 36 | 37 | Scene* getScene() { return _scene; } 38 | 39 | protected: 40 | Scene* _scene; 41 | FirstPersonCamera _fpCamera; 42 | 43 | private: 44 | void loadGrid(Scene* scene); 45 | }; 46 | 47 | 48 | 49 | 50 | 51 | #endif // GPRENDERER_H 52 | -------------------------------------------------------------------------------- /src/gp3d/PlatformQt.h: -------------------------------------------------------------------------------- 1 | #ifndef PLATFORMQT_H 2 | #define PLATFORMQT_H 3 | 4 | #include 5 | 6 | class QMouseEvent; 7 | class QWheelEvent; 8 | class QKeyEvent; 9 | 10 | /** 11 | * event filter for gplay widget 12 | */ 13 | class GPlayWidgetEventFilter : public QObject 14 | { 15 | Q_OBJECT 16 | public: 17 | bool eventFilter(QObject* watched, QEvent* event); 18 | 19 | private: 20 | void onWheel(QWheelEvent* event); 21 | void onMousePress(QMouseEvent* event); 22 | void onMouseRelease(QMouseEvent* event); 23 | void onMouseMove(QMouseEvent* event); 24 | void onKeyEvent(QKeyEvent* event); 25 | 26 | }; 27 | 28 | #endif // PLATFORMQT_H 29 | -------------------------------------------------------------------------------- /src/gp3d/QtImGui.cpp: -------------------------------------------------------------------------------- 1 | #include "QtImGui.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "../renderer/BGFXImGui.h" 11 | 12 | // bgfx imgui 13 | #include 14 | #include 15 | entry::MouseState m_mouseState; 16 | 17 | namespace QtImGui { 18 | 19 | 20 | class QWidgetWindowWrapper : public WindowWrapper 21 | { 22 | public: 23 | QWidgetWindowWrapper(QWidget *w) : w(w) {} 24 | void installEventFilter(QObject *object) override 25 | { 26 | return w->installEventFilter(object); 27 | } 28 | QSize size() const override 29 | { 30 | return w->size(); 31 | } 32 | qreal devicePixelRatio() const override 33 | { 34 | return w->devicePixelRatioF(); 35 | } 36 | bool isActive() const override 37 | { 38 | return w->isActiveWindow(); 39 | } 40 | QPoint mapFromGlobal(const QPoint &p) const override 41 | { 42 | return w->mapFromGlobal(p); 43 | } 44 | private: 45 | QWidget *w; 46 | }; 47 | 48 | void initialize(QWidget *window) 49 | { 50 | ImGuiRenderer::instance()->initialize(new QWidgetWindowWrapper(window)); 51 | } 52 | 53 | void newFrame() 54 | { 55 | ImGuiRenderer::instance()->newFrame(); 56 | } 57 | 58 | void endFrame() 59 | { 60 | ImGuiRenderer::instance()->endFrame(); 61 | } 62 | 63 | 64 | 65 | namespace { 66 | 67 | QHash keyMap = { 68 | { Qt::Key_Tab, ImGuiKey_Tab }, 69 | { Qt::Key_Left, ImGuiKey_LeftArrow }, 70 | { Qt::Key_Right, ImGuiKey_RightArrow }, 71 | { Qt::Key_Up, ImGuiKey_UpArrow }, 72 | { Qt::Key_Down, ImGuiKey_DownArrow }, 73 | { Qt::Key_PageUp, ImGuiKey_PageUp }, 74 | { Qt::Key_PageDown, ImGuiKey_PageDown }, 75 | { Qt::Key_Home, ImGuiKey_Home }, 76 | { Qt::Key_End, ImGuiKey_End }, 77 | { Qt::Key_Delete, ImGuiKey_Delete }, 78 | { Qt::Key_Backspace, ImGuiKey_Backspace }, 79 | { Qt::Key_Enter, ImGuiKey_Enter }, 80 | { Qt::Key_Escape, ImGuiKey_Escape }, 81 | { Qt::Key_A, ImGuiKey_A }, 82 | { Qt::Key_C, ImGuiKey_C }, 83 | { Qt::Key_V, ImGuiKey_V }, 84 | { Qt::Key_X, ImGuiKey_X }, 85 | { Qt::Key_Y, ImGuiKey_Y }, 86 | { Qt::Key_Z, ImGuiKey_Z }, 87 | }; 88 | 89 | QByteArray g_currentClipboardText; 90 | 91 | } 92 | 93 | ImGuiRenderer::ImGuiRenderer() 94 | { 95 | 96 | } 97 | 98 | void ImGuiRenderer::initialize(WindowWrapper *window) 99 | { 100 | m_window.reset(window); 101 | 102 | ImGui::CreateContext(); 103 | 104 | // Create bgfx imgui 105 | ///gplay::GPImGui::getInstance()->imguiInit(); 106 | imguiCreate(); 107 | 108 | ImGuiIO &io = ImGui::GetIO(); 109 | for (ImGuiKey key : keyMap.values()) { 110 | io.KeyMap[key] = key; 111 | } 112 | 113 | ///io.RenderDrawListsFn = [](ImDrawData *drawData) { 114 | /// gplay::GPImGui::getInstance()->imguiRender(drawData); 115 | ///}; 116 | 117 | io.SetClipboardTextFn = [](void *user_data, const char *text) { 118 | Q_UNUSED(user_data); 119 | QGuiApplication::clipboard()->setText(text); 120 | }; 121 | 122 | io.GetClipboardTextFn = [](void *user_data) { 123 | Q_UNUSED(user_data); 124 | g_currentClipboardText = QGuiApplication::clipboard()->text().toUtf8(); 125 | return (const char *)g_currentClipboardText.data(); 126 | }; 127 | 128 | window->installEventFilter(this); 129 | } 130 | 131 | void ImGuiRenderer::endFrame() 132 | { 133 | imguiEndFrame(); 134 | } 135 | 136 | void ImGuiRenderer::newFrame() 137 | { 138 | ImGuiIO& io = ImGui::GetIO(); 139 | 140 | // Setup display size (every frame to accommodate for window resizing) 141 | io.DisplaySize = ImVec2(m_window->size().width(), m_window->size().height()); 142 | io.DisplayFramebufferScale = ImVec2(m_window->devicePixelRatio(), m_window->devicePixelRatio()); 143 | 144 | // Setup time step 145 | double current_time = QDateTime::currentMSecsSinceEpoch() / double(1000); 146 | io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); 147 | g_Time = current_time; 148 | 149 | // Setup inputs 150 | // (we already got mouse wheel, keyboard keys & characters from glfw callbacks polled in glfwPollEvents()) 151 | if (m_window->isActive()) 152 | { 153 | auto pos = m_window->mapFromGlobal(QCursor::pos()); 154 | io.MousePos = ImVec2(pos.x(), pos.y()); // Mouse position in screen coordinates (set to -1,-1 if no mouse / on another screen, etc.) 155 | } 156 | else 157 | { 158 | io.MousePos = ImVec2(-1,-1); 159 | } 160 | 161 | for (int i = 0; i < 3; i++) 162 | { 163 | io.MouseDown[i] = g_MousePressed[i]; 164 | } 165 | 166 | io.MouseWheelH = g_MouseWheelH; 167 | io.MouseWheel = g_MouseWheel; 168 | g_MouseWheelH = 0; 169 | g_MouseWheel = 0; 170 | 171 | // Hide OS mouse cursor if ImGui is drawing it 172 | // glfwSetInputMode(g_Window, GLFW_CURSOR, io.MouseDrawCursor ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL); 173 | 174 | // bgfx imgui mouse state 175 | m_mouseState.m_mx = io.MousePos.x; 176 | m_mouseState.m_my = io.MousePos.y; 177 | m_mouseState.m_buttons[entry::MouseButton::Left] = io.MouseDown[0]; 178 | m_mouseState.m_buttons[entry::MouseButton::Right] = io.MouseDown[1]; 179 | m_mouseState.m_buttons[entry::MouseButton::Middle] = io.MouseDown[2]; 180 | 181 | 182 | // Start the frame 183 | ///ImGui::NewFrame(); 184 | imguiBeginFrame( 185 | m_mouseState.m_mx 186 | , m_mouseState.m_my 187 | , (m_mouseState.m_buttons[entry::MouseButton::Left] ? IMGUI_MBUT_LEFT : 0) 188 | | (m_mouseState.m_buttons[entry::MouseButton::Right] ? IMGUI_MBUT_RIGHT : 0) 189 | | (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0) 190 | , m_mouseState.m_mz 191 | , uint16_t(m_window->size().width()) 192 | , uint16_t(m_window->size().height()) 193 | ); 194 | 195 | } 196 | 197 | void ImGuiRenderer::onMousePressedChange(QMouseEvent *event) 198 | { 199 | g_MousePressed[0] = event->buttons() & Qt::LeftButton; 200 | g_MousePressed[1] = event->buttons() & Qt::RightButton; 201 | g_MousePressed[2] = event->buttons() & Qt::MiddleButton; 202 | } 203 | 204 | void ImGuiRenderer::onWheel(QWheelEvent *event) 205 | { 206 | // 5 lines per unit 207 | g_MouseWheelH += event->delta() / (ImGui::GetTextLineHeight()); 208 | g_MouseWheel += event->delta() / (5.0f * ImGui::GetTextLineHeight()); 209 | } 210 | 211 | void ImGuiRenderer::onKeyPressRelease(QKeyEvent *event) 212 | { 213 | ImGuiIO& io = ImGui::GetIO(); 214 | if (keyMap.contains(event->key())) { 215 | io.KeysDown[keyMap[event->key()]] = event->type() == QEvent::KeyPress; 216 | } 217 | 218 | if (event->type() == QEvent::KeyPress) { 219 | QString text = event->text(); 220 | if (text.size() == 1) { 221 | io.AddInputCharacter(text.at(0).unicode()); 222 | } 223 | } 224 | 225 | #ifdef Q_OS_MAC 226 | io.KeyCtrl = event->modifiers() & Qt::MetaModifier; 227 | io.KeyShift = event->modifiers() & Qt::ShiftModifier; 228 | io.KeyAlt = event->modifiers() & Qt::AltModifier; 229 | io.KeySuper = event->modifiers() & Qt::ControlModifier; // Comamnd key 230 | #else 231 | io.KeyCtrl = event->modifiers() & Qt::ControlModifier; 232 | io.KeyShift = event->modifiers() & Qt::ShiftModifier; 233 | io.KeyAlt = event->modifiers() & Qt::AltModifier; 234 | io.KeySuper = event->modifiers() & Qt::MetaModifier; 235 | #endif 236 | } 237 | 238 | bool ImGuiRenderer::eventFilter(QObject *watched, QEvent *event) 239 | { 240 | switch (event->type()) { 241 | case QEvent::MouseButtonPress: 242 | case QEvent::MouseButtonRelease: 243 | this->onMousePressedChange(static_cast(event)); 244 | break; 245 | case QEvent::Wheel: 246 | this->onWheel(static_cast(event)); 247 | break; 248 | case QEvent::KeyPress: 249 | case QEvent::KeyRelease: 250 | this->onKeyPressRelease(static_cast(event)); 251 | break; 252 | default: 253 | break; 254 | } 255 | return QObject::eventFilter(watched, event); 256 | } 257 | 258 | ImGuiRenderer* ImGuiRenderer::instance() 259 | { 260 | static ImGuiRenderer* instance = nullptr; 261 | if (!instance) { 262 | instance = new ImGuiRenderer(); 263 | } 264 | return instance; 265 | } 266 | 267 | 268 | } 269 | 270 | -------------------------------------------------------------------------------- /src/gp3d/QtImGui.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class QMouseEvent; 9 | class QWheelEvent; 10 | class QKeyEvent; 11 | 12 | namespace QtImGui { 13 | 14 | void initialize(QWidget *window); 15 | void newFrame(); 16 | void endFrame(); 17 | 18 | class WindowWrapper 19 | { 20 | public: 21 | virtual ~WindowWrapper() {} 22 | virtual void installEventFilter(QObject *object) = 0; 23 | virtual QSize size() const = 0; 24 | virtual qreal devicePixelRatio() const = 0; 25 | virtual bool isActive() const = 0; 26 | virtual QPoint mapFromGlobal(const QPoint &p) const = 0; 27 | }; 28 | 29 | class ImGuiRenderer : public QObject 30 | { 31 | Q_OBJECT 32 | public: 33 | void initialize(WindowWrapper *window); 34 | void newFrame(); 35 | void endFrame(); 36 | bool eventFilter(QObject *watched, QEvent *event); 37 | static ImGuiRenderer *instance(); 38 | 39 | private: 40 | ImGuiRenderer(); 41 | void onMousePressedChange(QMouseEvent *event); 42 | void onWheel(QWheelEvent *event); 43 | void onKeyPressRelease(QKeyEvent *event); 44 | 45 | std::unique_ptr m_window; 46 | double g_Time = 0.0f; 47 | bool g_MousePressed[3] = { false, false, false }; 48 | float g_MouseWheel; 49 | float g_MouseWheelH; 50 | }; 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/gp3d/helpers/Events.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENTS_H 2 | #define EVENTS_H 3 | 4 | #include 5 | 6 | using namespace gplay; 7 | 8 | 9 | GP_EVENT_BEGIN(MouseEvent) 10 | Mouse::MouseEvent event; // mouse event type 11 | Vector2 mousePos; // mouse position 12 | GP_EVENT_END() 13 | 14 | GP_EVENT_BEGIN(KeyEvent) 15 | Keyboard::KeyEvent event; // key event type 16 | int key; // key 17 | GP_EVENT_END() 18 | 19 | #endif // EVENTS_H 20 | -------------------------------------------------------------------------------- /src/gp3d/helpers/FirstPersonCamera.cpp: -------------------------------------------------------------------------------- 1 | #include "FirstPersonCamera.h" 2 | 3 | static const unsigned int MOVE_FORWARD = 1; 4 | static const unsigned int MOVE_BACKWARD = 2; 5 | static const unsigned int MOVE_LEFT = 4; 6 | static const unsigned int MOVE_RIGHT = 8; 7 | static const unsigned int MOVE_UP = 16; 8 | static const unsigned int MOVE_DOWN = 32; 9 | static const float MOVE_SPEED = 15.0f; 10 | static const float UP_DOWN_SPEED = 10.0f; 11 | 12 | 13 | namespace gplay { 14 | 15 | FirstPersonCamera::FirstPersonCamera() 16 | : _pitchNode(NULL), _rootNode(NULL) 17 | , _moveFlags(0), _prevX(0), _prevY(0), _buttonPressed(false) 18 | { 19 | 20 | } 21 | 22 | FirstPersonCamera::~FirstPersonCamera() 23 | { 24 | SAFE_RELEASE(_pitchNode); 25 | SAFE_RELEASE(_rootNode); 26 | } 27 | 28 | void FirstPersonCamera::initialize(float nearPlane, float farPlane, float fov) 29 | { 30 | SAFE_RELEASE(_pitchNode); 31 | SAFE_RELEASE(_rootNode); 32 | _rootNode = Node::create("FirstPersonCamera_root"); 33 | _pitchNode = Node::create("FirstPersonCamera_pitch"); 34 | _rootNode->addChild(_pitchNode); 35 | 36 | float aspectRatio = Game::getInstance()->getAspectRatio(); 37 | assert(aspectRatio > 0.0f); 38 | Camera* camera = Camera::createPerspective(fov, aspectRatio, nearPlane, farPlane); 39 | _pitchNode->setCamera(camera); 40 | SAFE_RELEASE(camera); 41 | } 42 | 43 | Node* FirstPersonCamera::getRootNode() 44 | { 45 | return _rootNode; 46 | } 47 | 48 | Camera* FirstPersonCamera::getCamera() 49 | { 50 | if (_pitchNode) 51 | return _pitchNode->getCamera(); 52 | return NULL; 53 | } 54 | 55 | void FirstPersonCamera::setPosition(const Vector3& position) 56 | { 57 | _rootNode->setTranslation(position); 58 | } 59 | 60 | void FirstPersonCamera::moveForward(float amount) 61 | { 62 | Vector3 v = _pitchNode->getForwardVectorWorld(); 63 | v.normalize().scale(amount); 64 | _rootNode->translate(v); 65 | } 66 | 67 | void FirstPersonCamera::moveBackward(float amount) 68 | { 69 | moveForward(-amount); 70 | } 71 | 72 | void FirstPersonCamera::moveLeft(float amount) 73 | { 74 | _rootNode->translateLeft(amount); 75 | } 76 | 77 | void FirstPersonCamera::moveRight(float amount) 78 | { 79 | _rootNode->translateLeft(-amount); 80 | } 81 | 82 | void FirstPersonCamera::moveUp(float amount) 83 | { 84 | _rootNode->translateUp(amount); 85 | } 86 | 87 | void FirstPersonCamera::moveDown(float amount) 88 | { 89 | _rootNode->translateUp(-amount); 90 | } 91 | 92 | void FirstPersonCamera::rotate(float yaw, float pitch) 93 | { 94 | _rootNode->rotateY(-yaw); 95 | _pitchNode->rotateX(pitch); 96 | } 97 | 98 | bool FirstPersonCamera::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta) 99 | { 100 | switch (evt) 101 | { 102 | case Mouse::MOUSE_WHEEL: 103 | moveForward(wheelDelta * MOVE_SPEED / 2.0f ); 104 | return true; 105 | 106 | case Mouse::MOUSE_PRESS_RIGHT_BUTTON: 107 | touchEvent(Touch::TOUCH_PRESS,x,y,0); 108 | return true; 109 | 110 | case Mouse::MOUSE_RELEASE_RIGHT_BUTTON: 111 | touchEvent(Touch::TOUCH_RELEASE,x,y,0); 112 | return true; 113 | 114 | case Mouse::MOUSE_MOVE: 115 | touchEvent(Touch::TOUCH_MOVE,x,y,0); 116 | return true; 117 | 118 | default: 119 | return false; 120 | } 121 | return false; 122 | } 123 | 124 | 125 | void FirstPersonCamera::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex) 126 | { 127 | switch (evt) 128 | { 129 | case Touch::TOUCH_PRESS: 130 | { 131 | _prevX = x; 132 | _prevY = y; 133 | break; 134 | } 135 | case Touch::TOUCH_RELEASE: 136 | { 137 | _prevX = 0; 138 | _prevY = 0; 139 | break; 140 | } 141 | case Touch::TOUCH_MOVE: 142 | { 143 | int deltaX = x - _prevX; 144 | int deltaY = y - _prevY; 145 | _prevX = x; 146 | _prevY = y; 147 | float pitch = -MATH_DEG_TO_RAD(deltaY * 0.5f); 148 | float yaw = MATH_DEG_TO_RAD(deltaX * 0.5f); 149 | rotate(yaw, pitch); 150 | break; 151 | } 152 | }; 153 | } 154 | 155 | void FirstPersonCamera::clearMoveFlag() 156 | { 157 | _moveFlags = 0; 158 | } 159 | 160 | void FirstPersonCamera::updateCamera(float elapsedTime) 161 | { 162 | float time = (float)elapsedTime / 1000.0f; 163 | 164 | Vector2 move; 165 | 166 | if (_moveFlags != 0) 167 | { 168 | // Forward motion 169 | if (_moveFlags & MOVE_FORWARD) 170 | { 171 | move.y = 1; 172 | } 173 | else if (_moveFlags & MOVE_BACKWARD) 174 | { 175 | move.y = -1; 176 | } 177 | // Strafing 178 | if (_moveFlags & MOVE_LEFT) 179 | { 180 | move.x = 1; 181 | } 182 | else if (_moveFlags & MOVE_RIGHT) 183 | { 184 | move.x = -1; 185 | } 186 | move.normalize(); 187 | 188 | // Up and down 189 | if (_moveFlags & MOVE_UP) 190 | { 191 | moveUp(time * UP_DOWN_SPEED); 192 | } 193 | else if (_moveFlags & MOVE_DOWN) 194 | { 195 | moveDown(time * UP_DOWN_SPEED); 196 | } 197 | } 198 | /*else if (_gamepad->getJoystickCount() > 0) 199 | { 200 | _gamepad->getJoystickValues(0, &move); 201 | move.x = -move.x; 202 | } 203 | if (_gamepad->getJoystickCount() > 1) 204 | { 205 | Vector2 joy2; 206 | _gamepad->getJoystickValues(1, &joy2); 207 | _fpCamera.rotate(MATH_DEG_TO_RAD(joy2.x * 2.0f), MATH_DEG_TO_RAD(joy2.y * 2.0f)); 208 | }*/ 209 | 210 | if (!move.isZero()) 211 | { 212 | move.scale(time * MOVE_SPEED); 213 | moveForward(move.y); 214 | moveLeft(move.x); 215 | } 216 | 217 | /*if (!_buttonPressed && _gamepad->isButtonDown(Gamepad::BUTTON_A)) 218 | { 219 | addSound("footsteps.wav"); 220 | } 221 | _buttonPressed = _gamepad->isButtonDown(Gamepad::BUTTON_A);*/ 222 | } 223 | 224 | void FirstPersonCamera::keyEvent(Keyboard::KeyEvent evt, int key) 225 | { 226 | if (evt == Keyboard::KEY_PRESS) 227 | { 228 | switch (key) 229 | { 230 | case Keyboard::KEY_W: 231 | _moveFlags |= MOVE_FORWARD; 232 | break; 233 | case Keyboard::KEY_S: 234 | _moveFlags |= MOVE_BACKWARD; 235 | break; 236 | case Keyboard::KEY_A: 237 | _moveFlags |= MOVE_LEFT; 238 | break; 239 | case Keyboard::KEY_D: 240 | _moveFlags |= MOVE_RIGHT; 241 | break; 242 | 243 | case Keyboard::KEY_Q: 244 | _moveFlags |= MOVE_DOWN; 245 | break; 246 | case Keyboard::KEY_E: 247 | _moveFlags |= MOVE_UP; 248 | break; 249 | case Keyboard::KEY_PG_UP: 250 | rotate(0, MATH_PIOVER4); 251 | break; 252 | case Keyboard::KEY_PG_DOWN: 253 | rotate(0, -MATH_PIOVER4); 254 | break; 255 | } 256 | } 257 | else if (evt == Keyboard::KEY_RELEASE) 258 | { 259 | switch (key) 260 | { 261 | case Keyboard::KEY_W: 262 | _moveFlags &= ~MOVE_FORWARD; 263 | break; 264 | case Keyboard::KEY_S: 265 | _moveFlags &= ~MOVE_BACKWARD; 266 | break; 267 | case Keyboard::KEY_A: 268 | _moveFlags &= ~MOVE_LEFT; 269 | break; 270 | case Keyboard::KEY_D: 271 | _moveFlags &= ~MOVE_RIGHT; 272 | break; 273 | case Keyboard::KEY_Q: 274 | _moveFlags &= ~MOVE_DOWN; 275 | break; 276 | case Keyboard::KEY_E: 277 | _moveFlags &= ~MOVE_UP; 278 | break; 279 | } 280 | } 281 | } 282 | 283 | 284 | 285 | } 286 | 287 | -------------------------------------------------------------------------------- /src/gp3d/helpers/FirstPersonCamera.h: -------------------------------------------------------------------------------- 1 | #ifndef FIRSTPERSONCAMERA_H_ 2 | #define FIRSTPERSONCAMERA_H_ 3 | 4 | #include 5 | 6 | namespace gplay { 7 | 8 | /** 9 | * FirstPersonCamera controls a camera like a first person shooter game. 10 | */ 11 | class FirstPersonCamera 12 | { 13 | public: 14 | 15 | /** 16 | * Constructor. 17 | */ 18 | FirstPersonCamera(); 19 | 20 | /** 21 | * Destructor. 22 | */ 23 | ~FirstPersonCamera(); 24 | 25 | /** 26 | * Initializes the first person camera. Should be called after the Game has been initialized. 27 | */ 28 | void initialize(float nearPlane = 1.0f, float farPlane = 1000.0f, float fov = 45.0f); 29 | 30 | /** 31 | * Gets root node. May be NULL if not initialized. 32 | * 33 | * @return Root node or NULL. 34 | */ 35 | Node* getRootNode(); 36 | 37 | /** 38 | * Gets the camera. May be NULL. 39 | * 40 | * @return Camera or NULL. 41 | */ 42 | Camera* getCamera(); 43 | 44 | /** 45 | * Sets the position of the camera. 46 | * 47 | * @param position The position to move to. 48 | */ 49 | void setPosition(const Vector3& position); 50 | 51 | /** 52 | * Moves the camera forward in the direction that it is pointing. (Fly mode) 53 | */ 54 | void moveForward(float amount); 55 | 56 | /** 57 | * Moves the camera in the opposite direction that it is pointing. 58 | */ 59 | void moveBackward(float amount); 60 | 61 | /** 62 | * Strafes that camera left, which is perpendicular to the direction it is facing. 63 | */ 64 | void moveLeft(float amount); 65 | 66 | /** 67 | * Strafes that camera right, which is perpendicular to the direction it is facing. 68 | */ 69 | void moveRight(float amount); 70 | 71 | void moveUp(float amount); 72 | 73 | void moveDown(float amount); 74 | 75 | /** 76 | * Rotates the camera in place in order to change the direction it is looking. 77 | * 78 | * @param yaw Rotates the camera around the yaw axis in radians. Positive looks right, negative looks left. 79 | * @param pitch Rotates the camera around the ptich axis in radians. Positive looks up, negative looks down. 80 | */ 81 | void rotate(float yaw, float pitch); 82 | 83 | 84 | 85 | void touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex); 86 | void keyEvent(Keyboard::KeyEvent evt, int key); 87 | bool mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta); 88 | void updateCamera(float elapsedTime); 89 | void clearMoveFlag(); 90 | 91 | private: 92 | 93 | Node* _pitchNode; 94 | Node* _rootNode; 95 | 96 | unsigned int _moveFlags; 97 | int _prevX; 98 | int _prevY; 99 | bool _buttonPressed; 100 | }; 101 | 102 | } 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /src/gp3d/helpers/Grid.cpp: -------------------------------------------------------------------------------- 1 | #include "Grid.h" 2 | 3 | Mesh* createGridMesh(unsigned int lineCount) 4 | { 5 | // There needs to be an odd number of lines 6 | lineCount |= 1; 7 | const unsigned int pointCount = lineCount * 4; 8 | const unsigned int verticesSize = pointCount * (3 + 3); 9 | 10 | std::vector vertices; 11 | vertices.resize(verticesSize); 12 | 13 | const float gridLength = (float)(lineCount / 2); 14 | float value = -gridLength; 15 | for (unsigned int i = 0; i < verticesSize; ++i) 16 | { 17 | // Default line color is dark grey 18 | Vector4 color(0.3f, 0.3f, 0.3f, 1.0f); 19 | 20 | // Very 10th line is brighter grey 21 | if (((int)value) % 10 == 0) 22 | { 23 | color.set(0.45f, 0.45f, 0.45f, 1.0f); 24 | } 25 | 26 | // The Z axis is blue 27 | if (value == 0.0f) 28 | { 29 | color.set(0.15f, 0.15f, 0.7f, 1.0f); 30 | } 31 | 32 | // Build the lines 33 | vertices[i] = value; 34 | vertices[++i] = 0.0f; 35 | vertices[++i] = -gridLength; 36 | vertices[++i] = color.x; 37 | vertices[++i] = color.y; 38 | vertices[++i] = color.z; 39 | 40 | vertices[++i] = value; 41 | vertices[++i] = 0.0f; 42 | vertices[++i] = gridLength; 43 | vertices[++i] = color.x; 44 | vertices[++i] = color.y; 45 | vertices[++i] = color.z; 46 | 47 | // The X axis is red 48 | if (value == 0.0f) 49 | { 50 | color.set(0.7f, 0.15f, 0.15f, 1.0f); 51 | } 52 | vertices[++i] = -gridLength; 53 | vertices[++i] = 0.0f; 54 | vertices[++i] = value; 55 | vertices[++i] = color.x; 56 | vertices[++i] = color.y; 57 | vertices[++i] = color.z; 58 | 59 | vertices[++i] = gridLength; 60 | vertices[++i] = 0.0f; 61 | vertices[++i] = value; 62 | vertices[++i] = color.x; 63 | vertices[++i] = color.y; 64 | vertices[++i] = color.z; 65 | 66 | value += 1.0f; 67 | } 68 | VertexFormat::Element elements[] = 69 | { 70 | VertexFormat::Element(VertexFormat::POSITION, 3), 71 | VertexFormat::Element(VertexFormat::COLOR, 3) 72 | }; 73 | Mesh* mesh = Mesh::createMesh(VertexFormat(elements, 2), pointCount, false); 74 | if (mesh == NULL) 75 | { 76 | return NULL; 77 | } 78 | mesh->setPrimitiveType(Mesh::LINES); 79 | mesh->setVertexData(&vertices[0], 0, pointCount); 80 | 81 | return mesh; 82 | } 83 | 84 | Model* createGridModel(unsigned int lineCount) 85 | { 86 | Mesh* mesh = createGridMesh(lineCount); 87 | if (!mesh) 88 | return NULL; 89 | 90 | Model* model = Model::create(mesh); 91 | mesh->release(); 92 | assert(model); 93 | return model; 94 | } 95 | -------------------------------------------------------------------------------- /src/gp3d/helpers/Grid.h: -------------------------------------------------------------------------------- 1 | #ifndef GRID_H_ 2 | #define GRID_H_ 3 | 4 | #include 5 | 6 | using namespace gplay; 7 | 8 | static const unsigned int DEFAULT_LINE_COUNT = 81; 9 | 10 | /** 11 | * Creates a new grid mesh. 12 | * 13 | * @param lineCount The number of lines in the grid. (Rows or columns). Should be odd. 14 | * 15 | * @return A new grid mesh or NULL if there was an error. 16 | */ 17 | Mesh* createGridMesh(unsigned int lineCount = DEFAULT_LINE_COUNT); 18 | 19 | /** 20 | * Creates a model that contains a new grid mesh. 21 | * 22 | * @param lineCount The number of lines in the grid. (Rows or columns). Should be odd. 23 | * 24 | * @return A new model containing a grid mesh or NULL if there was an error. 25 | */ 26 | Model* createGridModel(unsigned int lineCount = DEFAULT_LINE_COUNT); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "MainWindow.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char **argv) 8 | { 9 | gplay::Platform::setArguments(&argc, &argv); 10 | 11 | QApplication app(argc, argv); 12 | QCoreApplication::setOrganizationName("fredakilla"); 13 | QCoreApplication::setApplicationName("gplay-editor"); 14 | QCoreApplication::setApplicationVersion(QT_VERSION_STR); 15 | 16 | qApp->setStyle(QStyleFactory::create("Fusion")); 17 | 18 | QPalette darkPalette; 19 | darkPalette.setColor(QPalette::Window, QColor(53,53,53)); 20 | darkPalette.setColor(QPalette::WindowText, Qt::white); 21 | darkPalette.setColor(QPalette::Base, QColor(25,25,25)); 22 | darkPalette.setColor(QPalette::AlternateBase, QColor(53,53,53)); 23 | darkPalette.setColor(QPalette::ToolTipBase, Qt::white); 24 | darkPalette.setColor(QPalette::ToolTipText, Qt::white); 25 | darkPalette.setColor(QPalette::Text, Qt::white); 26 | darkPalette.setColor(QPalette::Button, QColor(53,53,53)); 27 | darkPalette.setColor(QPalette::ButtonText, Qt::white); 28 | darkPalette.setColor(QPalette::BrightText, Qt::red); 29 | darkPalette.setColor(QPalette::Link, QColor(42, 130, 218)); 30 | darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); 31 | darkPalette.setColor(QPalette::HighlightedText, Qt::black); 32 | qApp->setPalette(darkPalette); 33 | 34 | MainWindow mainWindow; 35 | mainWindow.showMaximized(); 36 | 37 | int ret = app.exec(); 38 | 39 | return ret; 40 | } 41 | -------------------------------------------------------------------------------- /src/node-editor/common/BaseNode.cpp: -------------------------------------------------------------------------------- 1 | #include "BaseNode.h" 2 | 3 | BaseNode::BaseNode() : _paramWidget(nullptr) 4 | { 5 | } 6 | 7 | BaseNode::~BaseNode() 8 | { 9 | } 10 | 11 | unsigned int BaseNode::nPorts(PortType portType) const 12 | { 13 | if(portType == PortType::In) 14 | { 15 | return _inputs.size(); 16 | } 17 | else if(portType == PortType::Out) 18 | { 19 | return _outputs.size(); 20 | } 21 | else 22 | { 23 | return 0; 24 | } 25 | } 26 | 27 | QString BaseNode::portCaption(PortType portType, PortIndex portIndex) const 28 | { 29 | if(portType == PortType::In) 30 | { 31 | Q_ASSERT((size_t)portIndex < _inputs.size()); 32 | return _inputs[portIndex]->name; 33 | } 34 | else if(portType == PortType::Out) 35 | { 36 | Q_ASSERT((size_t)portIndex < _outputs.size()); 37 | return _outputs[portIndex]->name; 38 | } 39 | else 40 | { 41 | return QString(""); 42 | } 43 | } 44 | 45 | 46 | NodeDataType BaseNode::dataType(PortType portType, PortIndex portIndex) const 47 | { 48 | if(portType == PortType::In) 49 | { 50 | return _inputs[portIndex]->dataType; 51 | } 52 | else if(portType == PortType::Out) 53 | { 54 | return _outputs[portIndex]->dataType; 55 | } 56 | else 57 | { 58 | return NODE_DATA_TYPE[EPT_NONE]; 59 | } 60 | } 61 | 62 | void BaseNode::setInData(std::shared_ptr nodeData, PortIndex portIndex) 63 | { 64 | _inputs[portIndex]->data = nodeData; 65 | process(); 66 | } 67 | 68 | unsigned int BaseNode::getParameterCount() 69 | { 70 | return (unsigned int)_parameters.size(); 71 | } 72 | 73 | Parameter* BaseNode::getParameter(unsigned int index) 74 | { 75 | if(index > getParameterCount()) 76 | return nullptr; 77 | 78 | return _parameters.at(index); 79 | } 80 | 81 | Parameter* BaseNode::getParameter(const QString name) 82 | { 83 | for (auto p : _parameters) 84 | { 85 | if(p->name == name) 86 | return p; 87 | } 88 | 89 | qFatal("FATAL error : Parameter '%s' does not exists in '%s' Node", 90 | name.toStdString().c_str(), 91 | this->Name().toStdString().c_str() 92 | ); 93 | 94 | return nullptr; 95 | } 96 | 97 | NodeValidationState BaseNode::validationState() const 98 | { 99 | // check if _paramWidget was created when node has paramaters. 100 | // if fatal error, you miss to call createParamWidgets() in the node constructor. 101 | if(_parameters.size() > 0 && _paramWidget == nullptr) 102 | { 103 | //qFatal("Fatal: _paramWidget was not created for node '%s'", Name().toStdString().c_str()); 104 | // or 105 | // force it here ?? (may be issues when serialize ?? to test...) 106 | //qWarning("Warning: _paramWidget was not created for node '%s'", Name().toStdString().c_str()); 107 | (const_cast(this))->createParamWidgets(); 108 | } 109 | 110 | return modelValidationState; 111 | } 112 | 113 | QString BaseNode::validationMessage() const 114 | { 115 | return modelValidationError; 116 | } 117 | -------------------------------------------------------------------------------- /src/node-editor/common/BaseNode.h: -------------------------------------------------------------------------------- 1 | #ifndef BASENODE_H 2 | #define BASENODE_H 3 | 4 | #include 5 | #include "ParamWidget.h" 6 | #include "Parameter.h" 7 | #include "Types.h" 8 | #include 9 | #include 10 | #include "Path.h" 11 | 12 | using QtNodes::NodeDataModel; 13 | using QtNodes::NodeDataType; 14 | using QtNodes::NodeData; 15 | using QtNodes::PortType; 16 | using QtNodes::PortIndex; 17 | using QtNodes::Port; 18 | using QtNodes::NodeValidationState; 19 | 20 | 21 | enum NodeClass 22 | { 23 | ENC_SYSTEM, 24 | ENC_GROUP, 25 | ENC_EMITTER, 26 | ENC_ZONE, 27 | ENC_RENDERER, 28 | ENC_MODIFIER, 29 | ENC_COLORINTERPOLATOR, 30 | ENC_PARAMINTERPOLATOR, 31 | ENC_PATH, 32 | }; 33 | 34 | static const NodeDataType NODE_DATA_TYPE[] = 35 | { 36 | { "system" , "system" }, 37 | { "group" , "group" }, 38 | { "emitter" , "emitter" }, 39 | { "zone" , "zone" }, 40 | { "renderer" , "renderer" }, 41 | { "modifier" , "modifier" }, 42 | { "colorinterpolator" , "colorinterpolator" }, 43 | { "paraminterpolator" , "paraminterpolator" }, 44 | { "path" , "path" }, 45 | }; 46 | 47 | 48 | //---------------------------------------------------------------------------------------------- 49 | // ePort 50 | //---------------------------------------------------------------------------------------------- 51 | struct ePort 52 | { 53 | PortType type; 54 | NodeDataType dataType; 55 | QString name; 56 | std::shared_ptr data; 57 | NodeClass nodeClass; 58 | 59 | ePort() {} 60 | 61 | ePort(PortType type, NodeDataType dataType, QString name, NodeClass nodeClass) : 62 | type(type), dataType(dataType), name(name), nodeClass(nodeClass) 63 | { 64 | //dataType = NODE_DATA_TYPE[paramType]; 65 | } 66 | }; 67 | 68 | //---------------------------------------------------------------------------------------------- 69 | // Base class for nodes 70 | //---------------------------------------------------------------------------------------------- 71 | class BaseNode : public NodeDataModel 72 | { 73 | Q_OBJECT 74 | 75 | public: 76 | BaseNode(); 77 | virtual ~BaseNode(); 78 | virtual void process() {} 79 | virtual void init() { process(); } 80 | unsigned int getParameterCount(); 81 | Parameter* getParameter(unsigned int index); 82 | Parameter* getParameter(const QString name); 83 | 84 | protected: 85 | virtual const QString Name() const = 0; 86 | QString name() const override { return Name(); } 87 | QString caption() const override { return Name(); } 88 | virtual bool captionVisible() const override { return true; } 89 | virtual bool portCaptionVisible(PortType, PortIndex) const override { return true; } 90 | QString portCaption(PortType portType, PortIndex portIndex) const override; 91 | unsigned int nPorts(PortType portType) const override; 92 | NodeDataType dataType(PortType portType, PortIndex portIndex) const override; 93 | void setInData(std::shared_ptr nodeData, PortIndex portIndex) override; 94 | virtual QWidget* embeddedWidget() override { return _paramWidget; } 95 | void createParamWidgets() { _paramWidget = new ParamWidget(this); } 96 | 97 | template 98 | void addParameter(ParamType type, QString name, float min, float max, T value) 99 | { 100 | Parameter* p = new Parameter(type, name, min, max, this); 101 | p->baseValue = (T)value; 102 | _parameters.push_back(p); 103 | } 104 | 105 | template 106 | std::shared_ptr getInput(unsigned int portIndex) 107 | { 108 | Q_ASSERT(portIndex < _inputs.size()); 109 | Q_ASSERT(_inputs[portIndex]->nodeClass == T::metatype()); 110 | std::shared_ptr ptr = std::dynamic_pointer_cast(_inputs[portIndex]->data); 111 | return ptr; 112 | } 113 | 114 | protected: 115 | std::vector _inputs; 116 | std::vector _outputs; 117 | ParamWidget* _paramWidget; 118 | std::vector _parameters; 119 | 120 | protected: 121 | NodeValidationState modelValidationState = NodeValidationState::Valid; 122 | QString modelValidationError = QString("ok"); 123 | NodeValidationState validationState() const; 124 | QString validationMessage() const; 125 | void setValidationState(NodeValidationState state, const QString& msg = "") 126 | { 127 | modelValidationState = state; 128 | modelValidationError = msg; 129 | } 130 | 131 | QJsonObject save() const override 132 | { 133 | QJsonObject modelJson = NodeDataModel::save(); 134 | 135 | if(_paramWidget) 136 | _paramWidget->save(modelJson); 137 | 138 | return modelJson; 139 | } 140 | 141 | void restore(QJsonObject const &p) override 142 | { 143 | if(_paramWidget) 144 | _paramWidget->restore(p); 145 | } 146 | 147 | 148 | public Q_SLOTS: 149 | virtual void onParameterChanged() 150 | { 151 | process(); 152 | Q_EMIT(dataUpdated(0)); 153 | } 154 | }; 155 | 156 | 157 | //---------------------------------------------------------------------------------------------- 158 | // add input/output macros 159 | //---------------------------------------------------------------------------------------------- 160 | #define IN_PORT(datatype, label) \ 161 | _inputs.push_back(new ePort(PortType::In, NODE_DATA_TYPE[datatype], QString(label), datatype)); 162 | 163 | #define OUT_PORT(datatype, label) \ 164 | _outputs.push_back(new ePort(PortType::Out, NODE_DATA_TYPE[datatype], QString(label), datatype)); 165 | 166 | 167 | //---------------------------------------------------------------------------------------------- 168 | // add parameter macros 169 | //---------------------------------------------------------------------------------------------- 170 | #define PARAM_TEXT(name, label) \ 171 | addParameter(EPT_TEXT, name, 0, 0, QString(label)) 172 | 173 | #define PARAM_STRING(name, label) \ 174 | addParameter(EPT_STRING, name, 0, 0, QString(label)) 175 | 176 | #define PARAM_BOOL(name, boolean) \ 177 | addParameter(EPT_BOOL, name, 0, 0, (bool)boolean) 178 | 179 | #define PARAM_INT(name, min, max, v) \ 180 | addParameter(EPT_INT, name, min, max, (eInt)v) 181 | 182 | #define PARAM_FLOAT(name, min, max, f) \ 183 | addParameter(EPT_FLOAT, name, min, max, (eF32)f) 184 | 185 | #define PARAM_FXY(name, min, max, x, y) \ 186 | addParameter(EPT_FXY, name, min, max, eFXY((eF32)x, (eF32)y)) 187 | 188 | #define PARAM_FXYZ(name, min, max, x, y, z) \ 189 | addParameter(EPT_FXYZ, name, min, max, eFXYZ((eF32)x, (eF32)y, (eF32)z)) 190 | 191 | #define PARAM_FXYZW(name, min, max, x, y, z, w) \ 192 | addParameter(EPT_FXYZW, name, min, max, eFXYZW((eF32)x, (eF32)y, (eF32)z, (eF32)w)) 193 | 194 | #define PARAM_IXY(name, min, max, x, y) \ 195 | addParameter(EPT_IXY, name, min, max, eIXY((eInt)x, (eInt)y)) 196 | 197 | #define PARAM_IXYZ(name, min, max, x, y, z) \ 198 | addParameter(EPT_IXYZ, name, min, max, eIXYZ((eInt)x, (eInt)y, (eInt)z)) 199 | 200 | #define PARAM_IXYZW(name, min, max, x, y, z, w) \ 201 | addParameter(EPT_IXYZW, name, min, max, eIXYZW((eInt)x, (eInt)y, (eInt)z, (eInt)w)) 202 | 203 | #define PARAM_ENUM(name, descr, index) \ 204 | addParameter(EPT_ENUM, name, 0, 255, (eF32)index); \ 205 | _parameters.back()->setDescription(descr) 206 | 207 | #define PARAM_FILE(name, path) \ 208 | addParameter(EPT_FILE, name, 0, 0, QString(path)); 209 | 210 | #define PARAM_FLAGS(name, descr, index) \ 211 | addParameter(EPT_FLAGS, name, 0, 255, (unsigned char)(index)); \ 212 | _parameters.back()->setDescription(descr); 213 | 214 | #define PARAM_RGBA(name, r, g, b, a) \ 215 | addParameter(EPT_RGBA, name, 0, 255, eColor(r,g,b,a)); 216 | 217 | #define PARAM_BUTTON(name, label) \ 218 | addParameter(EPT_BUTTON, name, 0, 0, QString(label)) 219 | 220 | //---------------------------------------------------------------------------------------------- 221 | // base class for every spark nodes 222 | //---------------------------------------------------------------------------------------------- 223 | class NodeSparkBaseNode : public BaseNode 224 | { 225 | protected: 226 | void createBaseObjectParams(eString name, bool shared = false) 227 | { 228 | PARAM_STRING("Name", name); 229 | PARAM_BOOL("Shared", shared); 230 | } 231 | 232 | void setBaseObjectParams(SPK::Ref object) 233 | { 234 | object->setName(getParameter("Name")->baseValue.get().toStdString()); 235 | object->setShared(getParameter("Shared")->baseValue.get()); 236 | } 237 | }; 238 | 239 | 240 | //---------------------------------------------------------------------------------------------- 241 | // NodeData template 242 | //---------------------------------------------------------------------------------------------- 243 | template 244 | class MyNodeData : public NodeData 245 | { 246 | public: 247 | MyNodeData() {} 248 | MyNodeData(T result) : _result(result) {} 249 | NodeDataType type() const override { return NODE_DATA_TYPE[C]; } 250 | static NodeClass metatype() { return C; } 251 | T _result; 252 | }; 253 | 254 | //---------------------------------------------------------------------------------------------- 255 | // specialize template NodeData 256 | //---------------------------------------------------------------------------------------------- 257 | typedef MyNodeData, ENC_SYSTEM> NodeDataSparkSystem; 258 | typedef MyNodeData>, ENC_GROUP> NodeDataSparkGroupList; 259 | typedef MyNodeData>, ENC_EMITTER> NodeDataSparkEmitterList; 260 | typedef MyNodeData, ENC_RENDERER> NodeDataSparkRenderer; 261 | typedef MyNodeData, ENC_ZONE> NodeDataSparkZone; 262 | typedef MyNodeData>, ENC_MODIFIER> NodeDataSparkModifierList; 263 | 264 | struct ParamFloatInterpolator 265 | { 266 | SPK::Param param; 267 | SPK::Ref> interpolatorFloat; 268 | }; 269 | 270 | typedef MyNodeData>, ENC_COLORINTERPOLATOR> NodeDataSparkColorInterpolator; 271 | typedef MyNodeData, ENC_PARAMINTERPOLATOR> NodeDataSparkParamInterpolatorList; 272 | 273 | typedef MyNodeData NodeDataPath; 274 | 275 | 276 | 277 | #include "../spark-nodes/SpkUtils.h" 278 | 279 | 280 | 281 | #endif // BASENODE_H 282 | -------------------------------------------------------------------------------- /src/node-editor/common/Color.cpp: -------------------------------------------------------------------------------- 1 | #include "Color.h" 2 | 3 | eColor::eColor() : r(0), g(0), b(0), a(255) 4 | { 5 | } 6 | 7 | eColor::eColor(eU8 nr, eU8 ng, eU8 nb, eU8 na) : r(nr), g(ng), b(nb), a(na) 8 | { 9 | } 10 | 11 | eColor::eColor(eColorConst cc) 12 | { 13 | static const eColor colors[] = 14 | { 15 | eColor(255, 0, 0), // red 16 | eColor( 0, 255, 0), // green 17 | eColor( 0, 0, 255), // blue 18 | eColor(215, 108, 0), // orange 19 | eColor(255, 255, 0), // yellow 20 | eColor(255, 0, 255), // purple 21 | eColor( 0, 255, 255), // cyan 22 | eColor(255, 0, 128), // pink 23 | eColor(255, 255, 255), // white 24 | eColor( 0, 0, 0), // black 25 | eColor(128, 128, 128), // gray 26 | eColor( 64, 64, 64), // dark gray 27 | eColor(204, 204, 204), // light gray 28 | }; 29 | 30 | *this = colors[cc]; 31 | } 32 | 33 | void eColor::set(eU8 nr, eU8 ng, eU8 nb) 34 | { 35 | r = nr; 36 | g = ng; 37 | b = nb; 38 | } 39 | 40 | void eColor::set(eU8 nr, eU8 ng, eU8 nb, eU8 na) 41 | { 42 | set(nr, ng, nb); 43 | a = na; 44 | } 45 | 46 | eU8 eColor::grayScale() const 47 | { 48 | return (r*11+g*16+b*5)/32; 49 | } 50 | 51 | void eColor::toGrayScale() 52 | { 53 | const eU8 gray = grayScale(); 54 | r = gray; 55 | g = gray; 56 | b = gray; 57 | } 58 | 59 | void eColor::scale (const eColor &c) 60 | { 61 | r = r*c.r/255; 62 | g = g*c.g/255; 63 | b = b*c.b/255; 64 | a = a*c.a/255; 65 | } 66 | 67 | eColor eColor::operator + (const eColor &c) const 68 | { 69 | return eColor(eMin((eInt)(r+c.r), 255), 70 | eMin((eInt)(g+c.g), 255), 71 | eMin((eInt)(b+c.b), 255), 72 | eMin((eInt)(a+c.a), 255)); 73 | } 74 | 75 | eColor eColor::operator - (const eColor &c) const 76 | { 77 | return eColor(eMax(0, (eInt)(r-c.r)), 78 | eMax(0, (eInt)(g-c.g)), 79 | eMax(0, (eInt)(b-c.b)), 80 | eMax(0, (eInt)(a-c.a))); 81 | } 82 | 83 | eColor eColor::operator * (eF32 s) const 84 | { 85 | eASSERT(s >= 0.0f); 86 | 87 | return eColor(eMin(eFtoL((eF32)r*s), 255), 88 | eMin(eFtoL((eF32)g*s), 255), 89 | eMin(eFtoL((eF32)b*s), 255), 90 | eMin(eFtoL((eF32)a*s), 255)); 91 | } 92 | 93 | eColor & eColor::operator += (const eColor &c) 94 | { 95 | *this = *this+c; 96 | return *this; 97 | } 98 | 99 | eColor & eColor::operator -= (const eColor &c) 100 | { 101 | *this = *this-c; 102 | return *this; 103 | } 104 | 105 | eColor & eColor::operator *= (eF32 s) 106 | { 107 | *this = *this*s; 108 | return *this; 109 | } 110 | 111 | void eColor::minComponents(const eColor &c) 112 | { 113 | r = eMin(r, c.r); 114 | g = eMin(g, c.g); 115 | b = eMin(b, c.b); 116 | a = eMin(a, c.a); 117 | } 118 | 119 | void eColor::maxComponents(const eColor &c) 120 | { 121 | r = eMax(r, c.r); 122 | g = eMax(g, c.g); 123 | b = eMax(b, c.b); 124 | a = eMax(a, c.a); 125 | } 126 | 127 | void eColor::average(const eColor &c) 128 | { 129 | r = (r+c.r)/2; 130 | g = (g+c.g)/2; 131 | b = (b+c.b)/2; 132 | a = (a+c.a)/2; 133 | } 134 | 135 | void eColor::difference(const eColor &c) 136 | { 137 | r = eAbs(r-c.r); 138 | g = eAbs(g-c.g); 139 | b = eAbs(b-c.b); 140 | a = eAbs(a-c.a); 141 | } 142 | 143 | // linear interpolation (0 <= t <= 1) 144 | eColor eColor::lerp(const eColor &to, eF32 t) const 145 | { 146 | eASSERT(t >= 0.0f && t <= 1.0f); 147 | 148 | return eColor(eFtoL(eLerp((eF32)r, (eF32)to.r, t)), 149 | eFtoL(eLerp((eF32)g, (eF32)to.g, t)), 150 | eFtoL(eLerp((eF32)b, (eF32)to.b, t)), 151 | eFtoL(eLerp((eF32)a, (eF32)to.a, t))); 152 | } 153 | 154 | eU32 eColor::toArgb() const // a MSB, b LSB 155 | { 156 | // swaps R und B channels 157 | eU32 argb = abgr&0xff00ff00; 158 | argb |= ((abgr&0x00ff0000)>>16); 159 | argb |= ((abgr&0x000000ff)<<16); 160 | return argb; 161 | } 162 | 163 | const eU8 & eColor::operator [] (eInt index) const 164 | { 165 | eASSERT(index < 4); 166 | return ((eU8 *)this)[index]; 167 | } 168 | 169 | eU8 & eColor::operator [] (eInt index) 170 | { 171 | eASSERT(index < 4); 172 | return ((eU8 *)this)[index]; 173 | } 174 | 175 | eBool eColor::operator == (const eColor &c) const 176 | { 177 | return (abgr == c.abgr); 178 | } 179 | 180 | eBool eColor::operator != (const eColor &c) const 181 | { 182 | return !(*this == c); 183 | } 184 | 185 | // converts from RGB to HSV color space. the hue 186 | // defines the color. its range is 0..359 if the 187 | // color is chromatic and -1 if the color is 188 | // achromatic. the saturation and value both vary 189 | // between 0 and 255. 190 | void eColor::toHsv(eInt &h, eInt &s, eInt &v) 191 | { 192 | // find maximum channel 193 | eInt max = r; 194 | eInt whatMax = 0; // r => 0, g => 1, b => 2 195 | 196 | if (g > max) 197 | { 198 | max = g; 199 | whatMax = 1; 200 | } 201 | 202 | if (b > max) 203 | { 204 | max = b; 205 | whatMax = 2; 206 | } 207 | 208 | // find minimum channel 209 | const eInt min = eMin(r, eMin(g, b)); 210 | const eInt delta = max-min; 211 | 212 | // calculate HSV values 213 | v = max; 214 | s = max ? (510*delta+max)/(2*max) : 0; 215 | 216 | if (s == 0) 217 | h = -1; // hue is undefined 218 | else 219 | { 220 | switch (whatMax) 221 | { 222 | case 0: // red is max component 223 | if (g >= b) 224 | h = (120*(g-b)+delta)/(2*delta); 225 | else 226 | h = (120*(g-b+delta)+delta)/(2*delta)+300; 227 | break; 228 | 229 | case 1: // green is max component 230 | if (b > r) 231 | h = 120+(120*(b-r)+delta)/(2*delta); 232 | else 233 | h = 60+(120*(b-r+delta)+delta)/(2*delta); 234 | break; 235 | 236 | case 2: // blue is max component 237 | if (r > g) 238 | h = 240+(120*(r-g)+delta)/(2*delta); 239 | else 240 | h = 180+(120*(r-g+delta)+delta)/(2*delta); 241 | break; 242 | } 243 | } 244 | } 245 | 246 | void eColor::fromHsv(eInt h, eInt s, eInt v) 247 | { 248 | if (h < -1 || (eU32)s > 255 || (eU32)v > 255) 249 | return; 250 | 251 | if (s == 0 || h == -1) 252 | set(v, v, v); // ignore achromatic case 253 | else 254 | { 255 | // much more complicated chromatic case 256 | if ((eU32)h >= 360) 257 | h %= 360; 258 | 259 | const eU32 f = h%60; 260 | h /= 60; 261 | const eU32 p = (eU32)(2*v*(255-s)+255)/510; 262 | 263 | if (h&1) 264 | { 265 | const eU32 q = (eU32)(2*v*(15300-s*f)+15300)/30600; 266 | 267 | switch (h) 268 | { 269 | case 1: 270 | set(q, v, p); 271 | break; 272 | 273 | case 3: 274 | set(p, q, v); 275 | break; 276 | 277 | case 5: 278 | set(v, p, q); 279 | break; 280 | } 281 | } 282 | else 283 | { 284 | const eU32 t = (eU32)(2*v*(15300-(s*(60-f)))+15300)/30600; 285 | 286 | switch (h) 287 | { 288 | case 0: 289 | set(v, t, p); 290 | break; 291 | 292 | case 2: 293 | set(p, v, t); 294 | break; 295 | 296 | case 4: 297 | set(t, p, v); 298 | break; 299 | } 300 | } 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /src/node-editor/common/Color.h: -------------------------------------------------------------------------------- 1 | #ifndef COLOR_HPP 2 | #define COLOR_HPP 3 | 4 | #include "Types.h" 5 | 6 | enum eColorConst 7 | { 8 | eCOL_RED, 9 | eCOL_GREEN, 10 | eCOL_BLUE, 11 | eCOL_ORANGE, 12 | eCOL_YELLOW, 13 | eCOL_PURPLE, 14 | eCOL_CYAN, 15 | eCOL_PINK, 16 | eCOL_WHITE, 17 | eCOL_BLACK, 18 | eCOL_GRAY, 19 | eCOL_DARKGRAY, 20 | eCOL_LIGHTGRAY, 21 | }; 22 | 23 | // 8-bit per channel integer color 24 | class eColor 25 | { 26 | public: 27 | eColor(); 28 | eColor(eU8 nr, eU8 ng, eU8 nb, eU8 na=255); 29 | eColor(eColorConst cc); 30 | 31 | void set(eU8 nr, eU8 ng, eU8 nb); 32 | void set(eU8 nr, eU8 ng, eU8 nb, eU8 na); 33 | eU8 grayScale() const; 34 | void toGrayScale(); 35 | void scale (const eColor &c); 36 | void minComponents(const eColor &c); 37 | void maxComponents(const eColor &c); 38 | void average(const eColor &c); 39 | void difference(const eColor &c); 40 | eColor lerp(const eColor &to, eF32 t) const; 41 | eU32 toArgb() const; 42 | 43 | eColor operator + (const eColor &c) const; 44 | eColor operator - (const eColor &c) const; 45 | eColor operator * (eF32 s) const; 46 | eColor & operator += (const eColor &c); 47 | eColor & operator -= (const eColor &c); 48 | eColor & operator *= (eF32 s); 49 | eU8 & operator [] (eInt index); 50 | eBool operator == (const eColor &c) const; 51 | eBool operator != (const eColor &c) const; 52 | 53 | const eU8 & operator [] (eInt index) const; 54 | 55 | friend eColor operator * (eF32 s, const eColor &c) 56 | { 57 | return c*s; 58 | } 59 | 60 | public: 61 | // non-inlinable functions 62 | void toHsv(eInt &h, eInt &s, eInt &v); 63 | void fromHsv(eInt h, eInt s, eInt v); 64 | 65 | public: 66 | union 67 | { 68 | struct 69 | { 70 | eU8 r; // LSB 71 | eU8 g; 72 | eU8 b; 73 | eU8 a; // MSB 74 | }; 75 | 76 | eU32 abgr; 77 | }; 78 | }; 79 | 80 | #endif // COLOR_HPP 81 | -------------------------------------------------------------------------------- /src/node-editor/common/CommentGraphicsItem.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMENTGRAPHICSITEM_H 2 | #define COMMENTGRAPHICSITEM_H 3 | 4 | #include "Types.h" 5 | #include 6 | 7 | #define TYPE_ID_COMMENT 0xFFFF + 1701 8 | 9 | //----------------------------------------------------------------------------------------- 10 | //! eCommentItem 11 | //! A comment graphics item. 12 | //----------------------------------------------------------------------------------------- 13 | class eCommentItem : public QGraphicsTextItem 14 | { 15 | Q_OBJECT 16 | public: 17 | eCommentItem(QGraphicsItem *parent); 18 | 19 | enum { Type = TYPE_ID_COMMENT }; 20 | int type() const { return Type; } 21 | eInt _getTextLength() { return m_realText.length(); } 22 | bool isEdited() { return m_edited; } 23 | 24 | //void saveToXml(QDomElement &node) const; 25 | //void loadFromXml(const QDomElement &node); 26 | QJsonObject save() const; 27 | void restore(QJsonObject const& json); 28 | 29 | protected: 30 | void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); 31 | void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *me); 32 | void mousePressEvent(QGraphicsSceneMouseEvent *me); 33 | void mouseMoveEvent(QGraphicsSceneMouseEvent *me); 34 | void mouseReleaseEvent(QGraphicsSceneMouseEvent *me); 35 | void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); 36 | void hoverEnterEvent(QGraphicsSceneHoverEvent *event); 37 | void hoverMoveEvent(QGraphicsSceneHoverEvent * me); 38 | void focusOutEvent(QFocusEvent *event); 39 | QPainterPath shape() const; 40 | QRectF boundingRect() const; 41 | 42 | private Q_SLOTS: 43 | void _onUpdateSize(const QSizeF newSize); 44 | 45 | private: 46 | void _formatOutput(); 47 | void _init(); 48 | 49 | private: 50 | static const eInt RESIZE_AREA = 10; // default resize area from bottom-right border (in pixels) 51 | QString m_realText; // store real text 52 | eInt m_mode; // text or html mode 53 | QColor m_colorBack; // background color 54 | QColor m_colorText; // text color 55 | eBool m_isResizing; // is resizing 56 | eBool m_edited; // is editing 57 | QPointF m_mouseDownPos; // mouse pos 58 | qreal m_width; // widget width 59 | qreal m_height; // widget height 60 | }; 61 | 62 | #endif // COMMENTGRAPHICSITEM_H 63 | -------------------------------------------------------------------------------- /src/node-editor/common/CustomFlowScene.cpp: -------------------------------------------------------------------------------- 1 | #include "CustomFlowScene.h" 2 | #include "CommentGraphicsItem.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "../spark-nodes/spark-nodes.h" 17 | #include "../../GplayDevice.h" 18 | 19 | 20 | CustomFlowScene::CustomFlowScene(std::shared_ptr registry, QObject * parent) : 21 | FlowScene(registry, parent) 22 | { 23 | _initialize(); 24 | } 25 | 26 | CustomFlowScene::CustomFlowScene(QObject * parent) : 27 | FlowScene(parent) 28 | { 29 | _initialize(); 30 | } 31 | 32 | CustomFlowScene::~CustomFlowScene() 33 | { 34 | delete _commentLayer; 35 | } 36 | 37 | void CustomFlowScene::_initialize() 38 | { 39 | _mousePos = QPoint(0,0); 40 | _commentLayer = new QGraphicsItemLayer(); 41 | 42 | connect(this, &FlowScene::nodeDoubleClicked, this, &CustomFlowScene::showNode); 43 | connect(this, &FlowScene::nodeCreated, this, &CustomFlowScene::initNode); 44 | } 45 | 46 | void CustomFlowScene::keyPressEvent(QKeyEvent *event) 47 | { 48 | // if a comment is being editing bypass event 49 | Q_FOREACH(eCommentItem* ci, _commentList) 50 | { 51 | if(ci->isEdited()) 52 | { 53 | FlowScene::keyPressEvent(event); 54 | return; 55 | } 56 | } 57 | 58 | switch (event->key()) 59 | { 60 | case Qt::Key_O: 61 | _addComment(_mousePos); 62 | break; 63 | } 64 | 65 | FlowScene::keyPressEvent(event); 66 | } 67 | 68 | void CustomFlowScene::keyReleaseEvent(QKeyEvent *event) 69 | { 70 | FlowScene::keyReleaseEvent(event); 71 | } 72 | 73 | void CustomFlowScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) 74 | { 75 | _mousePos = event->scenePos(); 76 | FlowScene::mouseMoveEvent(event); 77 | } 78 | 79 | void CustomFlowScene::showNode(QtNodes::Node& node) 80 | { 81 | // is a system node ? 82 | NodeSparkSystem* systemNode = dynamic_cast(node.nodeDataModel()); 83 | if(systemNode) 84 | { 85 | if(systemNode->getResult().get() != nullptr) 86 | { 87 | GplayDevice::getInstance()->setCurentParticleSystem(systemNode->getResult()); 88 | } 89 | 90 | return; 91 | } 92 | 93 | // is a Path node ? 94 | NodePath* pathNode = dynamic_cast(node.nodeDataModel()); 95 | if(pathNode) 96 | { 97 | if(pathNode->getResult() != nullptr) 98 | { 99 | Q_EMIT showPathNodeRequest(pathNode); 100 | } 101 | return; 102 | } 103 | } 104 | 105 | void CustomFlowScene::initNode(QtNodes::Node& node) 106 | { 107 | BaseNode* baseNode = dynamic_cast(node.nodeDataModel()); 108 | baseNode->init(); 109 | } 110 | 111 | eCommentItem* CustomFlowScene::_addComment(const QPointF &pos) 112 | { 113 | eCommentItem* comment = new eCommentItem(_commentLayer); 114 | comment->setPos(_mousePos); 115 | addItem(comment); 116 | 117 | _commentList.append(comment); 118 | 119 | return comment; 120 | } 121 | 122 | void CustomFlowScene::deleteSelectedComments() 123 | { 124 | for (QGraphicsItem* item : selectedItems()) 125 | { 126 | if (auto c = qgraphicsitem_cast(item)) 127 | { 128 | removeItem(c); 129 | _commentList.removeAll(c); 130 | delete c; 131 | } 132 | } 133 | } 134 | 135 | void CustomFlowScene::save() const 136 | { 137 | // original code from FlowScene 138 | // modified to append comments to json 139 | 140 | QString fileName = QFileDialog::getSaveFileName(nullptr, 141 | tr("Open Flow Scene"), 142 | QDir::homePath(), 143 | tr("Flow Scene Files (*.flow)")); 144 | 145 | if (!fileName.isEmpty()) 146 | { 147 | if (!fileName.endsWith("flow", Qt::CaseInsensitive)) 148 | fileName += ".flow"; 149 | 150 | QFile file(fileName); 151 | if (file.open(QIODevice::WriteOnly)) 152 | { 153 | // get nodes and connections data 154 | QByteArray data = saveToMemory(); 155 | 156 | // intercept json result and append comments 157 | QJsonObject json = QJsonDocument::fromJson(data).object(); 158 | saveCommentsToJson(json); 159 | 160 | // finally write all in file 161 | QJsonDocument document(json); 162 | QByteArray dataWithComments = document.toJson(); 163 | file.write(dataWithComments); 164 | } 165 | } 166 | } 167 | 168 | void CustomFlowScene::load() 169 | { 170 | // original code from FlowScene 171 | 172 | QString fileName = QFileDialog::getOpenFileName(nullptr, 173 | tr("Open Flow Scene"), 174 | QDir::homePath(), 175 | tr("Flow Scene Files (*.flow)")); 176 | 177 | if (!QFileInfo::exists(fileName)) 178 | return; 179 | 180 | QFile file(fileName); 181 | 182 | if (!file.open(QIODevice::ReadOnly)) 183 | return; 184 | 185 | clearScene(); // clear scene here, not like original. 186 | clearComments(); 187 | 188 | QByteArray wholeFile = file.readAll(); 189 | 190 | loadFromMemory(wholeFile); 191 | 192 | // additionnal code to load comments 193 | loadCommentsFromMemory(wholeFile); 194 | } 195 | 196 | void CustomFlowScene::clearComments() 197 | { 198 | Q_FOREACH(eCommentItem * i, _commentList) 199 | { 200 | removeItem(i); 201 | delete i; 202 | } 203 | _commentList.clear(); 204 | } 205 | 206 | void CustomFlowScene::saveCommentsToJson(QJsonObject &json) const 207 | { 208 | QJsonArray commentsJsonArray; 209 | for (auto const & commentItem : _commentList) 210 | { 211 | commentsJsonArray.append(commentItem->save()); 212 | } 213 | json["comments"] = commentsJsonArray; 214 | } 215 | 216 | void CustomFlowScene::loadCommentsFromMemory(const QByteArray& data) 217 | { 218 | QJsonObject const jsonDocument = QJsonDocument::fromJson(data).object(); 219 | 220 | // check for errors 221 | //QJsonParseError jsonError; 222 | //QJsonDocument configJsonDoc = QJsonDocument::fromJson(data, &jsonError); 223 | //if( jsonError.error != QJsonParseError::NoError ) 224 | // qDebug() << QString("Json error: %1").arg(jsonError.errorString()); 225 | //else if( configJsonDoc .isNull() ) 226 | // qDebug() << "Null JsonDocument"; 227 | 228 | QJsonArray commentsJsonArray = jsonDocument["comments"].toArray(); 229 | for (int i=0; irestore(commentsJsonArray[i].toObject()); 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /src/node-editor/common/CustomFlowScene.h: -------------------------------------------------------------------------------- 1 | #ifndef CUSTOMFLOWSCENE_H 2 | #define CUSTOMFLOWSCENE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "CommentGraphicsItem.h" 9 | 10 | using QtNodes::Node; 11 | using QtNodes::FlowView; 12 | using QtNodes::FlowScene; 13 | using QtNodes::DataModelRegistry; 14 | 15 | class NodePath; 16 | 17 | // empty graphic item used as parent container for comments items 18 | class QGraphicsItemLayer : public QGraphicsItem 19 | { 20 | public: 21 | virtual QRectF boundingRect() const override 22 | { 23 | return QRectF(0,0,0,0); 24 | } 25 | 26 | virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override 27 | { 28 | } 29 | }; 30 | 31 | 32 | 33 | class CustomFlowScene : public FlowScene 34 | { 35 | Q_OBJECT 36 | public: 37 | CustomFlowScene(std::shared_ptr registry, QObject * parent = Q_NULLPTR); 38 | CustomFlowScene(QObject * parent = Q_NULLPTR); 39 | ~CustomFlowScene(); 40 | 41 | void save() const; 42 | void load(); 43 | void clearComments(); 44 | void saveCommentsToJson(QJsonObject &json) const; 45 | void loadCommentsFromMemory(const QByteArray& data); 46 | 47 | Q_SIGNALS: 48 | void showPathNodeRequest(NodePath*); 49 | 50 | public Q_SLOTS: 51 | void deleteSelectedComments(); 52 | 53 | private Q_SLOTS: 54 | void showNode(Node& node); 55 | void initNode(QtNodes::Node& node); 56 | 57 | protected: 58 | void keyPressEvent(QKeyEvent *event) override; 59 | void keyReleaseEvent(QKeyEvent *event) override; 60 | void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; 61 | 62 | private: 63 | void _initialize(); 64 | eCommentItem* _addComment(const QPointF &pos); 65 | 66 | private: 67 | QGraphicsItemLayer* _commentLayer; 68 | QPointF _mousePos; 69 | QList _commentList; 70 | }; 71 | 72 | 73 | #endif // CUSTOMFLOWSCENE_H 74 | -------------------------------------------------------------------------------- /src/node-editor/common/CustomWidgets.h: -------------------------------------------------------------------------------- 1 | #ifndef PARAM_WIDGETS_HPP 2 | #define PARAM_WIDGETS_HPP 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "Parameter.h" 12 | #include "Trackedit.h" 13 | 14 | //------------------------------------------------------------------------------------------------------------------------------ 15 | // eParamTrackEdit2 16 | //------------------------------------------------------------------------------------------------------------------------------ 17 | class eParamTrackEdit : public eTrackEdit 18 | { 19 | Q_OBJECT 20 | public: 21 | eParamTrackEdit(eF32 &flt, Parameter ¶m, QWidget *parent=nullptr); 22 | eParamTrackEdit(eInt &intgr, Parameter ¶m, QWidget *parent=nullptr); 23 | eParamTrackEdit(eU8 &byte, Parameter ¶m, QWidget *parent=nullptr); 24 | 25 | void setIndicatorColor(const QColor &indCol); 26 | void setIndicatorEnabled(eBool indEnabled); 27 | 28 | virtual void paintEvent(QPaintEvent *pe); 29 | 30 | Q_SIGNALS: 31 | void onParameterChanged(); 32 | private Q_SLOTS: 33 | void _onValueChanged(); 34 | 35 | private: 36 | QString m_text; 37 | QColor m_indCol; 38 | bool m_indEnabled; 39 | }; 40 | 41 | 42 | //------------------------------------------------------------------------------------------------------------------------------ 43 | // push button 44 | //------------------------------------------------------------------------------------------------------------------------------ 45 | class eButton : public QPushButton 46 | { 47 | Q_OBJECT 48 | public: 49 | eButton(Parameter ¶m, QWidget *parent=nullptr); 50 | Q_SIGNALS: 51 | void onParameterChanged(const Parameter ¶m); 52 | private Q_SLOTS: 53 | void _onClicked(); 54 | private: 55 | Parameter& m_param; 56 | }; 57 | 58 | 59 | //------------------------------------------------------------------------------------------------------------------------------ 60 | // boolean button 61 | //------------------------------------------------------------------------------------------------------------------------------ 62 | class eBoolButton : public QToolButton 63 | { 64 | Q_OBJECT 65 | public: 66 | eBoolButton(Parameter ¶m, QWidget *parent=nullptr); 67 | Q_SIGNALS: 68 | void onParameterChanged(const Parameter ¶m); 69 | private Q_SLOTS: 70 | void _updateCaption(); 71 | void _onClicked(); 72 | private: 73 | Parameter& m_param; 74 | }; 75 | 76 | //------------------------------------------------------------------------------------------------------------------------------ 77 | // combo box 78 | //------------------------------------------------------------------------------------------------------------------------------ 79 | class eComboBox : public QComboBox 80 | { 81 | Q_OBJECT 82 | public: 83 | eComboBox(Parameter ¶m, QWidget *parent=nullptr); 84 | Q_SIGNALS: 85 | void onParameterChanged(const Parameter ¶m); 86 | private Q_SLOTS: 87 | void _updateSelection(); 88 | void _onActivated(int index); 89 | private: 90 | Parameter& m_param; 91 | }; 92 | 93 | //------------------------------------------------------------------------------------------------------------------------------ 94 | // flag button 95 | //------------------------------------------------------------------------------------------------------------------------------ 96 | class eFlagButton : public QToolButton 97 | { 98 | Q_OBJECT 99 | public: 100 | eFlagButton(Parameter ¶m, const QString &caption, eU32 flagIndex, QWidget *parent=nullptr); 101 | Q_SIGNALS: 102 | void onParameterChanged(const Parameter ¶m); 103 | private Q_SLOTS: 104 | void _updateDownState(); 105 | void _onClicked(); 106 | private: 107 | Parameter& m_param; 108 | eU32 m_flagIndex; 109 | }; 110 | 111 | //------------------------------------------------------------------------------------------------------------------------------ 112 | // text edit (multi-lines) 113 | //------------------------------------------------------------------------------------------------------------------------------ 114 | class eTextEdit : public QTextEdit 115 | { 116 | Q_OBJECT 117 | public: 118 | eTextEdit(Parameter ¶m, QWidget *parent=nullptr); 119 | Q_SIGNALS: 120 | void onParameterChanged(const Parameter ¶m); 121 | private Q_SLOTS: 122 | void _onTextChanged(); 123 | private: 124 | Parameter& m_param; 125 | }; 126 | 127 | //------------------------------------------------------------------------------------------------------------------------------ 128 | // line edit (single-line) 129 | //------------------------------------------------------------------------------------------------------------------------------ 130 | class eLineEdit : public QLineEdit 131 | { 132 | Q_OBJECT 133 | public: 134 | eLineEdit(Parameter ¶m, QWidget *parent=nullptr); 135 | Q_SIGNALS: 136 | void onParameterChanged(const Parameter ¶m); 137 | private Q_SLOTS: 138 | void _updateCaption(); 139 | void _onTextChanged(const QString &text); 140 | private: 141 | Parameter& m_param; 142 | }; 143 | 144 | 145 | //------------------------------------------------------------------------------------------------------------------------------ 146 | // file frame with line edit + button for open file dialog 147 | //------------------------------------------------------------------------------------------------------------------------------ 148 | class eFileFrame : public QWidget 149 | { 150 | Q_OBJECT 151 | public: 152 | eFileFrame(Parameter ¶m, QWidget *parent=nullptr); 153 | virtual ~eFileFrame(); 154 | Q_SIGNALS: 155 | void onParameterChanged(const Parameter ¶m); 156 | private Q_SLOTS: 157 | void _updateCaption(); 158 | void _onSelectLocally(); 159 | private: 160 | Parameter& m_param; 161 | eLineEdit* m_lineEdit; 162 | }; 163 | 164 | 165 | //------------------------------------------------------------------------------------------------------------------------------ 166 | // color frame 167 | //------------------------------------------------------------------------------------------------------------------------------ 168 | class eColorFrame : public QWidget 169 | { 170 | Q_OBJECT 171 | public: 172 | eColorFrame(Parameter ¶m, QWidget *parent=nullptr); 173 | virtual ~eColorFrame(); 174 | private: 175 | virtual void timerEvent(QTimerEvent *te); 176 | Q_SIGNALS: 177 | void onParameterChanged(); 178 | private Q_SLOTS: 179 | void _onSelectLocally(); 180 | void _updateEditColors(); 181 | private: 182 | Parameter& m_param; 183 | eParamTrackEdit* m_edits[4]; 184 | }; 185 | 186 | 187 | #endif // PARAM_WIDGETS_HPP 188 | -------------------------------------------------------------------------------- /src/node-editor/common/Nodestyle.h: -------------------------------------------------------------------------------- 1 | #ifndef NODESTYLE_H 2 | #define NODESTYLE_H 3 | 4 | #include 5 | #include 6 | #include 7 | using QtNodes::FlowViewStyle; 8 | using QtNodes::NodeStyle; 9 | using QtNodes::ConnectionStyle; 10 | 11 | static void setNodeStyle() 12 | { 13 | FlowViewStyle::setStyle( 14 | R"( 15 | { 16 | "FlowViewStyle": { 17 | "BackgroundColor": [50, 50, 50], 18 | "FineGridColor": [70, 70, 70], 19 | "CoarseGridColor": [90, 90, 90] 20 | } 21 | } 22 | )"); 23 | 24 | NodeStyle::setNodeStyle( 25 | R"( 26 | { 27 | "NodeStyle": { 28 | "NormalBoundaryColor": "darkgray", 29 | "SelectedBoundaryColor": "deepskyblue", 30 | "GradientColor0": "mintcream", 31 | "GradientColor1": "mintcream", 32 | "GradientColor2": "mintcream", 33 | "GradientColor3": "mintcream", 34 | "ShadowColor": [200, 200, 200], 35 | "FontColor": [10, 10, 10], 36 | "FontColorFaded": [100, 100, 100], 37 | "ConnectionPointColor": "white", 38 | "PenWidth": 2.0, 39 | "HoveredPenWidth": 2.5, 40 | "ConnectionPointDiameter": 10.0, 41 | "Opacity": 1.0 42 | } 43 | } 44 | )"); 45 | 46 | ConnectionStyle::setConnectionStyle( 47 | R"( 48 | { 49 | "ConnectionStyle": { 50 | "ConstructionColor": "gray", 51 | "NormalColor": "black", 52 | "SelectedColor": "gray", 53 | "SelectedHaloColor": "deepskyblue", 54 | "HoveredColor": "deepskyblue", 55 | 56 | "LineWidth": 3.0, 57 | "ConstructionLineWidth": 2.0, 58 | "PointDiameter": 10.0, 59 | 60 | "UseDataDefinedColors": false 61 | } 62 | } 63 | )"); 64 | } 65 | 66 | #endif // NODESTYLE_H 67 | -------------------------------------------------------------------------------- /src/node-editor/common/ParamWidget.h: -------------------------------------------------------------------------------- 1 | #ifndef PARAMWIDGET_H 2 | #define PARAMWIDGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class BaseNode; 9 | class Parameter; 10 | 11 | class ParamWidget : public QScrollArea 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | ParamWidget(BaseNode* node, QWidget* parent = nullptr); 17 | void save(QJsonObject& json); 18 | void restore(QJsonObject const &json); 19 | 20 | private: 21 | 22 | void createWidgets(); 23 | template void createParamTrackEditX(Parameter* p, QHBoxLayout* hbl); 24 | template void createParamTrackEditXY(Parameter* p, QHBoxLayout* hbl); 25 | template void createParamTrackEditXYZ(Parameter* p, QHBoxLayout* hbl); 26 | template void createParamTrackEditXYZW(Parameter* p, QHBoxLayout* hbl); 27 | void createParamLineEdit(Parameter* p, QHBoxLayout* hbl); 28 | void createParamBoolButton(Parameter* p, QHBoxLayout* hbl); 29 | void createParamEnum(Parameter* p, QHBoxLayout* hbl); 30 | void createParamFile(Parameter* p, QHBoxLayout* hbl); 31 | void createParamFlags(Parameter* p, QHBoxLayout* hbl); 32 | void createParamRGBA(Parameter* p, QHBoxLayout* hbl); 33 | void createParamButton(Parameter* p, QHBoxLayout* hbl); 34 | 35 | QVBoxLayout* _layout; 36 | BaseNode* _node; 37 | }; 38 | 39 | #endif // PARAMWIDGET_H 40 | -------------------------------------------------------------------------------- /src/node-editor/common/Parameter.cpp: -------------------------------------------------------------------------------- 1 | #include "Parameter.h" 2 | 3 | 4 | enum eParamClass 5 | { 6 | ePC_NONE, 7 | ePC_FLOAT, 8 | ePC_INT, 9 | ePC_STRING, 10 | ePC_BOOL, 11 | ePC_UCHAR, 12 | ePC_COLOR, 13 | }; 14 | 15 | struct ParameterInfo 16 | { 17 | eU32 numComponents; 18 | eParamClass classs; // three 's' because 'class' is keyword 19 | } 20 | PARAM_INFOS[] = 21 | { 22 | { 0, ePC_NONE }, // EPT_NONE 23 | { 1, ePC_STRING }, // EPT_STRING 24 | { 1, ePC_BOOL }, // EPT_BOOL 25 | { 1, ePC_INT }, // EPT_FLAGS 26 | { 1, ePC_INT }, // EPT_ENUM 27 | { 1, ePC_FLOAT }, // EPT_FLOAT 28 | { 2, ePC_FLOAT }, // EPT_FXY 29 | { 3, ePC_FLOAT }, // EPT_FXYZ 30 | { 4, ePC_FLOAT }, // EPT_FXYZW 31 | { 1, ePC_INT }, // EPT_INT 32 | { 2, ePC_INT }, // EPT_IXY 33 | { 3, ePC_INT }, // EPT_IXYZ 34 | { 4, ePC_INT }, // EPT_IXYZW 35 | { 1, ePC_INT }, // EPT_FILE 36 | { 1, ePC_STRING }, // EPT_TEXT 37 | { 3, ePC_COLOR }, // EPT_RGB 38 | { 4, ePC_COLOR }, // EPT_RGBA 39 | }; 40 | 41 | 42 | Parameter::Parameter() 43 | { 44 | 45 | } 46 | 47 | Parameter::Parameter(ParamType type, QString name, float min, float max, BaseNode* node) : 48 | type(type) 49 | , name(name) 50 | , min(min) 51 | , max(max) 52 | , node(node) 53 | , isConnected(false) 54 | { 55 | 56 | } 57 | 58 | void Parameter::setDescription(const QString &descr) 59 | { 60 | Q_ASSERT(type == EPT_ENUM || type == EPT_FLAGS); 61 | Q_ASSERT(descr.length() > 0); 62 | m_descr = descr; 63 | } 64 | 65 | const eString & Parameter::getDescription() const 66 | { 67 | return m_descr; 68 | } 69 | 70 | ParamType Parameter::getType() 71 | { 72 | return type; 73 | } 74 | 75 | eF32 Parameter::getMin() const 76 | { 77 | return min; 78 | } 79 | 80 | eF32 Parameter::getMax() const 81 | { 82 | return max; 83 | } 84 | 85 | BaseNode * Parameter::getOwnerOp() const 86 | { 87 | return node; 88 | } 89 | 90 | void Parameter::setChanged(eBool reconnect) 91 | { 92 | //@@m_ownerOp->setChanged(reconnect); 93 | } 94 | 95 | const eParamValue & Parameter::getDefaultValue() const 96 | { 97 | return defVal; 98 | } 99 | 100 | eParamValue & Parameter::getBaseValue() 101 | { 102 | return baseValue; 103 | } 104 | 105 | const eParamValue & Parameter::getBaseValue() const 106 | { 107 | return baseValue; 108 | } 109 | 110 | 111 | bool Parameter::getValueAsBool() const 112 | { 113 | Q_ASSERT(type == EPT_BOOL); 114 | return baseValue.get(); 115 | } 116 | 117 | int Parameter::getValueAsEnum() const 118 | { 119 | Q_ASSERT(type == EPT_ENUM); 120 | return baseValue.get(); 121 | } 122 | 123 | unsigned char Parameter::getValueAsFlags() const 124 | { 125 | Q_ASSERT(type == EPT_FLAGS); 126 | return baseValue.get(); 127 | } 128 | 129 | QString Parameter::getValueAsString() const 130 | { 131 | Q_ASSERT(type == EPT_STRING || type == EPT_FILE || type == EPT_BUTTON); 132 | return baseValue.get(); 133 | } 134 | 135 | eF32 Parameter::getValueAsFloat() const 136 | { 137 | Q_ASSERT(type == EPT_FLOAT); 138 | return baseValue.get(); 139 | } 140 | 141 | eFXY Parameter::getValueAsFXY() const 142 | { 143 | Q_ASSERT(type == EPT_FXY); 144 | return baseValue.get(); 145 | } 146 | 147 | eFXYZ Parameter::getValueAsFXYZ() const 148 | { 149 | Q_ASSERT(type == EPT_FXYZ); 150 | return baseValue.get(); 151 | } 152 | 153 | eFXYZW Parameter::getValueAsFXYZW() const 154 | { 155 | Q_ASSERT(type == EPT_FXYZW); 156 | return baseValue.get(); 157 | } 158 | 159 | eInt Parameter::getValueAsInt() const 160 | { 161 | Q_ASSERT(type == EPT_INT); 162 | return baseValue.get(); 163 | } 164 | 165 | eIXY Parameter::getValueAsIXY() const 166 | { 167 | Q_ASSERT(type == EPT_IXY); 168 | return baseValue.get(); 169 | } 170 | 171 | eIXYZ Parameter::getValueAsIXYZ() const 172 | { 173 | Q_ASSERT(type == EPT_IXYZ); 174 | return baseValue.get(); 175 | } 176 | 177 | eIXYZW Parameter::getValueAsIXYZW() const 178 | { 179 | Q_ASSERT(type == EPT_IXYZW); 180 | return baseValue.get(); 181 | } 182 | 183 | eColor Parameter::getValueAsColor() const 184 | { 185 | Q_ASSERT(type == EPT_RGB || type == EPT_RGBA); 186 | return baseValue.get(); 187 | } 188 | 189 | unsigned int Parameter::getComponentCount() 190 | { 191 | return PARAM_INFOS[type].numComponents; 192 | } 193 | -------------------------------------------------------------------------------- /src/node-editor/common/Parameter.h: -------------------------------------------------------------------------------- 1 | #ifndef PARAMETER_H 2 | #define PARAMETER_H 3 | 4 | #include "Types.h" 5 | #include "core/Variant.h" 6 | #include 7 | #include 8 | #include "Color.h" 9 | 10 | using QtNodes::NodeDataType; 11 | 12 | class BaseNode; 13 | 14 | enum ParamType 15 | { 16 | EPT_NONE = 0, 17 | EPT_STRING = 1, 18 | EPT_BOOL = 2, 19 | EPT_FLAGS = 3, 20 | EPT_ENUM = 4, 21 | EPT_FLOAT = 5, 22 | EPT_FXY = 6, 23 | EPT_FXYZ = 7, 24 | EPT_FXYZW = 8, 25 | EPT_INT = 9, 26 | EPT_IXY = 10, 27 | EPT_IXYZ = 11, 28 | EPT_IXYZW = 12, 29 | EPT_FILE = 13, 30 | EPT_TEXT = 14, 31 | EPT_RGB = 15, 32 | EPT_RGBA = 16, 33 | EPT_BUTTON = 17 34 | }; 35 | /* 36 | static const NodeDataType PARAM_TYPE[] = 37 | { 38 | // data types 39 | { "none" , "none" }, // 0 40 | { "string" , "string" }, // 1 41 | { "bool" , "bool" }, // 2 42 | { "flags" , "flags" }, // 3 43 | { "enum" , "enum" }, // 4 44 | { "float" , "float" }, // 5 45 | { "fxy" , "fxy" }, // 6 46 | { "fxyz" , "fxyz" }, // 7 47 | { "fxyzw" , "fxyzw" }, // 8 48 | { "int" , "int" }, // 9 49 | { "ixy" , "ixy" }, // 10 50 | { "ixyz" , "ixyz" }, // 11 51 | { "ixyzw" , "ixyzw" }, // 12 52 | { "file" , "file" }, // 13 53 | { "text" , "text" }, // 14 54 | { "rgb" , "rgb" }, // 15 55 | { "rgba" , "rgba" }, // 16 56 | }; 57 | */ 58 | 59 | 60 | // possible variant type for parameters 61 | typedef nonstd::variant 62 | < eF32, 63 | eFXY, 64 | eFXYZ, 65 | eFXYZW, 66 | eInt, 67 | eIXY, 68 | eIXYZ, 69 | eIXYZW, 70 | QString, 71 | bool, 72 | unsigned char, 73 | eColor 74 | > eParamValue; 75 | 76 | 77 | class Parameter : public QObject 78 | { 79 | Q_OBJECT 80 | public: 81 | ParamType type; 82 | QString name; 83 | float min; 84 | float max; 85 | BaseNode* node; 86 | bool isConnected; 87 | eParamValue baseValue; 88 | const eParamValue defVal; 89 | eString m_descr; // used for enum and flags texts 90 | 91 | Parameter(); 92 | Parameter(ParamType type, QString name, float min, float max, BaseNode* node); 93 | 94 | unsigned int getComponentCount(); 95 | void setDescription(const QString &descr); 96 | const eString & getDescription() const; 97 | ParamType getType(); 98 | eF32 getMin() const; 99 | eF32 getMax() const; 100 | BaseNode * getOwnerOp() const; 101 | void setChanged(eBool reconnect = eFALSE); 102 | const eParamValue & getDefaultValue() const; 103 | eParamValue & getBaseValue(); 104 | const eParamValue & getBaseValue() const; 105 | 106 | bool getValueAsBool() const; 107 | int getValueAsEnum() const; 108 | unsigned char getValueAsFlags() const; 109 | QString getValueAsString() const; 110 | 111 | eF32 getValueAsFloat() const; 112 | eFXY getValueAsFXY() const; 113 | eFXYZ getValueAsFXYZ() const; 114 | eFXYZW getValueAsFXYZW() const; 115 | 116 | eInt getValueAsInt() const; 117 | eIXY getValueAsIXY() const; 118 | eIXYZ getValueAsIXYZ() const; 119 | eIXYZW getValueAsIXYZW() const; 120 | 121 | eColor getValueAsColor() const; 122 | 123 | Q_SIGNALS: 124 | void parameterUpdated(); 125 | }; 126 | 127 | #endif // PARAMETER_H 128 | -------------------------------------------------------------------------------- /src/node-editor/common/Path.cpp: -------------------------------------------------------------------------------- 1 | #include "Path.h" 2 | #include 3 | #include 4 | 5 | Path::Path(PathType splineType, unsigned int keyCount) : 6 | _spline(nullptr), 7 | _loopMode(ELM_LAST) 8 | { 9 | switch(splineType) 10 | { 11 | case EPT_CONSTANT: _spline = new Splines::ConstantSpline; break; 12 | case EPT_LINEAR: _spline = new Splines::LinearSpline; break; 13 | case EPT_CUBIC: _spline = new Splines::CubicSpline; break; 14 | case EPT_AKIMA: _spline = new Splines::AkimaSpline; break; 15 | case EPT_BESSEL: _spline = new Splines::BesselSpline; break; 16 | case EPT_PCHIP: _spline = new Splines::PchipSpline; break; 17 | case EPT_QUINTIC: _spline = new Splines::QuinticSpline; break; 18 | default: assert(0); 19 | } 20 | 21 | //_times.resize(keyCount); 22 | //_values.resize(keyCount); 23 | } 24 | 25 | Path::~Path() 26 | { 27 | if(_spline) 28 | delete _spline; 29 | } 30 | 31 | void Path::addKey(double keyTime, double keyValue) 32 | { 33 | assert(keyTime >= 0.0); 34 | 35 | ///_insertKey(keyTime, keyValue); 36 | _times.push_back(keyTime); 37 | _values.push_back(keyValue); 38 | } 39 | 40 | void Path::_insertKey(double keyTime, double keyValue) 41 | { 42 | for (unsigned int i=0; i<_times.size(); i++) 43 | { 44 | if (_times[i] > keyTime) 45 | { 46 | _times.insert(_times.begin()+i, keyTime); 47 | _values.insert(_values.begin()+i, keyValue); 48 | return; 49 | } 50 | } 51 | 52 | // no key found => append 53 | _times.push_back(keyTime); 54 | _values.push_back(keyValue); 55 | } 56 | 57 | unsigned int Path::getKeyCount() const 58 | { 59 | return _times.size(); 60 | } 61 | 62 | const PathKey Path::getKeyByIndex(unsigned int index) const 63 | { 64 | assert(index < _times.size()); 65 | 66 | PathKey key; 67 | key.time = _times.at(index); 68 | key.value = _values.at(index); 69 | return key; 70 | } 71 | 72 | double Path::getStartTime() const 73 | { 74 | if (_times.size() == 0) 75 | return 0.0; 76 | 77 | return _times.front(); 78 | } 79 | 80 | double Path::getEndTime() const 81 | { 82 | if (_times.size() == 0) 83 | return 0.0f; 84 | 85 | return _times.back(); 86 | } 87 | 88 | void Path::clear() 89 | { 90 | _times.clear(); 91 | _values.clear(); 92 | } 93 | 94 | void Path::setAtIndex(unsigned index, double time, double value) 95 | { 96 | assert(index < _times.size()); 97 | _times[index] = time; 98 | _values[index] = value; 99 | } 100 | 101 | void Path::build() 102 | { 103 | _spline->clear(); 104 | _spline->build(_times.data(), _values.data(), _times.size()); 105 | } 106 | 107 | double Path::evaluate(double time) const 108 | { 109 | if (!_times.size()) 110 | return 0.0; 111 | 112 | const double minTime = _times.front(); 113 | const double maxTime = _times.back(); 114 | 115 | const double firstValue = _values.front(); 116 | const double lastValue = _values.back(); 117 | 118 | if (_loopMode == ELM_LOOP) 119 | time = fmodf(time - minTime, maxTime - minTime); 120 | 121 | if (time <= minTime || _times.size() == 1) // time before first key? 122 | return (_loopMode == ELM_ZERO ? 0.0 : firstValue); 123 | else if (time >= maxTime) // time after last key? 124 | return (_loopMode == ELM_ZERO ? 0.0 : lastValue); 125 | else 126 | return _spline->eval(time); 127 | } 128 | 129 | void Path::setLoopMode(PathLoopMode loopMode) 130 | { 131 | _loopMode = loopMode; 132 | } 133 | -------------------------------------------------------------------------------- /src/node-editor/common/Path.h: -------------------------------------------------------------------------------- 1 | #ifndef PATH_H 2 | #define PATH_H 3 | 4 | #include "thirdparty/splines/Splines.hh" 5 | using namespace SplinesLoad; 6 | 7 | enum PathType 8 | { 9 | EPT_CONSTANT, 10 | EPT_LINEAR, 11 | EPT_CUBIC, 12 | EPT_AKIMA, 13 | EPT_BESSEL, 14 | EPT_PCHIP, 15 | EPT_QUINTIC, 16 | }; 17 | 18 | enum PathLoopMode 19 | { 20 | ELM_LOOP, 21 | ELM_ZERO, 22 | ELM_LAST, 23 | }; 24 | 25 | struct PathKey 26 | { 27 | double time; 28 | double value; 29 | }; 30 | 31 | class Path 32 | { 33 | public: 34 | Path(PathType splineType, unsigned int keyCount = 0); 35 | ~Path(); 36 | 37 | void build(); 38 | double evaluate(double time) const; 39 | void addKey(double keyTime, double keyValue); 40 | void setAtIndex(unsigned index, double time, double value); 41 | void setLoopMode(PathLoopMode loopMode); 42 | void clear(); 43 | 44 | unsigned int getKeyCount() const; 45 | const PathKey getKeyByIndex(unsigned int index) const; 46 | double getStartTime() const; 47 | double getEndTime() const; 48 | 49 | private: 50 | void _insertKey(double keyTime, double keyValue); 51 | 52 | private: 53 | std::vector _times; 54 | std::vector _values; 55 | Splines::Spline* _spline; 56 | PathLoopMode _loopMode; 57 | }; 58 | 59 | class Path4 60 | { 61 | 62 | }; 63 | 64 | class PathSampler 65 | { 66 | 67 | }; 68 | 69 | class Path4Sampler 70 | { 71 | 72 | }; 73 | 74 | #endif // PATH_H 75 | -------------------------------------------------------------------------------- /src/node-editor/common/TrackEdit.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "Trackedit.h" 5 | 6 | eTrackEdit::eTrackEdit(eF32 &flt, eF32 min, eF32 max, QWidget *parent) : QLineEdit(parent), 7 | m_curFlt(flt), 8 | m_refFlt(&flt), 9 | m_refInt(nullptr), 10 | m_refByte(nullptr), 11 | m_ctrlDown(eFALSE), 12 | m_shiftDown(eFALSE), 13 | m_valChanged(eFALSE) 14 | { 15 | QDoubleValidator *dv = new QDoubleValidator(min, max, 3, this); 16 | dv->setNotation(QDoubleValidator::StandardNotation); 17 | dv->setLocale(QLocale::C); 18 | setValidator(dv); 19 | setText(QString::number(m_curFlt, 'f', FLOAT_PRECISION)); 20 | connect(this, SIGNAL(textEdited(const QString &)), this, SLOT(_onTextEdited(const QString &))); 21 | m_timerId = startTimer(100); 22 | } 23 | 24 | eTrackEdit::eTrackEdit(eInt &intgr, eInt min, eInt max, QWidget *parent) : QLineEdit(parent), 25 | m_curInt(intgr), 26 | m_refFlt(nullptr), 27 | m_refInt(&intgr), 28 | m_refByte(nullptr), 29 | m_ctrlDown(eFALSE), 30 | m_shiftDown(eFALSE), 31 | m_valChanged(eFALSE) 32 | { 33 | setValidator(new QIntValidator(min, max, this)); 34 | setText(eIntToStr(m_curInt)); 35 | connect(this, SIGNAL(textEdited(const QString &)), this, SLOT(_onTextEdited(const QString &))); 36 | m_timerId = startTimer(100); 37 | } 38 | 39 | eTrackEdit::eTrackEdit(eU8 &byte, eU8 min, eU8 max, QWidget *parent) : QLineEdit(parent), 40 | m_curByte(byte), 41 | m_refFlt(nullptr), 42 | m_refInt(nullptr), 43 | m_refByte(&byte), 44 | m_ctrlDown(eFALSE), 45 | m_shiftDown(eFALSE), 46 | m_valChanged(eFALSE) 47 | { 48 | setValidator(new QIntValidator(min, max, this)); 49 | setText(eIntToStr(m_curByte)); 50 | connect(this, SIGNAL(textEdited(const QString &)), this, SLOT(_onTextEdited(const QString &))); 51 | m_timerId = startTimer(100); 52 | } 53 | 54 | eTrackEdit::~eTrackEdit() 55 | { 56 | killTimer(m_timerId); 57 | } 58 | 59 | void eTrackEdit::wheelEvent(QWheelEvent *we) 60 | { 61 | if (hasFocus()) 62 | { 63 | _changeValue(eSign(we->delta())); 64 | we->accept(); 65 | } 66 | else 67 | QLineEdit::wheelEvent(we); 68 | } 69 | 70 | void eTrackEdit::keyPressEvent(QKeyEvent *ke) 71 | { 72 | QLineEdit::keyPressEvent(ke); 73 | 74 | if (ke->key() == Qt::Key_Control) 75 | m_ctrlDown = eTRUE; 76 | else if (ke->key() == Qt::Key_Shift) 77 | m_shiftDown = eTRUE; 78 | } 79 | 80 | void eTrackEdit::keyReleaseEvent(QKeyEvent *ke) 81 | { 82 | QLineEdit::keyReleaseEvent(ke); 83 | m_ctrlDown = eFALSE; 84 | m_shiftDown = eFALSE; 85 | } 86 | 87 | void eTrackEdit::mouseMoveEvent(QMouseEvent *me) 88 | { 89 | //@@eFUNCDELAY(25U); 90 | 91 | QLineEdit::mouseMoveEvent(me); 92 | 93 | if (me->buttons()&Qt::RightButton) 94 | { 95 | const QPoint diff = me->pos()-m_mouseDownPos; 96 | 97 | if (eAbs(diff.x()) > 1 && _changeValue(diff.x()/2)) 98 | { 99 | QCursor::setPos(mapToGlobal(m_mouseDownPos)); 100 | m_valChanged = eTRUE; 101 | } 102 | } 103 | } 104 | 105 | void eTrackEdit::mousePressEvent(QMouseEvent *me) 106 | { 107 | m_mouseDownPos = me->pos(); 108 | setContextMenuPolicy(Qt::PreventContextMenu); 109 | QLineEdit::mousePressEvent(me); 110 | } 111 | 112 | void eTrackEdit::mouseReleaseEvent(QMouseEvent *me) 113 | { 114 | QLineEdit::mouseReleaseEvent(me); 115 | 116 | if (m_valChanged) 117 | m_valChanged = eFALSE; 118 | else if (me->button() == Qt::RightButton) 119 | { 120 | QContextMenuEvent ce(QContextMenuEvent::Mouse, me->pos()); 121 | setContextMenuPolicy(Qt::DefaultContextMenu); 122 | contextMenuEvent(&ce); 123 | } 124 | } 125 | 126 | void eTrackEdit::timerEvent(QTimerEvent *te) 127 | { 128 | QLineEdit::timerEvent(te); 129 | 130 | if (m_refFlt && !eAreFloatsEqual(m_curFlt, *m_refFlt)) 131 | { 132 | m_curFlt = *m_refFlt; 133 | setText(QString::number(m_curFlt, 'f', FLOAT_PRECISION)); 134 | } 135 | else if (m_refInt && m_curInt != *m_refInt) 136 | { 137 | m_curInt = *m_refInt; 138 | setText(eIntToStr(m_curInt)); 139 | } 140 | else if (m_refByte && m_curByte != *m_refByte) 141 | { 142 | m_curByte = *m_refByte; 143 | setText(eIntToStr(m_curByte)); 144 | } 145 | } 146 | 147 | void eTrackEdit::focusInEvent(QFocusEvent *fe) 148 | { 149 | QLineEdit::focusInEvent(fe); 150 | setFocusPolicy(Qt::WheelFocus); 151 | } 152 | 153 | void eTrackEdit::focusOutEvent(QFocusEvent *fe) 154 | { 155 | QLineEdit::focusOutEvent(fe); 156 | setFocusPolicy(Qt::StrongFocus); 157 | } 158 | 159 | void eTrackEdit::_onTextEdited(const QString &text) 160 | { 161 | if (hasAcceptableInput()) 162 | { 163 | if (m_refFlt) 164 | { 165 | m_curFlt = text.toFloat(); 166 | *m_refFlt = m_curFlt; 167 | } 168 | else if (m_refInt) 169 | { 170 | m_curInt = text.toInt(); 171 | *m_refInt = m_curInt; 172 | } 173 | else if (m_refByte) 174 | { 175 | m_curByte = text.toInt(); 176 | *m_refByte = m_curByte; 177 | } 178 | 179 | Q_EMIT onValueChanged(); 180 | } 181 | } 182 | 183 | eBool eTrackEdit::_changeValue(eF32 factor) 184 | { 185 | if (m_ctrlDown) // [control] => change slow (0.1x) 186 | factor *= 0.1f; 187 | else if (m_shiftDown) // [shift] => change fast (10x) 188 | factor *= 10.0f; 189 | 190 | // calculate new parameter value 191 | QString newText; 192 | eInt newInt = 0; 193 | eF32 newFloat = 0.0f; 194 | 195 | if (m_refFlt) 196 | { 197 | newFloat = m_curFlt+0.01f*factor; 198 | newText.setNum(newFloat, 'f', FLOAT_PRECISION); 199 | } 200 | else 201 | { 202 | // value to small for change? 203 | if (eAbs(factor) < 1.0f) 204 | return eFALSE; 205 | 206 | newInt = (m_refInt ? m_curInt : m_curByte)+(eInt)factor; 207 | newText.setNum(newInt); 208 | } 209 | 210 | // validate format and range 211 | eInt pos; 212 | if (validator()->validate(newText, pos) == QValidator::Acceptable) 213 | { 214 | if (m_refFlt) 215 | { 216 | m_curFlt = newFloat; 217 | *m_refFlt = newFloat; 218 | } 219 | else if (m_refInt) 220 | { 221 | m_curInt = newInt; 222 | *m_refInt = newInt; 223 | } 224 | else if (m_refByte) 225 | { 226 | m_curByte = newInt; 227 | *m_refByte = newInt; 228 | } 229 | 230 | setText(newText); 231 | } 232 | 233 | Q_EMIT textEdited(text()); 234 | return eTRUE; 235 | } 236 | 237 | -------------------------------------------------------------------------------- /src/node-editor/common/Trackedit.h: -------------------------------------------------------------------------------- 1 | #ifndef TRACK_EDIT_HPP 2 | #define TRACK_EDIT_HPP 3 | #pragma once 4 | 5 | #include 6 | #include "Types.h" 7 | 8 | // basic track edit for floats, integer, and bytes 9 | class eTrackEdit : public QLineEdit 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | eTrackEdit(eF32 &flt, eF32 min, eF32 max, QWidget *parent); 15 | eTrackEdit(eInt &intgr, eInt min, eInt max, QWidget *parent); 16 | eTrackEdit(eU8 &byte, eU8 min, eU8 max, QWidget *parent); 17 | virtual ~eTrackEdit(); 18 | 19 | virtual void wheelEvent(QWheelEvent *we); 20 | virtual void keyPressEvent(QKeyEvent *ke); 21 | virtual void keyReleaseEvent(QKeyEvent *ke); 22 | virtual void mouseMoveEvent(QMouseEvent *me); 23 | virtual void mousePressEvent(QMouseEvent *me); 24 | virtual void mouseReleaseEvent(QMouseEvent *me); 25 | virtual void timerEvent(QTimerEvent *te); 26 | virtual void focusInEvent(QFocusEvent *fe); 27 | virtual void focusOutEvent(QFocusEvent *fe); 28 | 29 | Q_SIGNALS: 30 | void onValueChanged(); 31 | 32 | private Q_SLOTS: 33 | void _onTextEdited(const QString &text); 34 | 35 | private: 36 | eBool _changeValue(eF32 factor); 37 | 38 | public: 39 | static const eInt FLOAT_PRECISION = 3; 40 | 41 | private: 42 | eF32 m_curFlt; 43 | eInt m_curInt; 44 | eU8 m_curByte; 45 | eF32 * m_refFlt; 46 | eInt * m_refInt; 47 | eU8 * m_refByte; 48 | eBool m_ctrlDown; 49 | eBool m_shiftDown; 50 | eBool m_valChanged; 51 | QPoint m_mouseDownPos; 52 | eInt m_timerId; 53 | }; 54 | 55 | #endif // TRACK_EDIT_HPP 56 | -------------------------------------------------------------------------------- /src/node-editor/common/Types.cpp: -------------------------------------------------------------------------------- 1 | #include "Types.h" 2 | #include 3 | 4 | eF32 eAbs(eF32 x) 5 | { 6 | return fabsf(x); 7 | } 8 | 9 | eU32 eAbs(eInt x) 10 | { 11 | return ((x^(x>>31))-(x>>31)); 12 | } 13 | 14 | eChar * eIntToStr(eInt val) 15 | { 16 | // remember if integer is negative and 17 | // if it is, make it positive 18 | const eBool negative = (val < 0); 19 | 20 | if (negative) 21 | val = -val; 22 | 23 | // 12 spaces are enough for 32-bit decimal 24 | // (10 digits + 1 null terminator byte + 25 | // eventually a sign character) 26 | static eChar str[12]; 27 | 28 | eChar *cp = str+sizeof(str)-1; 29 | *cp = '\0'; 30 | 31 | do 32 | { 33 | *(--cp) = val%10+'0'; 34 | val /= 10; 35 | } 36 | while (val > 0); 37 | 38 | // prepend negative sign character 39 | if (negative) 40 | *(--cp) = '-'; 41 | 42 | return cp; 43 | } 44 | 45 | eU32 eSignBit(eF32 x) 46 | { 47 | return (eU32 &)x&0x80000000; 48 | } 49 | 50 | eF32 eSign(eF32 x) 51 | { 52 | // test exponent and mantissa bits: is input zero? 53 | if (((eInt &)x&0x7fffffff) == 0) 54 | return 0.0f; 55 | 56 | // mask sign bit in x, set it in r if necessary 57 | eF32 r = 1.0f; 58 | (eInt &)r |= eSignBit(x); 59 | return r; 60 | } 61 | 62 | eInt eSign(eInt x) 63 | { 64 | return (x != 0)|(x>>(sizeof(eInt)*8-1)); 65 | } 66 | 67 | eBool eIsFloatZero(eF32 x) 68 | { 69 | return (eAbs(x) < eALMOST_ZERO); 70 | } 71 | 72 | eBool eAreFloatsEqual(eF32 x, eF32 y) 73 | { 74 | return eIsFloatZero(x-y); 75 | } 76 | 77 | eBool eMemEqual(eConstPtr mem0, eConstPtr mem1, size_t count) 78 | { 79 | return !memcmp(mem0, mem1, count); 80 | } 81 | 82 | // faster float to long conversion than c-lib's 83 | // default version. must be called explicitly. 84 | #include 85 | eInt eFtoL(eF32 x) 86 | { 87 | return _mm_cvt_ss2si(_mm_load_ss(&x)); 88 | //return (eInt)(x+0.001) / 1L; 89 | //return (eInt)x; 90 | } 91 | -------------------------------------------------------------------------------- /src/node-editor/common/Types.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPES_H 2 | #define TYPES_H 3 | 4 | #include 5 | 6 | typedef unsigned char eU8; 7 | typedef signed char eS8; 8 | typedef unsigned short eU16; 9 | typedef short eS16; 10 | typedef unsigned int eU32; 11 | typedef int eS32; 12 | typedef float eF32; 13 | typedef double eF64; 14 | typedef int eInt; 15 | typedef char eChar; 16 | typedef signed char eBool; 17 | typedef void * ePtr; 18 | typedef const void * eConstPtr; 19 | typedef eU32 eID; 20 | 21 | #define eU32_MAX (0xffffffffU) 22 | #define eS32_MIN (-2147483647-1) 23 | #define eS32_MAX (2147483647) 24 | #define eU16_MAX (0xffffU) 25 | #define eS16_MIN (-32768) 26 | #define eS16_MAX (32767) 27 | #define eU8_MAX (0xffU) 28 | #define eS8_MIN (-128) 29 | #define eS8_MAX (127) 30 | #define eF32_MAX (3.402823466e+38F) 31 | #define eF32_MIN (-eF32_MAX) 32 | #define eF32_INF (1e30f) 33 | #define eTRUE (eBool)(!0) 34 | #define eFALSE 0 35 | #define eNOID 0 36 | 37 | #define eSQRT2 1.41421356237f 38 | #define ePI 3.1415926535897932384626433832795f 39 | #define eTWOPI (ePI*2.0f) 40 | #define eHALFPI (ePI*0.5f) 41 | #define eSQRPI (ePI*ePI) 42 | #define eINVHALFPI (1.0f/eHALFPI) 43 | #define eEXPONE 2.718281828459f 44 | #define eALMOST_ZERO 0.00001f 45 | #define eMAX_RAND 2147483647 46 | #define eMAX_NAME_LEN 64 47 | #define eMAX_PATH_LEN 256 48 | #define e360 360.0f 49 | 50 | 51 | #define eASSERT(X) assert(X) 52 | 53 | 54 | // fake type during code integration; to delete after 55 | typedef void* eIOperator; 56 | #include 57 | #include 58 | typedef QString eString; 59 | 60 | 61 | eF32 eAbs(eF32 x); 62 | eU32 eAbs(eInt x); 63 | eInt eFtoL(eF32 x); 64 | eChar* eIntToStr(eInt val); 65 | eU32 eSignBit(eF32 x); 66 | eF32 eSign(eF32 x); 67 | eInt eSign(eInt x); 68 | eBool eAreFloatsEqual(eF32 x, eF32 y); 69 | eBool eIsFloatZero(eF32 x); 70 | eBool eMemEqual(eConstPtr mem0,eConstPtr mem1, size_t count); 71 | 72 | 73 | 74 | template T eMin(const T &a, const T &b) 75 | { 76 | return (a < b) ? a : b; 77 | } 78 | 79 | template T eMax(const T &a, const T &b) 80 | { 81 | return (a > b) ? a : b; 82 | } 83 | 84 | template T eClamp(const T &min, const T &x, const T &max) 85 | { 86 | if (x < min) 87 | return min; 88 | else if (x > max) 89 | return max; 90 | else 91 | return x; 92 | } 93 | 94 | template inline T zLerp(const T &a, const T &b, T t) 95 | { 96 | return (1-t)*a + t*b; 97 | } 98 | 99 | template T eLerp(const T &a, const T &b, eF32 t) 100 | { 101 | return a+(b-a)*t; 102 | } 103 | 104 | template void eSetBit(T &t, eU32 index) 105 | { 106 | eASSERT(index < sizeof(T)*8); 107 | t |= (1< void eSetBit(T &t, eU32 index, eBool set) 111 | { 112 | eASSERT(set == 0 || set == 1); 113 | 114 | eASSERT(index void eClearBit(T &t, eU32 index) 119 | { 120 | eASSERT(index < sizeof(T)*8); 121 | t &= ~(1< eBool eGetBit(T t, eU32 index) 125 | { 126 | eASSERT(index < sizeof(T)*8); 127 | return ((t&(1< void eToggleBit(T &t, eU32 index) 131 | { 132 | eASSERT(index < sizeof(T)*8); 133 | t ^= (1< 142 | class eXY 143 | { 144 | public: 145 | struct 146 | { 147 | T x; 148 | T y; 149 | }; 150 | 151 | eXY() {} 152 | eXY(T x, T y) : x(x), y(y) {} 153 | }; 154 | 155 | 156 | template 157 | class eXYZ 158 | { 159 | public: 160 | struct 161 | { 162 | T x; 163 | T y; 164 | T z; 165 | }; 166 | 167 | eXYZ() {} 168 | eXYZ(T x, T y, T z) : x(x), y(y), z(z) {} 169 | }; 170 | 171 | 172 | template 173 | class eXYZW 174 | { 175 | public: 176 | struct 177 | { 178 | T x; 179 | T y; 180 | T z; 181 | T w; 182 | }; 183 | 184 | eXYZW() {} 185 | eXYZW(T x, T y, T z, T w) : x(x), y(y), z(z), w(w) {} 186 | }; 187 | 188 | typedef eXY eFXY; 189 | typedef eXYZ eFXYZ; 190 | typedef eXYZW eFXYZW; 191 | typedef eXY eIXY; 192 | typedef eXYZ eIXYZ; 193 | typedef eXYZW eIXYZW; 194 | 195 | 196 | #endif // TYPES_H 197 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SparkNodeRender.cpp: -------------------------------------------------------------------------------- 1 | #include "SparkNodeRender.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "SpkUtils.h" 8 | 9 | 10 | void createDebugGeomteriesFromZone(const SPK::Ref zone) 11 | { 12 | // every zone has a position 13 | const SPK::Vector3D pos = zone->getPosition(); 14 | 15 | if(zone->getClassName() == "Point") 16 | { 17 | DebugDraw::getInstance()->drawSphere(Vector3(pos.x, pos.y, pos.z), 0.1f, Vector3(1,1,1)); 18 | } 19 | else if(zone->getClassName() == "Sphere") 20 | { 21 | const SPK::Sphere* sphere = dynamic_cast(zone.get()); 22 | GP_ASSERT(sphere); 23 | float radius = sphere->getRadius(); 24 | DebugDraw::getInstance()->drawSphere(Vector3(pos.x, pos.y, pos.z), radius, Vector3(1,1,1)); 25 | } 26 | else if(zone->getClassName() == "Plane") 27 | { 28 | const SPK::Plane* plane = dynamic_cast(zone.get()); 29 | GP_ASSERT(plane); 30 | const SPK::Vector3D normal = plane->getNormal(); 31 | DebugDraw::getInstance()->drawPlane(Vector3(normal.x, normal.y, normal.z), 0.0f, Matrix::identity(), Vector3(1,1,1)); 32 | } 33 | else if(zone->getClassName() == "Box") 34 | { 35 | const SPK::Box* box = dynamic_cast(zone.get()); 36 | GP_ASSERT(box); 37 | Vector3 scale = ToGplayVector3(box->getDimensions()); 38 | Matrix matrix; 39 | // todo: fix rotation 40 | Matrix::createTranslation(ToGplayVector3(pos), &matrix); 41 | BoundingBox bbox(-scale/2.0f, scale/2.0f); 42 | bbox *= matrix; 43 | DebugDraw::getInstance()->drawBox(bbox.min, bbox.max, Vector3(1,1,1)); 44 | } 45 | else if(zone->getClassName() == "Cylinder") 46 | { 47 | const SPK::Cylinder* cylinder = dynamic_cast(zone.get()); 48 | GP_ASSERT(cylinder); 49 | 50 | const SPK::Vector3D axis = cylinder->getAxis(); 51 | float height = cylinder->getHeight(); 52 | float radius = cylinder->getRadius(); 53 | 54 | // todo: fix rotation 55 | Matrix matrix; 56 | Matrix::createTranslation(ToGplayVector3(pos), &matrix); 57 | DebugDraw::getInstance()->drawCylinder(radius, height/2.0f, 1, matrix, Vector3(1,1,1)); 58 | } 59 | else if(zone->getClassName() == "Ring") 60 | { 61 | const SPK::Ring* ring = dynamic_cast(zone.get()); 62 | GP_ASSERT(ring); 63 | 64 | float minRadius = ring->getMinRadius(); 65 | float maxRadius = ring->getMaxRadius(); 66 | 67 | // todo: fix rotation 68 | 69 | DebugDraw::getInstance()->drawArc(ToGplayVector3(pos), Vector3(0,1,0), Vector3(1,0,0), minRadius, minRadius, 0.0f, MATH_DEG_TO_RAD(360.0f), Vector3(1,1,1), false); 70 | DebugDraw::getInstance()->drawArc(ToGplayVector3(pos), Vector3(0,1,0), Vector3(1,0,0), maxRadius, maxRadius, 0.0f, MATH_DEG_TO_RAD(360.0f), Vector3(1,1,1), false); 71 | } 72 | } 73 | 74 | void drawDebugShapes(SparkParticleEmitter* spkEffect, Scene* scene) 75 | { 76 | DebugDraw::getInstance()->begin(scene->getActiveCamera()->getViewProjectionMatrix()); 77 | 78 | SPK::Ref spkSystem = spkEffect->getSparkSystem(); 79 | for(size_t nGroup = 0; nGroup < spkSystem->getNbGroups(); nGroup++) 80 | { 81 | // show emitters zones 82 | for(size_t nEmitter = 0; nEmitter < spkSystem->getGroup(nGroup)->getNbEmitters(); nEmitter++) 83 | { 84 | const SPK::Ref zone = spkSystem->getGroup(nGroup)->getEmitter(nEmitter)->getZone(); 85 | createDebugGeomteriesFromZone(zone); 86 | } 87 | 88 | // show modifiers zones 89 | for(size_t nModifiers = 0; nModifiers < spkSystem->getGroup(nGroup)->getNbModifiers(); nModifiers++) 90 | { 91 | const SPK::Ref modifier = spkSystem->getGroup(nGroup)->getModifier(nModifiers); 92 | 93 | if(modifier->getClassName() == "PointMass") 94 | { 95 | const SPK::PointMass* pointMass = dynamic_cast(modifier.get()); 96 | GP_ASSERT(pointMass); 97 | const SPK::Vector3D pos = pointMass->getPosition(); 98 | DebugDraw::getInstance()->drawSphere(Vector3(pos.x, pos.y, pos.z), 0.25f, Vector3(0,1,0)); 99 | } 100 | else if(modifier->getClassName() == "Destroyer") 101 | { 102 | const SPK::Destroyer* destroyer = dynamic_cast(modifier.get()); 103 | GP_ASSERT(destroyer); 104 | createDebugGeomteriesFromZone(destroyer->getZone()); 105 | } 106 | else if(modifier->getClassName() == "Obstacle") 107 | { 108 | const SPK::Obstacle* obstacle = dynamic_cast(modifier.get()); 109 | GP_ASSERT(obstacle); 110 | createDebugGeomteriesFromZone(obstacle->getZone()); 111 | } 112 | else if(modifier->getClassName() == "LinearForce") 113 | { 114 | const SPK::LinearForce* linearForce = dynamic_cast(modifier.get()); 115 | GP_ASSERT(linearForce); 116 | createDebugGeomteriesFromZone(linearForce->getZone()); 117 | } 118 | } 119 | } 120 | 121 | DebugDraw::getInstance()->end(); 122 | } 123 | 124 | 125 | 126 | 127 | FrameBuffer* _frameBuffer; 128 | #include 129 | 130 | 131 | SparkNodeRender::SparkNodeRender() : 132 | GPRenderer3D(), 133 | _isShowDebug(true) 134 | { 135 | 136 | // create a framebuffer for scene preview in imgui window 137 | 138 | const int frameBufferWidth = 512; 139 | const int frameBufferHeight = 512; 140 | 141 | Texture* texColor = Texture::create("targetColor", frameBufferWidth, frameBufferHeight, Texture::Format::RGBA, Texture::Type::TEXTURE_RT); 142 | Texture* texDepth = Texture::create("targetDepth", frameBufferWidth, frameBufferHeight, Texture::Format::D16, Texture::Type::TEXTURE_RT); 143 | std::vector textures; 144 | textures.push_back(texColor); 145 | textures.push_back(texDepth); 146 | _frameBuffer = FrameBuffer::create("MyFrameBuffer", textures); 147 | 148 | View::create(1, Rectangle(frameBufferWidth, frameBufferHeight), View::ClearFlags::COLOR_DEPTH, 0x000000ff, 1.0f, 0); 149 | 150 | 151 | // show gplay in game editor 152 | Game::getInstance()->showEditor(_scene); 153 | 154 | } 155 | 156 | void SparkNodeRender::setCurentParticleSystem(SPK::Ref sparkSystem) 157 | { 158 | Node* node = _scene->findNode("SparkNode"); 159 | if(node) 160 | _scene->removeNode(node); 161 | 162 | // Create a node in scene and attach spark effect 163 | SparkParticleEmitter* sparkEffect = SparkParticleEmitter::create(sparkSystem, true); 164 | Node* sparkNode = Node::create("SparkNode"); 165 | sparkNode->setDrawable(sparkEffect); 166 | sparkNode->setTranslation(0.0f, 0.0f, 0.0f); 167 | 168 | _scene->addNode(sparkNode); 169 | } 170 | 171 | void SparkNodeRender::update(float elapsedTime) 172 | { 173 | // call super class method 174 | GPRenderer3D::update(elapsedTime); 175 | 176 | // show framebuffer inside an imgui window 177 | ImGui::Begin("Game rendering"); 178 | { 179 | bgfx::TextureHandle th = _frameBuffer->getRenderTarget(0)->getTexture()->getHandle()->getHandle(); 180 | ImGui::Image(th, ImVec2(256, 256), ImVec2(0, 0), ImVec2(1, -1) ); 181 | } 182 | ImGui::End(); 183 | 184 | // update emitters 185 | _scene->visit(this, &SparkNodeRender::updateEmitters, elapsedTime); 186 | } 187 | 188 | 189 | void SparkNodeRender::render(float elapsedTime) 190 | { 191 | View::getView(1)->bind(); 192 | _frameBuffer->bind(); 193 | _scene->visit(this, &SparkNodeRender::drawScene); 194 | 195 | View::getView(0)->bind(); 196 | _scene->visit(this, &SparkNodeRender::drawScene); 197 | } 198 | 199 | bool SparkNodeRender::drawScene(Node* node) 200 | { 201 | Drawable* drawable = node->getDrawable(); 202 | if (drawable) 203 | drawable->draw(); 204 | return true; 205 | } 206 | 207 | bool SparkNodeRender::updateEmitters(Node* node, float elapsedTime) 208 | { 209 | SparkParticleEmitter* spkEffect = dynamic_cast(node->getDrawable()); 210 | if (spkEffect) 211 | spkEffect->update(elapsedTime); 212 | 213 | // show debug shapes for all zones in spark system 214 | if(spkEffect && _isShowDebug) 215 | { 216 | drawDebugShapes(spkEffect, _scene); 217 | } 218 | 219 | return true; 220 | } 221 | 222 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SparkNodeRender.h: -------------------------------------------------------------------------------- 1 | #ifndef SPKRENDERER_H 2 | #define SPKRENDERER_H 3 | 4 | #include "../../gp3d/GPRenderer.h" 5 | #include 6 | 7 | class SparkNodeRender : public GPRenderer3D 8 | { 9 | public: 10 | SparkNodeRender(); 11 | 12 | void setCurentParticleSystem(SPK::Ref sparkSystem); 13 | 14 | void update(float elapsedTime) override; 15 | void render(float elapsedTime) override; 16 | 17 | bool updateEmitters(Node* node, float elapsedTime); 18 | bool drawScene(Node* node); 19 | 20 | private: 21 | bool _isShowDebug; // show debug shapes in effects 22 | }; 23 | 24 | #endif // SPKRENDERER_H 25 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SparkNodesRegistry.cpp: -------------------------------------------------------------------------------- 1 | #include "spark-nodes.h" 2 | 3 | std::shared_ptr registerSparkNodesDataModels() 4 | { 5 | auto ret = std::make_shared(); 6 | 7 | ret->registerModel("test"); 8 | 9 | ret->registerModel("zones"); 10 | ret->registerModel("zones"); 11 | ret->registerModel("zones"); 12 | ret->registerModel("zones"); 13 | ret->registerModel("zones"); 14 | ret->registerModel("zones"); 15 | 16 | ret->registerModel("system"); 17 | ret->registerModel("system"); 18 | ret->registerModel("system"); 19 | ret->registerModel("renderer"); 20 | 21 | ret->registerModel("emitters"); 22 | ret->registerModel("emitters"); 23 | ret->registerModel("emitters"); 24 | ret->registerModel("emitters"); 25 | ret->registerModel("emitters"); 26 | ret->registerModel("emitters"); 27 | 28 | ret->registerModel("modifiers"); 29 | ret->registerModel("modifiers"); 30 | ret->registerModel("modifiers"); 31 | ret->registerModel("modifiers"); 32 | ret->registerModel("modifiers"); 33 | ret->registerModel("modifiers"); 34 | ret->registerModel("modifiers"); 35 | ret->registerModel("modifiers"); 36 | ret->registerModel("modifiers"); 37 | ret->registerModel("modifiers"); 38 | ret->registerModel("modifiers"); 39 | ret->registerModel("modifiers"); 40 | 41 | ret->registerModel("interpolators"); 42 | ret->registerModel("interpolators"); 43 | ret->registerModel("interpolators"); 44 | ret->registerModel("interpolators"); 45 | ret->registerModel("interpolators"); 46 | ret->registerModel("interpolators"); 47 | 48 | ret->registerModel("interpolators"); 49 | ret->registerModel("interpolators"); 50 | ret->registerModel("interpolators"); 51 | ret->registerModel("interpolators"); 52 | ret->registerModel("interpolators"); 53 | 54 | return ret; 55 | } 56 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SparkNodesRegistry.h: -------------------------------------------------------------------------------- 1 | #ifndef SPARKNODESREGISTRY_H 2 | #define SPARKNODESREGISTRY_H 3 | 4 | #include 5 | using QtNodes::DataModelRegistry; 6 | 7 | std::shared_ptr registerSparkNodesDataModels(); 8 | 9 | 10 | #endif // SPARKNODESREGISTRY_H 11 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SpkEmitters.cpp: -------------------------------------------------------------------------------- 1 | #include "SpkEmitters.h" 2 | #include "core/Base.h" 3 | 4 | //-------------------------------------------------------------------------------------------- 5 | // base spark emitter 6 | //-------------------------------------------------------------------------------------------- 7 | 8 | void NodeSparkEmitterBase::createBaseEmitterParams(eString name, bool shared) 9 | { 10 | // create base SPKObject parameters 11 | createBaseObjectParams(name,shared); 12 | 13 | // create base Emitter parameters 14 | PARAM_BOOL("Active", eTRUE); 15 | PARAM_IXY("Tank", -1, 10000, -1, -1); 16 | PARAM_FLOAT("Flow", -1, eF32_MAX, 25); 17 | PARAM_FXY("Force", eF32_MIN, eF32_MAX, 1.0f, 1.0f); 18 | } 19 | 20 | void NodeSparkEmitterBase::setBaseEmitterParams(SPK::Ref emitter) 21 | { 22 | if(emitter) 23 | { 24 | // get parameters 25 | bool active = getParameter("Active")->baseValue.get(); 26 | eIXY tank = getParameter("Tank")->baseValue.get(); 27 | eF32 flow = getParameter("Flow")->baseValue.get(); 28 | eFXY force = getParameter("Force")->baseValue.get(); 29 | 30 | // check parameters entries 31 | float minTank = tank.x; 32 | float maxTank = tank.y; 33 | if (minTank < 0 || maxTank < 0) minTank = maxTank = -1; 34 | if (minTank > maxTank) 35 | { 36 | // min tank is greater than max tank. Swap values. 37 | std::swap(minTank,maxTank); 38 | } 39 | 40 | // set Emitter parameters 41 | emitter->setActive(active); 42 | emitter->setTank(minTank, maxTank); 43 | emitter->setFlow(flow); 44 | emitter->setForce(force.x, force.y); 45 | 46 | // set base SPKObject parameters 47 | setBaseObjectParams(emitter); 48 | } 49 | } 50 | 51 | void NodeSparkEmitterBase::setResult(SPK::Ref emitter) 52 | { 53 | if(_emitters.size() > 1) 54 | _emitters.back().reset(); 55 | _emitters.clear(); 56 | _emitters.push_back(emitter); 57 | } 58 | 59 | //-------------------------------------------------------------------------------------------- 60 | // emitters list node 61 | //-------------------------------------------------------------------------------------------- 62 | 63 | NodeSparkEmitterList::NodeSparkEmitterList() 64 | { 65 | IN_PORT(ENC_EMITTER, "emitter"); 66 | IN_PORT(ENC_EMITTER, "emitter"); 67 | IN_PORT(ENC_EMITTER, "emitter"); 68 | IN_PORT(ENC_EMITTER, "emitter"); 69 | IN_PORT(ENC_EMITTER, "emitter"); 70 | OUT_PORT(ENC_EMITTER, "emitters"); 71 | } 72 | 73 | void NodeSparkEmitterList::process() 74 | { 75 | _emitters.clear(); 76 | for(size_t i=0; i<_inputs.size(); i++) 77 | { 78 | std::shared_ptr in = getInput(i); 79 | if(in.get()) 80 | { 81 | for(size_t j=0; j_result.size(); j++) 82 | _emitters.push_back(in->_result[j]); 83 | } 84 | } 85 | 86 | dataUpdated(0); 87 | } 88 | 89 | //-------------------------------------------------------------------------------------------- 90 | // static emitter node 91 | //-------------------------------------------------------------------------------------------- 92 | 93 | NodeSparkEmitterStatic::NodeSparkEmitterStatic() 94 | { 95 | IN_PORT(ENC_ZONE, "zone"); 96 | OUT_PORT(ENC_EMITTER, "emitter"); 97 | 98 | createBaseEmitterParams("StaticEmit"); 99 | } 100 | 101 | void NodeSparkEmitterStatic::process() 102 | { 103 | // create new emitter 104 | SPK::Ref staticEmitter = SPK::StaticEmitter::create(); 105 | 106 | // set base emitter parameters 107 | setBaseEmitterParams(staticEmitter); 108 | 109 | // set zone if exists 110 | std::shared_ptr inZone = getInput(0); 111 | if(inZone && inZone->_result.get()) 112 | { 113 | staticEmitter->setZone(inZone->_result); 114 | } 115 | 116 | // set new emitter as node result 117 | setResult(staticEmitter); 118 | 119 | // trigger nodes connections 120 | dataUpdated(0); 121 | } 122 | 123 | //-------------------------------------------------------------------------------------------- 124 | // spheric emitter node 125 | //-------------------------------------------------------------------------------------------- 126 | 127 | NodeSparkEmitterSpheric::NodeSparkEmitterSpheric() 128 | { 129 | IN_PORT(ENC_ZONE, "zone"); 130 | OUT_PORT(ENC_EMITTER, "emitter"); 131 | 132 | createBaseEmitterParams("SphericEmit"); 133 | PARAM_FXYZ("Direction", eF32_MIN, eF32_MAX, 0.0f, 1.0f, 0.0f); 134 | PARAM_FXY("Angles", 0, 2, 0.0f, 0.0f); 135 | } 136 | 137 | void NodeSparkEmitterSpheric::process() 138 | { 139 | // get parameters 140 | eFXYZ direction = getParameter("Direction")->getValueAsFXYZ(); 141 | eFXY angles = getParameter("Angles")->getValueAsFXY(); 142 | 143 | // create new emitter 144 | SPK::Ref sphericEmitter = SPK::SphericEmitter::create(); 145 | sphericEmitter->setDirection( SPK::Vector3D(direction.x, direction.y, direction.z) ); 146 | sphericEmitter->setAngles(angles.x * MATH_PI, angles.y * MATH_PI); 147 | 148 | // set base emitter parameters 149 | setBaseEmitterParams(sphericEmitter); 150 | 151 | // set zone if exists 152 | std::shared_ptr inZone = getInput(0); 153 | if(inZone && inZone->_result.get()) 154 | { 155 | sphericEmitter->setZone(inZone->_result); 156 | } 157 | 158 | // set new emitter as node result 159 | setResult(sphericEmitter); 160 | 161 | // trigger nodes connections 162 | dataUpdated(0); 163 | } 164 | 165 | //-------------------------------------------------------------------------------------------- 166 | // random emitter node 167 | //-------------------------------------------------------------------------------------------- 168 | 169 | NodeSparkEmitterRandom::NodeSparkEmitterRandom() 170 | { 171 | IN_PORT(ENC_ZONE, "zone"); 172 | OUT_PORT(ENC_EMITTER, "emitter"); 173 | 174 | createBaseEmitterParams("RandomEmit"); 175 | } 176 | 177 | void NodeSparkEmitterRandom::process() 178 | { 179 | // create new emitter 180 | SPK::Ref randomEmitter = SPK::RandomEmitter::create(); 181 | 182 | // set base emitter parameters 183 | setBaseEmitterParams(randomEmitter); 184 | 185 | // set zone if exists 186 | std::shared_ptr inZone = getInput(0); 187 | if(inZone && inZone->_result.get()) 188 | { 189 | randomEmitter->setZone(inZone->_result); 190 | } 191 | 192 | // set new emitter as node result 193 | setResult(randomEmitter); 194 | 195 | // trigger nodes connections 196 | dataUpdated(0); 197 | } 198 | 199 | //-------------------------------------------------------------------------------------------- 200 | // straight emitter node 201 | //-------------------------------------------------------------------------------------------- 202 | 203 | NodeSparkEmitterStraight::NodeSparkEmitterStraight() 204 | { 205 | IN_PORT(ENC_ZONE, "zone"); 206 | OUT_PORT(ENC_EMITTER, "emitter"); 207 | 208 | createBaseEmitterParams("RandomEmit"); 209 | PARAM_FXYZ("Direction", eF32_MIN, eF32_MAX, 0.0f, 1.0f, 0.0f); 210 | } 211 | 212 | void NodeSparkEmitterStraight::process() 213 | { 214 | // get parameters 215 | eFXYZ direction = getParameter("Direction")->getValueAsFXYZ(); 216 | 217 | // create new emitter 218 | SPK::Ref straightEmitter = SPK::StraightEmitter::create(); 219 | straightEmitter->setDirection(ToSpkVector3D(direction)); 220 | 221 | // set base emitter parameters 222 | setBaseEmitterParams(straightEmitter); 223 | 224 | // set zone if exists 225 | std::shared_ptr inZone = getInput(0); 226 | if(inZone && inZone->_result.get()) 227 | { 228 | straightEmitter->setZone(inZone->_result); 229 | } 230 | 231 | // set new emitter as node result 232 | setResult(straightEmitter); 233 | 234 | // trigger nodes connections 235 | dataUpdated(0); 236 | } 237 | 238 | 239 | //-------------------------------------------------------------------------------------------- 240 | // normal emitter node 241 | //-------------------------------------------------------------------------------------------- 242 | 243 | NodeSparkEmitterNormal::NodeSparkEmitterNormal() 244 | { 245 | IN_PORT(ENC_ZONE, "zone"); 246 | OUT_PORT(ENC_EMITTER, "emitter"); 247 | 248 | createBaseEmitterParams("NormalEmit"); 249 | PARAM_BOOL("InvertedNormals", eFALSE); 250 | } 251 | 252 | void NodeSparkEmitterNormal::process() 253 | { 254 | // get parameters 255 | bool inverted = getParameter("InvertedNormals")->getValueAsBool(); 256 | 257 | // create new emitter 258 | SPK::Ref normalEmitter = SPK::NormalEmitter::create(); 259 | normalEmitter->setInverted(inverted); 260 | 261 | // set base emitter parameters 262 | setBaseEmitterParams(normalEmitter); 263 | 264 | // set zone if exists 265 | std::shared_ptr inZone = getInput(0); 266 | if(inZone && inZone->_result.get()) 267 | { 268 | normalEmitter->setZone(inZone->_result); 269 | } 270 | 271 | // set new emitter as node result 272 | setResult(normalEmitter); 273 | 274 | // trigger nodes connections 275 | dataUpdated(0); 276 | } 277 | 278 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SpkEmitters.h: -------------------------------------------------------------------------------- 1 | #ifndef SPKEMITTERS_H 2 | #define SPKEMITTERS_H 3 | 4 | #include "../common/BaseNode.h" 5 | 6 | //------------------------------------------------------------------------------------------------------------------------------ 7 | // base spark emitter class 8 | //------------------------------------------------------------------------------------------------------------------------------ 9 | class NodeSparkEmitterBase : public NodeSparkBaseNode 10 | { 11 | protected: 12 | void createBaseEmitterParams(eString name, bool shared = false); 13 | void setBaseEmitterParams(SPK::Ref emitter); 14 | void setResult(SPK::Ref emitter); 15 | 16 | std::vector> _emitters; 17 | }; 18 | 19 | //------------------------------------------------------------------------------------------------------------------------------ 20 | // emitters list node 21 | //------------------------------------------------------------------------------------------------------------------------------ 22 | class NodeSparkEmitterList : public BaseNode 23 | { 24 | private: 25 | std::vector> _emitters; 26 | const QString Name() const override { return QString("Emitters"); } 27 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_emitters); } 28 | void process() override; 29 | public: 30 | NodeSparkEmitterList(); 31 | }; 32 | 33 | //------------------------------------------------------------------------------------------------------------------------------ 34 | // static emitter node 35 | //------------------------------------------------------------------------------------------------------------------------------ 36 | class NodeSparkEmitterStatic : public NodeSparkEmitterBase 37 | { 38 | private: 39 | const QString Name() const override { return QString("StaticEmitter"); } 40 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_emitters); } 41 | void process() override; 42 | public: 43 | NodeSparkEmitterStatic(); 44 | }; 45 | 46 | //------------------------------------------------------------------------------------------------------------------------------ 47 | // spheric emitter node 48 | //------------------------------------------------------------------------------------------------------------------------------ 49 | class NodeSparkEmitterSpheric : public NodeSparkEmitterBase 50 | { 51 | private: 52 | const QString Name() const override { return QString("SphericEmitter"); } 53 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_emitters); } 54 | void process() override; 55 | public: 56 | NodeSparkEmitterSpheric(); 57 | }; 58 | 59 | 60 | //------------------------------------------------------------------------------------------------------------------------------ 61 | // random emitter node 62 | //------------------------------------------------------------------------------------------------------------------------------ 63 | class NodeSparkEmitterRandom : public NodeSparkEmitterBase 64 | { 65 | private: 66 | const QString Name() const override { return QString("RandomEmitter"); } 67 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_emitters); } 68 | void process() override; 69 | public: 70 | NodeSparkEmitterRandom(); 71 | }; 72 | 73 | 74 | //------------------------------------------------------------------------------------------------------------------------------ 75 | // straight emitter node 76 | //------------------------------------------------------------------------------------------------------------------------------ 77 | class NodeSparkEmitterStraight : public NodeSparkEmitterBase 78 | { 79 | private: 80 | const QString Name() const override { return QString("StraightEmitter"); } 81 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_emitters); } 82 | void process() override; 83 | public: 84 | NodeSparkEmitterStraight(); 85 | }; 86 | 87 | 88 | //------------------------------------------------------------------------------------------------------------------------------ 89 | // normal emitter node 90 | //------------------------------------------------------------------------------------------------------------------------------ 91 | class NodeSparkEmitterNormal : public NodeSparkEmitterBase 92 | { 93 | private: 94 | const QString Name() const override { return QString("NormalEmitter"); } 95 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_emitters); } 96 | void process() override; 97 | public: 98 | NodeSparkEmitterNormal(); 99 | }; 100 | 101 | 102 | #endif // SPKEMITTERS_H 103 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SpkInterpolators.h: -------------------------------------------------------------------------------- 1 | #ifndef SPKINTERPOLATORS_H 2 | #define SPKINTERPOLATORS_H 3 | 4 | #include "../common/BaseNode.h" 5 | 6 | //------------------------------------------------------------------------------------------------------------------------------ 7 | // path node 8 | //------------------------------------------------------------------------------------------------------------------------------ 9 | class NodePath : public BaseNode 10 | { 11 | Path* _path; 12 | private: 13 | const QString Name() const override { return QString("Path"); } 14 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_path); } 15 | void process() override; 16 | public: 17 | NodePath(); 18 | Path* getResult() { return _path; } 19 | }; 20 | 21 | 22 | //------------------------------------------------------------------------------------------------------------------------------ 23 | // base spark color interpolator class 24 | //------------------------------------------------------------------------------------------------------------------------------ 25 | class NodeSparkColorInterpolatorBase : public NodeSparkBaseNode 26 | { 27 | protected: 28 | void setResult(const SPK::Ref> &colorInterpolator); 29 | SPK::Ref> _colorInterpolator; 30 | }; 31 | 32 | //------------------------------------------------------------------------------------------------------------------------------ 33 | // base spark param interpolator class 34 | //------------------------------------------------------------------------------------------------------------------------------ 35 | class NodeSparkParamInterpolatorBase : public NodeSparkBaseNode 36 | { 37 | protected: 38 | void setResult(const ParamFloatInterpolator& interpolator); 39 | std::vector _paramInterpolators; 40 | }; 41 | 42 | //------------------------------------------------------------------------------------------------------------------------------ 43 | // default color initializer node 44 | //------------------------------------------------------------------------------------------------------------------------------ 45 | class NodeSparkInterpolator_ColorInitializerDefault : public NodeSparkColorInterpolatorBase 46 | { 47 | private: 48 | const QString Name() const override { return QString("ColorInitializer"); } 49 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_colorInterpolator); } 50 | void process() override; 51 | public: 52 | NodeSparkInterpolator_ColorInitializerDefault(); 53 | }; 54 | 55 | //------------------------------------------------------------------------------------------------------------------------------ 56 | // random color initializer node 57 | //------------------------------------------------------------------------------------------------------------------------------ 58 | class NodeSparkInterpolator_ColorInitializerRandom : public NodeSparkColorInterpolatorBase 59 | { 60 | private: 61 | const QString Name() const override { return QString("ColorRandomInitializer"); } 62 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_colorInterpolator); } 63 | void process() override; 64 | public: 65 | NodeSparkInterpolator_ColorInitializerRandom(); 66 | }; 67 | 68 | //------------------------------------------------------------------------------------------------------------------------------ 69 | // simple color interpolator node 70 | //------------------------------------------------------------------------------------------------------------------------------ 71 | class NodeSparkInterpolator_ColorInterpolatorSimple : public NodeSparkColorInterpolatorBase 72 | { 73 | private: 74 | const QString Name() const override { return QString("ColorSimpleInterpolator"); } 75 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_colorInterpolator); } 76 | void process() override; 77 | public: 78 | NodeSparkInterpolator_ColorInterpolatorSimple(); 79 | }; 80 | 81 | //------------------------------------------------------------------------------------------------------------------------------ 82 | // random color interpolator node 83 | //------------------------------------------------------------------------------------------------------------------------------ 84 | class NodeSparkInterpolator_ColorInterpolatorRandom : public NodeSparkColorInterpolatorBase 85 | { 86 | private: 87 | const QString Name() const override { return QString("ColorRandomInterpolator"); } 88 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_colorInterpolator); } 89 | void process() override; 90 | public: 91 | NodeSparkInterpolator_ColorInterpolatorRandom(); 92 | }; 93 | 94 | //------------------------------------------------------------------------------------------------------------------------------ 95 | // graph color interpolator node 96 | //------------------------------------------------------------------------------------------------------------------------------ 97 | class NodeSparkInterpolator_ColorInterpolatorGraph : public NodeSparkColorInterpolatorBase 98 | { 99 | private: 100 | const QString Name() const override { return QString("ColorGraphInterpolator"); } 101 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_colorInterpolator); } 102 | void process() override; 103 | public: 104 | NodeSparkInterpolator_ColorInterpolatorGraph(); 105 | }; 106 | 107 | 108 | 109 | 110 | 111 | 112 | //------------------------------------------------------------------------------------------------------------------------------ 113 | // param interpolator list node 114 | //------------------------------------------------------------------------------------------------------------------------------ 115 | class NodeSparkInterpolatorParamList : public NodeSparkParamInterpolatorBase 116 | { 117 | private: 118 | const QString Name() const override { return QString("Params"); } 119 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_paramInterpolators); } 120 | void process() override; 121 | public: 122 | NodeSparkInterpolatorParamList(); 123 | }; 124 | 125 | //------------------------------------------------------------------------------------------------------------------------------ 126 | // default param initializer node 127 | //------------------------------------------------------------------------------------------------------------------------------ 128 | class NodeSparkInterpolator_ParamInitializer : public NodeSparkParamInterpolatorBase 129 | { 130 | private: 131 | const QString Name() const override { return QString("ParamInitializer"); } 132 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_paramInterpolators); } 133 | void process() override; 134 | public: 135 | NodeSparkInterpolator_ParamInitializer(); 136 | }; 137 | 138 | //------------------------------------------------------------------------------------------------------------------------------ 139 | // random param initializer node 140 | //------------------------------------------------------------------------------------------------------------------------------ 141 | class NodeSparkInterpolator_ParamInitializerRandom : public NodeSparkParamInterpolatorBase 142 | { 143 | private: 144 | const QString Name() const override { return QString("ParamRandomInitializer"); } 145 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_paramInterpolators); } 146 | void process() override; 147 | public: 148 | NodeSparkInterpolator_ParamInitializerRandom(); 149 | }; 150 | 151 | //------------------------------------------------------------------------------------------------------------------------------ 152 | // simple param interpolator node 153 | //------------------------------------------------------------------------------------------------------------------------------ 154 | class NodeSparkInterpolator_ParamInterpolatorSimple : public NodeSparkParamInterpolatorBase 155 | { 156 | private: 157 | const QString Name() const override { return QString("ParamSimpleInterpolator"); } 158 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_paramInterpolators); } 159 | void process() override; 160 | public: 161 | NodeSparkInterpolator_ParamInterpolatorSimple(); 162 | }; 163 | 164 | //------------------------------------------------------------------------------------------------------------------------------ 165 | // random param interpolator node 166 | //------------------------------------------------------------------------------------------------------------------------------ 167 | class NodeSparkInterpolator_ParamInterpolatorRandom : public NodeSparkParamInterpolatorBase 168 | { 169 | private: 170 | const QString Name() const override { return QString("ParamRandomInterpolator"); } 171 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_paramInterpolators); } 172 | void process() override; 173 | public: 174 | NodeSparkInterpolator_ParamInterpolatorRandom(); 175 | }; 176 | 177 | 178 | 179 | #endif // SPKINTERPOLATORS_H 180 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SpkModifiers.h: -------------------------------------------------------------------------------- 1 | #ifndef SPKMODIFIERS_H 2 | #define SPKMODIFIERS_H 3 | 4 | #include "../common/BaseNode.h" 5 | 6 | //------------------------------------------------------------------------------------------------------------------------------ 7 | // base spark modifier class 8 | //------------------------------------------------------------------------------------------------------------------------------ 9 | class NodeSparkModifierBase : public NodeSparkBaseNode 10 | { 11 | protected: 12 | void createBaseModifierParams(eString name, bool shared = false); 13 | void setBaseModifierParams(SPK::Ref modifier); 14 | void setResult(SPK::Ref modifier); 15 | 16 | std::vector> _modifiers; 17 | }; 18 | 19 | //------------------------------------------------------------------------------------------------------------------------------ 20 | // modifiers list node 21 | //------------------------------------------------------------------------------------------------------------------------------ 22 | class NodeSparkModifierList : public BaseNode 23 | { 24 | private: 25 | std::vector> _modifiers; 26 | const QString Name() const override { return QString("Modifiers"); } 27 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_modifiers); } 28 | void process() override; 29 | public: 30 | NodeSparkModifierList(); 31 | }; 32 | 33 | 34 | //------------------------------------------------------------------------------------------------------------------------------ 35 | // gravity modifier node 36 | //------------------------------------------------------------------------------------------------------------------------------ 37 | class NodeSparkModifierGravity : public NodeSparkModifierBase 38 | { 39 | private: 40 | const QString Name() const override { return QString("Gravity"); } 41 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_modifiers); } 42 | void process() override; 43 | public: 44 | NodeSparkModifierGravity(); 45 | }; 46 | 47 | 48 | //------------------------------------------------------------------------------------------------------------------------------ 49 | // friction modifier node 50 | //------------------------------------------------------------------------------------------------------------------------------ 51 | class NodeSparkModifierFriction : public NodeSparkModifierBase 52 | { 53 | private: 54 | const QString Name() const override { return QString("Friction"); } 55 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_modifiers); } 56 | void process() override; 57 | public: 58 | NodeSparkModifierFriction(); 59 | }; 60 | 61 | 62 | //------------------------------------------------------------------------------------------------------------------------------ 63 | // collider modifier node 64 | //------------------------------------------------------------------------------------------------------------------------------ 65 | class NodeSparkModifierCollider : public NodeSparkModifierBase 66 | { 67 | private: 68 | const QString Name() const override { return QString("Collider"); } 69 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_modifiers); } 70 | void process() override; 71 | public: 72 | NodeSparkModifierCollider(); 73 | }; 74 | 75 | 76 | //------------------------------------------------------------------------------------------------------------------------------ 77 | // destroyer modifier node 78 | //------------------------------------------------------------------------------------------------------------------------------ 79 | class NodeSparkModifierDestroyer : public NodeSparkModifierBase 80 | { 81 | private: 82 | const QString Name() const override { return QString("Destroyer"); } 83 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_modifiers); } 84 | void process() override; 85 | public: 86 | NodeSparkModifierDestroyer(); 87 | }; 88 | 89 | 90 | //------------------------------------------------------------------------------------------------------------------------------ 91 | // obstacle modifier node 92 | //------------------------------------------------------------------------------------------------------------------------------ 93 | class NodeSparkModifierObstacle : public NodeSparkModifierBase 94 | { 95 | private: 96 | const QString Name() const override { return QString("Obstacle"); } 97 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_modifiers); } 98 | void process() override; 99 | public: 100 | NodeSparkModifierObstacle(); 101 | }; 102 | 103 | 104 | //------------------------------------------------------------------------------------------------------------------------------ 105 | // pointmass modifier node 106 | //------------------------------------------------------------------------------------------------------------------------------ 107 | class NodeSparkModifierPointMass : public NodeSparkModifierBase 108 | { 109 | private: 110 | const QString Name() const override { return QString("PointMass"); } 111 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_modifiers); } 112 | void process() override; 113 | public: 114 | NodeSparkModifierPointMass(); 115 | }; 116 | 117 | 118 | //------------------------------------------------------------------------------------------------------------------------------ 119 | // random force modifier node 120 | //------------------------------------------------------------------------------------------------------------------------------ 121 | class NodeSparkModifierRandomForce : public NodeSparkModifierBase 122 | { 123 | private: 124 | const QString Name() const override { return QString("RandomForce"); } 125 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_modifiers); } 126 | void process() override; 127 | public: 128 | NodeSparkModifierRandomForce(); 129 | }; 130 | 131 | 132 | //------------------------------------------------------------------------------------------------------------------------------ 133 | // rotator modifier node 134 | //------------------------------------------------------------------------------------------------------------------------------ 135 | class NodeSparkModifierRotator : public NodeSparkModifierBase 136 | { 137 | private: 138 | const QString Name() const override { return QString("Rotator"); } 139 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_modifiers); } 140 | void process() override; 141 | public: 142 | NodeSparkModifierRotator(); 143 | }; 144 | 145 | 146 | //------------------------------------------------------------------------------------------------------------------------------ 147 | // vortex modifier node 148 | //------------------------------------------------------------------------------------------------------------------------------ 149 | class NodeSparkModifierVortex : public NodeSparkModifierBase 150 | { 151 | private: 152 | const QString Name() const override { return QString("Vortex"); } 153 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_modifiers); } 154 | void process() override; 155 | public: 156 | NodeSparkModifierVortex(); 157 | }; 158 | 159 | 160 | //------------------------------------------------------------------------------------------------------------------------------ 161 | // emitterAttacher modifier node 162 | //------------------------------------------------------------------------------------------------------------------------------ 163 | class NodeSparkModifierEmitterAttacher : public NodeSparkModifierBase 164 | { 165 | private: 166 | const QString Name() const override { return QString("EmitterAttacher"); } 167 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_modifiers); } 168 | void process() override; 169 | public: 170 | NodeSparkModifierEmitterAttacher(); 171 | }; 172 | 173 | 174 | //------------------------------------------------------------------------------------------------------------------------------ 175 | // linearForce modifier node 176 | //------------------------------------------------------------------------------------------------------------------------------ 177 | class NodeSparkModifierLinearForce : public NodeSparkModifierBase 178 | { 179 | private: 180 | const QString Name() const override { return QString("LinearForce"); } 181 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_modifiers); } 182 | void process() override; 183 | public: 184 | NodeSparkModifierLinearForce(); 185 | }; 186 | #endif // SPKMODIFIERS_H 187 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SpkSystem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "SpkSystem.h" 7 | #include "../../GplayDevice.h" 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | //------------------------------------------------------------------------------------------------------------------------------ 15 | // group list 16 | //------------------------------------------------------------------------------------------------------------------------------ 17 | 18 | NodeSparkGroupList::NodeSparkGroupList() 19 | { 20 | IN_PORT(ENC_GROUP, "group"); 21 | IN_PORT(ENC_GROUP, "group"); 22 | IN_PORT(ENC_GROUP, "group"); 23 | IN_PORT(ENC_GROUP, "group"); 24 | IN_PORT(ENC_GROUP, "group"); 25 | OUT_PORT(ENC_GROUP, "groups"); 26 | } 27 | 28 | void NodeSparkGroupList::process() 29 | { 30 | _groups.clear(); 31 | for(size_t i=0; i<_inputs.size(); i++) 32 | { 33 | std::shared_ptr in = getInput(i); 34 | if(in.get()) 35 | { 36 | for(size_t j=0; j_result.size(); j++) 37 | _groups.push_back(in->_result[j]); 38 | } 39 | } 40 | 41 | dataUpdated(0); 42 | } 43 | 44 | 45 | //-------------------------------------------------------------------------------------------- 46 | // group 47 | //-------------------------------------------------------------------------------------------- 48 | 49 | NodeSparkGroup::NodeSparkGroup() 50 | { 51 | IN_PORT(ENC_RENDERER, "renderer"); 52 | IN_PORT(ENC_EMITTER, "emitters"); 53 | IN_PORT(ENC_COLORINTERPOLATOR, "colors"); 54 | IN_PORT(ENC_PARAMINTERPOLATOR, "params"); 55 | IN_PORT(ENC_MODIFIER, "modifiers"); 56 | OUT_PORT(ENC_GROUP, "group"); 57 | 58 | //createBaseObjectParams("Group"); 59 | PARAM_INT("Capacity", 1, 500000, 100); 60 | PARAM_FXY("Lifetime", 0.000001, eF32_MAX, 1.0f, 1.0f); 61 | PARAM_BOOL("Immortal", false); 62 | PARAM_FLOAT("GraphicalRadius", 0, eF32_MAX, 1.0f); 63 | PARAM_FLOAT("PhysicalRadius", 0, eF32_MAX, 0.0f); 64 | PARAM_BOOL("Sorted", false); 65 | } 66 | 67 | void NodeSparkGroup::process() 68 | { 69 | const unsigned int INPUT_RENDERER_INDEX = 0; 70 | const unsigned int INPUT_EMITTERS_INDEX = 1; 71 | const unsigned int INPUT_COLORINTERPOLATOR_INDEX = 2; 72 | const unsigned int INPUT_PARAMSINTERPOLATOR_INDEX = 3; 73 | const unsigned int INPUT_MODIFIERS_INDEX = 4; 74 | 75 | // get parameters 76 | eInt capacity = getParameter("Capacity")->getValueAsInt(); 77 | eFXY lifetime = getParameter("Lifetime")->getValueAsFXY(); 78 | bool immortal = getParameter("Immortal")->getValueAsBool(); 79 | eF32 graphicalRadius = getParameter("GraphicalRadius")->getValueAsFloat(); 80 | eF32 physicalRadius = getParameter("PhysicalRadius")->getValueAsFloat(); 81 | bool sorted = getParameter("Sorted")->getValueAsBool(); 82 | 83 | // create new group 84 | SPK::Ref group = SPK::Group::create(capacity); 85 | //setBaseObjectParams(group); 86 | group->setLifeTime(lifetime.x, lifetime.y); 87 | group->setImmortal(immortal); 88 | group->setGraphicalRadius(graphicalRadius); 89 | group->setPhysicalRadius(physicalRadius); 90 | group->enableSorting(sorted); 91 | 92 | // set renderer 93 | std::shared_ptr inRenderer = getInput(INPUT_RENDERER_INDEX); 94 | if(inRenderer && inRenderer->_result.get()) 95 | { 96 | group->setRenderer(inRenderer->_result); 97 | } 98 | else 99 | { 100 | setValidationState(NodeValidationState::Error, "Missing renderer input"); 101 | return; 102 | } 103 | 104 | // add emitters 105 | std::shared_ptr inEmitters = getInput(INPUT_EMITTERS_INDEX); 106 | if(inEmitters) 107 | { 108 | for(size_t i=0; i_result.size(); i++) 109 | { 110 | if(inEmitters->_result[i].get()) 111 | group->addEmitter(inEmitters->_result[i]); 112 | } 113 | } 114 | 115 | // add modifiers 116 | std::shared_ptr inModifiers = getInput(INPUT_MODIFIERS_INDEX); 117 | if(inModifiers) 118 | { 119 | for(size_t i=0; i_result.size(); i++) 120 | { 121 | if(inModifiers->_result[i].get()) 122 | group->addModifier(inModifiers->_result[i]); 123 | } 124 | } 125 | 126 | // set color interpolator 127 | std::shared_ptr inColors = getInput(INPUT_COLORINTERPOLATOR_INDEX); 128 | if(inColors) 129 | { 130 | group->setColorInterpolator(inColors->_result); 131 | } 132 | 133 | // set param interpolators 134 | std::shared_ptr inParams = getInput(INPUT_PARAMSINTERPOLATOR_INDEX); 135 | if(inParams && inParams.get()) 136 | { 137 | for(size_t i=0; i_result.size(); i++) 138 | { 139 | if(inParams->_result[i].interpolatorFloat) 140 | group->setParamInterpolator(inParams->_result[i].param, inParams->_result[i].interpolatorFloat); 141 | } 142 | } 143 | 144 | // store result 145 | if(_groups.size() > 1) 146 | _groups.back().reset(); 147 | _groups.clear(); 148 | _groups.push_back(group); 149 | 150 | setValidationState(NodeValidationState::Valid); 151 | 152 | dataUpdated(0); 153 | } 154 | 155 | //-------------------------------------------------------------------------------------------- 156 | // system 157 | //-------------------------------------------------------------------------------------------- 158 | 159 | NodeSparkSystem::NodeSparkSystem() 160 | { 161 | IN_PORT(ENC_GROUP, "groups"); 162 | 163 | PARAM_STRING("Name", "System"); 164 | PARAM_BOOL("Initialized", eTRUE); 165 | } 166 | 167 | void NodeSparkSystem::process() 168 | { 169 | QString name = getParameter("Name")->getValueAsString(); 170 | bool initialized = getParameter("Initialized")->getValueAsBool(); 171 | 172 | /*if(!_system.get()) 173 | _system = SPK::System::create(true); 174 | else 175 | _system->removeAllGroups();*/ 176 | 177 | _system = SPK::System::create(initialized); 178 | _system->setName(name.toStdString()); 179 | 180 | // add groups 181 | std::shared_ptr in0 = getInput(0); 182 | if(in0) 183 | { 184 | for(size_t i=0; i_result.size(); i++) 185 | { 186 | if(in0->_result[i].get()) 187 | _system->addGroup(in0->_result[i]); 188 | } 189 | } 190 | 191 | GplayDevice::getInstance()->setCurentParticleSystem(_system); 192 | } 193 | 194 | 195 | //-------------------------------------------------------------------------------------------- 196 | // quad renderer node 197 | //-------------------------------------------------------------------------------------------- 198 | 199 | NodeSparkQuadRenderer::NodeSparkQuadRenderer() 200 | { 201 | OUT_PORT(ENC_RENDERER, "renderer"); 202 | 203 | createBaseObjectParams("Renderer"); 204 | PARAM_FILE("Material", "res/data/materials/particle.material"); 205 | PARAM_FILE("Texture", "res/data/textures/flare.png"); 206 | PARAM_IXY("AtlasDimension", 1, 1000, 1, 1); 207 | PARAM_FXY("Scale", 0.0f, eF32_MAX, 1.0f, 1.0f); 208 | PARAM_ENUM("Orientation", "CAMERA_PLANE_ALIGNED" 209 | "|CAMERA_POINT_ALIGNED" 210 | "|DIRECTION_ALIGNED" 211 | "|AROUND_AXIS" 212 | "|TOWARDS_POINT" 213 | "|FIXED_ORIENTATION", 0); 214 | } 215 | 216 | Material* createDefaultMaterial() 217 | { 218 | // Create a material for particles 219 | Material* material = Material::create("res/core/shaders/particle.vert", "res/core/shaders/particle.frag"); 220 | Texture::Sampler* sampler = material->getParameter("u_diffuseTexture")->setValue("res/data/textures/flare.png", true); 221 | sampler->setFilterMode(Texture::LINEAR_MIPMAP_LINEAR, Texture::LINEAR); 222 | material->getStateBlock()->setCullFace(true); 223 | material->getStateBlock()->setDepthTest(true); 224 | material->getStateBlock()->setDepthWrite(false); 225 | material->getStateBlock()->setBlend(true); 226 | material->getStateBlock()->setBlendSrc(RenderState::BLEND_SRC_ALPHA); 227 | material->getStateBlock()->setBlendDst(RenderState::BLEND_ONE); 228 | 229 | return material; 230 | } 231 | 232 | void NodeSparkQuadRenderer::process() 233 | { 234 | // get parameters 235 | std::string materialFile(getParameter("Material")->getValueAsString().toStdString()); 236 | std::string textureFile(getParameter("Texture")->getValueAsString().toStdString()); 237 | eIXY atlasDimensions = (getParameter("AtlasDimension")->getValueAsIXY()); 238 | eFXY scale = getParameter("Scale")->getValueAsFXY(); 239 | SPK::OrientationPreset orientation = SPK::OrientationPreset(getParameter("Orientation")->getValueAsEnum()); 240 | 241 | bool isMaterialFileExists = gplay::FileSystem::fileExists(materialFile.c_str()); 242 | bool isTextureFileExists = gplay::FileSystem::fileExists(textureFile.c_str()); 243 | 244 | Material* material = createDefaultMaterial(); 245 | material->getParameter("u_diffuseTexture")->setValue(textureFile.c_str(), true); 246 | 247 | // Renderer 248 | SPK::Ref renderer = SPK::GP3D::SparkQuadRenderer::create(); 249 | renderer->setTexturingMode(SPK::TEXTURE_MODE_2D); 250 | renderer->setBlendMode(SPK::BLEND_MODE_ADD); 251 | renderer->enableRenderingOption(SPK::RENDERING_OPTION_DEPTH_WRITE,false); 252 | renderer->setScale(scale.x, scale.y); 253 | renderer->setMaterial(material->clone()); 254 | renderer->setAtlasDimensions(atlasDimensions.x, atlasDimensions.y); 255 | renderer->setOrientation(orientation); 256 | 257 | _renderer.reset(); 258 | _renderer = renderer; 259 | 260 | dataUpdated(0); 261 | } 262 | 263 | 264 | 265 | //------------------------------------------------------------------------------------------------------------------------------ 266 | // test node 267 | //------------------------------------------------------------------------------------------------------------------------------ 268 | 269 | #include 270 | #include "../common/CustomWidgets.h" 271 | 272 | NodeSparkTest::NodeSparkTest() 273 | { 274 | OUT_PORT(ENC_RENDERER, "renderer"); 275 | 276 | PARAM_TEXT("text", "Bonjour"); 277 | PARAM_STRING("string", "Hello"); 278 | PARAM_BOOL("bool", false); 279 | PARAM_INT("int", -5, 5, 2); 280 | PARAM_FLOAT("float", -5.0f, 5.0f, 3.14f); 281 | PARAM_FXY("fxy", -5.0f, 5.0f, 1.0f, 2.0f); 282 | PARAM_FXYZ("fxyz", -5.0f, 5.0f, 1.0f, 2.0f, 3.0f); 283 | PARAM_FXYZW("fxyzw", -5.0f, 5.0f, 1.0f, 2.0f, 3.0f, 4.0f); 284 | PARAM_IXY("ixy", -5, 5, 1, 2); 285 | PARAM_IXYZ("ixyz", -5, 5, 1, 2, 3); 286 | PARAM_IXYZW("ixyzw", -5, 5, 1, 2, 3, 4); 287 | PARAM_ENUM("enum", "enum1|enum2|enum3|num4|enum5", 1); 288 | PARAM_FILE("file", "res/data/textures"); 289 | PARAM_FLAGS("flags", "flag1|flag2|flag3|flag4|flag5", 2) 290 | PARAM_RGBA("rgba", 100, 50, 50, 255); 291 | PARAM_BUTTON("button", "Simple Button"); 292 | 293 | 294 | 295 | // force parameters widget creation immediately to get acess to pushbutton ptr 296 | createParamWidgets(); 297 | 298 | // connect push button to a slot 299 | eButton* button = (eButton*)getParameter("button")->userData(0); 300 | Q_ASSERT(button); 301 | connect(button, &QPushButton::clicked, this, &NodeSparkTest::onTestButtonClick); 302 | } 303 | 304 | void NodeSparkTest::process() 305 | { 306 | 307 | } 308 | 309 | void NodeSparkTest::onTestButtonClick() 310 | { 311 | QMessageBox msgBox; 312 | msgBox.setText("The button has been clicked."); 313 | msgBox.exec(); 314 | } 315 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SpkSystem.h: -------------------------------------------------------------------------------- 1 | #ifndef SPKSYSTEMNODE_H 2 | #define SPKSYSTEMNODE_H 3 | 4 | #include "../common/BaseNode.h" 5 | 6 | //------------------------------------------------------------------------------------------------------------------------------ 7 | // group list 8 | //------------------------------------------------------------------------------------------------------------------------------ 9 | class NodeSparkGroupList : public BaseNode 10 | { 11 | private: 12 | std::vector> _groups; 13 | const QString Name() const override { return QString("Groups"); } 14 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_groups); } 15 | void process() override; 16 | public: 17 | NodeSparkGroupList(); 18 | }; 19 | 20 | //------------------------------------------------------------------------------------------------------------------------------ 21 | // group 22 | //------------------------------------------------------------------------------------------------------------------------------ 23 | class NodeSparkGroup : public NodeSparkBaseNode 24 | { 25 | private: 26 | std::vector> _groups; 27 | const QString Name() const override { return QString("Group"); } 28 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_groups); } 29 | void process() override; 30 | public: 31 | NodeSparkGroup(); 32 | }; 33 | 34 | //------------------------------------------------------------------------------------------------------------------------------ 35 | // system 36 | //------------------------------------------------------------------------------------------------------------------------------ 37 | class NodeSparkSystem : public BaseNode 38 | { 39 | private: 40 | SPK::Ref _system; 41 | const QString Name() const override { return QString("System"); } 42 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_system); } 43 | void process() override; 44 | public: 45 | NodeSparkSystem(); 46 | SPK::Ref getResult() { return _system; } 47 | }; 48 | 49 | //------------------------------------------------------------------------------------------------------------------------------ 50 | // quad renderer 51 | //------------------------------------------------------------------------------------------------------------------------------ 52 | class NodeSparkQuadRenderer : public NodeSparkBaseNode 53 | { 54 | private: 55 | SPK::Ref _renderer; 56 | const QString Name() const override { return QString("QuadRenderer"); } 57 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_renderer); } 58 | void process() override; 59 | public: 60 | NodeSparkQuadRenderer(); 61 | }; 62 | 63 | //------------------------------------------------------------------------------------------------------------------------------ 64 | // test node 65 | //------------------------------------------------------------------------------------------------------------------------------ 66 | class NodeSparkTest : public NodeSparkBaseNode 67 | { 68 | private: 69 | SPK::Ref _renderer; 70 | const QString Name() const override { return QString("Test"); } 71 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_renderer); } 72 | void process() override; 73 | public: 74 | NodeSparkTest(); 75 | 76 | private Q_SLOTS: 77 | void onTestButtonClick(); 78 | }; 79 | 80 | #endif // SPKSYSTEMNODE_H 81 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SpkUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "SpkUtils.h" 2 | 3 | 4 | SPK::Vector3D ToSpkVector3D(const eFXYZ& v) 5 | { 6 | return SPK::Vector3D(v.x, v.y, v.z); 7 | } 8 | 9 | gplay::Vector3 ToGplayVector3(const SPK::Vector3D& v) 10 | { 11 | return gplay::Vector3(v.x, v.y, v.z); 12 | } 13 | 14 | SPK::Color ToSpkColor(const eColor& c) 15 | { 16 | return SPK::Color(c.r, c.g, c.b, c.a); 17 | } 18 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SpkUtils.h: -------------------------------------------------------------------------------- 1 | #ifndef SPKUTILS_H 2 | #define SPKUTILS_H 3 | 4 | #include "spark/SPARK_Core.h" 5 | #include "../math/Vector3.h" 6 | #include "../../node-editor/common/Types.h" 7 | #include "../../node-editor/common/Color.h" 8 | 9 | //---------------------------------------------------------------------------------------------- 10 | // Conversion functions for spark 11 | //---------------------------------------------------------------------------------------------- 12 | 13 | SPK::Vector3D ToSpkVector3D(const eFXYZ& v); 14 | gplay::Vector3 ToGplayVector3(const SPK::Vector3D& v); 15 | SPK::Color ToSpkColor(const eColor& c); 16 | 17 | #endif // SPKUTILS_H 18 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SpkZones.cpp: -------------------------------------------------------------------------------- 1 | #include "SpkZones.h" 2 | 3 | //-------------------------------------------------------------------------------------------- 4 | // base spark zone 5 | //-------------------------------------------------------------------------------------------- 6 | 7 | void NodeSparkZoneBase::createBaseZoneParams(eString name, bool shared) 8 | { 9 | // create base SPKObject parameters 10 | createBaseObjectParams(name,shared); 11 | 12 | // create base Zone parameters 13 | PARAM_FXYZ("Position", eF32_MIN, eF32_MAX, 0.0f, 0.0f, 0.0f); 14 | } 15 | 16 | void NodeSparkZoneBase::setBaseZoneParams(SPK::Ref zone) 17 | { 18 | if(zone) 19 | { 20 | // get parameters 21 | SPK::Vector3D position = ToSpkVector3D(getParameter("Position")->getValueAsFXYZ()); 22 | 23 | // set zone parameters 24 | zone->setPosition(position); 25 | 26 | // set base SPKObject parameters 27 | setBaseObjectParams(zone); 28 | } 29 | } 30 | 31 | void NodeSparkZoneBase::setResult(SPK::Ref zone) 32 | { 33 | _zone.reset(); 34 | _zone = zone; 35 | } 36 | 37 | 38 | //------------------------------------------------------------------------------------------------------------------------------ 39 | // zone point node 40 | //------------------------------------------------------------------------------------------------------------------------------ 41 | 42 | NodeSparkZonePoint::NodeSparkZonePoint() 43 | { 44 | OUT_PORT(ENC_ZONE, "zone"); 45 | 46 | createBaseZoneParams("PointZone"); 47 | } 48 | 49 | void NodeSparkZonePoint::process() 50 | { 51 | SPK::Ref zonePoint = SPK::Point::create(); 52 | setBaseZoneParams(zonePoint); 53 | setResult(zonePoint); 54 | } 55 | 56 | 57 | //------------------------------------------------------------------------------------------------------------------------------ 58 | // plane zone node 59 | //------------------------------------------------------------------------------------------------------------------------------ 60 | 61 | NodeSparkZonePlane::NodeSparkZonePlane() 62 | { 63 | OUT_PORT(ENC_ZONE, "zone"); 64 | 65 | createBaseZoneParams("PlaneZone"); 66 | PARAM_FXYZ("Normal", eF32_MIN, eF32_MAX, 0.0f, 1.0f, 0.0f); 67 | } 68 | 69 | void NodeSparkZonePlane::process() 70 | { 71 | SPK::Vector3D normal = ToSpkVector3D(getParameter("Normal")->getValueAsFXYZ()); 72 | 73 | SPK::Ref zonePlane = SPK::Plane::create(); 74 | zonePlane->setNormal(normal); 75 | setBaseZoneParams(zonePlane); 76 | setResult(zonePlane); 77 | } 78 | 79 | 80 | //------------------------------------------------------------------------------------------------------------------------------ 81 | // sphere zone node 82 | //------------------------------------------------------------------------------------------------------------------------------ 83 | 84 | NodeSparkZoneSphere::NodeSparkZoneSphere() 85 | { 86 | OUT_PORT(ENC_ZONE, "zone"); 87 | 88 | createBaseZoneParams("SphereZone"); 89 | PARAM_FLOAT("Radius", 0.0f, eF32_MAX, 1.0f); 90 | } 91 | 92 | void NodeSparkZoneSphere::process() 93 | { 94 | float radius = getParameter("Radius")->getValueAsFloat(); 95 | 96 | SPK::Ref zoneSphere = SPK::Sphere::create(); 97 | zoneSphere->setRadius(radius); 98 | setBaseZoneParams(zoneSphere); 99 | setResult(zoneSphere); 100 | } 101 | 102 | 103 | //------------------------------------------------------------------------------------------------------------------------------ 104 | // box zone node 105 | //------------------------------------------------------------------------------------------------------------------------------ 106 | 107 | NodeSparkZoneBox::NodeSparkZoneBox() 108 | { 109 | OUT_PORT(ENC_ZONE, "zone"); 110 | 111 | createBaseZoneParams("BoxZone"); 112 | PARAM_FXYZ("Dimensions", eF32_MIN, eF32_MAX, 1.0f, 1.0f, 1.0f); 113 | PARAM_FXYZ("Front", eF32_MIN, eF32_MAX, 0.0f, 0.0f, 1.0f); 114 | PARAM_FXYZ("Up", eF32_MIN, eF32_MAX, 0.0f, 1.0f, 0.0f); 115 | } 116 | 117 | void NodeSparkZoneBox::process() 118 | { 119 | SPK::Vector3D dimensions = ToSpkVector3D(getParameter("Dimensions")->getValueAsFXYZ()); 120 | SPK::Vector3D front = ToSpkVector3D(getParameter("Front")->getValueAsFXYZ()); 121 | SPK::Vector3D up = ToSpkVector3D(getParameter("Up")->getValueAsFXYZ()); 122 | 123 | SPK::Ref zoneBox = SPK::Box::create(); 124 | zoneBox->setDimensions(dimensions); 125 | zoneBox->setAxis(front, up); 126 | setBaseZoneParams(zoneBox); 127 | setResult(zoneBox); 128 | } 129 | 130 | 131 | //------------------------------------------------------------------------------------------------------------------------------ 132 | // cylinder zone node 133 | //------------------------------------------------------------------------------------------------------------------------------ 134 | 135 | NodeSparkZoneCylinder::NodeSparkZoneCylinder() 136 | { 137 | OUT_PORT(ENC_ZONE, "zone"); 138 | 139 | createBaseZoneParams("CylinderZone"); 140 | PARAM_FLOAT("Height", 0.0f, eF32_MAX, 1.0f); 141 | PARAM_FLOAT("Radius", 0.0f, eF32_MAX, 1.0f); 142 | PARAM_FXYZ("Axis", eF32_MIN, eF32_MAX, 0.0f, 1.0f, 0.0f); 143 | } 144 | 145 | void NodeSparkZoneCylinder::process() 146 | { 147 | float height = getParameter("Height")->getValueAsFloat(); 148 | float radius = getParameter("Radius")->getValueAsFloat(); 149 | SPK::Vector3D axis = ToSpkVector3D(getParameter("Axis")->getValueAsFXYZ()); 150 | 151 | SPK::Ref zoneCylinder = SPK::Cylinder::create(); 152 | zoneCylinder->setDimensions(height, radius); 153 | zoneCylinder->setAxis(axis); 154 | setBaseZoneParams(zoneCylinder); 155 | setResult(zoneCylinder); 156 | } 157 | 158 | 159 | //------------------------------------------------------------------------------------------------------------------------------ 160 | // ring zone node 161 | //------------------------------------------------------------------------------------------------------------------------------ 162 | 163 | NodeSparkZoneRing::NodeSparkZoneRing() 164 | { 165 | OUT_PORT(ENC_ZONE, "zone"); 166 | 167 | createBaseZoneParams("RingZone"); 168 | PARAM_FXY("Radius", 0.0f, eF32_MAX, 0.0f, 1.0f); 169 | PARAM_FXYZ("Normal", eF32_MIN, eF32_MAX, 0.0f, 1.0f, 0.0f); 170 | } 171 | 172 | void NodeSparkZoneRing::process() 173 | { 174 | eFXY radius = getParameter("Radius")->getValueAsFXY(); 175 | SPK::Vector3D normal = ToSpkVector3D(getParameter("Normal")->getValueAsFXYZ()); 176 | 177 | SPK::Ref zoneRing = SPK::Ring::create(); 178 | zoneRing->setNormal(normal); 179 | zoneRing->setRadius(radius.x, radius.y); 180 | setBaseZoneParams(zoneRing); 181 | setResult(zoneRing); 182 | } 183 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/SpkZones.h: -------------------------------------------------------------------------------- 1 | #ifndef ZONENODE_H 2 | #define ZONENODE_H 3 | 4 | #include "../common/BaseNode.h" 5 | 6 | //------------------------------------------------------------------------------------------------------------------------------ 7 | // base spark zone class 8 | //------------------------------------------------------------------------------------------------------------------------------ 9 | class NodeSparkZoneBase : public NodeSparkBaseNode 10 | { 11 | protected: 12 | void createBaseZoneParams(eString name, bool shared = false); 13 | void setBaseZoneParams(SPK::Ref zone); 14 | void setResult(SPK::Ref zone); 15 | 16 | SPK::Ref _zone; 17 | }; 18 | 19 | 20 | //------------------------------------------------------------------------------------------------------------------------------ 21 | // point zone node 22 | //------------------------------------------------------------------------------------------------------------------------------ 23 | class NodeSparkZonePoint : public NodeSparkZoneBase 24 | { 25 | private: 26 | const QString Name() const override { return QString("PointZone"); } 27 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_zone); } 28 | void process() override; 29 | public: 30 | NodeSparkZonePoint(); 31 | }; 32 | 33 | //------------------------------------------------------------------------------------------------------------------------------ 34 | // plane zone node 35 | //------------------------------------------------------------------------------------------------------------------------------ 36 | class NodeSparkZonePlane : public NodeSparkZoneBase 37 | { 38 | private: 39 | const QString Name() const override { return QString("PlaneZone"); } 40 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_zone); } 41 | void process() override; 42 | public: 43 | NodeSparkZonePlane(); 44 | }; 45 | 46 | 47 | //------------------------------------------------------------------------------------------------------------------------------ 48 | // sphere zone node 49 | //------------------------------------------------------------------------------------------------------------------------------ 50 | class NodeSparkZoneSphere : public NodeSparkZoneBase 51 | { 52 | private: 53 | const QString Name() const override { return QString("SphereZone"); } 54 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_zone); } 55 | void process() override; 56 | public: 57 | NodeSparkZoneSphere(); 58 | }; 59 | 60 | 61 | //------------------------------------------------------------------------------------------------------------------------------ 62 | // box zone node 63 | //------------------------------------------------------------------------------------------------------------------------------ 64 | class NodeSparkZoneBox : public NodeSparkZoneBase 65 | { 66 | private: 67 | const QString Name() const override { return QString("BoxZone"); } 68 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_zone); } 69 | void process() override; 70 | public: 71 | NodeSparkZoneBox(); 72 | }; 73 | 74 | //------------------------------------------------------------------------------------------------------------------------------ 75 | // cylinder zone node 76 | //------------------------------------------------------------------------------------------------------------------------------ 77 | class NodeSparkZoneCylinder : public NodeSparkZoneBase 78 | { 79 | private: 80 | const QString Name() const override { return QString("CylinderZone"); } 81 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_zone); } 82 | void process() override; 83 | public: 84 | NodeSparkZoneCylinder(); 85 | }; 86 | 87 | //------------------------------------------------------------------------------------------------------------------------------ 88 | // ring zone node 89 | //------------------------------------------------------------------------------------------------------------------------------ 90 | class NodeSparkZoneRing : public NodeSparkZoneBase 91 | { 92 | private: 93 | const QString Name() const override { return QString("RingZone"); } 94 | std::shared_ptr outData(PortIndex) override { return std::make_shared(_zone); } 95 | void process() override; 96 | public: 97 | NodeSparkZoneRing(); 98 | }; 99 | 100 | #endif // ZONENODE_H 101 | -------------------------------------------------------------------------------- /src/node-editor/spark-nodes/spark-nodes.h: -------------------------------------------------------------------------------- 1 | #ifndef SPARKNODES_H 2 | #define SPARKNODES_H 3 | 4 | #include "SpkZones.h" 5 | #include "SpkSystem.h" 6 | #include "SpkEmitters.h" 7 | #include "SpkModifiers.h" 8 | #include "SpkInterpolators.h" 9 | #include "SparkNodesRegistry.h" 10 | 11 | 12 | #endif // SPARKNODES_H 13 | --------------------------------------------------------------------------------