c++ - 在 OpenGL 中加载 DDS DXT1,崩溃

标签 c++ opengl directdraw dds-format

知道我的代码有什么问题吗?当我执行 glCompressedTexImage2D() 时,程序就崩溃了(出现 Windows XP 崩溃消息……)

我正在尝试加载不带 mipmap 的 DDS 图像,图像格式为 DDS DXT1

我是否遗漏了一些包含文件,或者我做错了什么? 我从以下位置下载了包含的文件: http://sourceforge.net/projects/glew/files/glew/1.5.1/glew-1.5.1-win32.zip/download

我的 glew32.dll 与我的 .exe 位于同一文件夹中。

下面的代码只有我更改的部分才能加载 DDS 图像:

#pragma comment(lib, "glew32.lib")
#include <GL\glew.h>
#include <GL\gl.h>


...


typedef struct {
    GLuint dwSize;
    GLuint dwFlags;
    GLuint dwFourCC;
    GLuint dwRGBBitCount;
    GLuint dwRBitMask;
    GLuint dwGBitMask;
    GLuint dwBBitMask;
    GLuint dwABitMask;
} DDS_PIXELFORMAT;

typedef struct {
    GLuint dwMagic;
    GLuint dwSize;
    GLuint dwFlags;
    GLuint dwHeight;
    GLuint dwWidth;
    GLuint dwLinearSize;
    GLuint dwDepth;
    GLuint dwMipMapCount;
    GLuint dwReserved1[11];
    DDS_PIXELFORMAT ddpf;
    GLuint dwCaps;
    GLuint dwCaps2;
    GLuint dwCaps3;
    GLuint dwCaps4;
    GLuint dwReserved2;
} DDS_HEADER;

DDS_HEADER DDS_headers;


...


FILE *fp = fopen("test.dds", "rb");
fread(&DDS_headers, 1, sizeof(DDS_headers), fp);

img_width = DDS_headers.dwWidth;
img_height = DDS_headers.dwHeight;

maxsize = (img_width*img_height)/2;
unsigned char *imgdata = (unsigned char *)malloc(maxsize);

fread(imgdata, 1, maxsize, fp);

fclose(fp);

GLuint texID;

glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_PALETTE4_R5_G6_B5_OES, img_width, img_height, 0, maxsize, imgdata);
// NOTICE:
// Ive also tried with function:
// glCompressedTexImage2DARB();
// and internalformats: GL_COMPRESSED_RGB_S3TC_DXT1_EXT and all of the possible formats... its not a format error.

最佳答案

我记得在 glew 中弄乱了 DDS 加载器,我认为那里的 header 信息不正确。我一直无法让它正常工作。

最好的方法是使用 DDraw.h 中的 header 结构,这是我能够用于 DXT1、3 和 5 的结构,如果我没记错的话,它们是唯一可以在 OpenGL 中工作的结构。

    struct DDS_IMAGE_DATA
    {
           GLsizei  width;
            GLsizei  height;
            GLint    components;
            GLenum   format;
            int      numMipMaps;
            GLubyte *pixels;
    };

        DDS_IMAGE_DATA* CImage::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 )
            {   
                #if DEBUG
                char str[255];
                printf( str, "loadDDSTextureFile couldn't find, or failed to load \"%s\"", filename );
                #endif
                return NULL;
            }

            // Verify the file is a true .dds file
            fread( filecode, 1, 4, pFile );

            if( strncmp( filecode, "DDS ", 4 ) != 0 )
            {
                #if DEBUG
                char str[255];
                printf( str, "The file \"%s\" doesn't appear to be a valid .dds file!", filename );
                #endif
                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:

                #if DEBUG
                char str[255];
                printf( str, "The file \"%s\" doesn't appear to be compressed "
                    "using DXT1, DXT3, or DXT5!", filename );
                #endif
                return NULL;
            }

            //
            // How big will the buffer need to be to load all of the pixel data 
            // including mip-maps?
            //

            if( ddsd.dwLinearSize == 0 )
            {
                #if DEBUG
                printf("dwLinearSize is 0!");
                #endif
            }

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

void CImage::loadDDS(const char * szFilename, tTexture & texData)
{
    DDS_IMAGE_DATA *pDDSImageData = loadDDSTextureFile(szFilename);

    if( pDDSImageData != NULL )
    {
        texData.m_nHeight = pDDSImageData->height;
        texData.m_nWidth  = pDDSImageData->width;
        texData.m_nHeight = pDDSImageData->height;
        texData.m_eFormat = pDDSImageData->format;
        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 );
    }
}

这段特定的代码对我们尝试加载的 DDS 文件做了一些假设,首先是一个压缩文件,DXT1、3 或 5,并且 DDS 文件具有预先生成的 mipmaps 保存在它,因此我们不必自己生成它们。

我希望这能够帮助你,我花了一些时间才让它正常工作。如果此代码片段中有任何不清楚的地方,请告诉我,我会进一步帮助您。

关于c++ - 在 OpenGL 中加载 DDS DXT1,崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1715027/

相关文章:

winapi - 使用数组中的 RGB 数据重复填充窗口的最快方法是什么?

c++ - 使用静态变量和模板

OpenGL使用GL_TRIANGLE_FAN将圆放在椭圆内?

java - 如何将自定义字体与 Slick 的 UnicodeFont 类一起使用?

opengl - glGetUniformLocation 对于 USED 变量返回 -1,优化该死

c++ - DirectX 3(三)如何将信息呈现给显示器?

c++ - 运行时错误 : Assertion Failed, 列表迭代器不可取消引用

c++ - 不允许在类中使用关键字?

c++ - 使用来自另一个命名空间 C++ 的函数

c++ - 错误 LNK2001 : unresolved external symbol _IID_IDirectDraw2