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 // Interface
14 #include "ArcObstacle.h"
15
16 // System interfaces
17 #include <math.h>
18 #include <assert.h>
19
20 //Common interfaces
21 #include "global.h"
22 #include "Pack.h"
23 #include "PhysicsDriver.h"
24 #include "MeshTransform.h"
25
26 #include "MeshUtils.h"
27
28
29 const char* ArcObstacle::typeName = "ArcObstacle";
30
31
ArcObstacle()32 ArcObstacle::ArcObstacle()
33 {
34 return;
35 }
36
37
ArcObstacle(const MeshTransform & xform,const float * _pos,const float * _size,float _rotation,float _sweepAngle,float _ratio,const float _texsize[4],bool _useNormals,int _divisions,const BzMaterial * mats[MaterialCount],int physics,bool bounce,bool drive,bool shoot,bool rico)38 ArcObstacle::ArcObstacle(const MeshTransform& xform,
39 const float* _pos, const float* _size,
40 float _rotation, float _sweepAngle, float _ratio,
41 const float _texsize[4], bool _useNormals,
42 int _divisions, const BzMaterial* mats[MaterialCount],
43 int physics, bool bounce, bool drive, bool shoot, bool rico)
44 {
45 // common obstace parameters
46 memcpy(pos, _pos, sizeof(pos));
47 memcpy(size, _size, sizeof(size));
48 angle = _rotation;
49 ZFlip = false;
50 driveThrough = drive;
51 shootThrough = shoot;
52 ricochet = rico;
53
54 // arc specific parameters
55 transform = xform;
56 divisions = _divisions;
57 sweepAngle = _sweepAngle;
58 ratio = _ratio;
59 phydrv = physics;
60 smoothBounce = bounce;
61 useNormals = _useNormals;
62 memcpy(texsize, _texsize, sizeof(texsize));
63 memcpy(materials, mats, sizeof(materials));
64
65 finalize();
66
67 return;
68 }
69
70
~ArcObstacle()71 ArcObstacle::~ArcObstacle()
72 {
73 return;
74 }
75
76
copyWithTransform(const MeshTransform & xform) const77 Obstacle* ArcObstacle::copyWithTransform(const MeshTransform& xform) const
78 {
79 MeshTransform tmpXform = transform;
80 tmpXform.append(xform);
81
82 ArcObstacle* copy =
83 new ArcObstacle(tmpXform, pos, size, angle, sweepAngle, ratio,
84 texsize, useNormals, divisions,
85 const_cast<const BzMaterial**>(materials), phydrv,
86 smoothBounce, driveThrough, shootThrough, ricochet);
87 return copy;
88 }
89
90
getType() const91 const char* ArcObstacle::getType() const
92 {
93 return typeName;
94 }
95
96
getClassName()97 const char* ArcObstacle::getClassName() // const
98 {
99 return typeName;
100 }
101
102
isValid() const103 bool ArcObstacle::isValid() const
104 {
105 return true;
106 }
107
108
isFlatTop() const109 bool ArcObstacle::isFlatTop() const
110 {
111 return true;
112 }
113
114
finalize()115 void ArcObstacle::finalize()
116 {
117 return;
118 }
119
120
makeMesh()121 MeshObstacle* ArcObstacle::makeMesh()
122 {
123 MeshObstacle* mesh;
124
125 bool isPie = false; // has no inside edge
126 bool isCircle = false; // angle of 360 degrees
127 const float minSize = 1.0e-6f; // cheezy / lazy
128
129 // absolute the sizes
130 float sz[3];
131 sz[0] = fabsf(size[0]);
132 sz[1] = fabsf(size[1]);
133 sz[2] = fabsf(size[2]);
134
135 // validity checking
136 if ((sz[0] < minSize) || (sz[1] < minSize) || (sz[2] < minSize) ||
137 (fabsf(texsize[0]) < minSize) || (fabsf(texsize[1]) < minSize) ||
138 (fabsf(texsize[2]) < minSize) || (fabsf(texsize[3]) < minSize) ||
139 (ratio < 0.0f) || (ratio > 1.0f))
140 return NULL;
141
142 // adjust the texture sizes FIXME: finish texsz[2] & texsz[3]
143 float texsz[4];
144 memcpy (texsz, texsize, sizeof(float[4]));
145 if (texsz[0] < 0.0f)
146 {
147 // unless you want to do elliptic integrals, here's
148 // the Ramanujan approximation for the circumference
149 // of an ellipse (it will be rounded anyways)
150 const float circ =
151 (float)M_PI * ((3.0f * (sz[0] + sz[1])) -
152 sqrtf ((sz[0] + (3.0f * sz[1])) * (sz[1] + (3.0f * sz[0]))));
153 // make sure it's an integral number so that the edges line up
154 texsz[0] = -floorf(circ / texsz[0]);
155 }
156 if (texsz[1] < 0.0f)
157 texsz[1] = -(sz[2] / texsz[1]);
158
159 // setup the angles
160 float r = getRotation();
161 float a = sweepAngle;
162 if (a > +360.0f)
163 a = +360.0f;
164 if (a < -360.0f)
165 a = -360.0f;
166 a = a * (float)(M_PI / 180.0); // convert to radians
167 if (a < 0.0f)
168 {
169 r = r + a;
170 a = -a;
171 }
172
173 // more validity checking
174 if (divisions <= (int) ((a + minSize) / M_PI))
175 return NULL;
176
177 if (fabsf ((float)M_PI - fmodf (a + (float)M_PI, (float)M_PI * 2.0f)) < minSize)
178 isCircle = true;
179
180 // setup the radii
181 float inrad = sz[0] * (1.0f - ratio);
182 float outrad = sz[0];
183 if (inrad > outrad)
184 {
185 const float tmp = inrad;
186 inrad = outrad;
187 outrad = tmp;
188 }
189 if ((outrad < minSize) || ((outrad - inrad) < minSize))
190 return NULL;
191 if (inrad < minSize)
192 isPie = true;
193 const float squish = sz[1] / sz[0];
194
195 if (isPie)
196 mesh = makePie(isCircle, a, r, sz[2], outrad, squish, texsz);
197 else
198 mesh = makeRing(isCircle, a, r, sz[2], inrad, outrad, squish, texsz);
199
200 // wrap it up
201 mesh->finalize();
202
203 if (mesh->isValid())
204 return mesh;
205 else
206 {
207 delete mesh;
208 return NULL;
209 }
210 }
211
212
makePie(bool isCircle,float a,float r,float h,float radius,float squish,float texsz[4])213 MeshObstacle* ArcObstacle::makePie(bool isCircle, float a, float r,
214 float h, float radius, float squish,
215 float texsz[4])
216 {
217 MeshObstacle* mesh;
218 int i;
219
220 // setup the coordinates
221 std::vector<char> checkTypes;
222 std::vector<cfvec3> checkPoints;
223 std::vector<cfvec3> vertices;
224 std::vector<cfvec3> normals;
225 std::vector<cfvec2> texcoords;
226 cfvec3 v, n;
227 cfvec2 t;
228
229 // add the checkpoint (one is sufficient)
230 if (isCircle)
231 {
232 v[0] = pos[0];
233 v[1] = pos[1];
234 }
235 else
236 {
237 const float dir = r + (0.5f * a);
238 v[0] = pos[0] + (cosf(dir) * radius * 0.5f);
239 v[1] = pos[1] + (sinf(dir) * radius * 0.5f * squish);
240 }
241 v[2] = pos[2] + (0.5f * fabsf(size[2]));
242 checkPoints.push_back(v);
243 checkTypes.push_back(MeshObstacle::CheckInside);
244
245 // setup the texsize across the disc
246 if (texsz[2] < 0.0f)
247 texsz[2] = -((2.0f * radius) / texsz[2]);
248 if (texsz[3] < 0.0f)
249 texsz[3] = -((2.0f * radius * squish) / texsz[3]);
250
251 const float astep = a / (float) divisions;
252
253 for (i = 0; i < (divisions + 1); i++)
254 {
255 float ang = r + (astep * (float)i);
256 float cos_val = cosf(ang);
257 float sin_val = sinf(ang);
258
259 // vertices and normals
260 if (!isCircle || (i != divisions))
261 {
262 float delta[2];
263 delta[0] = cos_val * radius;
264 delta[1] = (sin_val * radius) * squish;
265 // vertices
266 v[0] = pos[0] + delta[0];
267 v[1] = pos[1] + delta[1];
268 v[2] = pos[2];
269 vertices.push_back(v);
270 v[2] = v[2] + h;
271 vertices.push_back(v);
272 // normal
273 if (useNormals)
274 {
275 n[2] = 0.0f;
276 n[0] = cos_val * squish;
277 n[1] = sin_val;
278 float len = 1.0f / sqrtf((n[0] * n[0]) + (n[1] * n[1]));
279 n[0] = n[0] * len;
280 n[1] = n[1] * len;
281 normals.push_back(n);
282 }
283 }
284
285 // texture coordinates (around the edge)
286 t[0] = (float) i / (float) divisions;
287 t[0] = texsz[0] * t[0];
288 t[1] = 0.0f;
289 texcoords.push_back(t);
290 // outside texcoord
291 t[1] = texsz[1] * 1.0f;
292 texcoords.push_back(t);
293 }
294
295 // texture coordinates (around the disc)
296 for (i = 0; i < (divisions + 1); i++)
297 {
298 float ang = astep * (float)i;
299 float cos_val = cosf(ang);
300 float sin_val = sinf(ang);
301 t[0] = texsz[2] * (0.5f + (0.5f * cos_val));
302 t[1] = texsz[3] * (0.5f + (0.5f * sin_val));
303 texcoords.push_back(t);
304 }
305
306 // the central coordinates
307 v[0] = pos[0];
308 v[1] = pos[1];
309 v[2] = pos[2];
310 vertices.push_back(v); // bottom
311 v[2] = pos[2] + h;
312 vertices.push_back(v); // top
313 t[0] = texsz[2] * 0.5f;
314 t[1] = texsz[3] * 0.5f;
315 texcoords.push_back(t);
316
317 // setup the face count
318 int fcount = (divisions * 3);
319 if (!isCircle)
320 {
321 fcount = fcount + 2; // add the start and end faces
322 }
323
324 mesh = new MeshObstacle(transform, checkTypes, checkPoints,
325 vertices, normals, texcoords, fcount,
326 false, smoothBounce, driveThrough, shootThrough, ricochet);
327
328 // now make the faces
329 int vlen, nlen;
330 if (isCircle)
331 {
332 vlen = divisions * 2;
333 nlen = divisions;
334 }
335 else
336 {
337 vlen = (divisions + 1) * 2;
338 nlen = (divisions + 1);
339 }
340
341 const int vtop = vlen + 1;
342 const int vbot = vlen;
343 const int tmid = ((divisions + 1) * 3);
344
345 std::vector<int> vlist;
346 std::vector<int> nlist;
347 std::vector<int> tlist;
348
349 for (i = 0; i < divisions; i++)
350 {
351
352 // handy macros
353 #define PV(x) (((x) + (i * 2)) % vlen)
354 #define PN(x) (((x) + i) % nlen)
355 #define PTO(x) ((x) + (i * 2)) // outside edge
356 #define PTC(x) (((divisions + 1) * 2) + (x) + i) // around the disc
357 #define PTCI(x) (((divisions + 1) * 3) - (x) - i - 1)
358
359 // outside
360 push4Ints(vlist, PV(0), PV(2), PV(3), PV(1));
361 if (useNormals) push4Ints(nlist, PN(0), PN(1), PN(1), PN(0));
362 push4Ints(tlist, PTO(0), PTO(2), PTO(3), PTO(1));
363 addFace(mesh, vlist, nlist, tlist, materials[Outside_], phydrv);
364
365 // top
366 push3Ints(vlist, vtop, PV(1), PV(3));
367 push3Ints(tlist, tmid, PTC(0), PTC(1));
368 addFace(mesh, vlist, nlist, tlist, materials[Top], phydrv);
369
370 // bottom
371 push3Ints(vlist, vbot, PV(2), PV(0));
372 push3Ints(tlist, tmid, PTCI(1), PTCI(0));
373 addFace(mesh, vlist, nlist, tlist, materials[Bottom], phydrv);
374 }
375
376
377 if (!isCircle)
378 {
379 int tc = (divisions * 2);
380 // start face
381 push4Ints(vlist, vbot, 0, 1, vtop);
382 push4Ints(tlist, 0, tc + 0, tc + 1, 1);
383 addFace(mesh, vlist, nlist, tlist, materials[StartFace], phydrv);
384
385 // end face
386 int e = divisions * 2;
387 push4Ints(vlist, e + 0, vbot, vtop, e + 1);
388 push4Ints(tlist, 0, tc + 0, tc + 1, 1);
389 addFace(mesh, vlist, nlist, tlist, materials[EndFace], phydrv);
390 }
391
392 return mesh;
393 }
394
395
makeRing(bool isCircle,float a,float r,float h,float inrad,float outrad,float squish,float texsz[4])396 MeshObstacle* ArcObstacle::makeRing(bool isCircle, float a, float r,
397 float h, float inrad, float outrad,
398 float squish, float texsz[4])
399 {
400 MeshObstacle* mesh;
401
402 // setup the coordinates
403 std::vector<char> checkTypes;
404 std::vector<cfvec3> checkPoints;
405 std::vector<cfvec3> vertices;
406 std::vector<cfvec3> normals;
407 std::vector<cfvec2> texcoords;
408 cfvec3 v, n;
409 cfvec2 t;
410
411 // add the checkpoints (very wasteful)
412 v[0] = pos[0];
413 v[1] = pos[1];
414 const float height = fabsf(size[2]);
415 if (pos[2] > 0.0f)
416 {
417 // down
418 v[2] = pos[2] - (1.0f * height);
419 checkPoints.push_back(v);
420 checkTypes.push_back(MeshObstacle::CheckOutside);
421 // up
422 v[2] = pos[2] + (2.0f * height);
423 checkPoints.push_back(v);
424 checkTypes.push_back(MeshObstacle::CheckOutside);
425 }
426 else
427 {
428 // up
429 v[2] = pos[2] + (2.0f * height);
430 checkPoints.push_back(v);
431 checkTypes.push_back(MeshObstacle::CheckOutside);
432 // down
433 v[2] = pos[2] - (1.0f * height);
434 checkPoints.push_back(v);
435 checkTypes.push_back(MeshObstacle::CheckOutside);
436 }
437 // east
438 v[2] = pos[2] + (0.5f * height);
439 v[0] = pos[0] + (outrad * 2.0f);
440 checkPoints.push_back(v);
441 checkTypes.push_back(MeshObstacle::CheckOutside);
442 // west
443 v[0] = pos[0] - (outrad * 2.0f);
444 checkPoints.push_back(v);
445 checkTypes.push_back(MeshObstacle::CheckOutside);
446 // north
447 v[0] = pos[0];
448 v[1] = pos[1] + (outrad * squish * 2.0f);
449 checkPoints.push_back(v);
450 checkTypes.push_back(MeshObstacle::CheckOutside);
451 // south
452 v[1] = pos[1] - (outrad * squish * 2.0f);
453 checkPoints.push_back(v);
454 checkTypes.push_back(MeshObstacle::CheckOutside);
455
456 int i;
457 const float astep = a / (float) divisions;
458
459 for (i = 0; i < (divisions + 1); i++)
460 {
461 float ang = r + (astep * (float)i);
462 float cos_val = cosf(ang);
463 float sin_val = sinf(ang);
464
465 // vertices and normals
466 if (!isCircle || (i != divisions))
467 {
468 // inside points
469 v[0] = pos[0] + (cos_val * inrad);
470 v[1] = pos[1] + (squish * (sin_val * inrad));
471 v[2] = pos[2];
472 vertices.push_back(v);
473 v[2] = v[2] + h;
474 vertices.push_back(v);
475 // outside points
476 v[0] = pos[0] + (cos_val * outrad);
477 v[1] = pos[1] + (squish * (sin_val * outrad));
478 v[2] = pos[2];
479 vertices.push_back(v);
480 v[2] = v[2] + h;
481 vertices.push_back(v);
482 // inside normal
483 if (useNormals)
484 {
485 n[2] = 0.0f;
486 n[0] = -cos_val * squish;
487 n[1] = -sin_val;
488 float len = 1.0f / sqrtf((n[0] * n[0]) + (n[1] * n[1]));
489 n[0] = n[0] * len;
490 n[1] = n[1] * len;
491 normals.push_back(n);
492 // outside normal
493 n[0] = -n[0];
494 n[1] = -n[1];
495 normals.push_back(n);
496 }
497 }
498
499 // texture coordinates
500 // inside texcoord
501 t[0] = (float) i / (float) divisions;
502 t[0] = texsz[0] * t[0];
503 t[1] = 0.0f;
504 texcoords.push_back(t);
505 // outside texcoord
506 t[1] = texsz[1] * 1.0f;
507 texcoords.push_back(t);
508 }
509
510 // setup the face count
511 int fcount = (divisions * 4);
512 if (!isCircle)
513 {
514 fcount = fcount + 2; // add the start and end faces
515 }
516
517 mesh = new MeshObstacle(transform, checkTypes, checkPoints,
518 vertices, normals, texcoords, fcount,
519 false, smoothBounce, driveThrough, shootThrough, ricochet);
520
521 // now make the faces
522 int vlen, nlen;
523 if (isCircle)
524 {
525 vlen = divisions * 4;
526 nlen = divisions * 2;
527 }
528 else
529 {
530 vlen = (divisions + 1) * 4;
531 nlen = (divisions + 1) * 2;
532 }
533
534 std::vector<int> vlist;
535 std::vector<int> nlist;
536 std::vector<int> tlist;
537
538 for (i = 0; i < divisions; i++)
539 {
540
541 // handy macros
542 #define RV(x) (((x) + (i * 4)) % vlen)
543 #define RN(x) (((x) + (i * 2)) % nlen)
544 #define RT(x) ((x) + (i * 2))
545 #define RIT(x) ((divisions + ((x)%2))*2 - ((x) + (i * 2)))
546
547 // inside
548 push4Ints(vlist, RV(4), RV(0), RV(1), RV(5));
549 if (useNormals) push4Ints(nlist, RN(2), RN(0), RN(0), RN(2));
550 push4Ints(tlist, RIT(2), RIT(0), RIT(1), RIT(3));
551 addFace(mesh, vlist, nlist, tlist, materials[Inside], phydrv);
552
553 // outside
554 push4Ints(vlist, RV(2), RV(6), RV(7), RV(3));
555 if (useNormals) push4Ints(nlist, RN(1), RN(3), RN(3), RN(1));
556 push4Ints(tlist, RT(0), RT(2), RT(3), RT(1));
557 addFace(mesh, vlist, nlist, tlist, materials[Outside_], phydrv);
558
559 // top
560 push4Ints(vlist, RV(3), RV(7), RV(5), RV(1));
561 push4Ints(tlist, RT(0), RT(2), RT(3), RT(1));
562 addFace(mesh, vlist, nlist, tlist, materials[Top], phydrv);
563
564 // bottom
565 push4Ints(vlist, RV(0), RV(4), RV(6), RV(2));
566 push4Ints(tlist, RT(0), RT(2), RT(3), RT(1));
567 addFace(mesh, vlist, nlist, tlist, materials[Bottom], phydrv);
568 }
569
570 if (!isCircle)
571 {
572 int tc = (divisions * 2);
573 // start face
574 push4Ints(vlist, 0, 2, 3, 1);
575 push4Ints(tlist, 0, tc + 0, tc + 1, 1);
576 addFace(mesh, vlist, nlist, tlist, materials[StartFace], phydrv);
577
578 // end face
579 int e = divisions * 4;
580 push4Ints(vlist, e + 2, e + 0, e + 1, e + 3);
581 push4Ints(tlist, 0, tc + 0, tc + 1, 1);
582 addFace(mesh, vlist, nlist, tlist, materials[EndFace], phydrv);
583 }
584
585 return mesh;
586 }
587
588
intersect(const Ray &) const589 float ArcObstacle::intersect(const Ray&) const
590 {
591 assert(false);
592 return -1.0f;
593 }
594
595
get3DNormal(const float *,float *) const596 void ArcObstacle::get3DNormal(const float*, float*) const
597 {
598 assert(false);
599 return;
600 }
601
602
getNormal(const float *,float *) const603 void ArcObstacle::getNormal(const float*, float*) const
604 {
605 assert(false);
606 return;
607 }
608
609
getHitNormal(const float *,float,const float *,float,float,float,float,float *) const610 bool ArcObstacle::getHitNormal(const float*, float, const float*, float,
611 float, float, float, float*) const
612 {
613 assert(false);
614 return false;
615 }
616
617
inCylinder(const float *,float,float) const618 bool ArcObstacle::inCylinder(const float*,float, float) const
619 {
620 assert(false);
621 return false;
622 }
623
624
inBox(const float *,float,float,float,float) const625 bool ArcObstacle::inBox(const float*, float, float, float, float) const
626 {
627 assert(false);
628 return false;
629 }
630
631
inMovingBox(const float *,float,const float *,float,float,float,float) const632 bool ArcObstacle::inMovingBox(const float*, float, const float*, float,
633 float, float, float) const
634 {
635 assert(false);
636 return false;
637 }
638
639
isCrossing(const float * UNUSED (p),float UNUSED (_angle),float UNUSED (dx),float UNUSED (dy),float UNUSED (height),float * UNUSED (_plane)) const640 bool ArcObstacle::isCrossing(const float* UNUSED(p), float UNUSED(_angle),
641 float UNUSED(dx), float UNUSED(dy), float UNUSED(height),
642 float* UNUSED(_plane)) const
643 {
644 assert(false);
645 return false;
646 }
647
648
pack(void * buf) const649 void* ArcObstacle::pack(void* buf) const
650 {
651 buf = transform.pack(buf);
652 buf = nboPackVector(buf, pos);
653 buf = nboPackVector(buf, size);
654 buf = nboPackFloat(buf, angle);
655 buf = nboPackFloat(buf, sweepAngle);
656 buf = nboPackFloat(buf, ratio);
657 buf = nboPackInt(buf, divisions);
658 buf = nboPackInt(buf, phydrv);
659
660 int i;
661 for (i = 0; i < 4; i++)
662 buf = nboPackFloat(buf, texsize[i]);
663 for (i = 0; i < MaterialCount; i++)
664 {
665 int matindex = MATERIALMGR.getIndex(materials[i]);
666 buf = nboPackInt(buf, matindex);
667 }
668
669 // pack the state byte
670 unsigned char stateByte = 0;
671 stateByte |= isDriveThrough() ? (1 << 0) : 0;
672 stateByte |= isShootThrough() ? (1 << 1) : 0;
673 stateByte |= smoothBounce ? (1 << 2) : 0;
674 stateByte |= useNormals ? (1 << 3) : 0;
675 stateByte |= canRicochet() ? (1 << 4) : 0;
676 buf = nboPackUByte(buf, stateByte);
677
678 return buf;
679 }
680
681
unpack(const void * buf)682 const void* ArcObstacle::unpack(const void* buf)
683 {
684 int32_t inTmp;
685 buf = transform.unpack(buf);
686 buf = nboUnpackVector(buf, pos);
687 buf = nboUnpackVector(buf, size);
688 buf = nboUnpackFloat(buf, angle);
689 buf = nboUnpackFloat(buf, sweepAngle);
690 buf = nboUnpackFloat(buf, ratio);
691 buf = nboUnpackInt(buf, inTmp);
692 divisions = int(inTmp);
693 buf = nboUnpackInt(buf, inTmp);
694 phydrv = int(inTmp);
695
696 int i;
697 for (i = 0; i < 4; i++)
698 buf = nboUnpackFloat(buf, texsize[i]);
699 for (i = 0; i < MaterialCount; i++)
700 {
701 int matindex;
702 buf = nboUnpackInt(buf, inTmp);
703 matindex = int(inTmp);
704 materials[i] = MATERIALMGR.getMaterial(matindex);
705 }
706
707 // unpack the state byte
708 unsigned char stateByte;
709 buf = nboUnpackUByte(buf, stateByte);
710 driveThrough = (stateByte & (1 << 0)) != 0;
711 shootThrough = (stateByte & (1 << 1)) != 0;
712 smoothBounce = (stateByte & (1 << 2)) != 0;
713 useNormals = (stateByte & (1 << 3)) != 0;
714 ricochet = (stateByte & (1 << 4)) != 0;
715
716 finalize();
717
718 return buf;
719 }
720
721
packSize() const722 int ArcObstacle::packSize() const
723 {
724 int fullSize = transform.packSize();
725 fullSize += sizeof(float[3]);
726 fullSize += sizeof(float[3]);
727 fullSize += sizeof(float);
728 fullSize += sizeof(float);
729 fullSize += sizeof(float);
730 fullSize += sizeof(int32_t);
731 fullSize += sizeof(int32_t);
732 fullSize += sizeof(float[4]);
733 fullSize += sizeof(int32_t[MaterialCount]);
734 fullSize += sizeof(unsigned char);
735 return fullSize;
736 }
737
738
print(std::ostream & out,const std::string & indent) const739 void ArcObstacle::print(std::ostream& out, const std::string& indent) const
740 {
741 int i;
742
743 out << indent << "arc" << std::endl;
744
745 out << indent << " position " << pos[0] << " "
746 << pos[1] << " " << pos[2] << std::endl;
747 out << indent << " size " << size[0] << " "
748 << size[1] << " " << size[2] << std::endl;
749 out << indent << " rotation " << ((angle * 180.0) / M_PI) << std::endl;
750 out << indent << " angle " << sweepAngle << std::endl;
751 out << indent << " ratio " << ratio << std::endl;
752 out << indent << " divisions " << divisions << std::endl;
753
754 transform.printTransforms(out, indent);
755
756 out << indent << " texsize " << texsize[0] << " " << texsize[1] << " "
757 << texsize[2] << " " << texsize[3]
758 << std::endl;
759
760 const char* sideNames[MaterialCount] =
761 { "top", "bottom", "inside", "outside", "startside", "endside" };
762 for (i = 0; i < MaterialCount; i++)
763 {
764 out << indent << " " << sideNames[i] << " matref ";
765 MATERIALMGR.printReference(out, materials[i]);
766 out << std::endl;
767 }
768
769 const PhysicsDriver* driver = PHYDRVMGR.getDriver(phydrv);
770 if (driver != NULL)
771 {
772 out << indent << " phydrv ";
773 if (driver->getName().size() > 0)
774 out << driver->getName();
775 else
776 out << phydrv;
777 out << std::endl;
778 }
779
780 if (smoothBounce)
781 out << indent << " smoothBounce" << std::endl;
782 if (driveThrough)
783 out << indent << " driveThrough" << std::endl;
784 if (shootThrough)
785 out << indent << " shootThrough" << std::endl;
786 if (ricochet)
787 out << indent << " ricochet" << std::endl;
788 if (!useNormals)
789 out << indent << " flatshading" << std::endl;
790
791 out << indent << "end" << std::endl;
792
793 return;
794 }
795
796
797 // Local Variables: ***
798 // mode: C++ ***
799 // tab-width: 4 ***
800 // c-basic-offset: 4 ***
801 // indent-tabs-mode: nil ***
802 // End: ***
803 // ex: shiftwidth=4 tabstop=4
804