Render to texture: Creating GUI textures at runtime

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!
Post Reply
pin3
Posts: 108
Joined: Fri Oct 06, 2006 8:50 pm
Contact:

Render to texture: Creating GUI textures at runtime

Post by pin3 »

I want to create create the GUI widgets graphics in my project at run time. Basically I'm thinking of a texture that will get rendered on it several layers of graphics (widget corners, sides, text, etc.). I need a base texture with a user defined size. Problem is RenderTargetTexture can only have power of two size.
Can anyone suggest how can I create this 'base' texture on which I will render everything else?


Thanks in advance
pin3
Posts: 108
Joined: Fri Oct 06, 2006 8:50 pm
Contact:

Post by pin3 »

after some searching I found that I create a new texture of non-power by 2 size with driver->AddTexture().
Is there a way to copy a portion of the render target texture to my custom size texture?
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

You should lock the texture and copy the part you want. Please check the color formats to get the correct byte count!
pin3
Posts: 108
Joined: Fri Oct 06, 2006 8:50 pm
Contact:

Post by pin3 »

Thanks, works OK so far. One question: do I have to lock only the destination texture or both the source and the destination. i.e:

Code: Select all


Layer0 = driverRef.CreateRenderTargetTexture(new Dimension2D(256, 256));

//....
            // Create a blank texture 
            Texture Layer1 = driverRef.AddTexture(Size, ID, Layer0.ColorFormat);

            //Copy a portion of RTT 
            Layer1.Lock();
            Layer0.Lock();

            for (int x = 0; x < Size.Width; x++ )
            {
                for (int y = 0; y < Size.Height; y++)
                {
                    Layer1.SetPixel(x, y, Layer0.GetPixel(x, y));

                }

            }
            Layer1.Unlock();
            Layer0.Unlock();
Last edited by pin3 on Wed Feb 14, 2007 7:38 am, edited 3 times in total.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Yes, you need to lock both textures.
pin3
Posts: 108
Joined: Fri Oct 06, 2006 8:50 pm
Contact:

Post by pin3 »

Thanks.
pin3
Posts: 108
Joined: Fri Oct 06, 2006 8:50 pm
Contact:

Post by pin3 »

hybrid wrote:Please check the color formats to get the correct byte count!
Ok, I've run into a little problem so far I have been using the Software Renderer. It worked fine, the texture was copied the way I wanted. I just switched to Direact3D/OpenGL and im getting a protected memory read/write error when I run the code.

Is it because I'm not doing any color format checking?
You can see the code I'm using posted above.
Also it might be related with the problem mentioned here, I'm not sure:
http://irrlicht.sourceforge.net/phpBB2/ ... olorformat
Robert Y.
Posts: 212
Joined: Sun Jan 28, 2007 11:23 pm

Post by Robert Y. »

This is probably because of the color format. You can set it like this:

Code: Select all

video::ITexture* texture = driver->addTexture(core::dimension2d<s32>(256,256), "mytexture", video::ECF_A8R8G8B8);   
video::SColor *p = (video::SColor *)texture->lock();   
p[0] = video::SColor(255,0,255,0);        // set a value in the buffer
texture->unlock();  
Personally, I would use pointers like in this code, instead of things like getpixel.
pin3
Posts: 108
Joined: Fri Oct 06, 2006 8:50 pm
Contact:

Post by pin3 »

Robert Y. wrote:This is probably because of the color format. You can set it like this:

Code: Select all

video::ITexture* texture = driver->addTexture(core::dimension2d<s32>(256,256), "mytexture", video::ECF_A8R8G8B8);   
video::SColor *p = (video::SColor *)texture->lock();   
p[0] = video::SColor(255,0,255,0);        // set a value in the buffer
texture->unlock();  
Personally, I would use pointers like in this code, instead of things like getpixel.
Well, I'm using .Net which doesn't have pointers. I don't think I can achieve the same result without using get/SetPixel

Code: Select all

 Color[] Target = (Color[])Layer1.Lock();
 Color[] Source = (Color[])Layer0.Lock();
This obviously doesn't work, Lock() returns a IntPtr
cederron
Posts: 53
Joined: Thu Jul 13, 2006 11:35 pm

Post by cederron »

pin3 wrote:
Robert Y. wrote:This is probably because of the color format. You can set it like this:

Code: Select all

video::ITexture* texture = driver->addTexture(core::dimension2d<s32>(256,256), "mytexture", video::ECF_A8R8G8B8);   
video::SColor *p = (video::SColor *)texture->lock();   
p[0] = video::SColor(255,0,255,0);        // set a value in the buffer
texture->unlock();  
Personally, I would use pointers like in this code, instead of things like getpixel.
Well, I'm using .Net which doesn't have pointers. I don't think I can achieve the same result without using get/SetPixel

Code: Select all

 Color[] Target = (Color[])Layer1.Lock();
 Color[] Source = (Color[])Layer0.Lock();
This obviously doesn't work, Lock() returns a IntPtr

? why isn't it going to work ?
For sure c# has pointers.
you can unsafely( meaning in unsafe code) cast IntPtr to a pointer, like:

Code: Select all

IntPtr MPtr = tex.Lock();
unsafe
{
    Int16* sptr = (Int16*)MPtr;
    sptr += 20 = 1; //Now this works like a c++ pointer
}
tex,Unlock();
And of course this will be a hundred times faster, because you don't have to do pointer arithmetic to get/set the position of each pixel like GetPixel()/SetPixel() does.

Edit: well I'm a bit bored, so I will expand the example a bit :D
This will be to copy a texture, the destination texture must be created with same size as the source texture :

Code: Select all

IntPtr PtrSource = SourceTexture.Lock();
IntPtr PtrDest = DestTexture.Lock();

unsafe
{
    Int16* src = (Int16*)PtrSource; //In case textures are 16 bit, 
     Int16* dst = (Int16*)PtrDest;    //if not,  should be Int32*

    
        //Note that you can even make the bit below even faster, by using 
         // a function that copies the entire memory, without pointer
         // arithmetic, but this involves calling a native function and
         // out of the scope of this sample 

    for (int i = 0; i < texture_height; i++)
    {
         //Point to next row
          src += texture_width;
          dst += texture_width;
          //Copy this row
          for (int j = 0; j < texture_width; j++) 
          {
               dst[j] = src[j];
           }
     }
}

SourceTexture.Unlock();
DestTexture.Unlock();
This is actually c# code, though it may look like c++
Post Reply