/* 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. */ // TerrainInterface.cpp : implementation file // #include "stdafx.h" #include "WorldEditor.h" #include "TerrainInterface.h" #include #ifdef _DEBUG #undef new #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define RENDERED_BRUSH_SIZE_IN_METERS 32.0f #define CHANGE_ANGLE_SENSITIVITY (1.0f/1.0f) #define CHANGE_INDEX_SENSITIVITY (1.0f/16.0f) #define CHANGE_NORMALIZED_SENSITIVITY (1.0f/100.0f) #define CHANGE_PREASSURE_SENSITIVITY (1.0f) #define CHANGE_OFFSET_SENSITIVITY 0.1f #define CHANGE_STRETCH_SENSITIVITY 1.0f #define LAYER_START_X 48 #define LAYER_HEIGHT 48 #define LAYER_SPACING_V PIX(4) #define COL_ODD_LAYERS (RGBToColor(25,25,30)|CT_OPAQUE) #define COL_EVEN_LAYERS (RGBToColor(40,40,50)|CT_OPAQUE) COLOR _colSelectedLayerBcg=0x500000FF; #define COL_SELECTED_LAYER _colSelectedLayerBcg #define SLIDER_WIDTH 12 #define SLIDER_HOLDER_HEIGHT 32 #define COL_DEFAULT_ITEM (C_YELLOW|CT_OPAQUE) #define COL_SETTINGS (C_vlBLUE|CT_OPAQUE) #define COL_SEPARATOR (C_WHITE|CT_OPAQUE) static FLOAT _fScrollLayers=0; INDEX _iGenerateForLayer; Rect _rectInvalid; CUpdateableRT _udAutoGenerateDistribution; CChangeableRT _chAutoGenerateDistribution; CTerrain *_ptrLastEditedTerrain=NULL; CTerrainEditBrush atebDefaultEditBrushValues[]= { {0,1}, {0,2}, {0,4}, {0,6}, {0,8}, {0,12}, {0,16}, {0,24}, {0,32}, {0,40}, {0,52}, {0,63}, {1,1}, {2,2}, {4,4}, {6,6}, {8,8}, {12,12}, {16,16}, {24,24}, {32,32}, {40,40}, {52,52}, {63,63}, {2,4}, {3,6}, {4,8}, {6,12}, {8,16}, {12,24}, {16,32}, {32,63}, }; CTerrainEditBrush atebCustomEditBrushes[CT_BRUSHES]; static CTextureObject _toIcons; static CDynamicContainer dcButtons; void GenerateTerrainBrushTexture( INDEX iBrush, FLOAT fHotSpot, FLOAT fFallOff); ///////////////////////////////////////////////////////////////////////////// // CTerrainInterface static CTString _strToolTip; static void GetToolTipText(void *pTerrainInterface, char *pToolTipText) { pToolTipText+= sprintf(pToolTipText, "%s", _strToolTip); } CTFileName GetBrushTextureName(INDEX iBrush) { CTString strBrushFile; strBrushFile.PrintF("Textures\\Editor\\TerrainBrush%02d.tex", iBrush); return strBrushFile; } void CTerrainInterface::HideCursor(void) { RECT rect; GetClientRect( &rect); ClientToScreen( &rect); ClipCursor(&rect); while (ShowCursor(FALSE)>=0); } void CTerrainInterface::UnhideCursor(void) { ClipCursor(NULL); while (ShowCursor(TRUE)<0); } void GetButtonOffset(CTIButton &tib, PIX &pixOffsetX, PIX &pixOffsetY) { if(tib.tib_iLayer!=-1) { CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; pixOffsetX=LAYER_START_X; pixOffsetY=(ptrTerrain->tr_atlLayers.Count()-1-tib.tib_iLayer)*LAYER_HEIGHT-_fScrollLayers; } } #define TERRAIN_SURFACE_VER "V002" void LoadSurface(CTFileName fnSurface) { CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; try { CTFileStream strmFile; strmFile.Open_t( fnSurface); strmFile.ExpectID_t( CChunkID( "TRSF")); // terrain surface // check version number if( !( CChunkID(TERRAIN_SURFACE_VER) == strmFile.GetID_t()) ) { throw( "Invalid version of terrain surface file. Unable to load"); } INDEX ctLayers=ptrTerrain->tr_atlLayers.Count(); for(INDEX iDelLayer=0; iDelLayerRemoveLayer(0, FALSE); } ptrTerrain->tr_atlLayers[0].ResetLayerMask(0xFF); ctLayers=0; strmFile>>ctLayers; for( INDEX iLayer=0; iLayer>fnTexture; // check if texture exists if(!FileExists( fnTexture)) { fnTexture=CTFILENAME("Textures\\Editor\\Default.tex"); } CTerrainLayer *ptlLayer=&ptrTerrain->tr_atlLayers[0]; if( iLayer!=0) { ptlLayer=&ptrTerrain->AddLayer_t(fnTexture, LT_NORMAL, FALSE); } else { ptlLayer->SetLayerTexture_t(fnTexture); } // load surface strmFile>>ptlLayer->tl_fRotateX; strmFile>>ptlLayer->tl_fRotateY; strmFile>>ptlLayer->tl_fStretchX; strmFile>>ptlLayer->tl_fStretchY; strmFile>>ptlLayer->tl_fOffsetX; strmFile>>ptlLayer->tl_fOffsetY; strmFile>>ptlLayer->tl_bAutoRegenerated; strmFile>>ptlLayer->tl_fCoverage; strmFile>>ptlLayer->tl_fCoverageNoise; strmFile>>ptlLayer->tl_fCoverageRandom; strmFile>>ptlLayer->tl_bApplyMinAltitude; strmFile>>ptlLayer->tl_fMinAltitude; strmFile>>ptlLayer->tl_fMinAltitudeFade; strmFile>>ptlLayer->tl_fMinAltitudeNoise; strmFile>>ptlLayer->tl_fMinAltitudeRandom; strmFile>>ptlLayer->tl_bApplyMaxAltitude; strmFile>>ptlLayer->tl_fMaxAltitude; strmFile>>ptlLayer->tl_fMaxAltitudeFade; strmFile>>ptlLayer->tl_fMaxAltitudeNoise; strmFile>>ptlLayer->tl_fMaxAltitudeRandom; strmFile>>ptlLayer->tl_bApplyMinSlope; strmFile>>ptlLayer->tl_fMinSlope; strmFile>>ptlLayer->tl_fMinSlopeFade; strmFile>>ptlLayer->tl_fMinSlopeNoise; strmFile>>ptlLayer->tl_fMinSlopeRandom; strmFile>>ptlLayer->tl_bApplyMaxSlope; strmFile>>ptlLayer->tl_fMaxSlope; strmFile>>ptlLayer->tl_fMaxSlopeFade; strmFile>>ptlLayer->tl_fMaxSlopeNoise; strmFile>>ptlLayer->tl_fMaxSlopeRandom; strmFile>>ptlLayer->tl_colMultiply; } strmFile.Close(); } catch( char *strError) { WarningMessage(strError); return; } GenerateLayerDistribution(-1); theApp.m_ctTerrainPage.MarkChanged(); ptrTerrain->RefreshTerrain(); } void SaveSurface(CTFileName fnSurface) { CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; try { CTFileStream strmFile; strmFile.Create_t( fnSurface); strmFile.WriteID_t( CChunkID( "TRSF")); // terrain surface // write version number strmFile.WriteID_t(TERRAIN_SURFACE_VER); INDEX ctLayers=ptrTerrain->tr_atlLayers.Count(); strmFile<tr_atlLayers[iLayer]; if(ptlLayer->tl_ptdTexture==NULL) continue; CTFileName fnTexture=ptlLayer->tl_ptdTexture->GetName(); strmFile<tl_fRotateX; strmFile<tl_fRotateY; strmFile<tl_fStretchX; strmFile<tl_fStretchY; strmFile<tl_fOffsetX; strmFile<tl_fOffsetY; strmFile<tl_bAutoRegenerated; strmFile<tl_fCoverage; strmFile<tl_fCoverageNoise; strmFile<tl_fCoverageRandom; strmFile<tl_bApplyMinAltitude; strmFile<tl_fMinAltitude; strmFile<tl_fMinAltitudeFade; strmFile<tl_fMinAltitudeNoise; strmFile<tl_fMinAltitudeRandom; strmFile<tl_bApplyMaxAltitude; strmFile<tl_fMaxAltitude; strmFile<tl_fMaxAltitudeFade; strmFile<tl_fMaxAltitudeNoise; strmFile<tl_fMaxAltitudeRandom; strmFile<tl_bApplyMinSlope; strmFile<tl_fMinSlope; strmFile<tl_fMinSlopeFade; strmFile<tl_fMinSlopeNoise; strmFile<tl_fMinSlopeRandom; strmFile<tl_bApplyMaxSlope; strmFile<tl_fMaxSlope; strmFile<tl_fMaxSlopeFade; strmFile<tl_fMaxSlopeNoise; strmFile<tl_fMaxSlopeRandom; strmFile<tl_colMultiply; } strmFile.Close(); } catch( char *strError) { WarningMessage(strError); return; } } void PointToIconSpace(CPoint &pt, CTIButton *ptib) { PIX pixOffsetX=0; PIX pixOffsetY=0; GetButtonOffset(*ptib, pixOffsetX, pixOffsetY); PIX x=ptib->tib_fx+pixOffsetX; PIX y=ptib->tib_fy+pixOffsetY; pt.x=Clamp(pt.x-x, INDEX(0), INDEX(ptib->tib_fdx)); pt.y=Clamp(pt.y-y, INDEX(0), INDEX(ptib->tib_fdy)); } void PointToScreenSpace(CPoint &pt, CDrawPort *pdp) { HWND hWnd=pdp->dp_Raster->ra_pvpViewPort->vp_hWnd; ClientToScreen(hWnd, &pt); } PIXaabbox2D GetButtonScreenBox(CTIButton &tib) { PIX pixOffsetX=0; PIX pixOffsetY=0; GetButtonOffset(tib, pixOffsetX, pixOffsetY); PIX x=tib.tib_fx+pixOffsetX; PIX y=tib.tib_fy+pixOffsetY; PIX dx=tib.tib_fdx; PIX dy=tib.tib_fdy; PIXaabbox2D boxScreen=PIXaabbox2D( PIX2D(x,y), PIX2D(x+dx, y+dy)); return boxScreen; } void GenerateDefaultBrush(INDEX iBrush) { atebCustomEditBrushes[iBrush].teb_fHotSpot=atebDefaultEditBrushValues[iBrush].teb_fHotSpot; atebCustomEditBrushes[iBrush].teb_fFallOff=atebDefaultEditBrushValues[iBrush].teb_fFallOff; GenerateTerrainBrushTexture( iBrush, atebCustomEditBrushes[iBrush].teb_fHotSpot-0.1f, atebCustomEditBrushes[iBrush].teb_fFallOff-0.1f); } void SetDefaultEditBrushes(void) { for(INDEX iBrush=0; iBrushObtain_t(fnBrush); } catch(char *strError) { (void) strError; } } } } CTerrainInterface::CTerrainInterface() { m_pDrawPort = NULL; m_pViewPort = NULL; _fScrollLayers=0; _udAutoGenerateDistribution.MarkUpdated(); } CTerrainInterface::~CTerrainInterface() { } BEGIN_MESSAGE_MAP(CTerrainInterface, CWnd) //{{AFX_MSG_MAP(CTerrainInterface) ON_WM_PAINT() ON_WM_DESTROY() ON_WM_LBUTTONDOWN() ON_WM_MOUSEMOVE() ON_WM_LBUTTONUP() ON_WM_RBUTTONDOWN() ON_WM_RBUTTONUP() ON_WM_LBUTTONDBLCLK() ON_WM_DROPFILES() ON_WM_CREATE() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CTerrainInterface message handlers void CTerrainInterface::OnPaint() { #if ALLOW_TERRAINS { CPaintDC dc(this); } if( (m_pViewPort == NULL) && (m_pDrawPort == NULL) ) { // initialize canvas for active texture button _pGfx->CreateWindowCanvas( m_hWnd, &m_pViewPort, &m_pDrawPort); } // if there is a valid drawport, and the drawport can be locked if( (m_pDrawPort != NULL) && (m_pDrawPort->Lock()) ) { if(dcButtons.Count()==0 || GetTerrain()!=_ptrLastEditedTerrain) { InitializeInterface(m_pDrawPort); _ptrLastEditedTerrain=GetTerrain(); } PIXaabbox2D rectPict; rectPict = PIXaabbox2D( PIX2D(0, 0), PIX2D(m_pDrawPort->GetWidth(), m_pDrawPort->GetHeight())); // clear texture area to black m_pDrawPort->Fill( C_BLACK | CT_OPAQUE); // erase z-buffer m_pDrawPort->FillZBuffer(ZBUF_BACK); RenderInterface(m_pDrawPort); // unlock the drawport m_pDrawPort->Unlock(); if (m_pViewPort!=NULL) { m_pViewPort->SwapBuffers(); } } #endif } void CTerrainInterface::RenderInterface(CDrawPort *pdp) { #if ALLOW_TERRAINS // render terrain interface buttons FOREACHINDYNAMICCONTAINER( dcButtons, CTIButton, ittib) { CTIButton &tib=*ittib; PIX pixOffsetX=0; PIX pixOffsetY=0; GetButtonOffset(tib, pixOffsetX, pixOffsetY); if( tib.tib_pPreRender!=NULL) tib.tib_pPreRender(&tib, pdp); PIX x=tib.tib_fx+pixOffsetX; PIX y=tib.tib_fy+pixOffsetY; PIX dx=tib.tib_fdx; PIX dy=tib.tib_fdy; // bcg icon fill if( tib.tib_colFill&0xFF) { if(pdp->Lock()) { pdp->Fill(x,y,dx,dy, tib.tib_colFill); pdp->Unlock(); } } // icon texture if( tib.tib_iIcon!=-1) { PIXaabbox2D boxScreen=PIXaabbox2D( PIX2D(x,y), PIX2D(x+dx, y+dy)); MEXaabbox2D boxTexture=MEXaabbox2D( MEX2D(16*tib.tib_iIcon,0), MEX2D(16*tib.tib_iIcon+16,16)); COLOR colMultiply=C_WHITE|CT_OPAQUE; if(tib.tib_pIsEnabled!=NULL && !tib.tib_pIsEnabled(&tib)) { colMultiply=C_dGRAY|CT_OPAQUE; } pdp->PutTexture( &_toIcons, boxScreen, boxTexture, colMultiply); } // custom render if(tib.tib_pOnRender!=NULL) tib.tib_pOnRender(&tib, pdp); // icon border if( tib.tib_colBorderColor&0xFF) { if(pdp->Lock()) { pdp->DrawBorder(x,y,dx,dy, tib.tib_colBorderColor); pdp->Unlock(); } } } #endif } PIXaabbox2D GetLayersBox(CDrawPort *pdp) { return PIXaabbox2D( PIX2D(LAYER_START_X,0), PIX2D(pdp->GetWidth()-LAYER_START_X, pdp->GetHeight())); } PIX2D GetLayerSize(CDrawPort *pdp) { return PIX2D(pdp->GetWidth()-LAYER_START_X, LAYER_HEIGHT); } void CTerrainInterface::OnDestroy() { CWnd::OnDestroy(); if( m_pViewPort != NULL) { _pGfx->DestroyWindowCanvas( m_pViewPort); m_pViewPort = NULL; } m_pViewPort = NULL; m_pDrawPort = NULL; } void GenerateTerrainBrushTexture( INDEX iBrush, FLOAT fHotSpot, FLOAT fFallOff) { #if ALLOW_TERRAINS INDEX iLog2=INDEX(ceil(Log2(fFallOff*2+2))); PIX pixSize=1UL<<(iLog2+1); FLOAT fcx=pixSize/2.0f; FLOAT fcy=pixSize/2.0f; CImageInfo ii; ii.ii_Width=pixSize; ii.ii_Height=pixSize; ii.ii_BitsPerPixel=32; ii.ii_Picture=(UBYTE*) AllocMemory(ii.ii_Width*ii.ii_Height*ii.ii_BitsPerPixel/8); COLOR *pcol=(COLOR *)ii.ii_Picture; for(INDEX iy=0; iyfFallOff) fcolPower=0.0f; else if(fDist>fHotSpot) { fcolPower=CalculateRatio(fDist, fHotSpot, fFallOff, 0.0f, 1.0f); fcolPower=1.0f-(1.0f-fcolPower)*(1.0f-fcolPower); } UBYTE ubCol=fcolPower*255.0f; COLOR col=RGBToColor(ubCol,ubCol,ubCol)|CT_OPAQUE; *pcol=ByteSwap(col); pcol++; } } CTextureData tdBrush; try { tdBrush.Create_t( &ii, pixSize, 16, TRUE); CTString strBrushFile; strBrushFile.PrintF("Textures\\Editor\\TerrainBrush%02d.tex", iBrush); tdBrush.Save_t( strBrushFile); tdBrush.Reload(); } catch( char *strError) { (void) strError; WarningMessage("Unable to create terrain brush texture!"); } #endif } CTIButton::CTIButton() { tib_fx=0.0f; tib_fy=0.0f; tib_fdx=0.0f; tib_fdy=0.0f; tib_iIcon=-1; tib_colBorderColor=0; tib_fDataMin=0.0f; tib_fDataMax=0.0f; tib_bWrapData=TRUE; tib_fDataDelta=0.0f; tib_pfData1=NULL; tib_pfData2=NULL; tib_iLayer=-1; tib_strToolTip="Unknown tool tip"; tib_pPreRender=NULL; tib_pOnRender=NULL; tib_pOnLeftClick=NULL; tib_pOnLeftClickMove=NULL; tib_pOnRightClick=NULL; tib_pOnRightClickMove=NULL; tib_pOnDropFiles=NULL; tib_pGetClickMoveData=NULL; tib_pIsEnabled=NULL; tib_bMouseTrapForMove=TRUE; tib_bContinueTesting=FALSE; } CTIButton *AddButton(CDynamicContainer &dc, FLOAT x, FLOAT y, FLOAT dx, FLOAT dy, INDEX iLayer, INDEX iIcon, CTString strToolTip, COLOR colBorder=C_RED|CT_TRANSPARENT, COLOR colFill=C_BLACK|CT_TRANSPARENT) { CTIButton &tib=*(new CTIButton); tib.tib_fx=x; tib.tib_fy=y; tib.tib_fdx=dx; tib.tib_fdy=dy; tib.tib_iLayer=iLayer; tib.tib_iIcon=iIcon; tib.tib_strToolTip=strToolTip; tib.tib_colBorderColor=colBorder; tib.tib_colFill=colFill; dc.Add(&tib); return &tib; } void CTIButton::SetData( FLOAT fDataMin, FLOAT fDataMax, FLOAT fDataDelta, BOOL bWrap/*=FALSE*/, FLOAT *pfData1/*=NULL*/, FLOAT *pfData2/*=NULL*/) { tib_fDataMin=fDataMin; tib_fDataMax=fDataMax; tib_fDataDelta=fDataDelta; tib_bWrapData=bWrap; tib_pfData1=pfData1; tib_pfData2=pfData2; } void CTIButton::SetFunctions( void (*pOnRender)(CTIButton *ptib, CDrawPort *pdp)/*=NULL*/, void (*pOnLeftClick)(CTIButton *ptib, CPoint pt, CDrawPort *pdp)/*=NULL*/, void (*pOnLeftClickMove)(CTIButton *ptib, FLOAT fdx, FLOAT fdy, CDrawPort *pdp)/*=NULL*/, void (*pOnRightClick)(CTIButton *ptib, CPoint pt, CDrawPort *pdp)/*=NULL*/, void (*pOnRightClickMove)(CTIButton *ptib, FLOAT fdx, FLOAT fdy, CDrawPort *pdp)/*=NULL*/, void (*pPreRender)(CTIButton *ptib, CDrawPort *pdp)/*=NULL*/) { tib_pOnRender=pOnRender; tib_pOnLeftClick=pOnLeftClick; tib_pOnLeftClickMove=pOnLeftClickMove; tib_pOnRightClick=pOnRightClick; tib_pOnRightClickMove=pOnRightClickMove; tib_pPreRender=pPreRender; } void RenderBrushNo(CTIButton *ptib, CDrawPort *pdp) { pdp->SetFont( _pfdConsoleFont); pdp->SetTextAspect( 1.0f); pdp->SetTextScaling( 1.0f); CTString strText; strText.PrintF("%d", INDEX(theApp.m_fCurrentTerrainBrush)); pdp->PutTextC( strText, ptib->tib_fx+ptib->tib_fdx/2, ptib->tib_fy+4, C_YELLOW|CT_OPAQUE); } void RenderBrushShape( INDEX iBrush, PIXaabbox2D rect, CDrawPort *pdp) { CDrawPort dpBrush=CDrawPort(pdp, rect); CTextureObject to; CTString strBrushFile; strBrushFile.PrintF("Textures\\Editor\\TerrainBrush%02d.tex", iBrush); try { to.SetData_t(strBrushFile); CTextureData *ptd=(CTextureData *)to.GetData(); if( dpBrush.Lock()) { dpBrush.Fill(C_BLACK|CT_OPAQUE); PIX pixTexW=ptd->GetPixWidth(); PIX pixTexH=ptd->GetPixHeight(); FLOAT fScreenW=dpBrush.GetWidth()*pixTexW/RENDERED_BRUSH_SIZE_IN_METERS; FLOAT fScreenH=dpBrush.GetHeight()*pixTexH/RENDERED_BRUSH_SIZE_IN_METERS; PIXaabbox2D rectPic; rectPic = PIXaabbox2D( PIX2D(dpBrush.GetWidth()/2.0f-fScreenW/2.0f, dpBrush.GetHeight()/2.0f-fScreenH/2.0f), PIX2D(dpBrush.GetWidth()/2.0f-fScreenW/2.0f+fScreenW, dpBrush.GetHeight()/2.0f-fScreenH/2.0f+fScreenH)); dpBrush.PutTexture( &to, rectPic); dpBrush.Unlock(); } } catch( char *strError) { (void) strError; } } void RenderBrushShape(CTIButton *ptib, CDrawPort *pdp) { INDEX iBrush=INDEX(theApp.m_fCurrentTerrainBrush); CTerrainEditBrush &teb=atebCustomEditBrushes[iBrush]; PIXaabbox2D rectButton = PIXaabbox2D( PIX2D(ptib->tib_fx, ptib->tib_fy), PIX2D(ptib->tib_fx+ptib->tib_fdx, ptib->tib_fy+ptib->tib_fdy)); RenderBrushShape(iBrush,rectButton,pdp); } void RenderBrushPressure(CTIButton *ptib, CDrawPort *pdp) { pdp->SetFont( _pfdConsoleFont); pdp->SetTextAspect( 1.0f); pdp->SetTextScaling( 1.0f); CTString strText; strText.PrintF("%d%%", INDEX(theApp.m_fTerrainBrushPressure/1024.0f*100.0f)); pdp->PutTextC( strText, ptib->tib_fx+ptib->tib_fdx/2, ptib->tib_fy, C_YELLOW|CT_OPAQUE); } void RenderLayerTexture(CTIButton *ptib, CDrawPort *pdp) { INDEX iLayer=ptib->tib_iLayer; CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer!=NULL && ptlLayer->tl_ptdTexture!=NULL) { CTextureObject to; to.SetData(ptlLayer->tl_ptdTexture); PIXaabbox2D boxScreen=GetButtonScreenBox(*ptib); pdp->PutTexture( &to, boxScreen); } } void RenderLayerBcg(CTIButton *ptib, CDrawPort *pdp) { INDEX iLayer=ptib->tib_iLayer; CTIButton &tib=*ptib; PIX pixOffsetX=0; PIX pixOffsetY=0; GetButtonOffset(tib, pixOffsetX, pixOffsetY); if( tib.tib_pPreRender!=NULL) tib.tib_pPreRender(&tib, pdp); PIX x=tib.tib_fx+pixOffsetX; PIX y=tib.tib_fy+pixOffsetY; PIX dx=tib.tib_fdx; PIX dy=tib.tib_fdy; COLOR colBcg=C_WHITE|CT_OPAQUE; if( tib.tib_iLayer==GetLayerIndex()) colBcg=COL_SELECTED_LAYER; else if( iLayer&1) colBcg=COL_ODD_LAYERS; else colBcg=COL_EVEN_LAYERS; if(pdp->Lock()) { pdp->Fill(x,y,dx,dy, colBcg); pdp->Unlock(); } } void RenderLayerMask(CTIButton *ptib, CDrawPort *pdp) { INDEX iLayer=ptib->tib_iLayer; CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer!=NULL && ptlLayer->tl_ptdTexture!=NULL) { CTextureObject to; CTextureData *ptd=ptlLayer->GetThumbnail(64,64); to.SetData(ptd); PIXaabbox2D boxScreen=GetButtonScreenBox(*ptib); pdp->PutTexture( &to, boxScreen); } } void GetBrushModeInfo(INDEX iMode, INDEX &iIcon, CTString &strText) { strText="Unknown"; iIcon=0; switch(INDEX (iMode)) { case TBM_PAINT: { strText="Paint (J)"; if(INDEX(theApp.m_iTerrainEditMode)==TEM_HEIGHTMAP) iIcon=12; else iIcon=8; break; } case TBM_SMOOTH: strText="Smooth tool (O)"; iIcon=10; break; case TBM_FILTER: strText="Filter tool (F)"; iIcon=30; break; case TBM_MINIMUM: strText="Limit down (M)"; iIcon=27; break; case TBM_MAXIMUM: strText="Limit up (X)"; iIcon=11; break; case TBM_FLATTEN: strText="Flatten (=)"; iIcon=18; break; case TBM_POSTERIZE: strText="Posterize (;)"; iIcon=28; break; case TBM_RND_NOISE: strText="Random noise (K)"; iIcon=21; break; case TBM_CONTINOUS_NOISE: strText="Texture noise (Y)"; iIcon=31; break; case TBM_ERASE: strText="Erase (D)"; iIcon=9; break; } } void UpdateEditModeIcon(CTIButton *ptib, CDrawPort *pdp) { if(INDEX(theApp.m_iTerrainEditMode)==TEM_HEIGHTMAP) ptib->tib_iIcon=20; else ptib->tib_iIcon=19; } void UpdateBrushModeIcon(CTIButton *ptib, CDrawPort *pdp) { INDEX iIcon; CTString strText; GetBrushModeInfo(INDEX(theApp.m_iTerrainBrushMode), iIcon, strText); ptib->tib_iIcon=iIcon; } void UpdateLayerVisibleFlag(CTIButton *ptib, CDrawPort *pdp) { INDEX iLayer=ptib->tib_iLayer; CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer!=NULL) { if( ptlLayer->tl_bVisible) ptib->tib_iIcon=3; else ptib->tib_iIcon=4; } } void UpdatePressure(CTIButton *ptib, CDrawPort *pdp) { if(theApp.m_fTerrainBrushPressureEnum>=0) { theApp.m_fTerrainBrushPressure=(theApp.m_fTerrainBrushPressureEnum+1)/10.0f*1024.0f+1; theApp.m_fTerrainBrushPressureEnum=-1; } } void SetAsActiveLayer(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { SelectLayer(ptib->tib_iLayer); CWorldEditorDoc* pDoc = theApp.GetActiveDocument(); if(pDoc!=NULL) { pDoc->m_chSelections.MarkChanged(); } } void ApplyLayerCommand(INDEX iSelectedItem) { CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; CTerrainLayer *ptlLayer=GetLayer(); INDEX iLayer=GetLayerIndex(); if(ptlLayer!=NULL) { switch( iSelectedItem) { case 0: // "Delete layer" { if(ptrTerrain->tr_atlLayers.Count()>1) { if( ::MessageBoxA( pMainFrame->m_hWnd, "Are you sure that you want to delete this layer?", "Warning !", MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON1| MB_SYSTEMMODAL | MB_TOPMOST) == IDYES) { ptrTerrain->RemoveLayer(iLayer); if(GetLayerIndex()>=ptrTerrain->tr_atlLayers.Count()) { SelectLayer(ptrTerrain->tr_atlLayers.Count()-1); } } } break; } case 1: // "Insert texture layer" { try { ptrTerrain->AddLayer_t( CTFILENAME("Textures\\Editor\\Default.tex")); SelectLayer( ptrTerrain->tr_atlLayers.Count()-1); } catch(char *strError) { WarningMessage("Unable to obtain default texture for new texture layer!\nError: %s", strError); } break; } case 4: // "Insert tile layer" { try { ptrTerrain->AddLayer_t( CTFILENAME("Textures\\Editor\\Default.tex"), LT_TILE); SelectLayer( ptrTerrain->tr_atlLayers.Count()-1); } catch(char *strError) { WarningMessage("Unable to obtain default texture for new tile layer!\nError: %s", strError); } break; } case 2: // "Move up" { if(iLayertr_atlLayers.Count()-1) { ptrTerrain->SetLayerIndex( iLayer, iLayer+1); SelectLayer(iLayer+1); } break; } case 3: // "Move down" { if(iLayer>0) { ptrTerrain->SetLayerIndex( iLayer, iLayer-1); SelectLayer(iLayer-1); } break; } } } theApp.m_ctTerrainPage.MarkChanged(); } void DisplayLayerTexture(INDEX iLayer) { CWndDisplayTexture *pDisplay=new CWndDisplayTexture; CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer!=NULL && ptlLayer->tl_ptdTexture!=NULL) { POINT pt; GetCursorPos(&pt); CTString strText1=ptlLayer->tl_ptdTexture->GetName(); CTString strText2=ptlLayer->tl_ptdTexture->GetDescription(); pDisplay->Initialize(pt.x, pt.y, ptlLayer->tl_ptdTexture, strText1, strText2); } } void ApplyLayerTextureCommand(INDEX iSelectedItem) { CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; CTerrainLayer *ptlLayer=GetLayer(); INDEX iLayer=GetLayerIndex(); if(ptlLayer!=NULL) { switch( iSelectedItem) { case 0: // "Create izohipse textutre" { CTFileName fnGradient=_EngineGUI.FileRequester( "Select izohipse gradient", FILTER_TEX FILTER_ALL FILTER_END, "Texture directory", "Textures\\"); if( fnGradient=="") return; CTextureData *ptdGradient; try { ptdGradient=_pTextureStock->Obtain_t( fnGradient); ptdGradient->Force(TEX_STATIC|TEX_CONSTANT); } catch( char *strError) { (void) strError; WarningMessage("Unable to obtain izohipse gradient texture!"); return; } CTFileName fnIzohipseTexture=_EngineGUI.FileRequester( "Choose name for izohipse texture", FILTER_TEX FILTER_ALL FILTER_END, "Texture directory", "Textures\\"); if( fnIzohipseTexture=="") return; INDEX iHMWidth=ptrTerrain->tr_pixHeightMapWidth; INDEX iHMHeight=ptrTerrain->tr_pixHeightMapHeight; CImageInfo ii; ii.ii_Width=iHMWidth-1; ii.ii_Height=iHMHeight-1; ii.ii_BitsPerPixel=32; ii.ii_Picture=(UBYTE*) AllocMemory(ii.ii_Width*ii.ii_Height*ii.ii_BitsPerPixel/8); COLOR *pcol=(COLOR *)ii.ii_Picture; INDEX iGradientHeight=ptdGradient->GetPixHeight(); UWORD *puw=ptrTerrain->tr_auwHeightMap; if(puw==NULL) return; for( INDEX iy=0; iyGetTexel(0,iGradPix1); COLOR colPix2=ptdGradient->GetTexel(0,iGradPix2); FLOAT fLerpFactor=iGradientHeight*fHeightRatio-INDEX(iGradientHeight*fHeightRatio); COLOR colResult=LerpColor(colPix1,colPix2,fLerpFactor); *(pcol+iy*ii.ii_Width+ix)=ByteSwap(colResult); } } _pTextureStock->Release(ptdGradient); CTextureData tdIzohipse; try { tdIzohipse.Create_t( &ii, 1024, 16, TRUE); tdIzohipse.Save_t( fnIzohipseTexture); ptlLayer->SetLayerTexture_t(fnIzohipseTexture); ptlLayer->tl_fStretchX=1.0f/ptrTerrain->tr_vTerrainSize(1); ptlLayer->tl_fStretchY=1.0f/ptrTerrain->tr_vTerrainSize(2); } catch( char *strError) { (void) strError; WarningMessage("Unable to save izohipse texture!"); return; } ptrTerrain->RefreshTerrain(); theApp.m_ctTerrainPage.MarkChanged(); break; } case 1: // "Browse texture" { CTFileName fnTexture=_EngineGUI.FileRequester( "Browse texture", FILTER_TEX FILTER_ALL FILTER_END, "Texture directory", "Textures\\"); if( fnTexture=="") return; try { ptlLayer->SetLayerTexture_t(fnTexture); theApp.m_ctTerrainPageCanvas.MarkChanged(); ptrTerrain->RefreshTerrain(); } catch(char *strError) { (void) strError; } break; } case 2: // "View layer texture" { DisplayLayerTexture(iLayer); } } } } void DisplayLayerMask(INDEX iLayer) { CWndDisplayTexture *pDisplay=new CWndDisplayTexture; CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer!=NULL && ptlLayer->tl_ptdTexture!=NULL) { CTextureData *ptd=ptlLayer->GetThumbnail(ptlLayer->tl_iMaskWidth-1,ptlLayer->tl_iMaskHeight-1); POINT pt; GetCursorPos(&pt); CTString strText1; strText1.PrintF("%dx%d",ptlLayer->tl_iMaskWidth-1, ptlLayer->tl_iMaskHeight-1); pDisplay->Initialize(pt.x, pt.y, ptd, strText1); } } void ApplyLayerMaskCommand(INDEX iSelectedItem) { CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; CTerrainLayer *ptlLayer=GetLayer(); INDEX iLayer=GetLayerIndex(); if(ptlLayer!=NULL) { switch( iSelectedItem) { case 0: // "Fill mask" { if( ::MessageBoxA( pMainFrame->m_hWnd, "Are you sure that you want to fill this layer's mask?", "Warning !", MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON1| MB_SYSTEMMODAL | MB_TOPMOST) == IDYES) { EditTerrain(NULL, FLOAT3D(0,0,0), 1.0f, TE_FILL_LAYER_MASK); } break; } case 1: // "Clear mask" { if( ::MessageBoxA( pMainFrame->m_hWnd, "Are you sure that you want to clear this layer's mask?", "Warning !", MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON1| MB_SYSTEMMODAL | MB_TOPMOST) == IDYES) { EditTerrain(NULL, FLOAT3D(0,0,0), 1.0f, TE_CLEAR_LAYER_MASK); } break; } case 2: // "Import mask" { CTFileName fnMaskMap=_EngineGUI.FileRequester( "Import layer mask", FILTER_TGA FILTER_PCX FILTER_ALL FILTER_END, "Layer mask directory", "Textures\\"); if( fnMaskMap=="") return; try { ptlLayer->ImportLayerMask_t(fnMaskMap); ptrTerrain->RefreshTerrain(); pMainFrame->Invalidate(FALSE); theApp.GetActiveDocument()->SetModifiedFlag( TRUE); } catch(char *strError) { AfxMessageBox( CString(strError)); } break; } case 3: // "Export mask" { CTFileName fnMaskMap=_EngineGUI.FileRequester( "Export layer mask", FILTER_TGA FILTER_PCX FILTER_ALL FILTER_END, "Layer mask directory", "Textures\\"); if( fnMaskMap=="") return; try { ptlLayer->ExportLayerMask_t(fnMaskMap); ptrTerrain->RefreshTerrain(); pMainFrame->Invalidate(FALSE); } catch(char *strError) { AfxMessageBox( CString(strError)); } break; } case 4: // noise { EditTerrain(NULL, FLOAT3D(0,0,0), 1.0f, TE_LAYER_RND_NOISE); break; } case 5: // "View mask" { DisplayLayerMask(iLayer); } } theApp.m_ctTerrainPageCanvas.MarkChanged(); } } void PickLayerColor(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { INDEX iLayer=ptib->tib_iLayer; CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer==NULL) return; CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); COLORREF colMfc=CLRF_CLR( ptlLayer->tl_colMultiply); if( MyChooseColor( colMfc, *pMainFrame)) { ptlLayer->tl_colMultiply=CLR_CLRF( colMfc) | ptlLayer->tl_colMultiply&0x000000FF; } } void NumericAlpha(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { INDEX iLayer=ptib->tib_iLayer; CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer==NULL) return; CDlgNumericAlpha dlgNumericAlpha( ptlLayer->tl_colMultiply&0xFF); if( dlgNumericAlpha.DoModal() == IDOK) { ptlLayer->tl_colMultiply&=0xFFFFFF00; ptlLayer->tl_colMultiply|=(dlgNumericAlpha.m_iAlpha&0xFF); } } void InvokeLayerOptions(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { INDEX iLayer=ptib->tib_iLayer; if(iLayer==-1) return; CDlgEditTerrainLayer dlg; if( dlg.DoModal()==IDOK) { GenerateLayerDistribution(iLayer); } } void PickSelectedLayerBcgColor(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { PointToScreenSpace(pt, pdp); CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); pMainFrame->CustomColorPicker( pt.x-50, pt.y); COLORREF TmpColor = CLRF_CLR( _colSelectedLayerBcg); if( MyChooseColor( TmpColor, *pMainFrame)) { _colSelectedLayerBcg = CLR_CLRF( TmpColor)|CT_OPAQUE; } theApp.m_ctTerrainPageCanvas.MarkChanged(); } INDEX InsertItemMacro( CCustomComboWnd *pCC, CTString strText, INDEX iIcon=-1, INDEX iValue=-1, COLOR col=COL_DEFAULT_ITEM) { INDEX iItem; if(iIcon!=-1) { MEXaabbox2D boxIcon=MEXaabbox2D( MEX2D(16*iIcon,0), MEX2D(16*iIcon+16,16)); DECLARE_CTFILENAME( fnTerrainEditIcons, "Textures\\Editor\\TerrainEditingIcons.tex"); iItem=pCC->InsertItem( strText, fnTerrainEditIcons, boxIcon); } else { iItem=pCC->InsertItem( strText); } if(iValue!=-1) { pCC->SetItemValue(iItem, iValue); } pCC->SetItemColor( iItem, col); return iItem; } void InvokeLayerPopup(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; CCustomComboWnd *pCombo=new CCustomComboWnd; InsertItemMacro( pCombo, "Delete layer", -1, 0); InsertItemMacro( pCombo, "Insert texture layer", -1, 1); InsertItemMacro( pCombo, "Insert tile layer", -1, 4); InsertItemMacro( pCombo, "Move up", -1, 2); InsertItemMacro( pCombo, "Move down", -1, 3); PointToScreenSpace(pt, pdp); pCombo->Initialize(NULL, ApplyLayerCommand, pt.x, pt.y); } void InvokeLayerTexturePopup(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; CCustomComboWnd *pCombo=new CCustomComboWnd; InsertItemMacro( pCombo, "Create izohipse texture", 22, 0); InsertItemMacro( pCombo, "Browse texture", 22, 1); InsertItemMacro( pCombo, "View layer texture", 3, 2); PointToScreenSpace(pt, pdp); pCombo->Initialize(NULL, ApplyLayerTextureCommand, pt.x, pt.y); } void InvokeLayerMaskPopup(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; CCustomComboWnd *pCombo=new CCustomComboWnd; InsertItemMacro( pCombo, "Fill mask", 17, 0); InsertItemMacro( pCombo, "Clear mask", 9, 1); InsertItemMacro( pCombo, "Noise", 12, 4); InsertItemMacro( pCombo, "--------------",-1,-1); InsertItemMacro( pCombo, "Import mask", 22, 2); InsertItemMacro( pCombo, "Export mask", 22, 3); InsertItemMacro( pCombo, "--------------",-1,-1); InsertItemMacro( pCombo, "View mask", 3, 5); PointToScreenSpace(pt, pdp); pCombo->Initialize(NULL, ApplyLayerMaskCommand, pt.x, pt.y); } CTString GetStretchInfo(CTIButton *ptib, CPoint pt, CDrawPort *pdp, BOOL bLmb) { CTString strInfo; INDEX iLayer=ptib->tib_iLayer; if( iLayer!=-1) { CTerrainLayer *ptlLayer=GetLayer(iLayer); CTerrain *ptrTerrain=GetTerrain(); if(ptlLayer!=NULL && ptrTerrain!=NULL) { strInfo.PrintF("Texture stretch: %g", ptlLayer->tl_fStretchX); return strInfo; } } return strInfo; } CTString GetEditedData(CTIButton *ptib, CPoint pt, CDrawPort *pdp, BOOL bLmb) { CTString strInfo; if(ptib->tib_pfData1!=NULL) strInfo.PrintF("%f", ptib->tib_pfData1); return strInfo; } void OnDropIntoLayerTexture(CTIButton *ptib, CPoint pt, CDrawPort *pdp, CTFileName fnDropped) { // if it is not texture, report error if( fnDropped.FileExt() != ".tex" ) { AfxMessageBox( L"You can only drop textures here."); return; } INDEX iLayer=ptib->tib_iLayer; CTerrainLayer *ptlLayer=GetLayer(iLayer); CTerrain *ptrTerrain=GetTerrain(); if(ptlLayer!=NULL && ptrTerrain!=NULL) { ASSERT(ptlLayer->tl_ptdTexture!=NULL); CTFileName fnOldTexture=CTFILENAME("Textures\\Editor\\Default.tex"); if(ptlLayer->tl_ptdTexture!=NULL) { fnOldTexture=ptlLayer->tl_ptdTexture->GetName(); } BOOL bSetOldTexture=TRUE; try { fnDropped.RemoveApplicationPath_t(); ptlLayer->SetLayerTexture_t(fnDropped); bSetOldTexture=FALSE; theApp.m_ctTerrainPageCanvas.MarkChanged(); ptrTerrain->RefreshTerrain(); } catch(char *strError) { (void) strError; } // if should restore old texture if(bSetOldTexture) { try { ptlLayer->SetLayerTexture_t(fnOldTexture); } catch(char *strError) { (void) strError; } } } } void ToggleLayerVisibleFlag(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { INDEX iLayer=ptib->tib_iLayer; if( iLayer!=-1) { CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer!=NULL) { ptlLayer->tl_bVisible=!ptlLayer->tl_bVisible; CTerrain *ptrTerrain=GetTerrain(); ptrTerrain->RefreshTerrain(); } } } void ToggleFlag(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { INDEX iLayer=ptib->tib_iLayer; if( iLayer!=-1) { CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer!=NULL) { BOOL bOldValue=*(BOOL*)((UBYTE*)ptlLayer+(ULONG)ptib->tib_pfData1); bOldValue=!bOldValue; *(BOOL*)((UBYTE*)ptlLayer+(ULONG)ptib->tib_pfData1)=bOldValue; } } } BOOL DisableIfNoTerrainSelected(CTIButton *ptib) { CTerrain *ptrTerrain=GetTerrain(); return ptrTerrain!=NULL; } CTString GetNormalizedPercentageInfo(CTIButton *ptib, CPoint pt, CDrawPort *pdp, BOOL bLmb) { CTString strInfo; INDEX iLayer=ptib->tib_iLayer; if( iLayer!=-1) { CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer!=NULL) { FLOAT *pfNormalized=(FLOAT *)((UBYTE*)ptlLayer+(ULONG)ptib->tib_pfData1); FLOAT fValue=*pfNormalized; strInfo.PrintF("%s: %d%%", ptib->tib_strToolTip, INDEX(floor(fValue*100.0f+0.5f))); return strInfo; } } return strInfo; } void ChangeLayerDistributionData(CTIButton *ptib, FLOAT fdx, FLOAT fdy, CDrawPort *pdp) { if( ptib->tib_pfData1==NULL) return; INDEX iLayer=ptib->tib_iLayer; if( iLayer==-1) return; CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer==NULL) return; FLOAT *pfNormalized=(FLOAT *)((UBYTE*)ptlLayer+(ULONG)ptib->tib_pfData1); FLOAT fOldValue=*pfNormalized; FLOAT fAddX=ptib->tib_fDataDelta*fdx; FLOAT fNewValue=Clamp( fOldValue+fAddX, 0.0f, 1.0f); *pfNormalized=fNewValue; _iGenerateForLayer=iLayer; _chAutoGenerateDistribution.MarkChanged(); } void ChangeData(CTIButton *ptib, FLOAT fdx, FLOAT fdy, CDrawPort *pdp) { if( ptib->tib_pfData1!=NULL) { FLOAT fData=*ptib->tib_pfData1; FLOAT fAdd=ptib->tib_fDataDelta*fdx; if((fData+fAdd)>=ptib->tib_fDataMax) { if(ptib->tib_bWrapData) { fData=ptib->tib_fDataMin+((fData+fAdd)-ptib->tib_fDataMax); } else { fData=ptib->tib_fDataMax; } } else if((fData+fAdd)<=ptib->tib_fDataMin) { if(ptib->tib_bWrapData) { fData=ptib->tib_fDataMax+(fData+fAdd); } else { fData=ptib->tib_fDataMin; } } else { fData=fData+fAdd; } *ptib->tib_pfData1=fData; } } void ChangeTextureRotation(CTIButton *ptib, FLOAT fdx, FLOAT fdy, CDrawPort *pdp) { INDEX iLayer=ptib->tib_iLayer; if( iLayer!=-1) { CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer!=NULL) { FLOAT fAdd=CHANGE_ANGLE_SENSITIVITY*fdx; ptlLayer->tl_fRotateX+=fAdd; ptlLayer->tl_fRotateY+=fAdd; } } } void ChangeTextureOffset(CTIButton *ptib, FLOAT fdx, FLOAT fdy, CDrawPort *pdp) { INDEX iLayer=ptib->tib_iLayer; if( iLayer!=-1) { CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer!=NULL) { FLOAT fAddX=CHANGE_OFFSET_SENSITIVITY*fdx; FLOAT fAddY=CHANGE_OFFSET_SENSITIVITY*fdy; ptlLayer->tl_fOffsetX+=fAddX; ptlLayer->tl_fOffsetY+=fAddY; } } } void ChangeTextureStretch(CTIButton *ptib, FLOAT fdx, FLOAT fdy, CDrawPort *pdp) { INDEX iLayer=ptib->tib_iLayer; if( iLayer!=-1) { CTerrainLayer *ptlLayer=GetLayer(iLayer); CTerrain *ptrTerrain=GetTerrain(); if(ptlLayer!=NULL && ptrTerrain!=NULL) { if(fdx>=CHANGE_STRETCH_SENSITIVITY) { ptlLayer->tl_fStretchX/=2; ptlLayer->tl_fStretchY/=2; ptrTerrain->RefreshTerrain(); } else if(fdx<=-CHANGE_STRETCH_SENSITIVITY) { ptlLayer->tl_fStretchX*=2; ptlLayer->tl_fStretchY*=2; ptrTerrain->RefreshTerrain(); } } } } void OnSelectBrush(INDEX iSelectedItem) { if( iSelectedItem>=0 && iSelectedItemSetStatusLineModeInfoMessage(); } else if(iSelectedItem==-1) { CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; CDlgEditFloat dlg; dlg.m_fEditFloat=theApp.m_fPosterizeStep; dlg.m_strVarName = "Posterize step (m)"; dlg.m_strTitle = "Enter posterize step"; if(dlg.DoModal()!=IDOK) return; theApp.m_fPosterizeStep=dlg.m_fEditFloat; } // auto update terrain distribution flag else if(iSelectedItem==50) { theApp.m_Preferences.ap_bAutoUpdateTerrainDistribution=!theApp.m_Preferences.ap_bAutoUpdateTerrainDistribution; } // settings else if(iSelectedItem==100) { CDlgTEOperationSettings dlg; dlg.DoModal(); } } void InvokeBrushModeCombo(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { PointToScreenSpace(pt, pdp); CCustomComboWnd *pCombo=new CCustomComboWnd; INDEX iFlag=6; if(theApp.m_Preferences.ap_bAutoUpdateTerrainDistribution) { iFlag=7; } InsertItemMacro( pCombo, "Auto update layer distribution", iFlag, 50, COL_SETTINGS); InsertItemMacro( pCombo, "---------------------------------", -1, -1, COL_SEPARATOR); for(INDEX iMode=0; iModeInitialize(NULL, OnSelectBrush, pt.x, pt.y); } void InvokePercentageCombo(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { PointToScreenSpace(pt, pdp); CCustomComboWnd *pCombo=new CCustomComboWnd; for( INDEX i=1; i<11; i++) { CTString strText; strText.PrintF("%d", i*10); pCombo->InsertItem( strText); } pCombo->Initialize(&theApp.m_fTerrainBrushPressureEnum, NULL, pt.x, pt.y); } void InvokeEditModeCombo(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { PointToScreenSpace(pt, pdp); CCustomComboWnd *pCombo=new CCustomComboWnd; InsertItemMacro( pCombo, "Altitude (U)", 20); InsertItemMacro( pCombo, "Texture (L)", 19); pCombo->Initialize(&theApp.m_iTerrainEditMode, NULL, pt.x, pt.y); } void NextEnum(CTIButton *ptib, CPoint pt) { ChangeData(ptib, 1, 0, NULL); } FLOAT GetMaxSliderPos(CDrawPort *pdp) { CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return 0; FLOAT fMaxPos=ClampDn(ptrTerrain->tr_atlLayers.Count()*LAYER_HEIGHT-pdp->GetHeight(),PIX(0)); return fMaxPos; } void OnSliderArrowUp(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { _fScrollLayers=ClampDn(_fScrollLayers-PIX(LAYER_HEIGHT),0.0f); } void OnSliderArrowDown(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { _fScrollLayers=ClampUp(_fScrollLayers+PIX(LAYER_HEIGHT),GetMaxSliderPos(pdp)); } void RenderLayerColor(CTIButton *ptib, CDrawPort *pdp) { INDEX iLayer=ptib->tib_iLayer; CTerrainLayer *ptlLayer=GetLayer(iLayer); if(ptlLayer==NULL) return; PIXaabbox2D box=GetButtonScreenBox(*ptib); pdp->Fill(box.Min()(1), box.Min()(2), box.Size()(1), box.Size()(2), ptlLayer->tl_colMultiply); } void RenderSlider(CTIButton *ptib, CDrawPort *pdp) { FLOAT fMaxPos=GetMaxSliderPos(pdp); PIX pixSliderY=FLOAT(ptib->tib_fdy-SLIDER_HOLDER_HEIGHT/2)/fMaxPos*_fScrollLayers; pixSliderY=ClampDn(pixSliderY-SLIDER_HOLDER_HEIGHT/2, 0); pdp->Fill(ptib->tib_fx, ptib->tib_fy+pixSliderY, ptib->tib_fdx-2, SLIDER_HOLDER_HEIGHT, C_mlGRAY|CT_OPAQUE); } void OnSliderClick(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { FLOAT fMaxPos=GetMaxSliderPos(pdp); PointToIconSpace(pt, ptib); pt.y=ClampUp( pt.y, INDEX(ptib->tib_fdy-SLIDER_HOLDER_HEIGHT/2)); if(pt.ytib_fdy-SLIDER_HOLDER_HEIGHT); FLOAT fSetPos=pt.y*fRemapFactor; _fScrollLayers=ClampUp(fSetPos,fMaxPos); } void DragSlider(CTIButton *ptib, FLOAT fdx, FLOAT fdy, CDrawPort *pdp/*=NULL*/) { FLOAT fMaxPos=GetMaxSliderPos(pdp); FLOAT fRemapFactor=FLOAT(fMaxPos)/(ptib->tib_fdy-SLIDER_HOLDER_HEIGHT); FLOAT fNewPos=_fScrollLayers+fdy*fRemapFactor; _fScrollLayers=Clamp( fNewPos, 0.0f, fMaxPos); } void RecalculateShadows(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { RecalculateShadows(); } void DisplayHeightMap(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { PointToScreenSpace(pt, pdp); DisplayHeightMapWindow( pt); } void ApplyTerrainOptions(INDEX iSelectedItem) { CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; switch(iSelectedItem) { // invoke properties case 0: { CDlgTerrainProperties dlg; dlg.DoModal(); break; } // generate terrain case 3: { ApplyGenerateTerrain(); break; } // smooth case 4: { ApplySmoothOntoTerrain(); break; } // filter case 5: { ApplyFilterOntoTerrain(); break; } // add noise case 6: { ApplyRndNoiseOntoTerrain(); break; } // equalize case 7: { ApplyEqualizeOntoTerrain(); break; } // operation settings case 8: { // option settings CDlgTEOperationSettings dlg; dlg.DoModal(); break; } // posterize case 9: { ApplyPosterizeOntoTerrain(); break; } // add continous noise case 11: { ApplyContinousNoiseOntoTerrain(); break; } // limit down case 12: { ApplyMinimumOntoTerrain(); break; } // limit up case 13: { ApplyMaximumOntoTerrain(); break; } // flatten case 14: { ApplyFlattenOntoTerrain(); break; } // recalcualte shadows case 15: { ptrTerrain->UpdateShadowMap(); } // generate layer distribution case 16: { GenerateLayerDistribution(-1); } // optimize layers case 17: { OptimizeLayers(); } // view heightmap case 50: { CPoint pt; GetCursorPos( &pt); DisplayHeightMapWindow( pt); } } } void InvokeTerrainOptions(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; CCustomComboWnd *pCombo=new CCustomComboWnd; INDEX iItem=0; InsertItemMacro( pCombo, "Terrain properties (Ctrl+Shift+T)",2,0); InsertItemMacro( pCombo, "------------------------------------", -1, -1, COL_SEPARATOR); InsertItemMacro( pCombo, "Generate terrain (Ctrl+Shift+G)",25, 3); InsertItemMacro( pCombo, "Equalize (Ctrl+Shift+E)",1,7); InsertItemMacro( pCombo, "------------------------------------", -1, -1, COL_SEPARATOR); InsertItemMacro( pCombo, "Recalculate shadows (Ctrl+Shift+R)",5, 15); InsertItemMacro( pCombo, "Generate layer distribution (Ctrl+G)",19, 16); InsertItemMacro( pCombo, "Optimize layers (Ctrl+Shift+Z)",25, 17); InsertItemMacro( pCombo, "------------------------------------", -1, -1, COL_SEPARATOR); InsertItemMacro( pCombo, "Smooth (Ctrl+Shift+O)",10,4); InsertItemMacro( pCombo, "Filter (Ctrl+Shift+F)",30,5); InsertItemMacro( pCombo, "Limit down (Ctrl+Shift+M)",27,12); InsertItemMacro( pCombo, "Limit up (Ctrl+Shift+X)",11,13); InsertItemMacro( pCombo, "Flatten (Ctrl+Shift+N)",18,14); InsertItemMacro( pCombo, "Posterize",28,9); InsertItemMacro( pCombo, "Random noise (Ctrl+Shift+K)",21,6); InsertItemMacro( pCombo, "Texture noise (Ctrl+Shift+Y)",31,11); InsertItemMacro( pCombo, "------------------------------------", -1, -1,COL_SEPARATOR); InsertItemMacro( pCombo, "View height map ", 26, 50); InsertItemMacro( pCombo, "Operation settings (Ctrl+Shift+P)", 26, 8, COL_SETTINGS); PointToScreenSpace(pt, pdp); pCombo->Initialize(NULL, ApplyTerrainOptions, pt.x, pt.y); } void DisplayHeightMapWindow(CPoint pt) { CTextureData tdHeightMap; CImageInfo ii; CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; PIX pixW=ptrTerrain->tr_pixHeightMapWidth; PIX pixH=ptrTerrain->tr_pixHeightMapHeight; if(ptrTerrain->tr_auwHeightMap==NULL) return; ii.ii_BitsPerPixel=32; ii.ii_Width=pixW-1; ii.ii_Height=pixH-1; ii.ii_Picture=(UBYTE*)AllocMemory((pixW-1)*(pixH-1)*sizeof(COLOR)); COLOR *pcol=(COLOR *)ii.ii_Picture; for( INDEX iy=0; iytr_auwHeightMap+iy*pixW+ix; UWORD uw=*pdest; FLOAT fPix=uw/256.0f; UBYTE ubR=UBYTE(fPix); COLOR col=RGBToColor(ubR,ubR,ubR)|CT_OPAQUE; col=RGBToColor(ubR,ubR,ubR)|CT_OPAQUE; *(pcol+iy*(pixW-1)+ix)=ByteSwap(col); } } try { tdHeightMap.Create_t( &ii, pixW-1, 16, TRUE); CTString strHeightMap="Temp\\ViewHeightMap.tex"; tdHeightMap.Save_t( strHeightMap); CTextureData *ptd; ptd=_pTextureStock->Obtain_t( strHeightMap); ptd->Reload(); CWndDisplayTexture *pDisplay=new CWndDisplayTexture; pDisplay->Initialize(pt.x, pt.y, ptd); } catch( char *strError) { (void) strError; WarningMessage("Unable to display height map!"); } } void OnSelectLoadSave(INDEX iSelectedItem) { switch( iSelectedItem) { case 0: case 1: case 2: case 3: { ApplyImportExport(iSelectedItem); } case 4: // "Load surface" { CTFileName fnSurface=_EngineGUI.FileRequester( "Load surface", "Surfaces (*.sfc)\0*.sfc\0" FILTER_ALL FILTER_END, "Surface directory", "Surfaces\\"); if( fnSurface=="") return; LoadSurface(fnSurface); break; } case 5: // "Save surface" { CTFileName fnSurface=_EngineGUI.FileRequester( "Save surface", "Surfaces (*.sfc)\0*.sfc\0" FILTER_ALL FILTER_END, "Surface directory", "Surfaces\\"); if( fnSurface=="") return; SaveSurface(fnSurface); break; } } } void ApplyImportExport(INDEX iOperation) { CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; CTFileName fnHeightmap; if(iOperation<2) { fnHeightmap=_EngineGUI.FileRequester( "Import heightmap", FILTER_TGA FILTER_PCX FILTER_ALL FILTER_END, "Terrain heightmap directory", "Textures\\"); if( fnHeightmap=="") return; } else { fnHeightmap=_EngineGUI.FileRequester( "Export heightmap", FILTER_TGA FILTER_PCX FILTER_ALL FILTER_END, "Terrain heightmap directory", "Textures\\"); if( fnHeightmap=="") return; } try { switch( iOperation) { // import 8 bit case 0: { ptrTerrain->ImportHeightMap_t(fnHeightmap, FALSE); theApp.m_ctTerrainPage.MarkChanged(); break; } // import 16 bit case 1: { ptrTerrain->ImportHeightMap_t(fnHeightmap, TRUE); theApp.m_ctTerrainPage.MarkChanged(); break; } // export 8 bit case 2: { ptrTerrain->ExportHeightMap_t(fnHeightmap, FALSE); break; } // export 16 bit case 3: { ptrTerrain->ExportHeightMap_t(fnHeightmap, TRUE); break; } } } catch(char *strError) { AfxMessageBox( CString(strError)); } } void GenerateLayerDistribution(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { GenerateLayerDistribution(-1); } void InvokeImportExportCombo(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain==NULL) return; CCustomComboWnd *pCombo=new CCustomComboWnd; InsertItemMacro( pCombo, "Import 8-bit", 22, 0); InsertItemMacro( pCombo, "Import 16-bit", 22, 1); InsertItemMacro( pCombo, "Export 8-bit", 22, 2); InsertItemMacro( pCombo, "Export 16-bit", 22, 3); InsertItemMacro( pCombo, "----------------", -1, -1, COL_SEPARATOR); InsertItemMacro( pCombo, "Load surface", 22, 4); InsertItemMacro( pCombo, "Save surface", 22, 5); PointToScreenSpace(pt, pdp); pCombo->Initialize(NULL, OnSelectLoadSave, pt.x, pt.y); } void InvokeTerrainTilePalette( PIX pixX, PIX pixY) { CWndTerrainTilePalette *pDisplay=new CWndTerrainTilePalette; CTerrainLayer *ptlLayer=GetLayer(); if(ptlLayer!=NULL && ptlLayer->tl_ptdTexture!=NULL) { pDisplay->Initialize(pixX, pixY, ptlLayer->tl_ptdTexture, TRUE); } } CBrushPaletteWnd *_pBrushPalette=NULL; void InvokeTerrainBrushPalette( PIX pixX, PIX pixY) { // calculate palette window's rectangle CRect rectWindow; rectWindow.left = pixX; rectWindow.bottom = pixY; rectWindow.right = rectWindow.left + BRUSH_PALETTE_WIDTH; rectWindow.top = rectWindow.bottom - BRUSH_PALETTE_HEIGHT; if( _pBrushPalette == NULL) { // instantiate new choose color palette window _pBrushPalette = new CBrushPaletteWnd; // create window CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); BOOL bResult = _pBrushPalette->CreateEx( WS_EX_TOOLWINDOW, NULL, L"Brush palette", WS_CHILD|WS_POPUP|WS_VISIBLE, rectWindow.left, rectWindow.top, rectWindow.Width(), rectWindow.Height(), pMainFrame->m_hWnd, NULL, NULL); _pBrushPalette->SetFocus(); if( !bResult) { AfxMessageBox( L"Error: Failed to create brush palette"); return; } // initialize canvas for active texture button _pGfx->CreateWindowCanvas( _pBrushPalette->m_hWnd, &_pBrushPalette->m_pViewPort, &_pBrushPalette->m_pDrawPort); } else { _pBrushPalette->ShowWindow(SW_SHOW); _pBrushPalette->SetFocus(); } } void InvokeBrushPalette(CTIButton *ptib, CPoint pt, CDrawPort *pdp) { PointToScreenSpace(pt, pdp); InvokeTerrainBrushPalette( pt.x, pt.y); } BOOL CTerrainInterface::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext) { return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext); } BOOL CTerrainInterface::IsClicked(CTIButton &tib, CPoint pt) const { PIX pixOffsetX=0; PIX pixOffsetY=0; GetButtonOffset(tib, pixOffsetX, pixOffsetY); PIX x=tib.tib_fx+pixOffsetX; PIX y=tib.tib_fy+pixOffsetY; PIX dx=tib.tib_fdx; PIX dy=tib.tib_fdy; return( (pt.x>x) && (pt.xy) && (pt.yGetWidth()/2; m_ptMouseCenter.y=m_pDrawPort->GetHeight()/2; m_ptMouseCenterScreen=m_ptMouseCenter; ClientToScreen(&m_ptMouseCenterScreen); _bDummyMouseMove=TRUE; SetCursorPos(m_ptMouseCenterScreen.x, m_ptMouseCenterScreen.y); HideCursor(); _bMouseTrapInProgress=TRUE; } if(!tib.tib_bContinueTesting) break; } } } } void CTerrainInterface::OnLButtonDblClk(UINT nFlags, CPoint point) { OnLButtonDown(nFlags, point); } void CTerrainInterface::OnMouseMove(UINT nFlags, CPoint point) { theApp.m_cttToolTips.MouseMoveNotify( m_hWnd, 500, &::GetToolTipText, this); BOOL bLMB = nFlags & MK_LBUTTON; BOOL bRMB = nFlags & MK_RBUTTON; FLOAT fdx=point.x-m_ptMouseCenter.x; FLOAT fdy=point.y-m_ptMouseCenter.y; FLOAT fdxNotLocked=point.x-m_ptMouse.x; FLOAT fdyNotLocked=point.y-m_ptMouse.y; fdx=fdxNotLocked; fdy=fdyNotLocked; m_ptMouse=point; if( _bDummyMouseMove) { _bDummyMouseMove=FALSE; return; } if( bLMB) { FOREACHINDYNAMICCONTAINER( dcButtons, CTIButton, ittib) { CTIButton &tib=*ittib; if( IsClicked(tib, m_ptMouseDown) && tib.tib_pOnLeftClickMove!=NULL) { if(tib.tib_bMouseTrapForMove) { tib.tib_pOnLeftClickMove(&tib, fdx, fdy, m_pDrawPort); _bDummyMouseMove=TRUE; SetCursorPos(m_ptMouseCenterScreen.x, m_ptMouseCenterScreen.y); } else { tib.tib_pOnLeftClickMove(&tib, fdxNotLocked, fdyNotLocked, m_pDrawPort); } Invalidate(FALSE); // update tool tip if( tib.tib_pGetClickMoveData!=NULL) { _strToolTip=tib.tib_pGetClickMoveData(&tib, point, m_pDrawPort, TRUE); theApp.m_cttToolTips.ManualUpdate(); } if(!tib.tib_bContinueTesting) break; } } } else if( bRMB) { FOREACHINDYNAMICCONTAINER( dcButtons, CTIButton, ittib) { CTIButton &tib=*ittib; if( IsClicked(tib, m_ptMouseDown) && tib.tib_pOnRightClickMove!=NULL) { if(tib.tib_bMouseTrapForMove) { tib.tib_pOnRightClickMove(&tib, fdx, fdy, m_pDrawPort); _bDummyMouseMove=TRUE; SetCursorPos(m_ptMouseCenterScreen.x, m_ptMouseCenterScreen.y); } else { tib.tib_pOnRightClickMove(&tib, fdxNotLocked, fdyNotLocked, m_pDrawPort); } Invalidate(FALSE); // update tool tip if( tib.tib_pGetClickMoveData!=NULL) { _strToolTip=tib.tib_pGetClickMoveData(&tib, point, m_pDrawPort, FALSE); theApp.m_cttToolTips.ManualUpdate(); } if(!tib.tib_bContinueTesting) break; } } } CWnd::OnMouseMove(nFlags, point); } void CTerrainInterface::OnLButtonUp(UINT nFlags, CPoint point) { theApp.m_cttToolTips.ManualOff(); ReleaseCapture(); _bDummyMouseMove=TRUE; if( _bMouseTrapInProgress) { SetCursorPos(m_ptMouseDownScreen.x, m_ptMouseDownScreen.y); _bMouseTrapInProgress=FALSE; UnhideCursor(); m_ptMouseDown.x=-1; m_ptMouseDown.y=-1; } CWnd::OnLButtonUp(nFlags, point); } BOOL CTerrainInterface::PreTranslateMessage(MSG* pMsg) { return CWnd::PreTranslateMessage(pMsg); } void CTerrainInterface::OnRButtonDown(UINT nFlags, CPoint point) { CWnd::OnRButtonDown(nFlags, point); SetFocus(); m_ptMouseDown=point; m_ptMouse=point; m_ptMouseDownScreen=point; ClientToScreen(&m_ptMouseDownScreen); FOREACHINDYNAMICCONTAINER( dcButtons, CTIButton, ittib) { CTIButton &tib=*ittib; if( IsClicked(tib, point)) { if(tib.tib_pOnRightClick!=NULL) { tib.tib_pOnRightClick(&tib, m_ptMouse, m_pDrawPort); _bMouseTrapInProgress=FALSE; UnhideCursor(); Invalidate(FALSE); if(!tib.tib_bContinueTesting) break; } if(tib.tib_pOnRightClickMove!=NULL) { // display tool tip if( tib.tib_pGetClickMoveData!=NULL) { CTString strInfo=tib.tib_pGetClickMoveData(&tib, point, m_pDrawPort, TRUE); _strToolTip=strInfo; theApp.m_cttToolTips.ManualOn( m_ptMouseDownScreen.x, m_ptMouseDownScreen.y, &::GetToolTipText, this); SetCapture(); } // if should trap the mouse if(tib.tib_bMouseTrapForMove) { m_ptMouseCenter.x=m_pDrawPort->GetWidth()/2; m_ptMouseCenter.y=m_pDrawPort->GetHeight()/2; m_ptMouseCenterScreen=m_ptMouseCenter; ClientToScreen(&m_ptMouseCenterScreen); _bDummyMouseMove=TRUE; SetCursorPos(m_ptMouseCenterScreen.x, m_ptMouseCenterScreen.y); HideCursor(); _bMouseTrapInProgress=TRUE; } if(!tib.tib_bContinueTesting) break; } } } } void CTerrainInterface::OnRButtonUp(UINT nFlags, CPoint point) { theApp.m_cttToolTips.ManualOff(); ReleaseCapture(); _bDummyMouseMove=TRUE; if( _bMouseTrapInProgress) { SetCursorPos(m_ptMouseDownScreen.x, m_ptMouseDownScreen.y); _bMouseTrapInProgress=FALSE; UnhideCursor(); m_ptMouseDown.x=-1; m_ptMouseDown.y=-1; } CWnd::OnRButtonUp(nFlags, point); } void CTerrainInterface::OnIdle(void) { CWorldEditorDoc *pDoc = theApp.GetDocument(); if(!_chAutoGenerateDistribution.IsUpToDate( _udAutoGenerateDistribution)) { GenerateLayerDistribution(_iGenerateForLayer); _udAutoGenerateDistribution.MarkUpdated(); } CTerrain *ptrTerrain=GetTerrain(); if(ptrTerrain!=NULL) { if(GetLayerIndex()>=ptrTerrain->tr_atlLayers.Count()) { SelectLayer(0); } } BOOL bLMB = (GetKeyState( VK_LBUTTON)&0x8000) != 0; BOOL bRMB = (GetKeyState( VK_RBUTTON)&0x8000) != 0; if(!bLMB && !bRMB && _bMouseTrapInProgress) { _bMouseTrapInProgress=FALSE; UnhideCursor(); theApp.m_cttToolTips.ManualOff(); } // if should re-initialize interface if(pDoc!=NULL && !pDoc->m_chSelections.IsUpToDate( m_udTerrainPage) || !theApp.m_ctTerrainPage.IsUpToDate( m_udTerrainPage) ) { if(m_pDrawPort!=NULL) { InitializeInterface(m_pDrawPort); Invalidate(FALSE); m_udTerrainPage.MarkUpdated(); } } // if should just redraw interface if(!theApp.m_ctTerrainPageCanvas.IsUpToDate( m_udTerrainPageCanvas) ) { Invalidate(FALSE); m_udTerrainPageCanvas.MarkUpdated(); } } void CTerrainInterface::OnDropFiles(HDROP hDropInfo) { INDEX iNoOfFiles = DragQueryFile( hDropInfo, 0xFFFFFFFF, NULL, 0); if( iNoOfFiles != 1) { AfxMessageBox( L"You can drop only one file at a time."); return; } // buffer for dropped file name wchar_t chrFile[ 256]; // place dropped file name into buffer DragQueryFile( hDropInfo, 0, chrFile, 256); // create file name from buffer CTFileName fnDropped = CTString(CStringA(chrFile)); CPoint ptMouse; GetCursorPos( &ptMouse); ScreenToClient(&ptMouse); FOREACHINDYNAMICCONTAINER( dcButtons, CTIButton, ittib) { CTIButton &tib=*ittib; if( IsClicked(tib, ptMouse) && tib.tib_pOnDropFiles!=NULL) { tib.tib_pOnDropFiles(&tib, ptMouse, m_pDrawPort, fnDropped); } } CWnd::OnDropFiles(hDropInfo); } int CTerrainInterface::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; DragAcceptFiles(); EnableToolTips( TRUE); return 0; } int CTerrainInterface::OnToolHitTest( CPoint point, TOOLINFO* pTI ) const { FOREACHINDYNAMICCONTAINER( dcButtons, CTIButton, ittib) { CTIButton &tib=*ittib; _strToolTip=""; if( IsClicked(tib, point)) { if( tib.tib_strToolTip!="" && tib.tib_strToolTip[0]!='_') { _strToolTip=tib.tib_strToolTip; return 1; } } } return 0; } void CTerrainInterface::InitializeInterface(CDrawPort *pdp) { try { DECLARE_CTFILENAME( fnTerrainEditIcons, "Textures\\Editor\\TerrainEditingIcons.tex"); _toIcons.SetData_t(fnTerrainEditIcons); } catch(char *strError) { (void)strError; return; } FOREACHINDYNAMICCONTAINER( dcButtons, CTIButton, ittib) { delete &*ittib; } dcButtons.Clear(); CTIButton *ptib; COLOR colBcg=RGBToColor(45,45,60)|CT_OPAQUE; ptib=AddButton(dcButtons,0,0,LAYER_START_X,pdp->GetHeight(),-1,-1, "_Terrain options area fill", C_dGRAY|CT_TRANSPARENT, colBcg); ptib=AddButton(dcButtons,1,1,45,45,-1,-1, "Current brush (\\)", C_lGRAY|CT_OPAQUE); ptib->SetData(0, CT_BRUSHES, CHANGE_INDEX_SENSITIVITY, FALSE, &theApp.m_fCurrentTerrainBrush, NULL); ptib->SetFunctions( RenderBrushShape, NULL, ChangeData, InvokeBrushPalette); ptib=AddButton(dcButtons,0,52,LAYER_START_X,8,-1,-1, "Brush pressure (keys 0-10)"); ptib->SetData(0, 1024.0f, CHANGE_PREASSURE_SENSITIVITY, FALSE, &theApp.m_fTerrainBrushPressure, NULL); ptib->SetFunctions( RenderBrushPressure, NULL, ChangeData, InvokePercentageCombo, NULL, UpdatePressure); ptib=AddButton(dcButtons,6,64,16,16,-1,19, "Edit mode"); ptib->SetData(0, CT_EDIT_MODES, CHANGE_INDEX_SENSITIVITY, FALSE, &theApp.m_iTerrainEditMode, NULL); UpdateEditModeIcon(ptib, NULL); ptib->SetFunctions( NULL, NULL, ChangeData, InvokeEditModeCombo, NULL, UpdateEditModeIcon); ptib=AddButton(dcButtons,28,64,16,16,-1,-1, "Brush mode"); ptib->SetData(0, CT_BRUSH_MODES-0.5f, CHANGE_INDEX_SENSITIVITY, FALSE, &theApp.m_iTerrainBrushMode, NULL); UpdateBrushModeIcon(ptib, NULL); ptib->SetFunctions( NULL, NULL, ChangeData, InvokeBrushModeCombo, NULL, UpdateBrushModeIcon); /* ptib=AddButton(dcButtons,6,84,16,16,-1,5, "Recalculate shadows (Ctrl+R)"); ptib->SetFunctions( NULL, RecalculateShadows); ptib->tib_pIsEnabled=DisableIfNoTerrainSelected; */ ptib=AddButton(dcButtons,28,84,16,16,-1,25, "Terrain options"); ptib->SetFunctions( NULL, NULL, NULL, InvokeTerrainOptions); ptib->tib_pIsEnabled=DisableIfNoTerrainSelected; /* ptib=AddButton(dcButtons,6,104,16,16,-1,6, "Generate layer distribution (Ctrl+G)"); ptib->SetFunctions( NULL, GenerateLayerDistribution); ptib->tib_pIsEnabled=DisableIfNoTerrainSelected; */ ptib=AddButton(dcButtons,6,84,16,16,-1,22, "Import/Export"); ptib->SetFunctions( NULL, NULL, NULL, InvokeImportExportCombo); ptib->tib_pIsEnabled=DisableIfNoTerrainSelected; CTerrain *ptrTerrain=GetTerrain(); if( ptrTerrain!=NULL) { for(INDEX iLayer=0; iLayertr_atlLayers.Count(); iLayer++) { CTerrainLayer &tlLayer=ptrTerrain->tr_atlLayers[iLayer]; ptib=AddButton(dcButtons,0,0,GetLayerSize(pdp)(1)-SLIDER_WIDTH, GetLayerSize(pdp)(2),iLayer,-1, "_Layer options area bcg"); ptib->SetFunctions( RenderLayerBcg, SetAsActiveLayer, NULL, SetAsActiveLayer); ptib->tib_bContinueTesting=TRUE; ptib=AddButton(dcButtons, LAYER_SPACING_V/2, LAYER_SPACING_V/2, LAYER_HEIGHT-LAYER_SPACING_V/2-1, LAYER_HEIGHT-LAYER_SPACING_V/2-1, iLayer,-1, "Layer texture", C_BLACK|CT_OPAQUE); ptib->SetFunctions( RenderLayerTexture, NULL, NULL, InvokeLayerTexturePopup); ptib->tib_pOnDropFiles=OnDropIntoLayerTexture; ptib=AddButton(dcButtons, LAYER_SPACING_V/2, LAYER_SPACING_V/2, 16, 16, iLayer, -1, "Layer visibility"); UpdateLayerVisibleFlag(ptib, NULL); ptib->tib_pfData1=(FLOAT*)offsetof(CTerrainLayer, tl_bVisible); ptib->SetFunctions( NULL, ToggleLayerVisibleFlag, NULL, NULL, NULL, UpdateLayerVisibleFlag); ptib=AddButton(dcButtons, LAYER_HEIGHT, LAYER_SPACING_V/2, LAYER_HEIGHT-LAYER_SPACING_V/2-1, LAYER_HEIGHT-LAYER_SPACING_V/2-1, iLayer,-1, "Layer mask", C_BLACK|CT_OPAQUE); ptib->SetFunctions( RenderLayerMask, NULL, NULL, InvokeLayerMaskPopup); if(tlLayer.tl_ltType==LT_NORMAL) { ptib=AddButton(dcButtons, LAYER_HEIGHT*2,2,16,16,iLayer,0, "Rotate texture"); ptib->SetFunctions( NULL, NULL, ChangeTextureRotation); ptib=AddButton(dcButtons, LAYER_HEIGHT*2,16,16,16,iLayer,2, "Stretch texture"); ptib->SetFunctions( NULL, NULL, ChangeTextureStretch); ptib->tib_pGetClickMoveData=GetStretchInfo; ptib=AddButton(dcButtons, LAYER_HEIGHT*2,30,16,16,iLayer,1, "Offset texture"); ptib->SetFunctions( NULL, NULL, ChangeTextureOffset); #define ICON_COVERAGE_X (LAYER_HEIGHT*2+16) #define ICON_FILTER_X (LAYER_HEIGHT*2+40) #define ICON_FADE_X (ICON_FILTER_X+16) #define ICON_NOISE_X (ICON_FADE_X+16) #define ICON_SLOPE_OFFSET 56 #define ICON_LINE1_Y 6 #define ICON_LINE2_Y 26 ptib=AddButton(dcButtons, ICON_COVERAGE_X,ICON_LINE1_Y,16,16,iLayer,17, "Layer coverage"); ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fCoverage)); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib=AddButton(dcButtons, ICON_COVERAGE_X,ICON_LINE2_Y,16,16,iLayer,21, "Layer coverage noise"); ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fCoverageNoise)); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib=AddButton(dcButtons, ICON_FILTER_X, ICON_LINE1_Y,16,16,iLayer,14, "Max altitude"); ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fMaxAltitude)); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib=AddButton(dcButtons, ICON_FADE_X, ICON_LINE1_Y,16,16,iLayer,29, "Max altitude fade"); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fMaxAltitudeFade)); ptib=AddButton(dcButtons, ICON_NOISE_X, ICON_LINE1_Y,16,16,iLayer,21, "Max altitude noise"); ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fMaxAltitudeNoise)); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib=AddButton(dcButtons, ICON_FILTER_X, ICON_LINE2_Y,16,16,iLayer,13, "Min altitude"); ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fMinAltitude)); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib=AddButton(dcButtons, ICON_FADE_X, ICON_LINE2_Y,16,16,iLayer,29, "Min altitude fade"); ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fMinAltitudeFade)); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib=AddButton(dcButtons, ICON_NOISE_X, ICON_LINE2_Y,16,16,iLayer,21, "Min altitude noise"); ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fMinAltitudeNoise)); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib=AddButton(dcButtons, ICON_FILTER_X+ICON_SLOPE_OFFSET, ICON_LINE1_Y,16,16,iLayer,16, "Max slope"); ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fMaxSlope)); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib=AddButton(dcButtons, ICON_FADE_X+ICON_SLOPE_OFFSET, ICON_LINE1_Y,16,16,iLayer,29, "Max slope fade"); ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fMaxSlopeFade)); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib=AddButton(dcButtons, ICON_NOISE_X+ICON_SLOPE_OFFSET, ICON_LINE1_Y,16,16,iLayer,21, "Max slope noise"); ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fMaxSlopeNoise)); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib=AddButton(dcButtons, ICON_FILTER_X+ICON_SLOPE_OFFSET, ICON_LINE2_Y,16,16,iLayer,15, "Min slope"); ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fMinSlope)); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib=AddButton(dcButtons, ICON_FADE_X+ICON_SLOPE_OFFSET, ICON_LINE2_Y,16,16,iLayer,29, "Min slope fade"); ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fMinSlopeFade)); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib=AddButton(dcButtons, ICON_NOISE_X+ICON_SLOPE_OFFSET, ICON_LINE2_Y,16,16,iLayer,21, "Min slope noise"); ptib->SetData(0, 1, CHANGE_NORMALIZED_SENSITIVITY, FALSE, (FLOAT*)offsetof(CTerrainLayer, tl_fMinSlopeFade)); ptib->SetFunctions( NULL, NULL, ChangeLayerDistributionData); ptib->tib_pGetClickMoveData=GetNormalizedPercentageInfo; ptib=AddButton(dcButtons, GetLayerSize(pdp)(1)-12-SLIDER_WIDTH-1-2,2,12,12,iLayer,-1, "Multiply color", C_BLACK|CT_OPAQUE); ptib->SetFunctions( RenderLayerColor, PickLayerColor, NULL, NumericAlpha); ptib=AddButton(dcButtons, GetLayerSize(pdp)(1)-16-SLIDER_WIDTH-1,GetLayerSize(pdp)(2)-20,16,16,iLayer,26, "Layer options (Ctrl+Shift+L)"); ptib->SetFunctions( NULL, InvokeLayerOptions); } else if(tlLayer.tl_ltType==LT_TILE) { } ptib=AddButton(dcButtons,0,0,GetLayerSize(pdp)(1)-SLIDER_WIDTH-1,GetLayerSize(pdp)(2),iLayer,-1, "_Layer options area border", C_GRAY|CT_OPAQUE); // _Layer click detector ptib=AddButton(dcButtons,0,0,GetLayerSize(pdp)(1)-SLIDER_WIDTH, GetLayerSize(pdp)(2),iLayer,-1, "_Layer click detector"); ptib->SetFunctions( NULL, NULL, NULL, InvokeLayerPopup); } } //slider ptib=AddButton(dcButtons,pdp->GetWidth()-SLIDER_WIDTH, 0, SLIDER_WIDTH, SLIDER_WIDTH, -1, 23, "_Slider arrow up", C_GRAY|CT_OPAQUE, C_mdGRAY|CT_OPAQUE); ptib->SetFunctions(NULL,OnSliderArrowUp); ptib=AddButton(dcButtons,pdp->GetWidth()-SLIDER_WIDTH, pdp->GetHeight()-SLIDER_WIDTH, SLIDER_WIDTH, SLIDER_WIDTH, -1, 24, "_Slider arrow down", C_GRAY|CT_OPAQUE, C_mdGRAY|CT_OPAQUE); ptib->SetFunctions(NULL,OnSliderArrowDown); ptib=AddButton(dcButtons,pdp->GetWidth()-SLIDER_WIDTH, SLIDER_WIDTH, SLIDER_WIDTH, pdp->GetHeight()-SLIDER_WIDTH*2, -1,-1, "_Slider rect", C_dGRAY|CT_OPAQUE, colBcg); ptib->SetFunctions(RenderSlider,OnSliderClick, DragSlider); ptib->tib_bMouseTrapForMove=FALSE; }