在图形编程和图像处理领域,DDS(DirectDraw Surface)文件格式广泛用于存储纹理数据。由于DDS文件通常包含压缩或浮点格式的纹理数据,因此,有时我们需要将DDS文件中的纹理数据还原为易于分析和处理的文本格式。本文将详细介绍如何使用Direct3D(D3D9)库,读取DDS文件中的纹理数据并将其保存为TXT文件,以便于进一步分析。
1. 为什么需要将DDS文件数据还原为TXT格式?
DDS文件在图形应用中常用于高效存储纹理数据,但它们通常是二进制格式,直接读取不太方便。将纹理数据转换为文本格式有助于:
- 数据分析:方便开发人员分析每个像素的具体颜色值和纹理特性。
- 调试和验证:在调试过程中,文本格式比二进制格式更直观,有助于验证纹理是否正确加载和处理。
- 跨平台应用:文本文件更易于在不同平台之间传输和查看。
2. 示例:将DDS纹理数据还原为TXT格式
接下来,我们通过一个示例代码,演示如何将从DDS文件加载的纹理数据保存为TXT格式的文件。
cpp
#include <iostream>
#include <fstream>
#include <d3d9.h>
#include <d3dx9.h>
#include <cassert>
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
LPDIRECT3D9 m_pD3D = NULL;
LPDIRECT3DDEVICE9 m_pD3DDev = NULL;
LPDIRECT3DTEXTURE9 m_pTexture = NULL;
int m_nWidth = 0;
int m_nHeight = 0;
#define SafeRelease(p) if (p != NULL) { p->Release(); p = NULL; }
HRESULT InitD3D(HWND hwnd) {
if ((m_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)
{
return E_FAIL;
}
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
d3dpp.BackBufferWidth = m_nWidth;
d3dpp.BackBufferHeight = m_nHeight;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
if (FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &m_pD3DDev)))
{
if (FAILED(m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &m_pD3DDev)))
{
return E_FAIL;
}
}
return S_OK;
}
HRESULT LoadDDSTexture(const char* path) {
HRESULT hr;
hr = D3DXCreateTextureFromFile(m_pD3DDev, path, &m_pTexture);
if (FAILED(hr)) {
std::cout << "Failed to load DDS texture!" << std::endl;
return hr;
}
// Get the texture's dimensions
D3DSURFACE_DESC desc;
m_pTexture->GetLevelDesc(0, &desc);
m_nWidth = desc.Width;
m_nHeight = desc.Height;
return S_OK;
}
HRESULT SaveTextureToTXT(const char* path) {
if (m_pTexture == NULL) {
std::cout << "No texture to save!" << std::endl;
return E_FAIL;
}
// Get the texture's surface level
LPDIRECT3DSURFACE9 pSurface;
HRESULT hr = m_pTexture->GetSurfaceLevel(0, &pSurface);
if (FAILED(hr)) {
std::cout << "Failed to get surface level!" << std::endl;
return hr;
}
// Lock the surface to access pixel data
D3DLOCKED_RECT lockedRect;
hr = pSurface->LockRect(&lockedRect, NULL, D3DLOCK_READONLY);
if (FAILED(hr)) {
std::cout << "Failed to lock surface!" << std::endl;
return hr;
}
// Open the output text file
std::ofstream outFile(path);
if (!outFile.is_open()) {
std::cout << "Failed to open output file!" << std::endl;
return E_FAIL;
}
// Write the texture data to the text file
for (int y = 0; y < m_nHeight; ++y) {
for (int x = 0; x < m_nWidth; ++x) {
// Get the pixel data (assuming RGBA format with 32-bit floating point per channel)
DWORD* pixel = (DWORD*)((BYTE*)lockedRect.pBits + y * lockedRect.Pitch + x * sizeof(DWORD));
float* data = (float*)pixel;
// Write RGBA data (assuming D3DFMT_A32B32G32R32F format)
outFile << data[0] << " " << data[1] << " " << data[2] << " " << data[3] << std::endl;
}
}
// Close the file
outFile.close();
// Unlock the surface
pSurface->UnlockRect();
// Release the surface
SafeRelease(pSurface);
return S_OK;
}
int main() {
// Initialize Direct3D
HWND hwnd = GetConsoleWindow(); // Use console window for D3D initialization
if (FAILED(InitD3D(hwnd))) {
std::cout << "Direct3D Initialization Failed!" << std::endl;
return -1;
}
// Load the DDS texture file
const char* ddsFilePath = "input.dds";
if (FAILED(LoadDDSTexture(ddsFilePath))) {
std::cout << "Failed to load DDS file!" << std::endl;
return -1;
}
// Save the texture data to a TXT file
const char* txtFilePath = "output.txt";
if (FAILED(SaveTextureToTXT(txtFilePath))) {
std::cout << "Failed to save texture to TXT!" << std::endl;
return -1;
}
std::cout << "DDS texture data successfully saved to " << txtFilePath << std::endl;
// Cleanup
SafeRelease(m_pD3DDev);
SafeRelease(m_pD3D);
return 0;
}
3. 代码解析
初始化 Direct3D (InitD3D
)
- 使用
Direct3DCreate9
初始化 Direct3D 实例,并创建一个 Direct3D 设备(m_pD3DDev
),这是后续操作的基础。
加载 DDS 文件 (LoadDDSTexture
)
- 使用
D3DXCreateTextureFromFile
从指定路径加载 DDS 文件,并获取纹理的宽度和高度。m_pTexture
保存加载的纹理对象。
保存纹理数据到 TXT 文件 (SaveTextureToTXT
)
- 获取纹理的表面级别,并锁定该表面以便读取像素数据。
- 假设纹理采用 32 位浮点 RGBA 格式(
D3DFMT_A32B32G32R32F
),从每个像素的内存中提取 RGBA 值。 - 将每个像素的 RGBA 值保存到文本文件,每行一个像素的 4 个浮点数值,空格分隔。
主程序 (main
)
- 调用 Direct3D 初始化函数,加载 DDS 文件并将纹理数据保存为 TXT 文件。
4. 结果示例
假设纹理数据是浮点格式存储的,每个像素的 RGBA 值将被转换为以下格式存储:
python
0.1234 0.2345 0.3456 0.4567 0.5678 0.6789 0.7890 0.8901 ...
5. 注意事项
- 纹理格式 :此代码假设 DDS 文件使用的是
D3DFMT_A32B32G32R32F
格式,若 DDS 文件使用其他格式(如D3DFMT_R8G8B8A8
),则需要调整代码来处理不同的像素格式。 - 内存锁定 :锁定纹理表面时要小心,避免内存泄漏。使用
UnlockRect
来解锁内存。 - 输出文件格式:您可以根据需要调整输出格式,例如使用 CSV 格式或其他分隔符。