Sign in to follow this  
Jan Harms

Problem loading compressed DDS without pre-generated mipmaps

Recommended Posts

Hi everyone, 

 

I am currently working at rendering bitmap fonts. For that I want to load dds textures. Now the program I use creates these dds files without any mipmaps, but the dds-loader I used before for some model textures seems to only work with pre-generated mipmaps.  

 

This is my loader:

 

 

 

    //    structures for reading and information variables
    char magic[4];
    unsigned char header[124];
    unsigned int width, height, linearSize, mipMapCount, fourCC;
    unsigned char* dataBuffer;
    unsigned int bufferSize;


    fstream file(path, ios::in|ios::binary);


    //    read magic and header
    if (!file.read((char*)magic, sizeof(magic))){
        cerr<< "File " << path << " not found!"<<endl;
        return false;
    }


    if (magic[0]!='D' || magic[1]!='D' || magic[2]!='S' || magic[3]!=' '){
        cerr<< "File does not comply with dds file format!"<<endl;
        return false;
    }


    if (!file.read((char*)header, sizeof(header))){
        cerr<< "Not able to read file information!"<<endl;
        return false;
    }


    //    derive information from header
    height = *(int*)&(header[8]);
    width = *(int*)&(header[12]);
    linearSize = *(int*)&(header[16]);
    mipMapCount = *(int*)&(header[24]);
    fourCC = *(int*)&(header[80]);


    //    determine dataBuffer size
    bufferSize = mipMapCount > 1 ? linearSize * 2 : linearSize;
    dataBuffer = new unsigned char [bufferSize*2];


    //    read data and close file
    if (file.read((char*)dataBuffer, bufferSize/1.5))
        cout<<"Loading texture "<<path<<" successful"<<endl;
    else{
        cerr<<"Data of file "<<path<<" corrupted"<<endl;
        return false;
    }


    file.close();


    //    check pixel format
    unsigned int format;


    switch(fourCC){
    case FOURCC_DXT1:
        format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
        break;
    case FOURCC_DXT3:
        format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
        break;
    case FOURCC_DXT5:
        format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
        break;
    default:
        cerr << "Compression type not supported or corrupted!" << endl;
        return false;
    }


    glGenTextures(1, &ID);


    glBindTexture(GL_TEXTURE_2D, ID);
    glPixelStorei(GL_UNPACK_ALIGNMENT,1);
    //glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAX_LEVEL,0);


    unsigned int blockSize = (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;
    unsigned int offset = 0;


    /* load the mipmaps */
    for (unsigned int level = 0; level < mipMapCount && (width || height); ++level) {
        unsigned int size = ((width+3)/4)*((height+3)/4)*blockSize;
        glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height,
                            0, size, dataBuffer + offset);


        offset += size;
        width  /= 2;
        height /= 2;
    }




    textureType = DDS_TEXTURE;


    return true;
 

Now if there are no mipmaps, mipMapCount is equal to 0, and the loop does not start. I tried to set the glTexParameter and increased mipMapCount manually, but didn't really work(it showed only the "d" of "Hello World!" for some reason XD). So I'm kinda stuck now. 

 

I think somewhere I have to manually create the mipmaps with glGenerateMipmap but I'm not sure where and in what why the loop still works then.

 

I hope someone can help me out here. 
 

Thanks in advance. 

Share this post


Link to post
Share on other sites

Well, glCompressedTexImage2D has to get called one way or another.  Try this:

 

for (unsigned int level = 0; level < (mipMapCount+1) && (width || height); ++level) {

 

This way, the top level mipmap level always gets set.  Textures that don't use/need mipmaps still need level 0 accounted for.  It appears that you were setting every mip level except for the last.  Keep in mind that the mipMapCount represents the mipmap levels "besides" the top level, which is always 0.  Try this and make sure it works. ^^

 

Shogun.

Share this post


Link to post
Share on other sites

Thanks for your answer. 

 

Well this kind of works. Somehow only a few of my chars get drawn then, others are just invisible/(black if no transparency) so the texture is not loaded correctly there. 

Share this post


Link to post
Share on other sites

Okay I solved it. 

 

In case the texture had no pre-generated mipmaps, the data was only read partly because the bufferSize was devided by 1.5, which is needed for the case with mipmaps.

The solution was therefore to replace this code

 

 

 

//    determine dataBuffer size
    bufferSize = mipMapCount > 1 ? linearSize * 2 : linearSize;
    dataBuffer = new unsigned char [bufferSize*2];


    //    read data and close file
    if (file.read((char*)dataBuffer, bufferSize/1.5))
        cout<<"Loading texture "<<path<<" successful"<<endl;
 

by this code

 

 

 

//    determine dataBuffer size
    bufferSize = mipMapCount > 1 ? linearSize * 2 : linearSize * 1.5;
    dataBuffer = new unsigned char [bufferSize*2];


    //    read data and close file
    if (file.read((char*)dataBuffer, bufferSize/1.5))
        cout<<"Loading texture "<<path<<" successful"<<endl;
 

Thanks for your help.

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