OpenGL compatibility

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Robert Y.
Posts: 212
Joined: Sun Jan 28, 2007 11:23 pm

Re: OpenGL compatibility

Post by Robert Y. »

Hi guys,

ran into the same old problem recently: even 5 years later a lot of computers still have OpenGl 1.1 installed, so Irrlicht programs with OpenGL don't
run out-of-the-box.
But now the good news: I was able to fix the opengl 1.1 texture problem with some simple adjustments in COpenGLTexture::copyTexture(bool newTexture) and void COpenGLTexture::getImageData(IImage* image). Well, at least this works for Irrlicht 1.3, don't know if the newer Irrlicht versions have many changes in this code.

Here is the code, it would be great if this could be integrated in the newer Irrlicht versions, making it a lot more compatible.:

Code: Select all

 
void COpenGLTexture::getImageData(IImage* image)
{
    if (!image)
    {
        os::Printer::log("No image for OpenGL texture.", ELL_ERROR);
        return;
    }
 
    ImageSize = image->getDimension();
    OriginalSize = ImageSize;
    
    if (atof((c8*)glGetString(GL_VERSION)) < 1.1999)                // fix for opengl 1.1
    {
            core::dimension2d<s32> nImageSize;
            nImageSize.Width = getTextureSizeFromSurfaceSize(ImageSize.Width);
            nImageSize.Height = getTextureSizeFromSurfaceSize(ImageSize.Height);
        
            if (!nImageSize.Width || !nImageSize.Height || !ImageSize.Width || !ImageSize.Height)
            {
                os::Printer::log("Could not create OpenGL Texture.", ELL_ERROR);
                return;
            }
        
            ImageData = new s32[nImageSize.Width * nImageSize.Height];
                    
            if (nImageSize == ImageSize)
            {
                if (image->getColorFormat() == ECF_A8R8G8B8)
                {
                    s32 s = nImageSize.Width * nImageSize.Height;
                    s32 *t = (s32*)image->lock();
                    for (s32 i=0; i<s; ++i) ImageData[i] = t[i];
                    image->unlock();
                }
                else
                {
                    // slow converting
                    for (s32 x=0; x<ImageSize.Width; ++x)
                        for (s32 y=0; y<ImageSize.Height; ++y)
                            ImageData[y*nImageSize.Width + x] = image->getPixel(x,y).color;
                }
            }
            else
            {
                // scale texture
        
                s32* source = (s32*)image->lock();
        
                f32 sourceXStep = (f32)ImageSize.Width / (f32)nImageSize.Width;
                f32 sourceYStep = (f32)ImageSize.Height / (f32)nImageSize.Height;
                f32 sy;
        
                if (image->getColorFormat() == ECF_A8R8G8B8)
                {
                    // copy texture scaling
                    for (s32 x=0; x<nImageSize.Width; ++x)
                    {
                        sy = 0.0f;
        
                        for (s32 y=0; y<nImageSize.Height; ++y)
                        {
                            ImageData[(s32)(y*nImageSize.Width + x)] = source[(s32)(((s32)sy)*ImageSize.Width + x*sourceXStep)];
                            sy+=sourceYStep;
                        }
                    }
                }
                else
                {
                    // convert texture scaling, slow
                    for (s32 x=0; x<nImageSize.Width; ++x)
                    {
                        sy = 0.0f;
        
                        for (s32 y=0; y<nImageSize.Height; ++y)
                        {
                            ImageData[(s32)(y*nImageSize.Width + x)] = 
                                image->getPixel((s32)(x*sourceXStep), (s32)sy).color;
        
                            sy+=sourceYStep;
                        }
                    }
                }
            }       
        
            ImageSize = nImageSize;
            return;             
    }
 
    if ( !ImageSize.Width || !ImageSize.Height)
    {
        os::Printer::log("Invalid size of image for OpenGL Texture.", ELL_ERROR);
        return;
    }
 
    core::dimension2d<s32> nImageSize;
    if (Driver && Driver->queryFeature(EVDF_TEXTURE_NPOT))
        nImageSize=ImageSize;
    else
    {
        nImageSize.Width = getTextureSizeFromSurfaceSize(ImageSize.Width);
        nImageSize.Height = getTextureSizeFromSurfaceSize(ImageSize.Height);
    }
    SurfaceHasSameSize=ImageSize==nImageSize;
 
    s32 bpp=0;
    if (image->getColorFormat()==ECF_R8G8B8)
    {
        bpp=4;
        ColorFormat = ECF_A8R8G8B8;
    }
    else
    {
        bpp=image->getBytesPerPixel();
        ColorFormat = image->getColorFormat();
    }
 
    Pitch = nImageSize.Width*bpp;
    ImageData = new s32[Pitch * nImageSize.Height];
 
    if (nImageSize == ImageSize)
    {
        void* source = image->lock();
        if (image->getColorFormat()==ECF_R8G8B8)
            CColorConverter::convert_R8G8B8toA8R8G8B8(source,ImageSize.Width*ImageSize.Height,ImageData);
        else
            memcpy(ImageData,source,Pitch*nImageSize.Height);
    }
    else
    {
        u8* source = (u8*)image->lock();
        // scale texture
 
        f32 sourceXStep = (f32)ImageSize.Width / (f32)nImageSize.Width;
        f32 sourceYStep = (f32)ImageSize.Height / (f32)nImageSize.Height;
        f32 sx,sy;
 
        // copy texture scaling
        sy = 0.0f;
        for (s32 y=0; y<nImageSize.Height; ++y)
        {
            sx = 0.0f;
            for (s32 x=0; x<nImageSize.Width; ++x)
            {
                s32 i=((s32)(((s32)sy)*ImageSize.Width + sx));
                if (image->getColorFormat()==ECF_R8G8B8)
                {
                    i*=3;
                    ((s32*)ImageData)[y*nImageSize.Width + x]=SColor(255,source[i],source[i+1],source[i+2]).color;
                }
                else
                    memcpy(&ImageData[(y*nImageSize.Width + x)*bpp],&source[i*bpp],bpp);
                sx+=sourceXStep;
            }
            sy+=sourceYStep;
        }
    }
    image->unlock();
    ImageSize = nImageSize;
}
 
 
void COpenGLTexture::copyTexture(bool newTexture)
{
    if (atof((c8*)glGetString(GL_VERSION)) < 1.1999)        //fix for opengl 1.1
    {
        glBindTexture(GL_TEXTURE_2D, TextureName);  
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ImageSize.Width, ImageSize.Height, 0, GL_BGRA_EXT , GL_UNSIGNED_BYTE, ImageData);   
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        if (HasMipMaps)
        {
            s32 ret = 0;        
            #ifndef DISABLE_MIPMAPPING
            ret = gluBuild2DMipmaps(GL_TEXTURE_2D, 4, ImageSize.Width, ImageSize.Height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, ImageData);
            #endif
 
            if (ret)
            {
                #ifndef DISABLE_MIPMAPPING
                os::Printer::log("Could not create OpenGL texture mip maps.", (c8*)gluErrorString(ret), ELL_ERROR);
                #else
                os::Printer::log("Did not create OpenGL texture mip maps.", ELL_ERROR);
                #endif
            }
            else
            {
                glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
                glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
            }
        }   
        return;
    }
    glBindTexture(GL_TEXTURE_2D, TextureName);
    if (Driver->testGLError())
        os::Printer::log("Could not bind Texture", ELL_ERROR);
 
    switch (ColorFormat)
    {
        case ECF_A1R5G5B5:
            InternalFormat=GL_RGBA;
            PixelFormat=GL_BGRA_EXT;
            PixelType=GL_UNSIGNED_SHORT_1_5_5_5_REV;
            break;
        case ECF_R5G6B5:
            InternalFormat=GL_RGB;
            PixelFormat=GL_RGB;
            PixelType=GL_UNSIGNED_SHORT_5_6_5;
            break;
        case ECF_R8G8B8:
            InternalFormat=GL_RGB8;
            PixelFormat=GL_RGB;
            PixelType=GL_UNSIGNED_BYTE;
            break;
        case ECF_A8R8G8B8:
            InternalFormat=GL_RGBA;
            PixelFormat=GL_BGRA_EXT;
            PixelType=GL_UNSIGNED_INT_8_8_8_8_REV;
            break;
        default:
            os::Printer::log("Unsupported texture format", ELL_ERROR);
            break;
    }
 
    #ifndef DISABLE_MIPMAPPING
    if (HasMipMaps && Driver && Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE))
    {
        // automatically generate and update mipmaps
        glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
        AutomaticMipmapUpdate=true;
    }
    else
    {
        AutomaticMipmapUpdate=false;
        regenerateMipMapLevels();
    }
    if (HasMipMaps) // might have changed in regenerateMipMapLevels
    {
        // enable bilinear mipmap filter
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    }
    else
    #else
        HasMipMaps=false;
        os::Printer::log("Did not create OpenGL texture mip maps.", ELL_ERROR);
    #endif
    {
        // enable bilinear filter without mipmaps
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    }
    if (newTexture)
        glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, ImageSize.Width,
            ImageSize.Height, 0, PixelFormat, PixelType, ImageData);
    else
        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ImageSize.Width,
            ImageSize.Height, PixelFormat, PixelType, ImageData);
 
    if (Driver->testGLError())
        os::Printer::log("Could not glTexImage2D", ELL_ERROR);
} 
 
 
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: OpenGL compatibility

