Objects won't render when Texture Compression + Mipmapping is Enabled

Posted by felipedrl on Game Development See other posts from Game Development or by felipedrl
Published on 2012-10-09T23:31:18Z Indexed on 2012/10/10 3:54 UTC
Read the original article Hit count: 240

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.

© Game Development or respective owner

Related posts about opengl

Related posts about textures