1 /* bzflag
2  * Copyright (c) 1993-2021 Tim Riker
3  *
4  * This package is free software;  you can redistribute it and/or
5  * modify it under the terms of the license found in the file
6  * named COPYING that should have accompanied this file.
7  *
8  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11  */
12 
13 /* Obstacle:
14  *  Interface for all obstacles in the game environment,
15  *  including boxes, pyramids, and teleporters.
16  *
17  * isInside(const float*, float) is a rough test that considers
18  *  the tank as a circle
19  * isInside(const float*, float, float, float) is a careful test
20  *  that considers the tank as a rectangle
21  */
22 
23 #ifndef BZF_OBSTACLE_H
24 #define BZF_OBSTACLE_H
25 
26 #include "common.h"
27 
28 // system headers
29 #include <string>
30 #include <iostream>
31 
32 // common headers
33 #include "Extents.h"
34 
35 class Ray;
36 class SceneNode;
37 class MeshTransform;
38 
39 /** This ABC represents a (normally) solid object in a world. It has pure
40     virtual functions for getting information about it's size, checking ray
41     intersections, checking point intersections, computing normals etc.
42     All these functions have to be implemented in concrete subclasses.
43 */
44 
45 class Obstacle
46 {
47 
48     friend class ObstacleModifier;
49 
50 public:
51 
52     /** The default constructor. It sets all values to 0
53         and is not very useful. */
54     Obstacle();
55 
56     /** This function initializes the Obstacle with the given parameters.
57         @param pos    The position of the obstacle in world coordinates
58         @param rotation   The rotation around the obstacle's Z axis
59         @param hwidth     Half the X size of the obstacle
60         @param hbreadth   Half the Y size of the obstacle
61         @param height     The Z size of the obstacle
62         @param drive      @c true if the obstacle is drivethtrough, i.e. tanks
63           can pass through it
64         @param shoot      @c true if the obstacle is shootthrough, i.e. bullets
65           can pass through it
66     */
67     Obstacle(const float* pos, float rotation, float hwidth, float hbreadth,
68              float height, bool drive = false, bool shoot = false, bool rico = false);
69 
70     /** This function makes a copy using the given transform */
71     virtual Obstacle* copyWithTransform(const MeshTransform&) const;
72 
73     /** A virtual destructor is needed to let subclasses do their cleanup. */
74     virtual ~Obstacle();
75 
76     /** This function returns a string describing what kind of obstacle this is.
77      */
78     virtual const char* getType() const = 0;
79 
80     /** This function calculates extents from pos, size, and rotation */
81     void setExtents();
82 
83     /** This function returns true if the obstacle is valid */
84     virtual bool isValid() const;
85 
86     /** This function returns true if the obstacle has a flat top */
87     virtual bool isFlatTop() const;
88 
89     /** TThis function returns the network packed size in bytes */
90     virtual int packSize() const = 0;
91 
92     /** This function packs the obstacle into buf */
93     virtual void *pack(void* buf) const = 0;
94 
95     /** This function unpacks the obstacle from buf */
96     virtual const void *unpack(const void* buf) = 0;
97 
98     /** This function prints the obstacle to the stream */
99     virtual void print(std::ostream& out, const std::string& indent) const = 0;
100 
101     /** This function prints the obstacle in Alias Wavefront format to the stream */
printOBJ(std::ostream &,const std::string &)102     virtual void printOBJ(std::ostream&, const std::string&) const
103     {
104         return;
105     }
106 
107     /** This function returns the position of this obstacle. */
108     const Extents& getExtents() const;
109 
110     /** This function returns the position of this obstacle. */
111     const float* getPosition() const;
112 
113     /** This function returns the sizes of this obstacle. */
114     const float* getSize() const;
115 
116     /** This function returns the obstacle's rotation around its own Y axis. */
117     float getRotation() const;
118 
119     /** This function returns half the obstacle's X size. */
120     float getWidth() const;
121 
122     /** This function returns half the obstacle's Y size. */
123     float getBreadth() const;
124 
125     /** This function returns the obstacle's full height. */
126     float getHeight() const;
127 
128     /** This function returns the time of intersection between the obstacle
129         and a Ray object. If the ray does not intersect this obstacle -1 is
130         returned. */
131     virtual float intersect(const Ray&) const = 0;
132 
133     /** This function computes the two-dimensional surface normal of this
134         obstacle at the point @c p. The normal is stored in @c n. */
135     virtual void getNormal(const float* p, float* n) const = 0;
136 
137     /** This function computes the three-dimensional surface normal of this
138         obstacle at the point @c p. The normal is stored in @c n. */
139     virtual void get3DNormal(const float* p, float* n) const;
140 
141     /** This function checks if a tank, approximated as a cylinder with base
142         centre in point @c p and radius @c radius, intersects this obstacle. */
143     virtual bool inCylinder(const float* p, float radius, float height) const = 0;
144 
145     /** This function checks if a tank, approximated as a box rotated around its
146         Z axis, intersects this obstacle. */
147     virtual bool inBox(const float* p, float angle,
148                        float halfWidth, float halfBreadth, float height) const = 0;
149 
150     /** This function checks if a tank, approximated as a box rotated around its
151         Z axis, intersects this obstacle. It also factors in the difference
152         between the old Z location and the new Z location */
153     virtual bool inMovingBox(const float* oldP, float oldAngle,
154                              const float* newP, float newAngle,
155                              float halfWidth, float halfBreadth, float height) const = 0;
156 
157     /** This function checks if a horizontal rectangle crosses the surface of
158         this obstacle.
159         @param p       The position of the centre of the rectangle
160         @param angle   The rotation of the rectangle
161         @param halfWidth   Half the width of the rectangle
162         @param halfBreadth Half the breadth of the rectangle
163         @param plane   The tangent plane of the obstacle where it's
164            intersected by the rectangle will be stored here
165     */
166     virtual bool isCrossing(const float* p, float angle,
167                             float halfWidth, float halfBreadth, float height,
168                             float* plane) const;
169 
170     /** This function checks if a box moving from @c pos1 to @c pos2 will hit
171         this obstacle, and if it does what the surface normal at the hitpoint is.
172         @param pos1    The original position of the box
173         @param azimuth1    The original rotation of the box
174         @param pos2    The position of the box at the hit
175         @param azimuth2    The rotation of the box at the hit
176         @param halfWidth   Half the width of the box
177         @param halfBreadth Half the breadth of the box
178         @param height  The height of the box
179         @param normal  The surface normal of this obstacle at the hit point
180            will be stored here
181         @returns      @c true if the box hits this obstacle, @c false
182            otherwise
183     */
184     virtual bool getHitNormal(const float* pos1, float azimuth1,
185                               const float* pos2, float azimuth2,
186                               float halfWidth, float halfBreadth,
187                               float height, float* normal) const = 0;
188 
189     /** This function returns @c true if tanks can pass through this object,
190         @c false if they can't. */
191     bool isDriveThrough() const;
192 
193     /** This function returns @c true if bullets can pass through this object,
194         @c false if they can't. */
195     bool isShootThrough() const;
196 
197     /** This function returns @c true if tanks and bullets can pass through
198         this object, @c false if either can not */
199     bool isPassable() const;
200 
201     /** This function returns @c true if bullets will bounce off of this
202      * object, @c false if they simply die of contact */
203     bool canRicochet() const;
204 
205     /** This function sets the "zFlip" flag of this obstacle, i.e. if it's
206         upside down. */
207     void setZFlip(void);
208 
209 
210     /** This function returns the "zFlip" flag of this obstacle.
211         @see setZFlip()
212     */
213     bool getZFlip(void) const;
214 
215     // where did the object come from?
216     enum SourceBits
217     {
218         WorldSource     = 0,
219         GroupDefSource  = (1 << 0),
220         ContainerSource = (1 << 1)
221     };
222     void setSource(char);
223     char getSource() const;
224     bool isFromWorldFile() const;
225     bool isFromGroupDef() const;
226     bool isFromContainer() const;
227 
228     /** This function resets the object ID counter for printing OBJ files */
229     static void resetObjCounter();
230 
231     // inside sceneNodes
232     void addInsideSceneNode(SceneNode* node);
233     void freeInsideSceneNodeList();
234     int getInsideSceneNodeCount() const;
235     SceneNode** getInsideSceneNodeList() const;
236 
237     /** This boolean is used by CollisionManager.
238         Someone else can 'friend'ify it later.
239     */
240     bool collisionState;
241 
242     /** The maximum extent of any object parameter
243      */
244     static const float maxExtent;
245 
246 
247 
248 protected:
249     /** This function checks if a moving horizontal rectangle will hit a
250         box-shaped obstacle, and if it does, computes the obstacle's normal
251         at the hitpoint.
252         @param pos1    The original position of the rectangle
253         @param azimuth1    The original rotation of the rectangle
254         @param pos2    The final position of the rectangle
255         @param azimuth2    The final rotation of the rectangle
256         @param halfWidth   Half the width of the rectangle
257         @param halfBreadth Half the breadth of the rectangle
258         @param oPos    The position of the obstacle
259         @param oAzimuth    The rotation of the obstacle
260         @param oWidth  Half the width of the obstacle
261         @param oBreadth    Half the breadth of the obstacle
262         @param oHeight     The height of the obstacle
263         @param normal  The surface normal of the obstacle at the hitpoint
264            will be stored here
265         @returns       The time of the hit, where 0 is the time when the
266            rectangle is at @c pos1 and 1 is the time when it's
267            at @c pos2, and -1 means "no hit"
268     */
269     float getHitNormal(const float* pos1, float azimuth1,
270                        const float* pos2, float azimuth2,
271                        float halfWidth, float halfBreadth,
272                        const float* oPos, float oAzimuth,
273                        float oWidth, float oBreadth, float oHeight,
274                        float* normal) const;
275 
276 protected:
277     static int getObjCounter();
278     static void incObjCounter();
279 
280 protected:
281     Extents extents;
282     float pos[3];
283     float size[3]; // width, breadth, height
284     float angle;
285     bool driveThrough;
286     bool shootThrough;
287     bool ricochet;
288     bool ZFlip;
289     char source;
290 
291 private:
292     int insideNodeCount;
293     SceneNode** insideNodes;
294 
295 private:
296     static int objCounter;
297 };
298 
299 //
300 // Obstacle
301 //
302 
getExtents()303 inline const Extents& Obstacle::getExtents() const
304 {
305     return extents;
306 }
307 
getPosition()308 inline const float* Obstacle::getPosition() const
309 {
310     return pos;
311 }
312 
getSize()313 inline const float* Obstacle::getSize() const
314 {
315     return size;
316 }
317 
getRotation()318 inline float Obstacle::getRotation() const
319 {
320     return angle;
321 }
322 
getWidth()323 inline float Obstacle::getWidth() const
324 {
325     return size[0];
326 }
327 
getBreadth()328 inline float Obstacle::getBreadth() const
329 {
330     return size[1];
331 }
332 
getHeight()333 inline float Obstacle::getHeight() const
334 {
335     return size[2];
336 }
337 
get3DNormal(const float * p,float * n)338 inline void Obstacle::get3DNormal(const float *p, float *n) const
339 {
340     getNormal(p, n);
341 }
342 
isDriveThrough()343 inline bool Obstacle::isDriveThrough() const
344 {
345     return driveThrough;
346 }
347 
isShootThrough()348 inline bool Obstacle::isShootThrough() const
349 {
350     return shootThrough;
351 }
352 
isPassable()353 inline bool Obstacle::isPassable() const
354 {
355     return (driveThrough && shootThrough);
356 }
357 
canRicochet()358 inline bool Obstacle::canRicochet() const
359 {
360     return ricochet;
361 }
362 
setSource(char _source)363 inline void Obstacle::setSource(char _source)
364 {
365     source = _source;
366     return;
367 }
368 
getSource()369 inline char Obstacle::getSource() const
370 {
371     return source;
372 }
373 
isFromWorldFile()374 inline bool Obstacle::isFromWorldFile() const
375 {
376     return (source == WorldSource);
377 }
378 
isFromGroupDef()379 inline bool Obstacle::isFromGroupDef() const
380 {
381     return ((source & GroupDefSource) != 0);
382 }
383 
isFromContainer()384 inline bool Obstacle::isFromContainer() const
385 {
386     return ((source & ContainerSource) != 0);
387 }
388 
getObjCounter()389 inline int Obstacle::getObjCounter()
390 {
391     return objCounter;
392 }
incObjCounter()393 inline void Obstacle::incObjCounter()
394 {
395     objCounter++;
396 }
resetObjCounter()397 inline void Obstacle::resetObjCounter()
398 {
399     objCounter = 0;
400 }
401 
402 #endif // BZF_OBSTACLE_H
403 
404 // Local Variables: ***
405 // mode: C++ ***
406 // tab-width: 4 ***
407 // c-basic-offset: 4 ***
408 // indent-tabs-mode: nil ***
409 // End: ***
410 // ex: shiftwidth=4 tabstop=4
411