Sign in to follow this  
flakem

Need help with DDS loading

Recommended Posts

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;
}


Share this post


Link to post
Share on other sites
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_compression
PFNGLCOMPRESSEDTEXIMAGE2DARBPROC 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 );
}


Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this