Skip to main content
GameDev.net gamedev.net
🔒 Locked

Need help with DDS loading

Started by flakem May 22, 2006 at 9:52 PM 1 replies 1.4k views
Original Post
flakem
flakem
I am trying to write a DDS loader but I am having problems. After parsing the file the image data appears to be corrupted (as shown below). I am pretty sure that I parse the header properly but I cannot figure how to properly access the image data. broken dds loader I upload the texture with the following code.

unsigned char *pixels;
int width, height, compressFormat;
bool mipmapped;
LoadDDS("wall.dds", pixels, width, height, mipmapped, compressFormat);
int imgSize = std::max(1, width / 4) * std::max(1, height / 4) * 8; //DXT1

GLuint texId;
glGenTextures(1, &texId);
glBindTexture(GL_TEXTURE_2D, texId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, compressFormat, width, height, 0, imgSize, pixels);
delete [] pixels;

The code for the LoadDDS function is shown below.

struct DDSHeader_t
{
    unsigned magic;
    
    unsigned surfaceSize;
    unsigned surfaceFlags;
    unsigned surfaceHeight;
    unsigned surfaceWidth;
    unsigned surfacePitchOrLinearSize;
    unsigned surfaceDepth;
    unsigned surfaceMipMapCount;
    unsigned surfaceReserved[11];
    
    unsigned PFSize;
    unsigned PFFlags;
    unsigned PFFourCC;
    unsigned PFBPP;
    unsigned PFRedMask;
    unsigned PFGreenMask;
    unsigned PFBlueMask;
    unsigned PFAlphaMask;

    unsigned caps1;
    unsigned caps2;
    unsigned capsReserved[2];
    
    unsigned reserved;
};

void LoadDDS(const char *filename, unsigned char *&pixels,
             int &width, int &height, bool &mipmapped, int &compressFormat)
{
    std::ifstream inFile(filename);
    unsigned char *buffer;
    unsigned char *data;
    DDSHeader_t ddsHeader;

    bool compressed;

    pixels = NULL;
    compressFormat = 0;
        
    inFile.seekg(0, std::ios::end);
    int length = inFile.tellg();
    inFile.seekg(0, std::ios::beg);

    data = new unsigned char[length];
    inFile.read((char *)data, length);
    inFile.close();
    inFile.clear();
    
    buffer = data;
    
    ddsHeader.magic = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.surfaceSize = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.surfaceFlags = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.surfaceHeight = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.surfaceWidth = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.surfacePitchOrLinearSize = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.surfaceDepth = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.surfaceMipMapCount = *(unsigned *)buffer;
    buffer += 4;

    //Skip over reserved bytes.
    buffer += 44;
    
    ddsHeader.PFSize = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.PFFlags = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.PFFourCC = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.PFBPP = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.PFRedMask = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.PFGreenMask = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.PFBlueMask = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.PFAlphaMask = *(unsigned *)buffer;
    buffer += 4;
    
    ddsHeader.caps1 = *(unsigned *)buffer;
    buffer += 4;
    ddsHeader.caps2 = *(unsigned *)buffer;
    buffer += 4;
    
    //Skip reserved stuff.
    buffer += 12;

    switch (ddsHeader.PFFourCC)
    {
        case DXT1:
            if (ddsHeader.PFFlags & DDPF_ALPHAPIXELS)
                compressFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
            else
                compressFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
            break;
        case DXT2:
            delete [] data;
            return;
        case DXT3:
            compressFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
            break;
        case DXT4:
            delete [] data;
            return;
        case DXT5:
            compressFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
            break;
        default:
            delete [] data;
            return;
    }

    mipmapped = (ddsHeader.surfaceMipMapCount > 1);
    compressed = ((ddsHeader.PFFlags & DDPF_FOURCC) && (ddsHeader.surfaceFlags & DDSD_LINEARSIZE));
    width = ddsHeader.surfaceWidth;
    height = ddsHeader.surfaceHeight;    
    
    if (compressed )
    {
        unsigned pSize = 0;
        int factor = 16;
        int w = width;
        int h = height;
        
        if (ddsHeader.PFFourCC == DXT1)
            factor = 8;
        
        //Compute the buffer size.
        for (unsigned i = 0; i < ddsHeader.surfaceMipMapCount; i++)
        {
            pSize += std::max(1, w / 4) * std::max(1, h / 4) * factor;
            w /= 2;
            h /= 2;
        }
        pixels = new unsigned char[pSize];

        //Copy the image data?
        memcpy(pixels, buffer, pSize);
    }
    else
    {
        //Ignore uncompressed files for now.
    }

    delete [] data;
}


