RecastRegion.cpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812
  1. //
  2. // Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
  3. //
  4. // This software is provided 'as-is', without any express or implied
  5. // warranty. In no event will the authors be held liable for any damages
  6. // arising from the use of this software.
  7. // Permission is granted to anyone to use this software for any purpose,
  8. // including commercial applications, and to alter it and redistribute it
  9. // freely, subject to the following restrictions:
  10. // 1. The origin of this software must not be misrepresented; you must not
  11. // claim that you wrote the original software. If you use this software
  12. // in a product, an acknowledgment in the product documentation would be
  13. // appreciated but is not required.
  14. // 2. Altered source versions must be plainly marked as such, and must not be
  15. // misrepresented as being the original software.
  16. // 3. This notice may not be removed or altered from any source distribution.
  17. //
  18. #include <float.h>
  19. #define _USE_MATH_DEFINES
  20. #include <math.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include "Recast.h"
  25. #include "RecastAlloc.h"
  26. #include "RecastAssert.h"
  27. namespace
  28. {
  29. struct LevelStackEntry
  30. {
  31. LevelStackEntry(int x_, int y_, int index_) : x(x_), y(y_), index(index_) {}
  32. int x;
  33. int y;
  34. int index;
  35. };
  36. } // namespace
  37. static void calculateDistanceField(rcCompactHeightfield& chf, unsigned short* src, unsigned short& maxDist)
  38. {
  39. const int w = chf.width;
  40. const int h = chf.height;
  41. // Init distance and points.
  42. for (int i = 0; i < chf.spanCount; ++i)
  43. src[i] = 0xffff;
  44. // Mark boundary cells.
  45. for (int y = 0; y < h; ++y)
  46. {
  47. for (int x = 0; x < w; ++x)
  48. {
  49. const rcCompactCell& c = chf.cells[x+y*w];
  50. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  51. {
  52. const rcCompactSpan& s = chf.spans[i];
  53. const unsigned char area = chf.areas[i];
  54. int nc = 0;
  55. for (int dir = 0; dir < 4; ++dir)
  56. {
  57. if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
  58. {
  59. const int ax = x + rcGetDirOffsetX(dir);
  60. const int ay = y + rcGetDirOffsetY(dir);
  61. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
  62. if (area == chf.areas[ai])
  63. nc++;
  64. }
  65. }
  66. if (nc != 4)
  67. src[i] = 0;
  68. }
  69. }
  70. }
  71. // Pass 1
  72. for (int y = 0; y < h; ++y)
  73. {
  74. for (int x = 0; x < w; ++x)
  75. {
  76. const rcCompactCell& c = chf.cells[x+y*w];
  77. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  78. {
  79. const rcCompactSpan& s = chf.spans[i];
  80. if (rcGetCon(s, 0) != RC_NOT_CONNECTED)
  81. {
  82. // (-1,0)
  83. const int ax = x + rcGetDirOffsetX(0);
  84. const int ay = y + rcGetDirOffsetY(0);
  85. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0);
  86. const rcCompactSpan& as = chf.spans[ai];
  87. if (src[ai]+2 < src[i])
  88. src[i] = src[ai]+2;
  89. // (-1,-1)
  90. if (rcGetCon(as, 3) != RC_NOT_CONNECTED)
  91. {
  92. const int aax = ax + rcGetDirOffsetX(3);
  93. const int aay = ay + rcGetDirOffsetY(3);
  94. const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 3);
  95. if (src[aai]+3 < src[i])
  96. src[i] = src[aai]+3;
  97. }
  98. }
  99. if (rcGetCon(s, 3) != RC_NOT_CONNECTED)
  100. {
  101. // (0,-1)
  102. const int ax = x + rcGetDirOffsetX(3);
  103. const int ay = y + rcGetDirOffsetY(3);
  104. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3);
  105. const rcCompactSpan& as = chf.spans[ai];
  106. if (src[ai]+2 < src[i])
  107. src[i] = src[ai]+2;
  108. // (1,-1)
  109. if (rcGetCon(as, 2) != RC_NOT_CONNECTED)
  110. {
  111. const int aax = ax + rcGetDirOffsetX(2);
  112. const int aay = ay + rcGetDirOffsetY(2);
  113. const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 2);
  114. if (src[aai]+3 < src[i])
  115. src[i] = src[aai]+3;
  116. }
  117. }
  118. }
  119. }
  120. }
  121. // Pass 2
  122. for (int y = h-1; y >= 0; --y)
  123. {
  124. for (int x = w-1; x >= 0; --x)
  125. {
  126. const rcCompactCell& c = chf.cells[x+y*w];
  127. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  128. {
  129. const rcCompactSpan& s = chf.spans[i];
  130. if (rcGetCon(s, 2) != RC_NOT_CONNECTED)
  131. {
  132. // (1,0)
  133. const int ax = x + rcGetDirOffsetX(2);
  134. const int ay = y + rcGetDirOffsetY(2);
  135. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 2);
  136. const rcCompactSpan& as = chf.spans[ai];
  137. if (src[ai]+2 < src[i])
  138. src[i] = src[ai]+2;
  139. // (1,1)
  140. if (rcGetCon(as, 1) != RC_NOT_CONNECTED)
  141. {
  142. const int aax = ax + rcGetDirOffsetX(1);
  143. const int aay = ay + rcGetDirOffsetY(1);
  144. const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 1);
  145. if (src[aai]+3 < src[i])
  146. src[i] = src[aai]+3;
  147. }
  148. }
  149. if (rcGetCon(s, 1) != RC_NOT_CONNECTED)
  150. {
  151. // (0,1)
  152. const int ax = x + rcGetDirOffsetX(1);
  153. const int ay = y + rcGetDirOffsetY(1);
  154. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 1);
  155. const rcCompactSpan& as = chf.spans[ai];
  156. if (src[ai]+2 < src[i])
  157. src[i] = src[ai]+2;
  158. // (-1,1)
  159. if (rcGetCon(as, 0) != RC_NOT_CONNECTED)
  160. {
  161. const int aax = ax + rcGetDirOffsetX(0);
  162. const int aay = ay + rcGetDirOffsetY(0);
  163. const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 0);
  164. if (src[aai]+3 < src[i])
  165. src[i] = src[aai]+3;
  166. }
  167. }
  168. }
  169. }
  170. }
  171. maxDist = 0;
  172. for (int i = 0; i < chf.spanCount; ++i)
  173. maxDist = rcMax(src[i], maxDist);
  174. }
  175. static unsigned short* boxBlur(rcCompactHeightfield& chf, int thr,
  176. unsigned short* src, unsigned short* dst)
  177. {
  178. const int w = chf.width;
  179. const int h = chf.height;
  180. thr *= 2;
  181. for (int y = 0; y < h; ++y)
  182. {
  183. for (int x = 0; x < w; ++x)
  184. {
  185. const rcCompactCell& c = chf.cells[x+y*w];
  186. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  187. {
  188. const rcCompactSpan& s = chf.spans[i];
  189. const unsigned short cd = src[i];
  190. if (cd <= thr)
  191. {
  192. dst[i] = cd;
  193. continue;
  194. }
  195. int d = (int)cd;
  196. for (int dir = 0; dir < 4; ++dir)
  197. {
  198. if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
  199. {
  200. const int ax = x + rcGetDirOffsetX(dir);
  201. const int ay = y + rcGetDirOffsetY(dir);
  202. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
  203. d += (int)src[ai];
  204. const rcCompactSpan& as = chf.spans[ai];
  205. const int dir2 = (dir+1) & 0x3;
  206. if (rcGetCon(as, dir2) != RC_NOT_CONNECTED)
  207. {
  208. const int ax2 = ax + rcGetDirOffsetX(dir2);
  209. const int ay2 = ay + rcGetDirOffsetY(dir2);
  210. const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2);
  211. d += (int)src[ai2];
  212. }
  213. else
  214. {
  215. d += cd;
  216. }
  217. }
  218. else
  219. {
  220. d += cd*2;
  221. }
  222. }
  223. dst[i] = (unsigned short)((d+5)/9);
  224. }
  225. }
  226. }
  227. return dst;
  228. }
  229. static bool floodRegion(int x, int y, int i,
  230. unsigned short level, unsigned short r,
  231. rcCompactHeightfield& chf,
  232. unsigned short* srcReg, unsigned short* srcDist,
  233. rcTempVector<LevelStackEntry>& stack)
  234. {
  235. const int w = chf.width;
  236. const unsigned char area = chf.areas[i];
  237. // Flood fill mark region.
  238. stack.clear();
  239. stack.push_back(LevelStackEntry(x, y, i));
  240. srcReg[i] = r;
  241. srcDist[i] = 0;
  242. unsigned short lev = level >= 2 ? level-2 : 0;
  243. int count = 0;
  244. while (stack.size() > 0)
  245. {
  246. LevelStackEntry& back = stack.back();
  247. int cx = back.x;
  248. int cy = back.y;
  249. int ci = back.index;
  250. stack.pop_back();
  251. const rcCompactSpan& cs = chf.spans[ci];
  252. // Check if any of the neighbours already have a valid region set.
  253. unsigned short ar = 0;
  254. for (int dir = 0; dir < 4; ++dir)
  255. {
  256. // 8 connected
  257. if (rcGetCon(cs, dir) != RC_NOT_CONNECTED)
  258. {
  259. const int ax = cx + rcGetDirOffsetX(dir);
  260. const int ay = cy + rcGetDirOffsetY(dir);
  261. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(cs, dir);
  262. if (chf.areas[ai] != area)
  263. continue;
  264. unsigned short nr = srcReg[ai];
  265. if (nr & RC_BORDER_REG) // Do not take borders into account.
  266. continue;
  267. if (nr != 0 && nr != r)
  268. {
  269. ar = nr;
  270. break;
  271. }
  272. const rcCompactSpan& as = chf.spans[ai];
  273. const int dir2 = (dir+1) & 0x3;
  274. if (rcGetCon(as, dir2) != RC_NOT_CONNECTED)
  275. {
  276. const int ax2 = ax + rcGetDirOffsetX(dir2);
  277. const int ay2 = ay + rcGetDirOffsetY(dir2);
  278. const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2);
  279. if (chf.areas[ai2] != area)
  280. continue;
  281. unsigned short nr2 = srcReg[ai2];
  282. if (nr2 != 0 && nr2 != r)
  283. {
  284. ar = nr2;
  285. break;
  286. }
  287. }
  288. }
  289. }
  290. if (ar != 0)
  291. {
  292. srcReg[ci] = 0;
  293. continue;
  294. }
  295. count++;
  296. // Expand neighbours.
  297. for (int dir = 0; dir < 4; ++dir)
  298. {
  299. if (rcGetCon(cs, dir) != RC_NOT_CONNECTED)
  300. {
  301. const int ax = cx + rcGetDirOffsetX(dir);
  302. const int ay = cy + rcGetDirOffsetY(dir);
  303. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(cs, dir);
  304. if (chf.areas[ai] != area)
  305. continue;
  306. if (chf.dist[ai] >= lev && srcReg[ai] == 0)
  307. {
  308. srcReg[ai] = r;
  309. srcDist[ai] = 0;
  310. stack.push_back(LevelStackEntry(ax, ay, ai));
  311. }
  312. }
  313. }
  314. }
  315. return count > 0;
  316. }
  317. // Struct to keep track of entries in the region table that have been changed.
  318. struct DirtyEntry
  319. {
  320. DirtyEntry(int index_, unsigned short region_, unsigned short distance2_)
  321. : index(index_), region(region_), distance2(distance2_) {}
  322. int index;
  323. unsigned short region;
  324. unsigned short distance2;
  325. };
  326. static void expandRegions(int maxIter, unsigned short level,
  327. rcCompactHeightfield& chf,
  328. unsigned short* srcReg, unsigned short* srcDist,
  329. rcTempVector<LevelStackEntry>& stack,
  330. bool fillStack)
  331. {
  332. const int w = chf.width;
  333. const int h = chf.height;
  334. if (fillStack)
  335. {
  336. // Find cells revealed by the raised level.
  337. stack.clear();
  338. for (int y = 0; y < h; ++y)
  339. {
  340. for (int x = 0; x < w; ++x)
  341. {
  342. const rcCompactCell& c = chf.cells[x+y*w];
  343. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  344. {
  345. if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA)
  346. {
  347. stack.push_back(LevelStackEntry(x, y, i));
  348. }
  349. }
  350. }
  351. }
  352. }
  353. else // use cells in the input stack
  354. {
  355. // mark all cells which already have a region
  356. for (int j=0; j<stack.size(); j++)
  357. {
  358. int i = stack[j].index;
  359. if (srcReg[i] != 0)
  360. stack[j].index = -1;
  361. }
  362. }
  363. rcTempVector<DirtyEntry> dirtyEntries;
  364. int iter = 0;
  365. while (stack.size() > 0)
  366. {
  367. int failed = 0;
  368. dirtyEntries.clear();
  369. for (int j = 0; j < stack.size(); j++)
  370. {
  371. int x = stack[j].x;
  372. int y = stack[j].y;
  373. int i = stack[j].index;
  374. if (i < 0)
  375. {
  376. failed++;
  377. continue;
  378. }
  379. unsigned short r = srcReg[i];
  380. unsigned short d2 = 0xffff;
  381. const unsigned char area = chf.areas[i];
  382. const rcCompactSpan& s = chf.spans[i];
  383. for (int dir = 0; dir < 4; ++dir)
  384. {
  385. if (rcGetCon(s, dir) == RC_NOT_CONNECTED) continue;
  386. const int ax = x + rcGetDirOffsetX(dir);
  387. const int ay = y + rcGetDirOffsetY(dir);
  388. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
  389. if (chf.areas[ai] != area) continue;
  390. if (srcReg[ai] > 0 && (srcReg[ai] & RC_BORDER_REG) == 0)
  391. {
  392. if ((int)srcDist[ai]+2 < (int)d2)
  393. {
  394. r = srcReg[ai];
  395. d2 = srcDist[ai]+2;
  396. }
  397. }
  398. }
  399. if (r)
  400. {
  401. stack[j].index = -1; // mark as used
  402. dirtyEntries.push_back(DirtyEntry(i, r, d2));
  403. }
  404. else
  405. {
  406. failed++;
  407. }
  408. }
  409. // Copy entries that differ between src and dst to keep them in sync.
  410. for (int i = 0; i < dirtyEntries.size(); i++) {
  411. int idx = dirtyEntries[i].index;
  412. srcReg[idx] = dirtyEntries[i].region;
  413. srcDist[idx] = dirtyEntries[i].distance2;
  414. }
  415. if (failed == stack.size())
  416. break;
  417. if (level > 0)
  418. {
  419. ++iter;
  420. if (iter >= maxIter)
  421. break;
  422. }
  423. }
  424. }
  425. static void sortCellsByLevel(unsigned short startLevel,
  426. rcCompactHeightfield& chf,
  427. const unsigned short* srcReg,
  428. unsigned int nbStacks, rcTempVector<LevelStackEntry>* stacks,
  429. unsigned short loglevelsPerStack) // the levels per stack (2 in our case) as a bit shift
  430. {
  431. const int w = chf.width;
  432. const int h = chf.height;
  433. startLevel = startLevel >> loglevelsPerStack;
  434. for (unsigned int j=0; j<nbStacks; ++j)
  435. stacks[j].clear();
  436. // put all cells in the level range into the appropriate stacks
  437. for (int y = 0; y < h; ++y)
  438. {
  439. for (int x = 0; x < w; ++x)
  440. {
  441. const rcCompactCell& c = chf.cells[x+y*w];
  442. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  443. {
  444. if (chf.areas[i] == RC_NULL_AREA || srcReg[i] != 0)
  445. continue;
  446. int level = chf.dist[i] >> loglevelsPerStack;
  447. int sId = startLevel - level;
  448. if (sId >= (int)nbStacks)
  449. continue;
  450. if (sId < 0)
  451. sId = 0;
  452. stacks[sId].push_back(LevelStackEntry(x, y, i));
  453. }
  454. }
  455. }
  456. }
  457. static void appendStacks(const rcTempVector<LevelStackEntry>& srcStack,
  458. rcTempVector<LevelStackEntry>& dstStack,
  459. const unsigned short* srcReg)
  460. {
  461. for (int j=0; j<srcStack.size(); j++)
  462. {
  463. int i = srcStack[j].index;
  464. if ((i < 0) || (srcReg[i] != 0))
  465. continue;
  466. dstStack.push_back(srcStack[j]);
  467. }
  468. }
  469. struct rcRegion
  470. {
  471. inline rcRegion(unsigned short i) :
  472. spanCount(0),
  473. id(i),
  474. areaType(0),
  475. remap(false),
  476. visited(false),
  477. overlap(false),
  478. connectsToBorder(false),
  479. ymin(0xffff),
  480. ymax(0)
  481. {}
  482. int spanCount; // Number of spans belonging to this region
  483. unsigned short id; // ID of the region
  484. unsigned char areaType; // Are type.
  485. bool remap;
  486. bool visited;
  487. bool overlap;
  488. bool connectsToBorder;
  489. unsigned short ymin, ymax;
  490. rcIntArray connections;
  491. rcIntArray floors;
  492. };
  493. static void removeAdjacentNeighbours(rcRegion& reg)
  494. {
  495. // Remove adjacent duplicates.
  496. for (int i = 0; i < reg.connections.size() && reg.connections.size() > 1; )
  497. {
  498. int ni = (i+1) % reg.connections.size();
  499. if (reg.connections[i] == reg.connections[ni])
  500. {
  501. // Remove duplicate
  502. for (int j = i; j < reg.connections.size()-1; ++j)
  503. reg.connections[j] = reg.connections[j+1];
  504. reg.connections.pop();
  505. }
  506. else
  507. ++i;
  508. }
  509. }
  510. static void replaceNeighbour(rcRegion& reg, unsigned short oldId, unsigned short newId)
  511. {
  512. bool neiChanged = false;
  513. for (int i = 0; i < reg.connections.size(); ++i)
  514. {
  515. if (reg.connections[i] == oldId)
  516. {
  517. reg.connections[i] = newId;
  518. neiChanged = true;
  519. }
  520. }
  521. for (int i = 0; i < reg.floors.size(); ++i)
  522. {
  523. if (reg.floors[i] == oldId)
  524. reg.floors[i] = newId;
  525. }
  526. if (neiChanged)
  527. removeAdjacentNeighbours(reg);
  528. }
  529. static bool canMergeWithRegion(const rcRegion& rega, const rcRegion& regb)
  530. {
  531. if (rega.areaType != regb.areaType)
  532. return false;
  533. int n = 0;
  534. for (int i = 0; i < rega.connections.size(); ++i)
  535. {
  536. if (rega.connections[i] == regb.id)
  537. n++;
  538. }
  539. if (n > 1)
  540. return false;
  541. for (int i = 0; i < rega.floors.size(); ++i)
  542. {
  543. if (rega.floors[i] == regb.id)
  544. return false;
  545. }
  546. return true;
  547. }
  548. static void addUniqueFloorRegion(rcRegion& reg, int n)
  549. {
  550. for (int i = 0; i < reg.floors.size(); ++i)
  551. if (reg.floors[i] == n)
  552. return;
  553. reg.floors.push(n);
  554. }
  555. static bool mergeRegions(rcRegion& rega, rcRegion& regb)
  556. {
  557. unsigned short aid = rega.id;
  558. unsigned short bid = regb.id;
  559. // Duplicate current neighbourhood.
  560. rcIntArray acon;
  561. acon.resize(rega.connections.size());
  562. for (int i = 0; i < rega.connections.size(); ++i)
  563. acon[i] = rega.connections[i];
  564. rcIntArray& bcon = regb.connections;
  565. // Find insertion point on A.
  566. int insa = -1;
  567. for (int i = 0; i < acon.size(); ++i)
  568. {
  569. if (acon[i] == bid)
  570. {
  571. insa = i;
  572. break;
  573. }
  574. }
  575. if (insa == -1)
  576. return false;
  577. // Find insertion point on B.
  578. int insb = -1;
  579. for (int i = 0; i < bcon.size(); ++i)
  580. {
  581. if (bcon[i] == aid)
  582. {
  583. insb = i;
  584. break;
  585. }
  586. }
  587. if (insb == -1)
  588. return false;
  589. // Merge neighbours.
  590. rega.connections.resize(0);
  591. for (int i = 0, ni = acon.size(); i < ni-1; ++i)
  592. rega.connections.push(acon[(insa+1+i) % ni]);
  593. for (int i = 0, ni = bcon.size(); i < ni-1; ++i)
  594. rega.connections.push(bcon[(insb+1+i) % ni]);
  595. removeAdjacentNeighbours(rega);
  596. for (int j = 0; j < regb.floors.size(); ++j)
  597. addUniqueFloorRegion(rega, regb.floors[j]);
  598. rega.spanCount += regb.spanCount;
  599. regb.spanCount = 0;
  600. regb.connections.resize(0);
  601. return true;
  602. }
  603. static bool isRegionConnectedToBorder(const rcRegion& reg)
  604. {
  605. // Region is connected to border if
  606. // one of the neighbours is null id.
  607. for (int i = 0; i < reg.connections.size(); ++i)
  608. {
  609. if (reg.connections[i] == 0)
  610. return true;
  611. }
  612. return false;
  613. }
  614. static bool isSolidEdge(rcCompactHeightfield& chf, const unsigned short* srcReg,
  615. int x, int y, int i, int dir)
  616. {
  617. const rcCompactSpan& s = chf.spans[i];
  618. unsigned short r = 0;
  619. if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
  620. {
  621. const int ax = x + rcGetDirOffsetX(dir);
  622. const int ay = y + rcGetDirOffsetY(dir);
  623. const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir);
  624. r = srcReg[ai];
  625. }
  626. if (r == srcReg[i])
  627. return false;
  628. return true;
  629. }
  630. static void walkContour(int x, int y, int i, int dir,
  631. rcCompactHeightfield& chf,
  632. const unsigned short* srcReg,
  633. rcIntArray& cont)
  634. {
  635. int startDir = dir;
  636. int starti = i;
  637. const rcCompactSpan& ss = chf.spans[i];
  638. unsigned short curReg = 0;
  639. if (rcGetCon(ss, dir) != RC_NOT_CONNECTED)
  640. {
  641. const int ax = x + rcGetDirOffsetX(dir);
  642. const int ay = y + rcGetDirOffsetY(dir);
  643. const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(ss, dir);
  644. curReg = srcReg[ai];
  645. }
  646. cont.push(curReg);
  647. int iter = 0;
  648. while (++iter < 40000)
  649. {
  650. const rcCompactSpan& s = chf.spans[i];
  651. if (isSolidEdge(chf, srcReg, x, y, i, dir))
  652. {
  653. // Choose the edge corner
  654. unsigned short r = 0;
  655. if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
  656. {
  657. const int ax = x + rcGetDirOffsetX(dir);
  658. const int ay = y + rcGetDirOffsetY(dir);
  659. const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir);
  660. r = srcReg[ai];
  661. }
  662. if (r != curReg)
  663. {
  664. curReg = r;
  665. cont.push(curReg);
  666. }
  667. dir = (dir+1) & 0x3; // Rotate CW
  668. }
  669. else
  670. {
  671. int ni = -1;
  672. const int nx = x + rcGetDirOffsetX(dir);
  673. const int ny = y + rcGetDirOffsetY(dir);
  674. if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
  675. {
  676. const rcCompactCell& nc = chf.cells[nx+ny*chf.width];
  677. ni = (int)nc.index + rcGetCon(s, dir);
  678. }
  679. if (ni == -1)
  680. {
  681. // Should not happen.
  682. return;
  683. }
  684. x = nx;
  685. y = ny;
  686. i = ni;
  687. dir = (dir+3) & 0x3; // Rotate CCW
  688. }
  689. if (starti == i && startDir == dir)
  690. {
  691. break;
  692. }
  693. }
  694. // Remove adjacent duplicates.
  695. if (cont.size() > 1)
  696. {
  697. for (int j = 0; j < cont.size(); )
  698. {
  699. int nj = (j+1) % cont.size();
  700. if (cont[j] == cont[nj])
  701. {
  702. for (int k = j; k < cont.size()-1; ++k)
  703. cont[k] = cont[k+1];
  704. cont.pop();
  705. }
  706. else
  707. ++j;
  708. }
  709. }
  710. }
  711. static bool mergeAndFilterRegions(rcContext* ctx, int minRegionArea, int mergeRegionSize,
  712. unsigned short& maxRegionId,
  713. rcCompactHeightfield& chf,
  714. unsigned short* srcReg, rcIntArray& overlaps)
  715. {
  716. const int w = chf.width;
  717. const int h = chf.height;
  718. const int nreg = maxRegionId+1;
  719. rcTempVector<rcRegion> regions;
  720. if (!regions.reserve(nreg)) {
  721. ctx->log(RC_LOG_ERROR, "mergeAndFilterRegions: Out of memory 'regions' (%d).", nreg);
  722. return false;
  723. }
  724. // Construct regions
  725. for (int i = 0; i < nreg; ++i)
  726. regions.push_back(rcRegion((unsigned short) i));
  727. // Find edge of a region and find connections around the contour.
  728. for (int y = 0; y < h; ++y)
  729. {
  730. for (int x = 0; x < w; ++x)
  731. {
  732. const rcCompactCell& c = chf.cells[x+y*w];
  733. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  734. {
  735. unsigned short r = srcReg[i];
  736. if (r == 0 || r >= nreg)
  737. continue;
  738. rcRegion& reg = regions[r];
  739. reg.spanCount++;
  740. // Update floors.
  741. for (int j = (int)c.index; j < ni; ++j)
  742. {
  743. if (i == j) continue;
  744. unsigned short floorId = srcReg[j];
  745. if (floorId == 0 || floorId >= nreg)
  746. continue;
  747. if (floorId == r)
  748. reg.overlap = true;
  749. addUniqueFloorRegion(reg, floorId);
  750. }
  751. // Have found contour
  752. if (reg.connections.size() > 0)
  753. continue;
  754. reg.areaType = chf.areas[i];
  755. // Check if this cell is next to a border.
  756. int ndir = -1;
  757. for (int dir = 0; dir < 4; ++dir)
  758. {
  759. if (isSolidEdge(chf, srcReg, x, y, i, dir))
  760. {
  761. ndir = dir;
  762. break;
  763. }
  764. }
  765. if (ndir != -1)
  766. {
  767. // The cell is at border.
  768. // Walk around the contour to find all the neighbours.
  769. walkContour(x, y, i, ndir, chf, srcReg, reg.connections);
  770. }
  771. }
  772. }
  773. }
  774. // Remove too small regions.
  775. rcIntArray stack(32);
  776. rcIntArray trace(32);
  777. for (int i = 0; i < nreg; ++i)
  778. {
  779. rcRegion& reg = regions[i];
  780. if (reg.id == 0 || (reg.id & RC_BORDER_REG))
  781. continue;
  782. if (reg.spanCount == 0)
  783. continue;
  784. if (reg.visited)
  785. continue;
  786. // Count the total size of all the connected regions.
  787. // Also keep track of the regions connects to a tile border.
  788. bool connectsToBorder = false;
  789. int spanCount = 0;
  790. stack.resize(0);
  791. trace.resize(0);
  792. reg.visited = true;
  793. stack.push(i);
  794. while (stack.size())
  795. {
  796. // Pop
  797. int ri = stack.pop();
  798. rcRegion& creg = regions[ri];
  799. spanCount += creg.spanCount;
  800. trace.push(ri);
  801. for (int j = 0; j < creg.connections.size(); ++j)
  802. {
  803. if (creg.connections[j] & RC_BORDER_REG)
  804. {
  805. connectsToBorder = true;
  806. continue;
  807. }
  808. rcRegion& neireg = regions[creg.connections[j]];
  809. if (neireg.visited)
  810. continue;
  811. if (neireg.id == 0 || (neireg.id & RC_BORDER_REG))
  812. continue;
  813. // Visit
  814. stack.push(neireg.id);
  815. neireg.visited = true;
  816. }
  817. }
  818. // If the accumulated regions size is too small, remove it.
  819. // Do not remove areas which connect to tile borders
  820. // as their size cannot be estimated correctly and removing them
  821. // can potentially remove necessary areas.
  822. if (spanCount < minRegionArea && !connectsToBorder)
  823. {
  824. // Kill all visited regions.
  825. for (int j = 0; j < trace.size(); ++j)
  826. {
  827. regions[trace[j]].spanCount = 0;
  828. regions[trace[j]].id = 0;
  829. }
  830. }
  831. }
  832. // Merge too small regions to neighbour regions.
  833. int mergeCount = 0 ;
  834. do
  835. {
  836. mergeCount = 0;
  837. for (int i = 0; i < nreg; ++i)
  838. {
  839. rcRegion& reg = regions[i];
  840. if (reg.id == 0 || (reg.id & RC_BORDER_REG))
  841. continue;
  842. if (reg.overlap)
  843. continue;
  844. if (reg.spanCount == 0)
  845. continue;
  846. // Check to see if the region should be merged.
  847. if (reg.spanCount > mergeRegionSize && isRegionConnectedToBorder(reg))
  848. continue;
  849. // Small region with more than 1 connection.
  850. // Or region which is not connected to a border at all.
  851. // Find smallest neighbour region that connects to this one.
  852. int smallest = 0xfffffff;
  853. unsigned short mergeId = reg.id;
  854. for (int j = 0; j < reg.connections.size(); ++j)
  855. {
  856. if (reg.connections[j] & RC_BORDER_REG) continue;
  857. rcRegion& mreg = regions[reg.connections[j]];
  858. if (mreg.id == 0 || (mreg.id & RC_BORDER_REG) || mreg.overlap) continue;
  859. if (mreg.spanCount < smallest &&
  860. canMergeWithRegion(reg, mreg) &&
  861. canMergeWithRegion(mreg, reg))
  862. {
  863. smallest = mreg.spanCount;
  864. mergeId = mreg.id;
  865. }
  866. }
  867. // Found new id.
  868. if (mergeId != reg.id)
  869. {
  870. unsigned short oldId = reg.id;
  871. rcRegion& target = regions[mergeId];
  872. // Merge neighbours.
  873. if (mergeRegions(target, reg))
  874. {
  875. // Fixup regions pointing to current region.
  876. for (int j = 0; j < nreg; ++j)
  877. {
  878. if (regions[j].id == 0 || (regions[j].id & RC_BORDER_REG)) continue;
  879. // If another region was already merged into current region
  880. // change the nid of the previous region too.
  881. if (regions[j].id == oldId)
  882. regions[j].id = mergeId;
  883. // Replace the current region with the new one if the
  884. // current regions is neighbour.
  885. replaceNeighbour(regions[j], oldId, mergeId);
  886. }
  887. mergeCount++;
  888. }
  889. }
  890. }
  891. }
  892. while (mergeCount > 0);
  893. // Compress region Ids.
  894. for (int i = 0; i < nreg; ++i)
  895. {
  896. regions[i].remap = false;
  897. if (regions[i].id == 0) continue; // Skip nil regions.
  898. if (regions[i].id & RC_BORDER_REG) continue; // Skip external regions.
  899. regions[i].remap = true;
  900. }
  901. unsigned short regIdGen = 0;
  902. for (int i = 0; i < nreg; ++i)
  903. {
  904. if (!regions[i].remap)
  905. continue;
  906. unsigned short oldId = regions[i].id;
  907. unsigned short newId = ++regIdGen;
  908. for (int j = i; j < nreg; ++j)
  909. {
  910. if (regions[j].id == oldId)
  911. {
  912. regions[j].id = newId;
  913. regions[j].remap = false;
  914. }
  915. }
  916. }
  917. maxRegionId = regIdGen;
  918. // Remap regions.
  919. for (int i = 0; i < chf.spanCount; ++i)
  920. {
  921. if ((srcReg[i] & RC_BORDER_REG) == 0)
  922. srcReg[i] = regions[srcReg[i]].id;
  923. }
  924. // Return regions that we found to be overlapping.
  925. for (int i = 0; i < nreg; ++i)
  926. if (regions[i].overlap)
  927. overlaps.push(regions[i].id);
  928. return true;
  929. }
  930. static void addUniqueConnection(rcRegion& reg, int n)
  931. {
  932. for (int i = 0; i < reg.connections.size(); ++i)
  933. if (reg.connections[i] == n)
  934. return;
  935. reg.connections.push(n);
  936. }
  937. static bool mergeAndFilterLayerRegions(rcContext* ctx, int minRegionArea,
  938. unsigned short& maxRegionId,
  939. rcCompactHeightfield& chf,
  940. unsigned short* srcReg)
  941. {
  942. const int w = chf.width;
  943. const int h = chf.height;
  944. const int nreg = maxRegionId+1;
  945. rcTempVector<rcRegion> regions;
  946. // Construct regions
  947. if (!regions.reserve(nreg)) {
  948. ctx->log(RC_LOG_ERROR, "mergeAndFilterLayerRegions: Out of memory 'regions' (%d).", nreg);
  949. return false;
  950. }
  951. for (int i = 0; i < nreg; ++i)
  952. regions.push_back(rcRegion((unsigned short) i));
  953. // Find region neighbours and overlapping regions.
  954. rcIntArray lregs(32);
  955. for (int y = 0; y < h; ++y)
  956. {
  957. for (int x = 0; x < w; ++x)
  958. {
  959. const rcCompactCell& c = chf.cells[x+y*w];
  960. lregs.resize(0);
  961. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  962. {
  963. const rcCompactSpan& s = chf.spans[i];
  964. const unsigned short ri = srcReg[i];
  965. if (ri == 0 || ri >= nreg) continue;
  966. rcRegion& reg = regions[ri];
  967. reg.spanCount++;
  968. reg.ymin = rcMin(reg.ymin, s.y);
  969. reg.ymax = rcMax(reg.ymax, s.y);
  970. // Collect all region layers.
  971. lregs.push(ri);
  972. // Update neighbours
  973. for (int dir = 0; dir < 4; ++dir)
  974. {
  975. if (rcGetCon(s, dir) != RC_NOT_CONNECTED)
  976. {
  977. const int ax = x + rcGetDirOffsetX(dir);
  978. const int ay = y + rcGetDirOffsetY(dir);
  979. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir);
  980. const unsigned short rai = srcReg[ai];
  981. if (rai > 0 && rai < nreg && rai != ri)
  982. addUniqueConnection(reg, rai);
  983. if (rai & RC_BORDER_REG)
  984. reg.connectsToBorder = true;
  985. }
  986. }
  987. }
  988. // Update overlapping regions.
  989. for (int i = 0; i < lregs.size()-1; ++i)
  990. {
  991. for (int j = i+1; j < lregs.size(); ++j)
  992. {
  993. if (lregs[i] != lregs[j])
  994. {
  995. rcRegion& ri = regions[lregs[i]];
  996. rcRegion& rj = regions[lregs[j]];
  997. addUniqueFloorRegion(ri, lregs[j]);
  998. addUniqueFloorRegion(rj, lregs[i]);
  999. }
  1000. }
  1001. }
  1002. }
  1003. }
  1004. // Create 2D layers from regions.
  1005. unsigned short layerId = 1;
  1006. for (int i = 0; i < nreg; ++i)
  1007. regions[i].id = 0;
  1008. // Merge montone regions to create non-overlapping areas.
  1009. rcIntArray stack(32);
  1010. for (int i = 1; i < nreg; ++i)
  1011. {
  1012. rcRegion& root = regions[i];
  1013. // Skip already visited.
  1014. if (root.id != 0)
  1015. continue;
  1016. // Start search.
  1017. root.id = layerId;
  1018. stack.resize(0);
  1019. stack.push(i);
  1020. while (stack.size() > 0)
  1021. {
  1022. // Pop front
  1023. rcRegion& reg = regions[stack[0]];
  1024. for (int j = 0; j < stack.size()-1; ++j)
  1025. stack[j] = stack[j+1];
  1026. stack.resize(stack.size()-1);
  1027. const int ncons = (int)reg.connections.size();
  1028. for (int j = 0; j < ncons; ++j)
  1029. {
  1030. const int nei = reg.connections[j];
  1031. rcRegion& regn = regions[nei];
  1032. // Skip already visited.
  1033. if (regn.id != 0)
  1034. continue;
  1035. // Skip if the neighbour is overlapping root region.
  1036. bool overlap = false;
  1037. for (int k = 0; k < root.floors.size(); k++)
  1038. {
  1039. if (root.floors[k] == nei)
  1040. {
  1041. overlap = true;
  1042. break;
  1043. }
  1044. }
  1045. if (overlap)
  1046. continue;
  1047. // Deepen
  1048. stack.push(nei);
  1049. // Mark layer id
  1050. regn.id = layerId;
  1051. // Merge current layers to root.
  1052. for (int k = 0; k < regn.floors.size(); ++k)
  1053. addUniqueFloorRegion(root, regn.floors[k]);
  1054. root.ymin = rcMin(root.ymin, regn.ymin);
  1055. root.ymax = rcMax(root.ymax, regn.ymax);
  1056. root.spanCount += regn.spanCount;
  1057. regn.spanCount = 0;
  1058. root.connectsToBorder = root.connectsToBorder || regn.connectsToBorder;
  1059. }
  1060. }
  1061. layerId++;
  1062. }
  1063. // Remove small regions
  1064. for (int i = 0; i < nreg; ++i)
  1065. {
  1066. if (regions[i].spanCount > 0 && regions[i].spanCount < minRegionArea && !regions[i].connectsToBorder)
  1067. {
  1068. unsigned short reg = regions[i].id;
  1069. for (int j = 0; j < nreg; ++j)
  1070. if (regions[j].id == reg)
  1071. regions[j].id = 0;
  1072. }
  1073. }
  1074. // Compress region Ids.
  1075. for (int i = 0; i < nreg; ++i)
  1076. {
  1077. regions[i].remap = false;
  1078. if (regions[i].id == 0) continue; // Skip nil regions.
  1079. if (regions[i].id & RC_BORDER_REG) continue; // Skip external regions.
  1080. regions[i].remap = true;
  1081. }
  1082. unsigned short regIdGen = 0;
  1083. for (int i = 0; i < nreg; ++i)
  1084. {
  1085. if (!regions[i].remap)
  1086. continue;
  1087. unsigned short oldId = regions[i].id;
  1088. unsigned short newId = ++regIdGen;
  1089. for (int j = i; j < nreg; ++j)
  1090. {
  1091. if (regions[j].id == oldId)
  1092. {
  1093. regions[j].id = newId;
  1094. regions[j].remap = false;
  1095. }
  1096. }
  1097. }
  1098. maxRegionId = regIdGen;
  1099. // Remap regions.
  1100. for (int i = 0; i < chf.spanCount; ++i)
  1101. {
  1102. if ((srcReg[i] & RC_BORDER_REG) == 0)
  1103. srcReg[i] = regions[srcReg[i]].id;
  1104. }
  1105. return true;
  1106. }
  1107. /// @par
  1108. ///
  1109. /// This is usually the second to the last step in creating a fully built
  1110. /// compact heightfield. This step is required before regions are built
  1111. /// using #rcBuildRegions or #rcBuildRegionsMonotone.
  1112. ///
  1113. /// After this step, the distance data is available via the rcCompactHeightfield::maxDistance
  1114. /// and rcCompactHeightfield::dist fields.
  1115. ///
  1116. /// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone
  1117. bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf)
  1118. {
  1119. rcAssert(ctx);
  1120. rcScopedTimer timer(ctx, RC_TIMER_BUILD_DISTANCEFIELD);
  1121. if (chf.dist)
  1122. {
  1123. rcFree(chf.dist);
  1124. chf.dist = 0;
  1125. }
  1126. unsigned short* src = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP);
  1127. if (!src)
  1128. {
  1129. ctx->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'src' (%d).", chf.spanCount);
  1130. return false;
  1131. }
  1132. unsigned short* dst = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP);
  1133. if (!dst)
  1134. {
  1135. ctx->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'dst' (%d).", chf.spanCount);
  1136. rcFree(src);
  1137. return false;
  1138. }
  1139. unsigned short maxDist = 0;
  1140. {
  1141. rcScopedTimer timerDist(ctx, RC_TIMER_BUILD_DISTANCEFIELD_DIST);
  1142. calculateDistanceField(chf, src, maxDist);
  1143. chf.maxDistance = maxDist;
  1144. }
  1145. {
  1146. rcScopedTimer timerBlur(ctx, RC_TIMER_BUILD_DISTANCEFIELD_BLUR);
  1147. // Blur
  1148. if (boxBlur(chf, 1, src, dst) != src)
  1149. rcSwap(src, dst);
  1150. // Store distance.
  1151. chf.dist = src;
  1152. }
  1153. rcFree(dst);
  1154. return true;
  1155. }
  1156. static void paintRectRegion(int minx, int maxx, int miny, int maxy, unsigned short regId,
  1157. rcCompactHeightfield& chf, unsigned short* srcReg)
  1158. {
  1159. const int w = chf.width;
  1160. for (int y = miny; y < maxy; ++y)
  1161. {
  1162. for (int x = minx; x < maxx; ++x)
  1163. {
  1164. const rcCompactCell& c = chf.cells[x+y*w];
  1165. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  1166. {
  1167. if (chf.areas[i] != RC_NULL_AREA)
  1168. srcReg[i] = regId;
  1169. }
  1170. }
  1171. }
  1172. }
  1173. static const unsigned short RC_NULL_NEI = 0xffff;
  1174. struct rcSweepSpan
  1175. {
  1176. unsigned short rid; // row id
  1177. unsigned short id; // region id
  1178. unsigned short ns; // number samples
  1179. unsigned short nei; // neighbour id
  1180. };
  1181. /// @par
  1182. ///
  1183. /// Non-null regions will consist of connected, non-overlapping walkable spans that form a single contour.
  1184. /// Contours will form simple polygons.
  1185. ///
  1186. /// If multiple regions form an area that is smaller than @p minRegionArea, then all spans will be
  1187. /// re-assigned to the zero (null) region.
  1188. ///
  1189. /// Partitioning can result in smaller than necessary regions. @p mergeRegionArea helps
  1190. /// reduce unecessarily small regions.
  1191. ///
  1192. /// See the #rcConfig documentation for more information on the configuration parameters.
  1193. ///
  1194. /// The region data will be available via the rcCompactHeightfield::maxRegions
  1195. /// and rcCompactSpan::reg fields.
  1196. ///
  1197. /// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
  1198. ///
  1199. /// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
  1200. bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf,
  1201. const int borderSize, const int minRegionArea, const int mergeRegionArea)
  1202. {
  1203. rcAssert(ctx);
  1204. rcScopedTimer timer(ctx, RC_TIMER_BUILD_REGIONS);
  1205. const int w = chf.width;
  1206. const int h = chf.height;
  1207. unsigned short id = 1;
  1208. rcScopedDelete<unsigned short> srcReg((unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP));
  1209. if (!srcReg)
  1210. {
  1211. ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'src' (%d).", chf.spanCount);
  1212. return false;
  1213. }
  1214. memset(srcReg,0,sizeof(unsigned short)*chf.spanCount);
  1215. const int nsweeps = rcMax(chf.width,chf.height);
  1216. rcScopedDelete<rcSweepSpan> sweeps((rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP));
  1217. if (!sweeps)
  1218. {
  1219. ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'sweeps' (%d).", nsweeps);
  1220. return false;
  1221. }
  1222. // Mark border regions.
  1223. if (borderSize > 0)
  1224. {
  1225. // Make sure border will not overflow.
  1226. const int bw = rcMin(w, borderSize);
  1227. const int bh = rcMin(h, borderSize);
  1228. // Paint regions
  1229. paintRectRegion(0, bw, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
  1230. paintRectRegion(w-bw, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
  1231. paintRectRegion(0, w, 0, bh, id|RC_BORDER_REG, chf, srcReg); id++;
  1232. paintRectRegion(0, w, h-bh, h, id|RC_BORDER_REG, chf, srcReg); id++;
  1233. }
  1234. chf.borderSize = borderSize;
  1235. rcIntArray prev(256);
  1236. // Sweep one line at a time.
  1237. for (int y = borderSize; y < h-borderSize; ++y)
  1238. {
  1239. // Collect spans from this row.
  1240. prev.resize(id+1);
  1241. memset(&prev[0],0,sizeof(int)*id);
  1242. unsigned short rid = 1;
  1243. for (int x = borderSize; x < w-borderSize; ++x)
  1244. {
  1245. const rcCompactCell& c = chf.cells[x+y*w];
  1246. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  1247. {
  1248. const rcCompactSpan& s = chf.spans[i];
  1249. if (chf.areas[i] == RC_NULL_AREA) continue;
  1250. // -x
  1251. unsigned short previd = 0;
  1252. if (rcGetCon(s, 0) != RC_NOT_CONNECTED)
  1253. {
  1254. const int ax = x + rcGetDirOffsetX(0);
  1255. const int ay = y + rcGetDirOffsetY(0);
  1256. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0);
  1257. if ((srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
  1258. previd = srcReg[ai];
  1259. }
  1260. if (!previd)
  1261. {
  1262. previd = rid++;
  1263. sweeps[previd].rid = previd;
  1264. sweeps[previd].ns = 0;
  1265. sweeps[previd].nei = 0;
  1266. }
  1267. // -y
  1268. if (rcGetCon(s,3) != RC_NOT_CONNECTED)
  1269. {
  1270. const int ax = x + rcGetDirOffsetX(3);
  1271. const int ay = y + rcGetDirOffsetY(3);
  1272. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3);
  1273. if (srcReg[ai] && (srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
  1274. {
  1275. unsigned short nr = srcReg[ai];
  1276. if (!sweeps[previd].nei || sweeps[previd].nei == nr)
  1277. {
  1278. sweeps[previd].nei = nr;
  1279. sweeps[previd].ns++;
  1280. prev[nr]++;
  1281. }
  1282. else
  1283. {
  1284. sweeps[previd].nei = RC_NULL_NEI;
  1285. }
  1286. }
  1287. }
  1288. srcReg[i] = previd;
  1289. }
  1290. }
  1291. // Create unique ID.
  1292. for (int i = 1; i < rid; ++i)
  1293. {
  1294. if (sweeps[i].nei != RC_NULL_NEI && sweeps[i].nei != 0 &&
  1295. prev[sweeps[i].nei] == (int)sweeps[i].ns)
  1296. {
  1297. sweeps[i].id = sweeps[i].nei;
  1298. }
  1299. else
  1300. {
  1301. sweeps[i].id = id++;
  1302. }
  1303. }
  1304. // Remap IDs
  1305. for (int x = borderSize; x < w-borderSize; ++x)
  1306. {
  1307. const rcCompactCell& c = chf.cells[x+y*w];
  1308. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  1309. {
  1310. if (srcReg[i] > 0 && srcReg[i] < rid)
  1311. srcReg[i] = sweeps[srcReg[i]].id;
  1312. }
  1313. }
  1314. }
  1315. {
  1316. rcScopedTimer timerFilter(ctx, RC_TIMER_BUILD_REGIONS_FILTER);
  1317. // Merge regions and filter out small regions.
  1318. rcIntArray overlaps;
  1319. chf.maxRegions = id;
  1320. if (!mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg, overlaps))
  1321. return false;
  1322. // Monotone partitioning does not generate overlapping regions.
  1323. }
  1324. // Store the result out.
  1325. for (int i = 0; i < chf.spanCount; ++i)
  1326. chf.spans[i].reg = srcReg[i];
  1327. return true;
  1328. }
  1329. /// @par
  1330. ///
  1331. /// Non-null regions will consist of connected, non-overlapping walkable spans that form a single contour.
  1332. /// Contours will form simple polygons.
  1333. ///
  1334. /// If multiple regions form an area that is smaller than @p minRegionArea, then all spans will be
  1335. /// re-assigned to the zero (null) region.
  1336. ///
  1337. /// Watershed partitioning can result in smaller than necessary regions, especially in diagonal corridors.
  1338. /// @p mergeRegionArea helps reduce unecessarily small regions.
  1339. ///
  1340. /// See the #rcConfig documentation for more information on the configuration parameters.
  1341. ///
  1342. /// The region data will be available via the rcCompactHeightfield::maxRegions
  1343. /// and rcCompactSpan::reg fields.
  1344. ///
  1345. /// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions.
  1346. ///
  1347. /// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig
  1348. bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf,
  1349. const int borderSize, const int minRegionArea, const int mergeRegionArea)
  1350. {
  1351. rcAssert(ctx);
  1352. rcScopedTimer timer(ctx, RC_TIMER_BUILD_REGIONS);
  1353. const int w = chf.width;
  1354. const int h = chf.height;
  1355. rcScopedDelete<unsigned short> buf((unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount*2, RC_ALLOC_TEMP));
  1356. if (!buf)
  1357. {
  1358. ctx->log(RC_LOG_ERROR, "rcBuildRegions: Out of memory 'tmp' (%d).", chf.spanCount*4);
  1359. return false;
  1360. }
  1361. ctx->startTimer(RC_TIMER_BUILD_REGIONS_WATERSHED);
  1362. const int LOG_NB_STACKS = 3;
  1363. const int NB_STACKS = 1 << LOG_NB_STACKS;
  1364. rcTempVector<LevelStackEntry> lvlStacks[NB_STACKS];
  1365. for (int i=0; i<NB_STACKS; ++i)
  1366. lvlStacks[i].reserve(256);
  1367. rcTempVector<LevelStackEntry> stack;
  1368. stack.reserve(256);
  1369. unsigned short* srcReg = buf;
  1370. unsigned short* srcDist = buf+chf.spanCount;
  1371. memset(srcReg, 0, sizeof(unsigned short)*chf.spanCount);
  1372. memset(srcDist, 0, sizeof(unsigned short)*chf.spanCount);
  1373. unsigned short regionId = 1;
  1374. unsigned short level = (chf.maxDistance+1) & ~1;
  1375. // TODO: Figure better formula, expandIters defines how much the
  1376. // watershed "overflows" and simplifies the regions. Tying it to
  1377. // agent radius was usually good indication how greedy it could be.
  1378. // const int expandIters = 4 + walkableRadius * 2;
  1379. const int expandIters = 8;
  1380. if (borderSize > 0)
  1381. {
  1382. // Make sure border will not overflow.
  1383. const int bw = rcMin(w, borderSize);
  1384. const int bh = rcMin(h, borderSize);
  1385. // Paint regions
  1386. paintRectRegion(0, bw, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
  1387. paintRectRegion(w-bw, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
  1388. paintRectRegion(0, w, 0, bh, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
  1389. paintRectRegion(0, w, h-bh, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++;
  1390. }
  1391. chf.borderSize = borderSize;
  1392. int sId = -1;
  1393. while (level > 0)
  1394. {
  1395. level = level >= 2 ? level-2 : 0;
  1396. sId = (sId+1) & (NB_STACKS-1);
  1397. // ctx->startTimer(RC_TIMER_DIVIDE_TO_LEVELS);
  1398. if (sId == 0)
  1399. sortCellsByLevel(level, chf, srcReg, NB_STACKS, lvlStacks, 1);
  1400. else
  1401. appendStacks(lvlStacks[sId-1], lvlStacks[sId], srcReg); // copy left overs from last level
  1402. // ctx->stopTimer(RC_TIMER_DIVIDE_TO_LEVELS);
  1403. {
  1404. rcScopedTimer timerExpand(ctx, RC_TIMER_BUILD_REGIONS_EXPAND);
  1405. // Expand current regions until no empty connected cells found.
  1406. expandRegions(expandIters, level, chf, srcReg, srcDist, lvlStacks[sId], false);
  1407. }
  1408. {
  1409. rcScopedTimer timerFloor(ctx, RC_TIMER_BUILD_REGIONS_FLOOD);
  1410. // Mark new regions with IDs.
  1411. for (int j = 0; j<lvlStacks[sId].size(); j++)
  1412. {
  1413. LevelStackEntry current = lvlStacks[sId][j];
  1414. int x = current.x;
  1415. int y = current.y;
  1416. int i = current.index;
  1417. if (i >= 0 && srcReg[i] == 0)
  1418. {
  1419. if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack))
  1420. {
  1421. if (regionId == 0xFFFF)
  1422. {
  1423. ctx->log(RC_LOG_ERROR, "rcBuildRegions: Region ID overflow");
  1424. return false;
  1425. }
  1426. regionId++;
  1427. }
  1428. }
  1429. }
  1430. }
  1431. }
  1432. // Expand current regions until no empty connected cells found.
  1433. expandRegions(expandIters*8, 0, chf, srcReg, srcDist, stack, true);
  1434. ctx->stopTimer(RC_TIMER_BUILD_REGIONS_WATERSHED);
  1435. {
  1436. rcScopedTimer timerFilter(ctx, RC_TIMER_BUILD_REGIONS_FILTER);
  1437. // Merge regions and filter out smalle regions.
  1438. rcIntArray overlaps;
  1439. chf.maxRegions = regionId;
  1440. if (!mergeAndFilterRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg, overlaps))
  1441. return false;
  1442. // If overlapping regions were found during merging, split those regions.
  1443. if (overlaps.size() > 0)
  1444. {
  1445. ctx->log(RC_LOG_ERROR, "rcBuildRegions: %d overlapping regions.", overlaps.size());
  1446. }
  1447. }
  1448. // Write the result out.
  1449. for (int i = 0; i < chf.spanCount; ++i)
  1450. chf.spans[i].reg = srcReg[i];
  1451. return true;
  1452. }
  1453. bool rcBuildLayerRegions(rcContext* ctx, rcCompactHeightfield& chf,
  1454. const int borderSize, const int minRegionArea)
  1455. {
  1456. rcAssert(ctx);
  1457. rcScopedTimer timer(ctx, RC_TIMER_BUILD_REGIONS);
  1458. const int w = chf.width;
  1459. const int h = chf.height;
  1460. unsigned short id = 1;
  1461. rcScopedDelete<unsigned short> srcReg((unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP));
  1462. if (!srcReg)
  1463. {
  1464. ctx->log(RC_LOG_ERROR, "rcBuildLayerRegions: Out of memory 'src' (%d).", chf.spanCount);
  1465. return false;
  1466. }
  1467. memset(srcReg,0,sizeof(unsigned short)*chf.spanCount);
  1468. const int nsweeps = rcMax(chf.width,chf.height);
  1469. rcScopedDelete<rcSweepSpan> sweeps((rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP));
  1470. if (!sweeps)
  1471. {
  1472. ctx->log(RC_LOG_ERROR, "rcBuildLayerRegions: Out of memory 'sweeps' (%d).", nsweeps);
  1473. return false;
  1474. }
  1475. // Mark border regions.
  1476. if (borderSize > 0)
  1477. {
  1478. // Make sure border will not overflow.
  1479. const int bw = rcMin(w, borderSize);
  1480. const int bh = rcMin(h, borderSize);
  1481. // Paint regions
  1482. paintRectRegion(0, bw, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
  1483. paintRectRegion(w-bw, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++;
  1484. paintRectRegion(0, w, 0, bh, id|RC_BORDER_REG, chf, srcReg); id++;
  1485. paintRectRegion(0, w, h-bh, h, id|RC_BORDER_REG, chf, srcReg); id++;
  1486. }
  1487. chf.borderSize = borderSize;
  1488. rcIntArray prev(256);
  1489. // Sweep one line at a time.
  1490. for (int y = borderSize; y < h-borderSize; ++y)
  1491. {
  1492. // Collect spans from this row.
  1493. prev.resize(id+1);
  1494. memset(&prev[0],0,sizeof(int)*id);
  1495. unsigned short rid = 1;
  1496. for (int x = borderSize; x < w-borderSize; ++x)
  1497. {
  1498. const rcCompactCell& c = chf.cells[x+y*w];
  1499. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  1500. {
  1501. const rcCompactSpan& s = chf.spans[i];
  1502. if (chf.areas[i] == RC_NULL_AREA) continue;
  1503. // -x
  1504. unsigned short previd = 0;
  1505. if (rcGetCon(s, 0) != RC_NOT_CONNECTED)
  1506. {
  1507. const int ax = x + rcGetDirOffsetX(0);
  1508. const int ay = y + rcGetDirOffsetY(0);
  1509. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0);
  1510. if ((srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
  1511. previd = srcReg[ai];
  1512. }
  1513. if (!previd)
  1514. {
  1515. previd = rid++;
  1516. sweeps[previd].rid = previd;
  1517. sweeps[previd].ns = 0;
  1518. sweeps[previd].nei = 0;
  1519. }
  1520. // -y
  1521. if (rcGetCon(s,3) != RC_NOT_CONNECTED)
  1522. {
  1523. const int ax = x + rcGetDirOffsetX(3);
  1524. const int ay = y + rcGetDirOffsetY(3);
  1525. const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3);
  1526. if (srcReg[ai] && (srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai])
  1527. {
  1528. unsigned short nr = srcReg[ai];
  1529. if (!sweeps[previd].nei || sweeps[previd].nei == nr)
  1530. {
  1531. sweeps[previd].nei = nr;
  1532. sweeps[previd].ns++;
  1533. prev[nr]++;
  1534. }
  1535. else
  1536. {
  1537. sweeps[previd].nei = RC_NULL_NEI;
  1538. }
  1539. }
  1540. }
  1541. srcReg[i] = previd;
  1542. }
  1543. }
  1544. // Create unique ID.
  1545. for (int i = 1; i < rid; ++i)
  1546. {
  1547. if (sweeps[i].nei != RC_NULL_NEI && sweeps[i].nei != 0 &&
  1548. prev[sweeps[i].nei] == (int)sweeps[i].ns)
  1549. {
  1550. sweeps[i].id = sweeps[i].nei;
  1551. }
  1552. else
  1553. {
  1554. sweeps[i].id = id++;
  1555. }
  1556. }
  1557. // Remap IDs
  1558. for (int x = borderSize; x < w-borderSize; ++x)
  1559. {
  1560. const rcCompactCell& c = chf.cells[x+y*w];
  1561. for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i)
  1562. {
  1563. if (srcReg[i] > 0 && srcReg[i] < rid)
  1564. srcReg[i] = sweeps[srcReg[i]].id;
  1565. }
  1566. }
  1567. }
  1568. {
  1569. rcScopedTimer timerFilter(ctx, RC_TIMER_BUILD_REGIONS_FILTER);
  1570. // Merge monotone regions to layers and remove small regions.
  1571. chf.maxRegions = id;
  1572. if (!mergeAndFilterLayerRegions(ctx, minRegionArea, chf.maxRegions, chf, srcReg))
  1573. return false;
  1574. }
  1575. // Store the result out.
  1576. for (int i = 0; i < chf.spanCount; ++i)
  1577. chf.spans[i].reg = srcReg[i];
  1578. return true;
  1579. }