Exporting3DTextures         Saving to various 3D formats, like raw, DDS

Exporting 3D Textures

Welcome to the page about exporting 3D textures. It is fun, simple, everyone should do it!

to DevIL .RAW

Exporting raw volume data to DevIL .raw format is simple:

// Extents
    uint32 dims[3] = {width, height, depth};
    // Image data
    uint8 *data;

    FILE *f = fopen(outfile, "wb");
    assert(f);
    fwrite(dims, 3, 4, f);
    char bpp = 4; // channels
    char bpc = 1; // byte per component
    fwrite(&bpp, 1, 1, f);
    fwrite(&bpc, 1, 1, f);
    // ABGR
    fwrite(data, dims[0]*dims[1]*dims[2], 4, f);

to .DDS

Below is a source fragment that will convert "RDoutput.raw" in DevIL .RAW format to "RDoutput.dds" as a Direct3D volume.
This is a somewhat more compact and portable format than the .RAW format used above. It is more involved because it needs a working D3D9 and windows context to work.

#include <iostream>
#include <cstdio>
#include <cassert>

#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>

#include <IL/il.h>
#include <IL/ilu.h>

LPDIRECT3D9 gD3dObject=NULL;
LPDIRECT3DDEVICE9 gD3dDevice=NULL;

int checkError(HRESULT hr)
{
    if(FAILED(hr))
    {
        std::cerr << "D3D9 failure" << std::endl;
        exit(0);
    }
}

LRESULT WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    return DefWindowProc( hWnd, uMsg, wParam, lParam );
}

int WinMain(
    HINSTANCE hInst,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow
)
{
    size_t width, height, depth;
    char *infile="RDoutput.raw";
    char *outfile="RDoutput.dds";

    std::cerr << "Main begins" << std::endl;
    ilInit();
    ilEnable( IL_FILE_OVERWRITE );

    std::cerr << "Creating window" << std::endl;
    std::string name = "Window";

    // Register the window class
    // NB allow 4 bytes of window data for D3D9RenderWindow pointer
    WNDCLASS wndClass = { CS_HREDRAW | CS_VREDRAW, (WNDPROC)WndProc, 0, 0, hInst,
        LoadIcon( NULL, IDI_APPLICATION ),
        LoadCursor( NULL, IDC_ARROW ),
        (HBRUSH)GetStockObject( BLACK_BRUSH ), NULL,
        TEXT(name.c_str()) };
    RegisterClass( &wndClass );

    // Create our main window
    // Pass pointer to self
    HWND hWnd = CreateWindow(TEXT(name.c_str()),
                                TEXT(name.c_str()),
                                WS_OVERLAPPEDWINDOW, 0, 0,
                                640, 480, 0L, 0L, hInst, 0);

    ShowWindow(hWnd, SW_SHOWNORMAL);
    UpdateWindow(hWnd);

    std::cerr << "Creating D3D9" << std::endl;
    gD3dObject = Direct3DCreate9(D3D_SDK_VERSION);

    D3DPRESENT_PARAMETERS presParams;
    ZeroMemory(&presParams, sizeof(presParams));
    presParams.Windowed = TRUE;
    presParams.BackBufferFormat = D3DFMT_UNKNOWN;
    presParams.BackBufferCount = 1;
    presParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
    presParams.hDeviceWindow = hWnd;
    //presParams.BackBufferWidth = 640;
    //presParams.BackBufferHeight = 480;

    checkError(gD3dObject->CreateDevice(D3DADAPTER_DEFAULT,
        D3DDEVTYPE_HAL,hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING,
        &presParams, &gD3dDevice));

    ILuint ImageName;

    ilGenImages( 1, &ImageName );
    ilBindImage( ImageName );

    // Put it right side up
    ilEnable(IL_ORIGIN_SET);
    ilSetInteger(IL_ORIGIN_MODE, IL_ORIGIN_UPPER_LEFT);
    ilLoad(IL_RAW, infile);
    width = ilGetInteger(IL_IMAGE_WIDTH);
    height = ilGetInteger(IL_IMAGE_HEIGHT);
    depth = ilGetInteger(IL_IMAGE_DEPTH);
    std::cerr << "Dimensions " << width << " " << height << " " << depth << std::endl;
    ilConvertImage(IL_BGRA, IL_UNSIGNED_BYTE);

    assert(ilGetInteger(IL_IMAGE_WIDTH) == width);

    std::cerr << "Creating volume texture" << std::endl;
    LPDIRECT3DVOLUMETEXTURE9 pVolumeTexture;

    checkError(D3DXCreateVolumeTexture(
        gD3dDevice,
        width, height, depth, 1, 0,
        D3DFMT_A8R8G8B8,
        D3DPOOL_MANAGED,
        &pVolumeTexture
    ));

    std::cerr << "Converting image" << std::endl;
    // Data
    unsigned char *data = (unsigned char*)ilGetData();

    std::cerr << "Acquiring volume" << std::endl;
    D3DBOX srcBox, destBox;
    LPDIRECT3DVOLUME9 volume;
    checkError(pVolumeTexture->GetVolumeLevel(0, &volume));

    std::cerr << "Loading image into D3DX" << std::endl;
    srcBox.Left = 0;
    srcBox.Top = 0;
    srcBox.Right = width;
    srcBox.Bottom = height;
    srcBox.Front = 0;
    srcBox.Back = depth;
    destBox = srcBox;
    unsigned int *datax = (unsigned int*)ilGetData();

    int rowPitch = width*4;
    int slicePitch = rowPitch*height;

    checkError(
        D3DXLoadVolumeFromMemory(
            volume,
            0,
            0,
            datax,
            D3DFMT_A8R8G8B8,
            rowPitch, slicePitch, 0,
            &srcBox,
            D3DX_DEFAULT, 0
        )
    );
    std::cerr << "Writing data" << std::endl;
    D3DXSaveVolumeToFile(outfile, D3DXIFF_DDS, volume, 0, 0);
    std::cerr << "Done" << std::endl;

    ilDeleteImages(1, &ImageName);
}