!XT (Code) Update copyright headers in Code/Sandbox.
[CRYENGINE.git] / Code / Sandbox / EditorQt / TerrainTextureExport.cpp
blob1e822a0ade8ce63f67b88448a27d72a457b2f3d3
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
4 #include "TerrainTextureExport.h"
5 #include "Terrain/TerrainTexGen.h"
6 #include "Qt/Widgets/QWaitProgress.h"
7 #include "CryEditDoc.h"
8 #include "ResizeResolutionDialog.h"
9 #include "Viewport.h"
10 #include "Terrain/TerrainManager.h"
11 #include "TerrainLighting.h"
12 #include "Controls/QuestionDialog.h"
13 #include "Util/FileUtil.h"
15 #include <EditorFramework/PersonalizationManager.h>
16 #include <FileDialogs/SystemFileDialog.h>
17 #include <FilePathUtil.h>
18 #include <QtUtil.h>
20 #define TERRAIN_PREVIEW_RESOLUTION 256
21 const char* szFileProperty = "File";
23 /////////////////////////////////////////////////////////////////////////////
24 // CTerrainTextureExport dialog
26 //CDC CTerrainTextureExport::m_dcLightmap;
28 CTerrainTextureExport::CTerrainTextureExport(CWnd* pParent /*=NULL*/)
29 : CDialog(CTerrainTextureExport::IDD, pParent)
31 //{{AFX_DATA_INIT(CTerrainTextureExport)
32 //}}AFX_DATA_INIT
34 m_cx = 19;
35 m_cy = 24;
37 m_bSelectMode = false;
38 rcSel.left = rcSel.top = rcSel.right = rcSel.bottom = -1;
40 m_pTexGen = new CTerrainTexGen;
41 m_pTexGen->Init(TERRAIN_PREVIEW_RESOLUTION, true);
44 CTerrainTextureExport::~CTerrainTextureExport()
46 delete m_pTexGen;
49 void CTerrainTextureExport::DoDataExchange(CDataExchange* pDX)
51 CDialog::DoDataExchange(pDX);
52 //{{AFX_DATA_MAP(CTerrainTextureExport)
53 DDX_Control(pDX, IDC_IMPORT, m_importBtn);
54 DDX_Control(pDX, IDC_EXPORT, m_exportBtn);
55 DDX_Control(pDX, IDCANCEL, m_closeBtn);
56 DDX_Control(pDX, IDC_CHANGE, m_changeResolutionBtn);
57 //}}AFX_DATA_MAP
60 BEGIN_MESSAGE_MAP(CTerrainTextureExport, CDialog)
61 //{{AFX_MSG_MAP(CTerrainTextureExport)
62 ON_WM_PAINT()
63 ON_COMMAND(IDC_EXPORT, OnExport)
64 ON_COMMAND(IDC_IMPORT, OnImport)
65 ON_COMMAND(IDC_CHANGE, OnChangeResolutionBtn)
66 ON_WM_MOUSEMOVE()
67 ON_WM_LBUTTONDOWN()
68 ON_WM_LBUTTONUP()
69 //}}AFX_MSG_MAP
70 END_MESSAGE_MAP()
72 /////////////////////////////////////////////////////////////////////////////
73 // CTerrainTextureExport message handlers
75 //////////////////////////////////////////////////////////////////////////
76 BOOL CTerrainTextureExport::OnInitDialog()
78 CDialog::OnInitDialog();
80 m_terrain.Allocate(TERRAIN_PREVIEW_RESOLUTION, TERRAIN_PREVIEW_RESOLUTION);
82 string filePath(GET_PERSONALIZATION_PROPERTY(CTerrainTextureExport, szFileProperty).toString().toLocal8Bit());
83 GetDlgItem(IDC_FILE)->SetWindowText(filePath);
85 CRGBLayer* pRGBLayer = GetIEditorImpl()->GetTerrainManager()->GetRGBLayer();
86 string maskInfoText;
87 maskInfoText.Format("RGB(%dx%d)",
88 pRGBLayer->CalcMinRequiredTextureExtend(),
89 pRGBLayer->CalcMinRequiredTextureExtend());
90 GetDlgItem(IDC_INFO_TEXT)->SetWindowText(maskInfoText);
92 return TRUE; // return TRUE unless you set the focus to a control
93 // EXCEPTION: OCX Property Pages should return FALSE
96 void CTerrainTextureExport::OnPaint()
98 CPaintDC dc(this);
99 DrawPreview(dc);
102 void CTerrainTextureExport::PreviewToTile(uint32& outX, uint32& outY, uint32 x, uint32 y)
104 uint32 dwTileCountY = GetIEditorImpl()->GetTerrainManager()->GetRGBLayer()->GetTileCountY();
106 // rotate 90 deg
107 outX = dwTileCountY - 1 - y;
108 outY = x;
111 //////////////////////////////////////////////////////////////////////////
112 void CTerrainTextureExport::DrawPreview(CDC& dc)
114 //CPaintDC dc(this); // device context for painting
115 CPen cGrayPen(PS_SOLID, 1, 0x007F7F7F);
116 CPen cRedPen(PS_SOLID, 1, 0x004040ff);
117 CPen cGreenPen(PS_SOLID, 1, 0x0000ff00);
118 CBrush brush(0x00808080);
120 CRGBLayer* pRGBLayer = GetIEditorImpl()->GetTerrainManager()->GetRGBLayer();
122 uint32 dwTileCountX = pRGBLayer->GetTileCountX();
123 uint32 dwTileCountY = pRGBLayer->GetTileCountY();
124 if (dwTileCountX == 0 || dwTileCountY == 0)
125 return;
127 // Generate a preview if we don't have one
128 if (!m_dcLightmap.m_hDC)
129 OnGenerate();
131 // Draw the preview
132 dc.BitBlt(m_cx, m_cy, TERRAIN_PREVIEW_RESOLUTION, TERRAIN_PREVIEW_RESOLUTION, &m_dcLightmap, 0, 0, SRCCOPY);
134 CPen* prevPen = dc.SelectObject(&cGrayPen);
136 dc.SetBkMode(TRANSPARENT);
137 for (int x = 0; x < dwTileCountX; x++)
138 for (int y = 0; y < dwTileCountY; y++)
140 RECT rc = {
141 m_cx + x * TERRAIN_PREVIEW_RESOLUTION / dwTileCountX, m_cy + y * TERRAIN_PREVIEW_RESOLUTION / dwTileCountY,
142 m_cx + (x + 1) * TERRAIN_PREVIEW_RESOLUTION / dwTileCountX, m_cy + (y + 1) * TERRAIN_PREVIEW_RESOLUTION / dwTileCountY
145 uint32 dwTileX;
146 uint32 dwTileY;
147 PreviewToTile(dwTileX, dwTileY, x, y);
148 uint32 dwLocalSize = pRGBLayer->GetTileResolution(dwTileX, dwTileY);
149 dc.SetTextColor(RGB(SATURATEB(dwLocalSize / 8), 0, 0));
151 if (rcSel.left <= x && rcSel.right >= x && rcSel.top <= y && rcSel.bottom >= y)
153 RECT rc = {
154 m_cx + x * TERRAIN_PREVIEW_RESOLUTION / dwTileCountX + 4, m_cy + y * TERRAIN_PREVIEW_RESOLUTION / dwTileCountY + 4,
155 m_cx + (x + 1) * TERRAIN_PREVIEW_RESOLUTION / dwTileCountX - 4, m_cy + (y + 1) * TERRAIN_PREVIEW_RESOLUTION / dwTileCountY - 4
157 dc.FillRect(&rc, &brush);
160 char str[32];
161 if (dwLocalSize == 1024)
162 cry_sprintf(str, "1k");
163 else if (dwLocalSize == 2048)
164 cry_sprintf(str, "2k");
165 else if (dwLocalSize == 4096)
166 cry_sprintf(str, "4k");
167 else
168 cry_sprintf(str, "%d", dwLocalSize);
169 dc.DrawText(str, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
173 dc.SelectObject(&cGreenPen);
174 for (int x = 0; x <= dwTileCountX; x++)
176 dc.MoveTo(m_cx + x * TERRAIN_PREVIEW_RESOLUTION / dwTileCountX, m_cy);
177 dc.LineTo(m_cx + x * TERRAIN_PREVIEW_RESOLUTION / dwTileCountX, m_cy + TERRAIN_PREVIEW_RESOLUTION);
179 for (int y = 0; y <= dwTileCountY; y++)
181 dc.MoveTo(m_cx, m_cy + y * TERRAIN_PREVIEW_RESOLUTION / dwTileCountY);
182 dc.LineTo(m_cx + TERRAIN_PREVIEW_RESOLUTION, m_cy + y * TERRAIN_PREVIEW_RESOLUTION / dwTileCountY);
185 if (rcSel.top >= 0)
187 RECT rc = {
188 m_cx + rcSel.left * TERRAIN_PREVIEW_RESOLUTION / dwTileCountX + 1, m_cy + rcSel.top * TERRAIN_PREVIEW_RESOLUTION / dwTileCountY + 1,
189 m_cx + (rcSel.right + 1) * TERRAIN_PREVIEW_RESOLUTION / dwTileCountX - 1, m_cy + (rcSel.bottom + 1) * TERRAIN_PREVIEW_RESOLUTION / dwTileCountY - 1
192 dc.SelectObject(&cRedPen);
194 dc.MoveTo(rc.left, rc.top);
195 dc.LineTo(rc.right, rc.top);
196 dc.LineTo(rc.right, rc.bottom);
197 dc.LineTo(rc.left, rc.bottom);
198 dc.LineTo(rc.left, rc.top);
201 dc.SelectObject(prevPen);
204 void CTerrainTextureExport::OnGenerate()
206 RECT rcUpdate;
208 BeginWaitCursor();
210 LightingSettings* ls = GetIEditorImpl()->GetDocument()->GetLighting();
212 int skyQuality = ls->iHemiSamplQuality;
213 ls->iHemiSamplQuality = 0;
215 // Create a DC and a bitmap
216 if (!m_dcLightmap.m_hDC)
217 VERIFY(m_dcLightmap.CreateCompatibleDC(NULL));
218 if (!m_bmpLightmap.m_hObject)
219 VERIFY(m_bmpLightmap.CreateBitmap(TERRAIN_PREVIEW_RESOLUTION, TERRAIN_PREVIEW_RESOLUTION, 1, 32, NULL));
220 m_dcLightmap.SelectObject(&m_bmpLightmap);
222 // Calculate the lighting.
223 CImageEx terrainImgTmp;
224 terrainImgTmp.Allocate(TERRAIN_PREVIEW_RESOLUTION, TERRAIN_PREVIEW_RESOLUTION);
225 m_pTexGen->InvalidateLighting();
226 m_pTexGen->GenerateSurfaceTexture(ETTG_LIGHTING | ETTG_QUIET | ETTG_ABGR | ETTG_BAKELIGHTING | ETTG_NOTEXTURE | ETTG_SHOW_WATER, terrainImgTmp);
228 m_terrain.RotateOrt(terrainImgTmp, 1);
230 // put m_terrain into m_bmpLightmap
232 BITMAPINFO bi;
234 ZeroStruct(bi);
235 bi.bmiHeader.biSize = sizeof(bi);
236 bi.bmiHeader.biWidth = m_terrain.GetWidth();
237 bi.bmiHeader.biHeight = -m_terrain.GetHeight();
238 bi.bmiHeader.biBitCount = 32;
239 bi.bmiHeader.biPlanes = 1;
240 bi.bmiHeader.biCompression = BI_RGB;
242 SetDIBits(m_dcLightmap.m_hDC, (HBITMAP)m_bmpLightmap.GetSafeHandle(), 0, m_terrain.GetHeight(), m_terrain.GetData(), &bi, false);
245 // Update the preview
246 ::SetRect(&rcUpdate, 10, 10, 20 + TERRAIN_PREVIEW_RESOLUTION, 30 + TERRAIN_PREVIEW_RESOLUTION);
247 InvalidateRect(&rcUpdate, FALSE);
248 UpdateWindow();
249 ls->iHemiSamplQuality = skyQuality;
251 EndWaitCursor();
254 //////////////////////////////////////////////////////////////////////////
255 string CTerrainTextureExport::BrowseTerrainTexture(bool bIsSave)
257 string filePath(GET_PERSONALIZATION_PROPERTY(CTerrainTextureExport, szFileProperty).toString().toLocal8Bit());
258 if (filePath.empty())
259 filePath = CFileUtil::FormatInitialFolderForFileDialog(PathUtil::GamePathToCryPakPath("", true).c_str()) + "terraintex.bmp";
261 CSystemFileDialog::RunParams runParams;
262 runParams.extensionFilters << CExtensionFilter("Bitmap Image File (*.bmp)", "bmp");
263 runParams.initialFile = QString::fromLocal8Bit(filePath.c_str());
265 if (bIsSave)
267 QString file = CSystemFileDialog::RunExportFile(runParams, nullptr);
268 if (!file.isEmpty())
269 return file.toLocal8Bit().data();
271 else
273 QString file = CSystemFileDialog::RunImportFile(runParams, nullptr);
274 if (!file.isEmpty())
275 return file.toLocal8Bit().data();
278 return "";
281 //////////////////////////////////////////////////////////////////////////
282 void CTerrainTextureExport::ImportExport(bool bIsImport, bool bIsClipboard)
284 string filePath;
285 if (!bIsClipboard)
287 filePath = BrowseTerrainTexture(!bIsImport);
288 SET_PERSONALIZATION_PROPERTY(CTerrainTextureExport, szFileProperty, filePath.c_str());
289 if (filePath.empty())
290 return;
292 GetDlgItem(IDC_FILE)->SetWindowText(filePath);
295 CHeightmap* pHeightmap = GetIEditorImpl()->GetHeightmap();
296 CRGBLayer* pRGBLayer = GetIEditorImpl()->GetTerrainManager()->GetRGBLayer();
298 uint32 dwTileCountX = pRGBLayer->GetTileCountX();
299 uint32 dwTileCountY = pRGBLayer->GetTileCountY();
301 uint32 left;
302 uint32 top;
303 uint32 right;
304 uint32 bottom;
306 PreviewToTile(right, top, rcSel.left, rcSel.top);
307 PreviewToTile(left, bottom, rcSel.right, rcSel.bottom);
309 uint32 square;
310 pRGBLayer->ImportExportBlock(bIsClipboard ? 0 : filePath, left, top, right + 1, bottom + 1, &square, bIsImport);
312 if (bIsImport)
314 if (square > 2048 * 2048)
316 CQuestionDialog::SWarning(QObject::tr(""), QObject::tr("Save a level and generate terrain texture to see the result."));
318 else
320 RECT rc = {
321 left* pHeightmap->GetWidth() / dwTileCountX, top * pHeightmap->GetHeight() / dwTileCountY,
322 (right + 1) * pHeightmap->GetWidth() / dwTileCountX, (bottom + 1) * pHeightmap->GetHeight() / dwTileCountY
324 pHeightmap->UpdateLayerTexture(rc);
329 //////////////////////////////////////////////////////////////////////////
330 void CTerrainTextureExport::OnExport()
332 if (rcSel.top < 0)
333 return;
335 CHeightmap* pHeightmap = GetIEditorImpl()->GetHeightmap();
336 if (!pHeightmap->IsAllocated())
337 return;
339 ImportExport(false /*bIsImport*/);
342 //////////////////////////////////////////////////////////////////////////
343 void CTerrainTextureExport::OnImport()
345 if (rcSel.top < 0)
346 return;
348 CHeightmap* pHeightmap = GetIEditorImpl()->GetHeightmap();
349 if (!pHeightmap->IsAllocated())
350 return;
352 ImportExport(true /*bIsImport*/);
354 GetIEditorImpl()->SetModifiedFlag();
357 //////////////////////////////////////////////////////////////////////////
358 void CTerrainTextureExport::OnLButtonDown(UINT nFlags, CPoint point)
360 CDialog::OnLButtonDown(nFlags, point);
362 CRGBLayer* pRGBLayer = GetIEditorImpl()->GetTerrainManager()->GetRGBLayer();
364 uint32 dwTileCountX = pRGBLayer->GetTileCountX();
365 uint32 dwTileCountY = pRGBLayer->GetTileCountY();
366 if (dwTileCountX == 0 || dwTileCountY == 0)
367 return;
369 int x = (point.x - m_cx) * dwTileCountX / TERRAIN_PREVIEW_RESOLUTION;
370 int y = (point.y - m_cy) * dwTileCountY / TERRAIN_PREVIEW_RESOLUTION;
372 if (x >= 0 && y >= 0 && x < dwTileCountX && y < dwTileCountY)
374 if (rcSel.left == x && rcSel.top == y && rcSel.right == x && rcSel.bottom == y)
376 rcSel.left = rcSel.top = rcSel.right = rcSel.bottom = -1;
378 else
380 rcSel.left = x;
381 rcSel.top = y;
382 rcSel.right = x;
383 rcSel.bottom = y;
384 m_bSelectMode = true;
385 SetCapture();
389 DrawPreview(*(GetDC()));
392 //////////////////////////////////////////////////////////////////////////
393 void CTerrainTextureExport::OnLButtonUp(UINT nFlags, CPoint point)
395 if (m_bSelectMode)
397 ReleaseCapture();
398 m_bSelectMode = false;
400 CDialog::OnLButtonUp(nFlags, point);
403 //////////////////////////////////////////////////////////////////////////
404 void CTerrainTextureExport::OnMouseMove(UINT nFlags, CPoint point)
406 CDialog::OnMouseMove(nFlags, point);
408 if (!m_bSelectMode)
409 return;
411 if (nFlags & MK_LBUTTON)
413 CRGBLayer* pRGBLayer = GetIEditorImpl()->GetTerrainManager()->GetRGBLayer();
415 uint32 dwTileCountX = pRGBLayer->GetTileCountX();
416 uint32 dwTileCountY = pRGBLayer->GetTileCountY();
418 int x = (point.x - m_cx) * dwTileCountX / TERRAIN_PREVIEW_RESOLUTION;
419 int y = (point.y - m_cy) * dwTileCountY / TERRAIN_PREVIEW_RESOLUTION;
421 if (x >= 0 && y >= 0 && x >= rcSel.left && y >= rcSel.top && x < dwTileCountX && y < dwTileCountY
422 && (x != rcSel.right || y != rcSel.bottom))
424 rcSel.right = x;
425 rcSel.bottom = y;
426 DrawPreview(*(GetDC()));
431 //////////////////////////////////////////////////////////////////////////
432 void CTerrainTextureExport::OnChangeResolutionBtn()
434 if (rcSel.left == -1 || rcSel.top == -1)
436 CQuestionDialog::SCritical(QObject::tr("Error"), QObject::tr("Error: You have to select a sector."));
437 return;
440 uint32 dwTileX;
441 uint32 dwTileY;
442 PreviewToTile(dwTileX, dwTileY, rcSel.left, rcSel.top);
444 CHeightmap* pHeightmap = GetIEditorImpl()->GetHeightmap();
446 CResizeResolutionDialog dlg;
447 uint32 dwCurSize = pHeightmap->GetRGBLayer()->GetTileResolution(dwTileX, dwTileY);
448 dlg.SetSize(dwCurSize);
449 if (dlg.DoModal() != IDOK)
450 return;
452 uint32 dwNewSize = dlg.GetSize();
454 for (uint32 y = rcSel.top; y <= rcSel.bottom; ++y)
455 for (uint32 x = rcSel.left; x <= rcSel.right; ++x)
457 PreviewToTile(dwTileX, dwTileY, x, y);
459 uint32 dwOldSize = pHeightmap->GetRGBLayer()->GetTileResolution(dwTileX, dwTileY);
460 if (dwOldSize == dwNewSize || dwNewSize < 64 || dwNewSize > 2048)
461 continue;
463 GetIEditorImpl()->GetTerrainManager()->GetHeightmap()->GetRGBLayer()->ChangeTileResolution(dwTileX, dwTileY, dwNewSize);
464 GetIEditorImpl()->GetDocument()->SetModifiedFlag(TRUE);
466 // update terrain preview image in the dialog
467 DrawPreview(*(GetDC()));
469 // update 3D Engine display
470 I3DEngine* p3DEngine = GetIEditorImpl()->Get3DEngine();
472 int nTerrainSize = p3DEngine->GetTerrainSize();
473 int nTexSectorSize = p3DEngine->GetTerrainTextureNodeSizeMeters();
474 uint32 dwCountX = pHeightmap->GetRGBLayer()->GetTileCountX();
475 uint32 dwCountY = pHeightmap->GetRGBLayer()->GetTileCountY();
477 if (!nTexSectorSize || !nTerrainSize || !dwCountX)
478 continue;
480 int numTexSectorsX = nTerrainSize / dwCountX / nTexSectorSize;
481 int numTexSectorsY = nTerrainSize / dwCountY / nTexSectorSize;
483 for (int iY = 0; iY < numTexSectorsY; ++iY)
484 for (int iX = 0; iX < numTexSectorsX; ++iX)
485 pHeightmap->UpdateSectorTexture(CPoint(iX + dwTileX * numTexSectorsY, iY + dwTileY * numTexSectorsX), 0, 0, 1, 1);
488 GetIEditorImpl()->GetActiveView()->Update();