Area.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace Game{
  5. /******************************************************************************/
  6. // AREA OBJECT
  7. /******************************************************************************/
  8. Bool Area::Data::AreaObj::save(File &f, CChar *path)C
  9. {
  10. f.cmpUIntV(0); // version
  11. f<<id;
  12. if(super::saveData(f, path))
  13. return f.ok();
  14. return false;
  15. }
  16. Bool Area::Data::AreaObj::load(File &f, CChar *path)
  17. {
  18. switch(f.decUIntV())
  19. {
  20. case 0:
  21. {
  22. f>>id;
  23. if(super::loadData(f, path))
  24. if(f.ok())return true;
  25. }break;
  26. }
  27. return false;
  28. }
  29. Bool Area::Data::AreaObj::loadOld(File &f)
  30. {
  31. id.randomize();
  32. if(super::loadData(f))
  33. if(f.ok())return true;
  34. return false;
  35. }
  36. /******************************************************************************/
  37. // AREA PATH
  38. /******************************************************************************/
  39. void AreaPath2D::zero()
  40. {
  41. _changed=false;
  42. _groups =0;
  43. }
  44. AreaPath2D::AreaPath2D() {zero();}
  45. void AreaPath2D::del()
  46. {
  47. _map.del();
  48. _neighbor.del();
  49. zero();
  50. }
  51. void AreaPath2D::create(Int size)
  52. {
  53. _map.createSoftTry(size, size, 1, IMAGE_I8);
  54. _map.clear();
  55. group();
  56. }
  57. void AreaPath2D::createFromQuarter(AreaPath2D &src, Bool right, Bool forward, WorldSettings &settings)
  58. {
  59. src._map.crop(_map, right ? src._map.w()/2 : 0, forward ? src._map.h()/2 : 0, src._map.w()/2, src._map.h()/2);
  60. _map.resize(settings.path2DRes(), settings.path2DRes(), FILTER_NONE);
  61. group();
  62. }
  63. void AreaPath2D::createFromQuad(AreaPath2D *lb, AreaPath2D *rb, AreaPath2D *lf, AreaPath2D *rf, WorldSettings &settings)
  64. {
  65. create(settings.path2DRes());
  66. REPD(y, _map.h())
  67. REPD(x, _map.w())
  68. {
  69. AreaPath2D *src=null;
  70. Bool right =(x>=(_map.w()/2)), // if right half should be taken
  71. forward=(y>=(_map.h()/2)); // if forward half should be taken
  72. if(right)
  73. {
  74. if(forward)src=rf;else src=rb;
  75. }
  76. else // left
  77. {
  78. if(forward)src=lf;else src=lb;
  79. }
  80. if(src)
  81. {
  82. Int src_x=((right ? x-_map.w()/2 : x)*src->_map.w())/(_map.w()/2),
  83. src_y=((forward ? y-_map.h()/2 : y)*src->_map.h())/(_map.h()/2);
  84. _map.pixel(x, y, src->_map.pixel(src_x, src_y));
  85. }
  86. }
  87. group();
  88. }
  89. /******************************************************************************/
  90. Bool AreaPath2D::walkable(Int x, Int y)C
  91. {
  92. return (InRange(x, _map.w()) && InRange(y, _map.h())) ? _map.pixB(x, y)!=0xFF : false;
  93. }
  94. AreaPath2D& AreaPath2D::walkable(Int x, Int y, Bool walkable)
  95. {
  96. if(InRange(x, _map.w())
  97. && InRange(y, _map.h()))
  98. {
  99. _map.pixB(x, y)=(walkable ? 0xFE : 0xFF);
  100. _changed=true;
  101. }
  102. return T;
  103. }
  104. /******************************************************************************/
  105. Bool AreaPath2D::fullyWalkable()
  106. {
  107. REPD(y, _map.h())
  108. REPD(x, _map.w())if(!walkable(x, y))return false;
  109. return true;
  110. }
  111. /******************************************************************************/
  112. void AreaPath2D::group()
  113. {
  114. // set groups
  115. {
  116. #define BLOCKED 0xFFFF
  117. UShort path [MAX_PATH_RES][MAX_PATH_RES], // [y][x]
  118. new_group[65536];
  119. Bool parent [65536];
  120. // set map
  121. Int groups=0;
  122. REPD(y, _map.h())
  123. REPD(x, _map.w())path[y][x]=(walkable(x, y) ? groups++ : BLOCKED);
  124. // set group remap
  125. REP(groups)new_group[i]=i;
  126. // join
  127. REP((Max(_map.w(), _map.h())>=48) ? 3 : 2) // steps
  128. {
  129. REP(groups)parent[i]=false;
  130. // link with neighbors
  131. FREPD(y, _map.h())
  132. FREPD(x, _map.w())
  133. {
  134. UInt g=path[y][x];
  135. if( g!=BLOCKED && new_group[g]==g) // it's not blocked and it's a main group (it can be linked)
  136. {
  137. Bool right=false, left=false, up=false, down=false;
  138. Int r =x+1 , l =x-1 , u =y+1 , d =y-1 ;
  139. // try linking right
  140. if(InRange(r, _map.w()))
  141. {
  142. UInt n =path[y][r]; // neighbor
  143. if( n!=BLOCKED)
  144. {
  145. right=true;
  146. if(n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
  147. }
  148. }
  149. // try linking up
  150. if(InRange(u, _map.h()))
  151. {
  152. UInt n =path[u][x]; // neighbor
  153. if( n!=BLOCKED)
  154. {
  155. up=true;
  156. if(n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
  157. }
  158. }
  159. #if 0
  160. // try linking left
  161. if(InRange(l, _map.w()))
  162. {
  163. UInt n =path[y][l]; // neighbor
  164. if( n!=BLOCKED)
  165. {
  166. left=true;
  167. if(n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
  168. }
  169. }
  170. // try linking down
  171. if(InRange(d, _map.h()))
  172. {
  173. UInt n =path[d][x]; // neighbor
  174. if( n!=BLOCKED)
  175. {
  176. down=true;
  177. if(n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
  178. }
  179. }
  180. #endif
  181. // try linking diagonal
  182. #if 1
  183. if(right || up)if(InRange(r, _map.w()) && InRange(u, _map.h()))
  184. {
  185. UInt n =path[u][r]; // neighbor
  186. if( n!=BLOCKED && n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
  187. }
  188. #if 0
  189. if(left || up)if(InRange(l, AREA_PATH_RES) && InRange(u, AREA_PATH_RES))
  190. {
  191. UInt n =path[u][l]; // neighbor
  192. if( n!=BLOCKED && n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
  193. }
  194. if(right || down)if(InRange(r, AREA_PATH_RES) && InRange(d, AREA_PATH_RES))
  195. {
  196. UInt n =path[d][r]; // neighbor
  197. if( n!=BLOCKED && n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
  198. }
  199. if(left || down)if(InRange(l, AREA_PATH_RES) && InRange(d, AREA_PATH_RES))
  200. {
  201. UInt n =path[d][l]; // neighbor
  202. if( n!=BLOCKED && n!=g && new_group[n]==n && !parent[n]){new_group[n]=g; parent[g]=true;} // link
  203. }
  204. #endif
  205. #endif
  206. }
  207. }
  208. // update groups map
  209. REPD(y, _map.h())
  210. REPD(x, _map.w())
  211. {
  212. UInt g =path[y][x];
  213. if( g!=BLOCKED)path[y][x]=new_group[g];
  214. }
  215. }
  216. // set target map
  217. T._groups=0;
  218. REP(groups)new_group[i]=BLOCKED; // set not yet added to target 'path' map
  219. REPD(y, _map.h())
  220. REPD(x, _map.w())
  221. {
  222. UInt g =path[y][x];
  223. if( g!=BLOCKED)
  224. {
  225. UShort &n=new_group[g];
  226. if( n==BLOCKED)n=T._groups++; // not yet added
  227. _map.pixB(x, y)=n; // set target map
  228. }
  229. }
  230. }
  231. // find neighbors
  232. VecI2 offset[]=
  233. {
  234. VecI2(-1, 1),
  235. VecI2( 0, 1),
  236. VecI2( 1, 1),
  237. VecI2(-1, 0),
  238. };
  239. _neighbor.clear();
  240. REPD(y, _map.h())
  241. REPD(x, _map.w())
  242. {
  243. Int a =_map.pixB(x, y);
  244. if( a!=0xFF)
  245. {
  246. REPA(offset)
  247. {
  248. Int sx=x+offset[i].x,
  249. sy=y+offset[i].y;
  250. if(InRange(sx, _map.w())
  251. && InRange(sy, _map.h()))
  252. {
  253. Int b =_map.pixB(sx,sy);
  254. if( b!=0xFF && a!=b)
  255. {
  256. Byte cost=5;
  257. if(offset[i].x && offset[i].y) // if diagonal
  258. {
  259. // if blocked diagonal
  260. if(!walkable(sx, y)
  261. && !walkable( x, sy))continue; // don't add
  262. cost=7; // increase the movement cost
  263. }
  264. // check if the neighbor entry already exists
  265. Int min, max; MinMax(a, b, min, max);
  266. REPA(_neighbor)
  267. {
  268. Neighbor &n=_neighbor[i];
  269. if(n.a==min && n.b==max){MIN(n.cost, cost); goto exists;}
  270. }
  271. _neighbor.New().set(min, max, cost);
  272. exists:;
  273. }
  274. }
  275. }
  276. }
  277. }
  278. _changed=false;
  279. }
  280. /******************************************************************************/
  281. void AreaPath2D::resize(Int size)
  282. {
  283. _map.resize(size, size, FILTER_NONE);
  284. group();
  285. }
  286. /******************************************************************************/
  287. Bool AreaPath2D::save(File &f)C
  288. {
  289. f.cmpUIntV(1); // version
  290. f<<_groups;
  291. if(_map . save (f))
  292. if(_neighbor._saveRaw(f))
  293. return f.ok();
  294. return false;
  295. }
  296. Bool AreaPath2D::load(File &f)
  297. {
  298. _changed=false;
  299. switch(f.decUIntV()) // version
  300. {
  301. case 1:
  302. {
  303. f>>_groups;
  304. if(_map . load (f))
  305. if(_neighbor._loadRaw(f))
  306. if(f.ok())return true;
  307. }break;
  308. case 0:
  309. {
  310. Byte path[32][32]; // [y][x]
  311. f>>path>>_groups;
  312. if(_neighbor._loadRaw(f))
  313. if(_map.createSoftTry(32, 32, 1, IMAGE_I8))
  314. {
  315. REPD(y, _map.h())
  316. REPD(x, _map.w())_map.pixB(x, y)=path[y][x];
  317. if(f.ok())return true;
  318. }
  319. }break;
  320. }
  321. del(); return false;
  322. }
  323. /******************************************************************************/
  324. // AREA DATA
  325. /******************************************************************************/
  326. Area::Data::~Data()
  327. {
  328. Delete(_path_mesh);
  329. Delete(_path2D );
  330. }
  331. Area::Data::Data(Area &area)
  332. {
  333. T._area =&area;
  334. T._path_mesh=null;
  335. T._path2D =null;
  336. T._path_node_offset=0;
  337. }
  338. Bool Area::Data::save(File &f)
  339. {
  340. ChunkWriter cw(f);
  341. if(height.is() || material_map.is() || materials.elms())if(File *f=cw.beginChunk("Heightmap", 0))
  342. {
  343. if(!height .save(*f))return false;
  344. if(!material_map.save(*f))return false;
  345. f->putInt(materials.elms()); REPA(materials)f->_putStr(materials[i].name());
  346. }
  347. if(mesh .is ())if(File *f=cw.beginChunk("Mesh" , 0))if(!mesh.save(*f))return false;
  348. if(phys .is ())if(File *f=cw.beginChunk("Phys" , 0))if(!phys.save(*f))return false;
  349. if(objs .elms())if(File *f=cw.beginChunk("Object" , 1))FREPA(objs)if(!objs[i].save(*f))return false;
  350. if(decals .elms())if(File *f=cw.beginChunk("Decal" , 0))if(!decals ._save(*f))return false;
  351. if(mesh_overlays.elms())if(File *f=cw.beginChunk("Mesh Overlay", 0))if(!mesh_overlays._save(*f))return false;
  352. if(_path_mesh )if(File *f=cw.beginChunk("PathMesh" , 0))if(!_path_mesh -> save(*f))return false;
  353. if(_path2D )if(File *f=cw.beginChunk("AreaPath" , 0))if(!_path2D -> save(*f))return false;
  354. if(waters .elms())if(File *f=cw.beginChunk("Water" , 0))if(!waters ._save(*f))return false;
  355. if(!customSave(cw))return false;
  356. cw.endChunkList();
  357. return f.ok();
  358. }
  359. Bool Area::Data::load(File &f)
  360. {
  361. for(ChunkReader cr(f); File *f=cr();)
  362. {
  363. if(cr.name()=="HeightmapMesh")switch(cr.ver())
  364. {
  365. case 0: mesh.loadAdd(*f); break;
  366. }else
  367. if(cr.name()=="HeightmapPhys")switch(cr.ver())
  368. {
  369. case 0: phys.loadAdd(*f); break;
  370. }else
  371. if(cr.name()=="ObjectMesh")switch(cr.ver())
  372. {
  373. case 0: mesh.loadAdd(*f); break;
  374. }else
  375. if(cr.name()=="ObjectPhys")switch(cr.ver())
  376. {
  377. case 0: phys.loadAdd(*f); break;
  378. }else
  379. if(cr.name()=="Heightmap")switch(cr.ver())
  380. {
  381. case 0: if(!height.load(*f))break; if(!material_map.load(*f))break; materials.setNum(f->getInt()); REPAO(materials)=f->_getStr(); break;
  382. }else
  383. if(cr.name()=="Mesh")switch(cr.ver())
  384. {
  385. case 0: mesh.loadAdd(*f); break;
  386. }else
  387. if(cr.name()=="Phys")switch(cr.ver())
  388. {
  389. case 0: phys.loadAdd(*f); break;
  390. }else
  391. if(cr.name()=="Object")switch(cr.ver())
  392. {
  393. case 1: for(; !f->end(); )if(!objs.New().load (*f)){objs.removeLast(); break;} break;
  394. case 0: for(; !f->end(); )if(!objs.New().loadOld(*f)){objs.removeLast(); break;} break;
  395. }else
  396. if(cr.name()=="Decal")switch(cr.ver())
  397. {
  398. case 0: decals._load(*f); break;
  399. }else
  400. if(cr.name()=="Mesh Overlay")switch(cr.ver())
  401. {
  402. case 0: mesh_overlays._load(*f); break;
  403. }else
  404. if(cr.name()=="PathMesh")switch(cr.ver())
  405. {
  406. case 0: New(Delete(_path_mesh))->load(*f); break;
  407. }else
  408. if(cr.name()=="AreaPath")switch(cr.ver())
  409. {
  410. case 0: New(Delete(_path2D))->load(*f); break;
  411. }else
  412. if(cr.name()=="Water")switch(cr.ver())
  413. {
  414. case 0: waters._load(*f); break;
  415. }else
  416. {
  417. customLoad(*f, cr.name(), cr.ver());
  418. }
  419. }
  420. // setup terrain/foliage objects (these containers should not be saved, because they are dynamically created from 'objs' which are already stored)
  421. terrain_objs_box.zero(); Bool have_terrain_box=false, have_foliage_box=false;
  422. foliage_objs_box.zero();
  423. terrain_objs.clear();
  424. foliage_objs.clear();
  425. FREPA(objs) // add in order
  426. {
  427. C AreaObj &obj=objs[i];
  428. switch(obj.access())
  429. {
  430. case OBJ_ACCESS_TERRAIN: if(obj.base())
  431. {
  432. TerrainObj &ter_obj=terrain_objs.New();
  433. ter_obj.obj =obj.base();
  434. ter_obj.matrix =obj.matrixFinal();
  435. ter_obj.mesh_variation=obj.meshVariationIndex();
  436. if(ter_obj.obj->mesh())
  437. {
  438. Box box=ter_obj.obj->mesh()->ext*ter_obj.matrix;
  439. if(have_terrain_box)terrain_objs_box|=box;
  440. else {terrain_objs_box =box; have_terrain_box=true;}
  441. }
  442. }break;
  443. case OBJ_ACCESS_GRASS:
  444. {
  445. Int mesh_variation=obj.meshVariationIndex();
  446. GrassObj *foliage=null; REPA(foliage_objs){GrassObj &fo=foliage_objs[i]; if(fo.mesh==obj.mesh() && fo.phys==obj.phys() && fo.mesh_variation==mesh_variation){foliage=&fo; break;}}
  447. if(!foliage) // create new one
  448. {
  449. foliage=&foliage_objs.New();
  450. foliage->shrink =false;
  451. foliage->mesh =obj.mesh();
  452. foliage->phys =obj.phys();
  453. foliage->mesh_variation=mesh_variation;
  454. }
  455. GrassObj::Instance &instance=foliage->instances.New(); // set new instance
  456. instance.matrix=obj.matrixFinal();
  457. if(obj.mesh())
  458. {
  459. Box box=obj.mesh()->ext*instance.matrix;
  460. if(have_foliage_box)foliage_objs_box|=box;
  461. else {foliage_objs_box =box; have_foliage_box=true;}
  462. }
  463. }break;
  464. }
  465. }
  466. if(f.ok())return true;
  467. /*del();*/ return false;
  468. }
  469. /******************************************************************************/
  470. // AREA
  471. /******************************************************************************/
  472. Area::~Area()
  473. {
  474. Delete(_data);
  475. }
  476. Area::Area(C VecI2 &xy, Ptr grid_user)
  477. {
  478. T._visited=false;
  479. T._temp =false;
  480. T._xz =xy;
  481. T._state =AREA_UNLOADED;
  482. T._data =null;
  483. T._saved_obj.writeMem(1024);
  484. T._world =(WorldManager*)grid_user;
  485. }
  486. /******************************************************************************/
  487. Flt Area::hmHeight(C Vec2 &xz, Bool smooth)C
  488. {
  489. if(_data)
  490. {
  491. Image &height=_data->height;
  492. if( height.is())
  493. {
  494. Vec2 pixel=xz/world()->areaSize(); // in area coordinates space
  495. pixel.x-=T._xz.x; //
  496. pixel.y-=T._xz.y; // local fraction
  497. pixel.x*=height.w()-1;
  498. pixel.y*=height.h()-1; // image space
  499. return smooth ? height.pixelFLinear( pixel.x , pixel.y, true)
  500. : height.pixelF (RoundPos(pixel.x), RoundPos(pixel.y) );
  501. }
  502. }
  503. return 0;
  504. }
  505. /******************************************************************************/
  506. C MaterialPtr& Area::hmMaterial(C Vec2 &xz)C
  507. {
  508. if(_data)
  509. {
  510. Image &map=_data->material_map;
  511. if( map.is())
  512. {
  513. Vec2 pixel=xz/world()->areaSize(); // in area coordinates space
  514. pixel.x-=T._xz.x; //
  515. pixel.y-=T._xz.y; // local fraction
  516. pixel.x*=map.w()-1;
  517. pixel.y*=map.h()-1; // image space
  518. UInt index=map.pixel(RoundPos(pixel.x), RoundPos(pixel.y)); // material index
  519. if(InRange(index, _data->materials))return _data->materials[index];
  520. }
  521. }
  522. return MaterialNull;
  523. }
  524. /******************************************************************************/
  525. Area::Data* Area::getData()
  526. {
  527. if(state()!=AREA_UNLOADED)if(!data())world()->_area_data(_data, T); // first check state, then data (in case the Area is being loaded in background thread)
  528. return data();
  529. }
  530. /******************************************************************************/
  531. void Area::setShader()
  532. {
  533. if(_data)
  534. {
  535. _data-> mesh.setShader();
  536. _data->customSetShader();
  537. }
  538. }
  539. /******************************************************************************/
  540. Bool Area::saveObj(Obj &obj)
  541. {
  542. #if 1 // save using Obj Type ID (this allows to load objects correctly after obj type name has changed, as long as it has the same ID as before)
  543. C UID &obj_type_id=ObjType.elmID(world()->objType(obj));
  544. if( obj_type_id.valid())
  545. {
  546. ChunkWriter cw; cw.appendChunkList(_saved_obj);
  547. if(File *f=cw.beginChunk(EncodeRaw(obj_type_id), 1)) // OBJ_TYPE id
  548. {
  549. if(!obj.save(*f))return false; // object data
  550. cw.endChunk();
  551. }
  552. }
  553. #else // save using Obj Type Name
  554. CChar8 *obj_type_name=ObjType.elmName(world()->objType(obj));
  555. if(Is( obj_type_name))
  556. {
  557. ChunkWriter cw; cw.appendChunkList(_saved_obj);
  558. if(File *f=cw.beginChunk(obj_type_name, 0)) // OBJ_TYPE name
  559. {
  560. if(!obj.save(*f))return false; // object data
  561. cw.endChunk();
  562. }
  563. }
  564. #endif
  565. return _saved_obj.ok();
  566. }
  567. Bool Area::saveObjs()
  568. {
  569. _saved_obj.reset();
  570. FREPA(_objs)
  571. {
  572. Obj &obj=*_objs[i];
  573. if( !obj.isConst() && obj.canBeSaved())if(!saveObj(obj))return false; // don't save constant objects, and save only those which want to be saved
  574. }
  575. return true;
  576. }
  577. Bool Area::save(File &f, C VecI2 &xy)
  578. {
  579. if(_visited || _saved_obj.size()) // if visited or has any objects to save
  580. {
  581. f<<xy<<_visited;
  582. f.cmpUIntV(_saved_obj.size());
  583. _saved_obj.pos(0); if(!_saved_obj.copy(f))return false;
  584. return f.ok();
  585. }
  586. return true;
  587. }
  588. Bool Area::load(File &f)
  589. {
  590. f>>_visited;
  591. Int size=f.decUIntV();
  592. return f.ok() && f.copy(_saved_obj, size);
  593. }
  594. /******************************************************************************/
  595. }}
  596. /******************************************************************************/