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