Clone of Bael'Zharon's Respite @ https://github.com/boardwalk/bzr

Land.cpp 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. /*
  2. * Bael'Zharon's Respite
  3. * Copyright (C) 2014 Daniel Skorupski
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. */
  18. #include "Land.h"
  19. #include "resource/Region.h"
  20. #include "resource/Scene.h"
  21. #include "BinReader.h"
  22. #include "Core.h"
  23. #include "DatFile.h"
  24. #include "LandcellManager.h"
  25. #include "PRNG.h"
  26. #include "ResourceCache.h"
  27. #include <glm/gtc/matrix_transform.hpp>
  28. #include <algorithm>
  29. const fp_t Land::kCellSize = fp_t(24.0);
  30. const fp_t Land::kBlockSize = fp_t(192.0);
  31. static fp_t cubic(fp_t p[4], fp_t x)
  32. {
  33. return p[1] + fp_t(0.5) * x * (p[2] - p[0] + x * (fp_t(2.0) * p[0] - fp_t(5.0) * p[1] + fp_t(4.0) * p[2] - p[3] + x * (fp_t(3.0) * (p[1] - p[2]) + p[3] - p[0])));
  34. }
  35. static fp_t bicubic(fp_t p[4][4], fp_t x, fp_t y)
  36. {
  37. fp_t arr[]
  38. {
  39. cubic(p[0], y),
  40. cubic(p[1], y),
  41. cubic(p[2], y),
  42. cubic(p[3], y)
  43. };
  44. return cubic(arr, x);
  45. }
  46. Land::Land(const void* data, size_t size) : numStructures_(0)
  47. {
  48. if(size != sizeof(Data))
  49. {
  50. throw runtime_error("Bad land data length");
  51. }
  52. memcpy(&data_, data, sizeof(data_));
  53. const Region& region = Core::get().region();
  54. for(int y = 0; y < kGridSize; y++)
  55. {
  56. for(int x = 0; x < kGridSize; x++)
  57. {
  58. heights_[x][y] = region.landHeights[data_.heightIndices[x][y]];
  59. }
  60. }
  61. }
  62. void Land::init()
  63. {
  64. if(!offsetMap_.empty())
  65. {
  66. return;
  67. }
  68. if(data_.flags)
  69. {
  70. initStaticObjects();
  71. }
  72. initScenes();
  73. // sample another two times at the edges so we don't have to clamp our bicubic resample
  74. static const int sampleSize = kGridSize;
  75. static const int edgeSize = 2;
  76. static const int totalSampleSize = sampleSize + edgeSize * 2;
  77. vector<fp_t> sample(totalSampleSize * totalSampleSize);
  78. for(int sy = 0; sy < totalSampleSize; sy++)
  79. {
  80. for(int sx = 0; sx < totalSampleSize; sx++)
  81. {
  82. fp_t lx = static_cast<fp_t>(sx - edgeSize) / static_cast<fp_t>(sampleSize - 1) * kBlockSize;
  83. fp_t ly = static_cast<fp_t>(sy - edgeSize) / static_cast<fp_t>(sampleSize - 1) * kBlockSize;
  84. sample[sx + sy * totalSampleSize] = calcHeightUnbounded(lx, ly);
  85. }
  86. }
  87. vector<fp_t> resample(kOffsetMapSize * kOffsetMapSize);
  88. fp_t minOffset = numeric_limits<fp_t>::max();
  89. fp_t maxOffset = numeric_limits<fp_t>::min();
  90. for(int oy = 0; oy < kOffsetMapSize; oy++)
  91. {
  92. for(int ox = 0; ox < kOffsetMapSize; ox++)
  93. {
  94. fp_t sx = static_cast<fp_t>(ox) / static_cast<fp_t>(kOffsetMapSize - 1) * static_cast<fp_t>(sampleSize - 1);
  95. fp_t sy = static_cast<fp_t>(oy) / static_cast<fp_t>(kOffsetMapSize - 1) * static_cast<fp_t>(sampleSize - 1);
  96. int ix = static_cast<int>(sx);
  97. int iy = static_cast<int>(sy);
  98. fp_t fx = sx - ix;
  99. fp_t fy = sy - iy;
  100. fp_t p[4][4];
  101. for(int py = 0; py < 4; py++)
  102. {
  103. for(int px = 0; px < 4; px++)
  104. {
  105. p[px][py] = sample[(edgeSize + ix + px - 1) + (edgeSize + iy + py - 1) * totalSampleSize];
  106. }
  107. }
  108. fp_t lx = static_cast<fp_t>(ox) / static_cast<fp_t>(kOffsetMapSize - 1) * kBlockSize;
  109. fp_t ly = static_cast<fp_t>(oy) / static_cast<fp_t>(kOffsetMapSize - 1) * kBlockSize;
  110. fp_t offset = bicubic(p, fx, fy) - calcHeight(lx, ly);
  111. minOffset = min(minOffset, offset);
  112. maxOffset = max(maxOffset, offset);
  113. resample[ox + oy * kOffsetMapSize] = offset;
  114. }
  115. }
  116. offsetMap_.resize(kOffsetMapSize * kOffsetMapSize);
  117. offsetMapBase_ = minOffset;
  118. offsetMapScale_ = maxOffset - minOffset;
  119. if(offsetMapScale_ < 0.0001)
  120. {
  121. memset(offsetMap_.data(), 0, offsetMap_.size() * sizeof(uint16_t));
  122. }
  123. else
  124. {
  125. for(int oy = 0; oy < kOffsetMapSize; oy++)
  126. {
  127. for(int ox = 0; ox < kOffsetMapSize; ox++)
  128. {
  129. fp_t offset = resample[ox + oy * kOffsetMapSize];
  130. offsetMap_[ox + oy * kOffsetMapSize] = static_cast<uint16_t>((offset - offsetMapBase_) / offsetMapScale_ * fp_t(0xFFFF));
  131. }
  132. }
  133. }
  134. normalMap_.resize(kOffsetMapSize * kOffsetMapSize * 3);
  135. for(int oy = 0; oy < kOffsetMapSize; oy++)
  136. {
  137. for(int ox = 0; ox < kOffsetMapSize; ox++)
  138. {
  139. int ox1 = max(ox - 1, 0);
  140. int oy1 = max(oy - 1, 0);
  141. int ox2 = min(ox + 1, kOffsetMapSize - 1);
  142. int oy2 = min(oy + 1, kOffsetMapSize - 1);
  143. fp_t lx1 = static_cast<fp_t>(ox1) / static_cast<fp_t>(kOffsetMapSize - 1) * kBlockSize;
  144. fp_t lx2 = static_cast<fp_t>(ox2) / static_cast<fp_t>(kOffsetMapSize - 1) * kBlockSize;
  145. fp_t ly1 = static_cast<fp_t>(oy1) / static_cast<fp_t>(kOffsetMapSize - 1) * kBlockSize;
  146. fp_t ly2 = static_cast<fp_t>(oy2) / static_cast<fp_t>(kOffsetMapSize - 1) * kBlockSize;
  147. fp_t h1 = resample[ox1 + oy1 * kOffsetMapSize] + calcHeight(lx1, ly1);
  148. fp_t h2 = resample[ox2 + oy1 * kOffsetMapSize] + calcHeight(lx2, ly1);
  149. fp_t h3 = resample[ox1 + oy2 * kOffsetMapSize] + calcHeight(lx1, ly2);
  150. glm::vec3 a{lx2 - lx1, 0.0, h2 - h1};
  151. glm::vec3 b{0.0, ly2 - ly1, h3 - h1};
  152. glm::vec3 n = glm::normalize(glm::cross(a, b)) * fp_t(0.5) + glm::vec3{0.5, 0.5, 0.5};
  153. normalMap_[(ox + oy * kOffsetMapSize) * 3] = static_cast<uint8_t>(n.x * fp_t(0xFF));
  154. normalMap_[(ox + oy * kOffsetMapSize) * 3 + 1] = static_cast<uint8_t>(n.y * fp_t(0xFF));
  155. normalMap_[(ox + oy * kOffsetMapSize) * 3 + 2] = static_cast<uint8_t>(n.z * fp_t(0xFF));
  156. }
  157. }
  158. }
  159. fp_t Land::getHeight(int gridX, int gridY) const
  160. {
  161. return heights_[gridX][gridY];
  162. }
  163. uint8_t Land::getRoad(int gridX, int gridY) const
  164. {
  165. return static_cast<uint8_t>(data_.styles[gridX][gridY] & 0x3);
  166. }
  167. uint8_t Land::getTerrain(int gridX, int gridY) const
  168. {
  169. return static_cast<uint8_t>((data_.styles[gridX][gridY] >> 2) & 0x1f);
  170. }
  171. uint8_t Land::getTerrainScene(int gridX, int gridY) const
  172. {
  173. return static_cast<uint8_t>(data_.styles[gridX][gridY] >> 11);
  174. }
  175. bool Land::isSplitNESW(int gridX, int gridY) const
  176. {
  177. // credits to Akilla
  178. uint32_t cell_x = id().x() * 8 + gridX;
  179. uint32_t cell_y = id().y() * 8 + gridY;
  180. return prng(cell_x, cell_y, RND_MID_DIAG) >= 0.5;
  181. }
  182. Plane Land::calcPlane(fp_t x, fp_t y) const
  183. {
  184. assert(x >= 0.0 && x <= kBlockSize);
  185. assert(y >= 0.0 && y <= kBlockSize);
  186. fp_t dix;
  187. fp_t fx = modf(x / kCellSize, &dix);
  188. int ix = static_cast<int>(dix);
  189. fp_t diy;
  190. fp_t fy = modf(y / kCellSize, &diy);
  191. int iy = static_cast<int>(diy);
  192. glm::vec3 v1(ix * kCellSize, iy * kCellSize, getHeight(ix, iy));
  193. glm::vec3 v2((ix + 1) * kCellSize, iy * kCellSize, getHeight(min(ix + 1, kGridSize - 1), iy));
  194. glm::vec3 v3(ix * kCellSize, (iy + 1) * kCellSize, getHeight(ix, min(iy + 1, kGridSize - 1)));
  195. glm::vec3 v4((ix + 1) * kCellSize, (iy + 1) * kCellSize, getHeight(min(ix + 1, kGridSize - 1), min(iy + 1, kGridSize - 1)));
  196. if(isSplitNESW(ix, iy))
  197. {
  198. // 3---4
  199. // |\ |
  200. // | \ |
  201. // | \|
  202. // 1---2
  203. if(fy > 1.0 - fx)
  204. {
  205. // upper right half
  206. return Plane(v2, v4, v3);
  207. }
  208. else
  209. {
  210. // lower left half
  211. return Plane(v1, v2, v3);
  212. }
  213. }
  214. else
  215. {
  216. // 3---4
  217. // | /|
  218. // | / |
  219. // |/ |
  220. // 1---2
  221. if(fy > fx)
  222. {
  223. // upper left half
  224. return Plane(v1, v4, v3);
  225. }
  226. else
  227. {
  228. // lower right half
  229. return Plane(v1, v2, v4);
  230. }
  231. }
  232. }
  233. fp_t Land::calcHeight(fp_t x, fp_t y) const
  234. {
  235. return calcPlane(x, y).calcZ(x, y);
  236. }
  237. fp_t Land::calcHeightUnbounded(fp_t x, fp_t y) const
  238. {
  239. int lx = id().x();
  240. int ly = id().y();
  241. while(x < 0.0)
  242. {
  243. lx--;
  244. x += kBlockSize;
  245. }
  246. while(x >= kBlockSize)
  247. {
  248. lx++;
  249. x -= kBlockSize;
  250. }
  251. while(y < 0.0)
  252. {
  253. ly--;
  254. y += kBlockSize;
  255. }
  256. while(y >= kBlockSize)
  257. {
  258. ly++;
  259. y -= kBlockSize;
  260. }
  261. if(lx < 0x00 || lx > 0xFF || ly < 0x00 || ly > 0xFF)
  262. {
  263. return fp_t(0.0);
  264. }
  265. auto it = Core::get().landcellManager().find(LandcellId(lx, ly));
  266. if(it == Core::get().landcellManager().end())
  267. {
  268. return fp_t(0.0);
  269. }
  270. Land& land = static_cast<Land&>(*it->second);
  271. return land.calcHeight(x, y);
  272. }
  273. LandcellId Land::id() const
  274. {
  275. return LandcellId(data_.fileId);
  276. }
  277. uint32_t Land::numStructures() const
  278. {
  279. return numStructures_;
  280. }
  281. const uint8_t* Land::normalMap() const
  282. {
  283. return normalMap_.data();
  284. }
  285. void Land::initStaticObjects()
  286. {
  287. // AC: CLandBlockInfo
  288. vector<uint8_t> blob = Core::get().cellDat().read(data_.fileId - 1);
  289. BinReader reader(blob.data(), blob.size());
  290. uint32_t fid = reader.readInt();
  291. assert(fid == data_.fileId - 1);
  292. UNUSED(fid);
  293. numStructures_ = reader.readInt();
  294. uint16_t numStaticObjects = reader.readShort();
  295. uint16_t unk1 = reader.readShort();
  296. assert(unk1 == 0);
  297. UNUSED(unk1);
  298. staticObjects_.resize(numStaticObjects);
  299. for(auto& staticObject : staticObjects_)
  300. {
  301. read(reader, staticObject);
  302. }
  303. uint16_t numStaticObjectsEx = reader.readShort();
  304. // I don't know what this is, but it means there's more data
  305. uint16_t unk2 = reader.readShort();
  306. assert(unk2 == 0 || unk2 == 1);
  307. UNUSED(unk2);
  308. staticObjects_.resize(numStaticObjects + numStaticObjectsEx);
  309. for(uint16_t i = 0; i < numStaticObjectsEx; i++)
  310. {
  311. // AC: BuildInfo
  312. read(reader, staticObjects_[numStaticObjects + i]);
  313. /*uint32_t numLeaves = */reader.readInt();
  314. uint32_t numPortals = reader.readInt();
  315. for(uint32_t pi = 0; pi < numPortals; pi++)
  316. {
  317. // AC: CBldPortal
  318. reader.readInt();
  319. reader.readShort();
  320. uint16_t numVisible = reader.readShort();
  321. for(uint16_t vi = 0; vi < numVisible; vi++)
  322. {
  323. /*cellId*/ reader.readShort();
  324. }
  325. reader.align();
  326. }
  327. }
  328. }
  329. void Land::initScenes()
  330. {
  331. const Region& region = Core::get().region();
  332. for(int x = 0; x < kGridSize; x++)
  333. {
  334. for(int y = 0; y < kGridSize; y++)
  335. {
  336. uint32_t terrainTypeNum = getTerrain(x, y);
  337. uint32_t terrainSceneTypeNum = getTerrainScene(x, y);
  338. assert(terrainTypeNum < region.terrainTypes.size());
  339. const vector<uint32_t>& terrainSceneTypes = region.terrainTypes[terrainTypeNum].sceneTypes;
  340. assert(terrainSceneTypeNum < terrainSceneTypes.size());
  341. uint32_t sceneTypeNum = terrainSceneTypes[terrainSceneTypeNum];
  342. const Region::SceneType& sceneType = region.sceneTypes[sceneTypeNum];
  343. if(sceneType.scenes.empty())
  344. {
  345. continue;
  346. }
  347. uint32_t cellX = id().x() * 8 + x;
  348. uint32_t cellY = id().y() * 8 + y;
  349. uint32_t sceneNum = static_cast<uint32_t>(prng(cellX, cellY, RND_SCENE_PICK) * static_cast<double>(sceneType.scenes.size()));
  350. if(sceneNum >= sceneType.scenes.size())
  351. {
  352. sceneNum = 0;
  353. }
  354. const Scene& scene = sceneType.scenes[sceneNum]->cast<Scene>();
  355. initScene(x, y, scene);
  356. }
  357. }
  358. }
  359. void Land::initScene(int x, int y, const Scene& scene)
  360. {
  361. uint32_t cellX = id().x() * 8 + x;
  362. uint32_t cellY = id().y() * 8 + y;
  363. double sceneRot = prng(cellX, cellY, RND_SCENE_ROT);
  364. for(uint32_t i = 0; i < scene.objects.size(); i++)
  365. {
  366. const Scene::ObjectDesc& objectDesc = scene.objects[i];
  367. if(objectDesc.isWeenieObj)
  368. {
  369. // not sure what these are for
  370. // they don't have a valid resourceId
  371. continue;
  372. }
  373. if(prng(cellX, cellY, RND_SCENE_FREQ + i) >= objectDesc.frequency)
  374. {
  375. // object hidden
  376. continue;
  377. }
  378. // calculate position within block
  379. glm::vec3 cellPos = objectDesc.position;
  380. if(objectDesc.displace.x > 0.0)
  381. {
  382. cellPos.x += static_cast<fp_t>(prng(cellX, cellY, RND_SCENE_DISP_X + i) * objectDesc.displace.x);
  383. }
  384. if(objectDesc.displace.y > 0.0)
  385. {
  386. cellPos.y += static_cast<fp_t>(prng(cellX, cellY, RND_SCENE_DISP_Y + i) * objectDesc.displace.y);
  387. }
  388. glm::vec3 tempPos = cellPos;
  389. if(sceneRot >= 0.75)
  390. {
  391. cellPos.x = tempPos.y;
  392. cellPos.y = -tempPos.x;
  393. }
  394. else if(sceneRot >= 0.5)
  395. {
  396. cellPos.x = -tempPos.x;
  397. cellPos.y = -tempPos.y;
  398. }
  399. else if(sceneRot >= 0.25)
  400. {
  401. cellPos.x = -tempPos.y;
  402. cellPos.y = tempPos.x;
  403. }
  404. else
  405. {
  406. cellPos.x = tempPos.y;
  407. cellPos.y = tempPos.x;
  408. }
  409. glm::vec3 blockPos = cellPos + glm::vec3(x * kCellSize, y * kCellSize, 0.0);
  410. if(blockPos.x < 0.0 || blockPos.x >= kBlockSize || blockPos.y < 0.0 || blockPos.y >= kBlockSize)
  411. {
  412. continue;
  413. }
  414. if(roadAtPoint(blockPos.x, blockPos.y))
  415. {
  416. continue;
  417. }
  418. Plane landPlane = calcPlane(blockPos.x, blockPos.y);
  419. if(landPlane.normal.z < objectDesc.minSlope || landPlane.normal.z > objectDesc.maxSlope)
  420. {
  421. continue;
  422. }
  423. blockPos.z += landPlane.calcZ(blockPos.x, blockPos.y);
  424. // calculate scale
  425. fp_t scale = static_cast<fp_t>(objectDesc.minScale * pow(objectDesc.maxScale / objectDesc.minScale, prng(cellX, cellY, RND_SCENE_SCALE1 + i)));
  426. // calculate rotation
  427. fp_t randRot = static_cast<fp_t>(prng(cellX, cellY, RND_SCENE_OBJROT + i)) * glm::radians(objectDesc.maxRotation);
  428. glm::quat rotation = glm::angleAxis(randRot, glm::vec3(0.0, 0.0, 1.0)) * objectDesc.rotation;
  429. glm::mat4 translateMat = glm::translate(glm::mat4{}, blockPos);
  430. glm::mat4 rotateMat = glm::mat4_cast(rotation);
  431. glm::mat4 scaleMat = glm::scale(glm::mat4{}, glm::vec3{scale, scale, scale});
  432. // add static object
  433. StaticObject staticObject;
  434. staticObject.resource = Core::get().resourceCache().get(objectDesc.resourceId);
  435. staticObject.transform = translateMat * rotateMat * scaleMat;
  436. staticObjects_.push_back(staticObject);
  437. }
  438. }
  439. bool Land::roadAtPoint(fp_t x, fp_t y) const
  440. {
  441. assert(x >= 0.0 && x < kBlockSize);
  442. assert(y >= 0.0 && y < kBlockSize);
  443. const fp_t kRoadHalfWidth = fp_t(5.0);
  444. fp_t dix;
  445. fp_t fx = modf(x / kCellSize, &dix);
  446. int ix = static_cast<int>(dix);
  447. fp_t diy;
  448. fp_t fy = modf(y / kCellSize, &diy);
  449. int iy = static_cast<int>(diy);
  450. int r1 = getRoad(ix, iy);
  451. int r2 = getRoad(ix + 1, iy);
  452. int r3 = getRoad(ix, iy + 1);
  453. int r4 = getRoad(ix + 1, iy + 1);
  454. if(r1 && r2 && r3 && r4)
  455. {
  456. return true;
  457. }
  458. if(r1)
  459. {
  460. if(r2 && fy < kRoadHalfWidth)
  461. {
  462. return true;
  463. }
  464. if(r3 && fx < kRoadHalfWidth)
  465. {
  466. return true;
  467. }
  468. if(fx < kRoadHalfWidth && fy < kRoadHalfWidth)
  469. {
  470. return true;
  471. }
  472. }
  473. if(r2)
  474. {
  475. if(r4 && fx > kCellSize - kRoadHalfWidth)
  476. {
  477. return true;
  478. }
  479. if(fx > kCellSize - kRoadHalfWidth && fy < kRoadHalfWidth)
  480. {
  481. return true;
  482. }
  483. }
  484. if(r3)
  485. {
  486. if(r4 && fy > kCellSize - kRoadHalfWidth)
  487. {
  488. return true;
  489. }
  490. if(fx < kRoadHalfWidth && fy > kCellSize - kRoadHalfWidth)
  491. {
  492. return true;
  493. }
  494. }
  495. if(r4)
  496. {
  497. if(fx > kCellSize - kRoadHalfWidth && fy > kCellSize - kRoadHalfWidth)
  498. {
  499. return true;
  500. }
  501. }
  502. // TODO diagonals?
  503. return false;
  504. }