Basiror
Basiror
Hi this is the source of a loader I found somewhere in these forums a few days ago

//-----------------------------------------------------------------------------//           Name: ogl_dds_texture_loader.cpp//         Author: Kevin Harris//  Last Modified: 02/01/05//    Description: This sample demonstrates how to use ARB_texture_compression//                 to load .dds compressed texture files.////   Control Keys: Left Mouse Button - Spin the view//                 F1 - Toggle between using a compressed texture and a  //                      regular texture.//                 Up Arrow   - View moves forward//                 Down Arrow - View moves backward//// NOTE: To create the compressed version of the original "lena.bmp" texture,//       I opened the texture file in Photoshop and flipped the image //       vertically and saved it out as "lena_flipped.bmp". This is to //       compensate for the .dds file format which is inverted. //       Some programmers opt not to flip the image itself. Instead they //       either flip it in their texture loader or adjust the texture //       coordinates to flip it. I chose to flip the actual image since //       I only had to fix one file. I've been tolds that this is how most //       programmers choose to deal with this problem. If you have a large //       collection of files to convert, there are command-line tools which //       can automate the process.////       I then used ATI's tool called "TheCompressonator" to generate mip-map //       levels and compress the file using DXT1 compression. I originally //       tried to use the "DirectX Texture Tool" that ships with DirectX 9.0c, //       but I had problems loading the resulting .dds files. The//       dwLinearSize member of its DDSURFACEDESC2 struct always returns 0, //       which causes problems since I can't load 0!////       You can get ATI's "TheCompressonator" tool from here:////       http://www.ati.com/developer/compressonator.html////-----------------------------------------------------------------------------#define STRICT#define WIN32_LEAN_AND_MEAN#include <windows.h>#include <stdio.h>#include <GL/gl.h>#include <GL/glu.h>#include <GL/glaux.h>#include <ddraw.h>    // Required for DirectX's DDSURFACEDESC2 structure definition#include "resource.h"//-----------------------------------------------------------------------------// FUNCTION POINTERS FOR OPENGL EXTENSIONS//-----------------------------------------------------------------------------// For convenience, this project ships with its own "glext.h" extension header // file. If you have trouble running this sample, it may be that this "glext.h" // file is defining something that your hardware doesn’t actually support. // Try recompiling the sample using your own local, vendor-specific "glext.h" // header file.#include "glext.h"      // Sample's header file//#include <GL/glext.h> // Your local header file// ARB_texture_compressionPFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB;//-----------------------------------------------------------------------------// GLOBALS//-----------------------------------------------------------------------------HWND   g_hWnd                = NULL;HDC    g_hDC                 = NULL;HGLRC  g_hRC                 = NULL;GLuint g_textureID           = -1;GLuint g_compressedTextureID = -1;bool g_bUseCompressedTexture = true;float g_fDistance = -3.0f;float g_fSpinX    = 0.0f;float g_fSpinY    = 0.0f;struct Vertex{    float tu, tv;    float x, y, z;};Vertex g_quadVertices[] ={    { 0.0f,0.0f, -1.0f,-1.0f, 0.0f },    { 1.0f,0.0f,  1.0f,-1.0f, 0.0f },    { 1.0f,1.0f,  1.0f, 1.0f, 0.0f },    { 0.0f,1.0f, -1.0f, 1.0f, 0.0f }};struct DDS_IMAGE_DATA{    GLsizei  width;    GLsizei  height;    GLint    components;    GLenum   format;    int      numMipMaps;    GLubyte *pixels;};//-----------------------------------------------------------------------------// PROTOTYPES//-----------------------------------------------------------------------------int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,                    LPSTR lpCmdLine, int nCmdShow);LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);void loadTexture(void);void loadCompressedTexture(void);DDS_IMAGE_DATA* loadDDSTextureFile(const char *filename);void init(void);void render(void);void shutDown(void);//-----------------------------------------------------------------------------// Name: WinMain()// Desc: The application's entry point//-----------------------------------------------------------------------------int WINAPI WinMain( HINSTANCE hInstance,                    HINSTANCE hPrevInstance,                    LPSTR     lpCmdLine,                    int       nCmdShow ){    WNDCLASSEX winClass;     MSG        uMsg;    memset(&uMsg,0,sizeof(uMsg));    winClass.lpszClassName = "MY_WINDOWS_CLASS";    winClass.cbSize        = sizeof(WNDCLASSEX);    winClass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;    winClass.lpfnWndProc   = WindowProc;    winClass.hInstance     = hInstance;    winClass.hIcon         = LoadIcon(hInstance, (LPCTSTR)IDI_OPENGL_ICON);    winClass.hIconSm       = LoadIcon(hInstance, (LPCTSTR)IDI_OPENGL_ICON);    winClass.hCursor       = LoadCursor(NULL, IDC_ARROW);    winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);    winClass.lpszMenuName  = NULL;    winClass.cbClsExtra    = 0;    winClass.cbWndExtra    = 0;        if( !RegisterClassEx(&winClass) )        return E_FAIL;    g_hWnd = CreateWindowEx( NULL, "MY_WINDOWS_CLASS",                              "OpenGL - Texture Compression Using .DDS Files",                             WS_OVERLAPPEDWINDOW | WS_VISIBLE,                             0, 0, 640, 480, NULL, NULL, hInstance, NULL );    if( g_hWnd == NULL )        return E_FAIL;    ShowWindow( g_hWnd, nCmdShow );    UpdateWindow( g_hWnd );    init();    while( uMsg.message != WM_QUIT )    {        if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) )        {            TranslateMessage( &uMsg );            DispatchMessage( &uMsg );        }        else            render();    }    shutDown();    UnregisterClass( "MY_WINDOWS_CLASS", hInstance );    return uMsg.wParam;}//-----------------------------------------------------------------------------// Name: WindowProc()// Desc: The window's message handler//-----------------------------------------------------------------------------LRESULT CALLBACK WindowProc( HWND   hWnd,                              UINT   msg,                              WPARAM wParam,                              LPARAM lParam ){    static POINT ptLastMousePosit;    static POINT ptCurrentMousePosit;    static bool bMousing;    switch( msg )    {        case WM_KEYDOWN:        {            switch( wParam )            {                case VK_ESCAPE:                    PostQuitMessage(0);                break;                case VK_F1:                    g_bUseCompressedTexture = !g_bUseCompressedTexture;                break;                case 38: // Up Arrow Key                    g_fDistance += 1.0f;                break;                case 40: // Down Arrow Key                    g_fDistance -= 1.0f;                break;            }        }        break;        case WM_LBUTTONDOWN:        {            ptLastMousePosit.x = ptCurrentMousePosit.x = LOWORD (lParam);            ptLastMousePosit.y = ptCurrentMousePosit.y = HIWORD (lParam);            bMousing = true;        }        break;        case WM_LBUTTONUP:        {            bMousing = false;        }        break;        case WM_MOUSEMOVE:        {            ptCurrentMousePosit.x = LOWORD (lParam);            ptCurrentMousePosit.y = HIWORD (lParam);            if( bMousing )            {                g_fSpinX -= (ptCurrentMousePosit.x - ptLastMousePosit.x);                g_fSpinY -= (ptCurrentMousePosit.y - ptLastMousePosit.y);            }                        ptLastMousePosit.x = ptCurrentMousePosit.x;            ptLastMousePosit.y = ptCurrentMousePosit.y;        }        break;        case WM_SIZE:        {            int nWidth  = LOWORD(lParam);             int nHeight = HIWORD(lParam);            glViewport(0, 0, nWidth, nHeight);            glMatrixMode( GL_PROJECTION );            glLoadIdentity();            gluPerspective( 45.0, (GLdouble)nWidth / (GLdouble)nHeight, 0.1, 100.0);        }        break;        case WM_CLOSE:        {            PostQuitMessage(0);         }        case WM_DESTROY:        {            PostQuitMessage(0);        }        break;                default:        {            return DefWindowProc( hWnd, msg, wParam, lParam );        }        break;    }    return 0;}//-----------------------------------------------------------------------------// Name: loadTexture()// Desc: //-----------------------------------------------------------------------------void loadTexture( void ){    AUX_RGBImageRec *pTextureImage = auxDIBImageLoad( ".\\lena.bmp" );    if( pTextureImage != NULL )    {        glGenTextures( 1, &g_textureID );        glBindTexture( GL_TEXTURE_2D, g_textureID );        glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR );        glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR );        glTexImage2D( GL_TEXTURE_2D, 0, 3, pTextureImage->sizeX, pTextureImage->sizeY, 0,            GL_RGB, GL_UNSIGNED_BYTE, pTextureImage->data );    }    if( pTextureImage )    {        if( pTextureImage->data )            free( pTextureImage->data );        free( pTextureImage );    }}//-----------------------------------------------------------------------------// Name: loadCompressedTexture()// Desc: //-----------------------------------------------------------------------------void loadCompressedTexture( void ){    // NOTE: Unlike "lena.bmp", "lena.dds" actually contains its own mip-map     // levels, which are also compressed.    DDS_IMAGE_DATA *pDDSImageData = loadDDSTextureFile( "lena.dds" );    if( pDDSImageData != NULL )    {        int nHeight     = pDDSImageData->height;        int nWidth      = pDDSImageData->width;        int nNumMipMaps = pDDSImageData->numMipMaps;        int nBlockSize;        if( pDDSImageData->format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT )            nBlockSize = 8;        else            nBlockSize = 16;        glGenTextures( 1, &g_compressedTextureID );        glBindTexture( GL_TEXTURE_2D, g_compressedTextureID );        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );        int nSize;        int nOffset = 0;        // Load the mip-map levels        for( int i = 0; i < nNumMipMaps; ++i )        {            if( nWidth  == 0 ) nWidth  = 1;            if( nHeight == 0 ) nHeight = 1;            nSize = ((nWidth+3)/4) * ((nHeight+3)/4) * nBlockSize;            glCompressedTexImage2DARB( GL_TEXTURE_2D,                                       i,                                       pDDSImageData->format,                                       nWidth,                                       nHeight,                                       0,                                       nSize,                                       pDDSImageData->pixels + nOffset );            nOffset += nSize;            // Half the image size for the next mip-map level...            nWidth  = (nWidth  / 2);            nHeight = (nHeight / 2);        }    }    if( pDDSImageData != NULL )    {        if( pDDSImageData->pixels != NULL )            free( pDDSImageData->pixels );        free( pDDSImageData );    }}//-----------------------------------------------------------------------------// Name: loadDDSTextureFile()// Desc: //-----------------------------------------------------------------------------DDS_IMAGE_DATA* loadDDSTextureFile( const char *filename ){    DDS_IMAGE_DATA *pDDSImageData;    DDSURFACEDESC2 ddsd;    char filecode[4];    FILE *pFile;    int factor;    int bufferSize;    // Open the file    pFile = fopen( filename, "rb" );    if( pFile == NULL )    {        char str[255];        sprintf( str, "loadDDSTextureFile couldn't find, or failed to load \"%s\"", filename );        MessageBox( NULL, str, "ERROR", MB_OK|MB_ICONEXCLAMATION );        return NULL;    }    // Verify the file is a true .dds file    fread( filecode, 1, 4, pFile );    if( strncmp( filecode, "DDS ", 4 ) != 0 )    {        char str[255];        sprintf( str, "The file \"%s\" doesn't appear to be a valid .dds file!", filename );        MessageBox( NULL, str, "ERROR", MB_OK|MB_ICONEXCLAMATION );        fclose( pFile );        return NULL;    }    // Get the surface descriptor    fread( &ddsd, sizeof(ddsd), 1, pFile );    pDDSImageData = (DDS_IMAGE_DATA*) malloc(sizeof(DDS_IMAGE_DATA));    memset( pDDSImageData, 0, sizeof(DDS_IMAGE_DATA) );    //    // This .dds loader supports the loading of compressed formats DXT1, DXT3     // and DXT5.    //    switch( ddsd.ddpfPixelFormat.dwFourCC )    {        case FOURCC_DXT1:            // DXT1's compression ratio is 8:1            pDDSImageData->format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;            factor = 2;            break;        case FOURCC_DXT3:            // DXT3's compression ratio is 4:1            pDDSImageData->format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;            factor = 4;            break;        case FOURCC_DXT5:            // DXT5's compression ratio is 4:1            pDDSImageData->format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;            factor = 4;            break;        default:            char str[255];            sprintf( str, "The file \"%s\" doesn't appear to be compressed "                "using DXT1, DXT3, or DXT5!", filename );            MessageBox( NULL, str, "ERROR", MB_OK|MB_ICONEXCLAMATION );            return NULL;    }    //    // How big will the buffer need to be to load all of the pixel data     // including mip-maps?    //    if( ddsd.dwLinearSize == 0 )    {        MessageBox( NULL, "dwLinearSize is 0!","ERROR",            MB_OK|MB_ICONEXCLAMATION);    }    if( ddsd.dwMipMapCount > 1 )        bufferSize = ddsd.dwLinearSize * factor;    else        bufferSize = ddsd.dwLinearSize;    pDDSImageData->pixels = (unsigned char*)malloc(bufferSize * sizeof(unsigned char));    fread( pDDSImageData->pixels, 1, bufferSize, pFile );    // Close the file    fclose( pFile );    pDDSImageData->width      = ddsd.dwWidth;    pDDSImageData->height     = ddsd.dwHeight;    pDDSImageData->numMipMaps = ddsd.dwMipMapCount;    if( ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT1 )        pDDSImageData->components = 3;    else        pDDSImageData->components = 4;    return pDDSImageData;}//-----------------------------------------------------------------------------// Name: init()// Desc: //-----------------------------------------------------------------------------void init( void ){    GLuint PixelFormat;    PIXELFORMATDESCRIPTOR pfd;    memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));    pfd.nSize      = sizeof(PIXELFORMATDESCRIPTOR);    pfd.nVersion   = 1;    pfd.dwFlags    = PFD_DRAW_TO_WINDOW |PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;    pfd.iPixelType = PFD_TYPE_RGBA;    pfd.cColorBits = 16;    pfd.cDepthBits = 16;        g_hDC = GetDC( g_hWnd );    PixelFormat = ChoosePixelFormat( g_hDC, &pfd );    SetPixelFormat( g_hDC, PixelFormat, &pfd);    g_hRC = wglCreateContext( g_hDC );    wglMakeCurrent( g_hDC, g_hRC );    glClearColor( 0.35f, 0.53f, 0.7f, 1.0f );    glEnable(GL_TEXTURE_2D);    glMatrixMode( GL_PROJECTION );    glLoadIdentity();    gluPerspective( 45.0f, 640.0f / 480.0f, 0.1f, 100.0f);    //    // If the required extension is present, get the addresses of its     // functions that we wish to use...    //    char *ext = (char*)glGetString( GL_EXTENSIONS );    if( strstr( ext, "ARB_texture_compression" ) == NULL )    {        MessageBox(NULL,"ARB_texture_compression extension was not found",            "ERROR",MB_OK|MB_ICONEXCLAMATION);        return;    }    else    {        glCompressedTexImage2DARB = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)wglGetProcAddress("glCompressedTexImage2DARB");        if( !glCompressedTexImage2DARB )        {            MessageBox(NULL,"One or more ARB_texture_compression functions were not found",                "ERROR",MB_OK|MB_ICONEXCLAMATION);            return;        }    }    loadTexture();    loadCompressedTexture();}//-----------------------------------------------------------------------------// Name: shutDown()// Desc: //-----------------------------------------------------------------------------void shutDown( void )   {    glDeleteTextures( 1, &g_textureID );    glDeleteTextures( 1, &g_compressedTextureID );    if( g_hRC != NULL )    {        wglMakeCurrent( NULL, NULL );        wglDeleteContext( g_hRC );        g_hRC = NULL;    }    if( g_hDC != NULL )    {        ReleaseDC( g_hWnd, g_hDC );        g_hDC = NULL;    }}//-----------------------------------------------------------------------------// Name: render()// Desc: //-----------------------------------------------------------------------------void render( void ){    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );    glMatrixMode( GL_MODELVIEW );    glLoadIdentity();    glTranslatef( 0.0f, 0.0f, g_fDistance );    glRotatef( -g_fSpinY, 1.0f, 0.0f, 0.0f );    glRotatef( -g_fSpinX, 0.0f, 1.0f, 0.0f );    if( g_bUseCompressedTexture == true )        glBindTexture( GL_TEXTURE_2D, g_compressedTextureID );    else        glBindTexture( GL_TEXTURE_2D, g_textureID );    glInterleavedArrays( GL_T2F_V3F, 0, g_quadVertices );    glDrawArrays( GL_QUADS, 0, 4 );    glDisable(GL_BLEND);    SwapBuffers( g_hDC );}
http://www.8ung.at/basiror/theironcross.html
flakem
flakem
I found the problem. I did not open the file in binary mode.
Replacing
std::ifstream inFile(filename);
with
std::ifstream inFile(filename, std::ios::binary);
fixed the problem.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.