123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596 |
- /* Copyright (c) 2002-2012 Croteam Ltd.
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as published by
- the Free Software Foundation
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
- #include "StdAfx.h"
- #include <Engine/Templates/Stock_CTextureData.h>
-
- // global variables used in terrain editing functions
- UWORD *_puwBuffer=NULL;
- Rect _rect;
- PIX _srcExtraW=0;
- PIX _srcExtraH=0;
- CTextureData *_ptdBrush=NULL;
- CTextureData *_ptdDistributionRandomNoise=NULL;
- CTextureData *_ptdContinousRandomNoise=NULL;
- UWORD *_puwNoiseTarget=NULL;
- PIX _pixNoiseTargetW=0;
- PIX _pixNoiseTargetH=0;
- FLOAT _fStrength=0.0f;
- // fbm noise buffer
- FLOAT *_pafWhiteNoise=NULL;
- #define WNOISE 64
- // undo variables
- UWORD *_puwUndoTerrain=NULL;
- Rect _rectUndo;
- BOOL _bUndoStart=FALSE;
- BufferType _btUndoBufferType=BT_INVALID;
- INDEX _iUndoBufferData=-1;
- INDEX _iTerrainEntityID=-1;
- // filter matrices
- FLOAT _afFilterFineBlur[5][5]=
- {
- {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, 0.0625f, 0.0625f, 0.0625f, 0.0f},
- {0.0f, 0.0625f, 0.5f, 0.0625f, 0.0f},
- {0.0f, 0.0625f, 0.0625f, 0.0625f, 0.0f},
- {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
- };
- FLOAT _afFilterBlurMore[5][5]=
- {
- {0.0277777f, 0.0277777f, 0.0277777f, 0.0277777f, 0.0277777f},
- {0.0277777f, 0.0555555f, 0.0555555f, 0.0555555f, 0.0277777f},
- {0.0277777f, 0.0555555f, 0.0111111f, 0.0555555f, 0.0277777f},
- {0.0277777f, 0.0555555f, 0.0555555f, 0.0555555f, 0.0277777f},
- {0.0277777f, 0.0277777f, 0.0277777f, 0.0277777f, 0.0277777f},
- };
- FLOAT _afFilterEdgeDetect[5][5]=
- {
- {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, 1.0f, 1.0f, 1.0f, 0.0f},
- {0.0f, 1.0f, -7.0f, 1.0f, 0.0f},
- {0.0f, 1.0f, 1.0f, 1.0f, 0.0f},
- {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
- };
- FLOAT _afFilterEmboss[5][5]=
- {
- {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, 1.0f, 1.0f, -1.0f, 0.0f},
- {0.0f, 1.0f, 1.0f, -1.0f, 0.0f},
- {0.0f, 1.0f, -1.0f, -1.0f, 0.0f},
- {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
- };
- FLOAT _afFilterSharpen[5][5]=
- {
- {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
- {0.0f, -1.0f, -1.0f, -1.0f, 0.0f},
- {0.0f, -1.0f, 16.0f, -1.0f, 0.0f},
- {0.0f, -1.0f, -1.0f, -1.0f, 0.0f},
- {0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
- };
- FLOAT GetBrushMultiplier(INDEX x, INDEX y)
- {
- if(_ptdBrush==NULL) return 1.0f;
- {
- COLOR col=_ptdBrush->GetTexel(x,y);
- FLOAT fResult=FLOAT(col>>24)/255.0f;
- return fResult;
- }
- }
- void ApplyAddPaint(UWORD uwMin, UWORD uwMax)
- {
- for(INDEX y=0; y<_rect.Height(); y++)
- {
- for(INDEX x=0; x<_rect.Width(); x++)
- {
- FLOAT fBrushMultiplier=GetBrushMultiplier(x,y);
- if( fBrushMultiplier==0.0f) continue;
- INDEX iOffset=y*_rect.Width()+x;
- FLOAT fValue=_puwBuffer[iOffset];
- fValue+=fBrushMultiplier*_fStrength*32.0f*theApp.m_fPaintPower;
- fValue=Clamp(fValue,FLOAT(uwMin),FLOAT(uwMax));
- _puwBuffer[iOffset]=fValue;
- }
- }
- }
- void ApplyRNDNoise(void)
- {
- CTerrain *ptrTerrain=GetTerrain();
- if( ptrTerrain==NULL) return;
- FLOAT fMaxNoise=theApp.m_fNoiseAltitude/ptrTerrain->tr_vTerrainSize(2)*65535.0f;
- for(INDEX y=0; y<_rect.Height(); y++)
- {
- for(INDEX x=0; x<_rect.Width(); x++)
- {
- FLOAT fBrushMultiplier=GetBrushMultiplier(x,y);
- INDEX iPixSrc=y*_rect.Width()+x;
- FLOAT fInfluence=_puwBuffer[iPixSrc];
- FLOAT fRnd=FLOAT(rand())/RAND_MAX-0.5f;
- FLOAT fValue=_puwBuffer[iPixSrc];
- FLOAT fMaxRandomized=fValue+fRnd*fMaxNoise;
- FLOAT fFilterPower=Clamp(fBrushMultiplier*_fStrength,0.0f,1.0f);
- FLOAT fResult=Lerp( fValue, fMaxRandomized, fFilterPower);
- UWORD uwResult=Clamp(UWORD(fResult),MIN_UWORD,MAX_UWORD);
- _puwBuffer[iPixSrc]=uwResult;
- }
- }
- }
- FLOAT GetDistributionNoise( INDEX x, INDEX y, FLOAT fRandom)
- {
- INDEX iw=_ptdDistributionRandomNoise->GetPixWidth();
- INDEX ih=_ptdDistributionRandomNoise->GetPixHeight();
- INDEX ctSize=iw*ih;
- INDEX iOffset=abs(INDEX(iw*y+x+fRandom*ctSize)%ctSize);
- COLOR col=_ptdDistributionRandomNoise->td_pulFrames[iOffset];
- FLOAT fResult=FLOAT(col&0xFF)/255.0f;
- return fResult;
- }
- FLOAT GetContinousNoise( INDEX x, INDEX y, FLOAT fRandom)
- {
- INDEX iw=_ptdContinousRandomNoise->GetPixWidth();
- INDEX ih=_ptdContinousRandomNoise->GetPixHeight();
- INDEX ctSize=iw*ih;
- INDEX iOffset=abs(INDEX(iw*y+x+fRandom*ctSize)%ctSize);
- COLOR col=_ptdContinousRandomNoise->td_pulFrames[iOffset];
- FLOAT fResult=FLOAT(col&0xFF)/255.0f;
- return fResult;
- }
- void ApplyContinousNoise(void)
- {
- CTerrain *ptrTerrain=GetTerrain();
- if( ptrTerrain==NULL) return;
- FLOAT fMaxNoise=theApp.m_fNoiseAltitude/ptrTerrain->tr_vTerrainSize(2)*65535.0f;
- for(INDEX y=0; y<_rect.Height(); y++)
- {
- INDEX oy=y+_rect.rc_iTop;
- for(INDEX x=0; x<_rect.Width(); x++)
- {
- INDEX ox=x+_rect.rc_iLeft;
- FLOAT fBrushMultiplier=GetBrushMultiplier(x,y);
- INDEX iPixSrc=y*_rect.Width()+x;
- FLOAT fInfluence=_puwBuffer[iPixSrc];
- FLOAT fRnd=GetContinousNoise( ox, oy, 0.0f)-0.5f;
- FLOAT fValue=_puwBuffer[iPixSrc];
- FLOAT fMaxRandomized=fValue+fRnd*fMaxNoise;
- fMaxRandomized=Clamp(fMaxRandomized,(FLOAT)MIN_UWORD,(FLOAT)MAX_UWORD);
- FLOAT fFilterPower=Clamp(fBrushMultiplier*_fStrength,0.0f,1.0f);
- FLOAT fResult=Lerp( fValue, fMaxRandomized, fFilterPower);
- UWORD uwResult=Clamp((UWORD)fResult,MIN_UWORD,MAX_UWORD);
- _puwBuffer[iPixSrc]=uwResult;
- }
- }
- }
- void ApplyPosterize(void)
- {
- CTerrain *ptrTerrain=GetTerrain();
- if( ptrTerrain==NULL) return;
- FLOAT fStepUW=theApp.m_fPosterizeStep/ptrTerrain->tr_vTerrainSize(2)*65535.0f;
- for(INDEX y=0; y<_rect.Height(); y++)
- {
- for(INDEX x=0; x<_rect.Width(); x++)
- {
- FLOAT fBrushMultiplier=GetBrushMultiplier(x,y);
- if(fBrushMultiplier==0.0f) continue;
- INDEX iPixSrc=y*_rect.Width()+x;
- FLOAT fValue=_puwBuffer[iPixSrc];
- FLOAT fPosterized=(INDEX(fValue/fStepUW))*fStepUW+1.0f;
- UWORD uwResult=Clamp(UWORD(fPosterized),MIN_UWORD,MAX_UWORD);
- _puwBuffer[iPixSrc]=uwResult;
- }
- }
- }
- void ApplyFilterMatrix(FLOAT afFilterMatrix[5][5])
- {
- INDEX ctBuffBytes=_rect.Width()*_rect.Height()*sizeof(UWORD);
- UWORD *puwDst=(UWORD*)AllocMemory(ctBuffBytes);
- memcpy(puwDst,_puwBuffer,ctBuffBytes);
- for(INDEX y=0; y<_rect.Height()-_srcExtraH*2; y++)
- {
- for(INDEX x=0; x<_rect.Width()-_srcExtraW*2; x++)
- {
- INDEX iPixDst=(y+_srcExtraH)*_rect.Width()+x+_srcExtraW;
- FLOAT fBrushMultiplier=GetBrushMultiplier(x,y);
- FLOAT fDivSum=0.0f;
- FLOAT fSum=0.0f;
- for(INDEX j=0; j<5; j++)
- {
- for(INDEX i=0; i<5; i++)
- {
- FLOAT fWeight=(afFilterMatrix)[i][j];
- fDivSum+=fWeight;
- INDEX iPixSrc=(y+j)*_rect.Width()+(x+i);
- FLOAT fInfluence=_puwBuffer[iPixSrc];
- fSum+=fInfluence*fWeight;
- }
- }
- UWORD uwMax=Clamp(UWORD(fSum/fDivSum),MIN_UWORD,MAX_UWORD);
- FLOAT fFilterPower=Clamp(fBrushMultiplier*_fStrength/64.0f,0.0f,1.0f);
- UWORD uwResult=Lerp( puwDst[iPixDst], uwMax, fFilterPower);
- puwDst[iPixDst]=uwResult;
- }
- }
- memcpy(_puwBuffer,puwDst,ctBuffBytes);
- FreeMemory( puwDst);
- }
- static INDEX _iTerrainWidth=0;
- static UWORD *_puwHeightMap=NULL;
- static INDEX _iRandomDX=0;
- void SetHMPixel( UWORD pix, INDEX x, INDEX y)
- {
- UWORD *pdest=_puwHeightMap+y*_iTerrainWidth+x;
- if (*pdest==65535) {
- *pdest=pix;
- }
- }
- UWORD GetHMPixel(INDEX x, INDEX y)
- {
- UWORD *pdest=_puwHeightMap+y*_iTerrainWidth+x;
- return *pdest;
- }
- UWORD RandomizePixel(FLOAT fmid, FLOAT fdmax)
- {
- FLOAT fRand=((FLOAT)rand())/RAND_MAX-0.5f;
- FLOAT fd=fdmax*fRand;
- FLOAT fres=Clamp(fmid+fd,0.0f,65536.0f);
- return fres;
- }
- void SubdivideAndDisplace(INDEX x, INDEX y, INDEX idx, FLOAT fdMax)
- {
- FLOAT flu=GetHMPixel(x,y);
- FLOAT fru=GetHMPixel(x+idx,y);
- FLOAT frd=GetHMPixel(x+idx,y+idx);
- FLOAT fld=GetHMPixel(x,y+idx);
- if( fdMax<_iRandomDX)
- {
- SetHMPixel(RandomizePixel((flu+fru)/2.0f,fdMax), x+idx/2, y ); // middle top
- SetHMPixel(RandomizePixel((fld+frd)/2.0f,fdMax), x+idx/2, y+idx ); // middle bottom
- SetHMPixel(RandomizePixel((fru+frd)/2.0f,fdMax), x+idx, y+idx/2); // right middle
- SetHMPixel(RandomizePixel((flu+fld)/2.0f,fdMax), x, y+idx/2); // left middle
-
- SetHMPixel(RandomizePixel((flu+fru+fld+frd)/4.0f,fdMax), x+idx/2, y+idx/2); // middle
- }
- else
- {
- SetHMPixel(RandomizePixel(65536.0f/2.0f,fdMax), x+idx/2, y ); // middle top
- SetHMPixel(RandomizePixel(65536.0f/2.0f,fdMax), x+idx/2, y+idx ); // middle bottom
- SetHMPixel(RandomizePixel(65536.0f/2.0f,fdMax), x+idx, y+idx/2); // right middle
- SetHMPixel(RandomizePixel(65536.0f/2.0f,fdMax), x, y+idx/2); // left middle
-
- SetHMPixel(RandomizePixel(65536.0f/2.0f,fdMax), x+idx/2, y+idx/2); // middle
- }
-
- fdMax*=0.5f;
- if(idx>1)
- {
- SubdivideAndDisplace(x ,y , idx/2, fdMax);
- SubdivideAndDisplace(x+idx/2,y , idx/2, fdMax);
- SubdivideAndDisplace(x ,y+idx/2, idx/2, fdMax);
- SubdivideAndDisplace(x+idx/2,y+idx/2, idx/2, fdMax);
- }
- }
- Rect GetTerrainRect(void)
- {
- Rect rect;
- rect.rc_iLeft=0;
- rect.rc_iRight=0;
- rect.rc_iTop=0;
- rect.rc_iBottom=0;
- CTerrain *ptrTerrain=GetTerrain();
- if( ptrTerrain==NULL) return rect;
- rect.rc_iLeft=0;
- rect.rc_iRight=ptrTerrain->tr_pixHeightMapWidth;
- rect.rc_iTop=0;
- rect.rc_iBottom=ptrTerrain->tr_pixHeightMapHeight;
- return rect;
- }
- FLOAT GetWrappedPixelValue( INDEX x, INDEX y)
- {
- INDEX iWrapX=(x+WNOISE)%WNOISE;
- INDEX iWrapY=(y+WNOISE)%WNOISE;
- return _pafWhiteNoise[iWrapY*WNOISE+iWrapX];
- }
- void RandomizeWhiteNoise(void)
- {
- if(_pafWhiteNoise==NULL)
- {
- _pafWhiteNoise=(FLOAT *)AllocMemory(WNOISE*WNOISE*sizeof(FLOAT));
- }
- FLOAT *pfTemp=_pafWhiteNoise;
- for(INDEX i=0; i<WNOISE*WNOISE; i++)
- {
- FLOAT fRnd=FLOAT(rand())/RAND_MAX-0.5f;
- *pfTemp=fRnd;
- pfTemp++;
- }
- }
- FLOAT *GenerateTerrain_FBMBuffer(PIX pixW, PIX pixH, INDEX ctOctaves, FLOAT fHighFrequencyStep,
- FLOAT fStepFactor, FLOAT fMaxAmplitude, FLOAT fAmplitudeDecreaser,
- BOOL bAddNegativeValues, BOOL bRandomOffest, FLOAT &fMin, FLOAT &fMax)
- {
- if(_pafWhiteNoise==NULL)
- {
- RandomizeWhiteNoise();
- }
- FLOAT *pfTemp=_pafWhiteNoise;
- FLOAT fTmpMaxAmplitude=fMaxAmplitude;
- INDEX ctMemory=pixW*pixH*sizeof(FLOAT);
- FLOAT *pafFBM=(FLOAT *)AllocMemory(ctMemory);
- memset(pafFBM,0,ctMemory);
- FLOAT fPixStep=fHighFrequencyStep/pow(fStepFactor,ctOctaves);
- fMin=1e6;
- fMax=-1e6;
- for(INDEX iOctave=ctOctaves-1; iOctave>=0; iOctave--)
- {
- FLOAT fOctaveOffset=0.0f;
- if( bRandomOffest)
- {
- fOctaveOffset=_pafWhiteNoise[iOctave];
- }
- for(INDEX y=0; y<pixH; y++)
- {
- for(INDEX x=0; x<pixW; x++)
- {
- FLOAT fY=y*fPixStep+fOctaveOffset;
- FLOAT fX=x*fPixStep+fOctaveOffset;
- // calculate bilinear value
- FLOAT fLU=GetWrappedPixelValue( fX , fY);
- FLOAT fRU=GetWrappedPixelValue( fX+1, fY);
- FLOAT fLD=GetWrappedPixelValue( fX , fY+1);
- FLOAT fRD=GetWrappedPixelValue( fX+1, fY+1);
- FLOAT fFX=fX-INDEX(fX);
- FLOAT fFY=fY-INDEX(fY);
- FLOAT fBil=Lerp(Lerp(fLU,fRU,fFX),Lerp(fLD,fRD,fFX),fFY);
- INDEX iOffset=pixW*y+x;
- FLOAT fValue=pafFBM[iOffset];
- FLOAT fAdd=fBil*fTmpMaxAmplitude;
- if(bAddNegativeValues || fAdd>0)
- {
- fValue=fValue+fAdd;
- }
- pafFBM[iOffset]=fValue;
- if(fValue>fMax) fMax=fValue;
- if(fValue<fMin) fMin=fValue;
- }
- }
- fPixStep*=fStepFactor;
- fTmpMaxAmplitude*=fAmplitudeDecreaser;
- }
- return pafFBM;
- }
- void GenerateTerrain_SubdivideAndDisplace(void)
- {
- // inside subdivide and displace functions we will use these global variables
- _iTerrainWidth=_rect.Width();
- _puwHeightMap=_puwBuffer;
- UWORD uwScrollValue=8.0f-Clamp(theApp.m_iRNDSubdivideAndDisplaceItterations, INDEX(0), INDEX(8));
- _iRandomDX=(_iTerrainWidth-1)<<uwScrollValue;
-
- UWORD uwrnd;
- FLOAT fdMax=65536.0f;
- for (INDEX i=0; i<_rect.Width()*_rect.Height(); i++) {
- _puwHeightMap[i] = 65535;
- }
- uwrnd=RandomizePixel(fdMax/2.0f,fdMax); SetHMPixel(uwrnd, 0, 0);
- uwrnd=RandomizePixel(fdMax/2.0f,fdMax); SetHMPixel(uwrnd, _iTerrainWidth-1, 0);
- uwrnd=RandomizePixel(fdMax/2.0f,fdMax); SetHMPixel(uwrnd, _iTerrainWidth-1, _iTerrainWidth-1);
- uwrnd=RandomizePixel(fdMax/2.0f,fdMax); SetHMPixel(uwrnd, 0, _iTerrainWidth-1);
- // generate rest of terrain pixels using recursion
- SubdivideAndDisplace(0,0,_iTerrainWidth-1,fdMax/2.0f);
- }
- void GenerateTerrain(void)
- {
- CTerrain *ptrTerrain=GetTerrain();
- if( ptrTerrain==NULL) return;
- switch(theApp.m_iTerrainGenerationMethod)
- {
- case 0:
- {
- GenerateTerrain_SubdivideAndDisplace();
- break;
- }
- case 1:
- {
- FLOAT fMin, fMax;
- PIX pixTerrainW=ptrTerrain->tr_pixHeightMapWidth;
- PIX pixTerrainH=ptrTerrain->tr_pixHeightMapHeight;
- FLOAT *pafFBM=GenerateTerrain_FBMBuffer( pixTerrainW, pixTerrainH, theApp.m_iFBMOctaves,
- theApp.m_fFBMHighFrequencyStep,theApp.m_fFBMStepFactor, theApp.m_fFBMMaxAmplitude,
- theApp.m_fFBMfAmplitudeDecreaser, theApp.m_bFBMAddNegativeValues, theApp.m_bFBMRandomOffset, fMin, fMax);
- // convert buffer to height map
- FLOAT fSizeY=ptrTerrain->tr_vTerrainSize(2);
- FLOAT fConvertFactor=(theApp.m_fFBMMaxAmplitude/fSizeY)*MAX_UWORD;
- // set height map
- for(INDEX iPix=0; iPix<pixTerrainW*pixTerrainH; iPix++)
- {
- FLOAT fValue=pafFBM[iPix];
- UWORD uwValue=UWORD(Clamp((fValue-fMin)/(fMax-fMin)*fConvertFactor,0.0f,65535.0f));
- _puwBuffer[iPix]=uwValue;
- }
-
- FreeMemory( pafFBM);
- break;
- }
- }
- }
- void EqualizeBuffer(void)
- {
- UWORD uwHeightMax=0;
- UWORD uwHeightMin=MAX_UWORD;
- INDEX x,y;
- for(y=0; y<_rect.Height(); y++)
- {
- for(x=0; x<_rect.Width(); x++)
- {
- INDEX iOffset = y*_rect.Width()+x;
- UWORD uwHeight = _puwBuffer[iOffset];
- if( uwHeight>uwHeightMax) uwHeightMax=uwHeight;
- if( uwHeight<uwHeightMin) uwHeightMin=uwHeight;
- }
- }
-
- FLOAT fFactor=65535.0f/(uwHeightMax-uwHeightMin);
- // equalize (normalize from 0 to 65535)
- for(y=0; y<_rect.Height(); y++)
- {
- for(x=0; x<_rect.Width(); x++)
- {
- INDEX iOffset = y*_rect.Width()+x;
- UWORD uwHeight = _puwBuffer[iOffset];
- FLOAT fNormalized=(uwHeight-uwHeightMin)*fFactor;
- _puwBuffer[iOffset]=fNormalized;
- }
- }
- }
- BOOL SetupContinousNoiseTexture( void)
- {
- try
- {
- _ptdContinousRandomNoise=_pTextureStock->Obtain_t( theApp.m_fnContinousNoiseTexture);
- _ptdContinousRandomNoise->Force(TEX_STATIC|TEX_CONSTANT);
- }
- catch( char *strError)
- {
- (void) strError;
- WarningMessage("Unable to obtain continous random noise texture!\nError: %s", strError);
- return FALSE;
- }
- return TRUE;
- }
- void FreeContinousNoiseTexture( void)
- {
- _pTextureStock->Release( _ptdContinousRandomNoise);
- }
- BOOL SetupDistributionNoiseTexture( void)
- {
- try
- {
- _ptdDistributionRandomNoise=_pTextureStock->Obtain_t( theApp.m_fnDistributionNoiseTexture);
- _ptdDistributionRandomNoise->Force(TEX_STATIC|TEX_CONSTANT);
- }
- catch( char *strError)
- {
- (void) strError;
- WarningMessage("Unable to obtain distribution random noise texture!\nError: %s", strError);
- return FALSE;
- }
- return TRUE;
- }
- void FreeDistributionNoiseTexture( void)
- {
- _pTextureStock->Release( _ptdDistributionRandomNoise);
- }
- FLOAT StepUp(FLOAT fCur, FLOAT fMin, FLOAT fMax)
- {
- if( fCur<=fMin) return 0.0f;
- if( fCur>=fMax) return 1.0f;
- return (fCur-fMin)/(fMax-fMin);
- }
- FLOAT StepDown(FLOAT fCur, FLOAT fMin, FLOAT fMax)
- {
- if( fCur<=fMin) return 1.0f;
- if( fCur>=fMax) return 0.0f;
- return (fMax-fCur)/(fMax-fMin);
- }
- FLOAT3D NormalFrom4Points(const FLOAT3D &v0, const FLOAT3D &v1, const FLOAT3D &v2, const FLOAT3D &v3,
- FLOAT fLerpX, FLOAT fLerpZ)
- {
- FLOAT fHDeltaX = Lerp(v1(2)-v0(2), v3(2)-v2(2), fLerpZ);
- FLOAT fHDeltaZ = Lerp(v0(2)-v2(2), v1(2)-v3(2), fLerpX);
- FLOAT fDeltaX = v1(1) - v0(1);
- FLOAT fDeltaZ = v0(3) - v2(3);
- FLOAT3D vNormal;
- vNormal(2) = sqrt(1 / (((fHDeltaX*fHDeltaX)/(fDeltaX*fDeltaX)) + ((fHDeltaZ*fHDeltaZ)/(fDeltaZ*fDeltaZ)) + 1));
- vNormal(1) = sqrt(vNormal(2)*vNormal(2) * ((fHDeltaX*fHDeltaX) / (fDeltaX*fDeltaX)));
- vNormal(3) = sqrt(vNormal(2)*vNormal(2) * ((fHDeltaZ*fHDeltaZ) / (fDeltaZ*fDeltaZ)));
- if (fHDeltaX>0) {
- vNormal(1) = -vNormal(1);
- }
- if (fHDeltaZ<0) {
- vNormal(3) = -vNormal(3);
- }
- //ASSERT(Abs(vNormal.Length()-1)<0.01);
- return vNormal;
- }
- FLOAT3D GetPoint(CTerrain *ptrTerrain, INDEX iX, INDEX iY)
- {
- const FLOAT3D &vStretch = ptrTerrain->tr_vStretch;
- iX = Clamp(iX, INDEX(0), ptrTerrain->tr_pixHeightMapWidth);
- iY = Clamp(iY, INDEX(0), ptrTerrain->tr_pixHeightMapHeight);
- return FLOAT3D(
- FLOAT(iX)*vStretch(1),
- (FLOAT)ptrTerrain->tr_auwHeightMap[iX+iY*ptrTerrain->tr_pixHeightMapWidth] * vStretch(2),
- FLOAT(iY)*vStretch(3));
- }
- UWORD GetSlope(CTerrain *ptrTerrain, INDEX iX, INDEX iY)
- {
- FLOAT3D av[9];
- INDEX iHMapWidth = ptrTerrain->tr_pixHeightMapWidth;
- FLOAT3D vStretch = ptrTerrain->tr_vStretch;
- av[0] = GetPoint(ptrTerrain, iX-1, iY-1);
- av[1] = GetPoint(ptrTerrain, iX , iY-1);
- av[2] = GetPoint(ptrTerrain, iX+1, iY-1);
- av[3] = GetPoint(ptrTerrain, iX-1, iY );
- av[4] = GetPoint(ptrTerrain, iX , iY );
- av[5] = GetPoint(ptrTerrain, iX+1, iY );
- av[6] = GetPoint(ptrTerrain, iX-1, iY+1);
- av[7] = GetPoint(ptrTerrain, iX , iY+1);
- av[8] = GetPoint(ptrTerrain, iX+1, iY+1);
- FLOAT3D avN[4];
- FLOAT3D vNormal;
- avN[0] = NormalFrom4Points(av[0], av[1], av[3], av[4], 1, 1);
- avN[1] = NormalFrom4Points(av[1], av[2], av[4], av[5], 0, 1);
- avN[2] = NormalFrom4Points(av[3], av[4], av[6], av[7], 1, 0);
- avN[3] = NormalFrom4Points(av[4], av[5], av[7], av[8], 0, 0);
- vNormal = avN[0]+avN[1]+avN[2]+avN[3];
- vNormal.Normalize();
- return (1-vNormal(2))*65535;
- }
- void GenerateLayerDistribution(INDEX iForLayer, Rect rect)
- {
- if(!SetupDistributionNoiseTexture()) return;
- CTerrain *ptrTerrain=GetTerrain();
- if( ptrTerrain==NULL) return;
- // obtain buffer
- UWORD *puwAltitude=GetBufferForEditing(ptrTerrain, rect, BT_HEIGHT_MAP, 0);
- INDEX ctSize=rect.Width()*rect.Height()*sizeof(UWORD);
- UWORD *puwSlope=(UWORD *)AllocMemory(ctSize);
- // prepare slope buffer
- for(INDEX y=0; y<rect.Height(); y++)
- {
- for(INDEX x=0; x<rect.Width(); x++)
- {
- INDEX iOffset = y*rect.Width()+x;
- puwSlope[iOffset] = GetSlope(ptrTerrain, x+rect.rc_iLeft, y+rect.rc_iTop);
- }
- }
-
- // for each layer
- for(INDEX iLayer=0; iLayer<ptrTerrain->tr_atlLayers.Count(); iLayer++)
- {
- if( iForLayer!=-1 && iLayer!=iForLayer) continue;
- CTerrainLayer *ptlLayer=GetLayer(iLayer);
- if(!ptlLayer->tl_bAutoRegenerated) continue;
- // get layer
- UWORD *puwMask=GetBufferForEditing(ptrTerrain, rect, BT_LAYER_MASK, iLayer);
- for(INDEX y=0; y<rect.Height(); y++)
- {
- INDEX oy=y+rect.rc_iTop;
- for(INDEX x=0; x<rect.Width(); x++)
- {
- INDEX ox=x+rect.rc_iLeft;
- INDEX iOffset = y*rect.Width()+x;
- FLOAT fAltitudeRatio = puwAltitude[iOffset]/65535.0f;
- FLOAT fSlopeRatio = puwSlope[iOffset]/65535.0f;
- FLOAT fAltitudeRange=ptlLayer->tl_fMaxAltitude-ptlLayer->tl_fMinAltitude;
- FLOAT fSlopeRange=ptlLayer->tl_fMaxSlope-ptlLayer->tl_fMinSlope;
- // get coverage influence
- FLOAT fCoverageInfluence=1.0f;
- FLOAT fCoverageRandom=GetDistributionNoise( ox, oy, ptlLayer->tl_fCoverageRandom);
- fCoverageInfluence=StepDown(fCoverageRandom, ptlLayer->tl_fCoverage, ptlLayer->tl_fCoverage+ptlLayer->tl_fCoverageNoise);
- // get min altitude influence
- FLOAT fMinAltitudeInfluence=1.0f;
- if(ptlLayer->tl_bApplyMinAltitude)
- {
- FLOAT fMinAltitudeNoise=(GetDistributionNoise( ox, oy, ptlLayer->tl_fMinAltitudeRandom)-0.5f)*ptlLayer->tl_fMinAltitudeNoise;
- FLOAT fAltMinFade1=ptlLayer->tl_fMinAltitude+fAltitudeRange*ptlLayer->tl_fMinAltitudeFade;
- fMinAltitudeInfluence=StepUp(fAltitudeRatio+fMinAltitudeNoise, ptlLayer->tl_fMinAltitude, fAltMinFade1);
- }
- // get max altitude influence
- FLOAT fMaxAltitudeInfluence=1.0f;
- if(ptlLayer->tl_bApplyMaxAltitude)
- {
- FLOAT fMaxAltitudeNoise=(GetDistributionNoise( ox, oy, ptlLayer->tl_fMaxAltitudeRandom)-0.5f)*ptlLayer->tl_fMaxAltitudeNoise;
- FLOAT fAltMaxFade1=ptlLayer->tl_fMaxAltitude-fAltitudeRange*ptlLayer->tl_fMaxAltitudeFade;
- fMaxAltitudeInfluence=StepDown(fAltitudeRatio+fMaxAltitudeNoise, fAltMaxFade1, ptlLayer->tl_fMaxAltitude);
- }
- // get min slope influence
- FLOAT fMinSlopeInfluence=1.0f;
- if(ptlLayer->tl_bApplyMinSlope)
- {
- FLOAT fMinSlopeNoise=(GetDistributionNoise( ox, oy, ptlLayer->tl_fMinSlopeRandom)-0.5f)*ptlLayer->tl_fMinSlopeNoise;
- FLOAT fSlopeMinFade1=ptlLayer->tl_fMinSlope+fSlopeRange*ptlLayer->tl_fMinSlopeFade;
- fMinSlopeInfluence=StepUp(fSlopeRatio+fMinSlopeNoise, ptlLayer->tl_fMinSlope, fSlopeMinFade1);
- }
- // get max slope influence
- FLOAT fMaxSlopeInfluence=1.0f;
- if(ptlLayer->tl_bApplyMaxSlope)
- {
- FLOAT fMaxSlopeNoise=(GetDistributionNoise( ox, oy, ptlLayer->tl_fMaxSlopeRandom)-0.5f)*ptlLayer->tl_fMaxSlopeNoise;
- FLOAT fSlopeMaxFade1=ptlLayer->tl_fMaxSlope-fSlopeRange*ptlLayer->tl_fMaxSlopeFade;
- fMaxSlopeInfluence=StepDown(fSlopeRatio+fMaxSlopeNoise, fSlopeMaxFade1, ptlLayer->tl_fMaxSlope);
- }
- // calculate result of all influences
- puwMask[iOffset]= 65535.0f*
- fCoverageInfluence*
- fMinAltitudeInfluence*
- fMaxAltitudeInfluence*
- fMinSlopeInfluence*
- fMaxSlopeInfluence;
- }
- }
- // apply buffer change
- SetBufferForEditing(ptrTerrain, puwMask, rect, BT_LAYER_MASK, iLayer);
- theApp.GetActiveDocument()->SetModifiedFlag( TRUE);
- FreeMemory(puwMask);
- }
- FreeMemory(puwAltitude);
- theApp.m_ctTerrainPageCanvas.MarkChanged();
- FreeDistributionNoiseTexture();
- }
- void GenerateLayerDistribution(INDEX iForLayer)
- {
- CTerrain *ptrTerrain=GetTerrain();
- if( ptrTerrain==NULL) return;
- Rect rect;
- rect.rc_iLeft=0;
- rect.rc_iRight=ptrTerrain->tr_pixHeightMapWidth;
- rect.rc_iTop=0;
- rect.rc_iBottom=ptrTerrain->tr_pixHeightMapHeight;
-
- GenerateLayerDistribution(iForLayer, rect);
- }
-
- void RecalculateShadows(void)
- {
- CTerrain *ptrTerrain=GetTerrain();
- if( ptrTerrain==NULL) return;
- ptrTerrain->UpdateShadowMap();
- }
- void OptimizeLayers(void)
- {
- CTerrain *ptrTerrain=GetTerrain();
- if( ptrTerrain==NULL) return;
- Rect rect;
- rect.rc_iLeft=0;
- rect.rc_iRight=ptrTerrain->tr_pixHeightMapWidth;
- rect.rc_iTop=0;
- rect.rc_iBottom=ptrTerrain->tr_pixHeightMapHeight;
- CStaticArray<UWORD*> apuwLayers;
- // obtain buffer
- INDEX ctLayers=ptrTerrain->tr_atlLayers.Count();
- apuwLayers.New(ctLayers);
- INDEX iLayer, iOffset;
- for( iLayer=0; iLayer<ctLayers; iLayer++)
- {
- UWORD *puw=GetBufferForEditing(ptrTerrain, rect, BT_LAYER_MASK, iLayer);
- apuwLayers[iLayer]=puw;
- }
- // count overdraw before optimisation
- INDEX ctDrawnBefore=0;
- INDEX ctPixels=rect.Width()*rect.Height();
- for(iOffset=0; iOffset<ctPixels; iOffset++)
- {
- for(INDEX i=0; i<ctLayers; i++)
- {
- UWORD *puwCurr=apuwLayers[i]+iOffset;
- if( (*puwCurr)>>8 != 0) ctDrawnBefore++;
- }
- }
- // optimize for overdraw
- for(iOffset=0; iOffset<ctPixels; iOffset++)
- {
- BOOL bOptimize=FALSE;
- for(INDEX i=ctLayers-1; i>=0; i--)
- {
- UWORD *puwCurr=apuwLayers[i]+iOffset;
- // if should optimize
- if(bOptimize)
- {
- // clear mask
- *puwCurr=0;
- }
- else
- {
- if( (*puwCurr)>>8 == 255)
- {
- // clear mask for all layers beneath current one
- bOptimize=TRUE;
- }
- }
- }
- }
- // count overdraw after optimisation
- INDEX ctDrawnAfter=0;
- for(iOffset=0; iOffset<ctPixels; iOffset++)
- {
- for(INDEX i=0; i<ctLayers; i++)
- {
- UWORD *puwCurr=apuwLayers[i]+iOffset;
- if( (*puwCurr)>>8 != 0) ctDrawnAfter++;
- }
- }
- // make a report about optimisation success
- CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd());
- CTString strReport;
- strReport.PrintF("Overdraw before optimization: %g. Overdraw after optimization: %g",
- FLOAT(ctDrawnBefore)/ctPixels, FLOAT(ctDrawnAfter)/ctPixels);
- pMainFrame->SetStatusBarMessage( strReport, STATUS_LINE_PANE, 5.0f);
- // free buffers
- for( iLayer=0; iLayer<ctLayers; iLayer++)
- {
- SetBufferForEditing(ptrTerrain, apuwLayers[iLayer], rect, BT_LAYER_MASK, iLayer);
- FreeMemory(apuwLayers[iLayer]);
- }
- theApp.GetActiveDocument()->SetModifiedFlag( TRUE);
- theApp.m_ctTerrainPageCanvas.MarkChanged();
- }
- BOOL _bIsUpToDate=TRUE;
- Rect _rectDiscarded;
- void DiscardLayerDistribution(Rect rect)
- {
- if(_bIsUpToDate)
- {
- _rectDiscarded.rc_iLeft=rect.rc_iLeft;
- _rectDiscarded.rc_iRight=rect.rc_iRight;
- _rectDiscarded.rc_iTop=rect.rc_iTop;
- _rectDiscarded.rc_iBottom=rect.rc_iBottom;
- }
- else
- {
- if(rect.rc_iLeft < _rectDiscarded.rc_iLeft) _rectDiscarded.rc_iLeft=rect.rc_iLeft;
- if(rect.rc_iRight > _rectDiscarded.rc_iRight) _rectDiscarded.rc_iRight=rect.rc_iRight;
- if(rect.rc_iTop < _rectDiscarded.rc_iTop) _rectDiscarded.rc_iTop=rect.rc_iTop;
- if(rect.rc_iBottom > _rectDiscarded.rc_iBottom) _rectDiscarded.rc_iBottom=rect.rc_iBottom;
- }
- _bIsUpToDate=FALSE;
- }
- void UpdateLayerDistribution(void)
- {
- if(_bIsUpToDate || !theApp.m_Preferences.ap_bAutoUpdateTerrainDistribution) return;
- // update layer distribution
- GenerateLayerDistribution(-1, _rectDiscarded);
- _bIsUpToDate=TRUE;
- }
- void ApplyFilterOntoTerrain(void)
- {
- EditTerrain(NULL, FLOAT3D(0,0,0), theApp.m_fFilterPower*16.0f, TE_ALTITUDE_FILTER);
- }
- void ApplySmoothOntoTerrain(void)
- {
- EditTerrain(NULL, FLOAT3D(0,0,0), theApp.m_fSmoothPower*16.0f, TE_ALTITUDE_SMOOTH);
- }
- void ApplyEqualizeOntoTerrain(void)
- {
- EditTerrain(NULL, FLOAT3D(0,0,0), 1.0f, TE_ALTITUDE_EQUALIZE);
- }
- void ApplyGenerateTerrain(void)
- {
- EditTerrain(NULL, FLOAT3D(0,0,0), 1.0f, TE_GENERATE_TERRAIN);
- }
- void ApplyRndNoiseOntoTerrain(void)
- {
- EditTerrain(NULL, FLOAT3D(0,0,0), theApp.m_fNoiseAltitude, TE_ALTITUDE_RND_NOISE);
- }
- void ApplyContinousNoiseOntoTerrain(void)
- {
- EditTerrain(NULL, FLOAT3D(0,0,0), theApp.m_fNoiseAltitude, TE_ALTITUDE_CONTINOUS_NOISE);
- }
- void ApplyMinimumOntoTerrain(void)
- {
- EditTerrain(NULL, FLOAT3D(0,0,0), 1.0f, TE_ALTITUDE_MINIMUM);
- }
- void ApplyMaximumOntoTerrain(void)
- {
- EditTerrain(NULL, FLOAT3D(0,0,0), 1.0f, TE_ALTITUDE_MAXIMUM);
- }
- void ApplyFlattenOntoTerrain(void)
- {
- EditTerrain(NULL, FLOAT3D(0,0,0), 1.0f, TE_ALTITUDE_FLATTEN);
- }
- void ApplyPosterizeOntoTerrain(void)
- {
- EditTerrain(NULL, FLOAT3D(0,0,0), theApp.m_fPosterizeStep, TE_ALTITUDE_POSTERIZE);
- }
- CEntity *GetEntityForID(ULONG iEntityID)
- {
- CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
- FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
- {
- if(iten->en_ulID==iEntityID) return &*iten;
- }
- return NULL;
- }
- // constructor
- CTerrainUndo::CTerrainUndo()
- {
- tu_puwUndoBuffer=NULL;
- tu_puwRedoBuffer=NULL;
- }
- void DeleteOneUndo(CTerrainUndo *ptrud)
- {
- if(ptrud->tu_puwUndoBuffer!=NULL) FreeMemory(ptrud->tu_puwUndoBuffer);
- if(ptrud->tu_puwRedoBuffer!=NULL) FreeMemory(ptrud->tu_puwRedoBuffer);
- delete ptrud;
- }
- void DeleteTerrainUndo(CWorldEditorDoc* pDoc)
- {
- for(INDEX iUndo=0; iUndo<pDoc->m_dcTerrainUndo.Count(); iUndo++)
- {
- CTerrainUndo *ptu=&pDoc->m_dcTerrainUndo[iUndo];
- pDoc->m_dcTerrainUndo.Remove(ptu);
- DeleteOneUndo(ptu);
- }
- }
- CTerrain *GetUndoTerrain(ULONG ulEntityID)
- {
- // obtain terrain entity
- CEntity *penTerrain=GetEntityForID(_iTerrainEntityID);
- if(penTerrain==NULL)
- {
- return NULL;
- }
- // obtain terrain
- CTerrain *ptrTerrain=penTerrain->GetTerrain();
- return ptrTerrain;
- }
- void ApplyTerrainUndo(CTerrainUndo *ptrud)
- {
- CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
- CTerrain *ptrTerrain=GetUndoTerrain(ptrud->tu_ulEntityID);
- if(ptrTerrain==NULL)
- {
- DeleteOneUndo(ptrud);
- return;
- }
- // obtain and store redo buffer
- if(ptrud->tu_puwRedoBuffer==NULL)
- {
- ptrud->tu_puwRedoBuffer=GetBufferForEditing(ptrTerrain, ptrud->tu_rcRect,
- ptrud->tu_btUndoBufferType, ptrud->tu_iUndoBufferData);
- }
- // apply buffer change (undo)
- SetBufferForEditing(ptrTerrain, ptrud->tu_puwUndoBuffer, ptrud->tu_rcRect,
- ptrud->tu_btUndoBufferType, ptrud->tu_iUndoBufferData);
- pDoc->m_iCurrentTerrainUndo--;
- DiscardLayerDistribution(ptrud->tu_rcRect);
- pDoc->SetModifiedFlag( TRUE);
- theApp.m_ctTerrainPageCanvas.MarkChanged();
- }
- void ApplyTerrainRedo(CTerrainUndo *ptrud)
- {
- CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
- CTerrain *ptrTerrain=GetUndoTerrain(ptrud->tu_ulEntityID);
- if(ptrTerrain==NULL)
- {
- DeleteOneUndo(ptrud);
- return;
- }
- if(ptrud->tu_puwRedoBuffer==NULL) return;
- // apply buffer change (redo)
- SetBufferForEditing(ptrTerrain, ptrud->tu_puwRedoBuffer, ptrud->tu_rcRect,
- ptrud->tu_btUndoBufferType, ptrud->tu_iUndoBufferData);
- pDoc->m_iCurrentTerrainUndo++;
- DiscardLayerDistribution(ptrud->tu_rcRect);
- pDoc->SetModifiedFlag( TRUE);
- theApp.m_ctTerrainPageCanvas.MarkChanged();
- }
- UWORD *ExtractUndoRect(PIX pixTerrainWidth)
- {
- INDEX ctBuffBytes=_rectUndo.Width()*_rectUndo.Height()*sizeof(UWORD);
- UWORD *puwBuff=(UWORD*)AllocMemory(ctBuffBytes);
- if(puwBuff==NULL) return NULL;
- UWORD *puwBuffTemp=puwBuff;
- for(INDEX y=_rectUndo.rc_iTop; y<_rectUndo.rc_iBottom; y++)
- {
- for(INDEX x=_rectUndo.rc_iLeft; x<_rectUndo.rc_iRight; x++)
- {
- INDEX iOffset=y*pixTerrainWidth+x;
- UWORD uwValue=_puwUndoTerrain[iOffset];
- *puwBuffTemp=uwValue;
- puwBuffTemp++;
- }
- }
- return puwBuff;
- }
- void TerrainEditBegin(void)
- {
- if( !(theApp.m_Preferences.ap_iMemoryForTerrainUndo>0))
- {
- return;
- }
- _bUndoStart=TRUE;
- }
- void RemoveRedoList(void)
- {
- CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
- CDynamicContainer<CTerrainUndo> dcTemp;
- for( INDEX itu=0; itu<pDoc->m_iCurrentTerrainUndo+1; itu++)
- {
- dcTemp.Add(&pDoc->m_dcTerrainUndo[itu]);
- }
- for( INDEX ituDel=pDoc->m_iCurrentTerrainUndo+1; ituDel<pDoc->m_dcTerrainUndo.Count(); ituDel++)
- {
- DeleteOneUndo(&pDoc->m_dcTerrainUndo[ituDel]);
- }
- pDoc->m_dcTerrainUndo.MoveContainer(dcTemp);
- }
- void LimitMemoryConsumption(INDEX iNewConsumption)
- {
- CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
- INDEX ctUndos=pDoc->m_dcTerrainUndo.Count();
- INDEX iLastValid=-1;
- INDEX iSum=iNewConsumption;
- for(INDEX iUndo=ctUndos-1; iUndo>=0; iUndo--)
- {
- CTerrainUndo *ptu=&pDoc->m_dcTerrainUndo[iUndo];
- INDEX iMemory=ptu->tu_rcRect.Width()*ptu->tu_rcRect.Height()*sizeof(UWORD);
- if(ptu->tu_puwRedoBuffer!=NULL)
- {
- iSum=iSum+iMemory*2;
- }
- else
- {
- iSum=iSum+iMemory;
- }
- if(iSum>theApp.m_Preferences.ap_iMemoryForTerrainUndo*1024*1024)
- {
- iLastValid=iUndo+1;
- break;
- }
- }
- if( iLastValid!=-1)
- {
- CDynamicContainer<CTerrainUndo> dcTemp;
- for( INDEX itu=iLastValid; itu<ctUndos; itu++)
- {
- dcTemp.Add(&pDoc->m_dcTerrainUndo[itu]);
- }
- for( INDEX ituDel=0; ituDel<iLastValid; ituDel++)
- {
- DeleteOneUndo(&pDoc->m_dcTerrainUndo[ituDel]);
- }
- pDoc->m_dcTerrainUndo.MoveContainer(dcTemp);
- if(pDoc->m_iCurrentTerrainUndo>=iLastValid)
- {
- pDoc->m_iCurrentTerrainUndo=pDoc->m_iCurrentTerrainUndo-iLastValid;
- }
- }
- }
- void TerrainEditEnd(void)
- {
- if( !(theApp.m_Preferences.ap_iMemoryForTerrainUndo>0))
- {
- return;
- }
- CWorldEditorDoc* pDoc = theApp.GetActiveDocument();
- // obtain terrain entity
- CEntity *penTerrain=GetEntityForID(_iTerrainEntityID);
- if(penTerrain==NULL)
- {
- if(_puwUndoTerrain!=NULL)
- {
- FreeMemory(_puwUndoTerrain);
- _puwUndoTerrain=NULL;
- }
- return;
- }
- // obtain terrain
- CTerrain *ptrTerrain=penTerrain->GetTerrain();
- if(ptrTerrain==NULL)
- {
- if(_puwUndoTerrain!=NULL)
- {
- FreeMemory(_puwUndoTerrain);
- _puwUndoTerrain=NULL;
- }
- return;
- }
- // we will add undo, clear all existing redo's
- RemoveRedoList();
- // remember undo
- CTerrainUndo *ptrud=new CTerrainUndo;
-
- INDEX iNewConsumption=_rectUndo.Width()*_rectUndo.Height()*sizeof(UWORD);
- LimitMemoryConsumption(iNewConsumption);
-
- ptrud->tu_ulEntityID=_iTerrainEntityID;
- ptrud->tu_rcRect=_rectUndo;
- ptrud->tu_btUndoBufferType=_btUndoBufferType;
- ptrud->tu_iUndoBufferData=_iUndoBufferData;
- ptrud->tu_puwUndoBuffer=ExtractUndoRect(ptrTerrain->tr_pixHeightMapWidth);
-
- if(ptrud->tu_puwUndoBuffer!=NULL)
- {
- pDoc->m_dcTerrainUndo.Add(ptrud);
- }
- else
- {
- delete ptrud;
- }
- pDoc->m_iCurrentTerrainUndo=pDoc->m_dcTerrainUndo.Count()-1;
- // release obtained terrain buffer
- if(_puwUndoTerrain!=NULL)
- {
- FreeMemory(_puwUndoTerrain);
- _puwUndoTerrain=NULL;
- }
- }
- CTileInfo::CTileInfo()
- {
- ti_ix=-1;
- ti_iy=-1;
- ti_bSwapXY=FALSE;
- ti_bFlipX=FALSE;
- ti_bFlipY=FALSE;
- }
- void ObtainLayerTileInfo(CDynamicContainer<CTileInfo> *pdcTileInfo, CTextureData *ptdTexture, INDEX &ctTilesPerRow)
- {
- CTFileName fnTexture=ptdTexture->GetName();
- CTFileName fnTileInfo=fnTexture.NoExt()+CTString(".tli");
- INDEX ctParsedLines=0;
- try
- {
- char achrLine[ 256];
- CTFileStream strm;
- strm.Open_t( fnTileInfo);
- FOREVER
- {
- CDynamicContainer<CTString> dcTokens;
- strm.GetLine_t(achrLine, 256);
- ctParsedLines++;
- char achrSeparators[] = " ,";
- char *pchrToken = strtok( achrLine, achrSeparators);
- while( pchrToken != NULL )
- {
- CTString *pstrToken=new CTString();
- *pstrToken=CTString( pchrToken);
- dcTokens.Add(pstrToken);
- // next token
- pchrToken = strtok( NULL, achrSeparators);
- }
- // if no tokens parsed
- if(dcTokens.Count()==0) continue;
- INDEX iToken=0;
- // analyze parsed tokens
- if(dcTokens[iToken]=="TilesPerRow")
- {
- // there must be at least 1 token for 'TilesPerRow' indentifier
- if(dcTokens.Count()-1-iToken<1)
- {
- throw("You must enter number of tiles per raw.");
- }
- ctTilesPerRow=0;
- INDEX iResultTPR=sscanf(dcTokens[iToken+1], "%d", &ctTilesPerRow);
- if(iResultTPR<=0)
- {
- ctTilesPerRow=0;
- throw("Unable to parse count of tiles per row.");
- }
- }
- else if(dcTokens[iToken]=="Tile")
- {
- // there must be at least 2 tokens for 'Tile' indentifier
- if(dcTokens.Count()-1-iToken<2)
- {
- throw("You must enter 2 coordinates per tile.");
- }
- INDEX x,y;
- INDEX iResultX=sscanf(dcTokens[iToken+1], "%d", &x);
- if(iResultX<=0)
- {
- throw("Unable to parse x coordinate.");
- }
- INDEX iResultY=sscanf(dcTokens[iToken+2], "%d", &y);
- if(iResultY<=0)
- {
- throw("Unable to parse y coordinate.");
- }
- if(x<=0 || y<=0)
- {
- throw("Tile coordinates must be greater than 0.");
- }
- // jump over coordinate tokens
- iToken+=3;
- // add tile info
- CTileInfo *pti=new CTileInfo();
- pti->ti_ix=x-1;
- pti->ti_iy=y-1;
- for( INDEX iFlagToken=iToken; iFlagToken<dcTokens.Count(); iFlagToken++)
- {
- if(dcTokens[iFlagToken]=="SwapXY")
- {
- pti->ti_bSwapXY=TRUE;
- }
- else if(dcTokens[iFlagToken]=="FlipX")
- {
- pti->ti_bFlipX=TRUE;
- }
- else if(dcTokens[iFlagToken]==";")
- {
- break;
- }
- else if(dcTokens[iFlagToken]=="FlipY")
- {
- pti->ti_bFlipY=TRUE;
- }
- else
- {
- throw("Unrecognizable character found.");
- }
- }
- pdcTileInfo->Add(pti);
- }
- // clear allocated tokens
- for(INDEX i=0; i<dcTokens.Count(); i++)
- {
- delete &dcTokens[i];
- }
- dcTokens.Clear();
- }
- }
- catch(char *strError)
- {
- (void) strError;
- }
- }
- void TilePaintTool(void)
- {
- CTerrain *ptrTerrain=GetTerrain();
- CTerrainLayer *ptlLayer=GetLayer();
- if(ptrTerrain==NULL || ptlLayer==NULL || ptlLayer->tl_ltType!=LT_TILE || ptlLayer->tl_ptdTexture==NULL) return;
-
- CDynamicContainer<CTileInfo> dcTileInfo;
- INDEX ctTilesPerRaw=0;
- ObtainLayerTileInfo( &dcTileInfo, ptlLayer->tl_ptdTexture, ctTilesPerRaw);
- INDEX ctTiles=dcTileInfo.Count();
- if(ctTilesPerRaw==0 || ctTiles==0) return;
- ptlLayer->SetTilesPerRow(ctTilesPerRaw);
- ptlLayer->tl_iSelectedTile= Clamp( ptlLayer->tl_iSelectedTile, (INDEX)0, INDEX(ctTiles-1) );
- if(ptlLayer->tl_iSelectedTile==-1) return;
- CTileInfo &ti=dcTileInfo[ptlLayer->tl_iSelectedTile];
- // _rect holds terrain size
- if(_fStrength>0)
- {
- UWORD uwValue=
- dcTileInfo[ptlLayer->tl_iSelectedTile].ti_iy*ctTilesPerRaw+
- dcTileInfo[ptlLayer->tl_iSelectedTile].ti_ix;
- if(ti.ti_bFlipX) uwValue|=TL_FLIPX;
- if(ti.ti_bFlipY) uwValue|=TL_FLIPY;
- if(ti.ti_bSwapXY) uwValue|=TL_SWAPXY;
- uwValue|=TL_VISIBLE;
- _puwBuffer[0]=uwValue<<8;
- }
- else
- {
- _puwBuffer[0]=0;
- }
- /*
- vidjeti sta ne radi sa brisanjem tile-ova
- ne pogadja se dobro lokacija tile-a ispod misa
- +view layer on/off ne discarda pretender texture
- +ne crta se dobro trenutno selektirani tile i preklapa se animirani (under mouse)
- +rotirane i flipane tileove crtati
- +nesto zapinje kad se prvi put otvara info window
- +ubaciti skrolanje tileova na mouse wheel
- +pick tile
- */
- // free allocated tile info structures
- for(INDEX i=0; i<dcTileInfo.Count(); i++)
- {
- delete &dcTileInfo[i];
- }
- dcTileInfo.Clear();
- }
- void EditTerrain(CTextureData *ptdBrush, FLOAT3D &vHitPoint, FLOAT fStrength, ETerrainEdit teTool)
- {
- _ptdBrush=ptdBrush;
- _fStrength=fStrength;
- CTerrain *ptrTerrain=GetTerrain();
- CTerrainLayer *ptlLayer=GetLayer();
- INDEX iLayer=GetLayerIndex();
- if(ptrTerrain==NULL || ptlLayer==NULL) return;
- // obtain buffer type
- BufferType btBufferType=BT_INVALID;
- INDEX iBufferData=-1;
- if( (teTool>TE_BRUSH_ALTITUDE_START && teTool<TE_BRUSH_ALTITUDE_END) ||
- (teTool>TE_ALTITUDE_START && teTool<TE_ALTITUDE_END) ||
- (teTool==TE_GENERATE_TERRAIN) ||
- (teTool==TE_ALTITUDE_EQUALIZE) )
- {
- btBufferType=BT_HEIGHT_MAP;
- }
- else if( (teTool>TE_BRUSH_LAYER_START && teTool<TE_BRUSH_LAYER_END) ||
- (teTool>TE_LAYER_START && teTool<TE_LAYER_END) ||
- teTool==TE_TILE_PAINT)
- {
- btBufferType=BT_LAYER_MASK;
- iBufferData=iLayer;
- }
- else if( teTool>TE_BRUSH_EDGE_START && teTool<TE_BRUSH_EDGE_END)
- {
- btBufferType=BT_EDGE_MAP;
- }
- else
- {
- return;
- }
- _puwBuffer=NULL;
- _srcExtraW=0;
- _srcExtraH=0;
- if( teTool==TE_BRUSH_ALTITUDE_SMOOTH ||
- teTool==TE_BRUSH_ALTITUDE_FILTER ||
- teTool==TE_BRUSH_LAYER_SMOOTH ||
- teTool==TE_ALTITUDE_SMOOTH ||
- teTool==TE_ALTITUDE_FILTER ||
- teTool==TE_LAYER_SMOOTH ||
- teTool==TE_LAYER_FILTER)
- {
- _srcExtraW=2;
- _srcExtraH=2;
- }
- // extract source rectangle
- Point pt=Calculate2dHitPoint(ptrTerrain, vHitPoint);
- // perform operation on brush rect
- if(teTool==TE_TILE_PAINT)
- {
- _rect.rc_iLeft=pt.pt_iX;
- _rect.rc_iRight=_rect.rc_iLeft+1;
- _rect.rc_iTop=pt.pt_iY;
- _rect.rc_iBottom=_rect.rc_iTop+1;
- }
- else if(_ptdBrush!=NULL)
- {
- _rect.rc_iLeft=pt.pt_iX-ptdBrush->GetPixWidth()/2-_srcExtraW;
- _rect.rc_iRight=pt.pt_iX+(ptdBrush->GetPixWidth()-ptdBrush->GetPixWidth()/2)+_srcExtraW;
- _rect.rc_iTop=pt.pt_iY-ptdBrush->GetPixHeight()/2-_srcExtraH;
- _rect.rc_iBottom=pt.pt_iY+(ptdBrush->GetPixHeight()-ptdBrush->GetPixHeight()/2)+_srcExtraH;
- }
- // perform operation on whole terrain area
- else
- {
- _rect.rc_iLeft=0;
- _rect.rc_iRight=ptrTerrain->tr_pixHeightMapWidth;
- _rect.rc_iTop=0;
- _rect.rc_iBottom=ptrTerrain->tr_pixHeightMapHeight;
- }
- Rect rectTerrain;
- rectTerrain.rc_iLeft=0;
- rectTerrain.rc_iTop=0;
- rectTerrain.rc_iRight=ptrTerrain->tr_pixHeightMapWidth;
- rectTerrain.rc_iBottom=ptrTerrain->tr_pixHeightMapHeight;
- BOOL bAutoRememberUndo=FALSE;
- // if should apply undo for whole terrain
- if( (teTool>TE_ALTITUDE_START && teTool<TE_ALTITUDE_END) ||
- (teTool>TE_LAYER_START && teTool<TE_LAYER_END) ||
- (teTool==TE_GENERATE_TERRAIN) ||
- (teTool==TE_ALTITUDE_EQUALIZE) )
- {
- TerrainEditBegin();
- bAutoRememberUndo=TRUE;
- }
- // edit start, undo starts
- if(_bUndoStart)
- {
- _bUndoStart=FALSE;
- _btUndoBufferType=btBufferType;
- _iUndoBufferData=iBufferData;
- _rectUndo=_rect;
- _iTerrainEntityID=ptrTerrain->tr_penEntity->en_ulID;
- _puwUndoTerrain=GetBufferForEditing(ptrTerrain, rectTerrain, btBufferType, iBufferData);
- }
- // editing in progress, update undo data
- else
- {
- // update undo rect
- if(_rect.rc_iLeft < _rectUndo.rc_iLeft) _rectUndo.rc_iLeft=_rect.rc_iLeft;
- if(_rect.rc_iRight > _rectUndo.rc_iRight) _rectUndo.rc_iRight=_rect.rc_iRight;
- if(_rect.rc_iTop < _rectUndo.rc_iTop) _rectUndo.rc_iTop=_rect.rc_iTop;
- if(_rect.rc_iBottom > _rectUndo.rc_iBottom) _rectUndo.rc_iBottom=_rect.rc_iBottom;
- }
- // clamp undo rect to terrain size
- _rectUndo.rc_iLeft=Clamp(_rectUndo.rc_iLeft, rectTerrain.rc_iLeft, rectTerrain.rc_iRight);
- _rectUndo.rc_iRight=Clamp(_rectUndo.rc_iRight, rectTerrain.rc_iLeft, rectTerrain.rc_iRight);
- _rectUndo.rc_iTop=Clamp(_rectUndo.rc_iTop, rectTerrain.rc_iTop, rectTerrain.rc_iBottom);
- _rectUndo.rc_iBottom=Clamp(_rectUndo.rc_iBottom, rectTerrain.rc_iTop, rectTerrain.rc_iBottom);
- // obtain buffer
- _puwBuffer=GetBufferForEditing(ptrTerrain, _rect, btBufferType, iBufferData);
- switch( teTool)
- {
- case TE_BRUSH_ALTITUDE_PAINT:
- {
- ApplyAddPaint(MIN_UWORD,MAX_UWORD);
- break;
- }
- case TE_BRUSH_EDGE_ERASE:
- {
- _fStrength=-fStrength;
- ApplyAddPaint(MIN_UWORD,MAX_UWORD);
- break;
- }
- case TE_BRUSH_LAYER_PAINT:
- {
- _fStrength=fStrength*32.0f;
- ApplyAddPaint(MIN_UWORD,MAX_UWORD);
- break;
- }
- case TE_BRUSH_ALTITUDE_SMOOTH:
- case TE_BRUSH_LAYER_SMOOTH:
- case TE_ALTITUDE_SMOOTH:
- case TE_LAYER_SMOOTH:
- {
- _fStrength=fStrength*theApp.m_fSmoothPower;
- ApplyFilterMatrix(_afFilterBlurMore);
- break;
- }
- case TE_BRUSH_ALTITUDE_FILTER:
- case TE_BRUSH_LAYER_FILTER:
- case TE_LAYER_FILTER:
- case TE_ALTITUDE_FILTER:
- {
- _fStrength=fStrength*theApp.m_fFilterPower;
- switch(theApp.m_iFilter)
- {
- case FLT_FINEBLUR: ApplyFilterMatrix(_afFilterFineBlur ); break;
- case FLT_SHARPEN: ApplyFilterMatrix(_afFilterSharpen ); break;
- case FLT_EMBOSS: ApplyFilterMatrix(_afFilterEmboss ); break;
- case FLT_EDGEDETECT: ApplyFilterMatrix(_afFilterEdgeDetect ); break;
- }
- break;
- }
- case TE_BRUSH_ALTITUDE_MINIMUM:
- case TE_ALTITUDE_MINIMUM:
- {
- _fStrength=0;
- ApplyAddPaint(theApp.m_uwEditAltitude,MAX_UWORD);
- break;
- }
- case TE_BRUSH_ALTITUDE_MAXIMUM:
- case TE_ALTITUDE_MAXIMUM:
- {
- _fStrength=0;
- ApplyAddPaint(MIN_UWORD, theApp.m_uwEditAltitude);
- break;
- }
- case TE_BRUSH_ALTITUDE_FLATTEN:
- case TE_ALTITUDE_FLATTEN:
- {
- _fStrength=0;
- ApplyAddPaint(theApp.m_uwEditAltitude, theApp.m_uwEditAltitude);
- break;
- }
- case TE_BRUSH_ALTITUDE_POSTERIZE:
- case TE_ALTITUDE_POSTERIZE:
- {
- ApplyPosterize();
- break;
- }
- case TE_BRUSH_ALTITUDE_RND_NOISE:
- case TE_BRUSH_LAYER_RND_NOISE:
- case TE_ALTITUDE_RND_NOISE:
- case TE_LAYER_RND_NOISE:
- {
- ApplyRNDNoise();
- break;
- }
- case TE_BRUSH_ALTITUDE_CONTINOUS_NOISE:
- case TE_BRUSH_LAYER_CONTINOUS_NOISE:
- case TE_ALTITUDE_CONTINOUS_NOISE:
- case TE_LAYER_CONTINOUS_NOISE:
- {
- if(!SetupContinousNoiseTexture()) return;
- ApplyContinousNoise();
- FreeContinousNoiseTexture();
- break;
- }
- case TE_GENERATE_TERRAIN:
- {
- GenerateTerrain();
- break;
- }
- case TE_ALTITUDE_EQUALIZE:
- {
- EqualizeBuffer();
- break;
- }
- case TE_CLEAR_LAYER_MASK:
- {
- for(INDEX i=0; i<_rect.Width()*_rect.Height(); i++)
- {
- _puwBuffer[i]=0;
- }
- break;
- }
- case TE_FILL_LAYER_MASK:
- {
- for(INDEX i=0; i<_rect.Width()*_rect.Height(); i++)
- {
- _puwBuffer[i]=MAX_UWORD;
- }
- break;
- }
- case TE_TILE_PAINT:
- {
- TilePaintTool();
- break;
- }
- }
- // apply buffer change
- SetBufferForEditing(ptrTerrain, _puwBuffer, _rect, btBufferType, iBufferData);
- theApp.GetActiveDocument()->SetModifiedFlag( TRUE);
- FreeMemory(_puwBuffer);
- // mark rect for layer distribution updating
- if(teTool!=TE_TILE_PAINT)
- {
- DiscardLayerDistribution(_rect);
- }
- theApp.m_ctTerrainPageCanvas.MarkChanged();
- if(bAutoRememberUndo)
- {
- TerrainEditEnd();
- }
- }
|