1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #ifndef PHYSICSWORLD_H |
5 | #define PHYSICSWORLD_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <QtQuick3DPhysics/qtquick3dphysicsglobal.h> |
19 | |
20 | #include <QtCore/QLoggingCategory> |
21 | #include <QtCore/QObject> |
22 | #include <QtCore/QTimerEvent> |
23 | #include <QtCore/QElapsedTimer> |
24 | #include <QtGui/QVector3D> |
25 | #include <QtQml/qqml.h> |
26 | #include <QBasicTimer> |
27 | |
28 | #include <QtQuick3D/private/qquick3dviewport_p.h> |
29 | |
30 | namespace physx { |
31 | class PxMaterial; |
32 | class PxPhysics; |
33 | class PxShape; |
34 | class PxRigidDynamic; |
35 | class PxRigidActor; |
36 | class PxRigidStatic; |
37 | class PxCooking; |
38 | class PxControllerManager; |
39 | } |
40 | |
41 | QT_BEGIN_NAMESPACE |
42 | |
43 | Q_DECLARE_LOGGING_CATEGORY(lcQuick3dPhysics); |
44 | |
45 | class QAbstractPhysicsNode; |
46 | class QAbstractCollisionShape; |
47 | class QAbstractRigidBody; |
48 | class QAbstractPhysXNode; |
49 | class QQuick3DModel; |
50 | class QQuick3DGeometry; |
51 | class QQuick3DDefaultMaterial; |
52 | class QPhysXWorld; |
53 | |
54 | class Q_QUICK3DPHYSICS_EXPORT QPhysicsWorld : public QObject, public QQmlParserStatus |
55 | { |
56 | Q_OBJECT |
57 | Q_INTERFACES(QQmlParserStatus) |
58 | Q_PROPERTY(QVector3D gravity READ gravity WRITE setGravity NOTIFY gravityChanged) |
59 | Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged) |
60 | Q_PROPERTY(bool forceDebugDraw READ forceDebugDraw WRITE setForceDebugDraw NOTIFY |
61 | forceDebugDrawChanged) |
62 | Q_PROPERTY(bool enableCCD READ enableCCD WRITE setEnableCCD NOTIFY enableCCDChanged) |
63 | Q_PROPERTY(float typicalLength READ typicalLength WRITE setTypicalLength NOTIFY |
64 | typicalLengthChanged) |
65 | Q_PROPERTY( |
66 | float typicalSpeed READ typicalSpeed WRITE setTypicalSpeed NOTIFY typicalSpeedChanged) |
67 | Q_PROPERTY(float defaultDensity READ defaultDensity WRITE setDefaultDensity NOTIFY |
68 | defaultDensityChanged) |
69 | Q_PROPERTY(QQuick3DNode *viewport READ viewport WRITE setViewport NOTIFY viewportChanged |
70 | REVISION(6, 5)) |
71 | Q_PROPERTY(float minimumTimestep READ minimumTimestep WRITE setMinimumTimestep NOTIFY |
72 | minimumTimestepChanged REVISION(6, 5)) |
73 | Q_PROPERTY(float maximumTimestep READ maximumTimestep WRITE setMaximumTimestep NOTIFY |
74 | maximumTimestepChanged REVISION(6, 5)) |
75 | Q_PROPERTY(QQuick3DNode *scene READ scene WRITE setScene NOTIFY sceneChanged REVISION(6, 5)) |
76 | |
77 | QML_NAMED_ELEMENT(PhysicsWorld) |
78 | |
79 | public: |
80 | explicit QPhysicsWorld(QObject *parent = nullptr); |
81 | ~QPhysicsWorld(); |
82 | |
83 | void classBegin() override; |
84 | void componentComplete() override; |
85 | |
86 | QVector3D gravity() const; |
87 | |
88 | bool running() const; |
89 | bool forceDebugDraw() const; |
90 | bool enableCCD() const; |
91 | float typicalLength() const; |
92 | float typicalSpeed() const; |
93 | float defaultDensity() const; |
94 | Q_REVISION(6, 5) float minimumTimestep() const; |
95 | Q_REVISION(6, 5) float maximumTimestep() const; |
96 | |
97 | bool isNodeRemoved(QAbstractPhysicsNode *object); |
98 | |
99 | static QPhysicsWorld *getWorld(QQuick3DNode *node); |
100 | |
101 | static void registerNode(QAbstractPhysicsNode *physicsNode); |
102 | static void deregisterNode(QAbstractPhysicsNode *physicsNode); |
103 | |
104 | Q_REVISION(6, 5) QQuick3DNode *viewport() const; |
105 | void setHasIndividualDebugDraw(); |
106 | physx::PxControllerManager *controllerManager(); |
107 | Q_REVISION(6, 5) QQuick3DNode *scene() const; |
108 | |
109 | public slots: |
110 | void setGravity(QVector3D gravity); |
111 | void setRunning(bool running); |
112 | void setForceDebugDraw(bool forceDebugDraw); |
113 | void setEnableCCD(bool enableCCD); |
114 | void setTypicalLength(float typicalLength); |
115 | void setTypicalSpeed(float typicalSpeed); |
116 | void setDefaultDensity(float defaultDensity); |
117 | Q_REVISION(6, 5) void setViewport(QQuick3DNode *viewport); |
118 | Q_REVISION(6, 5) void setMinimumTimestep(float minTimestep); |
119 | Q_REVISION(6, 5) void setMaximumTimestep(float maxTimestep); |
120 | Q_REVISION(6, 5) void setScene(QQuick3DNode *newScene); |
121 | |
122 | signals: |
123 | void gravityChanged(QVector3D gravity); |
124 | void runningChanged(bool running); |
125 | void enableCCDChanged(bool enableCCD); |
126 | void forceDebugDrawChanged(bool forceDebugDraw); |
127 | void typicalLengthChanged(float typicalLength); |
128 | void typicalSpeedChanged(float typicalSpeed); |
129 | void defaultDensityChanged(float defaultDensity); |
130 | Q_REVISION(6, 5) void viewportChanged(QQuick3DNode *viewport); |
131 | Q_REVISION(6, 5) void minimumTimestepChanged(float minimumTimestep); |
132 | Q_REVISION(6, 5) void maximumTimestepChanged(float maxTimestep); |
133 | void simulateFrame(float minTimestep, float maxTimestep); |
134 | Q_REVISION(6, 5) void frameDone(float timestep); |
135 | Q_REVISION(6, 5) void sceneChanged(); |
136 | |
137 | private: |
138 | void frameFinished(float deltaTime); |
139 | void frameFinishedDesignStudio(); |
140 | void initPhysics(); |
141 | void cleanupRemovedNodes(); |
142 | void updateDebugDraw(); |
143 | void updateDebugDrawDesignStudio(); |
144 | void setupDebugMaterials(QQuick3DNode *sceneNode); |
145 | void disableDebugDraw(); |
146 | void matchOrphanNodes(); |
147 | void findPhysicsNodes(); |
148 | |
149 | struct DebugModelHolder |
150 | { |
151 | QQuick3DModel *model = nullptr; |
152 | QQuick3DGeometry *geometry = nullptr; |
153 | QVector3D data; |
154 | |
155 | const QVector3D &halfExtents() const { return data; } |
156 | void setHalfExtents(const QVector3D &halfExtents) { data = halfExtents; } |
157 | |
158 | float radius() const { return data.x(); } |
159 | void setRadius(float radius) { data.setX(radius); } |
160 | |
161 | float heightScale() const { return data.x(); } |
162 | void setHeightScale(float heightScale) { data.setX(heightScale); } |
163 | |
164 | float halfHeight() const { return data.y(); } |
165 | void setHalfHeight(float halfHeight) { data.setY(halfHeight); } |
166 | |
167 | float rowScale() const { return data.y(); } |
168 | void setRowScale(float rowScale) { data.setY(rowScale); } |
169 | |
170 | float columnScale() const { return data.z(); } |
171 | void setColumnScale(float columnScale) { data.setZ(columnScale); } |
172 | }; |
173 | |
174 | QList<QAbstractPhysXNode *> m_physXBodies; |
175 | QList<QAbstractPhysicsNode *> m_newPhysicsNodes; |
176 | QHash<QPair<QAbstractCollisionShape *, QAbstractPhysicsNode *>, DebugModelHolder> |
177 | m_DesignStudioDebugModels; |
178 | QHash<QPair<QAbstractCollisionShape *, QAbstractPhysXNode *>, DebugModelHolder> |
179 | m_collisionShapeDebugModels; |
180 | QSet<QAbstractPhysicsNode *> m_removedPhysicsNodes; |
181 | QMutex m_removedPhysicsNodesMutex; |
182 | |
183 | QVector3D m_gravity = QVector3D(0.f, -981.f, 0.f); |
184 | float m_typicalLength = 100.f; // 100 cm |
185 | float m_typicalSpeed = 1000.f; // 1000 cm/s |
186 | float m_defaultDensity = 0.001f; // 1 g/cm^3 |
187 | float m_minTimestep = 16.667f; // 60 fps |
188 | float m_maxTimestep = 33.333f; // 30 fps |
189 | |
190 | bool m_running = true; |
191 | bool m_forceDebugDraw = false; |
192 | // For performance, used to keep track if we have indiviually enabled debug drawing for any |
193 | // collision shape |
194 | bool m_hasIndividualDebugDraw = false; |
195 | bool m_physicsInitialized = false; |
196 | bool m_enableCCD = false; |
197 | |
198 | QPhysXWorld *m_physx = nullptr; |
199 | QQuick3DNode *m_viewport = nullptr; |
200 | QVector<QQuick3DDefaultMaterial *> m_debugMaterials; |
201 | |
202 | friend class QQuick3DPhysicsMesh; // TODO: better internal API |
203 | friend class QTriangleMeshShape; //#### |
204 | friend class QHeightFieldShape; |
205 | friend class QQuick3DPhysicsHeightField; |
206 | friend class SimulationEventCallback; |
207 | friend class ControllerCallback; |
208 | static physx::PxPhysics *getPhysics(); |
209 | static physx::PxCooking *getCooking(); |
210 | QThread m_workerThread; |
211 | QQuick3DNode *m_scene = nullptr; |
212 | bool m_inDesignStudio = false; |
213 | }; |
214 | |
215 | QT_END_NAMESPACE |
216 | |
217 | #endif // PHYSICSWORLD_H |
218 | |