Post by hybrid »

Well, this can, for sure, not be integrated. It looks like a major code duplication without reasons. Maybe try to explain which parts you found to be problematic, so we can introduce some gentle modifications instead.
Robert Y.
Posts: 212
Joined: Sun Jan 28, 2007 11:23 pm

Re: OpenGL compatibility

Post by Robert Y. »

Hi Hybrid,

Thanks for your quick reply!
The changes are actually very simple. As I knew that OpenGL 1.1 worked in Irrlicht 1.0, I just copied the original code of Irrlicht 1.0, and run that if OpenGL version is 1.1.
So the functions were changed like this:

Code: Select all

 
if (atof((c8*)glGetString(GL_VERSION)) < 1.1999)                // fix for opengl 1.1
{
       ... old Irrlicht 1.0 code
       return;
}
... original Irrlicht 1.3 code
 
My knowledge on OpenGL programming is about zero, so I don't know how to optimize this code, but changing the two functions like this definitely solves the compatibility
problems with OpenGl 1.1 encountered by me. I hope this will help other users too. Textures on 3d models, draw2dimage and fonts work like a charm again.

Best regards, Robert
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: OpenGL compatibility

Post by hybrid »

Ah, ok. So I will have to work through the changes. Thansk for testing this, as I wouldn't know where to find a machine with such old drivers ;-)
CuteAlien
Admin
Posts: 9720
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: OpenGL compatibility

