TerrainEditing.cpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "StdAfx.h"
  13. #include <Engine/Templates/Stock_CTextureData.h>
  14. // global variables used in terrain editing functions
  15. UWORD *_puwBuffer=NULL;
  16. Rect _rect;
  17. PIX _srcExtraW=0;
  18. PIX _srcExtraH=0;
  19. CTextureData *_ptdBrush=NULL;
  20. CTextureData *_ptdDistributionRandomNoise=NULL;
  21. CTextureData *_ptdContinousRandomNoise=NULL;
  22. UWORD *_puwNoiseTarget=NULL;
  23. PIX _pixNoiseTargetW=0;
  24. PIX _pixNoiseTargetH=0;
  25. FLOAT _fStrength=0.0f;
  26. // fbm noise buffer
  27. FLOAT *_pafWhiteNoise=NULL;
  28. #define WNOISE 64
  29. // undo variables
  30. UWORD *_puwUndoTerrain=NULL;
  31. Rect _rectUndo;
  32. BOOL _bUndoStart=FALSE;
  33. BufferType _btUndoBufferType=BT_INVALID;
  34. INDEX _iUndoBufferData=-1;
  35. INDEX _iTerrainEntityID=-1;
  36. // filter matrices
  37. FLOAT _afFilterFineBlur[5][5]=
  38. {
  39. {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
  40. {0.0f, 0.0625f, 0.0625f, 0.0625f, 0.0f},
  41. {0.0f, 0.0625f, 0.5f, 0.0625f, 0.0f},
  42. {0.0f, 0.0625f, 0.0625f, 0.0625f, 0.0f},
  43. {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
  44. };
  45. FLOAT _afFilterBlurMore[5][5]=
  46. {
  47. {0.0277777f, 0.0277777f, 0.0277777f, 0.0277777f, 0.0277777f},
  48. {0.0277777f, 0.0555555f, 0.0555555f, 0.0555555f, 0.0277777f},
  49. {0.0277777f, 0.0555555f, 0.0111111f, 0.0555555f, 0.0277777f},
  50. {0.0277777f, 0.0555555f, 0.0555555f, 0.0555555f, 0.0277777f},
  51. {0.0277777f, 0.0277777f, 0.0277777f, 0.0277777f, 0.0277777f},
  52. };
  53. FLOAT _afFilterEdgeDetect[5][5]=
  54. {
  55. {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
  56. {0.0f, 1.0f, 1.0f, 1.0f, 0.0f},
  57. {0.0f, 1.0f, -7.0f, 1.0f, 0.0f},
  58. {0.0f, 1.0f, 1.0f, 1.0f, 0.0f},
  59. {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
  60. };
  61. FLOAT _afFilterEmboss[5][5]=
  62. {
  63. {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
  64. {0.0f, 1.0f, 1.0f, -1.0f, 0.0f},
  65. {0.0f, 1.0f, 1.0f, -1.0f, 0.0f},
  66. {0.0f, 1.0f, -1.0f, -1.0f, 0.0f},
  67. {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
  68. };
  69. FLOAT _afFilterSharpen[5][5]=
  70. {
  71. {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
  72. {0.0f, -1.0f, -1.0f, -1.0f, 0.0f},
  73. {0.0f, -1.0f, 16.0f, -1.0f, 0.0f},
  74. {0.0f, -1.0f, -1.0f, -1.0f, 0.0f},
  75. {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
  76. };
  77. FLOAT GetBrushMultiplier(INDEX x, INDEX y)
  78. {
  79. if(_ptdBrush==NULL) return 1.0f;
  80. {
  81. COLOR col=_ptdBrush->GetTexel(x,y);
  82. FLOAT fResult=FLOAT(col>>24)/255.0f;
  83. return fResult;
  84. }
  85. }
  86. void ApplyAddPaint(UWORD uwMin, UWORD uwMax)
  87. {
  88. for(INDEX y=0; y<_rect.Height(); y++)
  89. {
  90. for(INDEX x=0; x<_rect.Width(); x++)
  91. {
  92. FLOAT fBrushMultiplier=GetBrushMultiplier(x,y);
  93. if( fBrushMultiplier==0.0f) continue;
  94. INDEX iOffset=y*_rect.Width()+x;
  95. FLOAT fValue=_puwBuffer[iOffset];
  96. fValue+=fBrushMultiplier*_fStrength*32.0f*theApp.m_fPaintPower;
  97. fValue=Clamp(fValue,FLOAT(uwMin),FLOAT(uwMax));
  98. _puwBuffer[iOffset]=fValue;
  99. }
  100. }
  101. }
  102. void ApplyRNDNoise(void)
  103. {
  104. CTerrain *ptrTerrain=GetTerrain();
  105. if( ptrTerrain==NULL) return;
  106. FLOAT fMaxNoise=theApp.m_fNoiseAltitude/ptrTerrain->tr_vTerrainSize(2)*65535.0f;
  107. for(INDEX y=0; y<_rect.Height(); y++)
  108. {
  109. for(INDEX x=0; x<_rect.Width(); x++)
  110. {
  111. FLOAT fBrushMultiplier=GetBrushMultiplier(x,y);
  112. INDEX iPixSrc=y*_rect.Width()+x;
  113. FLOAT fInfluence=_puwBuffer[iPixSrc];
  114. FLOAT fRnd=FLOAT(rand())/RAND_MAX-0.5f;
  115. FLOAT fValue=_puwBuffer[iPixSrc];
  116. FLOAT fMaxRandomized=fValue+fRnd*fMaxNoise;
  117. FLOAT fFilterPower=Clamp(fBrushMultiplier*_fStrength,0.0f,1.0f);
  118. FLOAT fResult=Lerp( fValue, fMaxRandomized, fFilterPower);
  119. UWORD uwResult=Clamp(UWORD(fResult),MIN_UWORD,MAX_UWORD);
  120. _puwBuffer[iPixSrc]=uwResult;
  121. }
  122. }
  123. }
  124. FLOAT GetDistributionNoise( INDEX x, INDEX y, FLOAT fRandom)
  125. {
  126. INDEX iw=_ptdDistributionRandomNoise->GetPixWidth();
  127. INDEX ih=_ptdDistributionRandomNoise->GetPixHeight();
  128. INDEX ctSize=iw*ih;
  129. INDEX iOffset=abs(INDEX(iw*y+x+fRandom*ctSize)%ctSize);
  130. COLOR col=_ptdDistributionRandomNoise->td_pulFrames[iOffset];
  131. FLOAT fResult=FLOAT(col&0xFF)/255.0f;
  132. return fResult;
  133. }
  134. FLOAT GetContinousNoise( INDEX x, INDEX y, FLOAT fRandom)
  135. {
  136. INDEX iw=_ptdContinousRandomNoise->GetPixWidth();
  137. INDEX ih=_ptdContinousRandomNoise->GetPixHeight();
  138. INDEX ctSize=iw*ih;
  139. INDEX iOffset=abs(INDEX(iw*y+x+fRandom*ctSize)%ctSize);
  140. COLOR col=_ptdContinousRandomNoise->td_pulFrames[iOffset];
  141. FLOAT fResult=FLOAT(col&0xFF)/255.0f;
  142. return fResult;
  143. }
  144. void ApplyContinousNoise(void)
  145. {
  146. CTerrain *ptrTerrain=GetTerrain();
  147. if( ptrTerrain==NULL) return;
  148. FLOAT fMaxNoise=theApp.m_fNoiseAltitude/ptrTerrain->tr_vTerrainSize(2)*65535.0f;
  149. for(INDEX y=0; y<_rect.Height(); y++)
  150. {
  151. INDEX oy=y+_rect.rc_iTop;
  152. for(INDEX x=0; x<_rect.Width(); x++)
  153. {
  154. INDEX ox=x+_rect.rc_iLeft;
  155. FLOAT fBrushMultiplier=GetBrushMultiplier(x,y);
  156. INDEX iPixSrc=y*_rect.Width()+x;
  157. FLOAT fInfluence=_puwBuffer[iPixSrc];
  158. FLOAT fRnd=GetContinousNoise( ox, oy, 0.0f)-0.5f;
  159. FLOAT fValue=_puwBuffer[iPixSrc];
  160. FLOAT fMaxRandomized=fValue+fRnd*fMaxNoise;
  161. fMaxRandomized=Clamp(fMaxRandomized,(FLOAT)MIN_UWORD,(FLOAT)MAX_UWORD);
  162. FLOAT fFilterPower=Clamp(fBrushMultiplier*_fStrength,0.0f,1.0f);
  163. FLOAT fResult=Lerp( fValue, fMaxRandomized, fFilterPower);
  164. UWORD uwResult=Clamp((UWORD)fResult,MIN_UWORD,MAX_UWORD);
  165. _puwBuffer[iPixSrc]=uwResult;
  166. }
  167. }
  168. }
  169. void ApplyPosterize(void)
  170. {
  171. CTerrain *ptrTerrain=GetTerrain();
  172. if( ptrTerrain==NULL) return;
  173. FLOAT fStepUW=theApp.m_fPosterizeStep/ptrTerrain->tr_vTerrainSize(2)*65535.0f;
  174. for(INDEX y=0; y<_rect.Height(); y++)
  175. {
  176. for(INDEX x=0; x<_rect.Width(); x++)
  177. {
  178. FLOAT fBrushMultiplier=GetBrushMultiplier(x,y);
  179. if(fBrushMultiplier==0.0f) continue;
  180. INDEX iPixSrc=y*_rect.Width()+x;
  181. FLOAT fValue=_puwBuffer[iPixSrc];
  182. FLOAT fPosterized=(INDEX(fValue/fStepUW))*fStepUW+1.0f;
  183. UWORD uwResult=Clamp(UWORD(fPosterized),MIN_UWORD,MAX_UWORD);
  184. _puwBuffer[iPixSrc]=uwResult;
  185. }
  186. }
  187. }
  188. void ApplyFilterMatrix(FLOAT afFilterMatrix[5][5])
  189. {
  190. INDEX ctBuffBytes=_rect.Width()*_rect.Height()*sizeof(UWORD);
  191. UWORD *puwDst=(UWORD*)AllocMemory(ctBuffBytes);
  192. memcpy(puwDst,_puwBuffer,ctBuffBytes);
  193. for(INDEX y=0; y<_rect.Height()-_srcExtraH*2; y++)
  194. {
  195. for(INDEX x=0; x<_rect.Width()-_srcExtraW*2; x++)
  196. {
  197. INDEX iPixDst=(y+_srcExtraH)*_rect.Width()+x+_srcExtraW;
  198. FLOAT fBrushMultiplier=GetBrushMultiplier(x,y);
  199. FLOAT fDivSum=0.0f;
  200. FLOAT fSum=0.0f;
  201. for(INDEX j=0; j<5; j++)
  202. {
  203. for(INDEX i=0; i<5; i++)
  204. {
  205. FLOAT fWeight=(afFilterMatrix)[i][j];
  206. fDivSum+=fWeight;
  207. INDEX iPixSrc=(y+j)*_rect.Width()+(x+i);
  208. FLOAT fInfluence=_puwBuffer[iPixSrc];
  209. fSum+=fInfluence*fWeight;
  210. }
  211. }
  212. UWORD uwMax=Clamp(UWORD(fSum/fDivSum),MIN_UWORD,MAX_UWORD);
  213. FLOAT fFilterPower=Clamp(fBrushMultiplier*_fStrength/64.0f,0.0f,1.0f);
  214. UWORD uwResult=Lerp( puwDst[iPixDst], uwMax, fFilterPower);
  215. puwDst[iPixDst]=uwResult;
  216. }
  217. }
  218. memcpy(_puwBuffer,puwDst,ctBuffBytes);
  219. FreeMemory( puwDst);
  220. }
  221. static INDEX _iTerrainWidth=0;
  222. static UWORD *_puwHeightMap=NULL;
  223. static INDEX _iRandomDX=0;
  224. void SetHMPixel( UWORD pix, INDEX x, INDEX y)
  225. {
  226. UWORD *pdest=_puwHeightMap+y*_iTerrainWidth+x;
  227. if (*pdest==65535) {
  228. *pdest=pix;
  229. }
  230. }
  231. UWORD GetHMPixel(INDEX x, INDEX y)
  232. {
  233. UWORD *pdest=_puwHeightMap+y*_iTerrainWidth+x;
  234. return *pdest;
  235. }
  236. UWORD RandomizePixel(FLOAT fmid, FLOAT fdmax)
  237. {
  238. FLOAT fRand=((FLOAT)rand())/RAND_MAX-0.5f;
  239. FLOAT fd=fdmax*fRand;
  240. FLOAT fres=Clamp(fmid+fd,0.0f,65536.0f);
  241. return fres;
  242. }
  243. void SubdivideAndDisplace(INDEX x, INDEX y, INDEX idx, FLOAT fdMax)
  244. {
  245. FLOAT flu=GetHMPixel(x,y);
  246. FLOAT fru=GetHMPixel(x+idx,y);
  247. FLOAT frd=GetHMPixel(x+idx,y+idx);
  248. FLOAT fld=GetHMPixel(x,y+idx);
  249. if( fdMax<_iRandomDX)
  250. {
  251. SetHMPixel(RandomizePixel((flu+fru)/2.0f,fdMax), x+idx/2, y ); // middle top
  252. SetHMPixel(RandomizePixel((fld+frd)/2.0f,fdMax), x+idx/2, y+idx ); // middle bottom
  253. SetHMPixel(RandomizePixel((fru+frd)/2.0f,fdMax), x+idx, y+idx/2); // right middle
  254. SetHMPixel(RandomizePixel((flu+fld)/2.0f,fdMax), x, y+idx/2); // left middle
  255. SetHMPixel(RandomizePixel((flu+fru+fld+frd)/4.0f,fdMax), x+idx/2, y+idx/2); // middle
  256. }
  257. else
  258. {
  259. SetHMPixel(RandomizePixel(65536.0f/2.0f,fdMax), x+idx/2, y ); // middle top
  260. SetHMPixel(RandomizePixel(65536.0f/2.0f,fdMax), x+idx/2, y+idx ); // middle bottom
  261. SetHMPixel(RandomizePixel(65536.0f/2.0f,fdMax), x+idx, y+idx/2); // right middle
  262. SetHMPixel(RandomizePixel(65536.0f/2.0f,fdMax), x, y+idx/2); // left middle
  263. SetHMPixel(RandomizePixel(65536.0f/2.0f,fdMax), x+idx/2, y+idx/2); // middle
  264. }
  265. fdMax*=0.5f;
  266. if(idx>1)
  267. {
  268. SubdivideAndDisplace(x ,y , idx/2, fdMax);
  269. SubdivideAndDisplace(x+idx/2,y , idx/2, fdMax);
  270. SubdivideAndDisplace(x ,y+idx/2, idx/2, fdMax);
  271. SubdivideAndDisplace(x+idx/2,y+idx/2, idx/2, fdMax);
  272. }
  273. }
  274. Rect GetTerrainRect(void)
  275. {
  276. Rect rect;
  277. rect.rc_iLeft=0;
  278. rect.rc_iRight=0;
  279. rect.rc_iTop=0;
  280. rect.rc_iBottom=0;
  281. CTerrain *ptrTerrain=GetTerrain();
  282. if( ptrTerrain==NULL) return rect;
  283. rect.rc_iLeft=0;
  284. rect.rc_iRight=ptrTerrain->tr_pixHeightMapWidth;
  285. rect.rc_iTop=0;
  286. rect.rc_iBottom=ptrTerrain->tr_pixHeightMapHeight;
  287. return rect;
  288. }
  289. FLOAT GetWrappedPixelValue( INDEX x, INDEX y)
  290. {
  291. INDEX iWrapX=(x+WNOISE)%WNOISE;
  292. INDEX iWrapY=(y+WNOISE)%WNOISE;
  293. return _pafWhiteNoise[iWrapY*WNOISE+iWrapX];
  294. }
  295. void RandomizeWhiteNoise(void)
  296. {
  297. if(_pafWhiteNoise==NULL)
  298. {
  299. _pafWhiteNoise=(FLOAT *)AllocMemory(WNOISE*WNOISE*sizeof(FLOAT));
  300. }
  301. FLOAT *pfTemp=_pafWhiteNoise;
  302. for(INDEX i=0; i<WNOISE*WNOISE; i++)
  303. {
  304. FLOAT fRnd=FLOAT(rand())/RAND_MAX-0.5f;
  305. *pfTemp=fRnd;
  306. pfTemp++;
  307. }
  308. }
  309. FLOAT *GenerateTerrain_FBMBuffer(PIX pixW, PIX pixH, INDEX ctOctaves, FLOAT fHighFrequencyStep,
  310. FLOAT fStepFactor, FLOAT fMaxAmplitude, FLOAT fAmplitudeDecreaser,
  311. BOOL bAddNegativeValues, BOOL bRandomOffest, FLOAT &fMin, FLOAT &fMax)
  312. {
  313. if(_pafWhiteNoise==NULL)
  314. {
  315. RandomizeWhiteNoise();
  316. }
  317. FLOAT *pfTemp=_pafWhiteNoise;
  318. FLOAT fTmpMaxAmplitude=fMaxAmplitude;
  319. INDEX ctMemory=pixW*pixH*sizeof(FLOAT);
  320. FLOAT *pafFBM=(FLOAT *)AllocMemory(ctMemory);
  321. memset(pafFBM,0,ctMemory);
  322. FLOAT fPixStep=fHighFrequencyStep/pow(fStepFactor,ctOctaves);
  323. fMin=1e6;
  324. fMax=-1e6;
  325. for(INDEX iOctave=ctOctaves-1; iOctave>=0; iOctave--)
  326. {
  327. FLOAT fOctaveOffset=0.0f;
  328. if( bRandomOffest)
  329. {
  330. fOctaveOffset=_pafWhiteNoise[iOctave];
  331. }
  332. for(INDEX y=0; y<pixH; y++)
  333. {
  334. for(INDEX x=0; x<pixW; x++)
  335. {
  336. FLOAT fY=y*fPixStep+fOctaveOffset;
  337. FLOAT fX=x*fPixStep+fOctaveOffset;
  338. // calculate bilinear value
  339. FLOAT fLU=GetWrappedPixelValue( fX , fY);
  340. FLOAT fRU=GetWrappedPixelValue( fX+1, fY);
  341. FLOAT fLD=GetWrappedPixelValue( fX , fY+1);
  342. FLOAT fRD=GetWrappedPixelValue( fX+1, fY+1);
  343. FLOAT fFX=fX-INDEX(fX);
  344. FLOAT fFY=fY-INDEX(fY);
  345. FLOAT fBil=Lerp(Lerp(fLU,fRU,fFX),Lerp(fLD,fRD,fFX),fFY);
  346. INDEX iOffset=pixW*y+x;
  347. FLOAT fValue=pafFBM[iOffset];
  348. FLOAT fAdd=fBil*fTmpMaxAmplitude;
  349. if(bAddNegativeValues || fAdd>0)
  350. {
  351. fValue=fValue+fAdd;
  352. }
  353. pafFBM[iOffset]=fValue;
  354. if(fValue>fMax) fMax=fValue;
  355. if(fValue<fMin) fMin=fValue;
  356. }
  357. }
  358. fPixStep*=fStepFactor;
  359. fTmpMaxAmplitude*=fAmplitudeDecreaser;
  360. }
  361. return pafFBM;
  362. }
  363. void GenerateTerrain_SubdivideAndDisplace(void)
  364. {
  365. // inside subdivide and displace functions we will use these global variables
  366. _iTerrainWidth=_rect.Width();
  367. _puwHeightMap=_puwBuffer;
  368. UWORD uwScrollValue=8.0f-Clamp(theApp.m_iRNDSubdivideAndDisplaceItterations, INDEX(0), INDEX(8));
  369. _iRandomDX=(_iTerrainWidth-1)<<uwScrollValue;
  370. UWORD uwrnd;
  371. FLOAT fdMax=65536.0f;
  372. for (INDEX i=0; i<_rect.Width()*_rect.Height(); i++) {
  373. _puwHeightMap[i] = 65535;
  374. }
  375. uwrnd=RandomizePixel(fdMax/2.0f,fdMax); SetHMPixel(uwrnd, 0, 0);
  376. uwrnd=RandomizePixel(fdMax/2.0f,fdMax); SetHMPixel(uwrnd, _iTerrainWidth-1, 0);
  377. uwrnd=RandomizePixel(fdMax/2.0f,fdMax); SetHMPixel(uwrnd, _iTerrainWidth-1, _iTerrainWidth-1);
  378. uwrnd=RandomizePixel(fdMax/2.0f,fdMax); SetHMPixel(uwrnd, 0, _iTerrainWidth-1);
  379. // generate rest of terrain pixels using recursion
  380. SubdivideAndDisplace(0,0,_iTerrainWidth-1,fdMax/2.0f);
  381. }
  382. void GenerateTerrain(void)
  383. {
  384. CTerrain *ptrTerrain=GetTerrain();
  385. if( ptrTerrain==NULL) return;
  386. switch(theApp.m_iTerrainGenerationMethod)
  387. {
  388. case 0:
  389. {
  390. GenerateTerrain_SubdivideAndDisplace();
  391. break;
  392. }
  393. case 1:
  394. {
  395. FLOAT fMin, fMax;
  396. PIX pixTerrainW=ptrTerrain->tr_pixHeightMapWidth;
  397. PIX pixTerrainH=ptrTerrain->tr_pixHeightMapHeight;
  398. FLOAT *pafFBM=GenerateTerrain_FBMBuffer( pixTerrainW, pixTerrainH, theApp.m_iFBMOctaves,
  399. theApp.m_fFBMHighFrequencyStep,theApp.m_fFBMStepFactor, theApp.m_fFBMMaxAmplitude,
  400. theApp.m_fFBMfAmplitudeDecreaser, theApp.m_bFBMAddNegativeValues, theApp.m_bFBMRandomOffset, fMin, fMax);
  401. // convert buffer to height map
  402. FLOAT fSizeY=ptrTerrain->tr_vTerrainSize(2);
  403. FLOAT fConvertFactor=(theApp.m_fFBMMaxAmplitude/fSizeY)*MAX_UWORD;
  404. // set height map
  405. for(INDEX iPix=0; iPix<pixTerrainW*pixTerrainH; iPix++)
  406. {
  407. FLOAT fValue=pafFBM[iPix];
  408. UWORD uwValue=UWORD(Clamp((fValue-fMin)/(fMax-fMin)*fConvertFactor,0.0f,65535.0f));
  409. _puwBuffer[iPix]=uwValue;
  410. }
  411. FreeMemory( pafFBM);
  412. break;
  413. }
  414. }
  415. }
  416. void EqualizeBuffer(void)
  417. {
  418. UWORD uwHeightMax=0;
  419. UWORD uwHeightMin=MAX_UWORD;
  420. INDEX x,y;
  421. for(y=0; y<_rect.Height(); y++)
  422. {
  423. for(x=0; x<_rect.Width(); x++)
  424. {
  425. INDEX iOffset = y*_rect.Width()+x;
  426. UWORD uwHeight = _puwBuffer[iOffset];
  427. if( uwHeight>uwHeightMax) uwHeightMax=uwHeight;
  428. if( uwHeight<uwHeightMin) uwHeightMin=uwHeight;
  429. }
  430. }
  431. FLOAT fFactor=65535.0f/(uwHeightMax-uwHeightMin);
  432. // equalize (normalize from 0 to 65535)
  433. for(y=0; y<_rect.Height(); y++)
  434. {
  435. for(x=0; x<_rect.Width(); x++)
  436. {
  437. INDEX iOffset = y*_rect.Width()+x;
  438. UWORD uwHeight = _puwBuffer[iOffset];
  439. FLOAT fNormalized=(uwHeight-uwHeightMin)*fFactor;
  440. _puwBuffer[iOffset]=fNormalized;
  441. }
  442. }
  443. }
  444. BOOL SetupContinousNoiseTexture( void)
  445. {
  446. try
  447. {
  448. _ptdContinousRandomNoise=_pTextureStock->Obtain_t( theApp.m_fnContinousNoiseTexture);
  449. _ptdContinousRandomNoise->Force(TEX_STATIC|TEX_CONSTANT);
  450. }
  451. catch( char *strError)
  452. {
  453. (void) strError;
  454. WarningMessage("Unable to obtain continous random noise texture!\nError: %s", strError);
  455. return FALSE;
  456. }
  457. return TRUE;
  458. }
  459. void FreeContinousNoiseTexture( void)
  460. {
  461. _pTextureStock->Release( _ptdContinousRandomNoise);
  462. }
  463. BOOL SetupDistributionNoiseTexture( void)
  464. {
  465. try
  466. {
  467. _ptdDistributionRandomNoise=_pTextureStock->Obtain_t( theApp.m_fnDistributionNoiseTexture);
  468. _ptdDistributionRandomNoise->Force(TEX_STATIC|TEX_CONSTANT);
  469. }
  470. catch( char *strError)
  471. {
  472. (void) strError;
  473. WarningMessage("Unable to obtain distribution random noise texture!\nError: %s", strError);
  474. return FALSE;
  475. }
  476. return TRUE;
  477. }
  478. void FreeDistributionNoiseTexture( void)
  479. {
  480. _pTextureStock->Release( _ptdDistributionRandomNoise);
  481. }
  482. FLOAT StepUp(FLOAT fCur, FLOAT fMin, FLOAT fMax)
  483. {
  484. if( fCur<=fMin) return 0.0f;
  485. if( fCur>=fMax) return 1.0f;
  486. return (fCur-fMin)/(fMax-fMin);
  487. }
  488. FLOAT StepDown(FLOAT fCur, FLOAT fMin, FLOAT fMax)
  489. {
  490. if( fCur<=fMin) return 1.0f;
  491. if( fCur>=fMax) return 0.0f;
  492. return (fMax-fCur)/(fMax-fMin);
  493. }
  494. FLOAT3D NormalFrom4Points(const FLOAT3D &v0, const FLOAT3D &v1, const FLOAT3D &v2, const FLOAT3D &v3,
  495. FLOAT fLerpX, FLOAT fLerpZ)
  496. {
  497. FLOAT fHDeltaX = Lerp(v1(2)-v0(2), v3(2)-v2(2), fLerpZ);
  498. FLOAT fHDeltaZ = Lerp(v0(2)-v2(2), v1(2)-v3(2), fLerpX);
  499. FLOAT fDeltaX = v1(1) - v0(1);
  500. FLOAT fDeltaZ = v0(3) - v2(3);
  501. FLOAT3D vNormal;
  502. vNormal(2) = sqrt(1 / (((fHDeltaX*fHDeltaX)/(fDeltaX*fDeltaX)) + ((fHDeltaZ*fHDeltaZ)/(fDeltaZ*fDeltaZ)) + 1));
  503. vNormal(1) = sqrt(vNormal(2)*vNormal(2) * ((fHDeltaX*fHDeltaX) / (fDeltaX*fDeltaX)));
  504. vNormal(3) = sqrt(vNormal(2)*vNormal(2) * ((fHDeltaZ*fHDeltaZ) / (fDeltaZ*fDeltaZ)));
  505. if (fHDeltaX>0) {
  506. vNormal(1) = -vNormal(1);
  507. }
  508. if (fHDeltaZ<0) {
  509. vNormal(3) = -vNormal(3);
  510. }
  511. //ASSERT(Abs(vNormal.Length()-1)<0.01);
  512. return vNormal;
  513. }
  514. FLOAT3D GetPoint(CTerrain *ptrTerrain, INDEX iX, INDEX iY)
  515. {
  516. const FLOAT3D &vStretch = ptrTerrain->tr_vStretch;
  517. iX = Clamp(iX, INDEX(0), ptrTerrain->tr_pixHeightMapWidth);
  518. iY = Clamp(iY, INDEX(0), ptrTerrain->tr_pixHeightMapHeight);
  519. return FLOAT3D(
  520. FLOAT(iX)*vStretch(1),
  521. (FLOAT)ptrTerrain->tr_auwHeightMap[iX+iY*ptrTerrain->tr_pixHeightMapWidth] * vStretch(2),
  522. FLOAT(iY)*vStretch(3));
  523. }
  524. UWORD GetSlope(CTerrain *ptrTerrain, INDEX iX, INDEX iY)
  525. {
  526. FLOAT3D av[9];
  527. INDEX iHMapWidth = ptrTerrain->tr_pixHeightMapWidth;
  528. FLOAT3D vStretch = ptrTerrain->tr_vStretch;
  529. av[0] = GetPoint(ptrTerrain, iX-1, iY-1);
  530. av[1] = GetPoint(ptrTerrain, iX , iY-1);
  531. av[2] = GetPoint(ptrTerrain, iX+1, iY-1);
  532. av[3] = GetPoint(ptrTerrain, iX-1, iY );
  533. av[4] = GetPoint(ptrTerrain, iX , iY );
  534. av[5] = GetPoint(ptrTerrain, iX+1, iY );
  535. av[6] = GetPoint(ptrTerrain, iX-1, iY+1);
  536. av[7] = GetPoint(ptrTerrain, iX , iY+1);
  537. av[8] = GetPoint(ptrTerrain, iX+1, iY+1);
  538. FLOAT3D avN[4];
  539. FLOAT3D vNormal;
  540. avN[0] = NormalFrom4Points(av[0], av[1], av[3], av[4], 1, 1);
  541. avN[1] = NormalFrom4Points(av[1], av[2], av[4], av[5], 0, 1);
  542. avN[2] = NormalFrom4Points(av[3], av[4], av[6], av[7], 1, 0);
  543. avN[3] = NormalFrom4Points(av[4], av[5], av[7], av[8], 0, 0);
  544. vNormal = avN[0]+avN[1]+avN[2]+avN[3];
  545. vNormal.Normalize();
  546. return (1-vNormal(2))*65535;
  547. }
  548. void GenerateLayerDistribution(INDEX iForLayer, Rect rect)
  549. {
  550. if(!SetupDistributionNoiseTexture()) return;
  551. CTerrain *ptrTerrain=GetTerrain();
  552. if( ptrTerrain==NULL) return;
  553. // obtain buffer
  554. UWORD *puwAltitude=GetBufferForEditing(ptrTerrain, rect, BT_HEIGHT_MAP, 0);
  555. INDEX ctSize=rect.Width()*rect.Height()*sizeof(UWORD);
  556. UWORD *puwSlope=(UWORD *)AllocMemory(ctSize);
  557. // prepare slope buffer
  558. for(INDEX y=0; y<rect.Height(); y++)
  559. {
  560. for(INDEX x=0; x<rect.Width(); x++)
  561. {
  562. INDEX iOffset = y*rect.Width()+x;
  563. puwSlope[iOffset] = GetSlope(ptrTerrain, x+rect.rc_iLeft, y+rect.rc_iTop);
  564. }
  565. }
  566. // for each layer
  567. for(INDEX iLayer=0; iLayer<ptrTerrain->tr_atlLayers.Count(); iLayer++)
  568. {
  569. if( iForLayer!=-1 && iLayer!=iForLayer) continue;
  570. CTerrainLayer *ptlLayer=GetLayer(iLayer);
  571. if(!ptlLayer->tl_bAutoRegenerated) continue;
  572. // get layer
  573. UWORD *puwMask=GetBufferForEditing(ptrTerrain, rect, BT_LAYER_MASK, iLayer);
  574. for(INDEX y=0; y<rect.Height(); y++)
  575. {
  576. INDEX oy=y+rect.rc_iTop;
  577. for(INDEX x=0; x<rect.Width(); x++)
  578. {
  579. INDEX ox=x+rect.rc_iLeft;
  580. INDEX iOffset = y*rect.Width()+x;
  581. FLOAT fAltitudeRatio = puwAltitude[iOffset]/65535.0f;
  582. FLOAT fSlopeRatio = puwSlope[iOffset]/65535.0f;
  583. FLOAT fAltitudeRange=ptlLayer->tl_fMaxAltitude-ptlLayer->tl_fMinAltitude;
  584. FLOAT fSlopeRange=ptlLayer->tl_fMaxSlope-ptlLayer->tl_fMinSlope;
  585. // get coverage influence
  586. FLOAT fCoverageInfluence=1.0f;
  587. FLOAT fCoverageRandom=GetDistributionNoise( ox, oy, ptlLayer->tl_fCoverageRandom);
  588. fCoverageInfluence=StepDown(fCoverageRandom, ptlLayer->tl_fCoverage, ptlLayer->tl_fCoverage+ptlLayer->tl_fCoverageNoise);
  589. // get min altitude influence
  590. FLOAT fMinAltitudeInfluence=1.0f;
  591. if(ptlLayer->tl_bApplyMinAltitude)
  592. {
  593. FLOAT fMinAltitudeNoise=(GetDistributionNoise( ox, oy, ptlLayer->tl_fMinAltitudeRandom)-0.5f)*ptlLayer->tl_fMinAltitudeNoise;
  594. FLOAT fAltMinFade1=ptlLayer->tl_fMinAltitude+fAltitudeRange*ptlLayer->tl_fMinAltitudeFade;
  595. fMinAltitudeInfluence=StepUp(fAltitudeRatio+fMinAltitudeNoise, ptlLayer->tl_fMinAltitude, fAltMinFade1);
  596. }
  597. // get max altitude influence
  598. FLOAT fMaxAltitudeInfluence=1.0f;
  599. if(ptlLayer->tl_bApplyMaxAltitude)
  600. {
  601. FLOAT fMaxAltitudeNoise=(GetDistributionNoise( ox, oy, ptlLayer->tl_fMaxAltitudeRandom)-0.5f)*ptlLayer->tl_fMaxAltitudeNoise;
  602. FLOAT fAltMaxFade1=ptlLayer->tl_fMaxAltitude-fAltitudeRange*ptlLayer->tl_fMaxAltitudeFade;
  603. fMaxAltitudeInfluence=StepDown(fAltitudeRatio+fMaxAltitudeNoise, fAltMaxFade1, ptlLayer->tl_fMaxAltitude);
  604. }
  605. // get min slope influence
  606. FLOAT fMinSlopeInfluence=1.0f;
  607. if(ptlLayer->tl_bApplyMinSlope)
  608. {
  609. FLOAT fMinSlopeNoise=(GetDistributionNoise( ox, oy, ptlLayer->tl_fMinSlopeRandom)-0.5f)*ptlLayer->tl_fMinSlopeNoise;
  610. FLOAT fSlopeMinFade1=ptlLayer->tl_fMinSlope+fSlopeRange*ptlLayer->tl_fMinSlopeFade;
  611. fMinSlopeInfluence=StepUp(fSlopeRatio+fMinSlopeNoise, ptlLayer->tl_fMinSlope, fSlopeMinFade1);
  612. }
  613. // get max slope influence
  614. FLOAT fMaxSlopeInfluence=1.0f;
  615. if(ptlLayer->tl_bApplyMaxSlope)
  616. {
  617. FLOAT fMaxSlopeNoise=(GetDistributionNoise( ox, oy, ptlLayer->tl_fMaxSlopeRandom)-0.5f)*ptlLayer->tl_fMaxSlopeNoise;
  618. FLOAT fSlopeMaxFade1=ptlLayer->tl_fMaxSlope-fSlopeRange*ptlLayer->tl_fMaxSlopeFade;
  619. fMaxSlopeInfluence=StepDown(fSlopeRatio+fMaxSlopeNoise, fSlopeMaxFade1, ptlLayer->tl_fMaxSlope);
  620. }
  621. // calculate result of all influences
  622. puwMask[iOffset]= 65535.0f*
  623. fCoverageInfluence*
  624. fMinAltitudeInfluence*
  625. fMaxAltitudeInfluence*
  626. fMinSlopeInfluence*
  627. fMaxSlopeInfluence;
  628. }
  629. }
  630. // apply buffer change
  631. SetBufferForEditing(ptrTerrain, puwMask, rect, BT_LAYER_MASK, iLayer);
  632. theApp.GetActiveDocument()->SetModifiedFlag( TRUE);
  633. FreeMemory(puwMask);
  634. }
  635. FreeMemory(puwAltitude);
  636. theApp.m_ctTerrainPageCanvas.MarkChanged();
  637. FreeDistributionNoiseTexture();
  638. }
  639. void GenerateLayerDistribution(INDEX iForLayer)
  640. {
  641. CTerrain *ptrTerrain=GetTerrain();
  642. if( ptrTerrain==NULL) return;
  643. Rect rect;
  644. rect.rc_iLeft=0;
  645. rect.rc_iRight=ptrTerrain->tr_pixHeightMapWidth;
  646. rect.rc_iTop=0;
  647. rect.rc_iBottom=ptrTerrain->tr_pixHeightMapHeight;
  648. GenerateLayerDistribution(iForLayer, rect);
  649. }
  650. void RecalculateShadows(void)
  651. {
  652. CTerrain *ptrTerrain=GetTerrain();
  653. if( ptrTerrain==NULL) return;
  654. ptrTerrain->UpdateShadowMap();
  655. }
  656. void OptimizeLayers(void)
  657. {
  658. CTerrain *ptrTerrain=GetTerrain();
  659. if( ptrTerrain==NULL) return;
  660. Rect rect;
  661. rect.rc_iLeft=0;
  662. rect.rc_iRight=ptrTerrain->tr_pixHeightMapWidth;
  663. rect.rc_iTop=0;
  664. rect.rc_iBottom=ptrTerrain->tr_pixHeightMapHeight;
  665. CStaticArray<UWORD*> apuwLayers;
  666. // obtain buffer
  667. INDEX ctLayers=ptrTerrain->tr_atlLayers.Count();
  668. apuwLayers.New(ctLayers);
  669. INDEX iLayer, iOffset;
  670. for( iLayer=0; iLayer<ctLayers; iLayer++)
  671. {
  672. UWORD *puw=GetBufferForEditing(ptrTerrain, rect, BT_LAYER_MASK, iLayer);
  673. apuwLayers[iLayer]=puw;
  674. }
  675. // count overdraw before optimisation
  676. INDEX ctDrawnBefore=0;
  677. INDEX ctPixels=rect.Width()*rect.Height();
  678. for(iOffset=0; iOffset<ctPixels; iOffset++)
  679. {
  680. for(INDEX i=0; i<ctLayers; i++)
  681. {
  682. UWORD *puwCurr=apuwLayers[i]+iOffset;
  683. if( (*puwCurr)>>8 != 0) ctDrawnBefore++;
  684. }
  685. }
  686. // optimize for overdraw
  687. for(iOffset=0; iOffset<ctPixels; iOffset++)
  688. {
  689. BOOL bOptimize=FALSE;
  690. for(INDEX i=ctLayers-1; i>=0; i--)
  691. {
  692. UWORD *puwCurr=apuwLayers[i]+iOffset;
  693. // if should optimize
  694. if(bOptimize)
  695. {
  696. // clear mask
  697. *puwCurr=0;
  698. }
  699. else
  700. {
  701. if( (*puwCurr)>>8 == 255)
  702. {
  703. // clear mask for all layers beneath current one
  704. bOptimize=TRUE;
  705. }
  706. }
  707. }
  708. }
  709. // count overdraw after optimisation
  710. INDEX ctDrawnAfter=0;
  711. for(iOffset=0; iOffset<ctPixels; iOffset++)
  712. {
  713. for(INDEX i=0; i<ctLayers; i++)
  714. {
  715. UWORD *puwCurr=apuwLayers[i]+iOffset;
  716. if( (*puwCurr)>>8 != 0) ctDrawnAfter++;
  717. }
  718. }
  719. // make a report about optimisation success
  720. CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
  721. CTString strReport;
  722. strReport.PrintF("Overdraw before optimization: %g. Overdraw after optimization: %g",
  723. FLOAT(ctDrawnBefore)/ctPixels, FLOAT(ctDrawnAfter)/ctPixels);
  724. pMainFrame->SetStatusBarMessage( strReport, STATUS_LINE_PANE, 5.0f);
  725. // free buffers
  726. for( iLayer=0; iLayer<ctLayers; iLayer++)
  727. {
  728. SetBufferForEditing(ptrTerrain, apuwLayers[iLayer], rect, BT_LAYER_MASK, iLayer);
  729. FreeMemory(apuwLayers[iLayer]);
  730. }
  731. theApp.GetActiveDocument()->SetModifiedFlag( TRUE);
  732. theApp.m_ctTerrainPageCanvas.MarkChanged();
  733. }
  734. BOOL _bIsUpToDate=TRUE;
  735. Rect _rectDiscarded;
  736. void DiscardLayerDistribution(Rect rect)
  737. {
  738. if(_bIsUpToDate)
  739. {
  740. _rectDiscarded.rc_iLeft=rect.rc_iLeft;
  741. _rectDiscarded.rc_iRight=rect.rc_iRight;
  742. _rectDiscarded.rc_iTop=rect.rc_iTop;
  743. _rectDiscarded.rc_iBottom=rect.rc_iBottom;
  744. }
  745. else
  746. {
  747. if(rect.rc_iLeft < _rectDiscarded.rc_iLeft) _rectDiscarded.rc_iLeft=rect.rc_iLeft;
  748. if(rect.rc_iRight > _rectDiscarded.rc_iRight) _rectDiscarded.rc_iRight=rect.rc_iRight;
  749. if(rect.rc_iTop < _rectDiscarded.rc_iTop) _rectDiscarded.rc_iTop=rect.rc_iTop;
  750. if(rect.rc_iBottom > _rectDiscarded.rc_iBottom) _rectDiscarded.rc_iBottom=rect.rc_iBottom;
  751. }
  752. _bIsUpToDate=FALSE;
  753. }
  754. void UpdateLayerDistribution(void)
  755. {
  756. if(_bIsUpToDate || !theApp.m_Preferences.ap_bAutoUpdateTerrainDistribution) return;
  757. // update layer distribution
  758. GenerateLayerDistribution(-1, _rectDiscarded);
  759. _bIsUpToDate=TRUE;
  760. }
  761. void ApplyFilterOntoTerrain(void)
  762. {
  763. EditTerrain(NULL, FLOAT3D(0,0,0), theApp.m_fFilterPower*16.0f, TE_ALTITUDE_FILTER);
  764. }
  765. void ApplySmoothOntoTerrain(void)
  766. {
  767. EditTerrain(NULL, FLOAT3D(0,0,0), theApp.m_fSmoothPower*16.0f, TE_ALTITUDE_SMOOTH);
  768. }
  769. void ApplyEqualizeOntoTerrain(void)
  770. {
  771. EditTerrain(NULL, FLOAT3D(0,0,0), 1.0f, TE_ALTITUDE_EQUALIZE);
  772. }
  773. void ApplyGenerateTerrain(void)
  774. {
  775. EditTerrain(NULL, FLOAT3D(0,0,0), 1.0f, TE_GENERATE_TERRAIN);
  776. }
  777. void ApplyRndNoiseOntoTerrain(void)
  778. {
  779. EditTerrain(NULL, FLOAT3D(0,0,0), theApp.m_fNoiseAltitude, TE_ALTITUDE_RND_NOISE);
  780. }
  781. void ApplyContinousNoiseOntoTerrain(void)
  782. {
  783. EditTerrain(NULL, FLOAT3D(0,0,0), theApp.m_fNoiseAltitude, TE_ALTITUDE_CONTINOUS_NOISE);
  784. }
  785. void ApplyMinimumOntoTerrain(void)
  786. {
  787. EditTerrain(NULL, FLOAT3D(0,0,0), 1.0f, TE_ALTITUDE_MINIMUM);
  788. }
  789. void ApplyMaximumOntoTerrain(void)
  790. {
  791. EditTerrain(NULL, FLOAT3D(0,0,0), 1.0f, TE_ALTITUDE_MAXIMUM);
  792. }
  793. void ApplyFlattenOntoTerrain(void)
  794. {
  795. EditTerrain(NULL, FLOAT3D(0,0,0), 1.0f, TE_ALTITUDE_FLATTEN);
  796. }
  797. void ApplyPosterizeOntoTerrain(void)
  798. {
  799. EditTerrain(NULL, FLOAT3D(0,0,0), theApp.m_fPosterizeStep, TE_ALTITUDE_POSTERIZE);
  800. }
  801. CEntity *GetEntityForID(ULONG iEntityID)
  802. {
  803. CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
  804. FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
  805. {
  806. if(iten->en_ulID==iEntityID) return &*iten;
  807. }
  808. return NULL;
  809. }
  810. // constructor
  811. CTerrainUndo::CTerrainUndo()
  812. {
  813. tu_puwUndoBuffer=NULL;
  814. tu_puwRedoBuffer=NULL;
  815. }
  816. void DeleteOneUndo(CTerrainUndo *ptrud)
  817. {
  818. if(ptrud->tu_puwUndoBuffer!=NULL) FreeMemory(ptrud->tu_puwUndoBuffer);
  819. if(ptrud->tu_puwRedoBuffer!=NULL) FreeMemory(ptrud->tu_puwRedoBuffer);
  820. delete ptrud;
  821. }
  822. void DeleteTerrainUndo(CWorldEditorDoc* pDoc)
  823. {
  824. for(INDEX iUndo=0; iUndo<pDoc->m_dcTerrainUndo.Count(); iUndo++)
  825. {
  826. CTerrainUndo *ptu=&pDoc->m_dcTerrainUndo[iUndo];
  827. pDoc->m_dcTerrainUndo.Remove(ptu);
  828. DeleteOneUndo(ptu);
  829. }
  830. }
  831. CTerrain *GetUndoTerrain(ULONG ulEntityID)
  832. {
  833. // obtain terrain entity
  834. CEntity *penTerrain=GetEntityForID(_iTerrainEntityID);
  835. if(penTerrain==NULL)
  836. {
  837. return NULL;
  838. }
  839. // obtain terrain
  840. CTerrain *ptrTerrain=penTerrain->GetTerrain();
  841. return ptrTerrain;
  842. }
  843. void ApplyTerrainUndo(CTerrainUndo *ptrud)
  844. {
  845. CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
  846. CTerrain *ptrTerrain=GetUndoTerrain(ptrud->tu_ulEntityID);
  847. if(ptrTerrain==NULL)
  848. {
  849. DeleteOneUndo(ptrud);
  850. return;
  851. }
  852. // obtain and store redo buffer
  853. if(ptrud->tu_puwRedoBuffer==NULL)
  854. {
  855. ptrud->tu_puwRedoBuffer=GetBufferForEditing(ptrTerrain, ptrud->tu_rcRect,
  856. ptrud->tu_btUndoBufferType, ptrud->tu_iUndoBufferData);
  857. }
  858. // apply buffer change (undo)
  859. SetBufferForEditing(ptrTerrain, ptrud->tu_puwUndoBuffer, ptrud->tu_rcRect,
  860. ptrud->tu_btUndoBufferType, ptrud->tu_iUndoBufferData);
  861. pDoc->m_iCurrentTerrainUndo--;
  862. DiscardLayerDistribution(ptrud->tu_rcRect);
  863. pDoc->SetModifiedFlag( TRUE);
  864. theApp.m_ctTerrainPageCanvas.MarkChanged();
  865. }
  866. void ApplyTerrainRedo(CTerrainUndo *ptrud)
  867. {
  868. CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
  869. CTerrain *ptrTerrain=GetUndoTerrain(ptrud->tu_ulEntityID);
  870. if(ptrTerrain==NULL)
  871. {
  872. DeleteOneUndo(ptrud);
  873. return;
  874. }
  875. if(ptrud->tu_puwRedoBuffer==NULL) return;
  876. // apply buffer change (redo)
  877. SetBufferForEditing(ptrTerrain, ptrud->tu_puwRedoBuffer, ptrud->tu_rcRect,
  878. ptrud->tu_btUndoBufferType, ptrud->tu_iUndoBufferData);
  879. pDoc->m_iCurrentTerrainUndo++;
  880. DiscardLayerDistribution(ptrud->tu_rcRect);
  881. pDoc->SetModifiedFlag( TRUE);
  882. theApp.m_ctTerrainPageCanvas.MarkChanged();
  883. }
  884. UWORD *ExtractUndoRect(PIX pixTerrainWidth)
  885. {
  886. INDEX ctBuffBytes=_rectUndo.Width()*_rectUndo.Height()*sizeof(UWORD);
  887. UWORD *puwBuff=(UWORD*)AllocMemory(ctBuffBytes);
  888. if(puwBuff==NULL) return NULL;
  889. UWORD *puwBuffTemp=puwBuff;
  890. for(INDEX y=_rectUndo.rc_iTop; y<_rectUndo.rc_iBottom; y++)
  891. {
  892. for(INDEX x=_rectUndo.rc_iLeft; x<_rectUndo.rc_iRight; x++)
  893. {
  894. INDEX iOffset=y*pixTerrainWidth+x;
  895. UWORD uwValue=_puwUndoTerrain[iOffset];
  896. *puwBuffTemp=uwValue;
  897. puwBuffTemp++;
  898. }
  899. }
  900. return puwBuff;
  901. }
  902. void TerrainEditBegin(void)
  903. {
  904. if( !(theApp.m_Preferences.ap_iMemoryForTerrainUndo>0))
  905. {
  906. return;
  907. }
  908. _bUndoStart=TRUE;
  909. }
  910. void RemoveRedoList(void)
  911. {
  912. CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
  913. CDynamicContainer<CTerrainUndo> dcTemp;
  914. for( INDEX itu=0; itu<pDoc->m_iCurrentTerrainUndo+1; itu++)
  915. {
  916. dcTemp.Add(&pDoc->m_dcTerrainUndo[itu]);
  917. }
  918. for( INDEX ituDel=pDoc->m_iCurrentTerrainUndo+1; ituDel<pDoc->m_dcTerrainUndo.Count(); ituDel++)
  919. {
  920. DeleteOneUndo(&pDoc->m_dcTerrainUndo[ituDel]);
  921. }
  922. pDoc->m_dcTerrainUndo.MoveContainer(dcTemp);
  923. }
  924. void LimitMemoryConsumption(INDEX iNewConsumption)
  925. {
  926. CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
  927. INDEX ctUndos=pDoc->m_dcTerrainUndo.Count();
  928. INDEX iLastValid=-1;
  929. INDEX iSum=iNewConsumption;
  930. for(INDEX iUndo=ctUndos-1; iUndo>=0; iUndo--)
  931. {
  932. CTerrainUndo *ptu=&pDoc->m_dcTerrainUndo[iUndo];
  933. INDEX iMemory=ptu->tu_rcRect.Width()*ptu->tu_rcRect.Height()*sizeof(UWORD);
  934. if(ptu->tu_puwRedoBuffer!=NULL)
  935. {
  936. iSum=iSum+iMemory*2;
  937. }
  938. else
  939. {
  940. iSum=iSum+iMemory;
  941. }
  942. if(iSum>theApp.m_Preferences.ap_iMemoryForTerrainUndo*1024*1024)
  943. {
  944. iLastValid=iUndo+1;
  945. break;
  946. }
  947. }
  948. if( iLastValid!=-1)
  949. {
  950. CDynamicContainer<CTerrainUndo> dcTemp;
  951. for( INDEX itu=iLastValid; itu<ctUndos; itu++)
  952. {
  953. dcTemp.Add(&pDoc->m_dcTerrainUndo[itu]);
  954. }
  955. for( INDEX ituDel=0; ituDel<iLastValid; ituDel++)
  956. {
  957. DeleteOneUndo(&pDoc->m_dcTerrainUndo[ituDel]);
  958. }
  959. pDoc->m_dcTerrainUndo.MoveContainer(dcTemp);
  960. if(pDoc->m_iCurrentTerrainUndo>=iLastValid)
  961. {
  962. pDoc->m_iCurrentTerrainUndo=pDoc->m_iCurrentTerrainUndo-iLastValid;
  963. }
  964. }
  965. }
  966. void TerrainEditEnd(void)
  967. {
  968. if( !(theApp.m_Preferences.ap_iMemoryForTerrainUndo>0))
  969. {
  970. return;
  971. }
  972. CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
  973. // obtain terrain entity
  974. CEntity *penTerrain=GetEntityForID(_iTerrainEntityID);
  975. if(penTerrain==NULL)
  976. {
  977. if(_puwUndoTerrain!=NULL)
  978. {
  979. FreeMemory(_puwUndoTerrain);
  980. _puwUndoTerrain=NULL;
  981. }
  982. return;
  983. }
  984. // obtain terrain
  985. CTerrain *ptrTerrain=penTerrain->GetTerrain();
  986. if(ptrTerrain==NULL)
  987. {
  988. if(_puwUndoTerrain!=NULL)
  989. {
  990. FreeMemory(_puwUndoTerrain);
  991. _puwUndoTerrain=NULL;
  992. }
  993. return;
  994. }
  995. // we will add undo, clear all existing redo's
  996. RemoveRedoList();
  997. // remember undo
  998. CTerrainUndo *ptrud=new CTerrainUndo;
  999. INDEX iNewConsumption=_rectUndo.Width()*_rectUndo.Height()*sizeof(UWORD);
  1000. LimitMemoryConsumption(iNewConsumption);
  1001. ptrud->tu_ulEntityID=_iTerrainEntityID;
  1002. ptrud->tu_rcRect=_rectUndo;
  1003. ptrud->tu_btUndoBufferType=_btUndoBufferType;
  1004. ptrud->tu_iUndoBufferData=_iUndoBufferData;
  1005. ptrud->tu_puwUndoBuffer=ExtractUndoRect(ptrTerrain->tr_pixHeightMapWidth);
  1006. if(ptrud->tu_puwUndoBuffer!=NULL)
  1007. {
  1008. pDoc->m_dcTerrainUndo.Add(ptrud);
  1009. }
  1010. else
  1011. {
  1012. delete ptrud;
  1013. }
  1014. pDoc->m_iCurrentTerrainUndo=pDoc->m_dcTerrainUndo.Count()-1;
  1015. // release obtained terrain buffer
  1016. if(_puwUndoTerrain!=NULL)
  1017. {
  1018. FreeMemory(_puwUndoTerrain);
  1019. _puwUndoTerrain=NULL;
  1020. }
  1021. }
  1022. CTileInfo::CTileInfo()
  1023. {
  1024. ti_ix=-1;
  1025. ti_iy=-1;
  1026. ti_bSwapXY=FALSE;
  1027. ti_bFlipX=FALSE;
  1028. ti_bFlipY=FALSE;
  1029. }
  1030. void ObtainLayerTileInfo(CDynamicContainer<CTileInfo> *pdcTileInfo, CTextureData *ptdTexture, INDEX &ctTilesPerRow)
  1031. {
  1032. CTFileName fnTexture=ptdTexture->GetName();
  1033. CTFileName fnTileInfo=fnTexture.NoExt()+CTString(".tli");
  1034. INDEX ctParsedLines=0;
  1035. try
  1036. {
  1037. char achrLine[ 256];
  1038. CTFileStream strm;
  1039. strm.Open_t( fnTileInfo);
  1040. FOREVER
  1041. {
  1042. CDynamicContainer<CTString> dcTokens;
  1043. strm.GetLine_t(achrLine, 256);
  1044. ctParsedLines++;
  1045. char achrSeparators[] = " ,";
  1046. char *pchrToken = strtok( achrLine, achrSeparators);
  1047. while( pchrToken != NULL )
  1048. {
  1049. CTString *pstrToken=new CTString();
  1050. *pstrToken=CTString( pchrToken);
  1051. dcTokens.Add(pstrToken);
  1052. // next token
  1053. pchrToken = strtok( NULL, achrSeparators);
  1054. }
  1055. // if no tokens parsed
  1056. if(dcTokens.Count()==0) continue;
  1057. INDEX iToken=0;
  1058. // analyze parsed tokens
  1059. if(dcTokens[iToken]=="TilesPerRow")
  1060. {
  1061. // there must be at least 1 token for 'TilesPerRow' indentifier
  1062. if(dcTokens.Count()-1-iToken<1)
  1063. {
  1064. throw("You must enter number of tiles per raw.");
  1065. }
  1066. ctTilesPerRow=0;
  1067. INDEX iResultTPR=sscanf(dcTokens[iToken+1], "%d", &ctTilesPerRow);
  1068. if(iResultTPR<=0)
  1069. {
  1070. ctTilesPerRow=0;
  1071. throw("Unable to parse count of tiles per row.");
  1072. }
  1073. }
  1074. else if(dcTokens[iToken]=="Tile")
  1075. {
  1076. // there must be at least 2 tokens for 'Tile' indentifier
  1077. if(dcTokens.Count()-1-iToken<2)
  1078. {
  1079. throw("You must enter 2 coordinates per tile.");
  1080. }
  1081. INDEX x,y;
  1082. INDEX iResultX=sscanf(dcTokens[iToken+1], "%d", &x);
  1083. if(iResultX<=0)
  1084. {
  1085. throw("Unable to parse x coordinate.");
  1086. }
  1087. INDEX iResultY=sscanf(dcTokens[iToken+2], "%d", &y);
  1088. if(iResultY<=0)
  1089. {
  1090. throw("Unable to parse y coordinate.");
  1091. }
  1092. if(x<=0 || y<=0)
  1093. {
  1094. throw("Tile coordinates must be greater than 0.");
  1095. }
  1096. // jump over coordinate tokens
  1097. iToken+=3;
  1098. // add tile info
  1099. CTileInfo *pti=new CTileInfo();
  1100. pti->ti_ix=x-1;
  1101. pti->ti_iy=y-1;
  1102. for( INDEX iFlagToken=iToken; iFlagToken<dcTokens.Count(); iFlagToken++)
  1103. {
  1104. if(dcTokens[iFlagToken]=="SwapXY")
  1105. {
  1106. pti->ti_bSwapXY=TRUE;
  1107. }
  1108. else if(dcTokens[iFlagToken]=="FlipX")
  1109. {
  1110. pti->ti_bFlipX=TRUE;
  1111. }
  1112. else if(dcTokens[iFlagToken]==";")
  1113. {
  1114. break;
  1115. }
  1116. else if(dcTokens[iFlagToken]=="FlipY")
  1117. {
  1118. pti->ti_bFlipY=TRUE;
  1119. }
  1120. else
  1121. {
  1122. throw("Unrecognizable character found.");
  1123. }
  1124. }
  1125. pdcTileInfo->Add(pti);
  1126. }
  1127. // clear allocated tokens
  1128. for(INDEX i=0; i<dcTokens.Count(); i++)
  1129. {
  1130. delete &dcTokens[i];
  1131. }
  1132. dcTokens.Clear();
  1133. }
  1134. }
  1135. catch(char *strError)
  1136. {
  1137. (void) strError;
  1138. }
  1139. }
  1140. void TilePaintTool(void)
  1141. {
  1142. CTerrain *ptrTerrain=GetTerrain();
  1143. CTerrainLayer *ptlLayer=GetLayer();
  1144. if(ptrTerrain==NULL || ptlLayer==NULL || ptlLayer->tl_ltType!=LT_TILE || ptlLayer->tl_ptdTexture==NULL) return;
  1145. CDynamicContainer<CTileInfo> dcTileInfo;
  1146. INDEX ctTilesPerRaw=0;
  1147. ObtainLayerTileInfo( &dcTileInfo, ptlLayer->tl_ptdTexture, ctTilesPerRaw);
  1148. INDEX ctTiles=dcTileInfo.Count();
  1149. if(ctTilesPerRaw==0 || ctTiles==0) return;
  1150. ptlLayer->SetTilesPerRow(ctTilesPerRaw);
  1151. ptlLayer->tl_iSelectedTile= Clamp( ptlLayer->tl_iSelectedTile, (INDEX)0, INDEX(ctTiles-1) );
  1152. if(ptlLayer->tl_iSelectedTile==-1) return;
  1153. CTileInfo &ti=dcTileInfo[ptlLayer->tl_iSelectedTile];
  1154. // _rect holds terrain size
  1155. if(_fStrength>0)
  1156. {
  1157. UWORD uwValue=
  1158. dcTileInfo[ptlLayer->tl_iSelectedTile].ti_iy*ctTilesPerRaw+
  1159. dcTileInfo[ptlLayer->tl_iSelectedTile].ti_ix;
  1160. if(ti.ti_bFlipX) uwValue|=TL_FLIPX;
  1161. if(ti.ti_bFlipY) uwValue|=TL_FLIPY;
  1162. if(ti.ti_bSwapXY) uwValue|=TL_SWAPXY;
  1163. uwValue|=TL_VISIBLE;
  1164. _puwBuffer[0]=uwValue<<8;
  1165. }
  1166. else
  1167. {
  1168. _puwBuffer[0]=0;
  1169. }
  1170. /*
  1171. vidjeti sta ne radi sa brisanjem tile-ova
  1172. ne pogadja se dobro lokacija tile-a ispod misa
  1173. +view layer on/off ne discarda pretender texture
  1174. +ne crta se dobro trenutno selektirani tile i preklapa se animirani (under mouse)
  1175. +rotirane i flipane tileove crtati
  1176. +nesto zapinje kad se prvi put otvara info window
  1177. +ubaciti skrolanje tileova na mouse wheel
  1178. +pick tile
  1179. */
  1180. // free allocated tile info structures
  1181. for(INDEX i=0; i<dcTileInfo.Count(); i++)
  1182. {
  1183. delete &dcTileInfo[i];
  1184. }
  1185. dcTileInfo.Clear();
  1186. }
  1187. void EditTerrain(CTextureData *ptdBrush, FLOAT3D &vHitPoint, FLOAT fStrength, ETerrainEdit teTool)
  1188. {
  1189. _ptdBrush=ptdBrush;
  1190. _fStrength=fStrength;
  1191. CTerrain *ptrTerrain=GetTerrain();
  1192. CTerrainLayer *ptlLayer=GetLayer();
  1193. INDEX iLayer=GetLayerIndex();
  1194. if(ptrTerrain==NULL || ptlLayer==NULL) return;
  1195. // obtain buffer type
  1196. BufferType btBufferType=BT_INVALID;
  1197. INDEX iBufferData=-1;
  1198. if( (teTool>TE_BRUSH_ALTITUDE_START && teTool<TE_BRUSH_ALTITUDE_END) ||
  1199. (teTool>TE_ALTITUDE_START && teTool<TE_ALTITUDE_END) ||
  1200. (teTool==TE_GENERATE_TERRAIN) ||
  1201. (teTool==TE_ALTITUDE_EQUALIZE) )
  1202. {
  1203. btBufferType=BT_HEIGHT_MAP;
  1204. }
  1205. else if( (teTool>TE_BRUSH_LAYER_START && teTool<TE_BRUSH_LAYER_END) ||
  1206. (teTool>TE_LAYER_START && teTool<TE_LAYER_END) ||
  1207. teTool==TE_TILE_PAINT)
  1208. {
  1209. btBufferType=BT_LAYER_MASK;
  1210. iBufferData=iLayer;
  1211. }
  1212. else if( teTool>TE_BRUSH_EDGE_START && teTool<TE_BRUSH_EDGE_END)
  1213. {
  1214. btBufferType=BT_EDGE_MAP;
  1215. }
  1216. else
  1217. {
  1218. return;
  1219. }
  1220. _puwBuffer=NULL;
  1221. _srcExtraW=0;
  1222. _srcExtraH=0;
  1223. if( teTool==TE_BRUSH_ALTITUDE_SMOOTH ||
  1224. teTool==TE_BRUSH_ALTITUDE_FILTER ||
  1225. teTool==TE_BRUSH_LAYER_SMOOTH ||
  1226. teTool==TE_ALTITUDE_SMOOTH ||
  1227. teTool==TE_ALTITUDE_FILTER ||
  1228. teTool==TE_LAYER_SMOOTH ||
  1229. teTool==TE_LAYER_FILTER)
  1230. {
  1231. _srcExtraW=2;
  1232. _srcExtraH=2;
  1233. }
  1234. // extract source rectangle
  1235. Point pt=Calculate2dHitPoint(ptrTerrain, vHitPoint);
  1236. // perform operation on brush rect
  1237. if(teTool==TE_TILE_PAINT)
  1238. {
  1239. _rect.rc_iLeft=pt.pt_iX;
  1240. _rect.rc_iRight=_rect.rc_iLeft+1;
  1241. _rect.rc_iTop=pt.pt_iY;
  1242. _rect.rc_iBottom=_rect.rc_iTop+1;
  1243. }
  1244. else if(_ptdBrush!=NULL)
  1245. {
  1246. _rect.rc_iLeft=pt.pt_iX-ptdBrush->GetPixWidth()/2-_srcExtraW;
  1247. _rect.rc_iRight=pt.pt_iX+(ptdBrush->GetPixWidth()-ptdBrush->GetPixWidth()/2)+_srcExtraW;
  1248. _rect.rc_iTop=pt.pt_iY-ptdBrush->GetPixHeight()/2-_srcExtraH;
  1249. _rect.rc_iBottom=pt.pt_iY+(ptdBrush->GetPixHeight()-ptdBrush->GetPixHeight()/2)+_srcExtraH;
  1250. }
  1251. // perform operation on whole terrain area
  1252. else
  1253. {
  1254. _rect.rc_iLeft=0;
  1255. _rect.rc_iRight=ptrTerrain->tr_pixHeightMapWidth;
  1256. _rect.rc_iTop=0;
  1257. _rect.rc_iBottom=ptrTerrain->tr_pixHeightMapHeight;
  1258. }
  1259. Rect rectTerrain;
  1260. rectTerrain.rc_iLeft=0;
  1261. rectTerrain.rc_iTop=0;
  1262. rectTerrain.rc_iRight=ptrTerrain->tr_pixHeightMapWidth;
  1263. rectTerrain.rc_iBottom=ptrTerrain->tr_pixHeightMapHeight;
  1264. BOOL bAutoRememberUndo=FALSE;
  1265. // if should apply undo for whole terrain
  1266. if( (teTool>TE_ALTITUDE_START && teTool<TE_ALTITUDE_END) ||
  1267. (teTool>TE_LAYER_START && teTool<TE_LAYER_END) ||
  1268. (teTool==TE_GENERATE_TERRAIN) ||
  1269. (teTool==TE_ALTITUDE_EQUALIZE) )
  1270. {
  1271. TerrainEditBegin();
  1272. bAutoRememberUndo=TRUE;
  1273. }
  1274. // edit start, undo starts
  1275. if(_bUndoStart)
  1276. {
  1277. _bUndoStart=FALSE;
  1278. _btUndoBufferType=btBufferType;
  1279. _iUndoBufferData=iBufferData;
  1280. _rectUndo=_rect;
  1281. _iTerrainEntityID=ptrTerrain->tr_penEntity->en_ulID;
  1282. _puwUndoTerrain=GetBufferForEditing(ptrTerrain, rectTerrain, btBufferType, iBufferData);
  1283. }
  1284. // editing in progress, update undo data
  1285. else
  1286. {
  1287. // update undo rect
  1288. if(_rect.rc_iLeft < _rectUndo.rc_iLeft) _rectUndo.rc_iLeft=_rect.rc_iLeft;
  1289. if(_rect.rc_iRight > _rectUndo.rc_iRight) _rectUndo.rc_iRight=_rect.rc_iRight;
  1290. if(_rect.rc_iTop < _rectUndo.rc_iTop) _rectUndo.rc_iTop=_rect.rc_iTop;
  1291. if(_rect.rc_iBottom > _rectUndo.rc_iBottom) _rectUndo.rc_iBottom=_rect.rc_iBottom;
  1292. }
  1293. // clamp undo rect to terrain size
  1294. _rectUndo.rc_iLeft=Clamp(_rectUndo.rc_iLeft, rectTerrain.rc_iLeft, rectTerrain.rc_iRight);
  1295. _rectUndo.rc_iRight=Clamp(_rectUndo.rc_iRight, rectTerrain.rc_iLeft, rectTerrain.rc_iRight);
  1296. _rectUndo.rc_iTop=Clamp(_rectUndo.rc_iTop, rectTerrain.rc_iTop, rectTerrain.rc_iBottom);
  1297. _rectUndo.rc_iBottom=Clamp(_rectUndo.rc_iBottom, rectTerrain.rc_iTop, rectTerrain.rc_iBottom);
  1298. // obtain buffer
  1299. _puwBuffer=GetBufferForEditing(ptrTerrain, _rect, btBufferType, iBufferData);
  1300. switch( teTool)
  1301. {
  1302. case TE_BRUSH_ALTITUDE_PAINT:
  1303. {
  1304. ApplyAddPaint(MIN_UWORD,MAX_UWORD);
  1305. break;
  1306. }
  1307. case TE_BRUSH_EDGE_ERASE:
  1308. {
  1309. _fStrength=-fStrength;
  1310. ApplyAddPaint(MIN_UWORD,MAX_UWORD);
  1311. break;
  1312. }
  1313. case TE_BRUSH_LAYER_PAINT:
  1314. {
  1315. _fStrength=fStrength*32.0f;
  1316. ApplyAddPaint(MIN_UWORD,MAX_UWORD);
  1317. break;
  1318. }
  1319. case TE_BRUSH_ALTITUDE_SMOOTH:
  1320. case TE_BRUSH_LAYER_SMOOTH:
  1321. case TE_ALTITUDE_SMOOTH:
  1322. case TE_LAYER_SMOOTH:
  1323. {
  1324. _fStrength=fStrength*theApp.m_fSmoothPower;
  1325. ApplyFilterMatrix(_afFilterBlurMore);
  1326. break;
  1327. }
  1328. case TE_BRUSH_ALTITUDE_FILTER:
  1329. case TE_BRUSH_LAYER_FILTER:
  1330. case TE_LAYER_FILTER:
  1331. case TE_ALTITUDE_FILTER:
  1332. {
  1333. _fStrength=fStrength*theApp.m_fFilterPower;
  1334. switch(theApp.m_iFilter)
  1335. {
  1336. case FLT_FINEBLUR: ApplyFilterMatrix(_afFilterFineBlur ); break;
  1337. case FLT_SHARPEN: ApplyFilterMatrix(_afFilterSharpen ); break;
  1338. case FLT_EMBOSS: ApplyFilterMatrix(_afFilterEmboss ); break;
  1339. case FLT_EDGEDETECT: ApplyFilterMatrix(_afFilterEdgeDetect ); break;
  1340. }
  1341. break;
  1342. }
  1343. case TE_BRUSH_ALTITUDE_MINIMUM:
  1344. case TE_ALTITUDE_MINIMUM:
  1345. {
  1346. _fStrength=0;
  1347. ApplyAddPaint(theApp.m_uwEditAltitude,MAX_UWORD);
  1348. break;
  1349. }
  1350. case TE_BRUSH_ALTITUDE_MAXIMUM:
  1351. case TE_ALTITUDE_MAXIMUM:
  1352. {
  1353. _fStrength=0;
  1354. ApplyAddPaint(MIN_UWORD, theApp.m_uwEditAltitude);
  1355. break;
  1356. }
  1357. case TE_BRUSH_ALTITUDE_FLATTEN:
  1358. case TE_ALTITUDE_FLATTEN:
  1359. {
  1360. _fStrength=0;
  1361. ApplyAddPaint(theApp.m_uwEditAltitude, theApp.m_uwEditAltitude);
  1362. break;
  1363. }
  1364. case TE_BRUSH_ALTITUDE_POSTERIZE:
  1365. case TE_ALTITUDE_POSTERIZE:
  1366. {
  1367. ApplyPosterize();
  1368. break;
  1369. }
  1370. case TE_BRUSH_ALTITUDE_RND_NOISE:
  1371. case TE_BRUSH_LAYER_RND_NOISE:
  1372. case TE_ALTITUDE_RND_NOISE:
  1373. case TE_LAYER_RND_NOISE:
  1374. {
  1375. ApplyRNDNoise();
  1376. break;
  1377. }
  1378. case TE_BRUSH_ALTITUDE_CONTINOUS_NOISE:
  1379. case TE_BRUSH_LAYER_CONTINOUS_NOISE:
  1380. case TE_ALTITUDE_CONTINOUS_NOISE:
  1381. case TE_LAYER_CONTINOUS_NOISE:
  1382. {
  1383. if(!SetupContinousNoiseTexture()) return;
  1384. ApplyContinousNoise();
  1385. FreeContinousNoiseTexture();
  1386. break;
  1387. }
  1388. case TE_GENERATE_TERRAIN:
  1389. {
  1390. GenerateTerrain();
  1391. break;
  1392. }
  1393. case TE_ALTITUDE_EQUALIZE:
  1394. {
  1395. EqualizeBuffer();
  1396. break;
  1397. }
  1398. case TE_CLEAR_LAYER_MASK:
  1399. {
  1400. for(INDEX i=0; i<_rect.Width()*_rect.Height(); i++)
  1401. {
  1402. _puwBuffer[i]=0;
  1403. }
  1404. break;
  1405. }
  1406. case TE_FILL_LAYER_MASK:
  1407. {
  1408. for(INDEX i=0; i<_rect.Width()*_rect.Height(); i++)
  1409. {
  1410. _puwBuffer[i]=MAX_UWORD;
  1411. }
  1412. break;
  1413. }
  1414. case TE_TILE_PAINT:
  1415. {
  1416. TilePaintTool();
  1417. break;
  1418. }
  1419. }
  1420. // apply buffer change
  1421. SetBufferForEditing(ptrTerrain, _puwBuffer, _rect, btBufferType, iBufferData);
  1422. theApp.GetActiveDocument()->SetModifiedFlag( TRUE);
  1423. FreeMemory(_puwBuffer);
  1424. // mark rect for layer distribution updating
  1425. if(teTool!=TE_TILE_PAINT)
  1426. {
  1427. DiscardLayerDistribution(_rect);
  1428. }
  1429. theApp.m_ctTerrainPageCanvas.MarkChanged();
  1430. if(bAutoRememberUndo)
  1431. {
  1432. TerrainEditEnd();
  1433. }
  1434. }