create texture from image

Sickes

23-12-2007 23:19:42

Hi!

I want to create a texture for a plane using a System.Drawing.Image object.
How can i do that?

Thanks

GermanDZ

24-12-2007 11:38:25

Really easy to do:

At initialise:



DynTexture = TextureManager.Singleton.CreateManual("TEX_CUSTOM_DYN", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, TextureType.TEX_TYPE_2D, 2048, 1024, 0, PixelFormat.PF_BYTE_BGRA, 6/*TextureUsage.TU_DYNAMIC_WRITE_ONLY*/);
ResourcePtr rp2 = MaterialManager.Singleton.Create("MATERIAL_CUSTOM_DYN", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
MaterialPtr mat2 = (MaterialPtr)rp2;

TextureUnitState tState2 = mat2.GetTechnique(0).GetPass(0).CreateTextureUnitState("TEX_CUSTOM_DYN");
tState2.SetTextureAddressingMode(TextureUnitState.TextureAddressingMode.TAM_BORDER);





Any time you need change the texture:



public void ShowImageOnTexture(System.Drawing.Image img, Entity ent) {
ent.SetMaterialName("MATERIAL_CUSTOM_DYN");
MemoryStream ms = new MemoryStream();
img.Save(ms,System.Drawing.Imaging.ImageFormat.Bmp);
ReplaceTexture("DynTexture", ms.ToArray(), img.Width, img.Height);
}



You can search in wiki/forums the are some references too (I learn from that)

Sickes

24-12-2007 11:52:08

and what do the function "ReplaceTexture("DynTexture", ms.ToArray(), img.Width, img.Height); " ???

Thanks

GermanDZ

24-12-2007 13:28:36

Ooops.... I forgot to include that code:



public static void ReplaceTexture(HardwarePixelBuffer buffer, byte[] frame, int ancho, int alto)
{
unsafe
{

buffer.Lock(HardwareBuffer.LockOptions.HBL_NORMAL);
PixelBox pBox = buffer.CurrentLock;
pBox.format = PixelFormat.PF_BYTE_BGRA;

Marshal.Copy(frame, 0, pBox.data, (alto * ancho * 4));

buffer.Unlock();
}
}





REMEMBER: You must compile that as "unsafe"

Sickes

26-12-2007 12:11:35

two more questions:

1) Where are the Marshal class, i haven't it.

2) If the image is in gif format what i must change to work

Thks

Sickes

26-12-2007 12:19:22

ok i fix the point 1.

but the app crash with the next exception "Requested range extends past the end of the array." in the Marshal.Copy() method. ¿Any suggestion?

May be the format of the image, the example is for bmp and i use gif

GermanDZ

26-12-2007 13:12:46

I cant remember now, but the format is for Save, so don't care the source format (I use JPEG).

About the error "Requested range extends past the end of the array." seems to be a problem of sizes (width, height, bytes per pixel...).

Sickes

26-12-2007 13:39:58

i can't do it work.

i put all my code, with this code dont throw exception but the image dont load well.

Entity ePlanoReverso = mgr.CreateEntity("cartaReverso1", "planoReverso");

//creacion de la imagen
System.Drawing.Image img = null;
img = System.Drawing.Image.FromFile("reverse2.bmp");
System.IO.MemoryStream ms = new System.IO.MemoryStream();
img.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);

//Creacion de la textura de forma manual
TexturePtr DynTexture = TextureManager.Singleton.CreateManual(
"texReverso",
ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
TextureType.TEX_TYPE_2D,
(uint)img.Width,
(uint)img.Height,
0,
PixelFormat.PF_BYTE_BGRA,
(int)TextureUsage.TU_DEFAULT);

MaterialPtr _material = MaterialManager.Singleton.Create("matReverso", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
TextureUnitState tState2 = _material.GetTechnique(0).GetPass(0).CreateTextureUnitState("texReverso");
tState2.SetTextureAddressingMode(TextureUnitState.TextureAddressingMode.TAM_BORDER);

//asignamos la imagen a la textura
ePlanoReverso.SetMaterialName("matReverso");
unsafe
{
HardwarePixelBuffer buffer = DynTexture.GetBuffer();
buffer.Lock(HardwareBuffer.LockOptions.HBL_NORMAL);
PixelBox pBox = buffer.CurrentLock;
pBox.format = PixelFormat.PF_BYTE_BGRA;

int length = (img.Height * img.Width);
System.Runtime.InteropServices.Marshal.Copy(ms.ToArray(), 0, pBox.data, length);

buffer.Unlock();
}

GermanDZ

26-12-2007 23:48:59

I think the problem is the creation of the texture (TextureManager.Singleton.CreateManual("texReverso"....). Because textures must be "square" (widht = x^2, height=y^2) , so use 1024 x 512 or something like that.

The second problem is about the size of buffer. You must allocate 4 bytes per pixel, so you probably must use:


int length = (img.Height * img.Width) * 4;

Try it, and tell me.

Sickes

12-01-2008 12:10:02

nothing.

My image is about 200 x 300 pixels.

If i create a texture of 1024 x 512 and alocate 4 bytes per pixel the app throw exception in System.Runtime.InteropServices.Marshal.Copy(ms.ToArray(), 0, pBox.data, length);

Exception = "Requested range extends past the end of the array."

Sickes

12-01-2008 12:45:22

Debugging:

lengthBOX 219996 int
lengthMS 56946 int
length 219996 int

Why memoryStream is smaller than the pixelbox?

with the code:

//creacion de la imagen
System.Drawing.Image img = null;
img = System.Drawing.Image.FromFile("reverse2.bmp");
System.IO.MemoryStream ms = new System.IO.MemoryStream();
img.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);

//Creacion del material

ePlanoReverso.SetMaterialName("matReverso");
//Creacion de la textura de forma manual
TexturePtr DynTexture = TextureManager.Singleton.CreateManual(
"texReverso",
ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
TextureType.TEX_TYPE_2D,
(uint)img.Width,
(uint)img.Height,
0,
PixelFormat.PF_BYTE_BGRA,
(int)TextureUsage.TU_DEFAULT);

MaterialPtr _material = MaterialManager.Singleton.Create("matReverso", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
TextureUnitState tState2 = _material.GetTechnique(0).GetPass(0).CreateTextureUnitState("texReverso");
tState2.SetTextureAddressingMode(TextureUnitState.TextureAddressingMode.TAM_BORDER);

//asignamos la imagen a la textura
ePlanoReverso.SetMaterialName("matReverso");
unsafe
{
HardwarePixelBuffer buffer = DynTexture.GetBuffer();
buffer.Lock(HardwareBuffer.LockOptions.HBL_NORMAL);
PixelBox pBox = buffer.CurrentLock;
pBox.format = PixelFormat.PF_BYTE_BGRA;

int length = (img.Height * img.Width)*4;
int lengthMS = ms.ToArray().Length;
int lengthBOX = (int)pBox.GetConsecutiveSize();
System.Runtime.InteropServices.Marshal.Copy(ms.ToArray(), 0, pBox.data, length);
buffer.Unlock();
}

Sickes

12-01-2008 13:01:06

it must be a error with the pixelformats, but i don't know why