1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "TerrainTextureExport.h"
5 #include "Terrain/TerrainTexGen.h"
6 #include "Qt/Widgets/QWaitProgress.h"
7 #include "CryEditDoc.h"
8 #include "ResizeResolutionDialog.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>
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)
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()
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
);
60 BEGIN_MESSAGE_MAP(CTerrainTextureExport
, CDialog
)
61 //{{AFX_MSG_MAP(CTerrainTextureExport)
63 ON_COMMAND(IDC_EXPORT
, OnExport
)
64 ON_COMMAND(IDC_IMPORT
, OnImport
)
65 ON_COMMAND(IDC_CHANGE
, OnChangeResolutionBtn
)
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();
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()
102 void CTerrainTextureExport::PreviewToTile(uint32
& outX
, uint32
& outY
, uint32 x
, uint32 y
)
104 uint32 dwTileCountY
= GetIEditorImpl()->GetTerrainManager()->GetRGBLayer()->GetTileCountY();
107 outX
= dwTileCountY
- 1 - y
;
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)
127 // Generate a preview if we don't have one
128 if (!m_dcLightmap
.m_hDC
)
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
++)
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
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
)
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
);
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");
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
);
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()
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
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
);
249 ls
->iHemiSamplQuality
= skyQuality
;
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());
267 QString file
= CSystemFileDialog::RunExportFile(runParams
, nullptr);
269 return file
.toLocal8Bit().data();
273 QString file
= CSystemFileDialog::RunImportFile(runParams
, nullptr);
275 return file
.toLocal8Bit().data();
281 //////////////////////////////////////////////////////////////////////////
282 void CTerrainTextureExport::ImportExport(bool bIsImport
, bool bIsClipboard
)
287 filePath
= BrowseTerrainTexture(!bIsImport
);
288 SET_PERSONALIZATION_PROPERTY(CTerrainTextureExport
, szFileProperty
, filePath
.c_str());
289 if (filePath
.empty())
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();
306 PreviewToTile(right
, top
, rcSel
.left
, rcSel
.top
);
307 PreviewToTile(left
, bottom
, rcSel
.right
, rcSel
.bottom
);
310 pRGBLayer
->ImportExportBlock(bIsClipboard
? 0 : filePath
, left
, top
, right
+ 1, bottom
+ 1, &square
, bIsImport
);
314 if (square
> 2048 * 2048)
316 CQuestionDialog::SWarning(QObject::tr(""), QObject::tr("Save a level and generate terrain texture to see the result."));
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()
335 CHeightmap
* pHeightmap
= GetIEditorImpl()->GetHeightmap();
336 if (!pHeightmap
->IsAllocated())
339 ImportExport(false /*bIsImport*/);
342 //////////////////////////////////////////////////////////////////////////
343 void CTerrainTextureExport::OnImport()
348 CHeightmap
* pHeightmap
= GetIEditorImpl()->GetHeightmap();
349 if (!pHeightmap
->IsAllocated())
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)
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;
384 m_bSelectMode
= true;
389 DrawPreview(*(GetDC()));
392 //////////////////////////////////////////////////////////////////////////
393 void CTerrainTextureExport::OnLButtonUp(UINT nFlags
, CPoint point
)
398 m_bSelectMode
= false;
400 CDialog::OnLButtonUp(nFlags
, point
);
403 //////////////////////////////////////////////////////////////////////////
404 void CTerrainTextureExport::OnMouseMove(UINT nFlags
, CPoint point
)
406 CDialog::OnMouseMove(nFlags
, point
);
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
))
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."));
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
)
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)
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
)
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();