Files
FC1/Cry3DEngine/LMSerializationManager2.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

1067 lines
37 KiB
C++

#define NO_GDI
#include "stdafx.h"
#undef NO_GDI
#include "Cry3dEngineBase.h"
//#include <d3d8types.h>
#include "dds.h"
#include "LMSerializationManager2.h"
#include <StringUtils.h>
#include "IEntityRenderState.h"
#include <algorithm> // STL find
#include <set> // STL set<>
#include <memory>
#include "ObjMan.h"
#include "Brush.h"
#define LEVELLM_PAK_NAME "LevelLM.pak"
CLMSerializationManager2::CLMSerializationManager2(){}
CLMSerializationManager2::~CLMSerializationManager2()
{
for (std::vector<RawLMData *>::iterator itLMData=m_vLightPatches.begin(); itLMData!=m_vLightPatches.end(); itLMData++)
delete (*itLMData);
}
void CLMSerializationManager2::AddRawLMData(
const DWORD indwWidth, const DWORD indwHeight, const std::vector<int>& _vGLM_IDs_UsingPatch,
BYTE *_pColorLerp4, BYTE *_pHDRColorLerp4, BYTE *_pDomDirection3, BYTE *_pOccl2)
{
std::vector<RawLMData *>::iterator itLMData;
// for all stored lightmaps
for(itLMData=m_vLightPatches.begin(); itLMData!=m_vLightPatches.end();)
{
std::vector<int>::const_iterator itID;
RawLMData *pCurRawLMData = *itLMData;
// for all the given new object ids
for (itID=_vGLM_IDs_UsingPatch.begin(); itID!=_vGLM_IDs_UsingPatch.end(); itID++)
{
int id=*itID;
std::vector<int>::iterator itRemove=std::find(pCurRawLMData->vGLM_IDs_UsingPatch.begin(),pCurRawLMData->vGLM_IDs_UsingPatch.end(),id);
if(itRemove!=pCurRawLMData->vGLM_IDs_UsingPatch.end())
pCurRawLMData->vGLM_IDs_UsingPatch.erase(itRemove);
}
// if the lightmap is no longer used by any object - remove it
if(pCurRawLMData->vGLM_IDs_UsingPatch.empty())
{
delete pCurRawLMData;
pCurRawLMData=0;
itLMData=m_vLightPatches.erase(itLMData);
}
else
++itLMData;
}
RawLMData* pRawLM = new RawLMData(indwWidth, indwHeight,_vGLM_IDs_UsingPatch);
pRawLM->initFromBMP (RawLMData::TEX_COLOR, _pColorLerp4);
pRawLM->initFromBMP (RawLMData::TEX_DOMDIR, _pDomDirection3);
if(_pOccl2 != 0)
{
pRawLM->initFromBMP (RawLMData::TEX_OCCL, _pOccl2);
pRawLM->m_bUseOcclMaps = true;
}
else
pRawLM->m_bUseOcclMaps = false;
if(_pHDRColorLerp4 != 0)
{
pRawLM->initFromBMP (RawLMData::TEX_HDR, _pHDRColorLerp4);
pRawLM->m_bUseHDRMaps = true;
}
else
pRawLM->m_bUseHDRMaps = false;
m_vLightPatches.push_back(pRawLM);
}
void CLMSerializationManager2::AddTexCoordData(const std::vector<TexCoord2Comp>& vTexCoords, int iGLM_ID_UsingTexCoord, const DWORD indwHashValue, const std::vector<std::pair<EntityId, EntityId> >& rOcclIDs)
{
m_vTexCoords[iGLM_ID_UsingTexCoord] = RawTexCoordData(vTexCoords,indwHashValue, rOcclIDs);
}
struct AutoFileCloser: Cry3DEngineBase
{
AutoFileCloser(FILE*pFile):m_pFile(pFile){}
~AutoFileCloser(){if (m_pFile)GetPak()->FClose(m_pFile);}
protected:
FILE* m_pFile;
};
#ifdef WIN64
#pragma warning( push ) //AMD Port
#pragma warning( disable : 4267 )
#endif
bool CLMSerializationManager2::_Load( const char *pszFileName, std::vector<IEntityRender *> *inpIGLMs, const bool cbLoadTextures)
{
// ---------------------------------------------------------------------------------------------
// Reconstruct lightmap data from pszFileName
// ---------------------------------------------------------------------------------------------
GetSystem()->GetILog()->UpdateLoadingScreen("\003Loading lightmaps ...");
string strDirName = CryStringUtils::GetParentDirectory<string>(pszFileName);
// make sure the pak file in which this LM data resides is opened
GetPak()->OpenPack ((strDirName + "\\" LEVELLM_PAK_NAME).c_str());
FileHeader sHeader;
size_t iNumItemsRead;
std::map<int, RenderLMData_AutoPtr> mapLMData; // only used if inpIGLMs!=0
if(inpIGLMs)
{
if(inpIGLMs->empty())
{
GetSystem()->GetILog()->Log("No GLMs to load lightmaps for");
return false;
}
}
else
{
assert(m_vLightPatches.empty());
assert(m_vTexCoords.empty());
}
// Open file
FILE* hFile = GetPak()->FOpen(pszFileName, "rb");
if (hFile == NULL)
{
GetSystem()->GetILog()->Log("Could not load lightmap file");
return false;
}
AutoFileCloser _AutoClose (hFile);
// Read header
iNumItemsRead = GetPak()->FRead(&sHeader, sizeof(FileHeader), 1, hFile);
// Read LM texture data
for (UINT iCurLMTexData = 0; iCurLMTexData < sHeader.iNumLM_Pairs; ++iCurLMTexData)
{
LMHeader LM;
// width, height and the number of UVs
if (1 != GetPak()->FRead(&LM, sizeof(LM), 1, hFile))
{
Warning (0, pszFileName, "Cannot read LM data header #%d", iCurLMTexData);
GetSystem()->GetILog()->Log("Cannot read Lightmap data header ");
return false;
}
std::vector<int> vGLM_IDs_UsingPatch; // objects that use this lightmap texture
vGLM_IDs_UsingPatch.resize (LM.numGLMs);
// Read IDs of GLMs which use this texture pair
if (1 != GetPak()->FRead(&vGLM_IDs_UsingPatch[0], sizeof(int)*LM.numGLMs, 1, hFile))
{
Warning (0, pszFileName, "Cannot read LM data #%d", iCurLMTexData);
GetSystem()->GetILog()->Log("Cannot read Lightmap data");
return false;
}
std::vector<BYTE>vDomLightDir, vColorMap;
if(inpIGLMs)
{
// Create lightmap
RenderLMData_AutoPtr pNewLM =
sHeader.iVersion == 2?
CreateLightmap(strDirName, iCurLMTexData,LM.iWidth, LM.iHeight, false/*don't load occl maps*/) :
CreateLightmap(strDirName, iCurLMTexData,LM.iWidth, LM.iHeight, true/*load occl maps*/);
if (!pNewLM)
{
GetSystem()->GetILog()->Log("CreateLightmap has failed");
return false;
}
// Instance is assigned later when we get the texture coordinates. Store a
// reference so we can later safely release each element
for (std::vector<int>::iterator itID=vGLM_IDs_UsingPatch.begin(); itID!=vGLM_IDs_UsingPatch.end(); itID++)
{
// Shouldn't happen, probably need to fix something if. Might be wrong LM data, just
// delete the file or ignore the assert
assert (mapLMData.find(*itID) == mapLMData.end());
mapLMData[*itID] = pNewLM;
}
}
else
{
RawLMData* pRawLM = new RawLMData(LM.iWidth,LM.iHeight,vGLM_IDs_UsingPatch);
char szPostfix[8];
if(cbLoadTextures)
{
sprintf(szPostfix, "%d.dds", iCurLMTexData);
pRawLM->initFromDDS(RawLMData::TEX_COLOR, GetPak(), strDirName + "\\c" + szPostfix);
pRawLM->initFromDDS(RawLMData::TEX_DOMDIR, GetPak(), strDirName + "\\d" + szPostfix);
if(sHeader.iVersion > 2)//load occlusion maps too
{
pRawLM->initFromDDS(RawLMData::TEX_OCCL, GetPak(), strDirName + "\\o" + szPostfix);
pRawLM->initFromDDS(RawLMData::TEX_HDR, GetPak(), strDirName + "\\r" + szPostfix);
}
}
m_vLightPatches.push_back(pRawLM);
}
}
// Read texture coordinate data
for (UINT iNumTexCoordSets=0; iNumTexCoordSets<sHeader.iNumTexCoordSets; iNumTexCoordSets++)
{
UVSetHeader *pUVh(NULL);
if(sHeader.iVersion >= 3)
pUVh = new UVSetHeader3();
else
pUVh = new UVSetHeader();//old format
assert(pUVh);
std::auto_ptr<UVSetHeader> uvh(pUVh);
// Read position of GLM which uses this texture coordinate set
if (1 != GetPak()->FRead(pUVh, (sHeader.iVersion>=3)?sizeof(UVSetHeader3):sizeof(UVSetHeader), 1, hFile))
{
GetSystem()->GetILog()->Log("Could not read texture coordinates for lightmaps");
return false;
}
std::vector<TexCoord2Comp> vTexCoords;
vTexCoords.resize(pUVh->numUVs);
if (1 != GetPak()->FRead(&vTexCoords[0], sizeof(TexCoord2Comp)*pUVh->numUVs, 1, hFile))
{
GetSystem()->GetILog()->Log("Could not read texture coordinates for lightmaps");
return false;
}
#ifdef _DEBUG
for (UINT iCurTexCrd=0; iCurTexCrd<vTexCoords.size(); iCurTexCrd++)
{
if( vTexCoords[iCurTexCrd].s >= 0.0f && vTexCoords[iCurTexCrd].s <= 1.0f &&
vTexCoords[iCurTexCrd].t >= 0.0f && vTexCoords[iCurTexCrd].t <= 1.0f )
continue;
Warning(0, pszFileName, "CLMSerializationManager2::_Load: Lightmap texture coordinates out of range");
break;
}
#endif
// Hand out data/references to the GLMs
if(inpIGLMs)
{
std::vector<IEntityRender *>::iterator itGLM;
for (itGLM=inpIGLMs->begin(); itGLM!=inpIGLMs->end(); ++itGLM)
{
IEntityRender *pICurGLM = (* itGLM);
// Correct GLM for this texture coordinate set ?
if ( pICurGLM->GetEditorObjectId() == pUVh->nIdGLM && pICurGLM->GetEntityRS() )
{
std::map<int, RenderLMData_AutoPtr>::iterator itRenderLMData = mapLMData.find(pUVh->nIdGLM);
if (itRenderLMData == mapLMData.end())
{
// We shouldn't have a texture coordinate set for a GLM that has no matching LM object
assert(itRenderLMData != mapLMData.end());
break;
}
// Copy texture coordinates and hand out a reference to the lightmap object
if(sHeader.iVersion >= 3 && (strcmp(pICurGLM->GetEntityClassName(), "Brush") == 0))
{
const UVSetHeader3 *puvh = static_cast<const UVSetHeader3*>(pUVh);
//create vector with light ids
std::vector<std::pair<EntityId,EntityId> > vIDs; vIDs.resize(puvh->ucOcclCount);
for(int i=0; i<puvh->ucOcclCount; ++i)
{
vIDs[i].first = puvh->OcclIds[2*i];
vIDs[i].second = puvh->OcclIds[2*i+1];
}
CBrush *pBrush = reinterpret_cast<CBrush*>(pICurGLM);//safe due to GetEntityClassName
pBrush->SetLightmap (itRenderLMData->second, (float *) &vTexCoords[0], vTexCoords.size(), puvh->ucOcclCount, vIDs);
}
else
pICurGLM->SetLightmap (itRenderLMData->second, (float *) &vTexCoords[0], vTexCoords.size());
// Texture coordinates are per-instance
break;
}
}
}
else // !inpIGLMs
{
m_vTexCoords[pUVh->nIdGLM] = RawTexCoordData(vTexCoords, pUVh->nHashGLM);
}
}
GetSystem()->GetILog()->UpdateLoadingScreenPlus(" %d elements loaded", mapLMData.size());
GetSystem()->GetILog()->Log("Finished loading lightmaps ...");
return true;
}
bool CLMSerializationManager2::Load(const char *pszFileName, const bool cbLoadTextures)
{
return(_Load(pszFileName, 0, cbLoadTextures));
}
bool CLMSerializationManager2::ApplyLightmapfile(const char *pszFileName, std::vector<IEntityRender *>& vIGLMs )
{
return(_Load(pszFileName,&vIGLMs));
}
//////////////////////////////////////////////////////////////////////////
uint8* MemBufferCounter=0;
int m_numMips=0;
HRESULT SaveCompessedMipmapLevel( void * data, int miplevel, DWORD size, int width, int height, void * user_data )
{
assert( MemBufferCounter );
uint8* src=(uint8*)data;
for (uint32 i=0; i<size; i++)
{
*MemBufferCounter=src[i];
MemBufferCounter++;
}
m_numMips++;
return 0;
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------------------------------------------------------
unsigned int CLMSerializationManager2::Save(const char *pszFilePath, LMGenParam rParam, const bool cbAppend )
{
// ---------------------------------------------------------------------------------------------
// Store the lightmap data added in pszFileName
// ---------------------------------------------------------------------------------------------
string strDirName = CryStringUtils::GetParentDirectory<string>(pszFilePath);
const char* pFileName = pszFilePath + (strDirName.empty()?0:strDirName.length()+1);
string strPakName = strDirName + "\\" LEVELLM_PAK_NAME;
GetPak()->ClosePack(strPakName.c_str());
// make sure the pak file in which this LM data resides is opened
SetFileAttributes(strPakName.c_str(), FILE_ATTRIBUTE_NORMAL);
ICryArchive_AutoPtr pPak = GetPak()->OpenArchive (strPakName.c_str(), ICryArchive::FLAGS_RELATIVE_PATHS_ONLY);
if (!pPak)
return NSAVE_RESULT::EPAK_FILE_OPEN_FAIL;
unsigned int uiStartIndex = 0;
if(cbAppend)
{
//seek to the right file
for(;;)
{
char fileName[10];
//create filename
sprintf(fileName, "x%d.dds", uiStartIndex);
if(pPak->FindFile(fileName) == NULL)
break;
uiStartIndex++;
}
}
FileHeader sHeader;
std::map<int,RawTexCoordData>::iterator itTexCrdData;
RawLMData *pCurRawLMData = NULL;
RawTexCoordData *pCurRawTexCrdData = NULL;
CTempFile fMem;
// Write header
sHeader.iNumLM_Pairs = m_vLightPatches.size();
sHeader.iNumTexCoordSets = m_vTexCoords.size();
fMem.Write(sHeader);
// Write LM texture data
for (UINT iCurLMTexData = 0; iCurLMTexData < m_vLightPatches.size(); ++iCurLMTexData)
{
pCurRawLMData = m_vLightPatches[iCurLMTexData];
LMHeader LM;
LM.iHeight = pCurRawLMData->m_dwHeight;
LM.iWidth = pCurRawLMData->m_dwWidth;
LM.numGLMs = pCurRawLMData->vGLM_IDs_UsingPatch.size();
fMem.Write(LM);
fMem.Write(&pCurRawLMData->vGLM_IDs_UsingPatch[0], LM.numGLMs);
if(iCurLMTexData >= uiStartIndex)
{
uint32 size = pCurRawLMData->m_ColorLerp4.GetSize();
uint8* pSr0 = (uint8*)pCurRawLMData->m_ColorLerp4.GetData();
uint8* pSr1 = (uint8*)pCurRawLMData->m_DomDirection3.GetData();
DDS_HEADER* pDDS=(DDS_HEADER*)(pSr0+4);
uint32 width = pDDS->dwWidth;
uint32 height = pDDS->dwHeight;
char szName[8];
sprintf(szName, "x%d.dds", iCurLMTexData/* + uiStartIndex*/);
DDS_HEADER ddsh;
if (0)
{//save uncompressed version
szName[0] = 'c';
pPak->UpdateFile (szName, pCurRawLMData->m_ColorLerp4.GetData(), pCurRawLMData->m_ColorLerp4.GetSize(), ICryArchive::METHOD_COMPRESS, ICryArchive::LEVEL_BEST);
} else
{
//-------------------------------------------------------------------------------
//---- create DXT3-image for color-map ------------------------------------------
//-------------------------------------------------------------------------------
uint8* pColorMaps32 = (uint8*)pCurRawLMData->m_ColorLerp4.GetData();;
uint8* pColorDXT3=(uint8*)malloc(size);
MemBufferCounter = pColorDXT3;
m_numMips=0;
memset( (void*)(&ddsh), 0, sizeof(ddsh) );
*MemBufferCounter='D'; MemBufferCounter++;
*MemBufferCounter='D'; MemBufferCounter++;
*MemBufferCounter='S'; MemBufferCounter++;
*MemBufferCounter=' '; MemBufferCounter++;
ddsh.dwSize = sizeof(DDS_HEADER);
ddsh.dwWidth = width;
ddsh.dwHeight = height;
ddsh.dwMipMapCount = 0;
ddsh.ddspf = DDSPF_DXT3;
ddsh.dwHeaderFlags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_MIPMAP;
ddsh.dwSurfaceFlags = DDS_SURFACE_FLAGS_TEXTURE | DDS_SURFACE_FLAGS_MIPMAP;
uint8* hsrcDXT3=(uint8*)(&ddsh);
for (uint32 i=0; i<sizeof(ddsh); i++) {
*MemBufferCounter=hsrcDXT3[i]; MemBufferCounter++;
}
if(!GetSystem()->GetIRenderer()->DXTCompress(
&pColorMaps32[0x80],
width,
height,
eTF_DXT3, //DXT-format
false, //use hardware
0, //mipmaps on/off
4, //bytes per pixel
SaveCompessedMipmapLevel //callback
)) return NSAVE_RESULT::EDXT_COMPRESS_FAIL;
DDS_HEADER* pDXT3=(DDS_HEADER*)(pColorDXT3+4);
pDXT3->dwMipMapCount = m_numMips;
if (m_numMips==1) pDXT3->dwMipMapCount = 0;
szName[0] = 'c';
uint32 dxt3size=MemBufferCounter-pColorDXT3;
pPak->UpdateFile (szName, pColorDXT3, dxt3size, ICryArchive::METHOD_COMPRESS, ICryArchive::LEVEL_BEST);
szName[0] = 'h';
pPak->UpdateFile (szName, pCurRawLMData->m_ColorLerp4.GetData(), pCurRawLMData->m_ColorLerp4.GetSize(), ICryArchive::METHOD_COMPRESS, ICryArchive::LEVEL_BEST);
free(pColorDXT3);
}
//-------------------------------------------------------------------------------------------
szName[0] = 'd';
pPak->UpdateFile (szName, pCurRawLMData->m_DomDirection3.GetData(), pCurRawLMData->m_DomDirection3.GetSize(), ICryArchive::METHOD_COMPRESS, ICryArchive::LEVEL_BEST);
if(pCurRawLMData->m_bUseOcclMaps)
{
szName[0] = 'o';
pPak->UpdateFile (szName, pCurRawLMData->m_Occl2.GetData(), pCurRawLMData->m_Occl2.GetSize(), ICryArchive::METHOD_COMPRESS, ICryArchive::LEVEL_BEST);
}
if(pCurRawLMData->m_bUseHDRMaps)
{
szName[0] = 'r';
pPak->UpdateFile (szName, pCurRawLMData->m_HDRColorLerp4.GetData(), pCurRawLMData->m_HDRColorLerp4.GetSize(), ICryArchive::METHOD_COMPRESS, ICryArchive::LEVEL_BEST);
}
uint8* pSimpleLightmaps32 = (uint8*)malloc(size);
//copy headder
for (uint32 i=0; i<0x80; i++) {
pSimpleLightmaps32[i] = pSr0[i];
}
//create simple lightmap (RGBA)
for (uint32 i=0x80; i<size; i=i+4)
{
// compute lambert term with the surface normal and the averager light direction
float NdotL = ((float)pSr1[i] - 127.5f) / 127.5f;
// light behind the surface is 0
if (NdotL < 0) NdotL = 0;
// convert RGBA 0..255 color to float 0..1
float lmColor[4];
#ifdef APPLY_COLOUR_FIX
#ifdef USE_ALPHA_FOR_LOWSPEC
lmColor[0] = (float)pSr0[i+0] / 255.0f;
lmColor[1] = (float)pSr0[i+1] / 255.0f;
lmColor[2] = (float)pSr0[i+2] / 255.0f;
#else
lmColor[0] = (float)pSr0[i+0] * (float)pSr1[i+3] / 255.0f / 255.0f;
lmColor[1] = (float)pSr0[i+1] * (float)pSr1[i+3] / 255.0f / 255.0f;
lmColor[2] = (float)pSr0[i+2] * (float)pSr1[i+3] / 255.0f / 255.0f;
#endif
#else
lmColor[0] = (float)pSr0[i+0] / 255.0f;
lmColor[1] = (float)pSr0[i+1] / 255.0f;
lmColor[2] = (float)pSr0[i+2] / 255.0f;
#endif
lmColor[3] = (float)pSr0[i+3] / 255.0f;
// calculate the sum of the directional term (NdotL * lmColor[3])
// and the ambient term (1.0f-lmColor[3])
float lmIntens = NdotL * lmColor[3] + (1.0f-lmColor[3]);
// weight the colour with the calculated sum
#ifdef USE_ALPHA_FOR_LOWSPEC
pSimpleLightmaps32[i+0] = (byte)(lmColor[0] * 255.0f);
pSimpleLightmaps32[i+1] = (byte)(lmColor[1] * 255.0f);
pSimpleLightmaps32[i+2] = (byte)(lmColor[2] * 255.0f);
// alpha is used
pSimpleLightmaps32[i+3] = (byte)(lmIntens * (float)(pSr1[i+3]));
#else
pSimpleLightmaps32[i+0] = (byte)(lmColor[0] * lmIntens * 255.0f);
pSimpleLightmaps32[i+1] = (byte)(lmColor[1] * lmIntens * 255.0f);
pSimpleLightmaps32[i+2] = (byte)(lmColor[2] * lmIntens * 255.0f);
// alpha is not used
pSimpleLightmaps32[i+3] = 255;
#endif
}
//-------------------------------------------------------------------------------
//---- create DXT1-image --------------------------------------------------------
//-------------------------------------------------------------------------------
uint8* pSimpleLightmapsDXT1=(uint8*)malloc(size);
MemBufferCounter = pSimpleLightmapsDXT1;
m_numMips=0;
memset( (void*)(&ddsh), 0, sizeof(ddsh) );
*MemBufferCounter='D'; MemBufferCounter++;
*MemBufferCounter='D'; MemBufferCounter++;
*MemBufferCounter='S'; MemBufferCounter++;
*MemBufferCounter=' '; MemBufferCounter++;
ddsh.dwSize = sizeof(DDS_HEADER);
ddsh.dwWidth = width;
ddsh.dwHeight = height;
#ifdef USE_ALPHA_FOR_LOWSPEC
ddsh.ddspf = DDSPF_DXT5;
#else
ddsh.ddspf = DDSPF_DXT1;
#endif
ddsh.dwMipMapCount = 0;
ddsh.dwHeaderFlags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_MIPMAP;
ddsh.dwSurfaceFlags = DDS_SURFACE_FLAGS_TEXTURE | DDS_SURFACE_FLAGS_MIPMAP;
uint8* hsrcDXT1=(uint8*)(&ddsh);
for (uint32 i=0; i<sizeof(ddsh); i++) {
*MemBufferCounter=hsrcDXT1[i]; MemBufferCounter++;
}
#ifdef USE_ALPHA_FOR_LOWSPEC
if(!GetSystem()->GetIRenderer()->DXTCompress(
&pSimpleLightmaps32[0x80],
width,
height,
eTF_DXT5, //DXT-format
false, //use hardware
0, //mipmaps on/off
4, //bytes per pixel
SaveCompessedMipmapLevel //callback
))
return NSAVE_RESULT::EDXT_COMPRESS_FAIL;
#else
if(!GetSystem()->GetIRenderer()->DXTCompress(
&pSimpleLightmaps32[0x80],
width,
height,
eTF_DXT1, //DXT-format
false, //use hardware
0, //mipmaps on/off
4, //bytes per pixel
SaveCompessedMipmapLevel //callback
))
return NSAVE_RESULT::EDXT_COMPRESS_FAIL;
#endif
DDS_HEADER* pDXT1=(DDS_HEADER*)(pSimpleLightmapsDXT1+4);
pDXT1->dwMipMapCount = m_numMips;
if (m_numMips==1) pDXT1->dwMipMapCount = 0;
uint32 dxtsize=MemBufferCounter-pSimpleLightmapsDXT1;
szName[0] = 'x';
pPak->UpdateFile (szName, pSimpleLightmapsDXT1, dxtsize, ICryArchive::METHOD_COMPRESS, ICryArchive::LEVEL_BEST);
free(pSimpleLightmapsDXT1);
free(pSimpleLightmaps32);
}
}
// Write texture coordinate data
for (itTexCrdData=m_vTexCoords.begin(); itTexCrdData!=m_vTexCoords.end(); itTexCrdData++)
{
UVSetHeader3 uvh;
pCurRawTexCrdData = &((*itTexCrdData).second);
uvh.nIdGLM = (*itTexCrdData).first;
uvh.nHashGLM = pCurRawTexCrdData->m_dwHashValue;
uvh.numUVs = pCurRawTexCrdData->vTexCoords.size();
uvh.ucOcclCount = pCurRawTexCrdData->vOcclIDs.size();
for(int i=0; i<uvh.ucOcclCount; ++i)
{
uvh.OcclIds[2*i] = pCurRawTexCrdData->vOcclIDs[i].first;//real entity id
uvh.OcclIds[2*i+1] = pCurRawTexCrdData->vOcclIDs[i].second;//light index in statlights
}
fMem.Write (uvh);
fMem.Write(&pCurRawTexCrdData->vTexCoords[0], uvh.numUVs);
}
if(0 == pPak->UpdateFile(pFileName, fMem.GetData(), fMem.GetSize()))
return NSAVE_RESULT::ESUCCESS;
else
return NSAVE_RESULT::EPAK_FILE_UPDATE_FAIL;
}
#ifdef WIN64
#pragma warning( pop ) //AMD Port
#endif
DWORD CLMSerializationManager2::GetHashValue( const int iniGLM_ID_UsingTexCoord ) const
{
std::map<int,RawTexCoordData>::const_iterator itTexCrdData;
for (itTexCrdData=m_vTexCoords.begin(); itTexCrdData!=m_vTexCoords.end(); itTexCrdData++)
{
int iGLM_ID_UsingTexCoord=(*itTexCrdData).first;
if(iGLM_ID_UsingTexCoord==iniGLM_ID_UsingTexCoord)
{
const RawTexCoordData &rCurRawTexCrdData = (*itTexCrdData).second;
return(rCurRawTexCrdData.m_dwHashValue);
}
}
return(0x12341234); // object not found
}
RenderLMData * CLMSerializationManager2::CreateLightmap(const string& strDirPath, int nItem, UINT iWidth, UINT iHeight, const bool cbLoadHDRMaps, const bool cbLoadOcclMaps)
{
// ---------------------------------------------------------------------------------------------
// Create a DOT3 Lightmap object
// ---------------------------------------------------------------------------------------------
IRenderer *pIRenderer = GetSystem()->GetIRenderer();
int iColorLerpTex = 0, iHDRColorLerpTex = 0, iDomDirectionTex = 0, iOcclTex = 0;
int nGPU = pIRenderer->GetFeatures() & RFT_HW_MASK;
char szPostfix[8];
sprintf(szPostfix, "%d.dds", nItem);
//---------------------------------------------------------------------------------------------------
//---- load precalculated SimpleLightmaps -----------------------------------------------------
//---------------------------------------------------------------------------------------------------
if (GetCVars()->e_light_maps_quality==0 || nGPU == RFT_HW_GF2)
{
ITexPic *tp = pIRenderer->EF_LoadTexture((strDirPath + "\\x" + szPostfix).c_str(), FT_LM, FT2_NOANISO, eTT_Base);
iColorLerpTex = tp->GetTextureID();
return new RenderLMData(pIRenderer, iColorLerpTex, iHDRColorLerpTex, 0);
}
else
if (GetCVars()->e_light_maps_quality==1)
{
//load lightsmaps in DXT3-format
iColorLerpTex = pIRenderer->EF_LoadTexture((strDirPath + "\\c" + szPostfix).c_str(), FT_LM | FT_CLAMP, FT2_NOANISO, eTT_Base)->GetTextureID();
iDomDirectionTex = pIRenderer->EF_LoadTexture((strDirPath + "\\d" + szPostfix).c_str(), FT_LM | FT_CLAMP, FT2_NOANISO, eTT_Base)->GetTextureID();
}
else
if (GetCVars()->e_light_maps_quality==2)
{
//load lightmaps with high quality
ITexPic *tp = pIRenderer->EF_LoadTexture((strDirPath + "\\h" + szPostfix).c_str(), FT_LM | FT_CLAMP, FT2_NOANISO, eTT_Base);
if (tp && tp->IsTextureLoaded())
iColorLerpTex = tp->GetTextureID();
else
{
SAFE_RELEASE(tp);
iColorLerpTex = pIRenderer->EF_LoadTexture((strDirPath + "\\c" + szPostfix).c_str(), FT_LM | FT_CLAMP, FT2_NOANISO, eTT_Base)->GetTextureID();
}
iDomDirectionTex = pIRenderer->EF_LoadTexture((strDirPath + "\\d" + szPostfix).c_str(), FT_LM | FT_CLAMP, FT2_NOANISO, eTT_Base)->GetTextureID();
if(cbLoadOcclMaps)
{
iOcclTex = pIRenderer->EF_LoadTexture((strDirPath + "\\o" + szPostfix).c_str(), FT_LM | FT_CLAMP, FT2_NOANISO, eTT_Base)->GetTextureID();
}
if ((pIRenderer->GetFeatures() & RFT_HW_HDR) && cbLoadHDRMaps)
{
ITexPic *tp = pIRenderer->EF_LoadTexture((strDirPath + "\\r" + szPostfix).c_str(), FT_LM | FT_CLAMP, FT2_NOANISO, eTT_Base);
if (tp && tp->IsTextureLoaded())
iHDRColorLerpTex = tp->GetTextureID();
else
SAFE_RELEASE(tp);
}
}
return new RenderLMData(pIRenderer, iColorLerpTex, iHDRColorLerpTex, iDomDirectionTex, iOcclTex);
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------
RenderLMData * CLMSerializationManager2::CreateLightmap(const char *pszFileName, int nItem, UINT iWidth, UINT iHeight, BYTE *pColorLerp4, BYTE *pHDRColorLerp, BYTE *pDomDirection3, BYTE *pOccl2)
{
// Create a DOT3 Lightmap object
IRenderer *pIRenderer = GetSystem()->GetIRenderer();
int iColorLerpTex = 0, iHDRColorLerpTex = 0, iDomDirectionTex = 0, iOcclTex = 0;
assert(!IsBadReadPtr(pColorLerp4, sizeof(BYTE) * 4 * iWidth * iHeight));
#ifdef USE_DOT3_ALPHA
assert(!IsBadReadPtr(pDomDirection3, sizeof(BYTE) * 4 * iWidth * iHeight));
#else
assert(!IsBadReadPtr(pDomDirection3, sizeof(BYTE) * 3 * iWidth * iHeight));
#endif
if(pOccl2)
assert(!IsBadReadPtr(pOccl2, sizeof(BYTE) * 2 * iWidth * iHeight));
if(pHDRColorLerp)
assert(!IsBadReadPtr(pHDRColorLerp, sizeof(BYTE) * 4 * iWidth * iHeight));
char szName[128];
if (pszFileName)
{
sprintf(szName, "$DOT3LM%d$%s", nItem, pszFileName);
iColorLerpTex = pIRenderer->DownLoadToVideoMemory(pColorLerp4, iWidth, iHeight, eTF_RGBA, eTF_RGBA, 0, false, FILTER_BILINEAR, 0, szName);
}
else
iColorLerpTex = pIRenderer->DownLoadToVideoMemory(pColorLerp4, iWidth, iHeight, eTF_RGBA, eTF_RGBA, 0, false, FILTER_BILINEAR, 0, NULL);
assert(iColorLerpTex != 0);
#ifndef USE_DOT3_ALPHA
std::vector<BYTE> vRGBAData;
vRGBAData.resize(iWidth * iHeight * 4);
for (UINT i=0; i<iWidth * iHeight; i++)
{
memcpy(&vRGBAData[i * 4], &pDomDirection3[i * 3], 3);
vRGBAData[i * 4 + 3] = 0;
}
if (pszFileName)
{
sprintf(szName, "$DOT3LMDir%d$%s", nItem, pszFileName);
iDomDirectionTex = pIRenderer->DownLoadToVideoMemory(&vRGBAData[0], iWidth, iHeight, eTF_RGBA, eTF_RGBA, 0, false, FILTER_BILINEAR, 0, szName);
}
else
iDomDirectionTex = pIRenderer->DownLoadToVideoMemory(&vRGBAData[0], iWidth, iHeight, eTF_RGBA, eTF_RGBA, 0, false, FILTER_BILINEAR, 0, NULL);
#else
if (pszFileName)
{
sprintf(szName, "$DOT3LMDir%d$%s", nItem, pszFileName);
iDomDirectionTex = pIRenderer->DownLoadToVideoMemory(pDomDirection3, iWidth, iHeight, eTF_RGBA, eTF_RGBA, 0, false, FILTER_BILINEAR, 0, szName);
}
else
iDomDirectionTex = pIRenderer->DownLoadToVideoMemory(pDomDirection3, iWidth, iHeight, eTF_RGBA, eTF_RGBA, 0, false, FILTER_BILINEAR, 0, NULL);
#endif
assert(iDomDirectionTex != 0);
int nGPU = pIRenderer->GetFeatures() & RFT_HW_MASK;
bool bLow = (nGPU == RFT_HW_GF2);
if(!bLow && pOccl2 != 0 && (GetCVars()->e_light_maps_quality==2))
{
if (pszFileName)
{
sprintf(szName, "$DOT3LMOccl%d$%s", nItem, pszFileName);
iOcclTex = pIRenderer->DownLoadToVideoMemory(pOccl2, iWidth, iHeight, eTF_4444, eTF_4444, 0, false, FILTER_BILINEAR, 0, szName);
}
else
iOcclTex = pIRenderer->DownLoadToVideoMemory(pOccl2, iWidth, iHeight, eTF_4444, eTF_4444, 0, false, FILTER_BILINEAR, 0, NULL);
}
if(!bLow && pHDRColorLerp != 0 && (GetCVars()->e_light_maps_quality==2) && (pIRenderer->GetFeatures() & RFT_HW_HDR))
{
if (pszFileName)
{
sprintf(szName, "$DOT3LMHDR%d$%s", nItem, pszFileName);
iHDRColorLerpTex = pIRenderer->DownLoadToVideoMemory(pHDRColorLerp, iWidth, iHeight, eTF_RGBA, eTF_RGBA, 0, false, FILTER_BILINEAR, 0, szName);
}
else
iHDRColorLerpTex = pIRenderer->DownLoadToVideoMemory(pHDRColorLerp, iWidth, iHeight, eTF_RGBA, eTF_RGBA, 0, false, FILTER_BILINEAR, 0, NULL);
}
if (GetCVars()->e_light_maps_quality==0 || bLow)
{
ITexPic *pColorLerpTex = pIRenderer->EF_GetTextureByID(iColorLerpTex);
byte *pDataLerpTex = pColorLerpTex->GetData32();
ITexPic *pDomDirectionTex = pIRenderer->EF_GetTextureByID(iDomDirectionTex);
byte *pDataDirectionTex = pDomDirectionTex->GetData32();
int Width = pColorLerpTex->GetWidth();
int Height = pColorLerpTex->GetHeight();
assert(Width == pDomDirectionTex->GetWidth() && Height == pDomDirectionTex->GetHeight());
byte *pDst = new byte[Width*Height*4];
for (int i=0; i<Height; i++)
{
byte *pDs = &pDst[i*Width*4];
byte *pSr0 = &pDataLerpTex[i*Width*4];
byte *pSr1 = &pDataDirectionTex[i*Width*4];
for (int j=0; j<Width; j++)
{
Vec3d v;
float NdotL = ((float)pSr1[0] - 127.5f) / 127.5f;
if (NdotL < 0)
NdotL = 0;
float lmColor[4];
#ifdef APPLY_COLOUR_FIX
lmColor[0] = (float)pSr0[0] * (float)pSr1[3] / 255.0f / 255.0f;
lmColor[1] = (float)pSr0[1] * (float)pSr1[3] / 255.0f / 255.0f;
lmColor[2] = (float)pSr0[2] * (float)pSr1[3] / 255.0f / 255.0f;
#else
lmColor[0] = (float)pSr0[0] / 255.0f;
lmColor[1] = (float)pSr0[1] / 255.0f;
lmColor[2] = (float)pSr0[2] / 255.0f;
#endif
lmColor[3] = pSr0[3] / 255.0f;
float lmIntens = NdotL * lmColor[3] + (1.0f-lmColor[3]);
pDs[0] = (byte)(lmColor[0] * lmIntens * 255.0f);
pDs[1] = (byte)(lmColor[1] * lmIntens * 255.0f);
pDs[2] = (byte)(lmColor[2] * lmIntens * 255.0f);
pDs[3] = 255;
pDs += 4;
pSr0 += 4;
pSr1 += 4;
}
}
pColorLerpTex->Release();
pDomDirectionTex->Release();
if (pszFileName)
{
char szCacheName[512];
sprintf(szCacheName, "$LM%d$%s", nItem, pszFileName);
iColorLerpTex = pIRenderer->DownLoadToVideoMemory(pDst, Width, Height, eTF_8888, eTF_8888, 0, false, FILTER_BILINEAR, 0, szCacheName);
}
else
iColorLerpTex = pIRenderer->DownLoadToVideoMemory(pDst, Width, Height, eTF_8888, eTF_8888, 0, false, FILTER_BILINEAR, 0, NULL);
iDomDirectionTex = 0;
}
return new RenderLMData(pIRenderer, iColorLerpTex, iHDRColorLerpTex, iDomDirectionTex, iOcclTex);
}
typedef LMStatLightFileHeader LightFileHeader;
bool CLMSerializationManager2::ExportDLights(const char *pszFilePath, const CDLight **ppLights, UINT iNumLights, bool bNewZip) const
{
// ---------------------------------------------------------------------------------------------
// Serialize dynamic lights into a file
// ---------------------------------------------------------------------------------------------
string strDirName = CryStringUtils::GetParentDirectory<string>(pszFilePath);
const char* pFileName = pszFilePath + (strDirName.empty()?0:strDirName.length()+1);
string strPakName = strDirName + "\\" LEVELLM_PAK_NAME;
GetPak()->ClosePack(strPakName.c_str());
// make sure the pak file in which this LM data resides is opened
SetFileAttributes(strPakName.c_str(), FILE_ATTRIBUTE_NORMAL);
if (!bNewZip)
GetPak()->ClosePack( strPakName.c_str() );
ICryArchive_AutoPtr pPak = GetPak()->OpenArchive (strPakName.c_str(), ICryArchive::FLAGS_RELATIVE_PATHS_ONLY|(bNewZip?ICryArchive::FLAGS_CREATE_NEW:0));
if (!pPak)
return false;
LightFileHeader sHeader;
UINT iCurLight;
CTempFile fMem;
if (iNumLights == 0)
{
pPak->RemoveFile (pFileName);
return true;
}
assert(!IsBadReadPtr(ppLights, sizeof(CDLight *) * iNumLights));
sHeader.iNumDLights = iNumLights;
fMem.Write (sHeader);
for (iCurLight=0; iCurLight<iNumLights; iCurLight++)
{
fMem.Write(*(ppLights[iCurLight]));
int nFlags2 = ppLights[iCurLight]->m_pLightImage ? ppLights[iCurLight]->m_pLightImage->GetFlags2() : 0;
fMem.Write (nFlags2);
ITexPic* pLightImg = ppLights[iCurLight]->m_pLightImage;
WriteString(pLightImg? pLightImg->GetName() : "" , fMem);
IShader* pShader = ppLights[iCurLight]->m_pShader;
WriteString(pShader ? pShader->GetName() : "", fMem);
}
return 0 == pPak->UpdateFile (pFileName, fMem.GetData(), fMem.GetSize());
}
bool CLMSerializationManager2::LoadDLights(const char *pszFileName, CDLight **&ppLightsOut, UINT &iNumLightsOut) const
{
return true;
}
// writes the mips to the given DDS
// gets the highest level MIP from the dds itself (to the moment there must be the
// MIP written to the end of dds file). Returns the number of mips generated
// (including already given highest-level mip)
unsigned GenerateDDSMips( CTempFile& dds, int wdt, int hgt)
{
int wd;
int i, j;
int num;
// the size of all MIPs including the highest-level (given) one
unsigned numBytes = 0;
int w = wdt;
int h = hgt;
while (w || h)
{
if (w == 0) w = 1;
if (h == 0) h = 1;
numBytes += w * h * 4;
w >>= 1;
h >>= 1;
}
// the source mip offset: will be changed as the mips are generated sequentially
int nOffsetSrcMip = dds.GetSize() - wdt*hgt*4;
if (nOffsetSrcMip < 0)
return 0;
dds.SetSize(nOffsetSrcMip + numBytes);
num = 1; // number of mips
byte* src = (byte*)dds.GetData() + nOffsetSrcMip;
byte* dst = src + wdt*hgt*4; // pointer to next mip
wd = wdt<<2; // width of one row of the source mip
wdt >>= 1; // next mip dimension
hgt >>= 1;
while (wdt || hgt)
{
if (wdt < 1)
wdt = 1;
if (hgt < 1)
hgt = 1;
byte* src1 = src;
byte* dst1 = dst;
for (i=0; i<hgt; i++) // for all rows in the NEW mip
{
byte *src2 = src1; // running pointer to the previous mip's 2x2 block
for (j=0; j<wdt; j++)
{
assert (dst1 < (byte*)dds.GetData() + dds.GetSize());
dst1[0] = (src2[0]+src2[4]+src2[wd]+src2[wd+4])>>2;
dst1[1] = (src2[1]+src2[5]+src2[wd+1]+src2[wd+5])>>2;
dst1[2] = (src2[2]+src2[6]+src2[wd+2]+src2[wd+6])>>2;
dst1[3] = (src2[3]+src2[7]+src2[wd+3]+src2[wd+7])>>2;
dst1 += 4; // run the target pointer to the next pixel
src2 += 8; // run the source pointer to the next 2x2 block
}
src1 += wd<<1;
}
src = dst;
dst = dst1;
num++;
wd = wdt<<2; // width of one row of the source mip
wdt >>= 1; // next mip dimension
hgt >>= 1;
}
assert (dst == (byte*)dds.GetData() + dds.GetSize());
return num;
}
static CTempFile* g_pDDSTarget;
static unsigned int g_numMips;
static bool DDSCompressCallback(void * data, int miplevel, DWORD size)
{
g_pDDSTarget->WriteData(data, size);
return false;
}
// initializes from raw bitmaps
void CLMSerializationManager2::RawLMData::initFromBMP (BitmapEnum t, const void* pSource)
{
CTempFile* pBMP;
switch (t)
{
case TEX_COLOR: pBMP = &m_ColorLerp4; break;
case TEX_DOMDIR: pBMP = &m_DomDirection3; break;
case TEX_OCCL: pBMP = &m_Occl2; break;
case TEX_HDR: pBMP = &m_HDRColorLerp4; break;
default: return;
}
int nBytesPerPixel = 4;
int nBytesReservedPerPixel = 4;
switch(t)
{
case TEX_COLOR: nBytesPerPixel = 4; nBytesReservedPerPixel = 4; break;
#ifdef USE_DOT3_ALPHA
case TEX_DOMDIR: nBytesPerPixel = 4; nBytesReservedPerPixel = 4; break;
#else
case TEX_DOMDIR: nBytesPerPixel = 3; nBytesReservedPerPixel = 4; break;
#endif
case TEX_OCCL: nBytesPerPixel = 2; nBytesReservedPerPixel = 2; break;
case TEX_HDR: nBytesPerPixel = 4; nBytesReservedPerPixel = 4; break;
}
pBMP->Clear();
pBMP->Reserve (sizeof(DWORD) + sizeof(DDS_HEADER) + m_dwWidth*m_dwHeight*nBytesReservedPerPixel);
DWORD dwMagic = MAKEFOURCC('D','D','S',' ');
pBMP->Write( dwMagic);
DDS_HEADER ddsh;
ZeroStruct(ddsh);
ddsh.dwSize = sizeof(DDS_HEADER);
ddsh.dwWidth = m_dwWidth;
ddsh.dwHeight = m_dwHeight;
if(t == TEX_DOMDIR || t == TEX_COLOR || t == TEX_HDR)
{
ddsh.dwHeaderFlags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_MIPMAP;
ddsh.dwSurfaceFlags = DDS_SURFACE_FLAGS_TEXTURE | DDS_SURFACE_FLAGS_MIPMAP;
ddsh.dwMipMapCount = 1;
}
else
{
ddsh.dwHeaderFlags = DDS_HEADER_FLAGS_TEXTURE;
ddsh.dwSurfaceFlags = DDS_SURFACE_FLAGS_TEXTURE;
ddsh.dwMipMapCount = 0;
}
unsigned nOffsetDDSH = pBMP->GetSize();
if(t == TEX_DOMDIR || t == TEX_COLOR || t == TEX_HDR)
ddsh.ddspf = DDSPF_A8R8G8B8;
else
ddsh.ddspf = DDSPF_A4R4G4B4;
pBMP->Write (ddsh);
if(t == TEX_DOMDIR || t == TEX_COLOR || t == TEX_HDR)
{
for (unsigned i = 0; i < m_dwWidth*m_dwHeight; ++i)
{
const char* pSrc = ((const char*)pSource)+ i * nBytesPerPixel;
pBMP->Write<char>(pSrc[2]);
pBMP->Write<char>(pSrc[1]);
pBMP->Write<char>(pSrc[0]);
pBMP->Write<char>((nBytesPerPixel == 4) ? pSrc[3] : (char)0xFF);
}
unsigned numMips = GenerateDDSMips(*pBMP, m_dwWidth, m_dwHeight);
((DDS_HEADER*)((byte*)pBMP->GetData() + nOffsetDDSH))->dwMipMapCount = numMips;
}
else
{
for (unsigned i = 0; i < m_dwWidth*m_dwHeight; ++i)
{
const char* pSrc = ((const char*)pSource)+ i * nBytesPerPixel;//data already preswizzled into BGRA each 4 bit
pBMP->Write<char>(pSrc[0]);
pBMP->Write<char>(pSrc[1]);
}
}
}
// initializes from files
bool CLMSerializationManager2::RawLMData::initFromDDS (BitmapEnum t, ICryPak* pPak, const string& szFileName)
{
FILE* f = pPak->FOpen (szFileName.c_str(), "rb");
if (!f)
return false;
AutoFileCloser _AC(f);
if (pPak->FSeek(f, 0, SEEK_END))
return false;
long nLength = pPak->FTell(f);
if (nLength <= 0)
return false;
if (pPak->FSeek(f, 0, SEEK_SET))
return false;
CTempFile* pBMP;
switch (t)
{
case TEX_COLOR: pBMP = &m_ColorLerp4; break;
case TEX_DOMDIR: pBMP = &m_DomDirection3; break;
case TEX_OCCL: pBMP = &m_Occl2; break;
case TEX_HDR: pBMP = &m_HDRColorLerp4; break;
default: return false;
}
pBMP->Init(nLength);
if (pPak->FRead(pBMP->GetData(), nLength, 1, f) != 1)
{
pBMP->Init(0);
return false;
}
return true;
}