#ifdef USE_D3D9
UVAtlas::UVAtlas()
{
_GutterHelper = NULL;
}
UVAtlas::~UVAtlas()
{
FreeMemory();
}
void UVAtlas::FreeMemory()
{
_VertexRemapArray.FreeMemory();
_Cells.FreeMemory();
if(_GutterHelper)
{
_GutterHelper->Release();
_GutterHelper = NULL;
}
}
void UVAtlas::MakeDescriptiveBitmap(Bitmap &Bmp)
{
Bmp.Allocate(_Cells.Cols(), _Cells.Rows());
for(UINT y = 0; y < Bmp.Height(); y++)
{
for(UINT x = 0; x < Bmp.Width(); x++)
{
const UVAtlasCell &curCell = _Cells(y, x);
RGBColor &C = Bmp[y][x];
switch(curCell.TextelClass)
{
case 0:
C = RGBColor::Black;
break;
case 1:
C = RGBColor(Utility::Hash32(curCell.FaceIndex) % 256,
Utility::Hash32(curCell.FaceIndex * 765 + 424) % 256,
Utility::Hash32(curCell.FaceIndex * 431 + 861) % 256);
break;
case 2:
case 4:
C = RGBColor::Magenta;
break;
}
}
}
}
void UVAtlas::ApplyToTexture(LPDIRECT3DTEXTURE9 pTexture)
{
Assert(_GutterHelper != NULL, "Gutter helper not allocated");
_GutterHelper->ApplyGuttersTex(pTexture);
}
struct UVAtlasCallbackContext
{
UINT LastValue;
};
HRESULT __stdcall UVAtlasCallback(FLOAT fPercentDone, LPVOID lpUserContext)
{
UVAtlasCallbackContext *Context = (UVAtlasCallbackContext *)lpUserContext;
UINT CurValue = UINT(fPercentDone * 100.0f);
if(CurValue > Context->LastValue)
{
if(Context->LastValue == 0)
{
Console::WriteLine(String("Percent done: ") + String(fPercentDone * 100.0f) + String("%"));
}
else
{
Console::OverwriteLine(String("Percent done: ") + String(fPercentDone * 100.0f) + String("%"));
}
Context->LastValue = CurValue;
}
return S_OK;
}
void UVAtlas::Create(const BaseMesh &MeshIn, BaseMesh &MeshOut, UINT TextureWidth, UINT TextureHeight, bool UseProvidedTexCoords, const String &FastLoadDirectory)
{
Console::WriteLine(String("Generating atlas for ") + FastLoadDirectory + String(", ") + String(MeshIn.VertexCount()) + String(" vertices"));
Assert(MeshIn.VertexCount() > 0 && MeshIn.IndexCount() > 0, "UVAtlas called on empty mesh");
FreeMemory();
const UINT MaxCharts = 0;
const float AllowedStretch = 0.25f;
const float GutterSize = 3.0f;
const float Tolerance = 0.0f;
float MaxStretch;
UINT NumCharts;
D3D9Mesh MeshInCopy(MeshIn);
LPD3DXMESH MeshOutCopy = NULL;
bool FreeMeshOutCopy = false;
D3D9Mesh PartitionedMesh(MeshIn.GetGD());
if(UseProvidedTexCoords)
{
MeshOutCopy = MeshInCopy.GetMesh();
MeshOut = MeshInCopy;
}
else
{
DWORD Hash = Utility::Hash32((BYTE *)MeshInCopy.Indices(), sizeof(DWORD) * MeshInCopy.IndexCount()) +
Utility::Hash32((BYTE *)MeshInCopy.Vertices(), sizeof(MeshVertex) * MeshInCopy.VertexCount()) +
Utility::Hash32(TextureWidth) + Utility::Hash32(TextureHeight);
String DataFilename = FastLoadDirectory + String(Hash) + String(".dat");
String MeshFilename = FastLoadDirectory + String(Hash) + String(".x");
bool LoadFromFile = Utility::FileExists(DataFilename);
if(LoadFromFile)
{
PartitionedMesh.LoadFromXFile(MeshFilename);
MeshOutCopy = PartitionedMesh.GetMesh();
InputDataStream Stream;
Stream.LoadFromFile(DataFilename);
UINT Length;
Stream >> Length;
_VertexRemapArray.Allocate(Length);
Stream.ReadData((BYTE *)_VertexRemapArray.CArray(), _VertexRemapArray.Length() * sizeof(UINT));
}
else
{
FreeMeshOutCopy = true;
DWORD *pAdjacency = new DWORD[MeshIn.IndexCount()];
LPD3DXBUFFER FacePartitioningBuffer = NULL, VertexRemapArrayBuffer = NULL;
D3DValidate(MeshInCopy.GetMesh()->GenerateAdjacency(Tolerance, pAdjacency), "GenerateAdjacency");
UVAtlasCallbackContext Context;
Context.LastValue = 0;
D3DAlwaysValidate(D3DXUVAtlasCreate(
MeshInCopy.GetMesh(),
MaxCharts,
AllowedStretch,
TextureWidth,
TextureHeight,
GutterSize,
0,
pAdjacency,
NULL,
NULL,
UVAtlasCallback,
0.0001f,
&Context,
D3DXUVATLAS_DEFAULT,
&MeshOutCopy,
&FacePartitioningBuffer,
&VertexRemapArrayBuffer,
&MaxStretch,
&NumCharts
), "D3DXUVAtlasCreate");
delete[] pAdjacency;
_VertexRemapArray.Allocate(MeshOutCopy->GetNumVertices());
memcpy(_VertexRemapArray.CArray(), VertexRemapArrayBuffer->GetBufferPointer(), VertexRemapArrayBuffer->GetBufferSize());
FacePartitioningBuffer->Release();
VertexRemapArrayBuffer->Release();
PartitionedMesh.LoadMesh(MeshOutCopy);
if(FastLoadDirectory.Length() > 0)
{
PartitionedMesh.SaveToXFile(MeshFilename);
OutputDataStream Stream;
Stream << _VertexRemapArray.Length();
Stream.WriteData(_VertexRemapArray);
Stream.SaveToFile(DataFilename);
}
}
MeshOut = PartitionedMesh;
}
D3DAlwaysValidate(D3DXCreateTextureGutterHelper(TextureWidth, TextureHeight, MeshOutCopy, GutterSize / 2.0f, &_GutterHelper), "D3DXCreateTextureGutterHelper");
if(FreeMeshOutCopy)
{
MeshOutCopy->Release();
}
Grid<Vec2f> BarycentricCoordGrid(TextureHeight, TextureWidth);
Grid<BYTE> TextelClassGrid(TextureHeight, TextureWidth);
Grid<UINT> FaceIndexGrid(TextureHeight, TextureWidth);
D3DAlwaysValidate(_GutterHelper->GetBaryMap((D3DXVECTOR2 *)(BarycentricCoordGrid.CArray())), "GetBaryMap");
D3DAlwaysValidate(_GutterHelper->GetGutterMap(TextelClassGrid.CArray()), "GetGutterMap");
D3DAlwaysValidate(_GutterHelper->GetFaceMap(FaceIndexGrid.CArray()), "GetFaceMap");
_Cells.Allocate(TextureHeight, TextureWidth);
for(UINT y = 0; y < TextureHeight; y++)
{
for(UINT x = 0; x < TextureWidth; x++)
{
UVAtlasCell &CurCell = _Cells(y, x);
CurCell.BarycentricCoord = BarycentricCoordGrid(y, x);
CurCell.TextelClass = TextelClassGrid(y, x);
CurCell.FaceIndex = FaceIndexGrid(y, x);
}
}
}
#endif