Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/orxonox/worldentities/WorldEntity.h @ 11071

Last change on this file since 11071 was 11071, checked in by landauf, 8 years ago

merged branch cpp11_v3 back to trunk

  • Property svn:eol-style set to native
File size: 26.0 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *      Reto Grieder (physics)
25 *   Co-authors:
26 *      ...
27 *
28 */
29
30#ifndef _WorldEntity_H__
31#define _WorldEntity_H__
32
33#include "OrxonoxPrereqs.h"
34
35#ifdef ORXONOX_RELEASE
36#  include <OgreSceneNode.h>
37#endif
38#include <LinearMath/btMotionState.h>
39#include <LinearMath/btAlignedAllocator.h>
40
41#include "util/Math.h"
42#include "util/OgreForwardRefs.h"
43#include "core/BaseObject.h"
44#include "network/synchronisable/Synchronisable.h"
45
46namespace orxonox
47{
48    /**
49    @brief
50        The WorldEntity represents everything that can be put in a Scene at a certain location.
51
52        It is supposed to be the base class of everything you would call an 'object' in a Scene.
53        The class itself is abstract which means you cannot use it directly. You may use StaticEntity
54        as the simplest derivative or (derived from MobileEntity) MovableEntity and ControllableEntity
55        as more advanced ones.
56
57        The basic task of the WorldEntity is provide a location, a direction and a scaling and the possibility
58        to create an entire hierarchy of derived objects.
59        It is also the basis for the physics interface to the Bullet physics engine.
60        Every WorldEntity can have a specific collision type: @see CollisionType
61        This would then imply that every scene object could have any collision type. To limit this, you can always
62        override this->isCollisionTypeLegal(CollisionType). Return false if the collision type is not supported
63        for a specific object.
64        There is also support for attaching WorldEntities with physics to each other. Currently, the collision shape
65        of both objects simply get merged into one larger shape (for static collision type).
66        The physical body that is internally stored and administrated has the following supported properties:
67        - Restitution, angular factor, linear damping, angular damping, friction, mass and collision shape.
68        You can get more information at the corresponding set function.
69
70        Collision shapes: These are controlled by the internal WorldEntityCollisionShape. @see WorldEntityCollisionShape.
71    */
72    class _OrxonoxExport WorldEntity : public BaseObject, public Synchronisable, public btMotionState
73    {
74        friend class Scene;
75
76        public:
77            BT_DECLARE_ALIGNED_ALLOCATOR();
78
79            // Define our own transform space enum to avoid Ogre includes here
80            /**
81            @brief
82                Enumeration denoting the spaces which a transform can be relative to.
83            */
84            enum class TransformSpace
85            {
86                //! Transform is relative to the local space
87                Local,
88                //! Transform is relative to the space of the parent node
89                Parent,
90                //! Transform is relative to world space
91                World
92            };
93
94        public:
95            WorldEntity(Context* context);
96            virtual ~WorldEntity();
97
98            virtual void XMLPort(Element& xmlelement, XMLPort::Mode mode) override;
99
100            inline const Ogre::SceneNode* getNode() const
101                { return this->node_; }
102
103            static const Vector3 FRONT;
104            static const Vector3 BACK;
105            static const Vector3 LEFT;
106            static const Vector3 RIGHT;
107            static const Vector3 DOWN;
108            static const Vector3 UP;
109
110            virtual void changedActivity(void) override;
111            virtual void changedVisibility(void) override;
112
113            virtual void setPosition(const Vector3& position) = 0;
114            inline void setPosition(float x, float y, float z)
115                { this->setPosition(Vector3(x, y, z)); }
116            const Vector3& getPosition() const;
117            const Vector3& getWorldPosition() const;
118
119            void translate(const Vector3& distance, TransformSpace relativeTo = TransformSpace::Parent);
120            inline void translate(float x, float y, float z, TransformSpace relativeTo = TransformSpace::Parent)
121                { this->translate(Vector3(x, y, z), relativeTo); }
122
123            virtual inline const Vector3& getVelocity() const
124                { return Vector3::ZERO; }
125
126            virtual void setOrientation(const Quaternion& orientation) = 0;
127            inline void setOrientation(float w, float x, float y, float z)
128                { this->setOrientation(Quaternion(w, x, y, z)); }
129            inline void setOrientation(const Vector3& axis, const Radian& angle)
130                { this->setOrientation(Quaternion(angle, axis)); }
131            inline void setOrientation(const Vector3& axis, const Degree& angle)
132                { this->setOrientation(Quaternion(angle, axis)); }
133            const Quaternion& getOrientation() const;
134            const Quaternion& getWorldOrientation() const;
135
136            void rotate(const Quaternion& rotation, TransformSpace relativeTo = TransformSpace::Local);
137            inline void rotate(const Vector3& axis, const Degree& angle, TransformSpace relativeTo = TransformSpace::Local)
138                { this->rotate(Quaternion(angle, axis), relativeTo); }
139
140            inline void yaw(const Degree& angle, TransformSpace relativeTo = TransformSpace::Local)
141                { this->rotate(Quaternion(angle, Vector3::UNIT_Y), relativeTo); }
142            inline void pitch(const Degree& angle, TransformSpace relativeTo = TransformSpace::Local)
143                { this->rotate(Quaternion(angle, Vector3::UNIT_X), relativeTo); }
144            inline void roll(const Degree& angle, TransformSpace relativeTo = TransformSpace::Local)
145                { this->rotate(Quaternion(angle, Vector3::UNIT_Z), relativeTo); }
146
147            void lookAt(const Vector3& target, TransformSpace relativeTo = TransformSpace::Parent, const Vector3& localDirectionVector = Vector3::NEGATIVE_UNIT_Z);
148            void setDirection(const Vector3& direction, TransformSpace relativeTo = TransformSpace::Local, const Vector3& localDirectionVector = Vector3::NEGATIVE_UNIT_Z);
149            inline void setDirection(float x, float y, float z, TransformSpace relativeTo = TransformSpace::Local, const Vector3& localDirectionVector = Vector3::NEGATIVE_UNIT_Z)
150                { this->setDirection(Vector3(x, y, z), relativeTo, localDirectionVector); }
151
152            virtual void setScale3D(const Vector3& scale);
153            inline void setScale3D(float x, float y, float z)
154                { this->setScale3D(Vector3(x, y, z)); }
155            const Vector3& getScale3D() const;
156            const Vector3& getWorldScale3D() const;
157
158            inline void setScale(float scale)
159                { this->setScale3D(scale, scale, scale); }
160            inline float getScale() const
161                { Vector3 scale = this->getScale3D(); return (scale.x == scale.y && scale.x == scale.z) ? scale.x : 1; }
162            float getWorldScale() const;
163
164            inline void scale3D(const Vector3& scale)
165                { this->setScale3D(this->getScale3D() * scale); }
166            inline void scale3D(float x, float y, float z)
167                { this->scale3D(Vector3(x, y, z)); }
168            inline void scale(float scale)
169                { this->scale3D(scale, scale, scale); }
170
171            virtual void changedScale() {}
172
173            void attach(WorldEntity* object);
174            void detach(WorldEntity* object);
175            WorldEntity* getAttachedObject(unsigned int index);
176            inline const std::set<WorldEntity*>& getAttachedObjects() const
177                { return this->children_; }
178
179            void attachOgreObject(Ogre::MovableObject*  object);
180            void attachOgreObject(Ogre::BillboardSet*   object);
181            void attachOgreObject(Ogre::Camera*         object);
182            void attachOgreObject(Ogre::Entity*         object);
183            void attachOgreObject(Ogre::ParticleSystem* object);
184
185            void detachOgreObject(Ogre::MovableObject*  object);
186            void detachOgreObject(Ogre::BillboardSet*   object);
187            void detachOgreObject(Ogre::Camera*         object);
188            void detachOgreObject(Ogre::Entity*         object);
189            void detachOgreObject(Ogre::ParticleSystem* object);
190
191            Ogre::MovableObject* detachOgreObject(const Ogre::String& name);
192
193            inline void attachToParent(WorldEntity* parent)
194                { parent->attach(this); }
195            inline void detachFromParent()
196                { if (this->parent_) { this->parent_->detach(this); } }
197            inline WorldEntity* getParent() const
198                { return this->parent_; }
199
200            void attachNode(Ogre::SceneNode* node);
201            void detachNode(Ogre::SceneNode* node);
202            void attachToNode(Ogre::SceneNode* node);
203            void detachFromNode(Ogre::SceneNode* node);
204
205            inline void setDeleteWithParent(bool value)
206                { this->bDeleteWithParent_ = value; }
207            inline bool getDeleteWithParent() const
208                { return this->bDeleteWithParent_; }
209
210            void notifyChildPropsChanged();
211
212        protected:
213            virtual void parentChanged() {}
214
215            Ogre::SceneNode* node_;
216
217        private:
218            void registerVariables();
219
220            inline void lookAt_xmlport(const Vector3& target)
221                { this->lookAt(target); }
222            inline void setDirection_xmlport(const Vector3& direction)
223                { this->setDirection(direction); }
224            inline void yaw_xmlport(const Degree& angle)
225                { this->yaw(angle); }
226            inline void pitch_xmlport(const Degree& angle)
227                { this->pitch(angle); }
228            inline void roll_xmlport(const Degree& angle)
229                { this->roll(angle); }
230
231            // network callbacks
232            void networkcallback_parentChanged();
233            inline void scaleChanged()
234                { this->setScale3D(this->getScale3D()); }
235
236            WorldEntity* parent_;
237            unsigned int parentID_;
238            std::set<WorldEntity*> children_;
239            bool bDeleteWithParent_;
240
241            bool bActiveMem_;
242            bool bVisibleMem_;
243
244
245        /////////////
246        // Physics //
247        /////////////
248
249        public:
250            /**
251            @brief
252                Denotes the possible types of physical objects in a Scene.
253
254                Dynamic:   The object is influenced by its physical environment, like for instance little ball.
255                Kinematic: The object can only influence other dynamic objects. It's movement is coordinated by your own saying.
256                Static:    Like kinematic but the object is not allowed to move during the simulation.
257                None:      The object has no physics at all.
258            */
259            enum class CollisionType
260            {
261                Dynamic,
262                Kinematic,
263                Static,
264                None
265            };
266
267            //! Tells whether the object has any connection to the Bullet physics engine. If hasPhysics() is false, the object may still have a velocity.
268            bool hasPhysics()       const { return getCollisionType() != CollisionType::None     ; }
269            //! @see CollisionType
270            bool isStatic()         const { return getCollisionType() == CollisionType::Static   ; }
271            //! @see CollisionType
272            bool isKinematic()      const { return getCollisionType() == CollisionType::Kinematic; }
273            //! @see CollisionType
274            bool isDynamic()        const { return getCollisionType() == CollisionType::Dynamic  ; }
275            //! Tells whether physics has been activated (you can temporarily deactivate it)
276            bool isPhysicsActive()  const { return this->bPhysicsActive_; }
277            bool addedToPhysicalWorld() const;
278
279            void activatePhysics();
280            void deactivatePhysics();
281
282            //! Returns the CollisionType. @see CollisionType.
283            inline CollisionType getCollisionType() const
284                { return this->collisionType_; }
285            void setCollisionType(CollisionType type);
286
287            void setCollisionTypeStr(const std::string& type);
288            std::string getCollisionTypeStr() const;
289
290            //! Sets the mass of this object. Note that the total mass may be influenced by attached objects!
291            inline void setMass(float mass)
292                { this->mass_ = mass; recalculateMassProps(); }
293            //! Returns the mass of this object without its children.
294            inline float getMass() const
295                { return this->mass_; }
296
297            //! Returns the total mass of this object with all its attached children.
298            inline float getTotalMass() const
299                { return this->mass_ + this->childrenMass_; }
300
301            /**
302            @brief
303                Returns the diagonal elements of the inertia tensor when calculated in local coordinates.
304            @note
305                The local inertia tensor cannot be set, but is calculated by Bullet according to the collisionShape.
306                With compound collision shapes, an approximation is used.
307            */
308            inline const btVector3& getLocalInertia() const
309                { return this->localInertia_; }
310
311            /**
312            @brief
313                Sets how much reaction is applied in a collision.
314
315                Consider two equal spheres colliding with equal velocities:
316                Restitution 1 means that both spheres simply reverse their velocity (no loss of energy)
317                Restitution 0 means that both spheres will immediately stop moving
318                (maximum loss of energy without violating of the preservation of momentum)
319            */
320            inline void setRestitution(float restitution)
321                { this->restitution_ = restitution; internalSetPhysicsProps(); }
322            //! Returns the restitution parameter. @see setRestitution.
323            inline float getRestitution() const
324                { return this->restitution_; }
325
326            /**
327            @brief
328                Sets an artificial parameter that tells how much torque is applied when you apply a non-central force.
329
330                Normally the angular factor is 1, which means it's physically 'correct'. However if you have a player
331                character that should not rotate when hit sideways, you can set the angular factor to 0.
332            */
333            inline void setAngularFactor(float angularFactor)
334                { this->angularFactor_ = angularFactor; internalSetPhysicsProps(); }
335            //! Returns the angular factor. @see setAngularFactor.
336            inline float getAngularFactor() const
337                { return this->angularFactor_; }
338
339            //! Applies a mass independent damping. Velocities will simply diminish exponentially.
340            inline void setLinearDamping(float linearDamping)
341                { this->linearDamping_ = linearDamping; internalSetPhysicsProps(); }
342            //! Returns the linear damping. @see setLinearDamping.
343            inline float getLinearDamping() const
344                { return this->linearDamping_; }
345
346            //! Applies a tensor independent rotation damping. Angular velocities will simply diminish exponentially.
347            inline void setAngularDamping(float angularDamping)
348                { this->angularDamping_ = angularDamping; internalSetPhysicsProps(); }
349            //! Returns the angular damping. @see setAngularDamping.
350            inline float getAngularDamping() const
351                { return this->angularDamping_; }
352
353            //! Applies friction to the object. Friction occurs when two objects collide.
354            inline void setFriction(float friction)
355                { this->friction_ = friction; internalSetPhysicsProps(); }
356            //! Returns the amount of friction applied to the object.
357            inline float getFriction() const
358                { return this->friction_; }
359
360            /**
361             * Sets the motion threshold for continuous collision detection (CCD). This should be activated if an object moves further in one tick than its own
362             * size. This means that in one tick the object may be in front of a wall and in the next tick it will be behind the wall without ever triggering a
363             * collision. CCD ensures that collisions are still detected. By default it is deactivated (threshold = 0) which is fine for slow or static
364             * objects, but it should be set to a real value for fast moving objects (e.g. projectiles).
365             *
366             * A good value for the threshold is (diameter^2).
367             *
368             * @param ccdMotionThreshold CCD is enabled if the squared velocity of the object is > ccdMotionThreshold (default 0.0). 0.0 means deactivated.
369             */
370            inline void setCcdMotionThreshold(float ccdMotionThreshold)
371                { this->ccdMotionThreshold_ = ccdMotionThreshold; internalSetPhysicsProps(); }
372            //! Returns the currently used motion threshold for CCD (0 means CCD is deactivated).
373            inline float getCcdMotionThreshold() const
374                { return this->ccdMotionThreshold_; }
375
376            /**
377             * Sets the radius of the sphere which is used for continuous collision detection (CCD). The sphere should be embedded inside the objects collision
378             * shape, preferably smaller. @see setCcdMotionThreshold for more information about CCD.
379             *
380             * A good value for the radius is (diameter/5).
381             *
382             * @param ccdSweptSphereRadius The diameter of the sphere which is used for CCD (default 0.0).
383             */
384            inline void setCcdSweptSphereRadius(float ccdSweptSphereRadius)
385                { this->ccdSweptSphereRadius_ = ccdSweptSphereRadius; internalSetPhysicsProps(); }
386            //! Returns the currently used radius of the sphere for CCD.
387            inline float getCcdSweptSphereRadius() const
388                { return this->ccdSweptSphereRadius_; }
389
390            void attachCollisionShape(CollisionShape* shape);
391            void detachCollisionShape(CollisionShape* shape);
392            CollisionShape* getAttachedCollisionShape(unsigned int index);
393
394            void notifyCollisionShapeChanged();
395            void notifyChildMassChanged();
396
397            /**
398            @brief
399                Virtual function that gets called when this object collides with another.
400            @param otherObject
401                The object this one has collided into.
402            @param contactPoint
403                Contact point provided by Bullet. Holds more information and can me modified. See return value.
404            @return
405                Returning false means that no modification to the contactPoint has been made. Return true otherwise!
406            @note
407                Condition is that enableCollisionCallback() was called.
408            */
409            virtual inline bool collidesAgainst(WorldEntity* otherObject, const btCollisionShape* ownCollisionShape, btManifoldPoint& contactPoint)
410                { return false; } /* With false, Bullet assumes no modification to the collision objects. */
411
412            //! Enables the collidesAgainst(.) function. The object doesn't respond to collision otherwise!
413            inline void enableCollisionCallback()
414                { this->bCollisionCallbackActive_ = true; this->collisionCallbackActivityChanged(); }
415            //! Disables the collidesAgainst(.) function. @see enableCollisionCallback()
416            inline void disableCollisionCallback()
417                { this->bCollisionCallbackActive_ = false; this->collisionCallbackActivityChanged(); }
418            //! Tells whether there could be a collision callback via collidesAgainst(.)
419            inline bool isCollisionCallbackActive() const
420                { return this->bCollisionCallbackActive_; }
421
422            //! Enables or disables collision response (default is of course on)
423            inline void setCollisionResponse(bool value)
424                { this->bCollisionResponseActive_ = value; this->collisionResponseActivityChanged(); }
425            //! Tells whether there could be a collision response
426            inline bool hasCollisionResponse()
427                { return this->bCollisionResponseActive_; }
428
429        protected:
430            /**
431            @brief
432                Function checks whether the requested collision type is legal to this object.
433
434                You can override this function in a derived class to constrain the collision to e.g. None or Dynamic.
435                A projectile may not prove very useful if there is no physical body. Simply set the CollisionType
436                in its constructor and override this method. But be careful that a derived class's virtual functions
437                don't yet exist in the constructor if a base class.
438            */
439            virtual bool isCollisionTypeLegal(CollisionType type) const = 0;
440
441            btRigidBody*  physicalBody_; //!< Bullet rigid body. Everything physical is applied to this instance.
442
443        private:
444            void recalculateMassProps();
445            void internalSetPhysicsProps();
446
447            bool notifyBeingAttached(WorldEntity* newParent);
448            void notifyDetached();
449
450            // network callbacks
451            void collisionTypeChanged();
452            void physicsActivityChanged();
453            void collisionCallbackActivityChanged();
454            void collisionResponseActivityChanged();
455            //! Network callback workaround to call a function when the value changes.
456            inline void massChanged()
457                { this->setMass(this->mass_); }
458            //! Network callback workaround to call a function when the value changes.
459            inline void restitutionChanged()
460                { this->setRestitution(this->restitution_); }
461            //! Network callback workaround to call a function when the value changes.
462            inline void angularFactorChanged()
463                { this->setAngularFactor(this->angularFactor_); }
464            //! Network callback workaround to call a function when the value changes.
465            inline void linearDampingChanged()
466                { this->setLinearDamping(this->linearDamping_); }
467            //! Network callback workaround to call a function when the value changes.
468            inline void angularDampingChanged()
469                { this->setAngularDamping(this->angularDamping_); }
470            //! Network callback workaround to call a function when the value changes.
471            inline void frictionChanged()
472                { this->setFriction(this->friction_); }
473            //! Network callback workaround to call a function when the value changes.
474            inline void ccdMotionThresholdChanged()
475                { this->setCcdMotionThreshold(this->ccdMotionThreshold_); }
476            //! Network callback workaround to call a function when the value changes.
477            inline void ccdSweptSphereRadiusChanged()
478                { this->setCcdSweptSphereRadius(this->ccdSweptSphereRadius_); }
479
480            CollisionType                collisionType_;                 //!< @see setCollisionType
481            CollisionType                collisionTypeSynchronised_;     //!< Network synchronised variable for collisionType_
482            bool                         bPhysicsActive_;                //!< @see isPhysicsActive
483            bool                         bPhysicsActiveSynchronised_;    //!< Network synchronised variable for bPhysicsActive_
484            //! When attaching objects hierarchically this variable tells this object (as child) whether physics was activated before attaching (because the deactivate physics while being attached).
485            bool                         bPhysicsActiveBeforeAttaching_;
486            WorldEntityCollisionShape*   collisionShape_;                //!< Attached collision shapes go here
487            btScalar                     mass_;                          //!< @see setMass
488            btVector3                    localInertia_;                  //!< @see getLocalInertia
489            btScalar                     restitution_;                   //!< @see setRestitution
490            btScalar                     angularFactor_;                 //!< @see setAngularFactor
491            btScalar                     linearDamping_;                 //!< @see setLinearDamping
492            btScalar                     angularDamping_;                //!< @see setAngularDamping
493            btScalar                     friction_;                      //!< @see setFriction
494            btScalar                     childrenMass_;                  //!< Sum of all the children's masses
495            btScalar                     ccdMotionThreshold_;            //!< @see setCcdMotionThreshold
496            btScalar                     ccdSweptSphereRadius_;          //!< @see setCcdSweptSphereRadius
497            bool                         bCollisionCallbackActive_;      //!< @see enableCollisionCallback
498            bool                         bCollisionResponseActive_;      //!< Tells whether the object should respond to collisions
499    };
500
501    // Inline heavily used functions for release builds. In debug, we better avoid including OgreSceneNode here.
502#ifdef ORXONOX_RELEASE
503    inline const Vector3& WorldEntity::getPosition() const
504        { return this->node_->getPosition(); }
505    inline const Quaternion& WorldEntity::getOrientation() const
506        { return this->node_->getOrientation(); }
507    inline const Vector3& WorldEntity::getScale3D() const
508        { return this->node_->getScale(); }
509#endif
510
511    SUPER_FUNCTION(5, WorldEntity, changedScale, false);
512}
513
514#endif /* _WorldEntity_H__ */
Note: See TracBrowser for help on using the repository browser.