Another bug with texture under OpenGL

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
arras
Posts: 1622
Joined: Mon Apr 05, 2004 8:35 am
Location: Slovakia
Contact:

Another bug with texture under OpenGL

Post by arras »

Trere is something wrong with howe OpenGl renders texture. If texture data is manipulated once device is running under certain circumstances OpenGL fails to update texture.
I had observed this in such cases:

1. Node is using S3DVertex2TCoords, EMT_DETAIL_MAP material, second texture is loaded (detail map) and main texture is updated.

2. Node is using S3DVertex2TCoords, EMT_DETAIL_MAP material, no detail map texture is loaded and main lexture is updated.

3. Node is using S3DVertex2TCoords, standard material, second texture is loaded (in to material second texture layer like detail map) and main lexture is updated.

At firsth I tought that its problem of EMT_DETAIL_MAP with OpenGL but problem happen also with standard material when second texture is loaded. So only common thing is S3DVertex2TCoords used.

Everything works fine with DirectX.

Here is example code which shows problem. Program should change color of texture of node from red to blue and back.
Code is slightly modified 03.CustomSceneNode Example.
Works fine with DirectX, doesnt on OpenGL.

I dont know if it is realy bug in Irrlicht or it have something to do with OpenGL itself but in all cases code like this should work.

Code: Select all

// this code should change texture of node from red to blue and back
// works fine with DirectX but OpenGl fails

#include <irrlicht.h>
using namespace irr;

// custom scene node
// taken from Irrlicht 03.CustomSceneNode Example
// with exeption of vertices changed from S3DVertex to S3DVertex2TCoords type
// and color set to plain white for all vertices
class CSampleSceneNode : public scene::ISceneNode
{
	core::aabbox3d<f32> Box;
	video::S3DVertex2TCoords Vertices[4];
	video::SMaterial Material;

public:

	CSampleSceneNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id)
		: scene::ISceneNode(parent, mgr, id)
	{
		Material.Wireframe = false;
		Material.Lighting = false;

		Vertices[0] = video::S3DVertex2TCoords(0,0,10, 1,1,0, video::SColor(255,255,255,255), 0, 1);
		Vertices[1] = video::S3DVertex2TCoords(10,0,-10, 1,0,0, video::SColor(255,255,255,255), 1, 1);
		Vertices[2] = video::S3DVertex2TCoords(0,20,0, 0,1,1, video::SColor(255,255,255,255), 1, 0);
		Vertices[3] = video::S3DVertex2TCoords(-10,0,-10, 0,0,1, video::SColor(255,255,255,255), 0, 0);
		
		Box.reset(Vertices[0].Pos);
		for (s32 i=1; i<4; ++i)
			Box.addInternalPoint(Vertices[i].Pos);
	}
	
	virtual void OnRegisterSceneNode()
	{
		if (IsVisible)
			SceneManager->registerNodeForRendering(this);

		ISceneNode::OnRegisterSceneNode();
	}
	
	virtual void render()
	{
		u16 indices[] = {	0,2,3, 2,1,3, 1,0,3, 2,0,1	};
		video::IVideoDriver* driver = SceneManager->getVideoDriver();

		driver->setMaterial(Material);
		driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
		driver->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 4);
	}
	
	virtual const core::aabbox3d<f32>& getBoundingBox() const
	{
		return Box;
	}

	virtual u32 getMaterialCount()
	{
		return 1;
	}

	virtual video::SMaterial& getMaterial(u32 i)
	{
		return Material;
	}	
};

int main()
{
	IrrlichtDevice *device =
		createDevice(
        video::EDT_OPENGL, 
        //video::EDT_DIRECT3D9,
        core::dimension2d<s32>(800, 600), 32, false, false, false);
		
	if (device == 0) return 1;
    
	video::IVideoDriver* driver = device->getVideoDriver();
	scene::ISceneManager* smgr = device->getSceneManager();
	
	// camera
	smgr->addCameraSceneNode(0, core::vector3df(0,-40,0), core::vector3df(0,0,0));
    
    // create node
    CSampleSceneNode *myNode = 
		new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666);
	myNode->drop();
	
	// create texture for node
	// turn off mip maps so we dont have to update them each time texture is updated
	driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
    video::ITexture* texture = driver->addTexture(core::dimension2d<s32>(64, 64), "cubetexture", video::ECF_A8R8G8B8);
    myNode->setMaterialTexture(0, texture);
    
    // load detail map texture
    // detailmap3.jpg is from Irrlicht-1.3/media folder
    // change path to your own
    myNode->setMaterialTexture(1, driver->getTexture("your path/detailmap3.jpg"));
    
    // change material to detail map
    myNode->setMaterialType(video::EMT_DETAIL_MAP);
    
    // set color for texture
    video::SColor color(255,255,0,0);
    // update texture with color
    s32* p = (s32*)texture->lock();
    for(s32 i=0; i<64*64; i++)
        p[i] = color.color;
    texture->unlock();
    
    // animate
    scene::ISceneNodeAnimator* anim = 
		smgr->createRotationAnimator(core::vector3df(0.8f, 0, 0.8f));
	myNode->addAnimator(anim);
	anim->drop();
    
    // set some color variables
	f32 r = 255.0f; // red
	f32 rs = -0.001f; // how fast to change red
	f32 b = 0.0f; // blue
	f32 bs = 0.001f; // how fast to change blue
	
	while(device->run())
    {
        driver->beginScene(true, true, video::SColor(255,100,101,140));
        
        // change texture color from red to blue and back
        
        if(r >= 255.0f) rs = -0.1f;
        if(r <= 0.0f) rs = 0.1f;
        
        if(b >= 255.0f) bs = -0.1f;
        if(b <= 0.0f) bs = 0.1f;
        
        r += rs;
        b += bs;
        
        color.setRed((u32)r);
        color.setBlue((u32)b);
        
        // update rexture with new color
        s32* p = (s32*)texture->lock();
        for(s32 i=0; i<64*64; i++)
            p[i] = color.color;
        texture->unlock();
        
		smgr->drawAll();

		driver->endScene();
    }
    device->drop();
    
    return 0;
}
arras
Posts: 1622
Joined: Mon Apr 05, 2004 8:35 am
Location: Slovakia
Contact:

Post by arras »

It have to be some bug since if I change textures ...that is if I manipulate second texture instead of firsth then all works fine and OpenGL driver update texture properly.
Delight
Posts: 42
Joined: Tue Jul 05, 2005 3:16 pm
Location: Muenster, Germany

Post by Delight »

I got the same problem, even with DirectX and S3DVertex... The texture isn't updated correctly, only the pixels in a certain radius around the camera are shown correctly....

My workaround looks like this: Modify the texture, save it to a file, delete the texture from the driver and load the saved file. But I don't know how decelerating this is...
Spintz
Posts: 1688
Joined: Thu Nov 04, 2004 3:25 pm

Post by Spintz »

After changing a texture, you need to regenerateMipMapLevels. Should solve all your problems.

Remember, mipmaps are generated when a texture is loaded. If you change mip level 0, or the base texture, you need to propagate that change throughout the mipLevels, or simpley regenerateMipMapLevels <--- actual function for ITexture.
Image
Post Reply