1
\$\begingroup\$

[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.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

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.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Oct 10, 2012 at 10:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .