Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / server / src / ai_data_service / pacs_scan.cpp
blobe34e94bd87ff247d0ab5046f50227e3ca858b938
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2015 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 // Nel misc
21 #include "nel/misc/command.h"
22 #include "nel/misc/variable.h"
24 #include "nel/misc/common.h"
25 #include "nel/misc/aabbox.h"
26 #include "nel/misc/vector.h"
27 #include "nel/misc/vectord.h"
28 #include "nel/misc/i_xml.h"
29 #include "nel/misc/array_2d.h"
30 // TMP TMP
31 #include "nel/misc/bitmap.h"
34 #include "nel/misc/algo.h"
37 // Nel pacs
38 #include "nel/pacs/u_collision_desc.h"
39 #include "nel/pacs/u_global_position.h"
40 #include "nel/pacs/u_global_retriever.h"
41 #include "nel/pacs/u_move_container.h"
42 #include "nel/pacs/u_move_primitive.h"
43 #include "nel/pacs/u_retriever_bank.h"
44 #include "nel/pacs/u_primitive_block.h"
46 #include "nel/pacs/global_retriever.h"
49 // Nel Ligo
50 #include "nel/ligo/ligo_config.h"
51 #include "nel/ligo/primitive.h"
54 // Server share
55 #include "game_share/bmp4image.h"
56 #include "server_share/continent_container.h"
59 // AI share
60 #include "ai_share/world_map.h"
61 #include "ai_share/ai_spawn_commands.h"
64 // STL
65 #include <vector>
66 #include <map>
69 using namespace std;
70 using namespace NLMISC;
71 using namespace NLPACS;
72 using namespace RYAI_MAP_CRUNCH;
73 using namespace NLLIGO;
75 extern CLigoConfig LigoConfig;
77 //CAISpawnCtrl *CAISpawnCtrl::_instance=NULL;
79 string EvaluatedPos;
81 /// The start point for each continent
82 multimap<string, CVectorD> StartPoints;
83 multimap<string, string> PrimFiles;
84 CVectorD DefaultStartPoint = CVectorD::Null;
86 /// The output path
87 string OutputPath = string("./");
88 vector<string> PacsPrimPath;
89 vector<string> LookupPath;
90 vector<string> LookupNoRecursePath;
91 bool PathInitialized = false;
93 CWorldMap StaticWorldMap;
94 uint Verbose = 1;
95 CVectorD BoxMin, BoxMax;
98 namespace RYPACSCRUNCH
101 class CPacsCruncher
103 public:
105 CContinentContainer _Continents;
107 URetrieverBank *_Bank;
108 UGlobalRetriever *_Retriever;
109 UMoveContainer *_Container;
110 UMovePrimitive *_Primitive;
111 UMovePrimitive *_Primitive3;
112 UMovePrimitive *_Primitive5;
114 CWorldMap _WorldMap;
116 deque<UGlobalPosition> _Positions1;
117 deque<UGlobalPosition> _Positions3;
118 deque<UGlobalPosition> _Positions5;
120 CVectorD _BMin;
121 CVectorD _BMax;
122 CVectorD _BSize;
124 uint32 _RetrieverWidth;
125 uint32 _RetrieverHeight;
126 uint32 _RetrieverArea;
128 typedef std::map<std::string, NLPACS::UPrimitiveBlock*> TPacsPrimMap;
129 static TPacsPrimMap _PacsPrimMap;
131 protected:
133 CSlot getSurfaceAfterMove(UGlobalPosition &pos, const CMapPosition &newPosition, uint maxGabarit)
135 CVectorD target = newPosition.toVectorD()+CVectorD(0.1, 0.1, 0.0);
136 CVectorD motion = target - _Retriever->getDoubleGlobalPosition(pos);
138 motion.z = 0.0;
140 UMovePrimitive *prims[3] = { _Primitive, _Primitive3, _Primitive5 };
141 sint gabarit;
142 CSlot slot;
144 for (gabarit=maxGabarit; gabarit>=0; --gabarit)
146 UMovePrimitive *prim = prims[gabarit];
148 prim->setGlobalPosition(pos, 0);
149 prim->move(motion, 0);
150 //_Container->evalNCPrimitiveCollision(1.0, prim, 0);
151 _Container->evalCollision(1.0, 0);
153 UGlobalPosition newPos;
154 prim->getGlobalPosition(newPos, 0);
156 // DEBUG HERE
158 CVectorD dpos = _Retriever->getDoubleGlobalPosition(pos);
159 CVectorD dnpos = _Retriever->getDoubleGlobalPosition(newPos);
161 //bool test = (static_cast<NLPACS::CGlobalRetriever*>(_Retriever))->testPosition(newPos);
162 bool test=true;
164 NLPACS::CGlobalRetriever* gRetriever = static_cast<NLPACS::CGlobalRetriever*>(_Retriever);
166 if (newPos.InstanceId < 0 || newPos.InstanceId >= (sint)gRetriever->getInstances().size())
167 test=false;
169 const CRetrieverInstance & instance = gRetriever->getInstances()[newPos.InstanceId];
171 if (!instance.getBBox().include(newPos.LocalPosition.Estimation + instance.getOrigin()))
172 test=false;
173 else
175 const CLocalRetriever & lRetriever = gRetriever->getRetriever(instance.getRetrieverId());
177 if (!lRetriever.isLoaded())
178 test=false;
179 else if (newPos.LocalPosition.Surface < 0 || newPos.LocalPosition.Surface >= (sint)lRetriever.getSurfaces().size())
181 nlwarning("can't test inexistant surface %d", newPos.LocalPosition.Surface);
182 test=false;
184 else if (fabs(newPos.LocalPosition.Estimation.x) >= 256.0 || fabs(newPos.LocalPosition.Estimation.y) >= 256.0)
185 test=false;
188 if (!test)
190 if (Verbose)
191 nlinfo("Move from pos(%d,%d,%f,%f/%f,%f) motion(%f,%f) -> pos(%d,%d,%f,%f/%f,%f) %s", pos.InstanceId, pos.LocalPosition.Surface, pos.LocalPosition.Estimation.x, pos.LocalPosition.Estimation.y, dpos.x, dpos.y, motion.x, motion.y, newPos.InstanceId, newPos.LocalPosition.Surface, newPos.LocalPosition.Estimation.x, newPos.LocalPosition.Estimation.y, dnpos.x, dnpos.y, test ? "succeded" : "failed");
192 return slot;
197 CVectorD dmotion = dpos+motion-dnpos;
198 dmotion.z = 0.0;
200 // if the move was not accomplished successfully return '3' as "direction blocked"
201 if ( dmotion.norm() > 1.0e-2 )
202 continue;
204 CMapPosition checkPosition(_Retriever->getDoubleGlobalPosition(newPos));
205 nlassert(newPosition == checkPosition);
207 CUnitSlot surfId(newPos);
208 TCellUnit &slots = _WorldMap.getCellUnit(newPosition);
210 // locate a slot to stick the surface in
211 bool newSlot = false;
212 for (slot=CSlot(0); slot.isValid(); ++slot)
214 CUnitSlot& unitSlot=slots[slot.slot()];
215 if (!unitSlot.used())
217 unitSlot = surfId;
218 unitSlot.setHeight((uint)floor(dnpos.z/2.0 + 0.5));
219 unitSlot.setInterior(_Retriever->isInterior(newPos));
220 float waterHeight;
221 unitSlot.setWater(_Retriever->isWaterPosition(newPos, waterHeight));
222 unitSlot.setGabarit(gabarit);
223 if (gabarit==0) _Positions1.push_back(newPos);
224 else if (gabarit==1) _Positions3.push_back(newPos);
225 else _Positions5.push_back(newPos);
226 newSlot = true;
227 break;
229 else if (unitSlot.hasSameSurface(surfId))
231 break;
235 break;
237 return slot;
240 void readPrimitive(IPrimitive *primitive, const std::string &insertAt)
242 if (dynamic_cast<CPrimZone*>(primitive) != NULL)
244 CPrimZone *prim = static_cast<CPrimZone*>(primitive);
245 uint i;
246 for (i=0; i<prim->VPoints.size(); ++i)
248 StartPoints.insert(multimap<string, CVectorD>::value_type(insertAt, prim->VPoints[i]));
251 else if (dynamic_cast<CPrimPoint*>(primitive) != NULL)
253 CPrimPoint *prim = static_cast<CPrimPoint*>(primitive);
254 StartPoints.insert(multimap<string, CVectorD>::value_type(insertAt, prim->Point));
256 else if (dynamic_cast<CPrimPath*>(primitive) != NULL)
258 CPrimPath *prim = static_cast<CPrimPath*>(primitive);
259 uint i;
260 for (i=0; i<prim->VPoints.size(); ++i)
262 StartPoints.insert(multimap<string, CVectorD>::value_type(insertAt, prim->VPoints[i]));
266 // parse children
267 uint i;
268 for (i=0; i<primitive->getNumChildren(); ++i)
270 IPrimitive *child;
272 if (!primitive->getChild(child, i))
273 continue;
275 readPrimitive(child, insertAt);
280 void readStartupPrims(const std::string &continent)
282 pair<multimap<string, string>::iterator, multimap<string, string>::iterator> rng;
283 rng = PrimFiles.equal_range(continent);
285 multimap<string, string>::iterator it;
286 for (it=rng.first; it!=rng.second; ++it)
288 string prim = (*it).second;
290 CIFile f(CPath::lookup(prim));
291 CIXml xml;
293 CPrimitives prims;
295 // load xml file
296 xml.init(f);
297 nlinfo("Loaded prim file '%s'", prim.c_str());
299 // read nodes
300 if (!prims.read(xml.getRootNode(), prim.c_str(), LigoConfig))
302 nlwarning("Can't use primitive file '%s', xml parse error", prim.c_str());
303 continue;
310 public:
312 CPacsCruncher() : _Bank(NULL), _Retriever(NULL), _Container(NULL)
316 void initPackedSheets()
318 if (!PathInitialized)
320 uint i;
321 for (i=0; i<PacsPrimPath.size(); ++i)
322 _Continents.initPacsPrim(PacsPrimPath[i]);
323 for (i=0; i<LookupPath.size(); ++i)
324 CPath::addSearchPath(LookupPath[i], true, false);
325 for (i=0; i<LookupNoRecursePath.size(); ++i)
326 CPath::addSearchPath(LookupNoRecursePath[i], false, false);
328 PathInitialized = true;
331 _Continents.init(0, 0, 32.0f, 2, "./", 32.0);
334 void init(const std::string &name)
336 initPackedSheets();
337 _Continents.loadContinent(name, name, 0, true);
339 _Bank = _Continents.getRetrieverBank(0);
340 _Retriever = _Continents.getRetriever(0);
341 _Container = _Continents.getMoveContainer(0);
344 void release()
346 _Continents.removeContinent(0);
347 _Container = NULL;
348 _Retriever = NULL;
349 _Bank = NULL;
352 string secToString(sint sec)
354 return toString(sec/60)+"m"+toString(sec%60)+"s";
358 void crunch(const std::string &name, const CAABBox *constraintBox = NULL, const string &outputsuffix = "", const CVector *startPoint=NULL)
360 // nlassert(false);
362 // setup pacs
363 bool keep = true;
364 if (_Bank == NULL && _Retriever == NULL && _Container == NULL)
366 init(name);
367 keep = false;
370 CAABBox rBox = _Retriever->getBBox();
371 nlinfo("%s rbox: %.1f,%.1f - %.1f,%.1f", name.c_str(), rBox.getMin().x, rBox.getMin().y, rBox.getMax().x, rBox.getMax().y);
373 // compute new box
374 CAABBox useBox;
375 if (constraintBox)
377 CVector vmin, vmax;
378 vmin.maxof(constraintBox->getMin(), rBox.getMin());
379 vmax.minof(constraintBox->getMax(), rBox.getMax());
380 useBox.setMinMax(vmin, vmax);
382 else
384 useBox = rBox;
387 useBox.setMinMax(CVector((float)floor(useBox.getMin().x), (float)floor(useBox.getMin().y), (float)floor(useBox.getMin().z)),
388 CVector((float)ceil(useBox.getMax().x), (float)ceil(useBox.getMax().y), (float)ceil(useBox.getMax().z)));
390 nlinfo("Use Box: (%.3f,%.3f)-(%.3f,%.3f)", useBox.getMin().x, useBox.getMin().y, useBox.getMax().x, useBox.getMax().y);
392 // setup the grid of surface ids per location
393 _RetrieverWidth = (uint32)(useBox.getSize().x+1.0);
394 _RetrieverHeight = (uint32)(useBox.getSize().y+1.0);
395 _RetrieverArea = _RetrieverWidth*_RetrieverHeight;
397 // clear the world map object
398 _WorldMap.clear();
400 // setup the UMovePrimitive
401 _Primitive = _Container->addCollisionablePrimitive(0, 1);
402 _Primitive->setPrimitiveType( UMovePrimitive::_2DOrientedCylinder );
403 _Primitive->setReactionType( UMovePrimitive::Stop );
404 _Primitive->setTriggerType((UMovePrimitive::TTrigger)UMovePrimitive::NotATrigger);
405 _Primitive->setCollisionMask( 0xffffffff );
406 _Primitive->setOcclusionMask( 0x00000000 );
407 _Primitive->setObstacle( true );
408 _Primitive->setAbsorbtion( 0 );
409 _Primitive->setHeight( 6.0f );
410 _Primitive->setRadius( 0.5f );
412 _Primitive3 = _Container->addCollisionablePrimitive(0, 1);
413 _Primitive3->setPrimitiveType( UMovePrimitive::_2DOrientedCylinder );
414 _Primitive3->setReactionType( UMovePrimitive::Stop );
415 _Primitive3->setTriggerType((UMovePrimitive::TTrigger)UMovePrimitive::NotATrigger);
416 _Primitive3->setCollisionMask( 0xffffffff );
417 _Primitive3->setOcclusionMask( 0x00000000 );
418 _Primitive3->setObstacle( true );
419 _Primitive3->setAbsorbtion( 0 );
420 _Primitive3->setHeight( 6.0f );
421 _Primitive3->setRadius( 1.5f );
423 _Primitive5 = _Container->addCollisionablePrimitive(0, 1);
424 _Primitive5->setPrimitiveType( UMovePrimitive::_2DOrientedCylinder );
425 _Primitive5->setReactionType( UMovePrimitive::Stop );
426 _Primitive5->setTriggerType((UMovePrimitive::TTrigger)UMovePrimitive::NotATrigger);
427 _Primitive5->setCollisionMask( 0xffffffff );
428 _Primitive5->setOcclusionMask( 0x00000000 );
429 _Primitive5->setObstacle( true );
430 _Primitive5->setAbsorbtion( 0 );
431 _Primitive5->setHeight( 6.0f );
432 _Primitive5->setRadius( 2.5f );
434 _BMin = useBox.getMin();
435 _BMax = useBox.getMax();
437 if (BoxMin != CVectorD::Null)
439 if (BoxMin.x > _BMin.x) _BMin.x = BoxMin.x;
440 if (BoxMin.x > _BMin.x) _BMin.x = BoxMin.x;
443 if (BoxMax != CVectorD::Null)
445 if (BoxMax.x < _BMax.x) _BMax.x = BoxMax.x;
446 if (BoxMax.x < _BMax.x) _BMax.x = BoxMax.x;
449 _BSize = _BMax-_BMin;
451 // setup a start position for the primitive
452 CVectorD zoneCentre = useBox.getCenter();
453 zoneCentre.z = 0.0;
455 vector<CVectorD> startPoints;
456 pair<multimap<string, CVectorD>::iterator, multimap<string, CVectorD>::iterator> range = StartPoints.equal_range(name);
457 multimap<string, CVectorD>::iterator itsp;
458 for (itsp=range.first; itsp!=range.second; ++itsp)
459 startPoints.push_back((*itsp).second);
461 if (startPoint != NULL)
463 startPoints.push_back(*startPoint);
464 startPoints.back().z = 0.0;
467 if (DefaultStartPoint != CVectorD::Null)
469 startPoints.push_back(DefaultStartPoint);
470 startPoints.back().z = 0.0;
473 if (startPoints.empty())
475 startPoints.push_back(zoneCentre);
479 // init time counter
480 CGlobalRetriever *cgr = (CGlobalRetriever*)_Retriever;
482 uint sz = 0;
483 uint ic;
484 for (ic = 0; ic<cgr->getInstances().size(); ++ic)
486 const CRetrieverInstance &inst = cgr->getInstance(ic);
487 sz += (uint)(inst.getBBox().getHalfSize().x*inst.getBBox().getHalfSize().y*0.6f)*4;
490 nlinfo("Estimated %d iterations", sz);
491 uint count=0;
493 while (!startPoints.empty())
495 zoneCentre = startPoints.back();
496 startPoints.pop_back();
498 CMapPosition firstIndex = CMapPosition(zoneCentre);
499 zoneCentre = firstIndex.toVectorD();
501 nlinfo("Start scan at %.1f,%.1f", zoneCentre.x, zoneCentre.y);
503 _Positions5.clear();
504 _Positions3.clear();
505 _Positions1.clear();
507 _Primitive->setGlobalPosition(zoneCentre, 0);
508 _Container->evalCollision(1.0, 0);
509 _Primitive3->setGlobalPosition(zoneCentre, 0);
510 _Container->evalCollision(1.0, 0);
511 _Primitive5->setGlobalPosition(zoneCentre, 0);
512 _Container->evalCollision(1.0, 0);
514 // setup and intialise the positions to visit stack
515 _Positions5.push_back(UGlobalPosition());
516 _Primitive->getGlobalPosition(_Positions5[0], 0);
519 TCellUnit &slots = _WorldMap.getCellUnit(firstIndex);
520 CUnitSlot surfId(_Positions5[0]);
522 // locate a slot to stick the surface in
523 bool newSlot = true;
524 CSlot slot;
525 for (slot=CSlot(0); slot.isValid(); ++slot)
527 CUnitSlot& unitSlot=slots[slot.slot()];
529 if (unitSlot.hasSameSurface(surfId))
531 newSlot = false;
532 break;
536 if (!newSlot)
537 continue;
539 CWorldPosition worldPosition(_WorldMap.getWorldPositionGeneration(firstIndex,CSlot(0)));
540 _WorldMap.getUnitSlot(worldPosition) = CUnitSlot(_Positions5[0]);
541 _WorldMap.getUnitSlot(worldPosition).setGabarit(2);
544 uint xmaxreached = 0,
545 xminreached = 0,
546 ymaxreached = 0,
547 yminreached = 0;
549 TTime startTime = CTime::getLocalTime();
551 uint countGabarits[3] = { 0, 0, 0 };
553 while (!_Positions5.empty() || !_Positions3.empty() || !_Positions1.empty())
555 // pop the next postion to test off the stack
556 UGlobalPosition refPos;
558 if (!_Positions5.empty())
560 refPos = _Positions5.front();
561 _Positions5.pop_front();
563 else if (!_Positions3.empty())
565 refPos = _Positions3.front();
566 _Positions3.pop_front();
568 else
570 refPos = _Positions1.front();
571 _Positions1.pop_front();
574 if (!(count&0xfff))
576 TTime itime = CTime::getLocalTime();
578 UGlobalPosition nextPos = refPos;
579 CVectorD dpos = _Retriever->getDoubleGlobalPosition(nextPos);
581 double persec = (double)count*1000.0 / (double)(itime-startTime);
582 sint toGo = sz-count;
583 double ttoGo = (double)toGo/persec;
584 sint elapsed = (sint)((itime-startTime)/1000);
586 nlinfo("crunchPacsMap: %d iterations (%d,%d,%d) (%dpct, estimated %s, %s to go) - start at (%d,%d,%f,%f-%f,%f)", count, countGabarits[0], countGabarits[1], countGabarits[2], count*100/sz, secToString(elapsed+(sint)ttoGo).c_str(), secToString((sint)ttoGo).c_str(), nextPos.InstanceId, nextPos.LocalPosition.Surface, nextPos.LocalPosition.Estimation.x, nextPos.LocalPosition.Estimation.y, dpos.x, dpos.y);
588 ++count;
590 if (!(count&0xffff) && count>0)
592 //buildBMP("temp_"+name+toString(count));
595 CVectorD pos = _Retriever->getDoubleGlobalPosition(refPos);
596 // EvaluatedPos = toString(refPos.InstanceId)+","+toString(refPos.LocalPosition.Surface)+":"+toString(pos.x)+","+toString(pos.y)+","+toString(pos.z);
598 CVectorD d = pos - CVectorD(1045.0, -6086.0, 0.0);
599 d.z = 0.0f;
600 if (d.norm() < 0.5f)
601 nlinfo("Bla");
603 CMapPosition refIndex(pos);
605 TCellUnit &slots = _WorldMap.getCellUnit(refIndex);
606 uint slot;
608 CUnitSlot refSlot(refPos);
610 for (slot=0; slot<3 && !slots[slot].hasSameSurface(refSlot); ++slot)
613 if (slot >= 3)
615 nlwarning("Failed to find point in surface slots");
616 continue;
619 uint gabarit = slots[slot].gabarit();
621 nlassert(gabarit <= 2);
622 ++countGabarits[gabarit];
625 // check out eastern cell and OR east move into neighbour grid
626 if (pos.x + 1.0 <= _BMax.x)
627 slots[slot].cellLink().setESlot(getSurfaceAfterMove(refPos, refIndex.getStepE(), gabarit));
628 else
629 ++xmaxreached;
631 // check out westtern cell and OR west move into neighbour grid
632 if (pos.x - 1.0 >= _BMin.x)
633 slots[slot].cellLink().setWSlot(getSurfaceAfterMove(refPos, refIndex.getStepW(), gabarit));
634 else
635 ++xminreached;
637 // check out southern cell and OR south move into neighbour grid
638 if (pos.y + 1.0 <= _BMax.y)
639 slots[slot].cellLink().setNSlot(getSurfaceAfterMove(refPos, refIndex.getStepN(), gabarit));
640 else
641 ++ymaxreached;
643 // check out northern cell and OR north move into neighbour grid
644 if (pos.y - 1.0 >= _BMin.y)
645 slots[slot].cellLink().setSSlot(getSurfaceAfterMove(refPos, refIndex.getStepS(), gabarit));
646 else
647 ++yminreached;
649 nlinfo("crunchPacsMap: performed %d iterations",count);
653 if (count > 1)
655 //filter();
656 //checkMap(_WorldMap, true);
658 COFile f(OutputPath+name+".wmap");
660 f.serial(_WorldMap);
663 // HOUSEKEEPING
664 _Container->removePrimitive(_Primitive);
665 _Container->removePrimitive(_Primitive3);
666 _Container->removePrimitive(_Primitive5);
668 if (!keep)
670 release();
673 _WorldMap.clear();
676 void buildGabarit(const string &name, uint gabarit)
678 nlinfo("building gabarit %d map...", gabarit);
680 _WorldMap.clear();
681 CIFile f(OutputPath+name+".wmap");
682 f.serial(_WorldMap);
684 checkMap(_WorldMap);
685 filter();
686 checkMap(_WorldMap, true);
688 CMapPosition min, max;
689 _WorldMap.getBounds(min, max);
691 CMapPosition scan, scanline;
693 for (scan = min; scan.y() != max.y(); scan = scan.stepCell(0, 1))
695 for (scanline = scan; scanline.x() != max.x(); scanline = scanline.stepCell(1, 0))
697 //scanline = CMapPosition(0x0380, 0x2650);
699 if (!_WorldMap.exist(scanline))
700 continue;
702 const CComputeCell *cc = const_cast<const CWorldMap&>(_WorldMap).getComputeCellCst(scanline);
704 uint slot, i, j;
706 for (i=0; i<16; ++i)
708 for (j=0; j<16; ++j)
710 CMapPosition pos=scanline;
711 pos.setUnitId(j,i);
713 TCellUnit &slots = _WorldMap.getCellUnit(pos);
715 for (slot=0; slot<3; ++slot)
717 CUnitSlot &unitSlot=slots[slot];
719 // if slot is used but not accessible for my gabarit, reset it
720 if (unitSlot.getCellLink().used() && unitSlot.gabarit()<gabarit)
722 CSlot currentSlot=unitSlot.getCellLink().ESlot();
723 if (currentSlot.isValid())
724 _WorldMap.getUnitSlot(_WorldMap.getWorldPosition(pos.getStepE(), currentSlot)).cellLink().setWSlot(CSlot());
726 currentSlot=unitSlot.getCellLink().WSlot();
727 if (currentSlot.isValid())
728 _WorldMap.getUnitSlot(_WorldMap.getWorldPosition(pos.getStepW(), currentSlot)).cellLink().setESlot(CSlot());
730 currentSlot=unitSlot.getCellLink().NSlot();
731 if (currentSlot.isValid())
732 _WorldMap.getUnitSlot(_WorldMap.getWorldPosition(pos.getStepN(), currentSlot)).cellLink().setSSlot(CSlot());
734 currentSlot=unitSlot.getCellLink().SSlot();
735 if (currentSlot.isValid())
736 _WorldMap.getUnitSlot(_WorldMap.getWorldPosition(pos.getStepS(), currentSlot)).cellLink().setNSlot(CSlot());
738 unitSlot.reset();
746 checkMap(_WorldMap);
748 COFile of(OutputPath+name+"_"+toString(gabarit)+".wmap");
749 of.serial(_WorldMap);
752 void buildCrunchedMap(const string &name)
754 nlinfo("building crunched map...");
756 _WorldMap.clear();
757 CIFile f(OutputPath+name+".wmap");
758 f.serial(_WorldMap);
760 checkMap(_WorldMap);
762 buildTopologies();
763 checkMap(_WorldMap);
765 nlinfo("Build map...");
767 CMapPosition min, max;
768 _WorldMap.getBounds(min, max);
770 CMapPosition scan, scanline;
772 for (scan = min; scan.y() != max.y(); scan = scan.stepCell(0, 1))
774 for (scanline = scan; scanline.x() != max.x(); scanline = scanline.stepCell(1, 0))
776 //scanline = CMapPosition(0x1731, 0xe2f8);
778 const CComputeCell *cell = const_cast<const CWorldMap&>(_WorldMap).getComputeCellCst(scanline);
780 CRootCell *newCell = NULL;
782 if (cell == NULL)
783 continue;
785 CMapPosition pos;
787 uint i, j;
788 bool failed = false;
789 bool white = true;
790 for (i=0; i<16 && !failed; ++i)
792 // char buff[17];
793 for (j=0; j<16 && !failed; ++j)
795 bool sl0 = cell->isSlotUsed(pos, CSlot(0));
796 bool sl1 = cell->isSlotUsed(pos, CSlot(1));
797 bool sl2 = cell->isSlotUsed(pos, CSlot(2));
799 pos = scanline;
800 pos.setUnitId(j,i);
801 const TCellUnit &cunit = cell->getCellUnitCst(pos);
802 uint32 used = cell->maxUsedSlot(pos);
803 if (used>=1)
804 failed = true;
805 else if (used>0)
806 white = false;
808 if (white && cunit[0].getCellLink().getLinks() != 0)
809 white = false;
811 if (!failed && !white && cunit[0].getCellLink().used())
813 if ((!cunit[0].getCellLink().isNSlotValid() && _WorldMap.isSlotUsed(pos.getStepN(), CSlot(0))) ||
814 (!cunit[0].getCellLink().isSSlotValid() && _WorldMap.isSlotUsed(pos.getStepS(), CSlot(0))) ||
815 (!cunit[0].getCellLink().isESlotValid() && _WorldMap.isSlotUsed(pos.getStepE(), CSlot(0))) ||
816 (!cunit[0].getCellLink().isWSlotValid() && _WorldMap.isSlotUsed(pos.getStepW(), CSlot(0))))
817 failed = true;
820 if (sl0 && (cunit[0].interior() /*|| cunit[0].water()*/ || cunit[0].topology() != 0))
821 white = false;
824 // buff[16] = '\0';
825 // nlinfo("Dump: %s", buff);
828 uint32 used;
830 pos = scanline.getStepS();
831 for (i=0; i<16 && !failed; ++i, pos = pos.getStepE())
832 if ((used = _WorldMap.maxUsedSlot(pos)) >= 1)
833 failed = true;
834 else if (used != 0)
835 white = false;
837 pos = scanline.getStepW();
838 for (i=0; i<16 && !failed; ++i, pos = pos.getStepN())
839 if ((used = _WorldMap.maxUsedSlot(pos)) >= 1)
840 failed = true;
841 else if (used != 0)
842 white = false;
844 pos = scanline.stepCell(0, 1);
845 for (i=0; i<16 && !failed; ++i, pos = pos.getStepE())
846 if ((used = _WorldMap.maxUsedSlot(pos)) >= 1)
847 failed = true;
848 else if (used != 0)
849 white = false;
851 pos = scanline.stepCell(1, 0);
852 for (i=0; i<16 && !failed; ++i, pos = pos.getStepN())
853 if ((used = _WorldMap.maxUsedSlot(pos)) >= 1)
854 failed = true;
855 else if (used != 0)
856 white = false;
858 if (!failed && white)
860 // replace the compute cell by a white cell
861 CWhiteCell *wcell = new CWhiteCell(_WorldMap);
862 wcell->setTopologiesNodes(cell->getTopologiesNodes());
864 // build height map
865 CFull16x16Layer *heightMap = new CFull16x16Layer();
866 for (i=0; i<16; ++i)
867 for (j=0; j<16; ++j)
868 heightMap->set(i, j, cell->getHeight(_WorldMap.getWorldPositionGeneration(CMapPosition(j, i),CSlot(0))));
870 wcell->setHeightMap(I16x16Layer::compress(heightMap, 0x7fffffff));
872 newCell = wcell;
874 // _WorldMap.setRootCell(scanline, wcell);
876 else if (!failed)
878 // replace the compute cell by a single layer cell
879 CSingleLayerCell *slcell = new CSingleLayerCell(_WorldMap);
881 uint maxtopo = 0;
883 for (i=0; i<16; ++i)
885 for (j=0; j<16; ++j)
887 pos = scanline;
888 pos.setUnitId(j,i);
890 sint maxs = cell->maxUsedSlot(pos);
891 nlassert(maxs == 0 || maxs == -1);
892 slcell->setPos(pos, cell->isSlotUsed(pos, CSlot(0)));
894 uint topology=cell->getTopology(_WorldMap.getWorldPositionGeneration(pos,CSlot(0)));
895 if (topology>maxtopo)
896 maxtopo=topology;
901 if (maxtopo == 0)
903 slcell->setTopologies(NULL);
905 else if (maxtopo == 1)
907 C1Bit16x16Layer *layer = new C1Bit16x16Layer();
909 for (i=0; i<16; ++i)
911 for (j=0; j<16; ++j)
913 pos = scanline;
914 pos.setUnitId(j,i);
916 layer->set(i, j, cell->getTopology(_WorldMap.getWorldPositionGeneration(pos,CSlot(0))));
920 slcell->setTopologies(layer);
922 else
924 C8Bits16x16Layer *layer = new C8Bits16x16Layer();
926 for (i=0; i<16; ++i)
928 for (j=0; j<16; ++j)
930 pos = scanline;
931 pos.setUnitId(j,i);
933 layer->set(i, j, cell->getTopology(_WorldMap.getWorldPositionGeneration(pos,CSlot(0))));
937 slcell->setTopologies(layer);
940 pos = scanline.getStepS();
941 for (i=0; i<16; ++i, pos = pos.getStepE())
943 sint maxs = cell->maxUsedSlot(pos);
944 nlassert(maxs == 0 || maxs == -1);
945 slcell->setSLink(i, _WorldMap.maxUsedSlot(pos) == 0);
948 pos = scanline.getStepW();
949 for (i=0; i<16 && !failed; ++i, pos = pos.getStepN())
951 sint maxs = cell->maxUsedSlot(pos);
952 nlassert(maxs == 0 || maxs == -1);
953 slcell->setWLink(i, _WorldMap.maxUsedSlot(pos) == 0);
956 pos = scanline.stepCell(0, 1);
957 for (i=0; i<16 && !failed; ++i, pos = pos.getStepE())
959 sint maxs = cell->maxUsedSlot(pos);
960 nlassert(maxs == 0 || maxs == -1);
961 slcell->setNLink(i, _WorldMap.maxUsedSlot(pos) == 0);
964 pos = scanline.stepCell(1, 0);
965 for (i=0; i<16 && !failed; ++i, pos = pos.getStepN())
967 sint maxs = cell->maxUsedSlot(pos);
968 nlassert(maxs == 0 || maxs == -1);
969 slcell->setELink(i, _WorldMap.maxUsedSlot(pos) == 0);
972 slcell->setTopologiesNodes(cell->getTopologiesNodes());
974 // build height map
975 CFull16x16Layer *heightMap = new CFull16x16Layer();
976 for (i=0; i<16; ++i)
977 for (j=0; j<16; ++j)
978 heightMap->set(i, j, slcell->isSlotUsed(CMapPosition(j, i), CSlot(0)) ? cell->getHeight(_WorldMap.getWorldPositionGeneration(CMapPosition(j,i),CSlot(0))) :
979 0x7fffffff);
981 slcell->setHeightMap(I16x16Layer::compress(heightMap, 0x7fffffff));
983 newCell = slcell;
985 // _WorldMap.setRootCell(scanline, slcell);
987 else
989 // build multi layer
991 CMultiLayerCell *mlcell = new CMultiLayerCell(_WorldMap);
993 uint32 slot;
995 for (i=0; i<16; ++i)
997 for (j=0; j<16; ++j)
999 pos = scanline;
1000 pos.setUnitId(j,i);
1002 for (slot=0; slot<3; ++slot)
1004 CWorldPosition wp = _WorldMap.getWorldPositionGeneration(pos,CSlot(slot));
1005 const CUnitSlot &uslot = cell->getUnitSlotCst(wp);
1006 if (uslot.getCellLink().used())
1008 mlcell->setLinks(wp, uslot.getCellLink());
1009 mlcell->setTopology(wp, uslot.topology());
1015 // build height map
1016 CFull16x16Layer *heightMap[3] = { NULL, NULL, NULL };
1017 for (i=0; i<16; ++i)
1019 for (j=0; j<16; ++j)
1021 for (slot=0; slot<3; ++slot)
1023 CFull16x16Layer* heightMapPt=heightMap[slot];
1025 if (mlcell->isSlotUsed(CMapPosition(j, i), CSlot(slot)))
1027 if (!heightMapPt)
1029 heightMapPt=new CFull16x16Layer();
1030 heightMap[slot]=heightMapPt;
1032 nlassert(heightMapPt);
1033 heightMapPt->set(i, j, cell->getHeight(_WorldMap.getWorldPositionGeneration(CMapPosition(j, i), CSlot(slot))));
1035 else
1037 if (heightMapPt)
1038 heightMapPt->set(i, j, 0x7fffffff);
1044 for (slot=0; slot<3; ++slot)
1045 if (heightMap[slot] != NULL)
1046 mlcell->setHeightMap(CSlot(slot), I16x16Layer::compress(heightMap[slot], 0x7fffffff));
1048 mlcell->setTopologiesNodes(cell->getTopologiesNodes());
1050 newCell = mlcell;
1053 nlassert(newCell != NULL);
1055 pos = scanline;
1056 uint32 slot;
1057 for (i=0; i<16; ++i)
1059 for (j=0; j<16; ++j)
1061 pos.setUnitId(j, i);
1063 for (slot=0; slot<3; ++slot)
1065 CWorldPosition wpos = _WorldMap.getWorldPositionGeneration(pos, CSlot(slot));
1066 bool sused = cell->isSlotUsed(pos, CSlot(slot)),
1067 nsused = newCell->isSlotUsed(pos, CSlot(slot));
1068 nlassert(sused == nsused);
1070 if (cell->isSlotUsed(pos, CSlot(slot)))
1072 CCellLinkage lnk=cell->getCellLink(wpos),
1073 nlnk=newCell->getCellLink(wpos);
1074 uint top=cell->getTopology(wpos),
1075 ntop=newCell->getTopology(wpos);
1076 if (failed || !white)
1077 nlassert(cell->getCellLink(wpos).getLinks() == newCell->getCellLink(wpos).getLinks());
1078 nlassert(cell->getHeight(wpos) == newCell->getHeight(wpos));
1079 nlassert(cell->getTopology(wpos) == newCell->getTopology(wpos));
1085 _WorldMap.setRootCell(scanline, newCell);
1089 checkMap(_WorldMap);
1091 buildMotionLayers();
1093 // nlassert(false);
1094 COFile out(OutputPath+name+".cwmap2");
1095 out.serial(_WorldMap);
1098 void checkMap(CWorldMap &wmap, bool fix=false)
1100 nlinfo("Checking Wmap link integrity...");
1102 CMapPosition min, max;
1103 _WorldMap.getBounds(min, max);
1105 CMapPosition posy;
1107 for (posy=min; posy.y()<max.y(); posy=posy.step(0, 1))
1109 CMapPosition posx;
1110 for (posx=posy; posx.x()<max.x(); posx=posx.step(1, 0))
1112 uint s;
1113 for (s=0; s<3; ++s)
1115 CWorldPosition wpos = wmap.getSafeWorldPosition(posx, CSlot(s));
1117 if (!wpos.isValid())
1118 continue;
1120 CWorldPosition test;
1123 if (wpos.getCellLinkage().isNSlotValid())
1125 CSlot slot = wpos.getCellLinkage().NSlot();
1126 test = wmap.getSafeWorldPosition(CMapPosition(wpos).getStepN(), slot);
1127 bool failed = true;
1128 if (!test.isValid())
1130 //nlwarning("Check: invalid N link at (%04X,%04X,%d)", wpos.x(), wpos.y(), s);
1132 else if (!test.getCellLinkage().isSSlotValid())
1134 //nlwarning("Check: N slot of (%04X,%04X,%d) has invalid S link", wpos.x(), wpos.y(), s);
1135 if (fix)
1137 wmap.getUnitSlot(test).cellLink().setSSlot(CSlot(s));
1138 failed = false;
1141 else if (test.getCellLinkage().SSlot().slot() != s)
1143 //nlwarning("Check: N slot of (%04X,%04X,%d) points to another slot at S", wpos.x(), wpos.y(), s);
1145 else
1147 failed = false;
1149 if (failed && fix)
1150 wmap.resetUnitSlotNLink(wpos);
1154 if (wpos.getCellLinkage().isSSlotValid())
1156 CSlot slot = wpos.getCellLinkage().SSlot();
1157 test = wmap.getSafeWorldPosition(CMapPosition(wpos).getStepS(), slot);
1158 bool failed = true;
1159 if (!test.isValid())
1161 //nlwarning("Check: invalid S link at (%04X,%04X,%d)", wpos.x(), wpos.y(), s);
1163 else if (!test.getCellLinkage().isNSlotValid())
1165 //nlwarning("Check: S slot of (%04X,%04X,%d) has invalid N link", wpos.x(), wpos.y(), s);
1166 if (fix)
1168 wmap.getUnitSlot(test).cellLink().setNSlot(CSlot(s));
1169 failed = false;
1172 else if (test.getCellLinkage().NSlot().slot() != s)
1174 //nlwarning("Check: S slot of (%04X,%04X,%d) points to another slot at N", wpos.x(), wpos.y(), s);
1176 else
1178 failed = false;
1180 if (failed && fix)
1181 wmap.resetUnitSlotSLink(wpos);
1185 if (wpos.getCellLinkage().isESlotValid())
1187 CSlot slot = wpos.getCellLinkage().ESlot();
1188 test = wmap.getSafeWorldPosition(CMapPosition(wpos).getStepE(), slot);
1189 bool failed = true;
1190 if (!test.isValid())
1192 //nlwarning("Check: invalid E link at (%04X,%04X,%d)", wpos.x(), wpos.y(), s);
1194 else if (!test.getCellLinkage().isWSlotValid())
1196 //nlwarning("Check: E slot of (%04X,%04X,%d) has invalid W link", wpos.x(), wpos.y(), s);
1197 if (fix)
1199 wmap.getUnitSlot(test).cellLink().setWSlot(CSlot(s));
1200 failed = false;
1203 else if (test.getCellLinkage().WSlot().slot() != s)
1205 //nlwarning("Check: E slot of (%04X,%04X,%d) points to another slot at W", wpos.x(), wpos.y(), s);
1207 else
1209 failed = false;
1211 if (failed && fix)
1212 wmap.resetUnitSlotELink(wpos);
1216 if (wpos.getCellLinkage().isWSlotValid())
1218 CSlot slot = wpos.getCellLinkage().WSlot();
1219 test = wmap.getSafeWorldPosition(CMapPosition(wpos).getStepW(), slot);
1220 bool failed = true;
1221 if (!test.isValid())
1223 //nlwarning("Check: invalid W link at (%04X,%04X,%d)", wpos.x(), wpos.y(), s);
1225 else if (!test.getCellLinkage().isESlotValid())
1227 //nlwarning("Check: W slot of (%04X,%04X,%d) has invalid E link", wpos.x(), wpos.y(), s);
1228 if (fix)
1230 wmap.getUnitSlot(test).cellLink().setESlot(CSlot(s));
1231 failed = false;
1234 else if (test.getCellLinkage().ESlot().slot() != s)
1236 //nlwarning("Check: W slot of (%04X,%04X,%d) points to another slot at E", wpos.x(), wpos.y(), s);
1238 else
1240 failed = false;
1242 if (failed && fix)
1243 wmap.resetUnitSlotWLink(wpos);
1251 void clearHeightMap(const string &name, uint gabarit)
1253 nlinfo("clearing height map for '%s'", (name+"_"+toString(gabarit)+".cwmap2").c_str());
1255 // nlassert(false);
1256 _WorldMap.clear();
1257 CIFile fi(OutputPath+name+"_"+toString(gabarit)+".cwmap2");
1258 fi.serial(_WorldMap);
1259 fi.close();
1261 _WorldMap.clearHeightMap();
1263 COFile fo(OutputPath+name+"_"+toString(gabarit)+".cwmap2");
1264 fo.serial(_WorldMap);
1265 fo.close();
1269 void filter()
1271 nlinfo("filtering...");
1273 CMapPosition min, max;
1274 _WorldMap.getBounds(min, max);
1276 CMapPosition scanpos = min;
1277 uint x, y;
1279 uint scanWidth = max.x()-min.x();
1280 uint scanHeight = max.y()-min.y();
1282 for (y=0; y<scanHeight; ++y)
1284 CMapPosition pos(scanpos);
1286 for (x=0; x<scanWidth; ++x)
1288 if (_WorldMap.exist(pos))
1290 TCellUnit &slots = _WorldMap.getCellUnit(pos);
1292 if (slots[0].used() && slots[1].used() && !slots[2].used() && abs(sint(slots[0].height())-sint(slots[1].height()))<2)
1294 CMapPosition np;
1295 if ((!_WorldMap.exist(np = pos.getStepS()) || _WorldMap.nbUsedSlots(np) <= 1) &&
1296 (!_WorldMap.exist(np = pos.getStepN()) || _WorldMap.nbUsedSlots(np) <= 1) &&
1297 (!_WorldMap.exist(np = pos.getStepE()) || _WorldMap.nbUsedSlots(np) <= 1) &&
1298 (!_WorldMap.exist(np = pos.getStepW()) || _WorldMap.nbUsedSlots(np) <= 1))
1300 slots[1].reset();
1301 _WorldMap.getUnitSlot(_WorldMap.getWorldPosition(pos.getStepW(),CSlot(0))).cellLink().setESlot(CSlot(0));
1302 _WorldMap.getUnitSlot(_WorldMap.getWorldPosition(pos.getStepE(),CSlot(0))).cellLink().setWSlot(CSlot(0));
1303 _WorldMap.getUnitSlot(_WorldMap.getWorldPosition(pos.getStepS(),CSlot(0))).cellLink().setNSlot(CSlot(0));
1304 _WorldMap.getUnitSlot(_WorldMap.getWorldPosition(pos.getStepN(),CSlot(0))).cellLink().setSSlot(CSlot(0));
1309 pos = pos.getStepE();
1311 scanpos = scanpos.getStepN();
1316 void buildTopologies()
1318 // nlassert(false);
1319 nlinfo("building topologies...");
1322 CMapPosition min, max;
1323 _WorldMap.getBounds(min, max);
1325 CMapPosition scan, scanline;
1327 uint maxtopo = 0;
1328 vector<uint> toposcount;
1330 struct CTopoGrid
1332 sint getTopo(const CSlot &slot) const
1334 return topos[slot.slot()];
1336 sint topos[3];
1337 bool testGrid;
1339 CTopoGrid toposGridList[16][16];
1341 for (scan = min; scan.y() != max.y(); scan = scan.stepCell(0, 1))
1343 for (scanline = scan; scanline.x() != max.x(); scanline = scanline.stepCell(1, 0))
1345 if (!_WorldMap.exist(scanline))
1346 continue;
1348 //scanline = CMapPosition(0x02e0, 0xd440);
1350 CComputeCell *cell = _WorldMap.getComputeCell(scanline);
1353 for (uint i = 0; i < 16; ++i)
1355 for (uint j = 0; j < 16; ++j)
1357 toposGridList[i][j].topos[0] =
1358 toposGridList[i][j].topos[1] =
1359 toposGridList[i][j].topos[2] = -1;
1364 uint i = 0; // current topo
1366 CMapPosition sp = scanline;
1367 sp.setUnitId(0,0);
1369 uint spx, spy, spslot;
1371 for (spy=0; spy<16; ++spy)
1373 for (spx=0; spx<16; ++spx)
1375 sp.setUnitId(spx, spy);
1377 for (spslot=0; spslot<3; ++spslot)
1379 if (!cell->isSlotUsed(sp, CSlot(spslot)))
1380 continue;
1382 CTopoGrid &topoGrid=toposGridList[sp.yCoord().getUnitId()][sp.xCoord().getUnitId()];
1383 sint &curTopos=topoGrid.topos[spslot];
1385 if (curTopos<0)
1388 { // -- clean flood fill table --
1389 uint gi, gj;
1390 for (gi=0; gi<16; ++gi)
1391 for (gj=0; gj<16; ++gj)
1392 toposGridList[gi][gj].testGrid=false;
1393 } // ----------------------------
1395 topoGrid.testGrid=true;
1396 curTopos=i;
1398 CUnitSlot &unitslot = _WorldMap.getUnitSlot(_WorldMap.getWorldPosition(sp,CSlot(spslot)));
1400 unitslot.setTopology(i);
1402 bool interior = unitslot.interior();
1403 bool water = unitslot.water();
1404 bool nogo = unitslot.nogo();
1406 CVector totalPos(0.0f, 0.0f, 0.0f);
1407 uint totalElm = 0;
1409 vector<CWorldPosition> stack;
1410 stack.push_back(_WorldMap.getWorldPosition(sp, CSlot(spslot)));
1412 bool topoHasNeighb = false;
1414 while (!stack.empty())
1416 CWorldPosition wp(stack.back());
1417 stack.pop_back();
1419 totalPos+=CVector(wp.toVectorD());
1420 ++totalElm;
1422 static const CDirection::TDirection dirs[] =
1424 CDirection::W,
1425 CDirection::E,
1426 CDirection::S,
1427 CDirection::N
1431 for (uint dir=0; dir<4; ++dir)
1433 const CDirection direction=CDirection(dirs[dir]);
1434 CWorldPosition tm(wp);
1435 uint x = tm.xCoord().getUnitId()+direction.dx();
1436 uint y = tm.yCoord().getUnitId()+direction.dy();
1438 //InfoLog->displayRaw("Test move from %4X,%4X,%d to %4X,%4X", tm.x(), tm.y(), tm.slot(), tm.x()+direction.dx(), tm.y()+direction.dy());
1440 // store if move succeded
1441 bool mvres = _WorldMap.move(tm, direction);
1444 bool test1 = false;
1445 bool test2 = false;
1446 bool test3 = false;
1447 bool test4 = false;
1448 bool test5 = false;
1449 bool test6 = false;
1450 bool test7 = false;
1452 // check move is on same cell, and position hasn't been visited (nor in same topo or in another)
1453 // and moves in same kind of floor
1454 if ( (test1 = ((x&0xf0)==0))
1455 && (test2 = ((y&0xf0)==0))
1456 && (test3 = (!toposGridList[y][x].testGrid))
1457 && (test4 = (mvres))
1458 && (test5 = (toposGridList[y][x].topos[tm.slot()]<0))
1459 && (test6 = (_WorldMap.getUnitSlot(tm).interior() == interior))
1460 && (test7 = (_WorldMap.getUnitSlot(tm).water() == water)))
1463 if ( ((x&0xf0)==0)
1464 && ((y&0xf0)==0)
1465 && (!toposGridList[y][x].testGrid)
1466 && (mvres)
1467 && (toposGridList[y][x].topos[tm.slot()]<0)
1468 && (_WorldMap.getUnitSlot(tm).interior() == interior)
1469 && (_WorldMap.getUnitSlot(tm).water() == water)
1470 && (_WorldMap.getUnitSlot(tm).nogo() == nogo) )
1472 toposGridList[y][x].testGrid=true;
1473 toposGridList[y][x].topos[tm.slot()] = i;
1474 _WorldMap.getUnitSlot(tm).setTopology(i);
1475 stack.push_back(tm);
1476 // fakes move result so if on same topo, doesn't add a neighbour
1477 mvres = false;
1479 //InfoLog->displayRawNL(" SUCCESS");
1481 else
1483 //InfoLog->displayRawNL(" FAILED (test1=%d test2=%d test3=%d test4=%d test5=%d test6=%d test7=%d)", test1, test2, test3, test4, test5, test6, test7);
1486 if (mvres)
1487 topoHasNeighb = true;
1491 if (topoHasNeighb)
1493 CTopology &topology = cell->getTopologyNode(i);
1494 topology.Id = CTopology::TTopologyId(scanline, i);
1495 topology.Position = totalPos/(float)totalElm;
1496 topology.Flags = (interior ? Interior : 0) | (water ? Water : 0) | (nogo ? NoGo : 0);
1498 //nlinfo("Topology %08X %04X", topology.Id.getVal(), topology.Flags);
1500 ++i;
1502 else
1504 nlinfo("Unactivated topo %d in cell (%4X,%4X)",i, scanline.x()&0xffff, scanline.y()&0xffff);
1505 uint i, j, s;
1506 for (i=0; i<16; ++i)
1508 for (j=0; j<16; ++j)
1510 for (s=0; s<3; ++s)
1512 if (toposGridList[i][j].topos[s] == (sint)i)
1514 CMapPosition errp = scanline;
1515 errp.setUnitId(j, i);
1516 _WorldMap.resetUnitSlot(_WorldMap.getWorldPosition(errp, CSlot(s)));
1517 toposGridList[i][j].topos[s] = 0xffff;
1528 if (i>50)
1529 nlstop;
1531 if (i>maxtopo)
1532 maxtopo = i;
1534 if (i >= toposcount.size())
1535 toposcount.resize(i+1);
1537 toposcount[i]++;
1541 nlinfo("Found %d topologies maximum", maxtopo);
1542 uint i;
1543 for (i=0; i<toposcount.size(); ++i)
1544 nlinfo("%d cells of %d topologies", toposcount[i], i);
1547 class CMotionTrace
1549 public:
1550 CMotionTrace() : dx(0), dy(0), distance(0xffffffff), flags(0)
1553 sint8 dx;
1554 sint8 dy;
1555 uint32 distance;
1556 uint8 flags;
1560 void buildMotionLayers()
1562 nlinfo("building motion layers...");
1564 CMapPosition min, max;
1565 _WorldMap.getBounds(min, max);
1567 CMapPosition scan, scanline;
1569 uint compute = 0, white = 0, simple = 0, multi = 0, other = 0;
1570 _WorldMap.countCells(compute, white, simple, multi, other);
1571 uint total = compute+white+simple+multi+other;
1573 uint compCells = 0;
1574 TTime startTime = CTime::getLocalTime();
1577 //min = CMapPosition(0x3a40, 0x8330);
1578 //max = CMapPosition(0x3a50, 0x8340);
1580 for (scan = min; scan.y() != max.y(); scan = scan.stepCell(0, 1))
1582 for (scanline = scan; scanline.x() != max.x(); scanline = scanline.stepCell(1, 0))
1584 if (CTime::getLocalTime() - startTime > 5000)
1586 startTime = CTime::getLocalTime();
1587 nlinfo("buildMotionLayers: %d pct done...", compCells*100/total);
1591 //scanline = CMapPosition(0x3A40, 0x8330);
1593 if (!_WorldMap.exist(scanline))
1594 continue;
1596 //if (scanline.x() == 4436 && scanline.y() == -4240)
1597 // nlstop;
1599 ++compCells;
1601 CRootCell *cell = _WorldMap.getRootCell(scanline);
1602 uint topo = 0;
1603 uint maxtopo = 0;
1604 const CMapPosition mincell = scanline.stepCell(-1, -1),
1605 maxcell = scanline.stepCell( 2, 2);
1607 while (true)
1609 CMotionTrace fillGrid[16*3][16*3][3];
1611 bool found = false;
1612 uint stx = 0, sty = 0;
1613 uint32 stsl=0;
1614 CMapPosition sp = scanline;
1615 const CMapPosition soffset = sp.stepCell(-1, -1);
1617 set<CTopology::TTopologyRef> visited;
1619 const CTopology::TTopologyId startTId(scanline, topo);
1621 for (sty=0; sty<16; ++sty)
1623 for (stx=0; stx<16; ++stx)
1625 sp.setUnitId(stx,sty);
1627 for (stsl=0; stsl<3; ++stsl)
1629 if (!cell->isSlotUsed(sp, CSlot(stsl)))
1630 continue;
1632 CWorldPosition stwp = _WorldMap.getWorldPosition(sp, CSlot(stsl));
1633 const uint topology=cell->getTopology(stwp);
1635 if (topology>maxtopo && topology<0x80)
1636 maxtopo=topology;
1638 // find a point in the current topo
1639 if (topology==topo && fillGrid[sty+16][stx+16][stsl].distance == 0xffffffff)
1641 // this point exists, is not marked in fill grid and belongs to the current topo
1642 found = true;
1645 // HERE: use multimap instead of vector so the position stack is always sorted, and thus
1646 // the flood fill should be minimal (Dijkstra like graph route)
1648 //vector<CWorldPosition> stack;
1649 multimap<sint, CWorldPosition> stacks[5];
1651 // mark start point
1652 CMotionTrace &first = fillGrid[sp.y()-soffset.y()][sp.x()-soffset.x()][stsl];
1653 first.dx = 0;
1654 first.dy = 0;
1655 first.distance = 0;
1656 const CTopology& topNode = stwp.getTopologyRef().getCstTopologyNode();
1657 first.flags = (topNode.isInWater() ? 1 : 0) + (topNode.isInNogo() ? 2 : 0);
1659 // push first position
1660 stacks[first.flags].insert(std::pair<sint, CWorldPosition>(first.flags, stwp));
1662 while (true)
1664 uint stack;
1665 for (stack=0; stack<5; ++stack)
1666 if (!stacks[stack].empty())
1667 break;
1668 if (stack == 5)
1669 break;
1671 CWorldPosition next((*(stacks[stack].begin())).second);
1672 stacks[stack].erase(stacks[stack].begin());
1674 const CTopology& nextNode = next.getTopologyRef().getCstTopologyNode();
1675 uint8 nextflags = (nextNode.isInWater() ? 1 : 0) + (nextNode.isInNogo() ? 2 : 0);
1677 CTopology::TTopologyRef nextTId(next);
1679 sint cdist = fillGrid[next.y()-soffset.y()][next.x()-soffset.x()][next.slot()].distance;
1681 if ( nextTId != startTId
1682 && cdist<=CDirection::MAX_COST) // check if it is a touching topology
1683 visited.insert(nextTId);
1685 uint dir;
1686 for (dir=0; dir<8; ++dir)
1688 CWorldPosition tmp(next);
1690 CDirection direction((CDirection::TDirection)dir);
1692 if (_WorldMap.moveSecure(tmp,direction))
1694 // don't move more than 1 cell
1695 if ( tmp.x() < mincell.x()
1696 || tmp.x() >= maxcell.x()
1697 || tmp.y() < mincell.y()
1698 || tmp.y() >= maxcell.y())
1699 continue;
1701 // check we can move back
1702 CDirection opp = direction;
1703 opp.addStep(CDirection::HALF_TURN);
1704 CWorldPosition checkBackMove(tmp);
1705 if (!_WorldMap.move(checkBackMove, opp))
1707 nlwarning("Can't move back from pos (%d,%d,%d) to pos (%d,%d,%d)",
1708 next.x(), next.y(), next.slot(),
1709 tmp.x(), tmp.y(), tmp.slot());
1710 continue;
1712 else if (checkBackMove != next)
1715 if (Verbose)
1716 nlwarning("Reverse move from pos (%d,%d,%d) to pos (%d,%d,%d) gave a different path",
1717 next.x(), next.y(), next.slot(),
1718 tmp.x(), tmp.y(), tmp.slot());
1719 continue;
1722 const CTopology& tmpNode = tmp.getTopologyRef().getCstTopologyNode();
1723 uint8 tmpflags = (tmpNode.isInWater() ? 1 : 0) + (tmpNode.isInNogo() ? 2 : 0);
1725 if (tmpNode.Id != nextNode.Id)
1726 nlinfo("tamere");
1728 if (tmpflags != 0)
1729 nlinfo("blabla");
1732 uint ndist = (_WorldMap.getTopology(tmp)==topo && tmp.hasSameFullCellId(sp) ) ? 0 : cdist+direction.getWeight();
1734 CMotionTrace& motionTrace = fillGrid[tmp.y()-soffset.y()][tmp.x()-soffset.x()][tmp.slot()];
1736 uint forbid = nextflags & (~tmpflags);
1737 if ((motionTrace.distance == 0xffffffff) ||
1738 (forbid == 0 && motionTrace.distance > ndist))
1740 /*nlinfo("stack=%d ndist=%d move from (%04X,%04X,%d - topo=%08X,flags=%d) to (%04X,%04X,%d - topo=%08X,flags=%d) - %d %d %d %d",
1741 stack, ndist,
1742 next.x(), next.y(), next.slot(), nextNode.Id.getVal(), nextflags,
1743 tmp.x(), tmp.y(), tmp.slot(), tmpNode.Id.getVal(), tmpflags,
1744 stacks[0].size(), stacks[1].size(), stacks[2].size(), stacks[3].size());*/
1746 motionTrace.distance = ndist;
1747 if (ndist == 0)
1749 motionTrace.dx =
1750 motionTrace.dy = 0;
1752 else
1754 motionTrace.dx=-direction.dx();
1755 motionTrace.dy=-direction.dy();
1757 if (tmp.getTopologyNode().Id == topNode.Id)
1759 stacks[0].insert(std::pair<sint, CWorldPosition>(ndist, tmp));
1761 else
1763 stacks[tmpflags + 1].insert(std::pair<sint, CWorldPosition>(ndist, tmp));
1774 if (found)
1776 // generate direction map for this topo
1777 CDirectionMap *dmap = new CDirectionMap();
1779 uint x, y, s;
1780 for (s=0; s<3; ++s)
1782 CDirectionLayer* directionLayer=dmap->Layers[s];
1784 for (y=0; y<16*3; ++y)
1786 // char output[256];
1787 for (x=0; x<16*3; ++x)
1789 // static const char ht[]= "0123456789ABCDEF";
1790 CMotionTrace &motionTrace=fillGrid[y][x][s];
1792 // output[x] = ht[motionTrace.distance&15];
1794 if (motionTrace.distance != 0xffffffff)
1796 // create CDirectionLayer if it do not exists
1797 if (!directionLayer)
1799 directionLayer = new CDirectionLayer();
1800 nlassert(directionLayer!=NULL);
1801 dmap->Layers[s] = directionLayer;
1804 CGridDirectionLayer* dirLayer=directionLayer->getGridLayer(y>>4,x>>4);
1806 // create CGridDirectionLayer if it do not exists
1807 if (!dirLayer)
1809 directionLayer->setGridLayer(y>>4,x>>4, new C4Bits16x16Layer());
1810 dirLayer=directionLayer->getGridLayer(y>>4,x>>4);
1811 nlassert(dirLayer);
1813 dirLayer->setDirection(y&15, x&15, (motionTrace.dx == 0 && motionTrace.dy == 0 ? CDirection(CDirection::UNDEFINED) : CDirection(motionTrace.dx,motionTrace.dy)));
1817 // output[x] = '\0';
1818 // nlinfo("%s", output);
1823 for (s=0; s<3; ++s)
1825 CDirectionLayer* directionLayer=dmap->Layers[s];
1827 if (!directionLayer)
1828 continue;
1830 for (y=0; y<3; ++y)
1832 for (x=0; x<3; ++x)
1834 CGridDirectionLayer *layer=directionLayer->getGridLayer(y,x);
1836 if (layer==NULL)
1837 continue;
1839 uint i, j;
1840 uint cmotion = 15;
1841 bool different = false;
1843 for (i=0; i<16 && !different; ++i)
1845 for (j=0; j<16 && !different; ++j)
1847 uint nm = layer->get(i, j);
1848 if (cmotion != 15 && nm != 15 && nm != cmotion)
1850 different = true;
1852 else if (nm != 15)
1854 cmotion = layer->get(i, j);
1861 if (!different)
1863 CWhite16x16Layer *nlayer = new CWhite16x16Layer();
1865 nlayer->set (0, 0, cmotion);
1867 delete directionLayer->getGridLayer(y,x);
1868 directionLayer->setGridLayer(y,x,nlayer);
1877 // dmap->dump();
1879 cell->setDirectionMap(dmap, topo);
1881 CTopology &topology = cell->getTopologyNode(topo);
1883 topology.Id = CTopology::TTopologyId(scanline, topo);
1884 topology.Neighbours.clear();
1886 set<CTopology::TTopologyRef>::iterator it;
1887 for (it=visited.begin(); it!=visited.end(); ++it)
1889 CTopology::TTopologyRef topId(*it);
1890 const CTopology &node = topId.getCstTopologyNode(); // _WorldMap.getTopologyNode(topId)
1891 float Norm=(topology.Position-node.Position).norm();
1892 topology.Neighbours.push_back(CTopology::CNeighbourLink(topId, Norm));
1895 else if (Verbose)
1897 nlwarning("Topo %d not found, probably not accessible, left unchecked", topo);
1900 ++topo;
1902 if (topo > maxtopo)
1903 break;
1908 for (scan = min; scan.y() != max.y(); scan = scan.stepCell(0, 1))
1910 for (scanline = scan; scanline.x() != max.x(); scanline = scanline.stepCell(1, 0))
1912 if (!_WorldMap.exist(scanline))
1913 continue;
1915 CRootCell *cell = _WorldMap.getRootCell(scanline);
1916 if (cell == NULL)
1917 continue;
1919 vector<CTopology> &tops = cell->getTopologiesNodes();
1920 uint i, j;
1922 // for all topologies in cell
1923 for (i=0; i<tops.size(); ++i)
1925 CTopology &node = tops[i];
1926 vector<CTopology::CNeighbourLink>::iterator it;
1928 // look for all neighbours
1929 for (it=node.Neighbours.begin(); it!=node.Neighbours.end();)
1931 // and check that it is a neighbour of the neighbour
1932 const CTopology &neighb = (*it).getTopologyRef().getCstTopologyNode();
1933 for (j=0; j<neighb.Neighbours.size(); ++j)
1934 if (neighb.Neighbours[j].getTopologyRef() == node.Id)
1935 break;
1937 if (j == neighb.Neighbours.size())
1939 if (Verbose)
1940 nlwarning("Non bijective link between topology %08X and topology %08X, fixed", node.Id.getVal(), neighb.Id.getVal());
1941 it = node.Neighbours.erase(it);
1943 else
1944 ++it;
1950 _WorldMap.checkMotionLayer();
1951 _WorldMap.countSuperTopo();
1953 _WorldMap.buildMasterTopo(false, false);
1954 _WorldMap.buildMasterTopo(true, false);
1955 _WorldMap.buildMasterTopo(false, true);
1956 _WorldMap.buildMasterTopo(true, true);
1961 void buildBMP(const string &name)
1963 // nlassert(false);
1964 nlinfo("building bitmap...");
1966 uint compute = 0, white = 0, simple = 0, multi = 0, other = 0;
1967 _WorldMap.countCells(compute, white, simple, multi, other);
1968 uint total = compute+white+simple+multi+other;
1970 nlinfo("%d cells : compute=%d, white=%d, simple=%d, multi=%d, other=%d", total, compute, white, simple, multi, other);
1972 nlinfo("Build bmp...");
1974 CMapPosition min, max;
1975 _WorldMap.getBounds(min, max);
1977 uint scanWidth = max.x()-min.x();
1978 uint scanHeight = max.y()-min.y();
1980 uint imageWidth = (scanWidth+15)&~15;
1981 uint imageHeight = (scanHeight);
1983 CBMP4Image<2,2>::SHdr imageHdr(imageWidth, imageHeight);
1984 CBMP4Image<2,2>::SPalette imagePalette;
1986 FILE *outf = nlfopen(OutputPath+name+".bmp", "wb");
1988 if (outf == NULL)
1989 return;
1991 uint16 BM = 0x4D42;
1992 imagePalette.setupForCol();
1993 fwrite((void *)&BM, 1, sizeof(BM), outf);
1994 fwrite((void *)&imageHdr, 1, sizeof(imageHdr), outf);
1995 fwrite((void *)&imagePalette, 1, sizeof(imagePalette), outf);
1997 uint8 *lineBuffer = new uint8[imageWidth/2];
1998 memset(lineBuffer, 255, imageWidth/2);
2000 CMapPosition scanpos(min.x(),min.y());
2001 uint x, y;
2003 const CWorldMap *wmap = &_WorldMap;
2005 for (y=0; y<scanHeight; ++y)
2007 uint8 *linePtr = lineBuffer;
2008 uint8 pointBuffer;
2010 CMapPosition pos(scanpos);
2012 for (x=0; x<scanWidth; ++x)
2014 uint8 color = 0;
2015 sint32 colorHM = -32768;
2016 uint32 slot=0;
2018 const CRootCell *cell = wmap->getRootCellCst(pos);
2020 if (cell != NULL)
2022 uint ns;
2023 for (ns=0; ns<3; ++ns)
2025 CWorldPosition wp = _WorldMap.getSafeWorldPosition(pos, CSlot(ns));
2027 if (!wp.isValid())
2028 continue;
2030 ++slot;
2032 CCellLinkage links = cell->getCellLink(wp);
2033 sint32 height = cell->getHeight(wp);
2034 uint8 cl = 0;
2036 if (!links.isESlotValid()) ++cl;
2037 if (!links.isWSlotValid()) ++cl;
2038 if (!links.isSSlotValid()) ++cl;
2039 if (!links.isNSlotValid()) ++cl;
2041 if (cl > color)
2042 color = cl;
2044 if (height > colorHM)
2045 colorHM = height;
2049 pointBuffer = ((pointBuffer<<4) | (color+((uint8)slot<<2)));
2051 if (x & 1)
2053 *(linePtr++) = pointBuffer;
2056 pos = pos.getStepE();
2058 scanpos = scanpos.getStepN();
2060 fwrite((void*)lineBuffer, 1, imageWidth/2, outf);
2063 fclose(outf);
2064 delete [] lineBuffer;
2070 void buildBitMap(const string &name)
2072 // nlassert(false);
2073 nlinfo("building bitmap...");
2075 _WorldMap.clear();
2076 string ext = CFile::getExtension(name);
2077 if (ext.empty())
2078 ext = "cwmap2";
2079 CIFile f(OutputPath+CFile::getFilenameWithoutExtension(name)+"."+ext);
2080 f.serial(_WorldMap);
2082 uint compute = 0, white = 0, simple = 0, multi = 0, other = 0;
2083 _WorldMap.countCells(compute, white, simple, multi, other);
2084 uint total = compute+white+simple+multi+other;
2086 nlinfo("%d cells : compute=%d, white=%d, simple=%d, multi=%d, other=%d", total, compute, white, simple, multi, other);
2088 nlinfo("Build bmp...");
2090 CMapPosition min, max;
2091 _WorldMap.getBounds(min, max);
2093 uint scanWidth = max.x()-min.x();
2094 uint scanHeight = max.y()-min.y();
2096 uint imageWidth = (scanWidth+15)&~15;
2097 uint imageHeight = (scanHeight);
2099 CBMP4Image<2,2>::SHdr imageHdr(imageWidth, imageHeight);
2100 CBMP4Image<2,2>::SPalette imagePalette;
2102 FILE *outf = nlfopen(OutputPath+name+".bmp", "wb");
2103 FILE *outfh = nlfopen(OutputPath+name+"_hm.bmp", "wb");
2105 if (outf == NULL)
2106 return;
2108 uint16 BM = 0x4D42;
2109 imagePalette.setupForCol();
2110 fwrite((void *)&BM, 1, sizeof(BM), outf);
2111 fwrite((void *)&imageHdr, 1, sizeof(imageHdr), outf);
2112 fwrite((void *)&imagePalette, 1, sizeof(imagePalette), outf);
2114 imagePalette.setupHueCircle();
2115 fwrite((void *)&BM, 1, sizeof(BM), outfh);
2116 fwrite((void *)&imageHdr, 1, sizeof(imageHdr), outfh);
2117 fwrite((void *)&imagePalette, 1, sizeof(imagePalette), outfh);
2119 uint8 *lineBuffer = new uint8[imageWidth/2];
2120 memset(lineBuffer, 255, imageWidth/2);
2122 uint8 *lineBufferHM = new uint8[imageWidth/2];
2123 memset(lineBufferHM, 255, imageWidth/2);
2125 CMapPosition scanpos(min.x(),min.y());
2126 uint x, y;
2128 const CWorldMap *wmap = &_WorldMap;
2130 CTGAImage tgaImage;
2132 tgaImage.setup((uint16)imageWidth, (uint16)imageHeight, OutputPath+name+".tga", (uint16)min.x(), (uint16)-max.y());
2133 tgaImage.setupForCol();
2135 for (y=0; y<scanHeight; ++y)
2137 uint8 *linePtr = lineBuffer;
2138 uint8 *linePtrHM = lineBufferHM;
2139 uint8 pointBuffer = 0;
2140 uint8 pointBufferHM = 0;
2142 CMapPosition pos(scanpos);
2144 for (x=0; x<scanWidth; ++x)
2146 uint8 color = 0;
2147 sint32 colorHM = -32768;
2148 uint32 slot=0;
2150 const CRootCell *cell = wmap->getRootCellCst(pos);
2152 if (cell != NULL)
2154 uint ns;
2155 for (ns=0; ns<3; ++ns)
2157 CWorldPosition wp = _WorldMap.getSafeWorldPosition(pos, CSlot(ns));
2159 if (!wp.isValid())
2160 continue;
2162 ++slot;
2164 CCellLinkage links = cell->getCellLink(wp);
2165 sint32 height = cell->getHeight(wp);
2166 uint8 cl = 0;
2168 if (!links.isESlotValid()) ++cl;
2169 if (!links.isWSlotValid()) ++cl;
2170 if (!links.isSSlotValid()) ++cl;
2171 if (!links.isNSlotValid()) ++cl;
2173 if (cl > color)
2174 color = cl;
2176 if (height > colorHM)
2177 colorHM = height;
2181 tgaImage.set(x, color+((uint8)slot<<2));
2183 pointBuffer = ((pointBuffer<<4) | (color+((uint8)slot<<2)));
2184 pointBufferHM = ((pointBufferHM<<4) | (colorHM & 0xf));
2186 if (x & 1)
2188 *(linePtr++) = pointBuffer;
2189 *(linePtrHM++) = pointBufferHM;
2192 pos = pos.getStepE();
2194 scanpos = scanpos.getStepN();
2196 fwrite((void*)lineBuffer, 1, imageWidth/2, outf);
2197 fwrite((void*)lineBufferHM, 1, imageWidth/2, outfh);
2199 tgaImage.writeLine();
2202 fclose(outf);
2203 fclose(outfh);
2204 delete [] lineBuffer;
2205 delete [] lineBufferHM;
2207 _WorldMap.clear();
2211 // build a height map of sint16. Full path should be given for the input cw_map2
2212 void buildHeightMap16(const string &name)
2214 // nlassert(false);
2215 nlinfo("building heightmap for %s", name.c_str());
2217 _WorldMap.clear();
2218 string ext = CFile::getExtension(name);
2219 if (ext.empty())
2220 ext = "cw_map2";
2222 CIFile f(CFile::getPath(name) + CFile::getFilenameWithoutExtension(name)+"."+ext);
2223 f.serial(_WorldMap);
2225 uint compute = 0, white = 0, simple = 0, multi = 0, other = 0;
2226 _WorldMap.countCells(compute, white, simple, multi, other);
2227 uint total = compute+white+simple+multi+other;
2229 nlinfo("%d cells : compute=%d, white=%d, simple=%d, multi=%d, other=%d", total, compute, white, simple, multi, other);
2231 nlinfo("Build bmp...");
2233 CMapPosition min, max;
2234 _WorldMap.getBounds(min, max);
2236 uint scanWidth = max.x()-min.x();
2237 uint scanHeight = max.y()-min.y();
2241 CMapPosition scanpos(min.x(),min.y());
2242 uint x, y;
2244 const CWorldMap *wmap = &_WorldMap;
2246 CArray2D<sint16> heightMap;
2247 heightMap.init(scanWidth, scanHeight);
2249 sint16 *dest = &heightMap(0, 0);
2251 for (y=0; y<scanHeight; ++y)
2253 CMapPosition pos(scanpos);
2255 for (x=0; x<scanWidth; ++x)
2257 sint16 height = 0x7fff;
2259 const CRootCell *cell = wmap->getRootCellCst(pos);
2261 if (cell != NULL)
2263 uint ns;
2264 for (ns=0; ns<3; ++ns)
2266 CWorldPosition wp = _WorldMap.getSafeWorldPosition(pos, CSlot(ns));
2267 if (!wp.isValid())
2268 continue;
2269 sint32 newHeight = cell->getHeight(wp);
2270 if (newHeight < (sint16) height)
2271 height = (sint16) newHeight;
2275 *dest ++ = height;
2276 pos = pos.getStepE();
2278 scanpos = scanpos.getStepN();
2280 // write result
2281 COFile output(OutputPath + CFile::getFilenameWithoutExtension(name)+".cw_height");
2282 sint32 xmin = (sint32) min.x();
2283 sint32 xmax = (sint32) max.x();
2284 sint32 ymin = (sint32) (sint16) min.y();
2285 sint32 ymax = (sint32) (sint16) max.y();
2286 output.serialCheck(NELID("OBSI"));
2287 output.serial(xmin);
2288 output.serial(xmax);
2289 output.serial(ymin);
2290 output.serial(ymax);
2291 output.serial(heightMap);
2292 // TMP TMP
2294 CBitmap tgaHM;
2295 tgaHM.resize(heightMap.getWidth(), heightMap.getHeight());
2296 sint16 hMax = -32768;
2297 sint16 hMin= 32767;
2298 uint numPix = heightMap.getWidth() * heightMap.getHeight();
2299 for(CArray2D<sint16>::iterator it = heightMap.begin(); it != heightMap.end(); ++it)
2301 if (*it != 32767)
2303 hMax = std::max(hMax, *it);
2304 hMin = std::min(hMin, *it);
2308 float scale = 255.f / favoid0((float) (hMax - hMin));
2309 float bias = (float) - hMin;
2310 CRGBA *destCol = (CRGBA *) &tgaHM.getPixels()[0];
2311 for(CArray2D<sint16>::iterator it = heightMap.begin(); it != heightMap.end(); ++it)
2313 if (*it == 0x7fff)
2315 *destCol++ = CRGBA::Magenta;
2317 else
2319 float height = scale * ((*it) + bias);
2320 clamp(height, 0.f, 255.f);
2321 *destCol++ = CRGBA((uint8) height, (uint8) height, (uint8) height);
2325 COFile tgaOut("d:\\tmp\\whole_world_height_map.tga");
2326 tgaHM.writeTGA(tgaOut, 0, true);
2329 _WorldMap.clear();
2335 void findPath(const string &name, CVectorD start, CVectorD end)
2337 _WorldMap.clear();
2338 CIFile f(OutputPath+name+".cwmap2");
2339 f.serial(_WorldMap);
2341 CAStarPath path;
2342 path.setStartPos(_WorldMap.getWorldPosition(start));
2343 path.setEndPos(_WorldMap.getWorldPosition(end));
2344 _WorldMap.findAStarPath(path.getStartPos(), path.getEndPos(), path.topologiesPathForCalc());
2346 uint step=0;
2348 CWorldPosition cpos(_WorldMap.getWorldPosition(start));
2349 while (_WorldMap.move(cpos, path, step))
2351 CVectorD dpos = cpos.getPosition(); // _WorldMap.getPosition(cpos)
2352 CMapPosition mpos = cpos;
2353 nldebug("Move: (%.1f,%.1f,%.1f)/(%04x,%04x)", dpos.x, dpos.y, dpos.z, mpos.x(), mpos.y());
2356 _WorldMap.clear();
2360 void findInsidePath(const string &name, CVectorD start, CVectorD end)
2362 _WorldMap.clear();
2363 CIFile f(OutputPath+name+".cwmap2");
2364 f.serial(_WorldMap);
2366 CInsideAStarPath path;
2367 path.setStartPos(_WorldMap.getWorldPosition(start));
2368 path.setEndPos(_WorldMap.getWorldPosition(end));
2369 _WorldMap.findInsideAStarPath(path.getStartPos(), path.getEndPos(), path.getStepPathForCalc());
2371 uint step=0;
2373 CWorldPosition cpos = _WorldMap.getWorldPosition(start);
2374 while (_WorldMap.move(cpos, path, step))
2376 CVectorD dpos = _WorldMap.getWorldPosition(cpos);
2377 CMapPosition mpos = cpos.getMapPosition();
2378 nldebug("Move: (%.1f,%.1f,%.1f)/(%04x,%04x)", dpos.x, dpos.y, dpos.z, mpos.x.c, mpos.y.c);
2381 _WorldMap.clear();
2385 void testMove(const string &name, CVectorD start, CVectorD end)
2387 _WorldMap.clear();
2388 CIFile f(OutputPath+name+".cwmap2");
2389 f.serial(_WorldMap);
2391 CWorldPosition pos(_WorldMap.getWorldPosition(start));
2392 CMapPosition towards = _WorldMap.getWorldPosition(end);
2393 _WorldMap.move (pos,towards, Nothing);
2394 _WorldMap.clear ();
2398 CPacsCruncher::TPacsPrimMap CPacsCruncher::_PacsPrimMap;
2403 NLMISC_COMMAND(setStartPoint,"Set the start point for a continent","<continent> <startx> <starty> [startz]")
2405 if (args.size() < 3)
2406 return false;
2408 CVectorD startPoint;
2410 NLMISC::fromString(args[1], startPoint.x);
2411 NLMISC::fromString(args[2], startPoint.y);
2413 if (args.size() < 4)
2415 startPoint.z = 0.0;
2417 else
2419 NLMISC::fromString(args[3], startPoint.z);
2422 StartPoints.insert(multimap<string, CVectorD>::value_type(args[0], startPoint));
2424 nlinfo("Set start point (%.1f,%.1f,%.1f) for continent '%s'", startPoint.x, startPoint.y, startPoint.z, args[0].c_str());
2426 return true;
2429 NLMISC_COMMAND(setBoundingBox, "Set the working bounding box", "<minx> <miny> <maxx> <maxy>")
2431 if (args.size() < 4)
2432 return false;
2434 NLMISC::fromString(args[0], BoxMin.x);
2435 NLMISC::fromString(args[1], BoxMin.y);
2436 NLMISC::fromString(args[2], BoxMax.x);
2437 NLMISC::fromString(args[3], BoxMax.y);
2439 return true;
2442 NLMISC_COMMAND(setStartPrimFile,"Adds a .primitive file for a continent","<continent> <primitive file>")
2444 if (args.size() < 2)
2445 return false;
2447 string continent = args[0];
2448 string primFile = args[1];
2450 PrimFiles.insert(multimap<string, string>::value_type(continent, primFile));
2452 nlinfo("Added primitive file %s to continent '%s'", primFile.c_str(), continent.c_str());
2454 return true;
2457 NLMISC_COMMAND(setPacsPrimPath,"the pacs prim path","<path>")
2459 if (args.size() < 1)
2460 return false;
2462 PacsPrimPath.push_back(args[0]);
2464 return true;
2467 NLMISC_COMMAND(setDefaultStart,"Set the default start point for all continents","<startx> <starty> [startz]")
2469 if (args.size() < 2)
2470 return false;
2472 CVectorD startPoint;
2474 NLMISC::fromString(args[0], startPoint.x);
2475 NLMISC::fromString(args[1], startPoint.y);
2477 if (args.size() > 2)
2479 NLMISC::fromString(args[2], startPoint.z);
2481 else
2483 startPoint.z = 0.0;
2486 DefaultStartPoint = startPoint;
2488 nlinfo("Set default start point (%.1f,%.1f,%.1f)", startPoint.x, startPoint.y, startPoint.z);
2490 return true;
2494 NLMISC_COMMAND(setOutputPath,"Set the output path","<path>")
2496 if (args.size() < 1)
2497 return false;
2499 OutputPath = CPath::standardizePath(args[0]);
2501 return true;
2505 NLMISC_COMMAND(pacsCrunch,"Run a test of pacs crunch","<file name root> [<minx> <miny> <maxx> <maxy>]")
2507 if(args.size()<1)
2508 return false;
2510 //crunchPacsMap(args[0]);
2512 CPacsCruncher pc;
2514 if (args.size() == 5)
2516 float bxmin, bymin, bxmax, bymax;
2518 bxmin = (float)atof(args[1].c_str());
2519 bymin = (float)atof(args[2].c_str());
2520 bxmax = (float)atof(args[3].c_str());
2521 bymax = (float)atof(args[4].c_str());
2523 CAABBox box;
2525 box.setMinMax(CVector(bxmin, bymin, -10000.0f), CVector(bxmax, bymax, +10000.0f));
2527 pc.crunch(args[0], &box);
2529 else
2531 pc.crunch(args[0]);
2534 return true;
2537 NLMISC_COMMAND(pacsCrunchStart,"Run a test of pacs crunch","<file name root> <startx> <starty> [<minx> <miny> <maxx> <maxy>]")
2539 if(args.size()<3)
2540 return false;
2542 //crunchPacsMap(args[0]);
2545 float startx, starty;
2547 startx = (float)atof(args[1].c_str());
2548 starty = (float)atof(args[2].c_str());
2550 CVector start(startx, starty, 0.0f);
2552 CPacsCruncher pc;
2554 if (args.size() == 7)
2556 float bxmin, bymin, bxmax, bymax;
2558 bxmin = (float)atof(args[3].c_str());
2559 bymin = (float)atof(args[4].c_str());
2560 bxmax = (float)atof(args[5].c_str());
2561 bymax = (float)atof(args[6].c_str());
2563 CAABBox box;
2565 box.setMinMax(CVector(bxmin, bymin, -10000.0f), CVector(bxmax, bymax, +10000.0f));
2567 pc.crunch(args[0], &box, "", &start);
2569 else
2571 pc.crunch(args[0], NULL, "", &start);
2574 return true;
2577 NLMISC_COMMAND(pacsCrunchLoop,"Run a serie of tests of pacs crunch","<file name root> <startx> <starty> <loopx> <loopy> [<size>=160]")
2579 if(args.size()<5 || args.size()>6)
2580 return false;
2582 CPacsCruncher pc;
2584 float startx, starty;
2585 uint loopx, loopy;
2586 uint x, y;
2587 float size = 160.0f;
2589 startx = (float)atof(args[1].c_str());
2590 starty = (float)atof(args[2].c_str());
2591 NLMISC::fromString(args[3], loopx);
2592 NLMISC::fromString(args[4], loopy);
2594 if (args.size() >= 6)
2595 NLMISC::fromString(args[5], size);
2597 pc.init(args[0]);
2599 for (y=0; y<loopy; ++y)
2601 for (x=0; x<loopx; ++x)
2603 CAABBox box;
2605 box.setMinMax(CVector(startx+x*size, starty+y*size, -10000.0f), CVector(startx+(x+1)*size, starty+(y+1)*size, +10000.0f));
2607 pc.crunch(args[0], &box, toString(x)+"_"+toString(y));
2611 pc.release();
2613 return true;
2616 NLMISC_COMMAND(pacsBuildBitmap,"build a bitmap from a world map","<file name root>")
2618 if(args.size()<1)
2619 return false;
2621 CPacsCruncher pc;
2623 pc.buildBitMap(args[0]);
2625 return true;
2628 NLMISC_COMMAND(pacsBuildHeightMap16, "build a sint16 heightmap from a world map","<file name root>")
2630 if(args.size()<1)
2631 return false;
2633 CPacsCruncher pc;
2635 pc.buildHeightMap16(args[0]);
2637 return true;
2640 NLMISC_COMMAND(pacsBuildWmap,"build crunched world map from a world map","<file name root>")
2642 if(args.size()<1)
2643 return false;
2645 CPacsCruncher pc;
2647 pc.buildCrunchedMap(args[0]);
2649 return true;
2652 NLMISC_COMMAND(pacsBuildGabarit,"build gabarit maps from a world map","<file name root>")
2654 if(args.size()<1)
2655 return false;
2657 CPacsCruncher pc;
2659 uint i;
2660 for (i=0; i<3; ++i)
2661 pc.buildGabarit(args[0], i);
2663 return true;
2666 NLMISC_COMMAND(pacsClearHeightmap,"build gabarit maps from a world map","<file name root>")
2668 if(args.size()<1)
2669 return false;
2671 CPacsCruncher pc;
2673 uint i;
2674 for (i=1; i<3; ++i)
2675 pc.clearHeightMap(args[0], i);
2677 return true;
2682 NLMISC_COMMAND(testAstar, "test astar", "file startx starty endx endy (m)")
2684 if (args.size() < 4)
2685 return false;
2687 CPacsCruncher pc;
2689 pc.findPath(args[0], CVectorD(atof(args[1].c_str()), atof(args[2].c_str()), 0.0), CVectorD(atof(args[3].c_str()), atof(args[4].c_str()), 0.0));
2691 return true;
2694 NLMISC_COMMAND(testInsideAstar, "test inside astar", "file startx starty endx endy (m)")
2696 if (args.size() < 4)
2697 return false;
2699 CPacsCruncher pc;
2701 pc.findInsidePath(args[0], CVectorD(atof(args[1].c_str()), atof(args[2].c_str()), 0.0), CVectorD(atof(args[3].c_str()), atof(args[4].c_str()), 0.0));
2703 return true;
2706 NLMISC_COMMAND(testLine, "test linear movement", "file startx starty endx endy (m)")
2708 if (args.size() < 4)
2709 return false;
2711 CPacsCruncher pc;
2713 pc.testMove(args[0], CVectorD(atof(args[1].c_str()), atof(args[2].c_str()), 0.0), CVectorD(atof(args[3].c_str()), atof(args[4].c_str()), 0.0));
2715 return true;
2721 NLMISC_COMMAND(checkPackedSheets, "checks continents.packed_sheets file", "")
2723 // a simple pc will automatically checks for continents.packed_sheets file
2724 CPacsCruncher pc;
2725 pc.initPackedSheets();
2727 return true;
2732 NLMISC_COMMAND(loadWmap, "Loads a worldmap in static world map", "<file>")
2734 if (args.size() < 1)
2735 return false;
2737 StaticWorldMap.clear();
2738 CIFile f(OutputPath+args[0]);
2739 f.serial(StaticWorldMap);
2741 return true;
2744 NLMISC_COMMAND(clearWmap, "Clears static world map", "")
2746 StaticWorldMap.clear();
2748 return true;
2751 NLMISC_COMMAND(dumpMotionLayer, "Dumps motion layer around a position", "<x> <y> <z>")
2754 if (args.size() < 3)
2755 return false;
2757 CVectorD vpos;
2758 CWorldPosition pos;
2760 vpos.x = atof(args[0].c_str());
2761 vpos.y = atof(args[1].c_str());
2762 vpos.z = atof(args[2].c_str());
2764 StaticWorldMap.setWorldPosition(pos, CMapPosition(vpos));
2766 if (!pos.isValid())
2767 return false;
2769 CTopology::TTopologyId topoId = StaticWorldMap.getTopologyId(pos);
2770 const CTopology &topo = StaticWorldMap.getTopologyNode(topoId);
2772 topo.DirectionMap->dump();
2774 return true;
2777 NLMISC_COMMAND(dumpTopo, "Dumps motion layer around a position", "topoId in hexa")
2779 if (args.size() < 1)
2780 return false;
2782 uint32 id;
2784 sscanf(args[0].c_str(), "%x", &id);
2786 CTopology::TTopologyId topoId(id);
2787 const CTopology &topo = StaticWorldMap.getTopologyNode(topoId);
2789 topo.DirectionMap->dump();
2791 uint i;
2792 nlinfo("%08X neighbours (%d neighbours)", id, topo.Neighbours.size());
2793 for (i=0; i<topo.Neighbours.size(); ++i)
2794 nlinfo("%d: %08X", i, topo.Neighbours[i].getTopologyRef().getVal());
2796 return true;
2799 NLMISC_COMMAND(findTopoPath, "Find path between 2 topologies", "startTopoId endTopoId")
2801 if (args.size() < 2)
2802 return false;
2804 uint32 startId, endId;
2806 sscanf(args[0].c_str(), "%x", &startId);
2807 sscanf(args[1].c_str(), "%x", &endId);
2809 CTopology::TTopologyId startTopoId(startId);
2810 CTopology::TTopologyId endTopoId(endId);
2811 CAStarPath path;
2813 StaticWorldMap.findAStarPath(startTopoId, endTopoId, path);
2815 return true;
2818 NLMISC_COMMAND(findPath, "Find path between 2 world positions", "startx starty startslot endx endy endslot")
2820 if (args.size() < 6)
2821 return false;
2823 sint32 startx, starty, startslot;
2824 sint32 endx, endy, endslot;
2826 NLMISC::fromString(args[0], startx);
2827 NLMISC::fromString(args[1], starty);
2828 NLMISC::fromString(args[2], startslot);
2829 NLMISC::fromString(args[3], endx);
2830 NLMISC::fromString(args[4], endy);
2831 NLMISC::fromString(args[5], endslot);
2833 CWorldPosition start = StaticWorldMap.getWorldPosition(CMapPosition(startx, starty), CSlot(startslot));
2834 CWorldPosition end = StaticWorldMap.getWorldPosition(CMapPosition(endx, endy), CSlot(endslot));
2835 CAStarPath path;
2837 nlinfo("Start: topo %d, i0:%d i1:%d i2:%d i3:%d",
2838 start.getTopologyRef().getCstTopologyNode().Id.getVal(),
2839 start.getTopologyRef().getCstTopologyNode().MasterTopL,
2840 start.getTopologyRef().getCstTopologyNode().MasterTopLN,
2841 start.getTopologyRef().getCstTopologyNode().MasterTopLW,
2842 start.getTopologyRef().getCstTopologyNode().MasterTopLNW);
2843 nlinfo("End: topo %d, i0:%d i1:%d i2:%d i3:%d",
2844 end.getTopologyRef().getCstTopologyNode().Id.getVal(),
2845 end.getTopologyRef().getCstTopologyNode().MasterTopL,
2846 end.getTopologyRef().getCstTopologyNode().MasterTopLN,
2847 end.getTopologyRef().getCstTopologyNode().MasterTopLW,
2848 end.getTopologyRef().getCstTopologyNode().MasterTopLNW);
2850 path.setStartPos(start);
2851 path.setEndPos(end);
2852 StaticWorldMap.findAStarPath(start, end, path.topologiesPathForCalc(), Water);
2854 CWorldPosition current = start;
2855 uint currentStep = 0;
2857 while (StaticWorldMap.move(current, path, currentStep))
2858 nlinfo("current: x:%-10d y:%-10d topoid:%08X topoflags:%d", current.x(), current.y(), current.getTopologyRef().getCstTopologyNode().Id.getVal(), current.getTopologyRef().getCstTopologyNode().Flags);
2860 return true;
2865 NLMISC_COMMAND(testLinks, "test links at a position", "x y slot")
2867 if (args.size() < 3)
2868 return false;
2870 CWorldPosition pos, mv, back;
2871 CDirection dir(CDirection::E);
2873 sint posx, posy;
2874 uint slot;
2876 NLMISC::fromString(args[0], posx);
2877 NLMISC::fromString(args[1], posy);
2878 NLMISC::fromString(args[2], slot);
2880 pos = StaticWorldMap.getWorldPosition(CMapPosition(posx, posy), CSlot(slot));
2882 uint i;
2883 for (i=0; i<8; ++i)
2885 CDirection opp(dir);
2886 opp.addStep(CDirection::HALF_TURN);
2887 if (StaticWorldMap.move(mv=pos, dir))
2889 if (!StaticWorldMap.move(back=mv, opp))
2890 nlwarning("Link failure at direction %d of (%04X,%04X,%d)", dir.getVal(), pos.x(), pos.y(), pos.slot());
2891 else if (back != pos)
2892 nlwarning("Reverse link failure at direction %d of (%04X,%04X,%d)", dir.getVal(), pos.x(), pos.y(), pos.slot());
2895 dir.addStep(CDirection::HALF_TURN_LEFT);
2898 return true;
2902 NLMISC_COMMAND(checkMotionLayer, "checks motion layer", "")
2904 // StaticWorldMap.checkMotionLayer();
2905 StaticWorldMap.countSuperTopo();
2907 return true;
2913 NLMISC_COMMAND(getH, "get H", "")
2915 if (args.size() < 3)
2916 return false;
2918 sint32 startx, starty, startslot;
2920 NLMISC::fromString(args[0], startx);
2921 NLMISC::fromString(args[1], starty);
2922 NLMISC::fromString(args[2], startslot);
2924 CWorldPosition start = StaticWorldMap.getWorldPosition(CMapPosition(startx, starty), CSlot(startslot));
2926 sint32 h = start.getRootCell()->getMetricHeight(start);
2928 nlinfo("Pos at (%d,%d,%d), z=%d", start.x(), start.y(), start.slot(), h);
2930 return true;
2933 NLMISC_COMMAND(testPacsMove, "test a pacs move", "<continent> <x> <y> <dx> <dy>")
2935 if (args.size() != 5)
2936 return false;
2938 CPacsCruncher pc;
2940 string name = args[0];
2942 double x, y, dx, dy;
2943 NLMISC::fromString(args[1], x);
2944 NLMISC::fromString(args[2], y);
2945 NLMISC::fromString(args[3], dx);
2946 NLMISC::fromString(args[4], dy);
2948 pc.init(name);
2950 UMovePrimitive *primitive = pc._Container->addNonCollisionablePrimitive();
2951 primitive->setPrimitiveType( UMovePrimitive::_2DOrientedCylinder );
2952 primitive->setReactionType( UMovePrimitive::Stop );
2953 primitive->setTriggerType((UMovePrimitive::TTrigger)(UMovePrimitive::EnterTrigger+
2954 UMovePrimitive::ExitTrigger) );
2955 primitive->setCollisionMask( 0xffffffff );
2956 primitive->setOcclusionMask( 0x00000000 );
2957 primitive->setObstacle( true );
2958 primitive->setAbsorbtion( 0 );
2959 primitive->setHeight( 6.0f );
2960 primitive->setRadius( 0.5f );
2962 CVectorD startPos(x, y, 0);
2963 primitive->setGlobalPosition(startPos, 0);
2964 pc._Container->evalCollision(1.0, 0);
2966 primitive->move(CVectorD(dx, dy, 0.0), 0);
2967 pc._Container->evalNCPrimitiveCollision(1.0, primitive, 0);
2969 UGlobalPosition newPos;
2970 primitive->getGlobalPosition(newPos, 0);
2972 return true;
2978 NLMISC_VARIABLE(string, EvaluatedPos, "Last evaluated pacs position");
2979 NLMISC_VARIABLE(uint, Verbose, "Verbosity");