2 #include "AutoGeneratorTextureCreator.h"
3 #include "AutoGeneratorHelper.h"
4 #include "AutoGeneratorDataBase.h"
5 #include "Material/Material.h"
7 #include "Material/MaterialManager.h"
8 #include <CryRenderer/IMeshBaking.h>
9 #include <CryRenderer/ITexture.h>
10 #include "Util/Image.h"
11 #include "Util/ImageTIF.h"
13 #include "Controls/QuestionDialog.h"
14 #include "Util/FileUtil.h"
15 #include "FilePathUtil.h"
17 #define MAX_MAT_SLOTS 127
19 namespace LODGenerator
21 CAutoGeneratorTextureCreator::CAutoGeneratorTextureCreator()
27 CAutoGeneratorTextureCreator::~CAutoGeneratorTextureCreator()
32 void CAutoGeneratorTextureCreator::SetWidth(int iWidth
)
37 void CAutoGeneratorTextureCreator::SetHeight(int iHeight
)
42 bool CAutoGeneratorTextureCreator::Generate(int level
)
44 if (!GenerateTexture(level
))
46 if (!SaveTextures(level
))
51 bool CAutoGeneratorTextureCreator::GenerateTexture(int level
)
53 CAutoGeneratorDataBase
* pAutoGeneratorDataBase
= CAutoGeneratorDataBase::Instance();
54 CAutoGeneratorParams
& autoGeneratorParams
= CAutoGeneratorDataBase::Instance()->GetParams();
56 SMeshBakingMaterialParams params
[MAX_MAT_SLOTS
];
57 CMaterial
* pMat
= pAutoGeneratorDataBase
->GetLoadedMaterial();
61 const int nSubMatId
= pAutoGeneratorDataBase
->GetSubMatId(level
);
62 const int nSourceLod
= autoGeneratorParams
.GetGeometryOption
<int>("nSourceLod");
63 const float fRayLength
= autoGeneratorParams
.GetMaterialOption
<float>("RayTestLength");
64 const float fRayIndent
= autoGeneratorParams
.GetMaterialOption
<float>("RayStartDist");
65 const bool bAlpha
= autoGeneratorParams
.GetMaterialOption
<bool>("BakeAlpha");
66 const bool bSmoothCage
= autoGeneratorParams
.GetMaterialOption
<bool>("SmoothCage");
68 const bool bDilationPass
= false;//autoGeneratorParams.GetMaterialOption<bool>("DilationPass");
69 const int nBackgroundColour
= autoGeneratorParams
.GetMaterialOption
<int>("BackgroundColour");
70 const bool bSaveSpec
= autoGeneratorParams
.GetMaterialOption
<bool>("BakeUniqueSpecularMap");
71 const bool bUseAutoTextureSize
= autoGeneratorParams
.GetMaterialOption
<bool>("UseAutoTextureSize");
73 int nTWidth
= m_iWidth
;
74 int nTHeight
= m_iHeight
;
75 if(bUseAutoTextureSize
)
77 CryLog("Using AutoTextureSize...");
78 // Fill out the list with the size options
79 std::vector
< std::pair
<float,int> > textureSizeList
;
80 const float autoRadius1
= autoGeneratorParams
.GetMaterialOption
<float>("AutoTextureRadius1");
81 const int autoSize1
= autoGeneratorParams
.GetMaterialOption
<int>("AutoTextureSize1");
82 textureSizeList
.push_back(std::pair
<float,int>(autoRadius1
,autoSize1
));
84 const float autoRadius2
= autoGeneratorParams
.GetMaterialOption
<float>("AutoTextureRadius2");
85 const int autoSize2
= autoGeneratorParams
.GetMaterialOption
<int>("AutoTextureSize2");
86 textureSizeList
.push_back(std::pair
<float,int>(autoRadius2
,autoSize2
));
88 const float autoRadius3
= autoGeneratorParams
.GetMaterialOption
<float>("AutoTextureRadius3");
89 const int autoSize3
= autoGeneratorParams
.GetMaterialOption
<int>("AutoTextureSize3");
90 textureSizeList
.push_back(std::pair
<float,int>(autoRadius3
,autoSize3
));
92 std::sort(textureSizeList
.begin(),textureSizeList
.end(),std::greater
< std::pair
<float,int> >());
94 // Find the best setting to use on this model
95 int textureSize
= m_iWidth
; // Width and height should always be the same! There's only one size option in the UI.
96 IStatObj
*mesh
= pAutoGeneratorDataBase
->GetLoadedModel(level
);
99 float objectSize
= mesh
->GetAABB().GetRadius();
100 for(int i
= 0;i
<textureSizeList
.size();i
++)
102 if(objectSize
> textureSizeList
[i
].first
)
104 textureSize
= textureSizeList
[i
].second
;
108 CryLog("AutoTextureSize Object Radius: %f, Texture Size: %d",objectSize
,textureSize
);
110 nTWidth
= textureSize
;
111 nTHeight
= textureSize
;
114 const int submatCount
= pMat
->GetSubMaterialCount();
115 for ( int idx
= 0; idx
< submatCount
&& idx
< MAX_MAT_SLOTS
; ++idx
)
117 params
[idx
].rayLength
=fRayLength
;
118 params
[idx
].rayIndent
=fRayIndent
;
119 params
[idx
].bAlphaCutout
=bAlpha
;
120 params
[idx
].bIgnore
= (idx
!= nSubMatId
);
122 if (!params
[idx
].bIgnore
&& !VerifyNoOverlap(nSubMatId
))
124 if (QDialogButtonBox::StandardButton::No
== CQuestionDialog::SQuestion("UV Layout", "Detected overlapping UVs in target mesh. This could cause artifacts. Continue anyway?"))
129 SMeshBakingInputParams inParams
;
130 inParams
.pInputMesh
= pAutoGeneratorDataBase
->GetLoadedModel(nSourceLod
);
131 inParams
.pInputCharacter
=NULL
;
132 inParams
.pCageMesh
= pAutoGeneratorDataBase
->GetLoadedModel(level
);
133 inParams
.pCageCharacter
=NULL
;
134 inParams
.outputTextureWidth
=2*nTWidth
; // Bake out at twice resolution, we'll half it during conversion so it'll match the selected resolution
135 inParams
.outputTextureHeight
=2*nTHeight
;
136 inParams
.pMaterialParams
=params
;
137 inParams
.numMaterialParams
=submatCount
;
138 inParams
.nLodId
= level
;
139 inParams
.bDoDilationPass
=bDilationPass
;
140 inParams
.bSaveSpecular
= bSaveSpec
;
141 inParams
.dilateMagicColour
=ColorF(-16.0f
, -16.0f
, -16.0f
, -16.0f
); // Use the fact it's a floating point target to use a colour that'll never occur
142 inParams
.defaultBackgroundColour
=ColorF(GetRValue(nBackgroundColour
)/255.0f
, GetGValue(nBackgroundColour
)/255.0f
, GetBValue(nBackgroundColour
)/255.0f
, 1.0f
);
143 inParams
.bSmoothNormals
=bSmoothCage
;
144 inParams
.pMaterial
=pMat
->GetMatInfo();
146 SMeshBakingOutput pReturnValues
;
147 bool ret
= gEnv
->pRenderer
->BakeMesh(&inParams
, &pReturnValues
);
150 pAutoGeneratorDataBase
->GetBakeTextureResult().insert(std::pair
<int,SMeshBakingOutput
>(level
,pReturnValues
));
155 bool CAutoGeneratorTextureCreator::SaveTextures(const int level
)
157 CAutoGeneratorDataBase
* pAutoGeneratorDataBase
= CAutoGeneratorDataBase::Instance();
158 std::map
<int,SMeshBakingOutput
>& resultsMap
= pAutoGeneratorDataBase
->GetBakeTextureResult();
159 CAutoGeneratorParams
& autoGeneratorParams
= CAutoGeneratorDataBase::Instance()->GetParams();
161 if ( resultsMap
.find(level
) == resultsMap
.end())
164 string exportPath
= autoGeneratorParams
.GetMaterialOption
<string
>("ExportPath");
165 bool bBakeAlpha
= autoGeneratorParams
.GetMaterialOption
<bool>("BakeAlpha");
166 string filenamePattern
= autoGeneratorParams
.GetMaterialOption
<string
>("FilenameTemplate");
167 bool bSaveSpec
= autoGeneratorParams
.GetMaterialOption
<bool>("BakeUniqueSpecularMap");
169 for (int i
=CAutoGeneratorDataBase::eTextureType_Diffuse
; i
<CAutoGeneratorDataBase::eTextureType_Max
; i
++)
171 if ( i
== CAutoGeneratorDataBase::eTextureType_Spec
&& !bSaveSpec
)
174 string cPath
= CAutoGeneratorHelper::GetDefaultTextureName(i
,level
,bBakeAlpha
,exportPath
,filenamePattern
);
175 cPath
= PathUtil::Make(PathUtil::GetGameProjectAssetsPath(), cPath
);
176 CFileUtil::CreatePath(PathUtil::GetParentDirectory(cPath
));
177 bool checkedOut
= CAutoGeneratorHelper::CheckoutOrExtract(cPath
);
178 string preset
= GetPreset(i
);
179 bool bSaveAlpha
= (i
==CAutoGeneratorDataBase::eTextureType_Diffuse
&& bBakeAlpha
) || (i
==CAutoGeneratorDataBase::eTextureType_Normal
);
180 SaveTexture(resultsMap
[level
].ppOuputTexture
[i
], bSaveAlpha
, cPath
, preset
);
182 CAutoGeneratorHelper::CheckoutOrExtract(cPath
);
184 AssignToMaterial(level
,bBakeAlpha
,bSaveSpec
,exportPath
,filenamePattern
);
185 pAutoGeneratorDataBase
->ReloadModel();
190 string
CAutoGeneratorTextureCreator::GetPreset(const int texturetype
)
192 CAutoGeneratorParams
& autoGeneratorParams
= CAutoGeneratorDataBase::Instance()->GetParams();
197 case CAutoGeneratorDataBase::eTextureType_Diffuse
: preset
= autoGeneratorParams
.GetMaterialOption
<string
>("DiffuseTexturePreset");
199 case CAutoGeneratorDataBase::eTextureType_Normal
: preset
= autoGeneratorParams
.GetMaterialOption
<string
>("NormalTexturePreset");
201 case CAutoGeneratorDataBase::eTextureType_Spec
: preset
= autoGeneratorParams
.GetMaterialOption
<string
>("SpecularTexturePreset");
205 // NOTE: backwards-compatibility for old lod-settings
206 preset
.Replace("Normalmap_lowQ", "NormalsWithSmoothness");
207 preset
.Replace("Normalmap_highQ", "NormalsWithSmoothness");
208 preset
.Replace("NormalmapWithGlossInAlpha_highQ", "NormalsWithSmoothness");
209 preset
.Replace("Diffuse_lowQ", "Albedo");
210 preset
.Replace("Diffuse_highQ", "Albedo");
211 preset
.Replace("Specular_highQ", "Reflectance");
212 preset
.Replace("Specular_lowQ", "Reflectance");
218 void CAutoGeneratorTextureCreator::AssignToMaterial(const int nLod
, const bool bAlpha
, const bool bSaveSpec
, const string
& exportPath
, const string
& fileNameTemplate
)
220 CAutoGeneratorDataBase
* pAutoGeneratorDataBase
= CAutoGeneratorDataBase::Instance();
221 CAutoGeneratorParams
& autoGeneratorParams
= CAutoGeneratorDataBase::Instance()->GetParams();
223 CMaterial
* pMtl
= pAutoGeneratorDataBase
->GetLODMaterial();
226 bool checkedOut
= CAutoGeneratorHelper::CheckoutOrExtract(pMtl
->GetFilename());
230 // Generate base name
233 lodId
.Format("_lod%d.", nLod
);
234 relFile
=pAutoGeneratorDataBase
->GetLoadedModel()->GetFilePath();
235 relFile
.Replace(".", lodId
);
236 string
submatName(PathUtil::GetFileName(relFile
));
238 // const int nSubMatId = FindExistingLODMaterial(submatName);
239 const int nSubMatId
= pAutoGeneratorDataBase
->GetSubMatId(nLod
);
241 ColorF
diffuse(half
, half
, half
, 1.0f
);
242 ColorF
specular(half
, half
, half
, 1.0f
);
243 ColorF
emittance(half
, half
, half
, 0.0f
);
244 float opacity
= 1.0f
;
245 float smoothness
= 1.0f
;
249 CryLog("Error in AssignToMaterial: nSubMatId is -1");
253 CMaterial
* pTemplateMaterial
= GetIEditor()->GetMaterialManager()->LoadMaterial("%EDITOR%/Materials/lodgen_template.mtl");
254 if (pTemplateMaterial
)
256 pTemplateMaterial
->AddRef();
257 SInputShaderResources
&sr
=pTemplateMaterial
->GetShaderResources();
259 diffuse
= sr
.m_LMaterial
.m_Diffuse
;
260 specular
= sr
.m_LMaterial
.m_Specular
;
261 emittance
= sr
.m_LMaterial
.m_Emittance
;
262 opacity
= sr
.m_LMaterial
.m_Opacity
;
263 smoothness
= sr
.m_LMaterial
.m_Smoothness
;
265 pTemplateMaterial
->Release();
268 int subMaterialCount
=pMtl
->GetSubMaterialCount();
269 CMaterial
*pSubMat
=pMtl
->GetSubMaterial(nSubMatId
);
272 //load material template
273 pSubMat
= CAutoGeneratorHelper::CreateMaterialFromTemplate(submatName
);
275 if ( nSubMatId
>= subMaterialCount
)
276 pMtl
->SetSubMaterialCount(nSubMatId
+1);
277 pMtl
->SetSubMaterial(nSubMatId
,pSubMat
);
282 SInputShaderResources
&sr
=pSubMat
->GetShaderResources();
283 sr
.m_Textures
[EFTT_DIFFUSE
].m_Name
= CAutoGeneratorHelper::GetDefaultTextureName(0, nLod
, bAlpha
, exportPath
, fileNameTemplate
);
284 sr
.m_Textures
[EFTT_NORMALS
].m_Name
= CAutoGeneratorHelper::GetDefaultTextureName(1, nLod
, bAlpha
, exportPath
, fileNameTemplate
);
286 sr
.m_Textures
[EFTT_SPECULAR
].m_Name
= CAutoGeneratorHelper::GetDefaultTextureName(2, nLod
, bAlpha
, exportPath
, fileNameTemplate
);
288 sr
.m_Textures
[EFTT_SPECULAR
].m_Name
= "";
291 specular
= ColorF(1.0f
,1.0f
,1.0f
,1.0f
);
293 sr
.m_LMaterial
.m_Diffuse
= diffuse
;
294 sr
.m_LMaterial
.m_Specular
= specular
;
295 sr
.m_LMaterial
.m_Emittance
= emittance
;
296 sr
.m_LMaterial
.m_Opacity
= opacity
;
297 sr
.m_LMaterial
.m_Smoothness
= smoothness
;
299 sr
.m_AlphaRef
=bAlpha
?0.5f
:0.0f
;
301 sr
.m_VoxelCoverage
=255;
306 if(!pMtl
->Save(false))
308 CQuestionDialog::SWarning("Material File Save Failed", "The material file cannot be saved. The file is located in a PAK archive or access is denied");
315 bool CAutoGeneratorTextureCreator::SaveTexture(ITexture
* pTex
,const bool bAlpha
,const string
& fileName
,const string
& texturePreset
)
322 byte
*pStorage
=new byte
[pTex
->GetWidth()*pTex
->GetHeight()*4];
325 byte
*pData
=pTex
->GetData32(0,0,pStorage
);
330 int h
=pTex
->GetHeight();
331 int w
=pTex
->GetWidth();
332 byte
*pThreeChannelData
=new byte
[w
*h
*3];
333 for (int y
=0; y
<h
; y
++)
335 for (int x
=0; x
<w
; x
++)
340 pThreeChannelData
[pidx3
+0]=pData
[pidx4
+0];
341 pThreeChannelData
[pidx3
+1]=pData
[pidx4
+1];
342 pThreeChannelData
[pidx3
+2]=pData
[pidx4
+2];
345 bSaved
=tif
.SaveRAW(fileName
, pThreeChannelData
, pTex
->GetWidth(), pTex
->GetHeight(), 1, 3, false, texturePreset
);
346 delete[] pThreeChannelData
;
350 bSaved
=tif
.SaveRAW(fileName
, pData
, pTex
->GetWidth(), pTex
->GetHeight(), 1, 4, false, texturePreset
);
359 bool CAutoGeneratorTextureCreator::VerifyNoOverlap(const int nSubMatIdx
)
361 CAutoGeneratorDataBase
* pAutoGeneratorDataBase
= CAutoGeneratorDataBase::Instance();
363 IStatObj
*pCage
= pAutoGeneratorDataBase
->GetLoadedModel();
366 IRenderMesh
*pRM
= pCage
->GetRenderMesh();
369 InputLayoutHandle fmt
= pRM
->GetVertexFormat();
370 if (fmt
==EDefaultInputLayouts::P3F_C4B_T2F
|| fmt
==EDefaultInputLayouts::P3S_C4B_T2S
|| fmt
== EDefaultInputLayouts::P3S_N4B_C4B_T2S
)
372 std::vector
<Vec2
> uvList
;
373 pRM
->LockForThreadAccess();
374 const vtx_idx
*pIndices
= pRM
->GetIndexPtr(FSL_READ
);
377 const byte
*pUVs
= pRM
->GetUVPtr(uvStride
, FSL_READ
);
378 if (pIndices
&& pUVs
)
380 TRenderChunkArray
& chunkList
=pRM
->GetChunks();
381 for (int j
=0; j
<chunkList
.size(); j
++)
383 CRenderChunk
&c
= chunkList
[j
];
384 if (c
.m_nMatID
== nSubMatIdx
&& c
.nNumVerts
>0)
386 for (int idx
= c
.nFirstIndexId
; idx
<c
.nFirstIndexId
+c
.nNumIndices
; idx
++)
388 vtx_idx index
= pIndices
[idx
];
389 if (fmt
== EDefaultInputLayouts::P3F_C4B_T2F
)
391 const Vec2
*uv
= (Vec2
*)&pUVs
[uvStride
*index
];
392 uvList
.push_back(*uv
);
396 const Vec2f16
*uv16
= (Vec2f16
*)&pUVs
[uvStride
*index
];
397 uvList
.push_back(uv16
->ToVec2());
404 pRM
->UnLockForThreadAccess();
408 byte
*buffer
= new byte
[width
*width
];
409 memset(buffer
, 0, sizeof(byte
)*width
*width
);
411 for (int i
=0; i
<uvList
.size(); i
+=3)
413 if (CAutoGeneratorHelper::RasteriseTriangle(&uvList
[i
], buffer
, width
, width
))