1 // This file belongs to the "MiniCore" game engine.
2 // Copyright (C) 2010 Jussi Lind <jussi.lind@iki.fi>
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 // MA  02110-1301, USA.
18 //
19 
20 #ifndef MCWORLD_HH
21 #define MCWORLD_HH
22 
23 #include "mcmacros.hh"
24 #include "mcrendergroup.hh"
25 #include "mcvector2d.hh"
26 #include "mcvector3d.hh"
27 
28 #include <memory>
29 #include <vector>
30 
31 class MCCamera;
32 class MCCollisionDetector;
33 class MCContact;
34 class MCForceRegistry;
35 class MCImpulseGenerator;
36 class MCObject;
37 class MCObjectGrid;
38 class MCWorldRenderer;
39 
40 /*! \class World base class.
41  *  \brief World class holds every MCObject in the scene.
42  *
43  * MCWorld class holds every MCObject-derived object in the scene.
44  * It applies the physics integration and collision detections for
45  * the objects.
46  *
47  * MCWorld has always positive Z-axis pointing "up" and objects
48  * move on the XY-plane. Direction of the gravity can be freely set.
49  *
50  * MCWorld uses MCWorldRenderer to render the scene.
51  */
52 class MCWorld
53 {
54 public:
55     typedef std::vector<MCObject *> ObjectVector;
56 
57     //! Constructor.
58     MCWorld();
59 
60     //! Destructor.
61     virtual ~MCWorld();
62 
63     //! Return the one-and-only MCWorld instance.
64     static MCWorld & instance();
65 
66     static bool hasInstance();
67 
68     //! Remove all objects.
69     void clear();
70 
71     /*! Set dimensions of the world box in units.
72      *
73      *  \param metersPerUnit You could have, for example, a game object that is a
74      *  MCSurface of 10x20 units, but want it to behave like an real-world object
75      *  of 1x2 meters, so the metersPerUnits would be 0.1 in that case.
76      *
77      *  \param gridSize ver and hor size of the object grid. This affects the collision
78      *  detection performance.
79      */
80     void setDimensions(
81       float minX,
82       float maxX,
83       float minY,
84       float maxY,
85       float minZ,
86       float maxZ,
87       float metersPerUnit = 1.0f,
88       bool addAreaWalls = true,
89       size_t gridSize = 128);
90 
91     /*! Set gravity vector used by default friction generators (on XY-plane).
92      *  The default is [0, 0, -9.81]. Set the gravity (acceleration) for objects
93      *  independently when needed. */
94     void setGravity(const MCVector3dF & gravity);
95 
96     const MCVector3dF & gravity() const;
97 
98     //! Set how many meters equal one unit in the scene.
99     static void setMetersPerUnit(float value);
100 
101     //! Get how many meters equal one unit in the scene.
102     static float metersPerUnit();
103 
104     //! Convert scene units to meters.
105     static void toMeters(float & units);
106 
107     //! Convert scene units to meters.
108     static void toMeters(MCVector2dF & units);
109 
110     //! Convert scene units to meters.
111     static void toMeters(MCVector3dF & units);
112 
113     /*! Add object to the world. Object's current location is used.
114      *  \param object Object to be added. */
115     void addObject(MCObject & object);
116 
117     /*! Schedules the object to be removed from the world. This method
118      *  should be used when removing objects in the middle of a run.
119      *  Object is not removed immediately so possibly on-going physics
120      *  and collision calculations are not messed up. Do not delete the object.
121      *  \param object Object to be removed. */
122     void removeObject(MCObject & object);
123 
124     /*! Removes object from the world immediately. This can be used if the object
125      *  gets deleted. Slow.
126      *  \param object Object to be removed. */
127     void removeObjectNow(MCObject & object);
128 
129     //! Stop integrating the given object.
130     void removeObjectFromIntegration(MCObject & object);
131 
132     //! Restart integrating the given object.
133     void restoreObjectToIntegration(MCObject & object);
134 
135     //! \return Force registry. Use this to add force generators to objects.
136     MCForceRegistry & forceRegistry() const;
137 
138     /*! \brief Step world time
139      *  This causes the integration of physics and executes collision detections.
140      *  \param step Time step to be updated in msecs. */
141     void stepTime(int step);
142 
143     /*! \brief Call this (once) before calling render() or renderShadows().
144      *  \param camera The camera window to be used. If nullptr, then
145      *         no any translations or clipping done. */
146     virtual void prepareRendering(MCCamera * camera);
147 
148     /*! \brief Render given component.
149      *  \param camera Camera box, can be nullptr. */
150     virtual void render(MCCamera * camera, MCRenderGroup renderGroup);
151 
152     //! \return Reference to the objectGrid.
153     MCObjectGrid & objectGrid() const;
154 
155     //! \return The world renderer.
156     MCWorldRenderer & renderer() const;
157 
158     //! Get minimum X
159     float minX() const;
160 
161     //! Get maximum X
162     float maxX() const;
163 
164     //! Get minimum Y
165     float minY() const;
166 
167     //! Get maximum Y
168     float maxY() const;
169 
170     //! Get minimum Z
171     float minZ() const;
172 
173     //! Get maximum Z
174     float maxZ() const;
175 
176     /*! \brief Set collision resolver loop count.
177      *  Lower loop count results in faster collision calculations, but lower accuracy. */
178     void setResolverLoopCount(size_t resolverLoopCount = 5);
179 
180     //! \return size of the current integration vector
181     size_t objectCount() const;
182 
183     //! Get registered objects
184     const ObjectVector & objects() const;
185 
186 private:
187     DISABLE_COPY(MCWorld);
188     DISABLE_ASSI(MCWorld);
189     DISABLE_MOVE(MCWorld);
190 
191     void integrate(int step);
192 
193     void processRemovedObjects();
194 
195     void processCollisions();
196 
197     void doRemoveObject(MCObject & object);
198 
199     void generateImpulses();
200 
201     void resolvePositions(float accuracy);
202 
203     MCContact * getDeepestInterpenetration(const std::vector<MCContact *> & contacts);
204 
205     static MCWorld * m_instance;
206 
207     MCWorldRenderer * m_renderer;
208 
209     MCForceRegistry * m_forceRegistry;
210 
211     MCCollisionDetector * m_collisionDetector;
212 
213     MCImpulseGenerator * m_impulseGenerator;
214 
215     std::unique_ptr<MCObjectGrid> m_objectGrid;
216 
217     static float m_metersPerUnit;
218 
219     static float m_metersPerUnitSquared;
220 
221     float m_minX, m_maxX, m_minY, m_maxY, m_minZ, m_maxZ;
222 
223     MCWorld::ObjectVector m_objects;
224 
225     MCWorld::ObjectVector m_removeObjs;
226 
227     std::unique_ptr<MCObject> m_leftWallObject;
228 
229     std::unique_ptr<MCObject> m_rightWallObject;
230 
231     std::unique_ptr<MCObject> m_topWallObject;
232 
233     std::unique_ptr<MCObject> m_bottomWallObject;
234 
235     size_t m_numCollisions;
236 
237     size_t m_resolverLoopCount;
238 
239     float m_resolverStep;
240 
241     MCVector3dF m_gravity;
242 };
243 
244 #endif // MCWORLD_HH
245