// TerrainViewport.cpp : implementation file // #include "stdafx.h" #include "TerrainViewport.h" #include "CryEditDoc.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CTerrainViewport // Used to give each static object type a different color static DWORD StatObjColorArray[] = { 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00FFFFFF, 0x00FF00FF, 0x00FFFF00, 0x0000FFFF, 0x007F00FF, 0x007FFF7F, 0x00FF7F00, 0x0000FF7F, 0x007F7F7F, 0x00000000 }; CTerrainViewport::CTerrainViewport() { m_heightmapSize.cx = GetDocument()->m_cHeightmap.GetWidth(); m_heightmapSize.cy = GetDocument()->m_cHeightmap.GetHeight(); VERIFY(m_dcView.CreateCompatibleDC(NULL)); // Create a DC and a bitmap VERIFY(m_dcTerrain.CreateCompatibleDC(NULL)); VERIFY(m_bmpTerrain.CreateBitmap(m_heightmapSize.cx,m_heightmapSize.cy, 1, 32, NULL)); m_dcTerrain.SelectObject(&m_bmpTerrain); m_iBrushSize = 50; } CTerrainViewport::~CTerrainViewport() { } BEGIN_MESSAGE_MAP(CTerrainViewport, CViewport) //{{AFX_MSG_MAP(CTerrainViewport) ON_WM_PAINT() ON_WM_MOUSEWHEEL() ON_WM_MOUSEMOVE() ON_WM_ERASEBKGND() ON_WM_SIZE() ON_WM_RBUTTONDOWN() ON_WM_RBUTTONUP() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CTerrainViewport message handlers ////////////////////////////////////////////////////////////////////////// CPoint CTerrainViewport::WorldToView( Vec3d wp ) { CPoint p; float x = wp.x / 2.0f; float y = wp.y / 2.0f; float lTemp; // Swap the axis lTemp = x; x = y; y = lTemp; x = (x * GetZoomFactor()); y = (y * GetZoomFactor()); // Add the offset x += GetScrollOffset().x; y += GetScrollOffset().y; p.x = (int)x; p.y = (int)y; return p; } ////////////////////////////////////////////////////////////////////////// Vec3d CTerrainViewport::ViewToWorld( CPoint vp,bool *collideWithTerrain,bool onlyTerrain ) { vp.x += abs(GetScrollOffset().x); vp.y += abs(GetScrollOffset().y); // Swap the axis int lTemp = vp.x; vp.x = vp.y; vp.y = lTemp; // Scale with the zoom factor float x = (float)vp.x / GetZoomFactor(); float y = (float)vp.y / GetZoomFactor(); Vec3d wp; wp.x = x * 2.0f; wp.y = y * 2.0f; wp.z = GetIEditor()->GetTerrainElevation(wp.x,wp.y); if (collideWithTerrain) *collideWithTerrain = true; /* CEngineSingleton::GetGameInterface()->GetInterface()-> MovePlayer(point.x * 2.0f, point.y * 2.0f, CEngineSingleton:: GetGameInterface()->GetInterface()->GetTerrainElevation(point.x * 2.0f, point.y * 2.0f)); */ return wp; } void CTerrainViewport::ViewToWorldRay( CPoint vp,Vec3 &raySrc,Vec3 &rayDir ) { raySrc = ViewToWorld( vp ); raySrc.z = 1000; rayDir(0,0,-1); } bool CTerrainViewport::SetScrollOffset(long iX, long iY) { //////////////////////////////////////////////////////////////////////// // Set the scrolling offset. If the passed values are invalid, the // nearest valid values will be set and false is returned //////////////////////////////////////////////////////////////////////// bool bRangeValid = true; RECT rcWndPos; long iScaledTexWidth = (long) (m_heightmapSize.cx * GetZoomFactor()); // Obtain the size of the window GetClientRect(&rcWndPos); // Don't allow to scroll beyond the lower right corner if (abs(iX) > iScaledTexWidth - rcWndPos.right) { iX = -(iScaledTexWidth - rcWndPos.right); bRangeValid = false; } if (abs(iY) > iScaledTexWidth - rcWndPos.bottom) { iY = -(iScaledTexWidth - rcWndPos.bottom); bRangeValid = false; } // Don't allow to scroll beyond the upper left corner if (iX > 0) { iX = 0; bRangeValid = false; } if (iY > 0) { iY = 0; bRangeValid = false; } // Save the (eventually corrected) scroll offset m_cScrollOffset = CPoint(iX, iY); RedrawWindow(); return bRangeValid; } void CTerrainViewport::ResetContent() { //////////////////////////////////////////////////////////////////////// // Create a surface texture that consists entirely of water //////////////////////////////////////////////////////////////////////// DWORD *pWaterTexData = NULL; DWORD *pSurfaceTextureData = NULL; DWORD *pPixData = NULL, *pPixDataEnd = NULL; CBitmap bmpLoad; bool bReturn; // Load the water texture out of the ressource bReturn = bmpLoad.LoadBitmap(MAKEINTRESOURCE(IDB_WATER)); ASSERT(bReturn); // Allocate new memory to hold the bitmap data pWaterTexData = new DWORD[128 * 128]; ASSERT(pWaterTexData); // Retrieve the bits from the bitmap VERIFY(bmpLoad.GetBitmapBits(128 * 128 * sizeof(DWORD), pWaterTexData)); // Allocate memory for the surface texture pSurfaceTextureData = new DWORD[m_heightmapSize.cx*m_heightmapSize.cy]; ASSERT(pSurfaceTextureData); // Fill the surface texture with the water texture, tile as needed for (int j=0; j> 16) | (* pPixData & 0x0000FF00) | ((* pPixData & 0x000000FF) << 16); } */ // Load it into the bitmap m_bmpTerrain.SetBitmapBits(m_heightmapSize.cx*m_heightmapSize.cy*4, pSurfaceTextureData); if (::IsWindow(m_hWnd)) RedrawWindow(); // Free surface mem delete [] pSurfaceTextureData; pSurfaceTextureData = 0; // Free the water texture data delete [] pWaterTexData; pWaterTexData = 0; } void CTerrainViewport::UpdateContent( int flags ) { //////////////////////////////////////////////////////////////////////// // Generate a new surface texture //////////////////////////////////////////////////////////////////////// DWORD *pSurfaceData = NULL; bool bReturn; // Allocate memory pSurfaceData = new DWORD[m_heightmapSize.cx*m_heightmapSize.cy]; ASSERT(pSurfaceData); bReturn = GetDocument()->GetHeightmap().GetPreviewBitmap( (DWORD*)pSurfaceData,m_heightmapSize.cx,false,false ); /* // Fill in the surface data into the array. Apply lighting and water, use // the settings from the document bReturn = cSurfaceTexture.GenerateSurface(pSurfaceData, SURFACE_TEXTURE_WIDTH, SURFACE_TEXTURE_WIDTH, true, true, GLOBAL_GET_DOC->GetWaterLevel(), true); */ if (bReturn) { m_bmpTerrain.SetBitmapBits( m_heightmapSize.cx*m_heightmapSize.cy*4, pSurfaceData); if (IsWindow(GetSafeHwnd())) RedrawWindow(); } // Free the surface data array delete [] pSurfaceData; pSurfaceData = 0; /* CCryEditDoc *doc = GLOBAL_GET_DOC; if (!doc) return; m_heightmapSize.cx = doc->m_cHeightmap.GetWidth(); m_heightmapSize.cy = doc->m_cHeightmap.GetHeight(); m_waterLevel = doc->GetWaterLevel(); /* //////////////////////////////////////////////////////////////////////// // Generate a new surface texture //////////////////////////////////////////////////////////////////////// CTerrainTexture cSurfaceTexture; bool bReturn; CLogFile::FormatLine("Updating top view surface data (%i x %i)...", m_textureSize.cx, m_textureSize.cy); // Allocate memory if (m_textureData) delete []m_textureData; if (!m_bShowHeightmap) { m_textureSize.cx = SURFACE_TEXTURE_WIDTH; m_textureSize.cy = SURFACE_TEXTURE_WIDTH; m_textureData = new uint[m_textureSize.cx * m_textureSize.cy]; ASSERT(m_textureData); // Fill in the surface data into the array. Apply lighting and water, use // the settings from the document bReturn = cSurfaceTexture.GenerateSurface( (unsigned long*)m_textureData,m_textureSize.cx,m_textureSize.cy,true,true,m_waterLevel,true); } else { m_textureSize.cx = 512; m_textureSize.cy = 512; m_textureData = new uint[m_textureSize.cx * m_textureSize.cy]; ASSERT(m_textureData); // Show heightmap data. //GLOBAL_GET_DOC->m_cHeightmap.GetDataEx(pHeightmap, (m_rcView.right - m_rcView.left), false, false); GLOBAL_GET_DOC->m_cHeightmap.GetPreviewBitmap( (DWORD*)m_textureData,m_textureSize.cx,false,false ); } m_textureValid = false; if (bReturn) { if (::IsWindow(m_hWnd)) RedrawWindow(); } if (m_bShowStatObjects) { int w,h; GetIEditor()->GetDocument()->GetStatObjDistArray( w,h ); if (m_statObjTexData) delete []m_statObjTexData; m_statObjTexSize.cx = w; m_statObjTexSize.cy = h; m_statObjTexData = new uint[w*h]; memset( m_statObjTexData,0,w*h ); DrawStaticObjects(); } */ SetZoomFactor( GetZoomFactor() ); } void CTerrainViewport::SetZoomFactor(float fZoomFactor) { //////////////////////////////////////////////////////////////////////// // Adjust the zoom factor of the view. If the passed values are invalid, // the nearest valid values will be set and false is returned //////////////////////////////////////////////////////////////////////// RECT rcWndPos; bool bRangeValid = true; float fNewSizeTemp = 0; float fEnlargementFactor; // Zero can produce artifacts and errors if (fZoomFactor == 0.0f) { fZoomFactor = m_fZoomFactor; bRangeValid = false; } // Obtain the dimensions of the window GetClientRect(&rcWndPos); // Is the new zoom factor smaller than the last one ? if (fZoomFactor < m_fZoomFactor) { // We might run into the problem that the map is smaller than the // the window when displayed with the specified zoom factor if (m_heightmapSize.cx * fZoomFactor < rcWndPos.right) { // Calculate the new size fZoomFactor = (float) rcWndPos.right / m_heightmapSize.cx; bRangeValid = false; } if (m_heightmapSize.cx * fZoomFactor < rcWndPos.bottom) { // Calculate the new size fNewSizeTemp = (float) rcWndPos.bottom / m_heightmapSize.cx; // Only set the new zoom if it is larger than the previous fZoomFactor = (fZoomFactor > fNewSizeTemp) ? fZoomFactor : fNewSizeTemp; bRangeValid = false; } } // Calculate how much larger the new zoom is compared to the old one fEnlargementFactor = fZoomFactor / m_fZoomFactor; // Save the new zoom factor m_fZoomFactor = fZoomFactor; if (m_cScrollOffset.x + m_heightmapSize.cx*fZoomFactor < rcWndPos.right) m_cScrollOffset.x = rcWndPos.right - m_heightmapSize.cx*fZoomFactor; if (m_cScrollOffset.y + m_heightmapSize.cy*fZoomFactor < rcWndPos.bottom) m_cScrollOffset.y = rcWndPos.bottom - m_heightmapSize.cy*fZoomFactor; if (m_cScrollOffset.x > 0) m_cScrollOffset.x = 0; if (m_cScrollOffset.y > 0) m_cScrollOffset.y = 0; RedrawWindow(); } void CTerrainViewport::OnPaint() { CPaintDC dc(this); // device context for painting if (!GetDocument()) return; int iX, iY, iWidth, iHeight; /* OLD // Blit the image dc.SetStretchBltMode(HALFTONE); dc.StretchBlt(iX, iY, iWidth, iHeight, &m_dcTerrain, 0, 0, m_heightmapSize.cx, m_heightmapSize.cy, SRCCOPY); // Reset brush origin after strech blit. dc.SetBrushOrg( 0,0 ); */ // Free any old bitmap first if (m_bmpView.GetSafeHandle()) { //m_dcView.SelectObject(NULL); ::SelectObject(m_dcView.m_hDC, NULL); m_bmpView.DeleteObject(); } CRect rc( dc.m_ps.rcPaint ); // Calculate the position and dimension of the image iX = m_cScrollOffset.x; iY = m_cScrollOffset.y; iWidth = (m_heightmapSize.cx * m_fZoomFactor); iHeight = (m_heightmapSize.cy * m_fZoomFactor); CPoint hp1 = ViewToHeightmap( CPoint(rc.left,rc.top) ); CPoint hp2 = ViewToHeightmap( CPoint(rc.right,rc.bottom) ); // Create bitmap BITMAPINFO BmpInfo; BmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); BmpInfo.bmiHeader.biWidth = hp2.x - hp1.x; BmpInfo.bmiHeader.biHeight = -(hp2.y - hp1.y); BmpInfo.bmiHeader.biPlanes = 1; BmpInfo.bmiHeader.biBitCount = 32; BmpInfo.bmiHeader.biCompression = BI_RGB; BmpInfo.bmiHeader.biSizeImage = 0; BmpInfo.bmiHeader.biXPelsPerMeter = 0; BmpInfo.bmiHeader.biYPelsPerMeter = 0; BmpInfo.bmiHeader.biClrUsed = 0; BmpInfo.bmiHeader.biClrImportant = 0; DWORD *pBits = NULL; // Create the DIB section to draw into HBITMAP bmpView = ::CreateDIBSection(m_dcView.m_hDC, &BmpInfo, DIB_RGB_COLORS,(void**)&pBits, NULL, 0); ASSERT(bmpView); m_bmpView.Attach(bmpView); // Select the DIB into the DC m_dcView.SelectObject( m_bmpView ); //////////////////////////////////////////////////////////////////////// // Draw the heightmap into the final image //////////////////////////////////////////////////////////////////////// //m_dcView.BitBlt( 0,0,m_heightmapSize.cx,m_heightmapSize.cy,&m_dcTerrain, 0, 0, SRCCOPY); m_dcView.BitBlt( 0, 0,hp2.x-hp1.x,hp2.y-hp1.y, &m_dcTerrain, hp1.x,hp1.y, SRCCOPY); //m_dcView.SetBrushOrg( 0,0 ); DrawStaticObjects( pBits, hp2.x-hp1.x,hp2.y-hp1.y, CRect(hp1,hp2) ); //dc.BitBlt( 0,0,rc.right,rc.bottom,&m_dcView, 0, 0, SRCCOPY); dc.SetStretchBltMode(COLORONCOLOR); dc.StretchBlt(iX, iY, iWidth, iHeight, &m_dcView, 0, 0, hp2.x-hp1.x,hp2.y-hp1.y, SRCCOPY); //dc.BitBlt(0,0,rc.right,rc.bottom, &m_dcView, 0, 0, SRCCOPY); // Reset brush origin after strech blit. dc.SetBrushOrg( 0,0 ); /* CPoint p; p.x = m_viewerPos.x; p.y = m_viewerPos.y; HMCoordToWndCoord( &p ); dc.Ellipse( p.x-3,p.y-3,p.x+3,p.y+3 ); */ // Do not call CViewport::OnPaint() for painting messages } void CTerrainViewport::DrawStaticObjects( DWORD* pBits,int trgWidth,int trgHeight,CRect rc ) { } BOOL CTerrainViewport::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { float prevz = GetZoomFactor(); float z = GetZoomFactor() + (zDelta / 120.0f) * 2.0f; // Zoom to mouse position. float x = (float)(m_cMousePos.x - m_cScrollOffset.x)/prevz; float y = (float)(m_cMousePos.y - m_cScrollOffset.y)/prevz; m_cScrollOffset.x = m_cMousePos.x - z*x; m_cScrollOffset.y = m_cMousePos.y - z*y; SetZoomFactor( z ); return TRUE; } void CTerrainViewport::OnMouseMove(UINT nFlags, CPoint point) { m_cMousePos = point; if (GetViewMode() == ScrollZoomMode) { CRect rc; // You can only scroll while the middle or right mouse button is down if (nFlags & MK_RBUTTON || nFlags & MK_MBUTTON) { if (nFlags & MK_SHIFT) { // Get the dimensions of the window GetClientRect(&rc); CRect rc; GetClientRect( rc ); int w = rc.right; int h = rc.bottom; // Zoom to mouse position. float z = m_prevZoomFactor + (point.y - m_cMouseDownPos.y) * 0.1f; float x = (float)(m_cMouseDownPos.x - m_prevScrollOffset.cx)/m_prevZoomFactor; float y = (float)(m_cMouseDownPos.y - m_prevScrollOffset.cy)/m_prevZoomFactor; m_cScrollOffset.x = m_cMouseDownPos.x - z*x; m_cScrollOffset.y = m_cMouseDownPos.y - z*y; SetZoomFactor( z ); } else { // Set the new scrolled coordinates SetScrollOffset(GetScrollOffset() + (point - m_cPrevMousePos)); } m_cPrevMousePos = point; } return; } // Only proceed when the mouse is over the drawing area if (nFlags & MK_LBUTTON) { // Calculate the coordinates in heightmap coordinates // Translate into drawing window coordinates CPoint hp = ViewToHeightmap(point); /* if (!(nFlags & MK_CONTROL)) { // Add new static objects GetIEditor()->GetDocument()->GetStatObjMap()->DistributeObjects( hp, m_iBrushSize ); } else { // Remove static objects GetIEditor()->GetDocument()->GetStatObjMap()->ClearObjects( hp, m_iBrushSize ); } */ /* // Redraw the modified area rcRedraw.left = point.x - m_scaledBrushSize; rcRedraw.top = point.y - m_scaledBrushSize; rcRedraw.right = point.x + m_scaledBrushSize; rcRedraw.bottom = point.y + m_scaledBrushSize; RedrawWindow(&rcRedraw, NULL, RDW_NOERASE | RDW_INVALIDATE); */ RedrawWindow(); } CViewport::OnMouseMove(nFlags, point); } BOOL CTerrainViewport::OnEraseBkgnd(CDC* pDC) { return TRUE; } void CTerrainViewport::OnSize(UINT nType, int cx, int cy) { CViewport::OnSize(nType, cx, cy); //////////////////////////////////////////////////////////////////////// // Re-evaluate the zoom / scroll offset values // TODO: Restore the zoom rectangle instead of resetting it //////////////////////////////////////////////////////////////////////// float fZoomFac1, fZoomFac2; fZoomFac1 = (float) cx / m_heightmapSize.cx; fZoomFac2 = (float) cx / m_heightmapSize.cy; SetZoomFactor((fZoomFac1 < fZoomFac2) ? fZoomFac1 : fZoomFac2); } void CTerrainViewport::OnRButtonDown(UINT nFlags, CPoint point) { if (GetViewMode() != NothingMode) return; /* if (GetIEditor()->GetEditMode() == eEditModeCreate) { // Stop creation. GetIEditor()->GetObjectManager()->MouseCreateCallback( this,MOUSECREATE_RPOINT,point,0 ); } */ // Save the mouse down position m_cMouseDownPos = point; m_cPrevMousePos = point; m_prevZoomFactor = GetZoomFactor(); m_prevScrollOffset = m_cScrollOffset; SetCapture(); SetViewMode( ScrollZoomMode ); CViewport::OnRButtonDown(nFlags, point); } void CTerrainViewport::OnRButtonUp(UINT nFlags, CPoint point) { ReleaseCapture(); SetViewMode( NothingMode ); CViewport::OnRButtonUp(nFlags, point); } void CTerrainViewport::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CViewport::OnLButtonDown(nFlags, point); } void CTerrainViewport::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CViewport::OnLButtonUp(nFlags, point); } CPoint CTerrainViewport::ViewToHeightmap( CPoint hp ) { hp.x -= m_cScrollOffset.x; hp.y -= m_cScrollOffset.y; // Scale with the zoom factor float z1 = 1.0f / GetZoomFactor(); int x = FloatToIntRet((float)hp.x * z1); int y = FloatToIntRet((float)hp.y * z1); if (x < 0) x = 0; if (y < 0) y = 0; if (x >= m_heightmapSize.cx) x = m_heightmapSize.cx-1; if (y >= m_heightmapSize.cx) y = m_heightmapSize.cx-1; return CPoint( x,y ); } CPoint CTerrainViewport::HeightmapToView( CPoint hp ) { int x = FloatToIntRet(hp.x * GetZoomFactor()); int y = FloatToIntRet(hp.y * GetZoomFactor()); // Add the offset x += m_cScrollOffset.x; y += m_cScrollOffset.y; return CPoint( x,y ); }