Post by CuteAlien »

Hm, so the problem is with Irrlicht 1.3, so just wondering... can you try working with a newer Irrlicht? I mean this is really, really old...
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Robert Y.
Posts: 212
Joined: Sun Jan 28, 2007 11:23 pm

Re: OpenGL compatibility

Post by Robert Y. »

Hi Hybrid,

actually, I have a rather recent Asus EeePc with OpenGL 1.1! Will keep it that way, for testing purposes.

@CuteAlien:
I modified irrlicht 1.3, it does everything I need right now. Using a newer version would mean lots of rewriting, for the same result. In my case it's important, that
the program always works, no matter what drivers are installed. I don't use fancy stuff like shaders etc, but I hate it when you have to use an installer or that you
get errors because the drivers aren't the newest. Right now, my program is standalone, it tries several devices, and if dx8, dx9 and openGL don't work, it uses Burning renderer.
The only obstacle was OpenGl 1.1, which wasn't supported by irrlicht, forcing the program to Burning. But now OGL 1.1 works, so no matter what system, my exe will work fine. Irrlicht rules!
The only advantage I see right now of a newer version, is the use of 32 indices. It als would be great if Burning Renderer could handle transparent models, but I don't
thinks it implemented in the newest Irrlicht? And is the newest Irrlicht still compatible with dx8 and dx9?
CuteAlien
Admin
Posts: 9720
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: OpenGL compatibility

Post by CuteAlien »

Dx8 and Dx9 are still supported. Admittably I also still haven't updated a game that used a pre 1.3 version, so can't really tell how much work updating would be (I'll do it some day...). But I guess it's not even that much - a few interfaces have minor changes, but it's still basically the same engine. If it's a project on which you still code then it's probably useful to update as there have been lots of bugfixes over the years.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Post Reply