1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2015 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
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"
31 #include "nel/misc/bitmap.h"
34 #include "nel/misc/algo.h"
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"
50 #include "nel/ligo/ligo_config.h"
51 #include "nel/ligo/primitive.h"
55 #include "game_share/bmp4image.h"
56 #include "server_share/continent_container.h"
60 #include "ai_share/world_map.h"
61 #include "ai_share/ai_spawn_commands.h"
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;
81 /// The start point for each continent
82 multimap
<string
, CVectorD
> StartPoints
;
83 multimap
<string
, string
> PrimFiles
;
84 CVectorD DefaultStartPoint
= CVectorD::Null
;
87 string OutputPath
= string("./");
88 vector
<string
> PacsPrimPath
;
89 vector
<string
> LookupPath
;
90 vector
<string
> LookupNoRecursePath
;
91 bool PathInitialized
= false;
93 CWorldMap StaticWorldMap
;
95 CVectorD BoxMin
, BoxMax
;
98 namespace RYPACSCRUNCH
105 CContinentContainer _Continents
;
107 URetrieverBank
*_Bank
;
108 UGlobalRetriever
*_Retriever
;
109 UMoveContainer
*_Container
;
110 UMovePrimitive
*_Primitive
;
111 UMovePrimitive
*_Primitive3
;
112 UMovePrimitive
*_Primitive5
;
116 deque
<UGlobalPosition
> _Positions1
;
117 deque
<UGlobalPosition
> _Positions3
;
118 deque
<UGlobalPosition
> _Positions5
;
124 uint32 _RetrieverWidth
;
125 uint32 _RetrieverHeight
;
126 uint32 _RetrieverArea
;
128 typedef std::map
<std::string
, NLPACS::UPrimitiveBlock
*> TPacsPrimMap
;
129 static TPacsPrimMap _PacsPrimMap
;
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
);
140 UMovePrimitive
*prims
[3] = { _Primitive
, _Primitive3
, _Primitive5
};
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);
158 CVectorD dpos
= _Retriever
->getDoubleGlobalPosition(pos
);
159 CVectorD dnpos
= _Retriever
->getDoubleGlobalPosition(newPos
);
161 //bool test = (static_cast<NLPACS::CGlobalRetriever*>(_Retriever))->testPosition(newPos);
164 NLPACS::CGlobalRetriever
* gRetriever
= static_cast<NLPACS::CGlobalRetriever
*>(_Retriever
);
166 if (newPos
.InstanceId
< 0 || newPos
.InstanceId
>= (sint
)gRetriever
->getInstances().size())
169 const CRetrieverInstance
& instance
= gRetriever
->getInstances()[newPos
.InstanceId
];
171 if (!instance
.getBBox().include(newPos
.LocalPosition
.Estimation
+ instance
.getOrigin()))
175 const CLocalRetriever
& lRetriever
= gRetriever
->getRetriever(instance
.getRetrieverId());
177 if (!lRetriever
.isLoaded())
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
);
184 else if (fabs(newPos
.LocalPosition
.Estimation
.x
) >= 256.0 || fabs(newPos
.LocalPosition
.Estimation
.y
) >= 256.0)
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");
197 CVectorD dmotion
= dpos
+motion
-dnpos
;
200 // if the move was not accomplished successfully return '3' as "direction blocked"
201 if ( dmotion
.norm() > 1.0e-2 )
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())
218 unitSlot
.setHeight((uint
)floor(dnpos
.z
/2.0 + 0.5));
219 unitSlot
.setInterior(_Retriever
->isInterior(newPos
));
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
);
229 else if (unitSlot
.hasSameSurface(surfId
))
240 void readPrimitive(IPrimitive
*primitive
, const std::string
&insertAt
)
242 if (dynamic_cast<CPrimZone
*>(primitive
) != NULL
)
244 CPrimZone
*prim
= static_cast<CPrimZone
*>(primitive
);
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
);
260 for (i
=0; i
<prim
->VPoints
.size(); ++i
)
262 StartPoints
.insert(multimap
<string
, CVectorD
>::value_type(insertAt
, prim
->VPoints
[i
]));
268 for (i
=0; i
<primitive
->getNumChildren(); ++i
)
272 if (!primitive
->getChild(child
, i
))
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
));
297 nlinfo("Loaded prim file '%s'", prim
.c_str());
300 if (!prims
.read(xml
.getRootNode(), prim
.c_str(), LigoConfig
))
302 nlwarning("Can't use primitive file '%s', xml parse error", prim
.c_str());
312 CPacsCruncher() : _Bank(NULL
), _Retriever(NULL
), _Container(NULL
)
316 void initPackedSheets()
318 if (!PathInitialized
)
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
)
337 _Continents
.loadContinent(name
, name
, 0, true);
339 _Bank
= _Continents
.getRetrieverBank(0);
340 _Retriever
= _Continents
.getRetriever(0);
341 _Container
= _Continents
.getMoveContainer(0);
346 _Continents
.removeContinent(0);
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
)
364 if (_Bank
== NULL
&& _Retriever
== NULL
&& _Container
== NULL
)
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
);
378 vmin
.maxof(constraintBox
->getMin(), rBox
.getMin());
379 vmax
.minof(constraintBox
->getMax(), rBox
.getMax());
380 useBox
.setMinMax(vmin
, vmax
);
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
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();
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
);
480 CGlobalRetriever
*cgr
= (CGlobalRetriever
*)_Retriever
;
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
);
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
);
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
525 for (slot
=CSlot(0); slot
.isValid(); ++slot
)
527 CUnitSlot
& unitSlot
=slots
[slot
.slot()];
529 if (unitSlot
.hasSameSurface(surfId
))
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,
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();
570 refPos
= _Positions1
.front();
571 _Positions1
.pop_front();
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
);
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);
603 CMapPosition
refIndex(pos
);
605 TCellUnit
&slots
= _WorldMap
.getCellUnit(refIndex
);
608 CUnitSlot
refSlot(refPos
);
610 for (slot
=0; slot
<3 && !slots
[slot
].hasSameSurface(refSlot
); ++slot
)
615 nlwarning("Failed to find point in surface slots");
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
));
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
));
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
));
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
));
649 nlinfo("crunchPacsMap: performed %d iterations",count
);
656 //checkMap(_WorldMap, true);
658 COFile
f(OutputPath
+name
+".wmap");
664 _Container
->removePrimitive(_Primitive
);
665 _Container
->removePrimitive(_Primitive3
);
666 _Container
->removePrimitive(_Primitive5
);
676 void buildGabarit(const string
&name
, uint gabarit
)
678 nlinfo("building gabarit %d map...", gabarit
);
681 CIFile
f(OutputPath
+name
+".wmap");
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
))
702 const CComputeCell
*cc
= const_cast<const CWorldMap
&>(_WorldMap
).getComputeCellCst(scanline
);
710 CMapPosition pos
=scanline
;
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());
748 COFile
of(OutputPath
+name
+"_"+toString(gabarit
)+".wmap");
749 of
.serial(_WorldMap
);
752 void buildCrunchedMap(const string
&name
)
754 nlinfo("building crunched map...");
757 CIFile
f(OutputPath
+name
+".wmap");
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
;
790 for (i
=0; i
<16 && !failed
; ++i
)
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));
801 const TCellUnit
&cunit
= cell
->getCellUnitCst(pos
);
802 uint32 used
= cell
->maxUsedSlot(pos
);
808 if (white
&& cunit
[0].getCellLink().getLinks() != 0)
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))))
820 if (sl0
&& (cunit
[0].interior() /*|| cunit[0].water()*/ || cunit
[0].topology() != 0))
825 // nlinfo("Dump: %s", buff);
830 pos
= scanline
.getStepS();
831 for (i
=0; i
<16 && !failed
; ++i
, pos
= pos
.getStepE())
832 if ((used
= _WorldMap
.maxUsedSlot(pos
)) >= 1)
837 pos
= scanline
.getStepW();
838 for (i
=0; i
<16 && !failed
; ++i
, pos
= pos
.getStepN())
839 if ((used
= _WorldMap
.maxUsedSlot(pos
)) >= 1)
844 pos
= scanline
.stepCell(0, 1);
845 for (i
=0; i
<16 && !failed
; ++i
, pos
= pos
.getStepE())
846 if ((used
= _WorldMap
.maxUsedSlot(pos
)) >= 1)
851 pos
= scanline
.stepCell(1, 0);
852 for (i
=0; i
<16 && !failed
; ++i
, pos
= pos
.getStepN())
853 if ((used
= _WorldMap
.maxUsedSlot(pos
)) >= 1)
858 if (!failed
&& white
)
860 // replace the compute cell by a white cell
861 CWhiteCell
*wcell
= new CWhiteCell(_WorldMap
);
862 wcell
->setTopologiesNodes(cell
->getTopologiesNodes());
865 CFull16x16Layer
*heightMap
= new CFull16x16Layer();
868 heightMap
->set(i
, j
, cell
->getHeight(_WorldMap
.getWorldPositionGeneration(CMapPosition(j
, i
),CSlot(0))));
870 wcell
->setHeightMap(I16x16Layer::compress(heightMap
, 0x7fffffff));
874 // _WorldMap.setRootCell(scanline, wcell);
878 // replace the compute cell by a single layer cell
879 CSingleLayerCell
*slcell
= new CSingleLayerCell(_WorldMap
);
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
)
903 slcell
->setTopologies(NULL
);
905 else if (maxtopo
== 1)
907 C1Bit16x16Layer
*layer
= new C1Bit16x16Layer();
916 layer
->set(i
, j
, cell
->getTopology(_WorldMap
.getWorldPositionGeneration(pos
,CSlot(0))));
920 slcell
->setTopologies(layer
);
924 C8Bits16x16Layer
*layer
= new C8Bits16x16Layer();
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());
975 CFull16x16Layer
*heightMap
= new CFull16x16Layer();
978 heightMap
->set(i
, j
, slcell
->isSlotUsed(CMapPosition(j
, i
), CSlot(0)) ? cell
->getHeight(_WorldMap
.getWorldPositionGeneration(CMapPosition(j
,i
),CSlot(0))) :
981 slcell
->setHeightMap(I16x16Layer::compress(heightMap
, 0x7fffffff));
985 // _WorldMap.setRootCell(scanline, slcell);
991 CMultiLayerCell
*mlcell
= new CMultiLayerCell(_WorldMap
);
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());
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
)))
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
))));
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());
1053 nlassert(newCell
!= NULL
);
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();
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
);
1107 for (posy
=min
; posy
.y()<max
.y(); posy
=posy
.step(0, 1))
1110 for (posx
=posy
; posx
.x()<max
.x(); posx
=posx
.step(1, 0))
1115 CWorldPosition wpos
= wmap
.getSafeWorldPosition(posx
, CSlot(s
));
1117 if (!wpos
.isValid())
1120 CWorldPosition test
;
1123 if (wpos
.getCellLinkage().isNSlotValid())
1125 CSlot slot
= wpos
.getCellLinkage().NSlot();
1126 test
= wmap
.getSafeWorldPosition(CMapPosition(wpos
).getStepN(), slot
);
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);
1137 wmap
.getUnitSlot(test
).cellLink().setSSlot(CSlot(s
));
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);
1150 wmap
.resetUnitSlotNLink(wpos
);
1154 if (wpos
.getCellLinkage().isSSlotValid())
1156 CSlot slot
= wpos
.getCellLinkage().SSlot();
1157 test
= wmap
.getSafeWorldPosition(CMapPosition(wpos
).getStepS(), slot
);
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);
1168 wmap
.getUnitSlot(test
).cellLink().setNSlot(CSlot(s
));
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);
1181 wmap
.resetUnitSlotSLink(wpos
);
1185 if (wpos
.getCellLinkage().isESlotValid())
1187 CSlot slot
= wpos
.getCellLinkage().ESlot();
1188 test
= wmap
.getSafeWorldPosition(CMapPosition(wpos
).getStepE(), slot
);
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);
1199 wmap
.getUnitSlot(test
).cellLink().setWSlot(CSlot(s
));
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);
1212 wmap
.resetUnitSlotELink(wpos
);
1216 if (wpos
.getCellLinkage().isWSlotValid())
1218 CSlot slot
= wpos
.getCellLinkage().WSlot();
1219 test
= wmap
.getSafeWorldPosition(CMapPosition(wpos
).getStepW(), slot
);
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);
1230 wmap
.getUnitSlot(test
).cellLink().setESlot(CSlot(s
));
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);
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());
1257 CIFile
fi(OutputPath
+name
+"_"+toString(gabarit
)+".cwmap2");
1258 fi
.serial(_WorldMap
);
1261 _WorldMap
.clearHeightMap();
1263 COFile
fo(OutputPath
+name
+"_"+toString(gabarit
)+".cwmap2");
1264 fo
.serial(_WorldMap
);
1271 nlinfo("filtering...");
1273 CMapPosition min
, max
;
1274 _WorldMap
.getBounds(min
, max
);
1276 CMapPosition scanpos
= min
;
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)
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))
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()
1319 nlinfo("building topologies...");
1322 CMapPosition min
, max
;
1323 _WorldMap
.getBounds(min
, max
);
1325 CMapPosition scan
, scanline
;
1328 vector
<uint
> toposcount
;
1332 sint
getTopo(const CSlot
&slot
) const
1334 return topos
[slot
.slot()];
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
))
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
;
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
)))
1382 CTopoGrid
&topoGrid
=toposGridList
[sp
.yCoord().getUnitId()][sp
.xCoord().getUnitId()];
1383 sint
&curTopos
=topoGrid
.topos
[spslot
];
1388 { // -- clean flood fill table --
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;
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
);
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());
1419 totalPos
+=CVector(wp
.toVectorD());
1422 static const CDirection::TDirection dirs
[] =
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
);
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)))
1465 && (!toposGridList
[y
][x
].testGrid
)
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
1479 //InfoLog->displayRawNL(" SUCCESS");
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);
1487 topoHasNeighb
= true;
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);
1504 nlinfo("Unactivated topo %d in cell (%4X,%4X)",i
, scanline
.x()&0xffff, scanline
.y()&0xffff);
1506 for (i
=0; i
<16; ++i
)
1508 for (j
=0; j
<16; ++j
)
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;
1534 if (i
>= toposcount
.size())
1535 toposcount
.resize(i
+1);
1541 nlinfo("Found %d topologies maximum", maxtopo
);
1543 for (i
=0; i
<toposcount
.size(); ++i
)
1544 nlinfo("%d cells of %d topologies", toposcount
[i
], i
);
1550 CMotionTrace() : dx(0), dy(0), distance(0xffffffff), flags(0)
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
;
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
))
1596 //if (scanline.x() == 4436 && scanline.y() == -4240)
1601 CRootCell
*cell
= _WorldMap
.getRootCell(scanline
);
1604 const CMapPosition mincell
= scanline
.stepCell(-1, -1),
1605 maxcell
= scanline
.stepCell( 2, 2);
1609 CMotionTrace fillGrid
[16*3][16*3][3];
1612 uint stx
= 0, sty
= 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
)))
1632 CWorldPosition stwp
= _WorldMap
.getWorldPosition(sp
, CSlot(stsl
));
1633 const uint topology
=cell
->getTopology(stwp
);
1635 if (topology
>maxtopo
&& topology
<0x80)
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
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];
1652 CMotionTrace
&first
= fillGrid
[sp
.y()-soffset
.y()][sp
.x()-soffset
.x()][stsl
];
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
));
1665 for (stack
=0; stack
<5; ++stack
)
1666 if (!stacks
[stack
].empty())
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
);
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())
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());
1712 else if (checkBackMove
!= next
)
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());
1722 const CTopology
& tmpNode
= tmp
.getTopologyRef().getCstTopologyNode();
1723 uint8 tmpflags
= (tmpNode
.isInWater() ? 1 : 0) + (tmpNode
.isInNogo() ? 2 : 0);
1725 if (tmpNode.Id != nextNode.Id)
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",
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
;
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
));
1763 stacks
[tmpflags
+ 1].insert(std::pair
<sint
, CWorldPosition
>(ndist
, tmp
));
1776 // generate direction map for this topo
1777 CDirectionMap
*dmap
= new CDirectionMap();
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
1809 directionLayer
->setGridLayer(y
>>4,x
>>4, new C4Bits16x16Layer());
1810 dirLayer
=directionLayer
->getGridLayer(y
>>4,x
>>4);
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);
1825 CDirectionLayer
* directionLayer
=dmap
->Layers
[s
];
1827 if (!directionLayer
)
1834 CGridDirectionLayer
*layer
=directionLayer
->getGridLayer(y
,x
);
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
)
1854 cmotion
= layer
->get(i
, j
);
1863 CWhite16x16Layer
*nlayer
= new CWhite16x16Layer();
1865 nlayer
->set (0, 0, cmotion
);
1867 delete directionLayer
->getGridLayer(y
,x
);
1868 directionLayer
->setGridLayer(y
,x
,nlayer
);
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
));
1897 nlwarning("Topo %d not found, probably not accessible, left unchecked", topo
);
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
))
1915 CRootCell
*cell
= _WorldMap
.getRootCell(scanline
);
1919 vector
<CTopology
> &tops
= cell
->getTopologiesNodes();
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
)
1937 if (j
== neighb
.Neighbours
.size())
1940 nlwarning("Non bijective link between topology %08X and topology %08X, fixed", node
.Id
.getVal(), neighb
.Id
.getVal());
1941 it
= node
.Neighbours
.erase(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
)
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");
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());
2003 const CWorldMap
*wmap
= &_WorldMap
;
2005 for (y
=0; y
<scanHeight
; ++y
)
2007 uint8
*linePtr
= lineBuffer
;
2010 CMapPosition
pos(scanpos
);
2012 for (x
=0; x
<scanWidth
; ++x
)
2015 sint32 colorHM
= -32768;
2018 const CRootCell
*cell
= wmap
->getRootCellCst(pos
);
2023 for (ns
=0; ns
<3; ++ns
)
2025 CWorldPosition wp
= _WorldMap
.getSafeWorldPosition(pos
, CSlot(ns
));
2032 CCellLinkage links
= cell
->getCellLink(wp
);
2033 sint32 height
= cell
->getHeight(wp
);
2036 if (!links
.isESlotValid()) ++cl
;
2037 if (!links
.isWSlotValid()) ++cl
;
2038 if (!links
.isSSlotValid()) ++cl
;
2039 if (!links
.isNSlotValid()) ++cl
;
2044 if (height
> colorHM
)
2049 pointBuffer
= ((pointBuffer
<<4) | (color
+((uint8
)slot
<<2)));
2053 *(linePtr
++) = pointBuffer
;
2056 pos
= pos
.getStepE();
2058 scanpos
= scanpos
.getStepN();
2060 fwrite((void*)lineBuffer
, 1, imageWidth
/2, outf
);
2064 delete [] lineBuffer
;
2070 void buildBitMap(const string
&name
)
2073 nlinfo("building bitmap...");
2076 string ext
= CFile::getExtension(name
);
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");
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());
2128 const CWorldMap
*wmap
= &_WorldMap
;
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
)
2147 sint32 colorHM
= -32768;
2150 const CRootCell
*cell
= wmap
->getRootCellCst(pos
);
2155 for (ns
=0; ns
<3; ++ns
)
2157 CWorldPosition wp
= _WorldMap
.getSafeWorldPosition(pos
, CSlot(ns
));
2164 CCellLinkage links
= cell
->getCellLink(wp
);
2165 sint32 height
= cell
->getHeight(wp
);
2168 if (!links
.isESlotValid()) ++cl
;
2169 if (!links
.isWSlotValid()) ++cl
;
2170 if (!links
.isSSlotValid()) ++cl
;
2171 if (!links
.isNSlotValid()) ++cl
;
2176 if (height
> colorHM
)
2181 tgaImage
.set(x
, color
+((uint8
)slot
<<2));
2183 pointBuffer
= ((pointBuffer
<<4) | (color
+((uint8
)slot
<<2)));
2184 pointBufferHM
= ((pointBufferHM
<<4) | (colorHM
& 0xf));
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();
2204 delete [] lineBuffer
;
2205 delete [] lineBufferHM
;
2211 // build a height map of sint16. Full path should be given for the input cw_map2
2212 void buildHeightMap16(const string
&name
)
2215 nlinfo("building heightmap for %s", name
.c_str());
2218 string ext
= CFile::getExtension(name
);
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());
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
);
2264 for (ns
=0; ns
<3; ++ns
)
2266 CWorldPosition wp
= _WorldMap
.getSafeWorldPosition(pos
, CSlot(ns
));
2269 sint32 newHeight
= cell
->getHeight(wp
);
2270 if (newHeight
< (sint16
) height
)
2271 height
= (sint16
) newHeight
;
2276 pos
= pos
.getStepE();
2278 scanpos
= scanpos
.getStepN();
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
);
2295 tgaHM.resize(heightMap.getWidth(), heightMap.getHeight());
2296 sint16 hMax = -32768;
2298 uint numPix = heightMap.getWidth() * heightMap.getHeight();
2299 for(CArray2D<sint16>::iterator it = heightMap.begin(); it != heightMap.end(); ++it)
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)
2315 *destCol++ = CRGBA::Magenta;
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);
2335 void findPath(const string
&name
, CVectorD start
, CVectorD end
)
2338 CIFile
f(OutputPath
+name
+".cwmap2");
2339 f
.serial(_WorldMap
);
2342 path
.setStartPos(_WorldMap
.getWorldPosition(start
));
2343 path
.setEndPos(_WorldMap
.getWorldPosition(end
));
2344 _WorldMap
.findAStarPath(path
.getStartPos(), path
.getEndPos(), path
.topologiesPathForCalc());
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());
2360 void findInsidePath(const string
&name
, CVectorD start
, CVectorD end
)
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());
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);
2385 void testMove(const string
&name
, CVectorD start
, CVectorD end
)
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
);
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)
2408 CVectorD startPoint
;
2410 NLMISC::fromString(args
[1], startPoint
.x
);
2411 NLMISC::fromString(args
[2], startPoint
.y
);
2413 if (args
.size() < 4)
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());
2429 NLMISC_COMMAND(setBoundingBox
, "Set the working bounding box", "<minx> <miny> <maxx> <maxy>")
2431 if (args
.size() < 4)
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
);
2442 NLMISC_COMMAND(setStartPrimFile
,"Adds a .primitive file for a continent","<continent> <primitive file>")
2444 if (args
.size() < 2)
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());
2457 NLMISC_COMMAND(setPacsPrimPath
,"the pacs prim path","<path>")
2459 if (args
.size() < 1)
2462 PacsPrimPath
.push_back(args
[0]);
2467 NLMISC_COMMAND(setDefaultStart
,"Set the default start point for all continents","<startx> <starty> [startz]")
2469 if (args
.size() < 2)
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
);
2486 DefaultStartPoint
= startPoint
;
2488 nlinfo("Set default start point (%.1f,%.1f,%.1f)", startPoint
.x
, startPoint
.y
, startPoint
.z
);
2494 NLMISC_COMMAND(setOutputPath
,"Set the output path","<path>")
2496 if (args
.size() < 1)
2499 OutputPath
= CPath::standardizePath(args
[0]);
2505 NLMISC_COMMAND(pacsCrunch
,"Run a test of pacs crunch","<file name root> [<minx> <miny> <maxx> <maxy>]")
2510 //crunchPacsMap(args[0]);
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());
2525 box
.setMinMax(CVector(bxmin
, bymin
, -10000.0f
), CVector(bxmax
, bymax
, +10000.0f
));
2527 pc
.crunch(args
[0], &box
);
2537 NLMISC_COMMAND(pacsCrunchStart
,"Run a test of pacs crunch","<file name root> <startx> <starty> [<minx> <miny> <maxx> <maxy>]")
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
);
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());
2565 box
.setMinMax(CVector(bxmin
, bymin
, -10000.0f
), CVector(bxmax
, bymax
, +10000.0f
));
2567 pc
.crunch(args
[0], &box
, "", &start
);
2571 pc
.crunch(args
[0], NULL
, "", &start
);
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)
2584 float startx
, starty
;
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
);
2599 for (y
=0; y
<loopy
; ++y
)
2601 for (x
=0; x
<loopx
; ++x
)
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
));
2616 NLMISC_COMMAND(pacsBuildBitmap
,"build a bitmap from a world map","<file name root>")
2623 pc
.buildBitMap(args
[0]);
2628 NLMISC_COMMAND(pacsBuildHeightMap16
, "build a sint16 heightmap from a world map","<file name root>")
2635 pc
.buildHeightMap16(args
[0]);
2640 NLMISC_COMMAND(pacsBuildWmap
,"build crunched world map from a world map","<file name root>")
2647 pc
.buildCrunchedMap(args
[0]);
2652 NLMISC_COMMAND(pacsBuildGabarit
,"build gabarit maps from a world map","<file name root>")
2661 pc
.buildGabarit(args
[0], i
);
2666 NLMISC_COMMAND(pacsClearHeightmap
,"build gabarit maps from a world map","<file name root>")
2675 pc
.clearHeightMap(args
[0], i
);
2682 NLMISC_COMMAND(testAstar
, "test astar", "file startx starty endx endy (m)")
2684 if (args
.size() < 4)
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));
2694 NLMISC_COMMAND(testInsideAstar
, "test inside astar", "file startx starty endx endy (m)")
2696 if (args
.size() < 4)
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));
2706 NLMISC_COMMAND(testLine
, "test linear movement", "file startx starty endx endy (m)")
2708 if (args
.size() < 4)
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));
2721 NLMISC_COMMAND(checkPackedSheets
, "checks continents.packed_sheets file", "")
2723 // a simple pc will automatically checks for continents.packed_sheets file
2725 pc
.initPackedSheets();
2732 NLMISC_COMMAND(loadWmap
, "Loads a worldmap in static world map", "<file>")
2734 if (args
.size() < 1)
2737 StaticWorldMap
.clear();
2738 CIFile
f(OutputPath
+args
[0]);
2739 f
.serial(StaticWorldMap
);
2744 NLMISC_COMMAND(clearWmap
, "Clears static world map", "")
2746 StaticWorldMap
.clear();
2751 NLMISC_COMMAND(dumpMotionLayer
, "Dumps motion layer around a position", "<x> <y> <z>")
2754 if (args.size() < 3)
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));
2769 CTopology::TTopologyId topoId = StaticWorldMap.getTopologyId(pos);
2770 const CTopology &topo = StaticWorldMap.getTopologyNode(topoId);
2772 topo.DirectionMap->dump();
2777 NLMISC_COMMAND(dumpTopo
, "Dumps motion layer around a position", "topoId in hexa")
2779 if (args
.size() < 1)
2784 sscanf(args
[0].c_str(), "%x", &id
);
2786 CTopology::TTopologyId
topoId(id
);
2787 const CTopology
&topo
= StaticWorldMap
.getTopologyNode(topoId
);
2789 topo
.DirectionMap
->dump();
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());
2799 NLMISC_COMMAND(findTopoPath
, "Find path between 2 topologies", "startTopoId endTopoId")
2801 if (args
.size() < 2)
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
);
2813 StaticWorldMap
.findAStarPath(startTopoId
, endTopoId
, path
);
2818 NLMISC_COMMAND(findPath
, "Find path between 2 world positions", "startx starty startslot endx endy endslot")
2820 if (args
.size() < 6)
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
));
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
);
2865 NLMISC_COMMAND(testLinks
, "test links at a position", "x y slot")
2867 if (args
.size() < 3)
2870 CWorldPosition pos
, mv
, back
;
2871 CDirection
dir(CDirection::E
);
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
));
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
);
2902 NLMISC_COMMAND(checkMotionLayer
, "checks motion layer", "")
2904 // StaticWorldMap.checkMotionLayer();
2905 StaticWorldMap
.countSuperTopo();
2913 NLMISC_COMMAND(getH
, "get H", "")
2915 if (args
.size() < 3)
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
);
2933 NLMISC_COMMAND(testPacsMove
, "test a pacs move", "<continent> <x> <y> <dx> <dy>")
2935 if (args
.size() != 5)
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
);
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);
2978 NLMISC_VARIABLE(string
, EvaluatedPos
, "Last evaluated pacs position");
2979 NLMISC_VARIABLE(uint
, Verbose
, "Verbosity");