editableheightfield.cpp 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  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 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : leveledit *
  23. * *
  24. * $Archive:: /Commando/Code/Tools/LevelEdit/editableheightfield.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 3/11/02 5:01p $*
  29. * *
  30. * $Revision:: 5 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "stdafx.h"
  36. #include "editableheightfield.h"
  37. #include "utils.h"
  38. #include "dx8vertexbuffer.h"
  39. #include "dx8indexbuffer.h"
  40. #include "dx8wrapper.h"
  41. #include "sortingrenderer.h"
  42. #include "rinfo.h"
  43. #include "camera.h"
  44. #include "dx8fvf.h"
  45. #include "filemgr.h"
  46. #include "vector2i.h"
  47. #include "terrainmaterial.h"
  48. #include "renegadeterrainpatch.h"
  49. #include "renegadeterrainmaterialpass.h"
  50. #include "terrainmaterial.h"
  51. #include "staticphys.h"
  52. #include "sceneeditor.h"
  53. #include "filemgr.h"
  54. #include "nodemgr.h"
  55. ////////////////////////////////////////////////////////////////
  56. // Local constants
  57. ////////////////////////////////////////////////////////////////
  58. enum
  59. {
  60. CHUNKID_VARIABLES = 0x02261040,
  61. CHUNKID_HEIGHTS,
  62. CHUNKID_TEXTURE_WEIGHTS,
  63. CHUNKID_MATERIAL_LIST,
  64. CHUNKID_MATERIAL,
  65. CHUNKID_EMPTY_MATERIAL_SLOT,
  66. CHUNKID_QUAD_FLAGS
  67. };
  68. enum
  69. {
  70. VARID_GRID_PTS_X = 0x01,
  71. VARID_GRID_PTS_Y,
  72. VARID_GRID_PT_COUNT,
  73. VARID_GRID_WIDTH,
  74. VARID_GRID_HEIGHT,
  75. VARID_GRID_DENSITY,
  76. VARID_MAX_TEXTURE_PASSES,
  77. };
  78. //////////////////////////////////////////////////////////////////////
  79. //
  80. // EditableHeightfieldClass
  81. //
  82. //////////////////////////////////////////////////////////////////////
  83. EditableHeightfieldClass::EditableHeightfieldClass (void) :
  84. Width (0),
  85. Height (0),
  86. Density (1.0F),
  87. GridPointsX (0),
  88. GridPointsY (0),
  89. GridPointCount (0),
  90. Grid (NULL),
  91. GridNormals (NULL),
  92. QuadFlags (NULL),
  93. PatchGrid (NULL),
  94. PhysObjGrid (NULL),
  95. PatchesX (0),
  96. PatchesY (0),
  97. PatchGridPointsX (0),
  98. PatchGridPointsY (0),
  99. PatchWidth (0.0F),
  100. PatchHeight (0.0F)
  101. {
  102. Initialize ();
  103. return ;
  104. }
  105. //////////////////////////////////////////////////////////////////////
  106. //
  107. // EditableHeightfieldClass
  108. //
  109. //////////////////////////////////////////////////////////////////////
  110. EditableHeightfieldClass::EditableHeightfieldClass (const EditableHeightfieldClass &src) :
  111. Width (0),
  112. Height (0),
  113. Density (1.0F),
  114. GridPointsX (0),
  115. GridPointsY (0),
  116. GridPointCount (0),
  117. Grid (NULL),
  118. GridNormals (NULL),
  119. QuadFlags (NULL),
  120. PatchGrid (NULL),
  121. PhysObjGrid (NULL),
  122. PatchesX (0),
  123. PatchesY (0),
  124. PatchGridPointsX (0),
  125. PatchGridPointsY (0),
  126. PatchWidth (0.0F),
  127. PatchHeight (0.0F)
  128. {
  129. Initialize ();
  130. *this = src;
  131. return ;
  132. }
  133. //////////////////////////////////////////////////////////////////////
  134. //
  135. // ~EditableHeightfieldClass
  136. //
  137. //////////////////////////////////////////////////////////////////////
  138. EditableHeightfieldClass::~EditableHeightfieldClass (void)
  139. {
  140. Free_Grid ();
  141. Free_Material ();
  142. return ;
  143. }
  144. //////////////////////////////////////////////////////////////////////
  145. //
  146. // operator=
  147. //
  148. //////////////////////////////////////////////////////////////////////
  149. const EditableHeightfieldClass &
  150. EditableHeightfieldClass::operator= (const EditableHeightfieldClass &src)
  151. {
  152. return *this;
  153. }
  154. //////////////////////////////////////////////////////////////////////
  155. //
  156. // Initialize
  157. //
  158. //////////////////////////////////////////////////////////////////////
  159. void
  160. EditableHeightfieldClass::Initialize (void)
  161. {
  162. //
  163. // Zero all the lists
  164. //
  165. ::memset (MaterialList, 0, sizeof (MaterialList));
  166. ::memset (GridUVs, 0, sizeof (GridUVs));
  167. ::memset (TextureWeights, 0, sizeof (TextureWeights));
  168. //
  169. // Initialize the material settings
  170. //
  171. Initialize_Material ();
  172. return ;
  173. }
  174. //////////////////////////////////////////////////////////////////////
  175. //
  176. // Create
  177. //
  178. //////////////////////////////////////////////////////////////////////
  179. void
  180. EditableHeightfieldClass::Create (float width, float height, float meters_per_point)
  181. {
  182. Set_Dimensions (width, height, meters_per_point);
  183. Assign_Unique_IDs ();
  184. return ;
  185. }
  186. //////////////////////////////////////////////////////////////////////
  187. //
  188. // Set_Dimensions
  189. //
  190. //////////////////////////////////////////////////////////////////////
  191. void
  192. EditableHeightfieldClass::Set_Dimensions (float width, float height, float meters_per_point)
  193. {
  194. Free_Grid ();
  195. //
  196. // Calculate how many grid points we will have in the x and y directions
  197. //
  198. Density = meters_per_point;
  199. GridPointsX = int(width / Density);
  200. GridPointsY = int(height / Density);
  201. GridPointsX = max (1, GridPointsX);
  202. GridPointsY = max (1, GridPointsY);
  203. GridPointCount = (GridPointsX * GridPointsY);
  204. Width = (GridPointsX * Density);
  205. Height = (GridPointsY * Density);
  206. //
  207. // Allocate and initialize the grid and supporting data structures
  208. //
  209. Allocate_Patches ();
  210. Allocate_Grid ();
  211. return ;
  212. }
  213. //////////////////////////////////////////////////////////////////////
  214. //
  215. // Allocate_Grid
  216. //
  217. //////////////////////////////////////////////////////////////////////
  218. void
  219. EditableHeightfieldClass::Allocate_Grid (void)
  220. {
  221. //
  222. // Allocate the per-texture data structures
  223. //
  224. for (int index = 0; index < MAX_TEXTURE_PASSES; index ++) {
  225. //
  226. // Allocate the per-texture UV arrays
  227. //
  228. GridUVs[index] = new Vector2 [GridPointCount];
  229. //
  230. // Allocate the amount of texture influences for each texture for each vertex
  231. //
  232. TextureWeights[index] = new float[GridPointCount];
  233. ::memset (TextureWeights[index], 0, sizeof (float) * GridPointCount);
  234. }
  235. //
  236. // Allocate the arrays
  237. //
  238. GridNormals = new Vector3[GridPointCount];
  239. Grid = new Vector3[GridPointCount];
  240. //
  241. // Allocate and initiailze the array of quad flags
  242. //
  243. int quad_count = (GridPointsX - 1) * (GridPointsY - 1);
  244. QuadFlags = new uint8[quad_count];
  245. ::memset (QuadFlags, 0, sizeof (uint8) * quad_count);
  246. //
  247. // Initialize the grid and the uv array's
  248. //
  249. Initialize_Grid ();
  250. return ;
  251. }
  252. //////////////////////////////////////////////////////////////////////
  253. //
  254. // Initialize_Grid
  255. //
  256. //////////////////////////////////////////////////////////////////////
  257. void
  258. EditableHeightfieldClass::Initialize_Grid (void)
  259. {
  260. float y_value = 0;
  261. //
  262. // Give each point on the grid a position
  263. //
  264. for (int y_pos = 0; y_pos < GridPointsY; y_pos ++) {
  265. int start_index = (y_pos * GridPointsX);
  266. float x_value = 0;
  267. for (int x_pos = 0; x_pos < GridPointsX; x_pos ++) {
  268. //
  269. // Simply set the x,y,z position of this vertex
  270. //
  271. Grid[start_index + x_pos].Set (x_value, y_value, 0.0F);
  272. x_value += Density;
  273. //
  274. // Also give the vertex a texture influence weight
  275. //
  276. TextureWeights[0][start_index + x_pos] = 1.0F;
  277. //
  278. // Calculate the UV coordinate for this texture at this vertex
  279. //
  280. for (int index = 0; index < MAX_TEXTURE_PASSES; index ++) {
  281. if (MaterialList[index] != NULL) {
  282. float meters_per_texture = MaterialList[index]->Get_Meters_Per_Tile ();
  283. float u_value = Grid[start_index + x_pos].X / meters_per_texture;
  284. float v_value = Grid[start_index + x_pos].Y / meters_per_texture;
  285. GridUVs[index][start_index + x_pos].Set (u_value, v_value);
  286. }
  287. }
  288. }
  289. //
  290. // Move down to the next row
  291. //
  292. y_value += Density;
  293. }
  294. //
  295. // Update the normals of the grid
  296. //
  297. Update_Normals (0, 0, GridPointsX - 1, GridPointsY - 1);
  298. Update_Patch_Pos_And_Normals (0, 0, GridPointsX - 1, GridPointsY - 1);
  299. Update_UVs ();
  300. Update_Texture_Quad_List (0, 0, GridPointsX - 1, GridPointsY - 1);
  301. return ;
  302. }
  303. //////////////////////////////////////////////////////////////////////
  304. //
  305. // Free_Grid
  306. //
  307. //////////////////////////////////////////////////////////////////////
  308. void
  309. EditableHeightfieldClass::Free_Grid (void)
  310. {
  311. SAFE_DELETE_ARRAY (Grid);
  312. SAFE_DELETE_ARRAY (GridNormals);
  313. SAFE_DELETE_ARRAY (QuadFlags);
  314. //
  315. // Free the texture weight arrays
  316. //
  317. for (int index = 0; index < MAX_TEXTURE_PASSES; index ++) {
  318. SAFE_DELETE (TextureWeights[index]);
  319. SAFE_DELETE (GridUVs[index]);
  320. }
  321. Width = 0;
  322. Height = 0;
  323. Density = 1.0F;
  324. GridPointsX = 0;
  325. GridPointsY = 0;
  326. GridPointCount = 0;
  327. //
  328. // Now free each of the passes
  329. //
  330. Free_Patches ();
  331. return ;
  332. }
  333. //////////////////////////////////////////////////////////////////////
  334. //
  335. // Update_Texture_Quad_List
  336. //
  337. //////////////////////////////////////////////////////////////////////
  338. void
  339. EditableHeightfieldClass::Update_Texture_Quad_List (int min_x, int min_y, int max_x, int max_y)
  340. {
  341. //
  342. // Determine which patches this operation would possibly affect
  343. //
  344. int min_patch_x = min_x / (PatchGridPointsX - 1);
  345. int min_patch_y = min_y / (PatchGridPointsY - 1);
  346. int max_patch_x = max_x / (PatchGridPointsX - 1);
  347. int max_patch_y = max_y / (PatchGridPointsY - 1);
  348. max_patch_x = min (max_patch_x, (PatchesX - 1));
  349. max_patch_y = min (max_patch_y, (PatchesY - 1));
  350. int row_count = GridPointsY - 1;
  351. int col_count = GridPointsX - 1;
  352. int quads_per_patch_x = PatchGridPointsX - 1;
  353. int quads_per_patch_y = PatchGridPointsY - 1;
  354. //
  355. // Loop over each quad in the heightfield and determine which pass(es)
  356. // they should be rendered in...
  357. //
  358. for (int patch_y = min_patch_y; patch_y <= max_patch_y; patch_y ++) {
  359. for (int patch_x = min_patch_x; patch_x <= max_patch_x; patch_x ++) {
  360. //
  361. // Reset the passes for this patch
  362. //
  363. int patch_index = (patch_y * PatchesX) + patch_x;
  364. PatchGrid[patch_index]->Reset_Material_Passes ();
  365. for (int patch_quad_y = 0; patch_quad_y < quads_per_patch_y; patch_quad_y ++) {
  366. for (int patch_quad_x = 0; patch_quad_x < quads_per_patch_x; patch_quad_x ++) {
  367. //
  368. // Determine the quad index inside the patch
  369. //
  370. int patch_quad_index = (patch_quad_y * (PatchGridPointsX - 1)) + patch_quad_x;
  371. //
  372. // Calculate where in the overall heigtmap this quad is
  373. //
  374. int quad_x = (patch_x * quads_per_patch_x) + patch_quad_x;
  375. int quad_y = (patch_y * quads_per_patch_y) + patch_quad_y;
  376. int overall_quad_index = (quad_y * (GridPointsX - 1)) + quad_x;
  377. //
  378. // Copy the quad flags to the pathc
  379. //
  380. PatchGrid[patch_index]->Set_Quad_Flags (patch_quad_index, QuadFlags[overall_quad_index]);
  381. //
  382. // Skip this quad if its hidden
  383. //
  384. if (QuadFlags[overall_quad_index] & QF_HIDDEN) {
  385. continue;
  386. }
  387. //
  388. // Calculate what vertices define the four corners of this quad
  389. //
  390. int start_index = (quad_y * GridPointsX) + quad_x;
  391. int v0_index = start_index;
  392. int v1_index = start_index + 1;
  393. int v2_index = start_index + GridPointsX + 1;
  394. int v3_index = start_index + GridPointsX;
  395. //
  396. // Calculate what vertices define the four corners of this quad (in patch space)
  397. //
  398. int patch_start_index = (patch_quad_y * PatchGridPointsX) + patch_quad_x;
  399. int patch_v0_index = patch_start_index;
  400. int patch_v1_index = patch_start_index + 1;
  401. int patch_v2_index = patch_start_index + PatchGridPointsX + 1;
  402. int patch_v3_index = patch_start_index + PatchGridPointsX;
  403. float v0_alpha_sum = 0.0F;
  404. float v1_alpha_sum = 0.0F;
  405. float v2_alpha_sum = 0.0F;
  406. float v3_alpha_sum = 0.0F;
  407. //
  408. // Determine which passes this quad should be rendered in...
  409. //
  410. bool is_set = false;
  411. for (int layer = 0; layer < MAX_TEXTURE_PASSES; layer ++) {
  412. //
  413. // Is there a significant influence from one of the textures on this quad?
  414. //
  415. if ( TextureWeights[layer][v0_index] > 0.0F ||
  416. TextureWeights[layer][v1_index] > 0.0F ||
  417. TextureWeights[layer][v2_index] > 0.0F ||
  418. TextureWeights[layer][v3_index] > 0.0F)
  419. {
  420. //
  421. // Get acces to the material pass for this layer
  422. //
  423. RenegadeTerrainMaterialPassClass *material_pass = NULL;
  424. material_pass = PatchGrid[patch_index]->Get_Material_Pass (layer, MaterialList[layer]);
  425. v0_alpha_sum += TextureWeights[layer][v0_index];
  426. v1_alpha_sum += TextureWeights[layer][v1_index];
  427. v2_alpha_sum += TextureWeights[layer][v2_index];
  428. v3_alpha_sum += TextureWeights[layer][v3_index];
  429. //
  430. // Add this quad to either the alpha pass or the base pass
  431. //
  432. if (is_set) {
  433. material_pass->QuadList[PASS_ALPHA].Add (patch_quad_index);
  434. //
  435. // Set the vertex alpha's for the verts inside the material layer
  436. //
  437. material_pass->VertexAlpha[patch_v0_index] = TextureWeights[layer][v0_index] / v0_alpha_sum;
  438. material_pass->VertexAlpha[patch_v1_index] = TextureWeights[layer][v1_index] / v1_alpha_sum;
  439. material_pass->VertexAlpha[patch_v2_index] = TextureWeights[layer][v2_index] / v2_alpha_sum;
  440. material_pass->VertexAlpha[patch_v3_index] = TextureWeights[layer][v3_index] / v3_alpha_sum;
  441. } else {
  442. material_pass->QuadList[PASS_BASE].Add (patch_quad_index);
  443. is_set = true;
  444. }
  445. }
  446. }
  447. }
  448. }
  449. //
  450. // Now, make each patch update its internal rendering structures
  451. //
  452. PatchGrid[patch_index]->Update_Vertex_Render_Lists ();
  453. PatchGrid[patch_index]->Update_UVs ();
  454. }
  455. }
  456. return ;
  457. }
  458. //////////////////////////////////////////////////////////////////////
  459. //
  460. // Set_Material
  461. //
  462. //////////////////////////////////////////////////////////////////////
  463. void
  464. EditableHeightfieldClass::Set_Material (int index, TerrainMaterialClass *material)
  465. {
  466. if (index < 0 || index >= MAX_TEXTURE_PASSES) {
  467. return ;
  468. }
  469. //
  470. // Store this material in its slot
  471. //
  472. REF_PTR_SET (MaterialList[index], material);
  473. //
  474. // Update UV coords for this texture pass
  475. //
  476. On_Material_Changed (index);
  477. return ;
  478. }
  479. //////////////////////////////////////////////////////////////////////
  480. //
  481. // On_Material_Changed
  482. //
  483. //////////////////////////////////////////////////////////////////////
  484. void
  485. EditableHeightfieldClass::On_Material_Changed (int index)
  486. {
  487. if (index < 0 || index >= MAX_TEXTURE_PASSES || MaterialList[index] == NULL) {
  488. return ;
  489. }
  490. //
  491. // Loop over all the verts on the grid
  492. //
  493. /*for (int y_pos = 0; y_pos < GridPointsY; y_pos ++) {
  494. int start_index = (y_pos * GridPointsX);
  495. for (int x_pos = 0; x_pos < GridPointsX; x_pos ++) {
  496. //
  497. // Calculate the UV coordinate for this texture at this vertex
  498. //
  499. float meters_per_texture = MaterialList[index]->Get_Meters_Per_Tile ();
  500. float u_value = Grid[start_index + x_pos].X / meters_per_texture;
  501. float v_value = Grid[start_index + x_pos].Y / meters_per_texture;
  502. GridUVs[index][start_index + x_pos].Set (u_value, v_value);
  503. }
  504. }*/
  505. //
  506. // Now, make each patch update its internal rendering structures
  507. //
  508. int patch_count = PatchesX * PatchesY;
  509. for (int patch_index = 0; patch_index < patch_count; patch_index ++) {
  510. PatchGrid[patch_index]->Update_UVs ();
  511. }
  512. return ;
  513. }
  514. //////////////////////////////////////////////////////////////////////
  515. //
  516. // Update_UVs
  517. //
  518. //////////////////////////////////////////////////////////////////////
  519. void
  520. EditableHeightfieldClass::Update_UVs (void)
  521. {
  522. return ;
  523. }
  524. //////////////////////////////////////////////////////////////////////
  525. //
  526. // Update_Normals
  527. //
  528. //////////////////////////////////////////////////////////////////////
  529. void
  530. EditableHeightfieldClass::Update_Normals (int min_x, int min_y, int max_x, int max_y)
  531. {
  532. //
  533. // First, initialize each vertex normal to 0
  534. //
  535. for (int y_pos = min_y; y_pos <= max_y; y_pos ++) {
  536. int vert_index = (y_pos * GridPointsX) + min_x;
  537. for (int x_pos = min_x; x_pos <= max_x; x_pos ++) {
  538. //
  539. // Initialize this normal
  540. //
  541. GridNormals[vert_index ++].Set (0.0F, 0.0F, 0.0F);
  542. }
  543. }
  544. //
  545. // Loop over each vertex that's affected and add the plane normal of the
  546. // 6 triangles that are formed from this vertex .
  547. //
  548. for (y_pos = min_y; y_pos <= max_y; y_pos ++) {
  549. int vert_index = (y_pos * GridPointsX) + min_x;
  550. for (int x_pos = min_x; x_pos <= max_x; x_pos ++) {
  551. //
  552. // Upper-left quad
  553. //
  554. if (y_pos > 0 && x_pos > 0) {
  555. int q0_v0_index = (vert_index - GridPointsX) - 1;
  556. int q0_v1_index = vert_index - GridPointsX;
  557. int q0_v2_index = vert_index;
  558. int q0_v3_index = vert_index - 1;
  559. const Vector3 &q0_v0 = Grid[q0_v0_index];
  560. const Vector3 &q0_v1 = Grid[q0_v1_index];
  561. const Vector3 &q0_v2 = Grid[q0_v2_index];
  562. const Vector3 &q0_v3 = Grid[q0_v3_index];
  563. Vector3 q0_normal1 = Vector3::Cross_Product (q0_v2 - q0_v1, q0_v0 - q0_v1);
  564. Vector3 q0_normal2 = Vector3::Cross_Product (q0_v3 - q0_v2, q0_v0 - q0_v2);
  565. GridNormals[vert_index] += q0_normal1;
  566. GridNormals[vert_index] += q0_normal2;
  567. }
  568. //
  569. // Upper-right quad
  570. //
  571. if (y_pos > 0 && x_pos < (GridPointsX - 1)) {
  572. int q1_v0_index = vert_index - GridPointsX;
  573. int q1_v1_index = (vert_index - GridPointsX) + 1;
  574. int q1_v2_index = vert_index + 1;
  575. int q1_v3_index = vert_index;
  576. const Vector3 &q1_v0 = Grid[q1_v0_index];
  577. const Vector3 &q1_v1 = Grid[q1_v1_index];
  578. const Vector3 &q1_v2 = Grid[q1_v2_index];
  579. const Vector3 &q1_v3 = Grid[q1_v3_index];
  580. Vector3 q1_normal2 = Vector3::Cross_Product (q1_v3 - q1_v2, q1_v0 - q1_v2);
  581. GridNormals[vert_index] += q1_normal2;
  582. }
  583. //
  584. // Lower-right quad
  585. //
  586. if (y_pos < (GridPointsY - 1) && x_pos < (GridPointsX - 1)) {
  587. int q2_v0_index = vert_index;
  588. int q2_v1_index = vert_index + 1;
  589. int q2_v2_index = vert_index + GridPointsX + 1;
  590. int q2_v3_index = vert_index + GridPointsX;
  591. const Vector3 &q2_v0 = Grid[q2_v0_index];
  592. const Vector3 &q2_v1 = Grid[q2_v1_index];
  593. const Vector3 &q2_v2 = Grid[q2_v2_index];
  594. const Vector3 &q2_v3 = Grid[q2_v3_index];
  595. Vector3 q2_normal1 = Vector3::Cross_Product (q2_v2 - q2_v1, q2_v0 - q2_v1);
  596. Vector3 q2_normal2 = Vector3::Cross_Product (q2_v3 - q2_v2, q2_v0 - q2_v2);
  597. GridNormals[vert_index] += q2_normal1;
  598. GridNormals[vert_index] += q2_normal2;
  599. }
  600. //
  601. // Lower-left quad
  602. //
  603. if (y_pos < (GridPointsY - 1) && x_pos > 0) {
  604. int q3_v0_index = vert_index - 1;
  605. int q3_v1_index = vert_index;
  606. int q3_v2_index = vert_index + GridPointsX;
  607. int q3_v3_index = vert_index + GridPointsX - 1;
  608. const Vector3 &q3_v0 = Grid[q3_v0_index];
  609. const Vector3 &q3_v1 = Grid[q3_v1_index];
  610. const Vector3 &q3_v2 = Grid[q3_v2_index];
  611. const Vector3 &q3_v3 = Grid[q3_v3_index];
  612. Vector3 q3_normal1 = Vector3::Cross_Product (q3_v2 - q3_v1, q3_v0 - q3_v1);
  613. GridNormals[vert_index] += q3_normal1;
  614. }
  615. GridNormals[vert_index ++].Normalize ();
  616. }
  617. }
  618. return ;
  619. }
  620. //////////////////////////////////////////////////////////////////////
  621. //
  622. // Initialize_Material
  623. //
  624. //////////////////////////////////////////////////////////////////////
  625. void
  626. EditableHeightfieldClass::Initialize_Material (void)
  627. {
  628. //
  629. // Allocate a test texture
  630. //
  631. CString full_path = ::Get_File_Mgr ()->Make_Full_Path ("Heightfield\\DIRT_01.TGA");
  632. MaterialList[0] = new TerrainMaterialClass;
  633. MaterialList[0]->Set_Texture (full_path);
  634. MaterialList[0]->Set_Meters_Per_Tile (25.0F);
  635. //
  636. // Allocate a test texture
  637. //
  638. /*full_path = ::Get_File_Mgr ()->Make_Full_Path ("Heightfield\\L03_bushes.tga");
  639. MaterialList[1] = new TerrainMaterialClass;
  640. MaterialList[1]->Set_Texture (full_path);
  641. MaterialList[1]->Set_Meters_Per_Tile (25.0F);
  642. //
  643. // Allocate a test texture
  644. //
  645. full_path = ::Get_File_Mgr ()->Make_Full_Path ("Heightfield\\cht_GryStn.tga");
  646. MaterialList[2] = new TerrainMaterialClass;
  647. MaterialList[2]->Set_Texture (full_path);
  648. MaterialList[2]->Set_Meters_Per_Tile (25.0F);
  649. //
  650. // Allocate a test texture
  651. //
  652. full_path = ::Get_File_Mgr ()->Make_Full_Path ("Heightfield\\cht_snwmts.tga");
  653. MaterialList[3] = new TerrainMaterialClass;
  654. MaterialList[3]->Set_Texture (full_path);
  655. MaterialList[3]->Set_Meters_Per_Tile (25.0F);
  656. //
  657. // Allocate a test texture
  658. //
  659. full_path = ::Get_File_Mgr ()->Make_Full_Path ("Heightfield\\lv8_dirt2.tga");
  660. MaterialList[4] = new TerrainMaterialClass;
  661. MaterialList[4]->Set_Texture (full_path);
  662. MaterialList[4]->Set_Meters_Per_Tile (25.0F);
  663. //
  664. // Allocate a test texture
  665. //
  666. full_path = ::Get_File_Mgr ()->Make_Full_Path ("Heightfield\\L03_lav001.tga");
  667. MaterialList[5] = new TerrainMaterialClass;
  668. MaterialList[5]->Set_Texture (full_path);
  669. MaterialList[5]->Set_Meters_Per_Tile (25.0F);
  670. //
  671. // Allocate a test texture
  672. //
  673. full_path = ::Get_File_Mgr ()->Make_Full_Path ("Heightfield\\L03_bchsnd.tga");
  674. MaterialList[6] = new TerrainMaterialClass;
  675. MaterialList[6]->Set_Texture (full_path);
  676. MaterialList[6]->Set_Meters_Per_Tile (25.0F);*/
  677. return ;
  678. }
  679. //////////////////////////////////////////////////////////////////////
  680. //
  681. // Free_Material
  682. //
  683. //////////////////////////////////////////////////////////////////////
  684. void
  685. EditableHeightfieldClass::Free_Material (void)
  686. {
  687. //
  688. // Release the textures
  689. //
  690. for (int index = 0; index < MAX_TEXTURE_PASSES; index ++) {
  691. REF_PTR_RELEASE (MaterialList[index]);
  692. }
  693. return ;
  694. }
  695. //////////////////////////////////////////////////////////////////////
  696. //
  697. // Deform_Heightfield
  698. //
  699. //////////////////////////////////////////////////////////////////////
  700. void
  701. EditableHeightfieldClass::Deform_Heightfield
  702. (
  703. const Vector3 & world_space_center,
  704. float amount,
  705. float inner_radius,
  706. float outter_radius
  707. )
  708. {
  709. //
  710. // First, transform the center point into heightfield (object) space
  711. //
  712. const Matrix3D tm = Matrix3D (1);//Get_Transform ();
  713. Matrix3D world_to_obj_tm;
  714. tm.Get_Orthogonal_Inverse (world_to_obj_tm);
  715. Vector3 center;
  716. Matrix3D::Transform_Vector (world_to_obj_tm, world_space_center, &center);
  717. //
  718. // Offset the affect verts
  719. //
  720. float min_x_value = center.X - outter_radius;
  721. float min_y_value = center.Y - outter_radius;
  722. float max_x_value = center.X + outter_radius;
  723. float max_y_value = center.Y + outter_radius;
  724. int min_x = WWMath::Float_To_Int_Floor ((min_x_value / Density));
  725. int min_y = WWMath::Float_To_Int_Floor ((min_y_value / Density));
  726. int max_x = WWMath::Float_To_Int_Floor ((max_x_value / Density));
  727. int max_y = WWMath::Float_To_Int_Floor ((max_y_value / Density));
  728. min_x = WWMath::Clamp_Int (min_x, 0, GridPointsX - 1);
  729. min_y = WWMath::Clamp_Int (min_y, 0, GridPointsY - 1);
  730. max_x = WWMath::Clamp_Int (max_x, 0, GridPointsX - 1);
  731. max_y = WWMath::Clamp_Int (max_y, 0, GridPointsY - 1);
  732. float delta_radius = (outter_radius - inner_radius);
  733. //
  734. // Loop over all the verts in this region and apply the deformation
  735. //
  736. for (int y_pos = min_y; y_pos <= max_y; y_pos ++) {
  737. int curr_offset = (y_pos * GridPointsX) + min_x;
  738. for (int x_pos = min_x; x_pos <= max_x; x_pos ++) {
  739. Vector3 &vert_pos = Grid[curr_offset];
  740. //
  741. // Calculate how far this vertex is from the center of the deformation
  742. //
  743. Vector2 delta (vert_pos.X - center.X, vert_pos.Y - center.Y);
  744. float dist = WWMath::Sqrt ((delta.X * delta.X) + (delta.Y * delta.Y));
  745. //
  746. // Is this vertex inside the affected region?
  747. //
  748. if (dist <= outter_radius) {
  749. //
  750. // Calculate what percentage this vertex is affected by the deformation
  751. //
  752. float percent = 1.0F;
  753. if (dist > inner_radius && delta_radius > 0.0F) {
  754. percent = 1.0F - ((dist - inner_radius) / delta_radius);
  755. }
  756. //
  757. // Scale the amount and apply it to the z-position of the vertex
  758. //
  759. float delta_amount = percent * amount;
  760. vert_pos.Z += delta_amount;
  761. }
  762. //
  763. // Advance to the next vertex
  764. //
  765. curr_offset ++;
  766. }
  767. }
  768. //
  769. // Update the normals of the affected verts
  770. //
  771. Update_Normals (min_x, min_y, max_x, max_y);
  772. Update_Patch_Pos_And_Normals (min_x, min_y, max_x, max_y);
  773. Update_UVs ();
  774. return ;
  775. }
  776. //////////////////////////////////////////////////////////////////////
  777. //
  778. // Smooth_Foundation_Heightfield
  779. //
  780. //////////////////////////////////////////////////////////////////////
  781. void
  782. EditableHeightfieldClass::Smooth_Foundation_Heightfield
  783. (
  784. const Vector3 & world_space_center,
  785. float amount,
  786. float inner_radius,
  787. float outter_radius
  788. )
  789. {
  790. //
  791. // First, transform the center point into heightfield (object) space
  792. //
  793. const Matrix3D tm = Matrix3D (1);
  794. Matrix3D world_to_obj_tm;
  795. tm.Get_Orthogonal_Inverse (world_to_obj_tm);
  796. Vector3 center;
  797. Matrix3D::Transform_Vector (world_to_obj_tm, world_space_center, &center);
  798. //
  799. // Offset the affect verts
  800. //
  801. float min_x_value = center.X - outter_radius;
  802. float min_y_value = center.Y - outter_radius;
  803. float max_x_value = center.X + outter_radius;
  804. float max_y_value = center.Y + outter_radius;
  805. int min_x = WWMath::Float_To_Int_Floor ((min_x_value / Density));
  806. int min_y = WWMath::Float_To_Int_Floor ((min_y_value / Density));
  807. int max_x = WWMath::Float_To_Int_Floor ((max_x_value / Density));
  808. int max_y = WWMath::Float_To_Int_Floor ((max_y_value / Density));
  809. min_x = WWMath::Clamp_Int (min_x, 0, GridPointsX - 1);
  810. min_y = WWMath::Clamp_Int (min_y, 0, GridPointsY - 1);
  811. max_x = WWMath::Clamp_Int (max_x, 0, GridPointsX - 1);
  812. max_y = WWMath::Clamp_Int (max_y, 0, GridPointsY - 1);
  813. float delta_radius = (outter_radius - inner_radius);
  814. float avg_height = 0;
  815. int count = 0;
  816. //
  817. // Loop over all the verts in this region and apply the deformation
  818. //
  819. for (int y_pos = min_y; y_pos <= max_y; y_pos ++) {
  820. int curr_offset = (y_pos * GridPointsX) + min_x;
  821. for (int x_pos = min_x; x_pos <= max_x; x_pos ++) {
  822. Vector3 &vert_pos = Grid[curr_offset];
  823. //
  824. // Calculate how far this vertex is from the center of the deformation
  825. //
  826. Vector2 delta (vert_pos.X - center.X, vert_pos.Y - center.Y);
  827. float dist = WWMath::Sqrt ((delta.X * delta.X) + (delta.Y * delta.Y));
  828. //
  829. // Is this vertex inside the affected region?
  830. //
  831. if (dist <= outter_radius) {
  832. avg_height += vert_pos.Z;
  833. count ++;
  834. }
  835. //
  836. // Advance to the next vertex
  837. //
  838. curr_offset ++;
  839. }
  840. }
  841. if (count == 0) {
  842. return ;
  843. }
  844. avg_height = avg_height / count;
  845. //
  846. // Loop over all the verts in this region and apply the deformation
  847. //
  848. for (y_pos = min_y; y_pos <= max_y; y_pos ++) {
  849. int curr_offset = (y_pos * GridPointsX) + min_x;
  850. for (int x_pos = min_x; x_pos <= max_x; x_pos ++) {
  851. Vector3 &vert_pos = Grid[curr_offset];
  852. //
  853. // Calculate how far this vertex is from the center of the deformation
  854. //
  855. Vector2 delta (vert_pos.X - center.X, vert_pos.Y - center.Y);
  856. float dist = WWMath::Sqrt ((delta.X * delta.X) + (delta.Y * delta.Y));
  857. //
  858. // Is this vertex inside the affected region?
  859. //
  860. if (dist <= outter_radius) {
  861. //
  862. // Calculate what percentage this vertex is affected by the deformation
  863. //
  864. float percent = 1.0F;
  865. if (dist > inner_radius && delta_radius > 0.0F) {
  866. percent = 1.0F - ((dist - inner_radius) / delta_radius);
  867. }
  868. //
  869. // Scale the amount and apply it to the z-position of the vertex
  870. //
  871. float real_percent = percent * 0.5F;
  872. float z_value = (vert_pos.Z - avg_height) * real_percent;
  873. vert_pos.Z -= z_value;
  874. }
  875. //
  876. // Advance to the next vertex
  877. //
  878. curr_offset ++;
  879. }
  880. }
  881. //
  882. // Update the normals of the affected verts
  883. //
  884. Update_Normals (min_x, min_y, max_x, max_y);
  885. Update_Patch_Pos_And_Normals (min_x, min_y, max_x, max_y);
  886. Update_UVs ();
  887. return ;
  888. }
  889. //////////////////////////////////////////////////////////////////////
  890. //
  891. // Smooth_Heightfield
  892. //
  893. //////////////////////////////////////////////////////////////////////
  894. void
  895. EditableHeightfieldClass::Smooth_Heightfield
  896. (
  897. const Vector3 & world_space_center,
  898. float amount,
  899. float inner_radius,
  900. float outter_radius
  901. )
  902. {
  903. //
  904. // First, transform the center point into heightfield (object) space
  905. //
  906. const Matrix3D tm = Matrix3D (1);
  907. Matrix3D world_to_obj_tm;
  908. tm.Get_Orthogonal_Inverse (world_to_obj_tm);
  909. Vector3 center;
  910. Matrix3D::Transform_Vector (world_to_obj_tm, world_space_center, &center);
  911. //
  912. // Offset the affect verts
  913. //
  914. float min_x_value = center.X - outter_radius;
  915. float min_y_value = center.Y - outter_radius;
  916. float max_x_value = center.X + outter_radius;
  917. float max_y_value = center.Y + outter_radius;
  918. int min_x = WWMath::Float_To_Int_Floor ((min_x_value / Density));
  919. int min_y = WWMath::Float_To_Int_Floor ((min_y_value / Density));
  920. int max_x = WWMath::Float_To_Int_Floor ((max_x_value / Density));
  921. int max_y = WWMath::Float_To_Int_Floor ((max_y_value / Density));
  922. min_x = WWMath::Clamp_Int (min_x, 0, GridPointsX - 1);
  923. min_y = WWMath::Clamp_Int (min_y, 0, GridPointsY - 1);
  924. max_x = WWMath::Clamp_Int (max_x, 0, GridPointsX - 1);
  925. max_y = WWMath::Clamp_Int (max_y, 0, GridPointsY - 1);
  926. float delta_radius = (outter_radius - inner_radius);
  927. static const Vector2i INDEX_RING_OFFSETS[] =
  928. {
  929. Vector2i (-1, -1), Vector2i (0, -1), Vector2i (+1, -1),
  930. Vector2i (-1, 0), Vector2i (+1, 0),
  931. Vector2i (-1, +1), Vector2i (0, +1), Vector2i (+1, +1)
  932. };
  933. //
  934. // Create a list we can use to keep track of the height changes
  935. //
  936. DynamicVectorClass<float> new_height_list;
  937. DynamicVectorClass<int> new_height_list_pos;
  938. new_height_list.Set_Growth_Step (1000);
  939. new_height_list_pos.Set_Growth_Step (1000);
  940. //
  941. // Loop over all the verts in this region and apply the deformation
  942. //
  943. for (int y_pos = min_y; y_pos <= max_y; y_pos ++) {
  944. int curr_offset = (y_pos * GridPointsX) + min_x;
  945. for (int x_pos = min_x; x_pos <= max_x; x_pos ++) {
  946. Vector3 &vert_pos = Grid[curr_offset];
  947. //
  948. // Calculate how far this vertex is from the center of the deformation
  949. //
  950. Vector2 delta (vert_pos.X - center.X, vert_pos.Y - center.Y);
  951. float dist = WWMath::Sqrt ((delta.X * delta.X) + (delta.Y * delta.Y));
  952. //
  953. // Is this vertex inside the affected region?
  954. //
  955. if (dist <= outter_radius) {
  956. //
  957. // Calculate what percentage this vertex is affected by the deformation
  958. //
  959. float percent = 1.0F;
  960. if (dist > inner_radius && delta_radius > 0.0F) {
  961. percent = 1.0F - ((dist - inner_radius) / delta_radius);
  962. }
  963. //
  964. // Scale the amount and apply it to the z-position of the vertex
  965. //
  966. float real_percent = percent * 0.5F;
  967. //
  968. // Now, average the height of this vertex with the surrounding heights
  969. //
  970. int count = 0;
  971. float avg_height = 0;
  972. for (int index = 0; index < 7; index ++) {
  973. int new_x_pos = x_pos + INDEX_RING_OFFSETS[index].I;
  974. int new_y_pos = y_pos + INDEX_RING_OFFSETS[index].J;
  975. //
  976. // If there is a vertex in this position, the take
  977. // into consideration its height
  978. //
  979. if ( new_x_pos >= 0 && new_x_pos < GridPointsX &&
  980. new_y_pos >= 0 && new_y_pos < GridPointsY)
  981. {
  982. int test_index = (new_y_pos * GridPointsX) + new_x_pos;
  983. avg_height += Grid[test_index].Z;
  984. count ++;
  985. }
  986. }
  987. float z_value = vert_pos.Z;
  988. //
  989. // Use the average height value if possible
  990. //
  991. if (count > 0) {
  992. avg_height = avg_height / count;
  993. z_value -= (vert_pos.Z - avg_height) * real_percent;
  994. }
  995. new_height_list.Add (z_value);
  996. new_height_list_pos.Add (curr_offset);
  997. }
  998. //
  999. // Advance to the next vertex
  1000. //
  1001. curr_offset ++;
  1002. }
  1003. }
  1004. //
  1005. // Now, loop over all the verts in this region and apply the new heights
  1006. //
  1007. for (int index = 0; index < new_height_list.Count (); index ++) {
  1008. //
  1009. // Set this vertex's height
  1010. //
  1011. Vector3 &vert_pos = Grid[new_height_list_pos[index]];
  1012. vert_pos.Z = new_height_list[index];
  1013. }
  1014. //
  1015. // Update the normals of the affected verts
  1016. //
  1017. Update_Normals (min_x, min_y, max_x, max_y);
  1018. Update_Patch_Pos_And_Normals (min_x, min_y, max_x, max_y);
  1019. Update_UVs ();
  1020. return ;
  1021. }
  1022. //////////////////////////////////////////////////////////////////////
  1023. //
  1024. // Cutout_Heightfield
  1025. //
  1026. //////////////////////////////////////////////////////////////////////
  1027. void
  1028. EditableHeightfieldClass::Cutout_Heightfield
  1029. (
  1030. const Vector3 & world_space_center,
  1031. float outter_radius,
  1032. bool subtract
  1033. )
  1034. {
  1035. //
  1036. // First, transform the center point into heightfield (object) space
  1037. //
  1038. const Matrix3D tm = Matrix3D (1);
  1039. Matrix3D world_to_obj_tm;
  1040. tm.Get_Orthogonal_Inverse (world_to_obj_tm);
  1041. Vector3 center;
  1042. Matrix3D::Transform_Vector (world_to_obj_tm, world_space_center, &center);
  1043. //
  1044. // Determine which quads are affected by this operation
  1045. //
  1046. float min_x_value = center.X - outter_radius;
  1047. float min_y_value = center.Y - outter_radius;
  1048. float max_x_value = center.X + outter_radius;
  1049. float max_y_value = center.Y + outter_radius;
  1050. int min_x = Get_Quad_Index_X (min_x_value);
  1051. int min_y = Get_Quad_Index_Y (min_y_value);
  1052. int max_x = Get_Quad_Index_X (max_x_value);
  1053. int max_y = Get_Quad_Index_Y (max_y_value);
  1054. //
  1055. // Loop over all the quads in this region...
  1056. //
  1057. for (int quad_y = min_y; quad_y <= max_y; quad_y ++) {
  1058. int quad_index = (quad_y * (GridPointsX - 1)) + min_x;
  1059. for (int quad_x = min_x; quad_x <= max_x; quad_x ++) {
  1060. //
  1061. // Set the bits that specify this quad is not to be rendered
  1062. //
  1063. if (subtract) {
  1064. QuadFlags[quad_index] |= QF_HIDDEN;
  1065. } else {
  1066. QuadFlags[quad_index] &= (~QF_HIDDEN);
  1067. }
  1068. //
  1069. // Advance to the next quad
  1070. //
  1071. quad_index ++;
  1072. }
  1073. }
  1074. //
  1075. // Update the texture rendering lists
  1076. //
  1077. Update_Texture_Quad_List (Get_Point_Index_X (min_x_value), Get_Point_Index_Y (min_y_value),
  1078. Get_Point_Index_X (max_x_value), Get_Point_Index_Y (max_y_value));
  1079. return ;
  1080. }
  1081. //////////////////////////////////////////////////////////////////////
  1082. //
  1083. // Paint_Heightfield
  1084. //
  1085. //////////////////////////////////////////////////////////////////////
  1086. void
  1087. EditableHeightfieldClass::Paint_Heightfield
  1088. (
  1089. const Vector3 & world_space_center,
  1090. int texture_index,
  1091. float amount,
  1092. float inner_radius,
  1093. float outter_radius
  1094. )
  1095. {
  1096. //
  1097. // First, transform the center point into heightfield (object) space
  1098. //
  1099. const Matrix3D tm = Matrix3D (1);
  1100. Matrix3D world_to_obj_tm;
  1101. tm.Get_Orthogonal_Inverse (world_to_obj_tm);
  1102. Vector3 center;
  1103. Matrix3D::Transform_Vector (world_to_obj_tm, world_space_center, &center);
  1104. //
  1105. // Offset the affect verts
  1106. //
  1107. float min_x_value = center.X - outter_radius;
  1108. float min_y_value = center.Y - outter_radius;
  1109. float max_x_value = center.X + outter_radius;
  1110. float max_y_value = center.Y + outter_radius;
  1111. int min_x = WWMath::Float_To_Int_Floor ((min_x_value / Density));
  1112. int min_y = WWMath::Float_To_Int_Floor ((min_y_value / Density));
  1113. int max_x = WWMath::Float_To_Int_Floor ((max_x_value / Density));
  1114. int max_y = WWMath::Float_To_Int_Floor ((max_y_value / Density));
  1115. min_x = WWMath::Clamp_Int (min_x, 0, GridPointsX - 1);
  1116. min_y = WWMath::Clamp_Int (min_y, 0, GridPointsY - 1);
  1117. max_x = WWMath::Clamp_Int (max_x, 0, GridPointsX - 1);
  1118. max_y = WWMath::Clamp_Int (max_y, 0, GridPointsY - 1);
  1119. float delta_radius = (outter_radius - inner_radius);
  1120. //
  1121. // Loop over all the verts in this region and apply the deformation
  1122. //
  1123. for (int y_pos = min_y; y_pos <= max_y; y_pos ++) {
  1124. int curr_offset = (y_pos * GridPointsX) + min_x;
  1125. for (int x_pos = min_x; x_pos <= max_x; x_pos ++) {
  1126. Vector3 &vert_pos = Grid[curr_offset];
  1127. //
  1128. // Calculate how far this vertex is from the center of the deformation
  1129. //
  1130. Vector2 delta (vert_pos.X - center.X, vert_pos.Y - center.Y);
  1131. float dist = WWMath::Sqrt ((delta.X * delta.X) + (delta.Y * delta.Y));
  1132. //
  1133. // Is this vertex inside the affected region?
  1134. //
  1135. if (dist <= outter_radius) {
  1136. //
  1137. // Calculate what percentage this vertex is affected by the deformation
  1138. //
  1139. float percent = 1.0F;
  1140. if (dist > inner_radius && delta_radius > 0.0F) {
  1141. percent = 1.0F - ((dist - inner_radius) / delta_radius);
  1142. }
  1143. //
  1144. // Scale the amount and apply it to the z-position of the vertex
  1145. //
  1146. float delta_amount = percent * amount;
  1147. //
  1148. // Determine how much influence each of the other texture channel had
  1149. //
  1150. float amount = TextureWeights[texture_index][curr_offset];
  1151. float old_remainder_amount = 1.0F - amount;
  1152. if (old_remainder_amount < 0 || old_remainder_amount > 1.0F) {
  1153. int test = 0;
  1154. }
  1155. //
  1156. // Increment the amount of influence for this texture channel
  1157. //
  1158. float new_amount = amount + delta_amount;
  1159. new_amount = WWMath::Clamp (new_amount, 0.0F, 1.0F);
  1160. //
  1161. // Calculate how much influence is left for the other texture channels
  1162. //
  1163. float remainder = (1.0F - new_amount);
  1164. if (old_remainder_amount != 0.0F) {
  1165. //
  1166. // Reduce the amount of influence each pass has after this operation...
  1167. //
  1168. float scale_factor = remainder / old_remainder_amount;
  1169. for (int index = 0; index < MAX_TEXTURE_PASSES; index ++) {
  1170. if (index != texture_index) {
  1171. TextureWeights[index][curr_offset] *= scale_factor;
  1172. }
  1173. }
  1174. }
  1175. TextureWeights[texture_index][curr_offset] = new_amount;
  1176. }
  1177. //
  1178. // Advance to the next vertex
  1179. //
  1180. curr_offset ++;
  1181. }
  1182. }
  1183. //
  1184. // Update the texture rendering lists
  1185. //
  1186. Update_Texture_Quad_List (min_x, min_y, max_x, max_y);
  1187. return ;
  1188. }
  1189. //////////////////////////////////////////////////////////////////////
  1190. //
  1191. // Save
  1192. //
  1193. //////////////////////////////////////////////////////////////////////
  1194. bool
  1195. EditableHeightfieldClass::Save (ChunkSaveClass &csave)
  1196. {
  1197. //
  1198. // Write the variables
  1199. //
  1200. csave.Begin_Chunk (CHUNKID_VARIABLES);
  1201. WRITE_MICRO_CHUNK (csave, VARID_GRID_PTS_X, GridPointsX);
  1202. WRITE_MICRO_CHUNK (csave, VARID_GRID_PTS_Y, GridPointsY);
  1203. WRITE_MICRO_CHUNK (csave, VARID_GRID_PT_COUNT, GridPointCount);
  1204. WRITE_MICRO_CHUNK (csave, VARID_GRID_WIDTH, Width);
  1205. WRITE_MICRO_CHUNK (csave, VARID_GRID_HEIGHT, Height);
  1206. WRITE_MICRO_CHUNK (csave, VARID_GRID_DENSITY, Density);
  1207. int texture_passes = MAX_TEXTURE_PASSES;
  1208. WRITE_MICRO_CHUNK (csave, VARID_MAX_TEXTURE_PASSES, texture_passes);
  1209. csave.End_Chunk ();
  1210. //
  1211. // Now, write out the "array" of heights
  1212. //
  1213. csave.Begin_Chunk (CHUNKID_HEIGHTS);
  1214. for (int index = 0; index < GridPointCount; index ++) {
  1215. csave.Write (&Grid[index].Z, sizeof (float));
  1216. }
  1217. csave.End_Chunk ();
  1218. //
  1219. // Now, write out the "array" of weights
  1220. //
  1221. csave.Begin_Chunk (CHUNKID_TEXTURE_WEIGHTS);
  1222. //
  1223. // Save the array of texture weights per vertex per pass
  1224. //
  1225. for (index = 0; index < GridPointCount; index ++) {
  1226. for (int pass = 0; pass < MAX_TEXTURE_PASSES; pass ++) {
  1227. csave.Write (&TextureWeights[pass][index], sizeof (float));
  1228. }
  1229. }
  1230. csave.End_Chunk ();
  1231. //
  1232. // Now, write out the array of quad flags
  1233. //
  1234. csave.Begin_Chunk (CHUNKID_QUAD_FLAGS);
  1235. int quad_count = (GridPointsX - 1) * (GridPointsY - 1);
  1236. csave.Write (QuadFlags, sizeof (uint8) * quad_count);
  1237. csave.End_Chunk ();
  1238. //
  1239. // Now, write out the list of materials
  1240. //
  1241. csave.Begin_Chunk (CHUNKID_MATERIAL_LIST);
  1242. for (index = 0; index < MAX_TEXTURE_PASSES; index ++) {
  1243. //
  1244. // Is there a material to save?
  1245. //
  1246. if (MaterialList[index] != NULL) {
  1247. //
  1248. // Save the material's definition to this chunk
  1249. //
  1250. csave.Begin_Chunk (CHUNKID_MATERIAL);
  1251. MaterialList[index]->Save (csave);
  1252. csave.End_Chunk ();
  1253. } else {
  1254. //
  1255. // Save an empty chunk so we know to leave this slot empty
  1256. //
  1257. csave.Begin_Chunk (CHUNKID_EMPTY_MATERIAL_SLOT);
  1258. csave.End_Chunk ();
  1259. }
  1260. }
  1261. csave.End_Chunk ();
  1262. return true;
  1263. }
  1264. //////////////////////////////////////////////////////////////////////
  1265. //
  1266. // Load_Materials
  1267. //
  1268. //////////////////////////////////////////////////////////////////////
  1269. void
  1270. EditableHeightfieldClass::Load_Materials (ChunkLoadClass &cload)
  1271. {
  1272. //
  1273. // Start fresh
  1274. //
  1275. Free_Material ();
  1276. int index = 0;
  1277. while (cload.Open_Chunk ()) {
  1278. switch (cload.Cur_Chunk_ID ()) {
  1279. //
  1280. // Load all the variables from this chunk
  1281. //
  1282. case CHUNKID_MATERIAL:
  1283. {
  1284. //
  1285. // Load the material
  1286. //
  1287. TerrainMaterialClass *material = new TerrainMaterialClass;
  1288. material->Load (cload);
  1289. //
  1290. // Reset the texture filename as a "relative" path
  1291. //
  1292. CString full_texture_path = material->Get_Texture_Name ();
  1293. CString rel_texture_path = ::Get_File_Mgr ()->Make_Relative_Path (full_texture_path);
  1294. material->Set_Texture (rel_texture_path);
  1295. //
  1296. // Insert the material into our list
  1297. //
  1298. MaterialList[index ++] = material;
  1299. break;
  1300. }
  1301. case CHUNKID_EMPTY_MATERIAL_SLOT:
  1302. index ++;
  1303. break;
  1304. }
  1305. cload.Close_Chunk ();
  1306. }
  1307. return ;
  1308. }
  1309. //////////////////////////////////////////////////////////////////////
  1310. //
  1311. // Load
  1312. //
  1313. //////////////////////////////////////////////////////////////////////
  1314. bool
  1315. EditableHeightfieldClass::Load (ChunkLoadClass &cload)
  1316. {
  1317. Free_Grid ();
  1318. while (cload.Open_Chunk ()) {
  1319. switch (cload.Cur_Chunk_ID ()) {
  1320. //
  1321. // Load all the variables from this chunk
  1322. //
  1323. case CHUNKID_VARIABLES:
  1324. Load_Variables (cload);
  1325. break;
  1326. case CHUNKID_HEIGHTS:
  1327. {
  1328. //
  1329. // Read the array of heights
  1330. //
  1331. for (int index = 0; index < GridPointCount; index ++) {
  1332. cload.Read (&Grid[index].Z, sizeof (float));
  1333. }
  1334. break;
  1335. }
  1336. case CHUNKID_TEXTURE_WEIGHTS:
  1337. {
  1338. //
  1339. // Read the array of texture weights per vertex per pass
  1340. //
  1341. for (int index = 0; index < GridPointCount; index ++) {
  1342. for (int pass = 0; pass < MAX_TEXTURE_PASSES; pass ++) {
  1343. cload.Read (&TextureWeights[pass][index], sizeof (float));
  1344. }
  1345. }
  1346. break;
  1347. }
  1348. case CHUNKID_QUAD_FLAGS:
  1349. {
  1350. //
  1351. // Read the array of quad flags
  1352. //
  1353. int quad_count = (GridPointsX - 1) * (GridPointsY - 1);
  1354. cload.Read (QuadFlags, sizeof (uint8) * quad_count);
  1355. break;
  1356. }
  1357. case CHUNKID_MATERIAL_LIST:
  1358. {
  1359. Load_Materials (cload);
  1360. break;
  1361. }
  1362. }
  1363. cload.Close_Chunk ();
  1364. }
  1365. //
  1366. // Update all our internal data structures from the loaded data
  1367. //
  1368. Update_Normals (0, 0, GridPointsX - 1, GridPointsY - 1);
  1369. Update_Patch_Pos_And_Normals (0, 0, GridPointsX - 1, GridPointsY - 1);
  1370. Update_UVs ();
  1371. Update_Texture_Quad_List (0, 0, GridPointsX - 1, GridPointsY - 1);
  1372. return true;
  1373. }
  1374. ////////////////////////////////////////////////////////////////
  1375. //
  1376. // Load_Variables
  1377. //
  1378. ////////////////////////////////////////////////////////////////
  1379. void
  1380. EditableHeightfieldClass::Load_Variables (ChunkLoadClass &cload)
  1381. {
  1382. int texture_passes = MAX_TEXTURE_PASSES;
  1383. while (cload.Open_Micro_Chunk ()) {
  1384. switch (cload.Cur_Micro_Chunk_ID ()) {
  1385. //
  1386. // Read each of the microchunks
  1387. //
  1388. READ_MICRO_CHUNK (cload, VARID_GRID_PTS_X, GridPointsX);
  1389. READ_MICRO_CHUNK (cload, VARID_GRID_PTS_Y, GridPointsY);
  1390. READ_MICRO_CHUNK (cload, VARID_GRID_PT_COUNT, GridPointCount);
  1391. READ_MICRO_CHUNK (cload, VARID_GRID_WIDTH, Width);
  1392. READ_MICRO_CHUNK (cload, VARID_GRID_HEIGHT, Height);
  1393. READ_MICRO_CHUNK (cload, VARID_GRID_DENSITY, Density);
  1394. READ_MICRO_CHUNK (cload, VARID_MAX_TEXTURE_PASSES, texture_passes);
  1395. }
  1396. cload.Close_Micro_Chunk ();
  1397. }
  1398. WWASSERT (texture_passes == MAX_TEXTURE_PASSES);
  1399. //
  1400. // Allocate and initialize the grid and supporting data structures
  1401. //
  1402. Allocate_Patches ();
  1403. Allocate_Grid ();
  1404. return ;
  1405. }
  1406. ////////////////////////////////////////////////////////////////
  1407. //
  1408. // On_Post_Load
  1409. //
  1410. ////////////////////////////////////////////////////////////////
  1411. void
  1412. EditableHeightfieldClass::On_Post_Load (void)
  1413. {
  1414. //Assign_Unique_IDs ();
  1415. return ;
  1416. }
  1417. ////////////////////////////////////////////////////////////////
  1418. //
  1419. // Assign_Unique_IDs
  1420. //
  1421. ////////////////////////////////////////////////////////////////
  1422. void
  1423. EditableHeightfieldClass::Assign_Unique_IDs (void)
  1424. {
  1425. //
  1426. // Assign each patch a unique ID
  1427. //
  1428. int patch_count = PatchesX * PatchesY;
  1429. for (int index = 0; index < patch_count; index ++) {
  1430. PhysObjGrid[index]->Set_ID (NodeMgrClass::Get_Node_ID (NODE_TYPE_TERRAIN));
  1431. }
  1432. return ;
  1433. }
  1434. ////////////////////////////////////////////////////////////////
  1435. //
  1436. // Create
  1437. //
  1438. ////////////////////////////////////////////////////////////////
  1439. void
  1440. EditableHeightfieldClass::Create
  1441. (
  1442. const char * heightmap_filename,
  1443. float width,
  1444. float height,
  1445. float meters_per_point,
  1446. float scale
  1447. )
  1448. {
  1449. //
  1450. // Load the bitmap from disk
  1451. //
  1452. HBITMAP bitmap = (HBITMAP)::LoadImage (NULL, heightmap_filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
  1453. if (bitmap != NULL) {
  1454. //
  1455. // Initialize the heightfield from the bitmap
  1456. //
  1457. Create (bitmap, width, height, meters_per_point, scale);
  1458. ::DeleteObject (bitmap);
  1459. }
  1460. return ;
  1461. }
  1462. ////////////////////////////////////////////////////////////////
  1463. //
  1464. // Create
  1465. //
  1466. ////////////////////////////////////////////////////////////////
  1467. void
  1468. EditableHeightfieldClass::Create
  1469. (
  1470. HBITMAP bitmap,
  1471. float width,
  1472. float height,
  1473. float meters_per_point,
  1474. float scale
  1475. )
  1476. {
  1477. if (bitmap == NULL) {
  1478. return ;
  1479. }
  1480. //
  1481. // Get the dimensions of the bitmap
  1482. //
  1483. BITMAP bmp_info = { 0 };
  1484. ::GetObject (bitmap, sizeof (BITMAP), &bmp_info);
  1485. //
  1486. // Set-up the fields of the BITMAPINFOHEADER so we can retrieve the bitmap data in this format.
  1487. // Note: Top-down DIBs use negative height in Win32.
  1488. //
  1489. BITMAPINFOHEADER bitmap_info = { 0 };
  1490. bitmap_info.biSize = sizeof (BITMAPINFOHEADER);
  1491. bitmap_info.biWidth = bmp_info.bmWidth;
  1492. bitmap_info.biHeight = bmp_info.bmHeight;
  1493. bitmap_info.biPlanes = 1;
  1494. bitmap_info.biBitCount = 24;
  1495. bitmap_info.biCompression = BI_RGB;
  1496. bitmap_info.biSizeImage = ((bmp_info.bmWidth * bmp_info.bmHeight) * 3);
  1497. //
  1498. // Allocate a buffer to store the bitmap data int
  1499. //
  1500. int stride = (((bmp_info.bmWidth * 3) + 3) & ~3);
  1501. uint8 *bmp_bits = new uint8[stride * bmp_info.bmHeight];
  1502. //
  1503. // Get the bitmap data
  1504. //
  1505. HDC screen_dc = ::GetDC (NULL);
  1506. ::GetDIBits (screen_dc, bitmap, 0, bmp_info.bmHeight,
  1507. (LPVOID)bmp_bits, (BITMAPINFO *)&bitmap_info, DIB_RGB_COLORS);
  1508. ::ReleaseDC (NULL, screen_dc);
  1509. //
  1510. // First, create the grid
  1511. //
  1512. Set_Dimensions (width, height, meters_per_point);
  1513. float half_x_dist = ((float)bmp_info.bmWidth / (float)GridPointsX) / 2;
  1514. float half_y_dist = ((float)bmp_info.bmHeight / (float)GridPointsY) / 2;
  1515. //
  1516. // Now, loop over each point of the grid and determine what its height should
  1517. // be based on the intensity of the corresponding pixel in the bitmap.
  1518. //
  1519. for (int y_pos = 0; y_pos < GridPointsY; y_pos ++) {
  1520. int start_index = (y_pos * GridPointsX);
  1521. for (int x_pos = 0; x_pos < GridPointsX; x_pos ++) {
  1522. float x_percent = (float)x_pos / (float)(GridPointsX - 1);
  1523. float y_percent = (float)y_pos / (float)(GridPointsY - 1);
  1524. float pixel_x = ((bmp_info.bmWidth - 1) * x_percent) + 0.5F;
  1525. float pixel_y = ((bmp_info.bmHeight - 1) * y_percent) + 0.5F;
  1526. float z_value = 0.0F;
  1527. //
  1528. // Do we need to sub-sample or super-sample?
  1529. //
  1530. if ( ((bmp_info.bmWidth >= bmp_info.bmHeight) && (GridPointsX < bmp_info.bmWidth)) ||
  1531. ((bmp_info.bmHeight >= bmp_info.bmWidth) && (GridPointsY < bmp_info.bmHeight)))
  1532. {
  1533. //
  1534. // Determine what range of pixels this vertex overlays
  1535. //
  1536. /*float next_x_percent = (float)(x_pos + 1) / (float)(GridPointsX - 1);
  1537. float next_y_percent = (float)(y_pos + 1) / (float)(GridPointsY - 1);
  1538. float next_pixel_x = ((bmp_info.bmWidth - 1) * next_x_percent) + 0.5F;
  1539. float next_pixel_y = ((bmp_info.bmHeight - 1) * next_y_percent) + 0.5F;*/
  1540. float pixel_x_start = pixel_x - half_x_dist;
  1541. float pixel_y_start = pixel_y - half_y_dist;
  1542. float pixel_x_end = pixel_x + half_x_dist;
  1543. float pixel_y_end = pixel_y + half_y_dist;
  1544. //
  1545. // Clip the region to the bitmap
  1546. //
  1547. int pixel_x0 = WWMath::Clamp (pixel_x_start, 0, (bmp_info.bmWidth - 1));
  1548. int pixel_y0 = WWMath::Clamp (pixel_y_start, 0, (bmp_info.bmHeight - 1));
  1549. int pixel_x1 = WWMath::Clamp (pixel_x_end, 0, (bmp_info.bmWidth - 1));
  1550. int pixel_y1 = WWMath::Clamp (pixel_y_end, 0, (bmp_info.bmHeight - 1));
  1551. float total_intensity = 0.0F;
  1552. int count = 0;
  1553. //
  1554. // Sum the pixels in this region
  1555. //
  1556. for (int curr_pixel_y = pixel_y0; curr_pixel_y <= pixel_y1; curr_pixel_y ++) {
  1557. for (int curr_pixel_x = pixel_x0; curr_pixel_x <= pixel_x1; curr_pixel_x ++) {
  1558. total_intensity += bmp_bits[(curr_pixel_y * stride) + (curr_pixel_x * 3)];
  1559. count ++;
  1560. }
  1561. }
  1562. //
  1563. // The height value is the average of the pixel intensities in this region
  1564. //
  1565. if (count > 0) {
  1566. float intensity = total_intensity / (count * 255);
  1567. z_value = intensity * scale;
  1568. }
  1569. } else {
  1570. int pixel_x0 = (int)pixel_x;
  1571. int pixel_x1 = min (pixel_x0 + 1, bmp_info.bmWidth - 1);
  1572. int pixel_y0 = (int)pixel_y;
  1573. int pixel_y1 = min (pixel_y0 + 1, bmp_info.bmHeight - 1);
  1574. //
  1575. // Get the z-values of the four corners of the pixel
  1576. //
  1577. float z0 = (float)bmp_bits[(pixel_y0 * stride) + (pixel_x0 * 3)];
  1578. float z1 = (float)bmp_bits[(pixel_y0 * stride) + (pixel_x1 * 3)];
  1579. float z2 = (float)bmp_bits[(pixel_y1 * stride) + (pixel_x1 * 3)];
  1580. float z3 = (float)bmp_bits[(pixel_y1 * stride) + (pixel_x0 * 3)];
  1581. //
  1582. // Determine how much weight we should give the z-value of each corner
  1583. //
  1584. float x0_percent = 1.0F - ((pixel_x - 0.5F) - pixel_x0);
  1585. float y0_percent = 1.0F - ((pixel_y - 0.5F) - pixel_y0);
  1586. float x1_percent = ((pixel_x - 0.5F) - pixel_x0);
  1587. float y1_percent = ((pixel_y - 0.5F) - pixel_y0);
  1588. //
  1589. // Calculate what value each corner will contribute
  1590. //
  1591. float z0_part = (x0_percent * y0_percent) * z0;
  1592. float z1_part = (x1_percent * y0_percent) * z1;
  1593. float z2_part = (x1_percent * y1_percent) * z2;
  1594. float z3_part = (x0_percent * y1_percent) * z3;
  1595. //
  1596. // Sum the contributions from each of the four corners
  1597. // of the grid cell to form the height at this point.
  1598. //
  1599. z_value = (z0_part + z1_part + z2_part + z3_part) / 255.0F;
  1600. z_value *= scale;
  1601. }
  1602. //
  1603. // Get the vertex at this position and re-assign its new Z value
  1604. //
  1605. Vector3 &vertex_pos = Grid[start_index++];
  1606. vertex_pos.Z = z_value;
  1607. }
  1608. }
  1609. //
  1610. // Now, recalculate the rendering information
  1611. //
  1612. Update_Normals (0, 0, GridPointsX - 1, GridPointsY - 1);
  1613. Update_Patch_Pos_And_Normals (0, 0, GridPointsX - 1, GridPointsY - 1);
  1614. Update_UVs ();
  1615. Update_Texture_Quad_List (0, 0, GridPointsX - 1, GridPointsY - 1);
  1616. Assign_Unique_IDs ();
  1617. //
  1618. // Free the bitmap buffer
  1619. //
  1620. SAFE_DELETE (bmp_bits);
  1621. return ;
  1622. }
  1623. ////////////////////////////////////////////////////////////////
  1624. //
  1625. // Allocate_Patches
  1626. //
  1627. ////////////////////////////////////////////////////////////////
  1628. void
  1629. EditableHeightfieldClass::Allocate_Patches (void)
  1630. {
  1631. PatchGridPointsX = 64;
  1632. PatchGridPointsY = 64;
  1633. PatchWidth = PatchGridPointsX * Density;
  1634. PatchHeight = PatchGridPointsY * Density;
  1635. //
  1636. // Determine how many patches will compose this grid
  1637. //
  1638. PatchesX = int(((float)GridPointsX / (float)PatchGridPointsX) + 0.5F);
  1639. PatchesY = int(((float)GridPointsY / (float)PatchGridPointsY) + 0.5F);
  1640. PatchesX = max (1, PatchesX);
  1641. PatchesY = max (1, PatchesY);
  1642. //
  1643. // Allocate the grid of patches
  1644. //
  1645. int patch_count = PatchesX * PatchesY;
  1646. PatchGrid = new RenegadeTerrainPatchClass *[patch_count];
  1647. PhysObjGrid = new StaticPhysClass *[patch_count];
  1648. for (int index = 0; index < patch_count; index ++) {
  1649. //
  1650. // Create this patch
  1651. //
  1652. PatchGrid[index] = new RenegadeTerrainPatchClass;
  1653. PatchGrid[index]->Allocate (PatchGridPointsX, PatchGridPointsY, Density);
  1654. //
  1655. // Calculate the coordinate for this patch
  1656. //
  1657. int patch_y_pos = (index / PatchesX);
  1658. int patch_x_pos = index - (patch_y_pos * PatchesX);
  1659. //
  1660. // Let the patch know what its bounding box is...
  1661. //
  1662. float patch_min_x = patch_x_pos * (PatchWidth - Density);
  1663. float patch_min_y = patch_y_pos * (PatchHeight - Density);
  1664. float patch_max_x = (patch_x_pos + 1) * (PatchWidth - Density);
  1665. float patch_max_y = (patch_y_pos + 1) * (PatchHeight - Density);
  1666. PatchGrid[index]->Set_Bounding_Box_Min (Vector3 (patch_min_x, patch_min_y, 0.0F));
  1667. PatchGrid[index]->Set_Bounding_Box_Max (Vector3 (patch_max_x, patch_max_y, 0.0F));
  1668. //
  1669. // Create the physics object for this heightfield
  1670. //
  1671. PhysObjGrid[index] = new StaticPhysClass;
  1672. PhysObjGrid[index]->Set_Model (PatchGrid[index]);
  1673. PhysObjGrid[index]->Set_Transform (Matrix3D (1));
  1674. //
  1675. // Add the heightfield to the scene
  1676. //
  1677. ::Get_Scene_Editor ()->Add_Static_Object (PhysObjGrid[index]);
  1678. }
  1679. //
  1680. // Now, recompute the overall dimensions of the heightfield
  1681. //
  1682. GridPointsX = (PatchesX * PatchGridPointsX) - (PatchesX - 1);
  1683. GridPointsY = (PatchesY * PatchGridPointsY) - (PatchesY - 1);
  1684. GridPointCount = GridPointsX * GridPointsY;
  1685. Width = GridPointsX * Density;
  1686. Height = GridPointsY * Density;
  1687. //
  1688. // Force lighting to be updated...
  1689. //
  1690. ::Get_Scene_Editor ()->Update_Lighting ();
  1691. return ;
  1692. }
  1693. ////////////////////////////////////////////////////////////////
  1694. //
  1695. // Update_Patch_Pos_And_Normals
  1696. //
  1697. ////////////////////////////////////////////////////////////////
  1698. void
  1699. EditableHeightfieldClass::Update_Patch_Pos_And_Normals
  1700. (
  1701. int min_x,
  1702. int min_y,
  1703. int max_x,
  1704. int max_y
  1705. )
  1706. {
  1707. //
  1708. // Determine which patches this operation would possibly affect
  1709. //
  1710. int min_patch_x = min_x / (PatchGridPointsX - 1);
  1711. int min_patch_y = min_y / (PatchGridPointsY - 1);
  1712. int max_patch_x = max_x / (PatchGridPointsX - 1);
  1713. int max_patch_y = max_y / (PatchGridPointsY - 1);
  1714. max_patch_x = min (max_patch_x, (PatchesX - 1));
  1715. max_patch_y = min (max_patch_y, (PatchesY - 1));
  1716. //
  1717. // Loop over all the patches (by rows)
  1718. //
  1719. for (int y_pos = min_patch_y; y_pos <= max_patch_y; y_pos ++) {
  1720. //
  1721. // Reset the vertical vertex patch
  1722. //
  1723. int min_vert_y = y_pos * (PatchGridPointsY - 1);
  1724. int max_vert_y = (y_pos + 1) * (PatchGridPointsY - 1);
  1725. for (int x_pos = min_patch_x; x_pos <= max_patch_x; x_pos ++) {
  1726. //
  1727. // Reset the horizontal vertex patch
  1728. //
  1729. int min_vert_x = x_pos * (PatchGridPointsX - 1);
  1730. int max_vert_x = (x_pos + 1) * (PatchGridPointsX - 1);
  1731. //
  1732. // Determine which patch this is
  1733. //
  1734. int patch_index = (y_pos * PatchesX) + x_pos;
  1735. //
  1736. // Loop over the verts in this patch
  1737. //
  1738. for (int vert_y = min_vert_y; vert_y <= max_vert_y; vert_y ++) {
  1739. for (int vert_x = min_vert_x; vert_x <= max_vert_x; vert_x ++) {
  1740. //
  1741. // Get the position and normal at this vertex
  1742. //
  1743. const Vector3 &pos = Grid[Grid_Index (vert_x, vert_y)];
  1744. const Vector3 &normal = GridNormals[Grid_Index (vert_x, vert_y)];
  1745. //
  1746. // Determine what vertex index inside the patch we are changing
  1747. //
  1748. int patch_vert_x = vert_x - min_vert_x;
  1749. int patch_vert_y = vert_y - min_vert_y;
  1750. //
  1751. // Update the vertex position and normal inside the patch
  1752. //
  1753. PatchGrid[patch_index]->Set_Vertex_Pos (patch_vert_x, patch_vert_y, pos);
  1754. PatchGrid[patch_index]->Set_Vertex_Normal (patch_vert_x, patch_vert_y, normal);
  1755. }
  1756. }
  1757. //
  1758. // Update the culling box for this patch
  1759. //
  1760. PhysObjGrid[patch_index]->Update_Cull_Box ();
  1761. }
  1762. }
  1763. return ;
  1764. }
  1765. ////////////////////////////////////////////////////////////////
  1766. //
  1767. // Free_Patches
  1768. //
  1769. ////////////////////////////////////////////////////////////////
  1770. void
  1771. EditableHeightfieldClass::Free_Patches (void)
  1772. {
  1773. int patch_count = PatchesX * PatchesY;
  1774. //
  1775. // Release our hold on each patch in the grid
  1776. //
  1777. for (int index = 0; index < patch_count; index ++) {
  1778. ::Get_Scene_Editor ()->Remove_Object (PhysObjGrid[index]);
  1779. REF_PTR_RELEASE (PhysObjGrid[index]);
  1780. REF_PTR_RELEASE (PatchGrid[index]);
  1781. }
  1782. //
  1783. // Free the grid itself
  1784. //
  1785. SAFE_DELETE_ARRAY (PatchGrid);
  1786. SAFE_DELETE_ARRAY (PhysObjGrid);
  1787. PatchGrid = NULL;
  1788. PhysObjGrid = NULL;
  1789. PatchesX = 0;
  1790. PatchesY = 0;
  1791. PatchGridPointsX = 0;
  1792. PatchGridPointsY = 0;
  1793. PatchWidth = 0;
  1794. PatchHeight = 0;
  1795. return ;
  1796. }