mapdata.cpp 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863
  1. //---------------------------------------------------------------------------
  2. //
  3. // MapData.cpp -- File contains class code for the terrain mesh
  4. //
  5. // MechCommander 2
  6. //
  7. //---------------------------------------------------------------------------//
  8. // Copyright (C) Microsoft Corporation. All rights reserved. //
  9. //===========================================================================//
  10. //---------------------------------------------------------------------------
  11. // Include Files
  12. #ifndef MAPDATA_H
  13. #include "mapdata.h"
  14. #endif
  15. #ifndef TERRAIN_H
  16. #include "terrain.h"
  17. #endif
  18. #ifndef CAMERA_H
  19. #include "camera.h"
  20. #endif
  21. #ifndef TIMING_H
  22. #include "timing.h"
  23. #endif
  24. //---------------------------------------------------------------------------
  25. // c'tors for postCompVertex
  26. PostcompVertex& PostcompVertex::operator=( const PostcompVertex& src )
  27. {
  28. if ( &src != this )
  29. {
  30. vertexNormal = src.vertexNormal;
  31. elevation = src.elevation;
  32. textureData = src.textureData;
  33. localRGBLight = src.localRGBLight;
  34. terrainType = src.terrainType;
  35. selected = src.selected;
  36. shadow = src.shadow;
  37. highlighted = src.highlighted;
  38. }
  39. return *this;
  40. }
  41. //---------------------------------------------------------------------------
  42. PostcompVertex::PostcompVertex( const PostcompVertex& src )
  43. {
  44. vertexNormal = src.vertexNormal;
  45. elevation = src.elevation;
  46. textureData = src.textureData;
  47. localRGBLight = src.localRGBLight;
  48. terrainType = src.terrainType;
  49. selected = src.selected;
  50. shadow = src.shadow;
  51. highlighted = src.highlighted;
  52. }
  53. //---------------------------------------------------------------------------
  54. PostcompVertex::PostcompVertex()
  55. {
  56. elevation = 0.0f;
  57. textureData = 0;
  58. localRGBLight = 0;
  59. terrainType = 0;
  60. selected = 0;
  61. }
  62. //---------------------------------------------------------------------------
  63. // class MapData
  64. float MapData::waterDepth = 0.0f;
  65. float MapData::shallowDepth = 0.0f;
  66. float MapData::alphaDepth = 0.0f;
  67. DWORD MapData::WaterTXMData = 0xffffffff;
  68. float cloudScrollSpeedX = 0.002f;
  69. float cloudScrollSpeedY = 0.002f;
  70. float cloudScrollX = 0.0f;
  71. float cloudScrollY = 0.0f;
  72. void *MapData::operator new (size_t mySize)
  73. {
  74. void *result = Terrain::terrainHeap->Malloc(mySize);
  75. return(result);
  76. }
  77. //---------------------------------------------------------------------------
  78. void MapData::operator delete (void *us)
  79. {
  80. Terrain::terrainHeap->Free(us);
  81. }
  82. //---------------------------------------------------------------------------
  83. void MapData::destroy (void)
  84. {
  85. HeapManager::destroy();
  86. if (blankVertex)
  87. {
  88. delete blankVertex;
  89. blankVertex = NULL;
  90. }
  91. }
  92. //---------------------------------------------------------------------------
  93. void MapData::newInit (long numVertices)
  94. {
  95. if (heap)
  96. destroy();
  97. long result = createHeap((numVertices+1) * sizeof(PostcompVertex));
  98. gosASSERT(result == NO_ERR);
  99. result = commitHeap();
  100. gosASSERT(result == NO_ERR);
  101. //-----------------------------------------------------------
  102. // There is one (1) block of memory for the ENTIRE terrain now.
  103. // Since we no longer cache any aspect of the terrain, this is
  104. // FAR more efficient and easier to understand.
  105. MemoryPtr start = getHeapPtr();
  106. blocks = (PostcompVertexPtr)start;
  107. PostcompVertex* pTmp = blocks;
  108. // gotta set all of the z's to 1
  109. for ( int i = 0; i < numVertices; ++i )
  110. {
  111. pTmp->vertexNormal.z = 1.0;
  112. pTmp->terrainType = MC_MUD_TYPE;
  113. pTmp->textureData = 0xffff0000;
  114. pTmp++;
  115. }
  116. Terrain::recalcLight = true;
  117. Terrain::recalcShadows = false;
  118. calcTransitions();
  119. }
  120. //---------------------------------------------------------------------------
  121. void MapData::newInit (PacketFile* newFile, long numVertices)
  122. {
  123. newInit( numVertices );
  124. newFile->readPacket(newFile->getCurrentPacket(), (MemoryPtr)blocks );
  125. calcTransitions();
  126. }
  127. //---------------------------------------------------------------------------
  128. long MapData::save( PacketFile* file, int whichPacket )
  129. {
  130. return file->writePacket( whichPacket, (unsigned char*)blocks,
  131. Terrain::realVerticesMapSide * Terrain::realVerticesMapSide *sizeof(PostcompVertex ) );
  132. }
  133. //---------------------------------------------------------------------------
  134. void MapData::highlightAllTransitionsOver2 (void)
  135. {
  136. unhighlightAll();
  137. PostcompVertexPtr currentVertex = blocks;
  138. //--------------------------------------------------------------------------
  139. // This pass is used to mark the transitions over the value of 2
  140. for (long y=0;y<(Terrain::realVerticesMapSide-1);y++)
  141. {
  142. for (long x=0;x<(Terrain::realVerticesMapSide-1);x++)
  143. {
  144. //-----------------------------------------------
  145. // Get the data needed to make this terrain quad
  146. PostcompVertex *pVertex1 = currentVertex;
  147. PostcompVertex *pVertex2 = currentVertex + 1;
  148. PostcompVertex *pVertex3 = currentVertex + Terrain::realVerticesMapSide + 1;
  149. PostcompVertex *pVertex4 = currentVertex + Terrain::realVerticesMapSide;
  150. //-------------------------------------------------------------------------------
  151. long totalNotEqual1 = abs((pVertex1->terrainType != pVertex2->terrainType) +
  152. (pVertex3->terrainType != pVertex4->terrainType) +
  153. (pVertex2->terrainType != pVertex4->terrainType));
  154. long totalNotEqual2 = abs((pVertex2->terrainType != pVertex3->terrainType) +
  155. (pVertex1->terrainType != pVertex4->terrainType) +
  156. (pVertex1->terrainType != pVertex3->terrainType));
  157. if ((totalNotEqual1 >= 2) && (totalNotEqual2 >= 2))
  158. {
  159. pVertex1->highlighted = true;
  160. pVertex2->highlighted = true;
  161. pVertex3->highlighted = true;
  162. pVertex4->highlighted = true;
  163. }
  164. currentVertex++;
  165. }
  166. currentVertex++;
  167. }
  168. }
  169. //---------------------------------------------------------------------------
  170. void MapData::calcTransitions()
  171. {
  172. PostcompVertexPtr currentVertex = blocks;
  173. //--------------------------------------------------------------------------
  174. // This pass is used to calc the transitions.
  175. for (long y=0;y<(Terrain::realVerticesMapSide-1);y++)
  176. {
  177. for (long x=0;x<(Terrain::realVerticesMapSide-1);x++)
  178. {
  179. //-----------------------------------------------
  180. // Get the data needed to make this terrain quad
  181. PostcompVertex *pVertex1 = currentVertex;
  182. PostcompVertex *pVertex2 = currentVertex + 1;
  183. PostcompVertex *pVertex3 = currentVertex + Terrain::realVerticesMapSide + 1;
  184. PostcompVertex *pVertex4 = currentVertex + Terrain::realVerticesMapSide;
  185. //-------------------------------------------------------------------------------
  186. // Store texture in bottom part from TxmIndex provided by TerrainTextureManager
  187. DWORD terrainType = pVertex1->terrainType +
  188. (pVertex2->terrainType << 8) +
  189. (pVertex3->terrainType << 16) +
  190. (pVertex4->terrainType << 24);
  191. DWORD overlayType = (pVertex1->textureData >> 16);
  192. if (overlayType < Terrain::terrainTextures->getFirstOverlay())
  193. {
  194. pVertex1->textureData = 0xffff0000; //Erase the overlay, the numbers changed!
  195. overlayType = 0xffff;
  196. }
  197. //Insure Base Texture is zero.
  198. pVertex1->textureData &= (pVertex1->textureData & 0xffff0000);
  199. DWORD txmResult = Terrain::terrainTextures->setTexture(terrainType,overlayType);
  200. pVertex1->textureData += txmResult;
  201. gosASSERT((pVertex1->textureData & 0x0000ffff) != 0xffff);
  202. currentVertex++;
  203. }
  204. currentVertex++;
  205. }
  206. DWORD terrainType = MC_BLUEWATER_TYPE +
  207. (MC_BLUEWATER_TYPE << 8) +
  208. (MC_BLUEWATER_TYPE << 16) +
  209. (MC_BLUEWATER_TYPE << 24);
  210. WaterTXMData = Terrain::terrainTextures->setTexture(terrainType,0xffff);
  211. }
  212. long lowElevation = 255; //Stores the water level for old Maps
  213. //ONLY used by conversion code.
  214. long waterTest = 0; //Stores the water test elevation. Everything at or below this is underwater!
  215. //---------------------------------------------------------------------------
  216. void MapData::calcWater (float wDepth, float sDepth, float aDepth)
  217. {
  218. PostcompVertexPtr currentVertex = blocks;
  219. //---------------------------------------------------------------------------
  220. // BETTER. Store bits in top to indicate which way water goes. Store 2 bits
  221. // so water doesn't have to animate either!
  222. // Try random. May look way cool!
  223. bool odd1 = false;
  224. bool odd2 = false;
  225. BYTE marker = 0;
  226. for (long y=0;y<(Terrain::realVerticesMapSide-1);y++)
  227. {
  228. for (long x=0;x<(Terrain::realVerticesMapSide-1);x++)
  229. {
  230. if (currentVertex->elevation < wDepth)
  231. {
  232. currentVertex->water = 1 + marker;
  233. }
  234. else
  235. {
  236. currentVertex->water = 0 + marker;
  237. }
  238. currentVertex++;
  239. if (RollDice(50))
  240. odd1 ^= true;
  241. if (RollDice(50))
  242. odd2 ^= true;
  243. marker = (odd1 ? 0x80 : 0x0);
  244. marker += (odd2 ? 0x40 : 0x0);
  245. }
  246. currentVertex++; //Do not flip odd here so each row starts opposite the previous
  247. }
  248. Terrain::waterElevation = wDepth + sDepth;
  249. waterDepth = wDepth;
  250. shallowDepth = sDepth;
  251. alphaDepth = aDepth;
  252. }
  253. //---------------------------------------------------------------------------
  254. void MapData::recalcWater (void)
  255. {
  256. PostcompVertexPtr currentVertex = blocks;
  257. bool odd1 = false;
  258. bool odd2 = false;
  259. BYTE marker = 0;
  260. for (long y=0;y<(Terrain::realVerticesMapSide-1);y++)
  261. {
  262. for (long x=0;x<(Terrain::realVerticesMapSide-1);x++)
  263. {
  264. if (currentVertex->elevation < waterDepth)
  265. {
  266. currentVertex->water = 1 + marker;
  267. }
  268. else
  269. {
  270. currentVertex->water = 0 + marker;
  271. }
  272. currentVertex++;
  273. if (RollDice(50))
  274. odd1 ^= true;
  275. if (RollDice(50))
  276. odd2 ^= true;
  277. marker = (odd1 ? 0x80 : 0x0);
  278. marker += (odd2 ? 0x40 : 0x0);
  279. }
  280. currentVertex++; //Do not flip odd here so each row starts opposite the previous
  281. }
  282. }
  283. //---------------------------------------------------------------------------
  284. float MapData::getTopLeftElevation (void)
  285. {
  286. float result = 0.0;
  287. if (blocks)
  288. {
  289. result = blocks->elevation;
  290. }
  291. return(result);
  292. }
  293. float MAX_UV = 0.98f;
  294. float MIN_UV = 0.02f;
  295. float ScrollUV1 = MIN_UV;
  296. float ScrollUV2 = MAX_UV;
  297. float SCROLL_RATE = 0.005f;
  298. //---------------------------------------------------------------------------
  299. void MapData::setVertexHeight( int VertexIndex, float Val )
  300. {
  301. blocks[VertexIndex].elevation = Val;
  302. }
  303. //---------------------------------------------------------------------------
  304. float MapData::getVertexHeight( int VertexIndex )
  305. {
  306. return blocks[VertexIndex].elevation;
  307. }
  308. #define ContrastEnhance 1.0f
  309. //---------------------------------------------------------------------------
  310. void MapData::calcLight (void)
  311. {
  312. Terrain::recalcLight = false;
  313. //----------------------------------------
  314. // Let's calc the map dimensions...
  315. long height, width;
  316. height = width = Terrain::verticesBlockSide * Terrain::blocksMapSide;
  317. long totalVertices = height * width;
  318. Stuff::Vector3D lightDir;
  319. lightDir.x = lightDir.y = 0.0f;
  320. lightDir.z = 1.0f;
  321. if (eye)
  322. lightDir = eye->lightDirection;
  323. lightDir *= 64.0f;
  324. //---------------------
  325. //Lighting Pass Here
  326. PostcompVertexPtr currentVertex = blocks;
  327. for (long i=0;i<totalVertices;i++)
  328. {
  329. long diskMapIndex = i;
  330. long x = i % Terrain::realVerticesMapSide;
  331. long y = i / Terrain::realVerticesMapSide;
  332. //------------------------------------------------
  333. // Check Bounds to make sure we don't go off map
  334. if (((diskMapIndex - Terrain::realVerticesMapSide - 1) < 0) ||
  335. ((diskMapIndex - Terrain::realVerticesMapSide) < 0) ||
  336. ((diskMapIndex - 1) < 0))
  337. {
  338. //---------------------------------------------
  339. // Cant generate a normal. TOO close to edge.
  340. // Default data please!
  341. }
  342. else if (((diskMapIndex + 1) >= totalVertices) ||
  343. ((diskMapIndex + Terrain::realVerticesMapSide) >= totalVertices) ||
  344. ((diskMapIndex + Terrain::realVerticesMapSide + 1) >= totalVertices))
  345. {
  346. //---------------------------------------------
  347. // Cant generate a normal. TOO close to edge.
  348. // Default data please!
  349. }
  350. else
  351. {
  352. //---------------------------------------------
  353. // No problem
  354. // Generate at will!
  355. PostcompVertexPtr v0,v1,v2,v3,v4,v5,v6,v7,v8;
  356. v0 = currentVertex;
  357. v1 = currentVertex - Terrain::realVerticesMapSide - 1;
  358. v2 = currentVertex - Terrain::realVerticesMapSide;
  359. v3 = currentVertex - Terrain::realVerticesMapSide + 1;
  360. v4 = currentVertex + 1;
  361. v5 = currentVertex + Terrain::realVerticesMapSide + 1;
  362. v6 = currentVertex + Terrain::realVerticesMapSide;
  363. v7 = currentVertex + Terrain::realVerticesMapSide - 1;
  364. v8 = currentVertex - 1;
  365. //-----------------------------------------------------
  366. // Try and project shadow lines.
  367. if (Terrain::recalcShadows)
  368. {
  369. Stuff::Vector3D vertexPos;
  370. vertexPos.x = ((float(x) * Terrain::worldUnitsPerVertex) + Terrain::mapTopLeft3d.x);
  371. vertexPos.y = (Terrain::mapTopLeft3d.y - (float(y) * Terrain::worldUnitsPerVertex));
  372. vertexPos.z = 0.0f;
  373. vertexPos.z = terrainElevation(vertexPos);
  374. v0->shadow = 0;
  375. if ((lightDir.x != 0.0f) || (lightDir.y != 0.0f))
  376. {
  377. vertexPos.Add(vertexPos,lightDir);
  378. while (eye && Terrain::IsValidTerrainPosition(vertexPos))
  379. {
  380. float elev = terrainElevation(vertexPos);
  381. if ((elev+20.0f) >= vertexPos.z)
  382. {
  383. v0->shadow=1; //Mark as shadow edge
  384. break; //Its in shadow. Stop Projecting!
  385. }
  386. vertexPos.Add(vertexPos,lightDir);
  387. }
  388. }
  389. }
  390. Stuff::Vector3D normals[8];
  391. Stuff::Vector3D triVect[2];
  392. //-------------------------------------
  393. // Tri 021
  394. triVect[0].x = 0.0;
  395. triVect[0].y = Terrain::worldUnitsPerVertex;
  396. triVect[0].z = (v2->getElevation() - v0->getElevation()) * ContrastEnhance;
  397. triVect[1].x = -Terrain::worldUnitsPerVertex;
  398. triVect[1].y = Terrain::worldUnitsPerVertex;
  399. triVect[1].z = (v1->getElevation() - v0->getElevation()) * ContrastEnhance;
  400. normals[0].Cross(triVect[0],triVect[1]);
  401. gosASSERT(normals[0].z > 0.0);
  402. normals[0].Normalize(normals[0]);
  403. //-------------------------------------
  404. // Tri 032
  405. triVect[0].x = Terrain::worldUnitsPerVertex;
  406. triVect[0].y = 0.0;
  407. triVect[0].z = (v3->getElevation() - v0->getElevation()) * ContrastEnhance;
  408. triVect[1].x = 0.0;
  409. triVect[1].y = Terrain::worldUnitsPerVertex;
  410. triVect[1].z = (v2->getElevation() - v0->getElevation()) * ContrastEnhance;
  411. normals[1].Cross(triVect[0],triVect[1]);
  412. gosASSERT(normals[1].z > 0.0);
  413. normals[1].Normalize(normals[1]);
  414. //-------------------------------------
  415. // Tri 043
  416. triVect[0].x = Terrain::worldUnitsPerVertex;
  417. triVect[0].y = -Terrain::worldUnitsPerVertex;
  418. triVect[0].z = (v4->getElevation() - v0->getElevation()) * ContrastEnhance;
  419. triVect[1].x = Terrain::worldUnitsPerVertex;
  420. triVect[1].y = 0.0;
  421. triVect[1].z = (v3->getElevation() - v0->getElevation()) * ContrastEnhance;
  422. normals[2].Cross(triVect[0],triVect[1]);
  423. gosASSERT(normals[2].z > 0.0);
  424. normals[2].Normalize(normals[2]);
  425. //-------------------------------------
  426. // Tri 054
  427. triVect[0].x = 0.0;
  428. triVect[0].y = -Terrain::worldUnitsPerVertex;
  429. triVect[0].z = (v5->getElevation() - v0->getElevation()) * ContrastEnhance;
  430. triVect[1].x = Terrain::worldUnitsPerVertex;
  431. triVect[1].y = -Terrain::worldUnitsPerVertex;
  432. triVect[1].z = (v4->getElevation() - v0->getElevation()) * ContrastEnhance;
  433. normals[3].Cross(triVect[0],triVect[1]);
  434. gosASSERT(normals[3].z > 0.0);
  435. normals[3].Normalize(normals[3]);
  436. //-------------------------------------
  437. // Tri 065
  438. triVect[0].x = -Terrain::worldUnitsPerVertex;
  439. triVect[0].y = 0.0;
  440. triVect[0].z = (v6->getElevation() - v0->getElevation()) * ContrastEnhance;
  441. triVect[1].x = 0.0;
  442. triVect[1].y = -Terrain::worldUnitsPerVertex;
  443. triVect[1].z = (v5->getElevation() - v0->getElevation()) * ContrastEnhance;
  444. normals[4].Cross(triVect[0],triVect[1]);
  445. gosASSERT(normals[4].z > 0.0);
  446. normals[4].Normalize(normals[4]);
  447. //-------------------------------------
  448. // Tri 076
  449. triVect[0].x = -Terrain::worldUnitsPerVertex;
  450. triVect[0].y = 0.0;
  451. triVect[0].z = (v7->getElevation() - v0->getElevation()) * ContrastEnhance;
  452. triVect[1].x = 0.0;
  453. triVect[1].y = -Terrain::worldUnitsPerVertex;
  454. triVect[1].z = (v6->getElevation() - v0->getElevation()) * ContrastEnhance;
  455. normals[5].Cross(triVect[0],triVect[1]);
  456. gosASSERT(normals[5].z > 0.0);
  457. normals[5].Normalize(normals[5]);
  458. //-------------------------------------
  459. // Tri 087
  460. triVect[0].x = -Terrain::worldUnitsPerVertex;
  461. triVect[0].y = 0.0;
  462. triVect[0].z = (v8->getElevation() - v0->getElevation()) * ContrastEnhance;
  463. triVect[1].x = 0.0;
  464. triVect[1].y = -Terrain::worldUnitsPerVertex;
  465. triVect[1].z = (v7->getElevation() - v0->getElevation()) * ContrastEnhance;
  466. normals[6].Cross(triVect[0],triVect[1]);
  467. gosASSERT(normals[6].z > 0.0);
  468. normals[6].Normalize(normals[6]);
  469. //-------------------------------------
  470. // Tri 018
  471. triVect[0].x = -Terrain::worldUnitsPerVertex;
  472. triVect[0].y = Terrain::worldUnitsPerVertex;
  473. triVect[0].z = (v1->getElevation() - v0->getElevation()) * ContrastEnhance;
  474. triVect[1].x = -Terrain::worldUnitsPerVertex;
  475. triVect[1].y = 0.0;
  476. triVect[1].z = (v8->getElevation() - v0->getElevation()) * ContrastEnhance;
  477. normals[7].Cross(triVect[0],triVect[1]);
  478. gosASSERT(normals[7].z > 0.0);
  479. normals[7].Normalize(normals[7]);
  480. currentVertex->vertexNormal.x = normals[0].x + normals[1].x + normals[2].x + normals[3].x + normals[4].x + normals[5].x + normals[6].x + normals[7].x;
  481. currentVertex->vertexNormal.y = normals[0].y + normals[1].y + normals[2].y + normals[3].y + normals[4].y + normals[5].y + normals[6].y + normals[7].y;
  482. currentVertex->vertexNormal.z = normals[0].z + normals[1].z + normals[2].z + normals[3].z + normals[4].z + normals[5].z + normals[6].z + normals[7].z;
  483. currentVertex->vertexNormal.x /= 8.0;
  484. currentVertex->vertexNormal.y /= 8.0;
  485. currentVertex->vertexNormal.z /= 8.0;
  486. gosASSERT(currentVertex->vertexNormal.z > 0.0);
  487. }
  488. currentVertex++;
  489. }
  490. Terrain::recalcShadows = false;
  491. }
  492. //---------------------------------------------------------------------------
  493. void MapData::clearShadows()
  494. {
  495. //----------------------------------------
  496. // Let's calc the map dimensions...
  497. long height, width;
  498. height = width = Terrain::verticesBlockSide * Terrain::blocksMapSide;
  499. long totalVertices = height * width;
  500. PostcompVertexPtr currentVertex = blocks;
  501. for (long i=0;i<totalVertices;i++)
  502. {
  503. currentVertex->shadow = 0;
  504. currentVertex++;
  505. }
  506. }
  507. long sprayFrame = 1;
  508. long sprayAdd = 1;
  509. float SprayTextureNum = 0.0f;
  510. //---------------------------------------------------------------------------
  511. long MapData::update (void)
  512. {
  513. long result = NO_ERR;
  514. if (!blankVertex)
  515. {
  516. blankVertex = new PostcompVertex;
  517. blankVertex->elevation = 33.0f;
  518. blankVertex->textureData = (41<<16) + 41;
  519. blankVertex->vertexNormal.x = 0.0;
  520. blankVertex->vertexNormal.y = 0.0;
  521. blankVertex->vertexNormal.z = 1.0;
  522. blankVertex->localRGBLight = 0xffffffff;
  523. }
  524. Stuff::Vector3D position;
  525. if (eye)
  526. position = eye->getPosition();
  527. else
  528. return NO_ERR;
  529. //-----------------------------------------------------
  530. // Calculate the topLeftVertex from Camera.
  531. // This is the closest vertex to the Physical topLeft
  532. // coordinate of the visible terrain blocks.
  533. topLeftVertex.x = (position.x - Terrain::mapTopLeft3d.x) * Terrain::oneOverWorldUnitsPerVertex;
  534. topLeftVertex.y = (Terrain::mapTopLeft3d.y - position.y) * Terrain::oneOverWorldUnitsPerVertex;
  535. long PVx = float2long(topLeftVertex.x+0.5f);
  536. long PVy = float2long(topLeftVertex.y+0.5f);
  537. float fTLVx = float(PVx) - (Terrain::visibleVerticesPerSide>>1);
  538. float fTLVy = float(PVy) - (Terrain::visibleVerticesPerSide>>1);
  539. long TLVx = float2long(fTLVx);
  540. long TLVy = float2long(fTLVy);
  541. topLeftVertex.x = TLVx; //REAL ABS vertex now. No longer sub classified to block. OK if its out of range. makeLists will handle.
  542. topLeftVertex.y = TLVy;
  543. ScrollUV1 += SCROLL_RATE;
  544. ScrollUV2 -= SCROLL_RATE;
  545. if (ScrollUV1 > 0.5)
  546. {
  547. SCROLL_RATE = -SCROLL_RATE;
  548. }
  549. if (ScrollUV1 < 0.02)
  550. {
  551. SCROLL_RATE = -SCROLL_RATE;
  552. }
  553. if (Terrain::recalcLight && eye)
  554. calcLight();
  555. //Used to scroll the water texture.
  556. {
  557. cloudScrollX += frameLength * cloudScrollSpeedX;
  558. if (cloudScrollX > 1.0f)
  559. cloudScrollX = 0.0f;
  560. cloudScrollY += frameLength * cloudScrollSpeedY;
  561. if (cloudScrollY > 1.0f)
  562. cloudScrollY = 0.0f;
  563. }
  564. Terrain::frameAngle += Terrain::waterFreq * frameLength;
  565. if (Terrain::frameAngle >= 360.0f)
  566. Terrain::frameAngle = 0.0f;
  567. Terrain::frameCosAlpha = cos(Terrain::frameAngle * DEGREES_TO_RADS);
  568. Terrain::frameCos = Terrain::frameCosAlpha * Terrain::waterAmplitude;
  569. SprayTextureNum += frameLength;
  570. if (!Terrain::terrainTextures2)
  571. {
  572. if ((0.0 != Terrain::terrainTextures->getDetailFrameRate(0))
  573. && (SprayTextureNum > (1.0 / Terrain::terrainTextures->getDetailFrameRate(0))))
  574. {
  575. sprayFrame += sprayAdd;
  576. SprayTextureNum = 0.0f;
  577. if (sprayFrame == 31)
  578. {
  579. sprayAdd = -1;
  580. }
  581. else if (sprayFrame == 0)
  582. {
  583. sprayAdd = 1;
  584. }
  585. }
  586. }
  587. else
  588. {
  589. if (Terrain::terrainTextures2->getWaterDetailNumFrames() > 1)
  590. {
  591. if ((0.0 != Terrain::terrainTextures2->getWaterDetailFrameRate())
  592. && (SprayTextureNum > (1.0 / Terrain::terrainTextures2->getWaterDetailFrameRate())))
  593. {
  594. sprayFrame += sprayAdd;
  595. SprayTextureNum = 0.0f;
  596. if (((int)(sprayFrame + sprayAdd)) >= (int)Terrain::terrainTextures2->getWaterDetailNumFrames())/*carefull of the signed/unsigned mismatch*/
  597. {
  598. sprayAdd = -1;
  599. }
  600. else if (sprayFrame <= 0)
  601. {
  602. sprayAdd = 1;
  603. }
  604. }
  605. }
  606. else if (1 == Terrain::terrainTextures2->getWaterDetailNumFrames())
  607. {
  608. sprayFrame = 0;
  609. }
  610. }
  611. return(result);
  612. }
  613. //---------------------------------------------------------------------------
  614. void MapData::makeLists (VertexPtr vertexList, long &numVerts, TerrainQuadPtr quadList, long &numQuads)
  615. {
  616. long topLeftX = float2long(topLeftVertex.x);
  617. long topLeftY = float2long(topLeftVertex.y);
  618. PostcompVertexPtr Pvertex = NULL;
  619. VertexPtr currentVertex = vertexList;
  620. numVerts = 0;
  621. for (int y=0;y<Terrain::visibleVerticesPerSide;y++)
  622. {
  623. for (int x=0;x<Terrain::visibleVerticesPerSide;x++)
  624. {
  625. if ((topLeftX < 0) || (topLeftX >= Terrain::realVerticesMapSide) ||
  626. (topLeftY < 0) || (topLeftY >= Terrain::realVerticesMapSide))
  627. {
  628. //------------------------------------------------------------
  629. // Point this to the Blank Vertex
  630. Pvertex = blankVertex;
  631. currentVertex->vertexNum = -1;
  632. }
  633. else
  634. {
  635. Pvertex = &blocks[topLeftX + (topLeftY * Terrain::realVerticesMapSide)];
  636. currentVertex->vertexNum = topLeftX + (topLeftY * Terrain::realVerticesMapSide);
  637. }
  638. gosASSERT(Pvertex != NULL);
  639. currentVertex->pVertex = Pvertex;
  640. //------------------------------------------------
  641. // Must be calced from ABS positions now!
  642. long blockX = (topLeftX / Terrain::verticesBlockSide);
  643. long blockY = (topLeftY / Terrain::verticesBlockSide);
  644. long vertexX = topLeftX - (blockX * Terrain::verticesBlockSide);
  645. long vertexY = topLeftY - (blockY * Terrain::verticesBlockSide);
  646. currentVertex->blockVertex = ((blockX + (blockY * Terrain::blocksMapSide)) << 16) +
  647. (vertexX + (vertexY * Terrain::verticesBlockSide));
  648. //----------------------------------------------------------------------
  649. // From Blocks and vertex, calculate the World Position
  650. currentVertex->vx = float(topLeftX - Terrain::halfVerticesMapSide) * Terrain::worldUnitsPerVertex;
  651. currentVertex->vy = float(Terrain::halfVerticesMapSide - topLeftY) * Terrain::worldUnitsPerVertex;
  652. //----------------------------------------------------------------------
  653. long posTileR = topLeftY;
  654. long posTileC = topLeftX;
  655. currentVertex->posTile = (posTileR << 16) + (posTileC & 0x0000ffff);
  656. currentVertex->calcThisFrame = 0;
  657. currentVertex->px = currentVertex->py = -99999.0f;
  658. currentVertex->clipInfo = false;
  659. currentVertex++;
  660. numVerts++;
  661. topLeftX++;
  662. }
  663. topLeftX = float2long(topLeftVertex.x);
  664. topLeftY++;
  665. }
  666. //---------------------------------------------------------------
  667. // Now that the vertex list is done, use it to create a tile
  668. // list which corresponds to the correct vertices.
  669. currentVertex = vertexList;
  670. TerrainQuadPtr currentQuad = quadList;
  671. numQuads = 0;
  672. topLeftY = float2long(topLeftVertex.y);
  673. //------------------------------------------------------------------
  674. // The last row and last vertex in each row are only used to create
  675. // the previous tile. They do not have a tile associated with the,
  676. // since they have no other vertices than their own to refer to.
  677. long maxX,maxY;
  678. maxX = maxY = Terrain::visibleVerticesPerSide-1;
  679. for (y=0;y<maxY;y++)
  680. {
  681. for (int x=0;x<maxX;x++)
  682. {
  683. VertexPtr v0, v1, v2 ,v3;
  684. v0 = currentVertex;
  685. v1 = currentVertex+1;
  686. v2 = currentVertex+Terrain::visibleVerticesPerSide+1;
  687. v3 = currentVertex+Terrain::visibleVerticesPerSide;
  688. #ifdef _DEBUG
  689. v0->selected = false;
  690. #endif
  691. {
  692. bool tlx = (topLeftX & 1);
  693. bool tly = (topLeftY & 1);
  694. bool yby2 = (y & 1) ^ (tly);
  695. bool xby2 = (x & 1) ^ (tlx);
  696. if (yby2)
  697. {
  698. if (xby2)
  699. {
  700. currentQuad->init(v0,v1,v2,v3);
  701. currentQuad->uvMode = BOTTOMRIGHT;
  702. currentQuad++;
  703. numQuads++;
  704. }
  705. else
  706. {
  707. currentQuad->init(v0,v1,v2,v3);
  708. currentQuad->uvMode = BOTTOMLEFT;
  709. currentQuad++;
  710. numQuads++;
  711. }
  712. }
  713. else
  714. {
  715. if (xby2)
  716. {
  717. currentQuad->init(v0,v1,v2,v3);
  718. currentQuad->uvMode = BOTTOMLEFT;
  719. currentQuad++;
  720. numQuads++;
  721. }
  722. else
  723. {
  724. currentQuad->init(v0,v1,v2,v3);
  725. currentQuad->uvMode = BOTTOMRIGHT;
  726. currentQuad++;
  727. numQuads++;
  728. }
  729. }
  730. }
  731. gosASSERT(currentVertex->pVertex->vertexNormal.z > 0.0);
  732. currentVertex++;
  733. }
  734. //----------------------------------------------------------------
  735. // We are pointing to the last vertex in the row. Increment again
  736. // to point to first vertex in next row.
  737. currentVertex++;
  738. }
  739. }
  740. //---------------------------------------------------------------------------
  741. void MapData::setOverlayTile (long block, long vertex, long offset)
  742. {
  743. long blockX = (block % Terrain::blocksMapSide);
  744. long blockY = (block / Terrain::blocksMapSide);
  745. long vertexX = (vertex % Terrain::verticesBlockSide);
  746. long vertexY = (vertex / Terrain::verticesBlockSide);
  747. long indexX = blockX * Terrain::verticesBlockSide + vertexX;
  748. long indexY = blockY * Terrain::verticesBlockSide + vertexY;
  749. long index = indexX + indexY * Terrain::realVerticesMapSide;
  750. PostcompVertexPtr ourBlock = &blocks[index];
  751. ourBlock[vertex].textureData += (offset<<16);
  752. setTerrain(indexY,indexX,-1);
  753. }
  754. //---------------------------------------------------------------------------
  755. void MapData::setOverlay( long indexY, long indexX, Overlays type, unsigned long offset )
  756. {
  757. long index = indexX + indexY * Terrain::realVerticesMapSide;
  758. PostcompVertexPtr ourBlock = &blocks[index];
  759. ourBlock->textureData &= 0x0000ffff;
  760. ourBlock->textureData |= Terrain::terrainTextures->getOverlayHandle( type, offset );
  761. setTerrain(indexY,indexX,-1);
  762. }
  763. //---------------------------------------------------------------------------
  764. unsigned long MapData::getTexture( long indexY, long indexX )
  765. {
  766. gosASSERT( indexX > -1 && indexX < Terrain::realVerticesMapSide );
  767. gosASSERT( indexY > -1 && indexY < Terrain::realVerticesMapSide );
  768. long index = indexX + indexY * Terrain::realVerticesMapSide;
  769. return blocks[index].textureData;
  770. }
  771. //---------------------------------------------------------------------------
  772. float MapData::terrainElevation( long indexY, long indexX )
  773. {
  774. gosASSERT( indexX > -1 && indexX < Terrain::realVerticesMapSide );
  775. gosASSERT( indexY > -1 && indexY < Terrain::realVerticesMapSide );
  776. long index = indexX + indexY * Terrain::realVerticesMapSide;
  777. return blocks[index].elevation;
  778. }
  779. //---------------------------------------------------------------------------
  780. void MapData::setTerrain( long indexY, long indexX, int Type )
  781. {
  782. long Vertices[4][2];
  783. int x = 0;
  784. int y = 1;
  785. Vertices[0][x] = indexX;
  786. Vertices[0][y] = indexY;
  787. Vertices[1][x] = indexX > 0 ? indexX - 1 : 0;
  788. Vertices[1][y] = indexY;
  789. Vertices[2][x] = indexX > 0 ? indexX - 1 : 0;
  790. Vertices[2][y] = indexY > 0 ? indexY - 1 : 0;
  791. Vertices[3][x] = indexX;
  792. Vertices[3][y] = indexY > 0 ? indexY - 1 : 0;
  793. for ( int i = 0; i < 4; ++i )
  794. {
  795. if ( ( indexX > -1 && indexX < Terrain::realVerticesMapSide - 1 ) &&
  796. ( indexY > -1 && indexY < Terrain::realVerticesMapSide - 1 ) )
  797. {
  798. long index = Vertices[i][x] + Vertices[i][y] * Terrain::realVerticesMapSide;
  799. PostcompVertexPtr currentVertex = &blocks[index];
  800. currentVertex->textureData &= 0xffff0000;
  801. if ( i == 0 && Type > 0)
  802. currentVertex->terrainType = Type;
  803. //-----------------------------------------------
  804. // Get the data needed to make this terrain quad
  805. PostcompVertex *pVertex1 = currentVertex;
  806. PostcompVertex *pVertex2 = currentVertex + 1;
  807. PostcompVertex *pVertex3 = currentVertex + Terrain::realVerticesMapSide + 1;
  808. PostcompVertex *pVertex4 = currentVertex + Terrain::realVerticesMapSide;
  809. //-------------------------------------------------------------------------------
  810. // Store texture in bottom part from TxmIndex provided by TerrainTextureManager
  811. DWORD terrainType = pVertex1->terrainType +
  812. (pVertex2->terrainType << 8) +
  813. (pVertex3->terrainType << 16) +
  814. (pVertex4->terrainType << 24);
  815. DWORD overlayType = (pVertex1->textureData >> 16);
  816. if (overlayType < Terrain::terrainTextures->getFirstOverlay())
  817. {
  818. pVertex1->textureData = 0xffff0000; //Erase the overlay, the numbers changed!
  819. overlayType = 0xffff;
  820. }
  821. //Insure Base Texture is zero.
  822. pVertex1->textureData &= (pVertex1->textureData & 0xffff0000);
  823. DWORD txmResult = Terrain::terrainTextures->setTexture(terrainType,overlayType);
  824. pVertex1->textureData += txmResult;
  825. }
  826. }
  827. }
  828. //---------------------------------------------------------------------------
  829. long MapData::getTerrain( long tileR, long tileC )
  830. {
  831. gosASSERT( tileR < Terrain::realVerticesMapSide && tileR > -1 );
  832. gosASSERT( tileC < Terrain::realVerticesMapSide && tileC > -1 );
  833. long index = tileC + tileR * Terrain::realVerticesMapSide;
  834. return blocks[index].terrainType;
  835. }
  836. //---------------------------------------------------------------------------
  837. void MapData::getOverlay( long tileR, long tileC, Overlays& type, unsigned long& Offset )
  838. {
  839. gosASSERT( tileR < Terrain::realVerticesMapSide && tileR > -1 );
  840. gosASSERT( tileC < Terrain::realVerticesMapSide && tileC > -1 );
  841. long index = tileC + tileR * Terrain::realVerticesMapSide;
  842. Terrain::terrainTextures->getOverlayInfoFromHandle( blocks[index].textureData, type, Offset );
  843. }
  844. //---------------------------------------------------------------------------
  845. long MapData::getOverlayTile (long block, long vertex)
  846. {
  847. long blockX = (block % Terrain::blocksMapSide);
  848. long blockY = (block / Terrain::blocksMapSide);
  849. long vertexX = (vertex % Terrain::verticesBlockSide);
  850. long vertexY = (vertex / Terrain::verticesBlockSide);
  851. long indexX = blockX * Terrain::verticesBlockSide + vertexX;
  852. long indexY = blockY * Terrain::verticesBlockSide + vertexY;
  853. long index = indexX + indexY * Terrain::realVerticesMapSide;
  854. PostcompVertexPtr ourBlock = &blocks[index];
  855. return (ourBlock[vertex].textureData >> 16);
  856. }
  857. //---------------------------------------------------------------------------
  858. float MapData::terrainAngle (Stuff::Vector3D &position, Stuff::Vector3D* normal)
  859. {
  860. //-------------------------------------------------------------------
  861. // Recoded for real 3D terrain on march 3, 1999. Uses new triangle
  862. // method!
  863. Stuff::Vector3D triVert[3];
  864. Stuff::Vector2DOf<float> upperLeft;
  865. Stuff::Vector3D triPos;
  866. Stuff::Vector3D triangleVector[2];
  867. Stuff::Vector3D perpendicularVec;
  868. float result = 0.0;
  869. triVert[0].Zero();
  870. triVert[1].Zero();
  871. triVert[2].Zero();
  872. if (!Terrain::IsValidTerrainPosition(position))
  873. {
  874. normal->x = normal->y = 0.0f;
  875. normal->z = 1.0f;
  876. return(0.0f);
  877. }
  878. //--------------------------------------------------------
  879. // find closest vertex in UpperLeft direction to Position
  880. upperLeft.x = floor(position.x * Terrain::oneOverWorldUnitsPerVertex);
  881. upperLeft.x *= Terrain::worldUnitsPerVertex;
  882. upperLeft.y = floor(position.y * Terrain::oneOverWorldUnitsPerVertex);
  883. if (float(position.y * Terrain::oneOverWorldUnitsPerVertex) != (float)upperLeft.y)
  884. upperLeft.y += 1.0;
  885. upperLeft.y *= Terrain::worldUnitsPerVertex;
  886. Stuff::Vector2DOf<float> _upperLeft;
  887. _upperLeft.Multiply(upperLeft,float(Terrain::oneOverWorldUnitsPerVertex));
  888. Stuff::Vector2DOf<long> meshOffset;
  889. meshOffset.x = float2long(_upperLeft.x);
  890. meshOffset.y = float2long(_upperLeft.y);
  891. long verticesMapSide = Terrain::verticesBlockSide * Terrain::blocksMapSide;
  892. meshOffset.x += (verticesMapSide>>1);
  893. meshOffset.y = (verticesMapSide>>1) - meshOffset.y;
  894. //Make sure we have map data to return. Otherwise, just make it full bright
  895. if (((meshOffset.x + 1) >= Terrain::realVerticesMapSide) ||
  896. ((meshOffset.y + 1) >= Terrain::realVerticesMapSide) ||
  897. (meshOffset.x < 0) ||
  898. (meshOffset.y < 0))
  899. return(0.0f);
  900. PostcompVertexPtr pVertex1 = &blocks[meshOffset.x + (meshOffset.y * Terrain::realVerticesMapSide)];
  901. PostcompVertexPtr pVertex2 = &blocks[(meshOffset.x+1) + (meshOffset.y * Terrain::realVerticesMapSide)];
  902. PostcompVertexPtr pVertex3 = &blocks[(meshOffset.x+1) + ((meshOffset.y+1) * Terrain::realVerticesMapSide)];
  903. PostcompVertexPtr pVertex4 = &blocks[meshOffset.x + ((meshOffset.y+1) * Terrain::realVerticesMapSide)];
  904. triPos.x = Terrain::worldUnitsPerVertex * floor(_upperLeft.x);
  905. triPos.y = Terrain::worldUnitsPerVertex * floor(_upperLeft.y);
  906. triPos.z = pVertex1->elevation;
  907. bool tlx = (float2long(topLeftVertex.x) & 1);
  908. bool tly = (float2long(topLeftVertex.y) & 1);
  909. long x = meshOffset.x - float2long(topLeftVertex.x);
  910. long y = meshOffset.y - float2long(topLeftVertex.y);
  911. bool yby2 = (y & 1) ^ (tly);
  912. bool xby2 = (x & 1) ^ (tlx);
  913. long uvMode = 0;
  914. if (yby2)
  915. {
  916. if (xby2)
  917. {
  918. uvMode = BOTTOMRIGHT;
  919. }
  920. else
  921. {
  922. uvMode = BOTTOMLEFT;
  923. }
  924. }
  925. else
  926. {
  927. if (xby2)
  928. {
  929. uvMode = BOTTOMLEFT;
  930. }
  931. else
  932. {
  933. uvMode = BOTTOMRIGHT;
  934. }
  935. }
  936. float deltaX = 0.0f;
  937. float deltaY = 0.0f;
  938. if (uvMode == BOTTOMRIGHT)
  939. {
  940. deltaX = fabs(position.x - upperLeft.x);
  941. deltaY = fabs(upperLeft.y - position.y);
  942. //Calculate which triangle and return elevation
  943. //---------------------------------------------
  944. if (deltaX > deltaY)
  945. {
  946. //position is in Top Triangle
  947. //-------------------------
  948. triVert[0] = triPos;
  949. triVert[1].x = triVert[0].x + Terrain::worldUnitsPerVertex;
  950. triVert[1].y = triVert[0].y;
  951. triVert[1].z = pVertex2->elevation;
  952. triVert[2].x = triVert[1].x;
  953. triVert[2].y = triVert[0].y - Terrain::worldUnitsPerVertex;
  954. triVert[2].z = pVertex3->elevation;
  955. triangleVector[0].Subtract(triVert[1],triVert[0]);
  956. triangleVector[1].Subtract(triVert[2],triVert[0]);
  957. }
  958. else
  959. {
  960. //Position is in Bottom Triangle
  961. //----------------------------
  962. triVert[0] = triPos;
  963. triVert[1].x = triVert[0].x + Terrain::worldUnitsPerVertex;
  964. triVert[1].y = triVert[0].y - Terrain::worldUnitsPerVertex;
  965. triVert[1].z = pVertex3->elevation;
  966. triVert[2].x = triVert[0].x;
  967. triVert[2].y = triVert[1].y;
  968. triVert[2].z = pVertex4->elevation;
  969. triangleVector[0].Subtract(triVert[2],triVert[0]);
  970. triangleVector[1].Subtract(triVert[1],triVert[0]);
  971. }
  972. }
  973. else if (uvMode == BOTTOMLEFT)
  974. {
  975. deltaX = fabs((upperLeft.x + Terrain::worldUnitsPerVertex) - position.x);
  976. deltaY = fabs(upperLeft.y - position.y);
  977. //Calculate which triangle and return elevation
  978. //---------------------------------------------
  979. if (deltaX > deltaY)
  980. {
  981. //position is in Top Triangle
  982. //-------------------------
  983. triVert[1] = triPos;
  984. triVert[0].x = triPos.x + Terrain::worldUnitsPerVertex;
  985. triVert[0].y = triPos.y;
  986. triVert[0].z = pVertex2->elevation;
  987. triVert[2].x = triVert[1].x;
  988. triVert[2].y = triVert[1].y - Terrain::worldUnitsPerVertex;
  989. triVert[2].z = pVertex4->elevation;
  990. triangleVector[0].Subtract(triVert[1],triVert[0]);
  991. triangleVector[1].Subtract(triVert[2],triVert[0]);
  992. }
  993. else
  994. {
  995. //Position is in Bottom Triangle
  996. //----------------------------
  997. triVert[0].x = triPos.x + Terrain::worldUnitsPerVertex;
  998. triVert[0].y = triPos.y;
  999. triVert[0].z = pVertex2->elevation;
  1000. triVert[1].x = triPos.x;
  1001. triVert[1].y = triVert[0].y - Terrain::worldUnitsPerVertex;
  1002. triVert[1].z = pVertex4->elevation;
  1003. triVert[2].x = triVert[0].x;
  1004. triVert[2].y = triVert[1].y;
  1005. triVert[2].z = pVertex3->elevation;
  1006. triangleVector[0].Subtract(triVert[2],triVert[0]);
  1007. triangleVector[1].Subtract(triVert[1],triVert[0]);
  1008. }
  1009. deltaX = -deltaX; //Must reverse for Bottom_left triangles
  1010. }
  1011. //----------------------------------------------
  1012. //Calculate Normal vector to the Triangle Plane
  1013. triangleVector[0].Normalize(triangleVector[0]);
  1014. triangleVector[1].Normalize(triangleVector[1]);
  1015. perpendicularVec.Cross(triangleVector[0],triangleVector[1]);
  1016. //------------------------------
  1017. //Calculate terrain angle
  1018. gosASSERT(perpendicularVec.z != 0L);
  1019. {
  1020. Stuff::Vector3D worldK;
  1021. worldK.x = 0.0;
  1022. worldK.y = 0.0;
  1023. worldK.z = 1.0;
  1024. if (perpendicularVec.z < 0L)
  1025. {
  1026. perpendicularVec.Negate(perpendicularVec);
  1027. }
  1028. perpendicularVec.Normalize(perpendicularVec);
  1029. if (normal)
  1030. normal->Normalize(perpendicularVec);
  1031. //We ONLY want PITCH! No roll should be included!
  1032. perpendicularVec.y = 0.0f;
  1033. result = perpendicularVec * worldK;
  1034. result = acos(result) * RADS_TO_DEGREES;
  1035. }
  1036. return (result);
  1037. }
  1038. //---------------------------------------------------------------------------
  1039. float MapData::terrainLight (Stuff::Vector3D &position)
  1040. {
  1041. if (!Terrain::IsValidTerrainPosition(position))
  1042. return(1.0f);
  1043. //-------------------------------------------------------
  1044. // Need pointer to block containing this vertex.
  1045. float fTLVx = (position.x - Terrain::mapTopLeft3d.x) * Terrain::oneOverWorldUnitsPerVertex;
  1046. float fTLVy = (Terrain::mapTopLeft3d.y - position.y) * Terrain::oneOverWorldUnitsPerVertex;
  1047. long PVx = float2long(fTLVx);
  1048. long PVy = float2long(fTLVy);
  1049. //Make sure we have map data to return. Otherwise, just make it full bright
  1050. if (((PVx + 1) >= Terrain::realVerticesMapSide) ||
  1051. ((PVy + 1) >= Terrain::realVerticesMapSide) ||
  1052. (PVx < 0) ||
  1053. (PVy < 0))
  1054. return 1.0f;
  1055. PostcompVertexPtr pVertex1 = &blocks[PVx + (PVy * Terrain::realVerticesMapSide)];
  1056. PostcompVertexPtr pVertex2 = &blocks[(PVx+1) + (PVy * Terrain::realVerticesMapSide)];
  1057. PostcompVertexPtr pVertex3 = &blocks[(PVx+1) + ((PVy+1) * Terrain::realVerticesMapSide)];
  1058. PostcompVertexPtr pVertex4 = &blocks[PVx + ((PVy+1) * Terrain::realVerticesMapSide)];
  1059. Stuff::Vector3D vPos1,vPos2,vPos3,vPos4;
  1060. vPos1.x = (PVx * Terrain::worldUnitsPerVertex) + Terrain::mapTopLeft3d.x;
  1061. vPos1.y = Terrain::mapTopLeft3d.y - (PVy * Terrain::worldUnitsPerVertex);
  1062. vPos1.z = terrainElevation(vPos1);
  1063. vPos2.x = vPos1.x + Terrain::worldUnitsPerVertex;
  1064. vPos2.y = vPos1.y;
  1065. vPos2.z = terrainElevation(vPos2);
  1066. vPos3.x = vPos2.x;
  1067. vPos3.y = vPos1.y - Terrain::worldUnitsPerVertex;
  1068. vPos3.z = terrainElevation(vPos3);
  1069. vPos4.x = vPos1.x;
  1070. vPos4.y = vPos3.y;
  1071. vPos4.z = terrainElevation(vPos4);
  1072. vPos1.Subtract(position,vPos1);
  1073. vPos2.Subtract(position,vPos2);
  1074. vPos3.Subtract(position,vPos3);
  1075. vPos4.Subtract(position,vPos4);
  1076. float dist1 = vPos1.GetLength();
  1077. float dist2 = vPos2.GetLength();
  1078. float dist3 = vPos3.GetLength();
  1079. float dist4 = vPos4.GetLength();
  1080. //---------------------------------------
  1081. // CLOSEST vertex has GREATEST weight
  1082. float maxDist = fmax(dist4,fmax(dist3,fmax(dist2,dist1)));
  1083. dist1 = maxDist - dist1;
  1084. dist2 = maxDist - dist2;
  1085. dist3 = maxDist - dist3;
  1086. dist4 = maxDist - dist4;
  1087. float distWeight = dist1 + dist2 + dist3 + dist4;
  1088. Stuff::Vector3D weightedNormal;
  1089. weightedNormal.x = (pVertex1->vertexNormal.x * dist1) +
  1090. (pVertex2->vertexNormal.x * dist2) +
  1091. (pVertex3->vertexNormal.x * dist3) +
  1092. (pVertex4->vertexNormal.x * dist4);
  1093. weightedNormal.y = (pVertex1->vertexNormal.y * dist1) +
  1094. (pVertex2->vertexNormal.y * dist2) +
  1095. (pVertex3->vertexNormal.y * dist3) +
  1096. (pVertex4->vertexNormal.y * dist4);
  1097. weightedNormal.z = (pVertex1->vertexNormal.z * dist1) +
  1098. (pVertex2->vertexNormal.z * dist2) +
  1099. (pVertex3->vertexNormal.z * dist3) +
  1100. (pVertex4->vertexNormal.z * dist4);
  1101. if ( distWeight > Stuff::SMALL )
  1102. weightedNormal /= distWeight;
  1103. else
  1104. weightedNormal = Stuff::Vector3D( 0.0, 0.0, 1.0 );
  1105. float lightIntensity = weightedNormal * eye->lightDirection;
  1106. return (lightIntensity);
  1107. }
  1108. //---------------------------------------------------------------------------
  1109. Stuff::Vector3D MapData::terrainNormal (Stuff::Vector3D& position)
  1110. {
  1111. //-------------------------------------------------------------------
  1112. // Recoded for real 3D terrain on march 3, 1999. Uses new triangle
  1113. // method!
  1114. Stuff::Vector3D triVert[3];
  1115. Stuff::Vector2DOf<float> upperLeft;
  1116. Stuff::Vector3D triPos;
  1117. Stuff::Vector3D triangleVector[2];
  1118. Stuff::Vector3D perpendicularVec;
  1119. triVert[0].Zero();
  1120. triVert[1].Zero();
  1121. triVert[2].Zero();
  1122. if (!Terrain::IsValidTerrainPosition(position))
  1123. return(Stuff::Vector3D(0.0f,0.0f,1.0f));
  1124. //--------------------------------------------------------
  1125. // find closest vertex in UpperLeft direction to Position
  1126. upperLeft.x = floor(position.x * Terrain::oneOverWorldUnitsPerVertex);
  1127. upperLeft.x *= Terrain::worldUnitsPerVertex;
  1128. upperLeft.y = floor(position.y * Terrain::oneOverWorldUnitsPerVertex);
  1129. if (float(position.y * Terrain::oneOverWorldUnitsPerVertex) != (float)upperLeft.y)
  1130. upperLeft.y += 1.0;
  1131. upperLeft.y *= Terrain::worldUnitsPerVertex;
  1132. Stuff::Vector2DOf<float> _upperLeft;
  1133. _upperLeft.Multiply(upperLeft,float(Terrain::oneOverWorldUnitsPerVertex));
  1134. Stuff::Vector2DOf<long> meshOffset;
  1135. meshOffset.x = float2long(_upperLeft.x);
  1136. meshOffset.y = float2long(_upperLeft.y);
  1137. long verticesMapSide = Terrain::verticesBlockSide * Terrain::blocksMapSide;
  1138. meshOffset.x += (verticesMapSide>>1);
  1139. meshOffset.y = (verticesMapSide>>1) - meshOffset.y;
  1140. //Make sure we have map data to return. Otherwise, just make it full bright
  1141. if (((meshOffset.x + 1) >= Terrain::realVerticesMapSide) ||
  1142. ((meshOffset.y + 1) >= Terrain::realVerticesMapSide) ||
  1143. (meshOffset.x < 0) ||
  1144. (meshOffset.y < 0))
  1145. return(Stuff::Vector3D(0.0f,0.0f,1.0f));
  1146. PostcompVertexPtr pVertex1 = &blocks[meshOffset.x + (meshOffset.y * Terrain::realVerticesMapSide)];
  1147. PostcompVertexPtr pVertex2 = &blocks[(meshOffset.x+1) + (meshOffset.y * Terrain::realVerticesMapSide)];
  1148. PostcompVertexPtr pVertex3 = &blocks[(meshOffset.x+1) + ((meshOffset.y+1) * Terrain::realVerticesMapSide)];
  1149. PostcompVertexPtr pVertex4 = &blocks[meshOffset.x + ((meshOffset.y+1) * Terrain::realVerticesMapSide)];
  1150. triPos.x = Terrain::worldUnitsPerVertex * floor(_upperLeft.x);
  1151. triPos.y = Terrain::worldUnitsPerVertex * floor(_upperLeft.y);
  1152. triPos.z = pVertex1->elevation;
  1153. bool tlx = (float2long(topLeftVertex.x) & 1);
  1154. bool tly = (float2long(topLeftVertex.y) & 1);
  1155. long x = meshOffset.x - float2long(topLeftVertex.x);
  1156. long y = meshOffset.y - float2long(topLeftVertex.y);
  1157. bool yby2 = (y & 1) ^ (tly);
  1158. bool xby2 = (x & 1) ^ (tlx);
  1159. long uvMode = 0;
  1160. if (yby2)
  1161. {
  1162. if (xby2)
  1163. {
  1164. uvMode = BOTTOMRIGHT;
  1165. }
  1166. else
  1167. {
  1168. uvMode = BOTTOMLEFT;
  1169. }
  1170. }
  1171. else
  1172. {
  1173. if (xby2)
  1174. {
  1175. uvMode = BOTTOMLEFT;
  1176. }
  1177. else
  1178. {
  1179. uvMode = BOTTOMRIGHT;
  1180. }
  1181. }
  1182. float deltaX = 0.0f;
  1183. float deltaY = 0.0f;
  1184. if (uvMode == BOTTOMRIGHT)
  1185. {
  1186. deltaX = fabs(position.x - upperLeft.x);
  1187. deltaY = fabs(upperLeft.y - position.y);
  1188. //Calculate which triangle and return elevation
  1189. //---------------------------------------------
  1190. if (deltaX > deltaY)
  1191. {
  1192. //position is in Top Triangle
  1193. //-------------------------
  1194. triVert[0] = triPos;
  1195. triVert[1].x = triVert[0].x + Terrain::worldUnitsPerVertex;
  1196. triVert[1].y = triVert[0].y;
  1197. triVert[1].z = pVertex2->elevation;
  1198. triVert[2].x = triVert[1].x;
  1199. triVert[2].y = triVert[0].y - Terrain::worldUnitsPerVertex;
  1200. triVert[2].z = pVertex3->elevation;
  1201. triangleVector[0].Subtract(triVert[1],triVert[0]);
  1202. triangleVector[1].Subtract(triVert[2],triVert[0]);
  1203. }
  1204. else
  1205. {
  1206. //Position is in Bottom Triangle
  1207. //----------------------------
  1208. triVert[0] = triPos;
  1209. triVert[1].x = triVert[0].x + Terrain::worldUnitsPerVertex;
  1210. triVert[1].y = triVert[0].y - Terrain::worldUnitsPerVertex;
  1211. triVert[1].z = pVertex3->elevation;
  1212. triVert[2].x = triVert[0].x;
  1213. triVert[2].y = triVert[1].y;
  1214. triVert[2].z = pVertex4->elevation;
  1215. triangleVector[0].Subtract(triVert[2],triVert[0]);
  1216. triangleVector[1].Subtract(triVert[1],triVert[0]);
  1217. }
  1218. }
  1219. else if (uvMode == BOTTOMLEFT)
  1220. {
  1221. deltaX = fabs((upperLeft.x + Terrain::worldUnitsPerVertex) - position.x);
  1222. deltaY = fabs(upperLeft.y - position.y);
  1223. //Calculate which triangle and return elevation
  1224. //---------------------------------------------
  1225. if (deltaX > deltaY)
  1226. {
  1227. //position is in Top Triangle
  1228. //-------------------------
  1229. triVert[1] = triPos;
  1230. triVert[0].x = triPos.x + Terrain::worldUnitsPerVertex;
  1231. triVert[0].y = triPos.y;
  1232. triVert[0].z = pVertex2->elevation;
  1233. triVert[2].x = triVert[1].x;
  1234. triVert[2].y = triVert[1].y - Terrain::worldUnitsPerVertex;
  1235. triVert[2].z = pVertex4->elevation;
  1236. triangleVector[0].Subtract(triVert[1],triVert[0]);
  1237. triangleVector[1].Subtract(triVert[2],triVert[0]);
  1238. }
  1239. else
  1240. {
  1241. //Position is in Bottom Triangle
  1242. //----------------------------
  1243. triVert[0].x = triPos.x + Terrain::worldUnitsPerVertex;
  1244. triVert[0].y = triPos.y;
  1245. triVert[0].z = pVertex2->elevation;
  1246. triVert[1].x = triPos.x;
  1247. triVert[1].y = triVert[0].y - Terrain::worldUnitsPerVertex;
  1248. triVert[1].z = pVertex4->elevation;
  1249. triVert[2].x = triVert[0].x;
  1250. triVert[2].y = triVert[1].y;
  1251. triVert[2].z = pVertex3->elevation;
  1252. triangleVector[0].Subtract(triVert[2],triVert[0]);
  1253. triangleVector[1].Subtract(triVert[1],triVert[0]);
  1254. }
  1255. deltaX = -deltaX; //Must reverse for Bottom_left triangles
  1256. }
  1257. //----------------------------------------------
  1258. //Calculate Normal vector to the Triangle Plane
  1259. triangleVector[0].Normalize(triangleVector[0]);
  1260. triangleVector[1].Normalize(triangleVector[1]);
  1261. perpendicularVec.Cross(triangleVector[0],triangleVector[1]);
  1262. //------------------------------
  1263. //Calculate terrain Normal
  1264. if (perpendicularVec.z < 0L)
  1265. {
  1266. perpendicularVec.Negate(perpendicularVec);
  1267. }
  1268. perpendicularVec.Normalize(perpendicularVec);
  1269. return (perpendicularVec);
  1270. }
  1271. //---------------------------------------------------------------------------
  1272. float MapData::terrainElevation (Stuff::Vector3D &position)
  1273. {
  1274. //-------------------------------------------------------------------
  1275. // Recoded for real 3D terrain on march 3, 1999. Uses new triangle
  1276. // method!
  1277. Stuff::Vector3D triVert[3];
  1278. Stuff::Vector2DOf<float> upperLeft;
  1279. Stuff::Vector3D triPos;
  1280. Stuff::Vector3D triangleVector[2];
  1281. Stuff::Vector3D perpendicularVec;
  1282. float result = 0.0;
  1283. triVert[0].Zero();
  1284. triVert[1].Zero();
  1285. triVert[2].Zero();
  1286. if (!Terrain::IsValidTerrainPosition(position))
  1287. return(0.0f);
  1288. //--------------------------------------------------------
  1289. // find closest vertex in UpperLeft direction to Position
  1290. upperLeft.x = floor(position.x * Terrain::oneOverWorldUnitsPerVertex);
  1291. upperLeft.x *= Terrain::worldUnitsPerVertex;
  1292. upperLeft.y = floor(position.y * Terrain::oneOverWorldUnitsPerVertex);
  1293. if (float(position.y * Terrain::oneOverWorldUnitsPerVertex) != (float)upperLeft.y)
  1294. upperLeft.y += 1.0;
  1295. upperLeft.y *= Terrain::worldUnitsPerVertex;
  1296. Stuff::Vector2DOf<float> _upperLeft;
  1297. _upperLeft.Multiply(upperLeft,float(Terrain::oneOverWorldUnitsPerVertex));
  1298. Stuff::Vector2DOf<long> meshOffset;
  1299. meshOffset.x = floor(_upperLeft.x);
  1300. meshOffset.y = floor(_upperLeft.y);
  1301. if (long(floor(_upperLeft.x)) != float2long(_upperLeft.x))
  1302. PAUSE(("Long != float2long %d -> %d",long(floor(_upperLeft.x)),float2long(_upperLeft.x)));
  1303. if (long(floor(_upperLeft.y)) != float2long(_upperLeft.y))
  1304. PAUSE(("Long != float2long %d -> %d",long(floor(_upperLeft.y)),float2long(_upperLeft.y)));
  1305. long verticesMapSide = Terrain::verticesBlockSide * Terrain::blocksMapSide;
  1306. meshOffset.x += (verticesMapSide>>1);
  1307. meshOffset.y = (verticesMapSide>>1) - meshOffset.y;
  1308. if ((meshOffset.x >= (verticesMapSide-1)))
  1309. return 0.0f;
  1310. if ((meshOffset.y >= (verticesMapSide-1)))
  1311. return 0.0f;
  1312. PostcompVertexPtr pVertex1 = &blocks[meshOffset.x + (meshOffset.y * Terrain::realVerticesMapSide)];
  1313. PostcompVertexPtr pVertex2 = &blocks[(meshOffset.x+1) + (meshOffset.y * Terrain::realVerticesMapSide)];
  1314. PostcompVertexPtr pVertex3 = &blocks[(meshOffset.x+1) + ((meshOffset.y+1) * Terrain::realVerticesMapSide)];
  1315. PostcompVertexPtr pVertex4 = &blocks[meshOffset.x + ((meshOffset.y+1) * Terrain::realVerticesMapSide)];
  1316. triPos.x = Terrain::worldUnitsPerVertex * floor(_upperLeft.x);
  1317. triPos.y = Terrain::worldUnitsPerVertex * floor(_upperLeft.y);
  1318. triPos.z = pVertex1->elevation;
  1319. if (long(topLeftVertex.x) != float2long(topLeftVertex.x))
  1320. PAUSE(("Long != float2long %d -> %d",long(topLeftVertex.x),float2long(topLeftVertex.x)));
  1321. if (long(topLeftVertex.y) != float2long(topLeftVertex.y))
  1322. PAUSE(("Long != float2long %d -> %d",long(topLeftVertex.y),float2long(topLeftVertex.y)));
  1323. bool tlx = (long(topLeftVertex.x) & 1);
  1324. bool tly = (long(topLeftVertex.y) & 1);
  1325. long x = meshOffset.x - topLeftVertex.x;
  1326. long y = meshOffset.y - topLeftVertex.y;
  1327. bool yby2 = (y & 1) ^ (tly);
  1328. bool xby2 = (x & 1) ^ (tlx);
  1329. long uvMode = 0;
  1330. if (yby2)
  1331. {
  1332. if (xby2)
  1333. {
  1334. uvMode = BOTTOMRIGHT;
  1335. }
  1336. else
  1337. {
  1338. uvMode = BOTTOMLEFT;
  1339. }
  1340. }
  1341. else
  1342. {
  1343. if (xby2)
  1344. {
  1345. uvMode = BOTTOMLEFT;
  1346. }
  1347. else
  1348. {
  1349. uvMode = BOTTOMRIGHT;
  1350. }
  1351. }
  1352. float deltaX = 0.0f;
  1353. float deltaY = 0.0f;
  1354. if (uvMode == BOTTOMRIGHT)
  1355. {
  1356. deltaX = fabs(position.x - upperLeft.x);
  1357. deltaY = fabs(upperLeft.y - position.y);
  1358. //Calculate which triangle and return elevation
  1359. //---------------------------------------------
  1360. if (deltaX > deltaY)
  1361. {
  1362. //position is in Top Triangle
  1363. //-------------------------
  1364. triVert[0] = triPos;
  1365. triVert[1].x = triVert[0].x + Terrain::worldUnitsPerVertex;
  1366. triVert[1].y = triVert[0].y;
  1367. triVert[1].z = pVertex2->elevation;
  1368. triVert[2].x = triVert[1].x;
  1369. triVert[2].y = triVert[0].y - Terrain::worldUnitsPerVertex;
  1370. triVert[2].z = pVertex3->elevation;
  1371. triangleVector[0].Subtract(triVert[1],triVert[0]);
  1372. triangleVector[1].Subtract(triVert[2],triVert[0]);
  1373. }
  1374. else
  1375. {
  1376. //Position is in Bottom Triangle
  1377. //----------------------------
  1378. triVert[0] = triPos;
  1379. triVert[1].x = triVert[0].x + Terrain::worldUnitsPerVertex;
  1380. triVert[1].y = triVert[0].y - Terrain::worldUnitsPerVertex;
  1381. triVert[1].z = pVertex3->elevation;
  1382. triVert[2].x = triVert[0].x;
  1383. triVert[2].y = triVert[1].y;
  1384. triVert[2].z = pVertex4->elevation;
  1385. triangleVector[0].Subtract(triVert[2],triVert[0]);
  1386. triangleVector[1].Subtract(triVert[1],triVert[0]);
  1387. }
  1388. }
  1389. else if (uvMode == BOTTOMLEFT)
  1390. {
  1391. deltaX = fabs((upperLeft.x + Terrain::worldUnitsPerVertex) - position.x);
  1392. deltaY = fabs(upperLeft.y - position.y);
  1393. //Calculate which triangle and return elevation
  1394. //---------------------------------------------
  1395. if (deltaX > deltaY)
  1396. {
  1397. //position is in Top Triangle
  1398. //-------------------------
  1399. triVert[1] = triPos;
  1400. triVert[0].x = triPos.x + Terrain::worldUnitsPerVertex;
  1401. triVert[0].y = triPos.y;
  1402. triVert[0].z = pVertex2->elevation;
  1403. triVert[2].x = triVert[1].x;
  1404. triVert[2].y = triVert[1].y - Terrain::worldUnitsPerVertex;
  1405. triVert[2].z = pVertex4->elevation;
  1406. triangleVector[0].Subtract(triVert[1],triVert[0]);
  1407. triangleVector[1].Subtract(triVert[2],triVert[0]);
  1408. }
  1409. else
  1410. {
  1411. //Position is in Bottom Triangle
  1412. //----------------------------
  1413. triVert[0].x = triPos.x + Terrain::worldUnitsPerVertex;
  1414. triVert[0].y = triPos.y;
  1415. triVert[0].z = pVertex2->elevation;
  1416. triVert[1].x = triPos.x;
  1417. triVert[1].y = triVert[0].y - Terrain::worldUnitsPerVertex;
  1418. triVert[1].z = pVertex4->elevation;
  1419. triVert[2].x = triVert[0].x;
  1420. triVert[2].y = triVert[1].y;
  1421. triVert[2].z = pVertex3->elevation;
  1422. triangleVector[0].Subtract(triVert[2],triVert[0]);
  1423. triangleVector[1].Subtract(triVert[1],triVert[0]);
  1424. }
  1425. deltaX = -deltaX; //Must reverse for Bottom_left triangles
  1426. }
  1427. //----------------------------------------------
  1428. //Calculate Normal vector to the Triangle Plane
  1429. triangleVector[0].Normalize(triangleVector[0]);
  1430. triangleVector[1].Normalize(triangleVector[1]);
  1431. perpendicularVec.Cross(triangleVector[0],triangleVector[1]);
  1432. //------------------------------
  1433. //Calculate terrain elevation
  1434. if (perpendicularVec.z != 0L)
  1435. {
  1436. if (perpendicularVec.z < 0L)
  1437. {
  1438. perpendicularVec.Negate(perpendicularVec);
  1439. }
  1440. float perpendX = perpendicularVec.x / perpendicularVec.z;
  1441. float perpendY = perpendicularVec.y / perpendicularVec.z;
  1442. result = (deltaX*perpendX);
  1443. result += ((-deltaY)*perpendY);
  1444. result = -result;
  1445. result += triVert[0].z;
  1446. }
  1447. return (result);
  1448. }
  1449. //---------------------------------------------------------------------------
  1450. void MapData::unselectAll()
  1451. {
  1452. for ( int i = 0; i < Terrain::realVerticesMapSide * Terrain::realVerticesMapSide; ++i )
  1453. {
  1454. blocks[i].selected = false;
  1455. }
  1456. hasSelection = 0;
  1457. }
  1458. //---------------------------------------------------------------------------
  1459. void MapData::unhighlightAll()
  1460. {
  1461. for ( int i = 0; i < Terrain::realVerticesMapSide * Terrain::realVerticesMapSide; ++i )
  1462. {
  1463. blocks[i].highlighted = false;
  1464. }
  1465. }
  1466. //---------------------------------------------------------------------------
  1467. void MapData::selectVertex( unsigned long tileRow, unsigned long tileCol, bool bSelect, bool bToggle)
  1468. {
  1469. //Just return. Don't select anything!
  1470. if ( tileRow >= Terrain::realVerticesMapSide )
  1471. return;
  1472. if ( tileCol >= Terrain::realVerticesMapSide )
  1473. return;
  1474. unsigned long index = tileRow * Terrain::realVerticesMapSide + tileCol;
  1475. blocks[index].selected = bToggle ? !blocks[index].selected : bSelect;
  1476. if ( blocks[index].selected )
  1477. hasSelection ++;
  1478. else
  1479. hasSelection --;
  1480. if ( hasSelection < 0 )
  1481. hasSelection = 0;
  1482. }
  1483. //---------------------------------------------------------------------------
  1484. bool MapData::isVertexSelected( unsigned long tileRow, unsigned long tileCol )
  1485. {
  1486. gosASSERT( tileRow < Terrain::realVerticesMapSide );
  1487. gosASSERT( tileCol < Terrain::realVerticesMapSide );
  1488. unsigned long index = tileRow * Terrain::realVerticesMapSide + tileCol;
  1489. return blocks[index].selected ? true : false;
  1490. }
  1491. //---------------------------------------------------------------------------