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
14 #include "common.h"
15
16 // implementation header
17 #include "ObstacleMgr.h"
18
19 // system headers
20 #include <string.h>
21 #include <string>
22 #include <sstream>
23 #include <vector>
24 #include <map>
25 #include <iostream>
26
27 // common headers
28 #include "Pack.h"
29 #include "MeshTransform.h"
30 #include "ObstacleModifier.h"
31 #include "StateDatabase.h"
32 #include "PhysicsDriver.h"
33 #include "BzMaterial.h"
34 #include "MeshDrawInfo.h"
35
36 // obstacle headers
37 #include "Obstacle.h"
38 #include "WallObstacle.h"
39 #include "BoxBuilding.h"
40 #include "PyramidBuilding.h"
41 #include "BaseBuilding.h"
42 #include "Teleporter.h"
43 #include "MeshObstacle.h"
44 #include "ArcObstacle.h"
45 #include "ConeObstacle.h"
46 #include "SphereObstacle.h"
47 #include "TetraBuilding.h"
48
49
50 //////////////////////////////////////////////////////////////////////////////
51 //
52 // Group Instance
53 // - uses a group definition and a transform to produce obstacles
54 //
55
56
init()57 void GroupInstance::init()
58 {
59 modifyTeam = false;
60 team = 0;
61 modifyColor = false;
62 tint[0] = tint[1] = tint[2] = tint[3] = 1.0f;
63 modifyPhysicsDriver = false;
64 phydrv = -1;
65 modifyMaterial = false;
66 material = NULL;
67 driveThrough = false;
68 shootThrough = false;
69 ricochet = false;
70
71 return;
72 }
73
74
GroupInstance(const std::string & _groupdef)75 GroupInstance::GroupInstance(const std::string& _groupdef)
76 {
77 groupdef = _groupdef;
78 init();
79 return;
80 }
81
82
GroupInstance()83 GroupInstance::GroupInstance()
84 {
85 init();
86 return;
87 }
88
89
~GroupInstance()90 GroupInstance::~GroupInstance()
91 {
92 return;
93 }
94
95
setTransform(const MeshTransform & _transform)96 void GroupInstance::setTransform(const MeshTransform& _transform)
97 {
98 transform = _transform;
99 return;
100 }
101
102
setName(const std::string & _name)103 void GroupInstance::setName(const std::string& _name)
104 {
105 name = _name;
106 return;
107 }
108
109
getName() const110 const std::string& GroupInstance::getName() const
111 {
112 return name;
113 }
114
115
setTeam(int _team)116 void GroupInstance::setTeam(int _team)
117 {
118 team = _team;
119 modifyTeam = true;
120 return;
121 }
122
123
setTint(const float _tint[4])124 void GroupInstance::setTint(const float _tint[4])
125 {
126 memcpy(tint, _tint, sizeof(float[4]));
127 modifyColor = true;
128 return;
129 }
130
131
setPhysicsDriver(int _phydrv)132 void GroupInstance::setPhysicsDriver(int _phydrv)
133 {
134 phydrv = _phydrv;
135 modifyPhysicsDriver = true;
136 return;
137 }
138
139
setMaterial(const BzMaterial * _material)140 void GroupInstance::setMaterial(const BzMaterial* _material)
141 {
142 material = _material;
143 modifyMaterial = true;
144 return;
145 }
146
147
setDriveThrough()148 void GroupInstance::setDriveThrough()
149 {
150 driveThrough = true;
151 return;
152 }
153
154
setShootThrough()155 void GroupInstance::setShootThrough()
156 {
157 shootThrough = true;
158 return;
159 }
160
setCanRicochet()161 void GroupInstance::setCanRicochet()
162 {
163 ricochet = true;
164 return;
165 }
166
167
addMaterialSwap(const BzMaterial * srcMat,const BzMaterial * dstMat)168 void GroupInstance::addMaterialSwap(const BzMaterial* srcMat,
169 const BzMaterial* dstMat)
170 {
171 matMap[srcMat] = dstMat;
172 return;
173 }
174
175
getGroupDef() const176 const std::string& GroupInstance::getGroupDef() const
177 {
178 return groupdef;
179 }
180
181
getTransform() const182 const MeshTransform& GroupInstance::getTransform() const
183 {
184 return transform;
185 }
186
187
pack(void * buf)188 void* GroupInstance::pack(void* buf)
189 {
190 buf = nboPackStdString(buf, groupdef);
191
192 if (matMap.size() <= 0)
193 buf = nboPackStdString(buf, name);
194 else
195 {
196 // hack to stuff in material map data
197 std::string fakeString = name;
198 const unsigned int origSize = fakeString.size();
199 const unsigned int fakeSize =
200 (1 + sizeof(int32_t) + (matMap.size() * 2 * sizeof(int32_t)));
201 fakeString.resize(origSize + fakeSize);
202 char* buffer = new char[fakeSize];
203 void* p;
204 int count = matMap.size();
205 p = nboPackUByte(buffer, 0); // terminate
206 p = nboPackInt(p, count);
207 MaterialMap::const_iterator it;
208 for (it = matMap.begin(); it != matMap.end(); ++it)
209 {
210 int srcIndex = MATERIALMGR.getIndex(it->first);
211 int dstIndex = MATERIALMGR.getIndex(it->second);
212 p = nboPackInt(p, srcIndex);
213 p = nboPackInt(p, dstIndex);
214 }
215 for (unsigned int i = 0; i < fakeSize; i++)
216 fakeString[origSize + i] = buffer[i];
217 delete[] buffer;
218 buf = nboPackStdString(buf, fakeString);
219 }
220
221 buf = transform.pack(buf);
222
223 uint8_t bits = 0;
224 if (modifyTeam) bits |= (1 << 0);
225 if (modifyColor) bits |= (1 << 1);
226 if (modifyPhysicsDriver) bits |= (1 << 2);
227 if (modifyMaterial) bits |= (1 << 3);
228 if (driveThrough) bits |= (1 << 4);
229 if (shootThrough) bits |= (1 << 5);
230 if (ricochet) bits |= (1 << 6);
231 buf = nboPackUByte(buf, bits);
232
233 if (modifyTeam)
234 buf = nboPackUShort(buf, team);
235 if (modifyColor)
236 {
237 buf = nboPackVector(buf, tint);
238 buf = nboPackFloat(buf, tint[3]);
239 }
240 if (modifyPhysicsDriver)
241 buf = nboPackInt(buf, phydrv);
242 if (modifyMaterial)
243 {
244 int matindex = MATERIALMGR.getIndex(material);
245 buf = nboPackInt(buf, (int32_t) matindex);
246 }
247
248 return buf;
249 }
250
251
unpack(const void * buf)252 const void* GroupInstance::unpack(const void* buf)
253 {
254 buf = nboUnpackStdString(buf, groupdef);
255
256 buf = nboUnpackStdStringRaw(buf, name);
257 if (strlen(name.c_str()) != name.size())
258 {
259 // hack to extract material map data
260 const void* p = name.c_str() + strlen(name.c_str()) + 1;
261 nboUseErrorChecking(false);
262 {
263 int32_t count;
264 p = nboUnpackInt(p, count);
265 for (int i = 0; i < count; i++)
266 {
267 int32_t srcIndex, dstIndex;
268 p = nboUnpackInt(p, srcIndex);
269 p = nboUnpackInt(p, dstIndex);
270 const BzMaterial* srcMat = MATERIALMGR.getMaterial(srcIndex);
271 const BzMaterial* dstMat = MATERIALMGR.getMaterial(dstIndex);
272 matMap[srcMat] = dstMat;
273 }
274 }
275 nboUseErrorChecking(true);
276 name.resize(strlen(name.c_str())); // clean up the name
277 }
278
279 buf = transform.unpack(buf);
280
281 uint8_t bits;
282 buf = nboUnpackUByte(buf, bits);
283 modifyTeam = ((bits & (1 << 0)) == 0) ? false : true;
284 modifyColor = ((bits & (1 << 1)) == 0) ? false : true;
285 modifyPhysicsDriver = ((bits & (1 << 2)) == 0) ? false : true;
286 modifyMaterial = ((bits & (1 << 3)) == 0) ? false : true;
287 driveThrough = ((bits & (1 << 4)) == 0) ? false : true;
288 shootThrough = ((bits & (1 << 5)) == 0) ? false : true;
289 ricochet = ((bits & (1 << 6)) == 0) ? false : true;
290
291 if (modifyTeam)
292 {
293 uint16_t tmpTeam;
294 buf = nboUnpackUShort(buf, tmpTeam);
295 team = (int)tmpTeam;
296 }
297 if (modifyColor)
298 {
299 buf = nboUnpackVector(buf, tint);
300 buf = nboUnpackFloat(buf, tint[3]);
301 }
302 if (modifyPhysicsDriver)
303 {
304 int32_t inPhyDrv;
305 buf = nboUnpackInt(buf, inPhyDrv);
306 phydrv = int(inPhyDrv);
307 }
308 if (modifyMaterial)
309 {
310 int32_t matindex;
311 buf = nboUnpackInt(buf, matindex);
312 material = MATERIALMGR.getMaterial(matindex);
313 }
314
315 return buf;
316 }
317
318
packSize()319 int GroupInstance::packSize()
320 {
321 int fullSize = 0;
322 fullSize += nboStdStringPackSize(groupdef);
323
324 fullSize += nboStdStringPackSize(name);
325 if (matMap.size() > 0)
326 {
327 fullSize += 1; // terminator
328 fullSize += sizeof(int32_t); // count;
329 fullSize += matMap.size() * 2 * sizeof(int32_t);
330 }
331
332 fullSize += transform.packSize();
333 fullSize += sizeof(uint8_t);
334 if (modifyTeam)
335 fullSize += sizeof(uint16_t);
336 if (modifyColor)
337 fullSize += sizeof(float[4]);
338 if (modifyPhysicsDriver)
339 fullSize += sizeof(int32_t);
340 if (modifyMaterial)
341 fullSize += sizeof(int32_t);
342 return fullSize;
343 }
344
345
print(std::ostream & out,const std::string & indent) const346 void GroupInstance::print(std::ostream& out, const std::string& indent) const
347 {
348 out << indent << "group " << groupdef << std::endl;
349
350 if (name.size() > 0)
351 out << indent << " name " << name << std::endl;
352
353 transform.printTransforms(out, indent);
354 if (modifyTeam)
355 out << indent << " team " << team << std::endl;
356 if (modifyColor)
357 {
358 out << indent << " tint " << tint[0] << " " << tint[1] << " "
359 << tint[2] << " " << tint[3] << " "
360 << std::endl;
361 }
362 if (modifyPhysicsDriver)
363 {
364 const PhysicsDriver* driver = PHYDRVMGR.getDriver(phydrv);
365 if (driver != NULL)
366 {
367 out << indent << " phydrv ";
368 if (driver->getName().size() > 0)
369 out << driver->getName();
370 else
371 out << phydrv;
372 out << std::endl;
373 }
374 }
375 if (modifyMaterial)
376 {
377 out << indent << " matref ";
378 MATERIALMGR.printReference(out, material);
379 out << std::endl;
380 }
381 else if (matMap.size() > 0)
382 {
383 MaterialMap::const_iterator it;
384 for (it = matMap.begin(); it != matMap.end(); ++it)
385 {
386 out << indent << " matswap ";
387 MATERIALMGR.printReference(out, it->first);
388 out << " ";
389 MATERIALMGR.printReference(out, it->second);
390 out << std::endl;
391 }
392 }
393
394 if (driveThrough)
395 out << indent << " driveThrough" << std::endl;
396 if (shootThrough)
397 out << indent << " shootThrough" << std::endl;
398 if (ricochet)
399 out << indent << " ricochet" << std::endl;
400 out << indent << "end" << std::endl;
401
402 return;
403 }
404
405
406 //////////////////////////////////////////////////////////////////////////////
407 //
408 // Group Definition
409 // - defines an obstacle group
410 //
411
412 std::string GroupDefinition::depthName;
413
414
GroupDefinition(const std::string & _name)415 GroupDefinition::GroupDefinition(const std::string& _name)
416 {
417 name = _name;
418 active = false;
419 return;
420 }
421
422
~GroupDefinition()423 GroupDefinition::~GroupDefinition()
424 {
425 return;
426 }
427
428
newObstacle(int type)429 Obstacle* GroupDefinition::newObstacle(int type)
430 {
431 Obstacle* obs = NULL;
432
433 if (type == wallType)
434 obs = new WallObstacle();
435 else if (type == boxType)
436 obs = new BoxBuilding();
437 else if (type == pyrType)
438 obs = new PyramidBuilding();
439 else if (type == baseType)
440 obs = new BaseBuilding();
441 else if (type == teleType)
442 obs = new Teleporter();
443 else if (type == meshType)
444 obs = new MeshObstacle();
445 else if (type == arcType)
446 obs = new ArcObstacle();
447 else if (type == coneType)
448 obs = new ConeObstacle();
449 else if (type == sphereType)
450 obs = new SphereObstacle();
451 else if (type == tetraType)
452 obs = new TetraBuilding();
453
454 return obs;
455 }
456
457
addObstacle(Obstacle * obstacle)458 void GroupDefinition::addObstacle(Obstacle* obstacle)
459 {
460 const char* type = obstacle->getType();
461
462 if (WallObstacle::getClassName() == type)
463 lists[wallType].push_back(obstacle);
464 else if (BoxBuilding::getClassName() == type)
465 lists[boxType].push_back(obstacle);
466 else if (BaseBuilding::getClassName() == type)
467 lists[baseType].push_back(obstacle);
468 else if (PyramidBuilding::getClassName() == type)
469 lists[pyrType].push_back(obstacle);
470 else if (Teleporter::getClassName() == type)
471 lists[teleType].push_back(obstacle);
472 else if (MeshObstacle::getClassName() == type)
473 lists[meshType].push_back(obstacle);
474 else if (ArcObstacle::getClassName() == type)
475 lists[arcType].push_back(obstacle);
476 else if (ConeObstacle::getClassName() == type)
477 lists[coneType].push_back(obstacle);
478 else if (SphereObstacle::getClassName() == type)
479 lists[sphereType].push_back(obstacle);
480 else if (TetraBuilding::getClassName() == type)
481 lists[tetraType].push_back(obstacle);
482 else
483 {
484 printf ("GroupDefinition::addObstacle() ERROR: type = %s\n", type);
485 exit(1);
486 }
487
488 return;
489 }
490
491
addGroupInstance(GroupInstance * group)492 void GroupDefinition::addGroupInstance(GroupInstance* group)
493 {
494 groups.push_back(group);
495 return;
496 }
497
498
isContainer(int type)499 static bool isContainer(int type)
500 {
501 switch (type)
502 {
503 case GroupDefinition::arcType:
504 case GroupDefinition::coneType:
505 case GroupDefinition::sphereType:
506 case GroupDefinition::tetraType:
507 return true;
508 default:
509 return false;
510 }
511 }
512
513
makeTeleName(Obstacle * obs,unsigned int pos) const514 void GroupDefinition::makeTeleName(Obstacle* obs, unsigned int pos) const
515 {
516 Teleporter* tele = (Teleporter*) obs;
517 std::string fullname = depthName;
518 if (tele->getName().size() > 0)
519 fullname += tele->getName();
520 else
521 {
522 // make the default name
523 fullname += "/t";
524 char buffer[8];
525 sprintf (buffer, "%i", pos);
526 fullname += buffer;
527 }
528 tele->setName(fullname);
529 return;
530 }
531
532
appendGroupName(const GroupInstance * group) const533 void GroupDefinition::appendGroupName(const GroupInstance* group) const
534 {
535 std::string newName;
536 if (group->getName().size() > 0)
537 newName = group->getName();
538 else
539 {
540 // make the default name
541 int count = 0;
542 for (unsigned int i = 0; i < groups.size(); i++)
543 {
544 const GroupInstance* g = groups[i];
545 if (g == group)
546 break;
547 if (g->getGroupDef() == group->getGroupDef())
548 count++;
549 }
550 newName = "/";
551 newName += group->getGroupDef();
552 newName += "/";
553 std::stringstream buffer;
554 buffer << count;
555 newName += buffer.str();
556 }
557 depthName += newName;
558 depthName += ":";
559 return;
560 }
561
562
makeContainedMesh(int type,Obstacle * obs)563 static MeshObstacle* makeContainedMesh(int type, Obstacle* obs)
564 {
565 MeshObstacle* mesh = NULL;
566 switch (type)
567 {
568 case GroupDefinition::arcType:
569 {
570 mesh = ((ArcObstacle*)obs)->makeMesh();
571 break;
572 }
573 case GroupDefinition::coneType:
574 {
575 mesh = ((ConeObstacle*)obs)->makeMesh();
576 break;
577 }
578 case GroupDefinition::sphereType:
579 {
580 mesh = ((SphereObstacle*)obs)->makeMesh();
581 break;
582 }
583 case GroupDefinition::tetraType:
584 {
585 mesh = ((TetraBuilding*)obs)->makeMesh();
586 break;
587 }
588 }
589 return mesh;
590 }
591
592
makeGroups(const MeshTransform & xform,const ObstacleModifier & obsMod) const593 void GroupDefinition::makeGroups(const MeshTransform& xform,
594 const ObstacleModifier& obsMod) const
595 {
596 if (active)
597 {
598 logDebugMessage(1,"warning: avoided recursion, groupdef \"%s\"\n", name.c_str());
599 return; // avoid recursion
600 }
601
602 active = true;
603
604 const bool isWorld = (this == OBSTACLEMGR.getWorld());
605 char groupDefBit = isWorld ? Obstacle::WorldSource :
606 Obstacle::GroupDefSource;
607
608 for (int type = 0; type < ObstacleTypeCount; type++)
609 {
610 const ObstacleList& list = lists[type];
611 for (unsigned int i = 0; i < list.size(); i++)
612 {
613 Obstacle* obs;
614 if (isWorld)
615 {
616 obs = list[i]; // no need to copy
617 }
618 else
619 obs = list[i]->copyWithTransform(xform);
620
621 // the tele names are setup with default names if
622 // they are not named (even for those in the world
623 // groupd def). invalid teleporters are also named
624 if (type == teleType)
625 makeTeleName(obs, i);
626
627 if (obs->isValid())
628 {
629 if (!isWorld)
630 {
631 // add it to the world
632 // (this will also add container obstacles into the world group)
633 obs->setSource(Obstacle::GroupDefSource);
634 obsMod.execute(obs);
635 OBSTACLEMGR.addWorldObstacle(obs);
636 // add a modified MeshDrawInfo to the new mesh, if applicable
637 if (type == meshType)
638 {
639 const MeshObstacle* source = (const MeshObstacle*) list[i];
640 const MeshDrawInfo* diSource = source->getDrawInfo();
641 if ((diSource != NULL) &&
642 (!diSource->isServerSide()) && diSource->isValid())
643 {
644 MaterialSet matSet;
645 MaterialMap matMap;
646 diSource->getMaterials(matSet);
647 obsMod.getMaterialMap(matSet, matMap);
648 MeshDrawInfo* diDest = new MeshDrawInfo(diSource, xform, matMap);
649 MeshObstacle* dest = (MeshObstacle*) obs;
650 dest->setDrawInfo(diDest);
651 }
652 }
653 }
654 // generate contained meshes
655 // (always get placed into the world group)
656 MeshObstacle* mesh = makeContainedMesh(type, obs);
657 if ((mesh != NULL) && mesh->isValid())
658 {
659 mesh->setSource(Obstacle::ContainerSource | groupDefBit);
660 obsMod.execute(mesh);
661 OBSTACLEMGR.addWorldObstacle(mesh);
662 }
663 }
664 }
665 }
666
667 for (unsigned int i = 0; i < groups.size(); i++)
668 {
669 const GroupInstance* group = groups[i];
670 const GroupDefinition* groupDef =
671 OBSTACLEMGR.findGroupDef(group->getGroupDef());
672 if (groupDef != NULL)
673 {
674 // make the new depth name
675 std::string tmpDepthName = depthName;
676 appendGroupName(group);
677
678 // setup the transform and modifier
679 ObstacleModifier newObsMod(obsMod, *group);
680 MeshTransform tmpXform = xform;
681 tmpXform.prepend(group->getTransform());
682
683 // recurse and make plentiful
684 groupDef->makeGroups(tmpXform, newObsMod);
685
686 // revert to the old depth name
687 depthName = tmpDepthName;
688 }
689 else
690 {
691 logDebugMessage(1,"warning: group definition \"%s\" is missing\n",
692 group->getGroupDef().c_str());
693 }
694 }
695
696 active = false;
697
698 return;
699 }
700
701
replaceBasesWithBoxes()702 void GroupDefinition::replaceBasesWithBoxes()
703 {
704 ObstacleList& list = lists[baseType];
705 for (unsigned int i = 0; i < list.size(); i++)
706 {
707 BaseBuilding* base = (BaseBuilding*) list[i];
708 const float* baseSize = base->getSize();
709 BoxBuilding* box =
710 new BoxBuilding(base->getPosition(), base->getRotation(),
711 baseSize[0], baseSize[1], baseSize[2],
712 base->isDriveThrough(), base->isShootThrough(),
713 base->canRicochet(), false);
714 delete base;
715 list.remove(i);
716 i--;
717 addObstacle(box);
718 }
719 return;
720 }
721
722
clear()723 void GroupDefinition::clear()
724 {
725 for (int type = 0; type < ObstacleTypeCount; type++)
726 {
727 ObstacleList& list = lists[type];
728 for (unsigned int i = 0; i < list.size(); i++)
729 delete list[i];
730 list.clear();
731 }
732
733 for (unsigned int i = 0; i < groups.size(); i++)
734 delete groups[i];
735 groups.clear();
736
737 return;
738 }
739
740
tighten()741 void GroupDefinition::tighten()
742 {
743 for (int type = 0; type < ObstacleTypeCount; type++)
744 lists[type].tighten();
745 return;
746 }
747
748
sort(int (* compare)(const void * a,const void * b))749 void GroupDefinition::sort(int (*compare)(const void* a, const void* b))
750 {
751 if (this != OBSTACLEMGR.getWorld())
752 {
753 return; // only sort the world groupdef
754 }
755 for (int type = 0; type < ObstacleTypeCount; type++)
756 lists[type].sort(compare);
757 return;
758 }
759
760
deleteInvalidObstacles()761 void GroupDefinition::deleteInvalidObstacles()
762 {
763 if (this != OBSTACLEMGR.getWorld())
764 {
765 return; // only delete invalid obstacles in the world groupdef
766 }
767 for (int type = 0; type < ObstacleTypeCount; type++)
768 {
769 ObstacleList& list = lists[teleType];
770 for (unsigned int i = 0; i < list.size(); i++)
771 {
772 Obstacle* obs = list[i];
773 if (!obs->isValid())
774 {
775 logDebugMessage(1,"Deleted invalid %s obstacle\n", obs->getType());
776 delete obs;
777 list.remove(i);
778 i--; // don't miss the substitute
779 }
780 }
781 }
782 return;
783 }
784
785
getSourceMeshes(std::vector<MeshObstacle * > & meshes) const786 void GroupDefinition::getSourceMeshes(std::vector<MeshObstacle*>& meshes) const
787 {
788 const bool isWorld = (this == OBSTACLEMGR.getWorld());
789
790 const ObstacleList& list = lists[meshType];
791 for (unsigned int i = 0; i < list.size(); i++)
792 {
793 MeshObstacle* mesh = (MeshObstacle*)list[i];
794 if (!isWorld || mesh->isFromWorldFile())
795 {
796 const int listSize = (int)meshes.size();
797 int j;
798 for (j = 0; j < listSize; j++)
799 {
800 if (meshes[j] == mesh)
801 break;
802 }
803 if (j == listSize)
804 {
805 meshes.push_back(mesh); // a new entry
806 }
807 }
808 }
809
810 for (unsigned int i = 0; i < groups.size(); i++)
811 {
812 const GroupInstance* group = groups[i];
813 const GroupDefinition* groupDef =
814 OBSTACLEMGR.findGroupDef(group->getGroupDef());
815 if (groupDef != NULL)
816 groupDef->getSourceMeshes(meshes);
817 }
818
819 return;
820 }
821
822
pack(void * buf) const823 void* GroupDefinition::pack(void* buf) const
824 {
825 buf = nboPackStdString(buf, name);
826
827 unsigned int i;
828 for (int type = 0; type < ObstacleTypeCount; type++)
829 {
830 const ObstacleList& list = getList(type);
831 int count = 0;
832 for (i = 0; i < list.size(); i++)
833 {
834 if (list[i]->isFromWorldFile())
835 count++;
836 }
837 buf = nboPackUInt(buf, count);
838 for (i = 0; i < list.size(); i++)
839 {
840 if (list[i]->isFromWorldFile())
841 buf = list[i]->pack(buf);
842 }
843 }
844
845 buf = nboPackUInt(buf, groups.size());
846 for (i = 0; i < groups.size(); i++)
847 buf = groups[i]->pack(buf);
848
849 return buf;
850 }
851
852
unpack(const void * buf)853 const void* GroupDefinition::unpack(const void* buf)
854 {
855 buf = nboUnpackStdString(buf, name);
856
857 uint32_t i, count;
858
859 for (int type = 0; type < ObstacleTypeCount; type++)
860 {
861 buf = nboUnpackUInt(buf, count);
862 for (i = 0; i < count; i++)
863 {
864 Obstacle* obs = newObstacle(type);
865 if (obs != NULL)
866 {
867 buf = obs->unpack(buf);
868 if (obs->isValid())
869 lists[type].push_back(obs);
870 }
871 }
872 }
873
874 buf = nboUnpackUInt(buf, count);
875 for (i = 0; i < count; i++)
876 {
877 GroupInstance* group = new GroupInstance;
878 buf = group->unpack(buf);
879 addGroupInstance(group);
880 }
881
882 return buf;
883 }
884
885
packSize() const886 int GroupDefinition::packSize() const
887 {
888 int fullSize = 0;
889
890 fullSize += nboStdStringPackSize(name);
891
892 for (int type = 0; type < ObstacleTypeCount; type++)
893 {
894 fullSize += sizeof(uint32_t);
895 const ObstacleList& list = getList(type);
896 for (unsigned int i = 0; i < list.size(); i++)
897 {
898 if (list[i]->isFromWorldFile())
899 fullSize += list[i]->packSize();
900 }
901 }
902 fullSize += sizeof(uint32_t);
903 for (unsigned int i = 0; i < groups.size(); i++)
904 fullSize += groups[i]->packSize();
905
906 return fullSize;
907 }
908
909
printGrouped(std::ostream & out,const std::string & indent) const910 void GroupDefinition::printGrouped(std::ostream& out,
911 const std::string& indent) const
912 {
913 const bool isWorld = (this == OBSTACLEMGR.getWorld());
914 const bool saveAsMeshes = BZDB.isTrue("saveAsMeshes");
915 std::string myIndent = indent;
916
917 // deal with indenting
918 if (!isWorld)
919 {
920 myIndent += " ";
921 out << indent << "define " << name << std::endl;
922 }
923
924 // print the obstacles
925 for (int type = 0; type < ObstacleTypeCount; type++)
926 {
927 const ObstacleList& list = getList(type);
928 for (unsigned int i = 0; i < list.size(); i++)
929 {
930 Obstacle* obs = list[i];
931
932 if (!obs->isFromGroupDef() && !obs->isFromContainer())
933 {
934 if (!saveAsMeshes)
935 {
936 if (!obs->isFromContainer())
937 obs->print(out, myIndent);
938 }
939 else
940 {
941 if (!isContainer(type))
942 obs->print(out, myIndent);
943 else
944 {
945 // rebuild the mesh (ya, just to print it)
946 MeshObstacle* mesh = makeContainedMesh(type, obs);
947 if ((mesh != NULL) && (mesh->isValid()))
948 mesh->print(out, myIndent);
949 delete mesh;
950 }
951 }
952 }
953 }
954 }
955
956 // print the groups
957 for (unsigned int i = 0; i < groups.size(); i++)
958 groups[i]->print(out, myIndent);
959
960 // deal with indenting
961 if (!isWorld)
962 out << indent << "enddef" << std::endl << std::endl;
963
964 return;
965 }
966
967
printFlatFile(std::ostream & out,const std::string & indent) const968 void GroupDefinition::printFlatFile(std::ostream& out,
969 const std::string& indent) const
970 {
971 const bool saveAsOBJ = BZDB.isTrue("saveAsOBJ");
972 const bool saveAsMeshes = BZDB.isTrue("saveAsMeshes");
973
974 // print the obstacles
975 for (int type = 0; type < ObstacleTypeCount; type++)
976 {
977 const ObstacleList& list = getList(type);
978 for (unsigned int i = 0; i < list.size(); i++)
979 {
980 const Obstacle* obs = list[i];
981
982 if (!saveAsMeshes)
983 {
984 if (!obs->isFromContainer())
985 obs->print(out, indent);
986 }
987 else
988 {
989 if (!isContainer(type))
990 {
991 if (!saveAsOBJ)
992 obs->print(out, indent);
993 else
994 obs->printOBJ(out, indent);
995 }
996 }
997 }
998 }
999
1000 return;
1001 }
1002
1003
clearDepthName()1004 void GroupDefinition::clearDepthName()
1005 {
1006 depthName = "";
1007 return;
1008 }
1009
1010
1011 //////////////////////////////////////////////////////////////////////////////
1012 //
1013 // Group Definition Manager
1014 // - utility class to keep track of group definitions
1015 //
1016
1017 GroupDefinitionMgr OBSTACLEMGR;
1018
1019
GroupDefinitionMgr()1020 GroupDefinitionMgr::GroupDefinitionMgr() : world("")
1021 {
1022 return;
1023 }
1024
1025
~GroupDefinitionMgr()1026 GroupDefinitionMgr::~GroupDefinitionMgr()
1027 {
1028 clear();
1029 return;
1030 }
1031
1032
clear()1033 void GroupDefinitionMgr::clear()
1034 {
1035 world.clear();
1036 for (unsigned int i = 0; i < list.size(); i++)
1037 {
1038 list[i]->clear();
1039 delete list[i];
1040 }
1041 list.clear();
1042 return;
1043 }
1044
1045
tighten()1046 void GroupDefinitionMgr::tighten()
1047 {
1048 for (unsigned int i = 0; i < list.size(); i++)
1049 list[i]->tighten();
1050 world.tighten();
1051 return;
1052 }
1053
1054
compareHeights(const void * a,const void * b)1055 static int compareHeights(const void* a, const void* b)
1056 {
1057 const Obstacle* obsA = *((const Obstacle* const *)a);
1058 const Obstacle* obsB = *((const Obstacle* const *)b);
1059 const Extents& eA = obsA->getExtents();
1060 const Extents& eB = obsB->getExtents();
1061
1062 if (eA.maxs[2] > eB.maxs[2])
1063 return -1;
1064 else
1065 return +1;
1066 }
1067
1068
makeWorld()1069 void GroupDefinitionMgr::makeWorld()
1070 {
1071 GroupDefinition::clearDepthName();
1072
1073 MeshTransform noXform;
1074 ObstacleModifier noMods;
1075
1076 world.makeGroups(noXform, noMods);
1077
1078 world.deleteInvalidObstacles();
1079
1080 // sort from top to bottom for enhanced radar
1081 for (int type = 0; type < GroupDefinition::ObstacleTypeCount; type++)
1082 world.sort(compareHeights);
1083
1084 tighten();
1085
1086 return;
1087 }
1088
1089
replaceBasesWithBoxes()1090 void GroupDefinitionMgr::replaceBasesWithBoxes()
1091 {
1092 world.replaceBasesWithBoxes();
1093 }
1094
1095
addWorldObstacle(Obstacle * obstacle)1096 void GroupDefinitionMgr::addWorldObstacle(Obstacle* obstacle)
1097 {
1098 world.addObstacle(obstacle);
1099 return;
1100 }
1101
1102
addGroupDef(GroupDefinition * groupdef)1103 void GroupDefinitionMgr::addGroupDef(GroupDefinition* groupdef)
1104 {
1105 if (groupdef->getName().size() > 0)
1106 list.push_back(groupdef);
1107 else
1108 delete groupdef;
1109 return;
1110 }
1111
1112
findGroupDef(const std::string & name) const1113 GroupDefinition* GroupDefinitionMgr::findGroupDef(const std::string& name) const
1114 {
1115 if (name.size() <= 0)
1116 return NULL;
1117 for (unsigned int i = 0; i < list.size(); i++)
1118 {
1119 if (name == list[i]->getName())
1120 return list[i];
1121 }
1122 return NULL;
1123 }
1124
1125
getSourceMeshes(std::vector<MeshObstacle * > & meshes) const1126 void GroupDefinitionMgr::getSourceMeshes(std::vector<MeshObstacle*>& meshes) const
1127 {
1128 meshes.clear();
1129 world.getSourceMeshes(meshes);
1130 return;
1131 }
1132
1133
pack(void * buf) const1134 void* GroupDefinitionMgr::pack(void* buf) const
1135 {
1136 buf = world.pack(buf);
1137 buf = nboPackUInt(buf, list.size());
1138 for (unsigned int i = 0; i < list.size(); i++)
1139 buf = list[i]->pack(buf);
1140 return buf;
1141 }
1142
1143
unpack(const void * buf)1144 const void* GroupDefinitionMgr::unpack(const void* buf)
1145 {
1146 buf = world.unpack(buf);
1147 uint32_t i, count;
1148 buf = nboUnpackUInt(buf, count);
1149 for (i = 0; i < count; i++)
1150 {
1151 GroupDefinition* groupdef = new GroupDefinition("");
1152 buf = groupdef->unpack(buf);
1153 addGroupDef(groupdef);
1154 }
1155 return buf;
1156 }
1157
1158
packSize() const1159 int GroupDefinitionMgr::packSize() const
1160 {
1161 int fullSize = 0;
1162
1163 fullSize += world.packSize();
1164 fullSize += sizeof(uint32_t);
1165 for (unsigned int i = 0; i < list.size(); i++)
1166 fullSize += list[i]->packSize();
1167 return fullSize;
1168 }
1169
1170
print(std::ostream & out,const std::string & indent) const1171 void GroupDefinitionMgr::print(std::ostream& out,
1172 const std::string& indent) const
1173 {
1174 const bool saveAsOBJ = BZDB.isTrue("saveAsOBJ");
1175 const bool saveFlatFile = BZDB.isTrue("saveFlatFile");
1176 const bool saveAsMeshes = BZDB.isTrue("saveAsMeshes");
1177 if (saveAsOBJ)
1178 {
1179 BZDB.set("saveAsMeshes", "1");
1180 BZDB.set("saveFlatFile", "1");
1181 }
1182
1183 // for unique OBJ mesh ids
1184 Obstacle::resetObjCounter();
1185
1186 if (!(saveFlatFile || saveAsOBJ))
1187 {
1188 // print the group definitions
1189 for (unsigned int i = 0; i < list.size(); i++)
1190 list[i]->printGrouped(out, indent);
1191 // print the world
1192 world.printGrouped(out, indent);
1193 }
1194 else
1195 {
1196 // print the world
1197 world.printFlatFile(out, indent);
1198 }
1199
1200 if (saveAsOBJ)
1201 {
1202 BZDB.set("saveAsMeshes", saveAsMeshes ? "1" : "0");
1203 BZDB.set("saveFlatFile", saveFlatFile ? "1" : "0");
1204 }
1205
1206 return;
1207 }
1208
1209
1210 // Local Variables: ***
1211 // mode: C++ ***
1212 // tab-width: 4 ***
1213 // c-basic-offset: 4 ***
1214 // indent-tabs-mode: nil ***
1215 // End: ***
1216 // ex: shiftwidth=4 tabstop=4
1217