Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

[EDIT: FIXED - Calling setting texture max level fixed that]

I'm optimizing my game and I've just implemented compressed (DXTn) texture loading in OpenGL. I've worked my way removing bugs but I can't figure out this one: objects w/ DXTn + mipmapped textures are not being rendered. It's not like they are appearing with a flat color, they just don't appear at all. DXTn textured objs render and mipmapped non-compressed textures render just fine.

The texture in question is 256x256 I generate the mips all the way down 4x4, i.e 1 block. I've checked on gDebugger and it display all the levels (7) just fine. I'm using GL_LINEAR_MIPMAP_NEAREST for min filter and GL_LINEAR for mag one.

The texture is being compressed and mipmaps being created offline with Paint.NET tool using super sampling method. (I also tried bilinear just in case)

Source follow:

[SNIPPET 1: Loading DDS into sys memory + Initializing Object]

    // Read header
    DDSHeader header;
    file.read(reinterpret_cast<char*>(&header), sizeof(DDSHeader));
    uint pos = static_cast<uint>(file.tellg());
    file.seekg(0, std::ios_base::end);
    uint dataSizeInBytes = static_cast<uint>(file.tellg()) - pos;
    file.seekg(pos, std::ios_base::beg);

    // Read file data
    mData = new unsigned char[dataSizeInBytes];
    file.read(reinterpret_cast<char*>(mData), dataSizeInBytes);

    file.close();

    mMipmapCount = header.mipmapcount;
    mHeight = header.height;
    mWidth = header.width;
    mCompressionType = header.pf.fourCC;

    // Only support files divisible by 4 (for compression blocks algorithms)
    massert(mWidth % 4 == 0 && mHeight % 4 == 0);

    massert(mCompressionType == NO_COMPRESSION || mCompressionType == COMPRESSION_DXT1 || mCompressionType == COMPRESSION_DXT3 ||
            mCompressionType == COMPRESSION_DXT5);

    // Allow textures up to 65536x65536
    massert(header.mipmapcount <= MAX_MIPMAP_LEVELS);

    mTextureFilter = TextureFilter::LINEAR;
    if (mMipmapCount > 0)
    {
        mMipmapFilter = MipmapFilter::NEAREST;
    }
    else
    {
        mMipmapFilter = MipmapFilter::NO_MIPMAP;
    }

    mBitsPerPixel = header.pf.bitcount;
    if (mCompressionType == NO_COMPRESSION)
    {
        if (header.pf.flags & DDPF_ALPHAPIXELS)
        {
            // The only format supported w/ alpha is A8R8G8B8
            massert(header.pf.amask == 0xFF000000 && header.pf.rmask == 0xFF0000 &&
                header.pf.gmask == 0xFF00 && header.pf.bmask == 0xFF);

            mInternalFormat = GL_RGBA8;
            mFormat = GL_BGRA;
            mDataType = GL_UNSIGNED_BYTE;
        }
        else
        {
            massert(header.pf.rmask == 0xFF0000 && header.pf.gmask == 0xFF00 && header.pf.bmask == 0xFF);

            mInternalFormat = GL_RGB8;
            mFormat = GL_BGR;
            mDataType = GL_UNSIGNED_BYTE;
        }
    }
    else
    {
        uint blockSizeInBytes = 16;
        switch (mCompressionType)
        {
            case COMPRESSION_DXT1:
                blockSizeInBytes = 8;
                if (header.pf.flags & DDPF_ALPHAPIXELS)
                {
                    mInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
                }
                else
                {
                    mInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
                }
                break;

            case COMPRESSION_DXT3:
                mInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
                break;

            case COMPRESSION_DXT5:
                mInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
                break;

            default:
                // Not Supported (DXT2, DXT4 or any compression format)
                massert(false);         
        }
    }

[SNIPPET 2: Uploading into video memory]

    massert(mData != NULL);
    glGenTextures(1, &mHandle);
    massert(mHandle!=0);    
    glBindTexture(GL_TEXTURE_2D, mHandle);
    commitFiltering();

    uint offset = 0;
    Renderer* renderer = Renderer::getInstance();

    switch (mInternalFormat)
    {
        case GL_RGB:
        case GL_RGBA:
        case GL_RGB8:
        case GL_RGBA8:
            for (uint i = 0; i < mMipmapCount + 1; ++i)
            {
                uint width = std::max(1U, mWidth >> i);
                uint height = std::max(1U, mHeight >> i);
                glTexImage2D(GL_TEXTURE_2D, i, mInternalFormat, width, height, mHasBorder, mFormat, mDataType, &mData[offset]);
                offset += width * height * (mBitsPerPixel / 8);
            }
            break;

        case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
        case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
        case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
        case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:          
        {
            uint blockSize = 16;
            if (mInternalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || mInternalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
            {
                blockSize = 8;
            }

            uint width = mWidth;
            uint height = mHeight;
            for (uint i = 0; i < mMipmapCount + 1; ++i)
            {
                uint nBlocks = ((width + 3) / 4) * ((height + 3) / 4);

                // Only POT textures allowed for mipmapping
                massert(width % 4 == 0 && height % 4 == 0);
                glCompressedTexImage2D(GL_TEXTURE_2D, i, mInternalFormat, width, height, mHasBorder, nBlocks * blockSize, &mData[offset]);
                offset += nBlocks * blockSize;

                if (width <= 4 && height <= 4)
                {
                    break;
                }

                width = std::max(4U, width / 2);
                height = std::max(4U, height / 2); 
            }
            break;
        }
        default:
            // Not Supported
            massert(false);
    }

Also I don't understand the "+3" in the block size computation but looking for a solution for my problema I've encountered people defining it as that. I guess it won't make a differente for POT textures but I put just in case.

Thanks.

share|improve this question
add comment

1 Answer

up vote 0 down vote accepted

You're missing the texture parameters, or you have omitted that part.

massert(mData != NULL);
glGenTextures(1, &mHandle);
massert(mHandle!=0);    
glBindTexture(GL_TEXTURE_2D, mHandle);

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, (ddsd.mipMapLevels == 0) ? 0 : ddsd.mipMapLevels - 1);

The rest of your code looks similar to my own DDS texture loader for OpenGL, which loads textures correctly.

share|improve this answer
    
I was setting the filtering but not texture max level. When I did set max level to the number of mipmaps (7) it worked! I guess OpenGL was trying for some reason to get a level above that which doesn't make sense since it would map to a 1x1 pixel and the texel portion is much greater than that. –  felipedrl Oct 10 '12 at 10:49
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.