📄 loadsavedds.cpp
字号:
/* Copyright (C) Greg James, 2001.
* All rights reserved worldwide.
*
* This software is provided "as is" without express or implied
* warranties. You may freely copy and compile this source into
* applications you distribute provided that the copyright text
* below is included in the resulting source code, for example:
* "Portions Copyright (C) Greg James, 2001"
*/
#include "cdds.h"
/////////////////////////////////////////////////////////////////////////////
// CDDS construction/destruction
CDDS::CDDS()
{
m_ptexOrig = NULL;
m_ptexNew = NULL;
m_dwWidth = 0;
m_dwHeight = 0;
m_dwDepth = 0;
m_numMips = 0;
m_dwCubeMapFlags = 0;
m_bAllocatedInternally = false;
//m_bTitleModsChanged = FALSE;
}
CDDS::~CDDS()
{
if (m_bAllocatedInternally)
ReleasePpo(&m_ptexOrig);
//ReleasePpo(&m_ptexNew);
}
BOOL CDDS::MakeTexture(TextureType iTexType, DWORD dwWidth, DWORD dwHeight, int numMips,
D3DFORMAT fmt, int dwDepth)
{
HRESULT hr;
m_dwWidth = dwWidth;
m_dwHeight = dwHeight;
m_numMips = numMips;
switch(iTexType)
{
case TEXTURE2D:
LPDIRECT3DTEXTURE8 pmiptex;
hr = m_pd3ddev->CreateTexture(m_dwWidth, m_dwHeight, m_numMips,
0, fmt, D3DPOOL_MANAGED, &pmiptex);
if (FAILED(hr))
{
AfxMessageBox(ID_ERROR_CANTCREATETEXTURE);
return FALSE;
}
m_bAllocatedInternally = true;
m_ptexOrig = pmiptex;
break;
case CUBE_TEXTURE:
// Cube Map
LPDIRECT3DCUBETEXTURE8 pcubetex;
m_dwCubeMapFlags = DDS_CUBEMAP_ALLFACES;
hr = m_pd3ddev->CreateCubeTexture(m_dwWidth, m_numMips,
0, fmt, D3DPOOL_MANAGED, &pcubetex);
if (FAILED(hr))
{
AfxMessageBox(ID_ERROR_CANTCREATETEXTURE);
return FALSE;
}
m_bAllocatedInternally = true;
m_ptexOrig = pcubetex;
break;
case VOLUME_TEXTURE:
LPDIRECT3DVOLUMETEXTURE8 pvoltex;
m_dwDepth = dwDepth;
hr = m_pd3ddev->CreateVolumeTexture(m_dwWidth, m_dwHeight, m_dwDepth, m_numMips,
0, fmt, D3DPOOL_SYSTEMMEM, &pvoltex);
if (FAILED(hr))
{
AfxMessageBox(ID_ERROR_CANTCREATETEXTURE);
return FALSE;
}
m_bAllocatedInternally = true;
m_ptexOrig = pvoltex;
break;
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CDDS serialization
/*void CDDS::Serialize(CArchive& ar)
{
HRESULT hr;
if (ar.IsStoring())
{
LPDIRECT3DBASETEXTURE8 ptex;
ptex = (m_ptexNew == NULL ? m_ptexOrig : m_ptexNew);
SaveDDS(ptex, ar);
}
else
{
CFile* pFile = ar.GetFile();
CSTR str = pFile->GetFilePath();
TCHAR* pszExt = strrchr(str, '.');
if (lstrcmpi(pszExt, ".bmp") == 0 || lstrcmpi(pszExt, ".tga") == 0)
{
if (FAILED(hr = LoadBmp(str)))
AfxThrowArchiveException(CArchiveException::generic);
}
else if (lstrcmpi(pszExt, ".dds") == 0)
{
ReleasePpo(&m_ptexOrig);
ReleasePpo(&m_ptexNew);
if (FAILED(hr = LoadDDS(&m_ptexOrig, ar)))
AfxThrowArchiveException(CArchiveException::badIndex); // invalid file format
}
else
{
AfxThrowArchiveException(CArchiveException::badIndex); // invalid file format
}
}
} */
HRESULT CDDS::SaveTexture(LPDIRECT3DTEXTURE8 ptex, const char * filename)
{
//HRESULT hr;
D3DSURFACE_DESC sd;
ptex->GetLevelDesc(0, &sd);
m_dwWidth = sd.Width;
m_dwHeight = sd.Height;
m_numMips = ptex->GetLevelCount();
m_ptexOrig = ptex;
return SaveDDS(ptex, filename);
}
HRESULT CDDS::SaveCubeMap(LPDIRECT3DCUBETEXTURE8 pcubetex, const char * filename)
{
//HRESULT hr;
D3DSURFACE_DESC sd;
pcubetex->GetLevelDesc(0, &sd);
m_dwWidth = sd.Width;
m_dwHeight = sd.Height;
m_numMips = pcubetex->GetLevelCount();
m_ptexOrig = pcubetex;
return SaveDDS(pcubetex, filename);
}
HRESULT CDDS::SaveVolumeTexture(LPDIRECT3DVOLUMETEXTURE8 pvoltex, const char * filename)
{
//HRESULT hr;
D3DVOLUME_DESC vd;
pvoltex->GetLevelDesc(0, &vd);
m_dwWidth = vd.Width;
m_dwHeight = vd.Height;
m_dwDepth = vd.Depth;
m_numMips = pvoltex->GetLevelCount();
m_ptexOrig = pvoltex;
return SaveDDS(pvoltex, filename);
}
HRESULT CDDS::SaveDDS(LPDIRECT3DBASETEXTURE8 ptex, const char * filename)
{
CArchive ar;
HRESULT hr;
DDS_HEADER ddsh;
DWORD dwMagic;
D3DFORMAT fmt;
DWORD dwSize;
DWORD dwPitch = 0;
D3DLOCKED_RECT lr;
D3DLOCKED_BOX lb;
LPDIRECT3DTEXTURE8 pmiptex = NULL;
LPDIRECT3DCUBETEXTURE8 pcubetex = NULL;
LPDIRECT3DVOLUMETEXTURE8 pvoltex = NULL;
ar.Open(filename, "wb");
if (IsVolumeMap())
pvoltex = (LPDIRECT3DVOLUMETEXTURE8)ptex;
else if (!IsCubeMap())
pmiptex = (LPDIRECT3DTEXTURE8)ptex;
else
pcubetex = (LPDIRECT3DCUBETEXTURE8)ptex;
dwMagic = MAKEFOURCC('D','D','S',' ');
ar.Write(&dwMagic, sizeof(dwMagic));
// Fill in the DDS header structure
ZeroMemory(&ddsh, sizeof(ddsh));
ddsh.dwSize = sizeof(ddsh);
ddsh.dwHeaderFlags = DDS_HEADER_FLAGS_TEXTURE;
ddsh.dwWidth = m_dwWidth;
ddsh.dwHeight = m_dwHeight;
ddsh.dwSurfaceFlags = DDS_SURFACE_FLAGS_TEXTURE;
if (m_numMips > 1)
{
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_MIPMAP;
ddsh.dwSurfaceFlags |= DDS_SURFACE_FLAGS_MIPMAP;
ddsh.dwMipMapCount = m_numMips;
}
if (pvoltex != NULL)
{
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_VOLUME;
// Note: "dwCubemapFlags" is mostly for cubemap flags,
// but in this case is also used to indicate a volume texture
ddsh.dwCubemapFlags |= DDS_FLAGS_VOLUME;
ddsh.dwDepth = m_dwDepth;
}
// In DX7, you could (optionally) use and save a subset of
// cubemap faces. In DX8, you must use and save all faces of a cubemap.
if (IsCubeMap())
{
ddsh.dwSurfaceFlags |= DDS_SURFACE_FLAGS_CUBEMAP;
ddsh.dwCubemapFlags = DDS_CUBEMAP_ALLFACES;
}
// Determine dwPitch and dwSize for the texture
if (pvoltex != NULL)
{
D3DVOLUME_DESC vd;
pvoltex->GetLevelDesc(0, &vd);
fmt = vd.Format;
dwSize = vd.Size;
if (SUCCEEDED(pvoltex->LockBox(0, &lb, NULL, D3DLOCK_READONLY)))
{
dwPitch = lb.RowPitch;
pvoltex->UnlockBox(0);
}
}
else if (pmiptex != NULL)
{
D3DSURFACE_DESC sd;
pmiptex->GetLevelDesc(0, &sd);
fmt = sd.Format;
dwSize = sd.Size;
if (SUCCEEDED(pmiptex->LockRect(0, &lr, NULL, D3DLOCK_READONLY)))
{
dwPitch = lr.Pitch;
pmiptex->UnlockRect(0);
}
}
else
{
D3DSURFACE_DESC sd;
pcubetex->GetLevelDesc(0, &sd);
fmt = sd.Format;
dwSize = sd.Size;
if (SUCCEEDED(pcubetex->LockRect(D3DCUBEMAP_FACE_POSITIVE_X, 0,
&lr, NULL, D3DLOCK_READONLY)))
{
dwPitch = lr.Pitch;
pcubetex->UnlockRect(D3DCUBEMAP_FACE_POSITIVE_X, 0);
}
}
// Note that although this code stores the pitch or linear size
// of the surface in the DDS file (for consistency with DX7), it
// is better to use the pitch or linear size of the surface
// created when loading the DDS file into a texture than to use
// the file values. The pitch of a created surface, especially,
// can be different from the pitch stored in the DDS file.
switch (fmt)
{
case D3DFMT_DXT1:
ddsh.ddspf = DDSPF_DXT1;
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
ddsh.dwPitchOrLinearSize = dwSize;
break;
case D3DFMT_DXT2:
ddsh.ddspf = DDSPF_DXT2;
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
ddsh.dwPitchOrLinearSize = dwSize;
break;
case D3DFMT_DXT3:
ddsh.ddspf = DDSPF_DXT3;
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
ddsh.dwPitchOrLinearSize = dwSize;
break;
case D3DFMT_DXT4:
ddsh.ddspf = DDSPF_DXT4;
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
ddsh.dwPitchOrLinearSize = dwSize;
break;
case D3DFMT_DXT5:
ddsh.ddspf = DDSPF_DXT5;
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
ddsh.dwPitchOrLinearSize = dwSize;
break;
case D3DFMT_A8R8G8B8:
ddsh.ddspf = DDSPF_A8R8G8B8;
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_PITCH;
ddsh.dwPitchOrLinearSize = dwPitch;
break;
case D3DFMT_A1R5G5B5:
ddsh.ddspf = DDSPF_A1R5G5B5;
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_PITCH;
ddsh.dwPitchOrLinearSize = dwPitch;
break;
case D3DFMT_A4R4G4B4:
ddsh.ddspf = DDSPF_A4R4G4B4;
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_PITCH;
ddsh.dwPitchOrLinearSize = dwPitch;
break;
case D3DFMT_R8G8B8:
ddsh.ddspf = DDSPF_R8G8B8;
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_PITCH;
ddsh.dwPitchOrLinearSize = dwPitch;
break;
case D3DFMT_R5G6B5:
ddsh.ddspf = DDSPF_R5G6B5;
ddsh.dwHeaderFlags |= DDS_HEADER_FLAGS_PITCH;
ddsh.dwPitchOrLinearSize = dwPitch;
break;
default:
return E_FAIL;
}
ar.Write(&ddsh, sizeof(ddsh));
if (pvoltex != NULL)
{
if (FAILED(hr = SaveAllVolumeSurfaces(pvoltex, ar)))
return hr;
}
else if (pmiptex != NULL)
{
if (FAILED(hr = SaveAllMipSurfaces(ptex, D3DCUBEMAP_FACE_FORCE_DWORD, ar)))
return hr;
}
else
{
if (FAILED(hr = SaveAllMipSurfaces(ptex, D3DCUBEMAP_FACE_POSITIVE_X, ar)))
return hr;
if (FAILED(hr = SaveAllMipSurfaces(ptex, D3DCUBEMAP_FACE_NEGATIVE_X, ar)))
return hr;
if (FAILED(hr = SaveAllMipSurfaces(ptex, D3DCUBEMAP_FACE_POSITIVE_Y, ar)))
return hr;
if (FAILED(hr = SaveAllMipSurfaces(ptex, D3DCUBEMAP_FACE_NEGATIVE_Y, ar)))
return hr;
if (FAILED(hr = SaveAllMipSurfaces(ptex, D3DCUBEMAP_FACE_POSITIVE_Z, ar)))
return hr;
if (FAILED(hr = SaveAllMipSurfaces(ptex, D3DCUBEMAP_FACE_NEGATIVE_Z, ar)))
return hr;
}
ar.Close();
return S_OK;
}
HRESULT CDDS::SaveAllMipSurfaces(LPDIRECT3DBASETEXTURE8 ptex, D3DCUBEMAP_FACES FaceType, CArchive& ar)
{
HRESULT hr;
LPDIRECT3DSURFACE8 psurf;
D3DSURFACE_DESC sd;
UINT iLevel;
D3DLOCKED_RECT lr;
LPDIRECT3DTEXTURE8 pmiptex = NULL;
LPDIRECT3DCUBETEXTURE8 pcubetex = NULL;
if (FaceType == D3DCUBEMAP_FACE_FORCE_DWORD)
pmiptex = (LPDIRECT3DTEXTURE8)ptex;
else
pcubetex = (LPDIRECT3DCUBETEXTURE8)ptex;
for (iLevel = 0; iLevel < m_numMips; iLevel++)
{
if (pmiptex != NULL)
hr = pmiptex->GetSurfaceLevel(iLevel, &psurf);
else
hr = pcubetex->GetCubeMapSurface(FaceType, iLevel, &psurf);
if (FAILED(hr))
return hr;
psurf->GetDesc(&sd);
if (pmiptex != NULL)
hr = pmiptex->LockRect(iLevel, &lr, NULL, 0);
else
hr = pcubetex->LockRect(FaceType, iLevel, &lr, NULL, 0);
if (FAILED(hr))
return hr;
if (sd.Format == D3DFMT_DXT1 ||
sd.Format == D3DFMT_DXT2 ||
sd.Format == D3DFMT_DXT3 ||
sd.Format == D3DFMT_DXT4 ||
sd.Format == D3DFMT_DXT5)
{
ar.Write(lr.pBits, sd.Size);
}
else
{
DWORD yp;
BYTE* pbDest = (BYTE*)lr.pBits;
LONG dataBytesPerRow = 0;
if (sd.Format == D3DFMT_A8R8G8B8)
dataBytesPerRow = 4 * sd.Width;
else if (sd.Format == D3DFMT_R8G8B8)
dataBytesPerRow = 3 * sd.Width;
else
dataBytesPerRow = 2 * sd.Width;
for (yp = 0; yp < sd.Height; yp++)
{
ar.Write(pbDest, dataBytesPerRow);
pbDest += lr.Pitch;
}
}
if (pmiptex != NULL)
hr = pmiptex->UnlockRect(iLevel);
else
hr = pcubetex->UnlockRect(FaceType, iLevel);
}
return S_OK;
}
HRESULT CDDS::SaveAllVolumeSurfaces(LPDIRECT3DVOLUMETEXTURE8 pvoltex, CArchive& ar)
{
HRESULT hr;
D3DVOLUME_DESC vd;
D3DBOX box;
D3DLOCKED_BOX lb;
UINT iLevel;
UINT numBytesPerRow;
BYTE* pbSlice;
BYTE* pbRow;
UINT zp;
UINT yp;
for (iLevel = 0; iLevel < m_numMips; iLevel++)
{
pvoltex->GetLevelDesc(iLevel, &vd);
box.Left = 0;
box.Right = vd.Width;
box.Top = 0;
box.Bottom = vd.Height;
box.Front = 0;
box.Back = vd.Depth;
hr = pvoltex->LockBox(iLevel, &lb, &box, 0);
if (FAILED(hr))
return hr;
switch(vd.Format)
{
case D3DFMT_A8R8G8B8:
numBytesPerRow = 4 * vd.Width;
break;
case D3DFMT_R8G8B8:
numBytesPerRow = 3 * vd.Width;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -