Miyagi - render control to bitmap

kubatp

24-03-2013 16:54:51

Hi all,
does anyone know if it is possible to render control of Miagyi GUI to bitmap? I simply have one control I would like to render to bitmap and use this bitmap somewhere else (not in Miyagi GUI). Is it possible?

Thank you very much

smiley80

26-03-2013 15:03:14

You can render a gui to a texture and then copy that to a bitmap:
using (TexturePtr tex = TextureManager.Singleton.CreateManual(
"RTT",
ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
TextureType.TEX_TYPE_2D,
800,
600,
0,
PixelFormat.PF_A8R8G8B8,
(int)TextureUsage.TU_RENDERTARGET))
{
using (var buf = tex.GetBuffer())
{
using (var renderTexture = buf.GetRenderTarget())
{
GUI gui = miyagiSystem.GUIManager.GUIs[0];
gui.SpriteRenderer.Viewport = new MogreViewport(renderTexture.AddViewport(camera));
renderTexture.GetViewport(0).SetClearEveryFrame(true);
renderTexture.Update();

byte[] bytes = new byte[tex.Width * tex.Height * 4];
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try
{
PixelBox box = new PixelBox(tex.Width, tex.Height, 1, tex.Format, handle.AddrOfPinnedObject());
buf.BlitToMemory(box);

System.Drawing.Bitmap bit = new System.Drawing.Bitmap(
(int)tex.Width,
(int)tex.Height,
(int)tex.Width * 4,
System.Drawing.Imaging.PixelFormat.Format32bppArgb,
box.data);

...do stuff with the bitmap
}
finally
{
handle.Free();
}
}
}
}

kubatp

27-03-2013 20:58:53

Hi Smiley,
thank you very much for an answer. I cannot try it now, because the code is currently not buildable, but when I try it, I will write how it went.
Thank you again.

kubatp

12-04-2013 14:07:57

Hi Smiley,
I finally had time to try it. Thank you for the code, it works and it really does a screenshot of the screen. I might use it in my application, but this is not exactly what I meant. I am sorry if I didn't express myself correctly, but I want to render just the control OR at least the material.

What I try to achieve : I want to use HTMLControl where I can add images of my buttons (miyagi buttons), etc. I have miyagi materials' textures in one atlas texture, so I cannot add this image directly to the html source (because it would display whole image). Of course, I can manually crop the atlas and get just the part I need, but I would rather find a way how to use miyagi controls or materials to give me the image. Otherwise it is kind of code duplication.

When I use your code for that, there might be problem, when you have a control with non-rectangular texture (i.e. even you crop the texture from screenshot) there will be other parts of the scene (behind the control)

I hope it is more clear what I want to achieve:)

Is there a way to do this?

Thank you very much

smiley80

14-04-2013 12:17:04

This will only copy the control to the bitmap:
private System.Drawing.Bitmap ControlToBitmap(Control c, Camera cam)
{
var oldview = c.GUI.SpriteRenderer.Viewport;

uint width = (uint)c.Width;
uint height = (uint)c.Height;

var loc = c.GetLocationInViewport();
uint left = (uint)loc.X;
uint top = (uint)loc.Y;
uint right = left + width;
uint bottom = top + height;

using (var tex = TextureManager.Singleton.CreateManual(
"RTT",
ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
TextureType.TEX_TYPE_2D,
(uint)oldview.Bounds.Width,
(uint)oldview.Bounds.Height,
0,
PixelFormat.PF_A8R8G8B8,
(int)TextureUsage.TU_RENDERTARGET))
{
using (var buf = tex.GetBuffer())
{
using (var renderTexture = buf.GetRenderTarget())
{
c.GUI.SpriteRenderer.Viewport = new MogreViewport(renderTexture.AddViewport(cam));

renderTexture.GetViewport(0).SetClearEveryFrame(true);
renderTexture.Update();

c.GUI.SpriteRenderer.Viewport = oldview;

var bytes = new byte[width * height * 4];
var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try
{
var box = new PixelBox(width, height, 1, tex.Format, handle.AddrOfPinnedObject());
buf.BlitToMemory(new Box(left, top, right, bottom), box);

using (var bit = new System.Drawing.Bitmap(
(int)width,
(int)height,
(int)width * 4,
System.Drawing.Imaging.PixelFormat.Format32bppArgb,
box.data))
{
return (System.Drawing.Bitmap)bit.Clone();
}
}
finally
{
handle.Free();
}
}
}
}
}


If the control isn't fully opaque, make sure the camera doesn't show the scene.

kubatp

16-04-2013 17:48:58

Hi Smiley,
thank you very much!

kubatp

24-06-2013 12:58:17

Hi Smiley,
can you please tell me how to modify the code below to have screenshot including gui and modalgui as well? I have been playing around with it, but I am not able to get both.
Thank you very much.

kubatp

27-06-2013 21:35:20

Does anyone know how to do that?

smiley80

06-07-2013 22:02:02

You have to disable 'SetClearEveryFrame' for the render texture viewport, and then render the GUIs one after another:

private System.Drawing.Bitmap GUIsToBitmap(IEnumerable<GUI> guis, Camera cam)
{
uint width = (uint)cam.Viewport.ActualWidth;
uint height = (uint)cam.Viewport.ActualHeight;

using (var tex = TextureManager.Singleton.CreateManual(
"RTT",
ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
TextureType.TEX_TYPE_2D,
width,
height,
0,
PixelFormat.PF_A8R8G8B8,
(int)TextureUsage.TU_RENDERTARGET))
{
using (var buf = tex.GetBuffer())
{
using (var renderTexture = buf.GetRenderTarget())
{
var vp = renderTexture.AddViewport(cam);
vp.SetClearEveryFrame(false);

foreach (var gui in guis)
{
var oldview = gui.SpriteRenderer.Viewport;
gui.SpriteRenderer.Viewport = new MogreViewport(vp);

renderTexture.Update();

gui.SpriteRenderer.Viewport = oldview;
}

var bytes = new byte[width * height * 4];
var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
try
{
var box = new PixelBox(width, height, 1, tex.Format, handle.AddrOfPinnedObject());
buf.BlitToMemory(new Box(0, 0, width, height), box);

using (var bit = new System.Drawing.Bitmap(
(int)width,
(int)height,
(int)width * 4,
System.Drawing.Imaging.PixelFormat.Format32bppArgb,
box.data))
{
return (System.Drawing.Bitmap)bit.Clone();
}
}
finally
{
handle.Free();
}
}
}
}
}

kubatp

07-07-2013 19:33:29

Hi Smiley,
thank you, this really makes screenshot of all guis. But it doesn't show the 3D scene what it did before. Do I have to add something more?