├── .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