Converting Bitmaps to textures

There are several ways how you can load textures into TV namely: TVTextureFactory load methods, TVInternalObjects RegisterTexture/SetTexture methods and TVTextureFactory SetPixel methods. Their speed most probably decreases this order.

For one reason or another you may wish to get a Bitmap from .Net environment into TV and use it as texture or just display it on screen. To do that you could save the bitmap on HDD and load it into TV but this would be slow. The method I describe here copies the bitmap data directly into existing texture instead.

This method is quite efficient and can be used to update texture within the render loop (ie. for displaying images captured by webcam). It however still requires copying the whole buffer over and possibly resizing.

Format

The important thing to know is that TV textures can be easily updated using TVTextureFactory SetPixel methods. These work best if can supply the data in properly formatted array.

Textures are stored in BGRA (blue, green, red, alpha) format. You can use SetPixel and SetPixelFloat to bypass any problems with format by specifying each colour by TVGlobals.RGBA or using TV_COLOR structure. Unfortunatelly you would have to set each pixel colour separately. You can however use SetPixelArray or SetPixelArrayFloat(Ex) and supply all values in an array.

Let’s consider only SetPixelArray since it uses integers which are faster than floats. Here you’ll need an array of integers representing each pixel’s colour.

Question is how to represent colour consisting of 4 channels (BGRA) by 1 integer? Easy answer is by using TVGlobals.RGBA to convert it. The right answer is to construct the (32 bit) integer by joining four bytes (8 bits each). You only have to make sure that these bytes come in right order: BGRA.

Tip: You can directly cast Image to Bitmap: Bitmap MyBitmap = (Bitmap)MyImage;

Converting Bitmaps

The actual process of converting a bitmap is simple:

  • Resize bitmap to same size as texture (Optional)
  • Lock bitmap to make it possible to access its data
  • Make a copy of data
  • Lock texture
  • Use SetPixelArray to update the texture
  • Unlock both texture and bitmap

Only thing that remains is to make sure the format is right. There are two parts to it: Firstly specify correct pixel format when locking the bitmap - PixelFormat.Format32bppArgb. To make it more confusing the format is called Argb but the actual data will be in BGRA format afterwards. Secondly you need to convert the bitmap data into array of integers. The data is in form of a managed pointer (IntPtr). Luckily you can use use Marshall class to copy any data that the pointer points to into an array. And since you know the data is in right format you can copy it as array of integers.

In practice it looks like this:

C#
public void SetTexture(Bitmap MyBitmap, int MyTexture)
{
    // Get texture info
    TV_TEXTURE MyTextureInfo = TF.GetTextureInfo(MyTexture);
    // Resize bitmap to texture size (always ^2)
    MyBitmap = new Bitmap(MyBitmap, MyTextureInfo.RealWidth, MyTextureInfo.RealHeight);            
    // Lock bitmap data
    BitmapData MyBitmapData = MyBitmap.LockBits(new Rectangle(0, 0, MyBitmap.Width, MyBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    // Allocate buffer
    int[] buffer = new int[MyBitmap.Width * MyBitmap.Height];
    // Copy data from bitmap to buffer
    System.Runtime.InteropServices.Marshal.Copy(MyBitmapData.Scan0, buffer,0,MyBitmap.Width*MyBitmap.Height);
    // Unlock bitmap
    MyBitmap.UnlockBits(MyBitmapData);
    // Lock texture
    TF.LockTexture(MyTexture, false);
    // Write buffer into texture
    TF.SetPixelArray(MyTexture, 0, 0, MyBitmapData.Width, MyBitmapData.Height, buffer);
    // Unlock texture
    TF.UnlockTexture(MyTexture, true);
}
VB.Net
Public Sub SetTexture(ByVal MyBitmap As Bitmap, ByVal MyTexture As Integer)
    ' Get texture info
    Dim MyTextureInfo As TV_TEXTURE = TF.GetTextureInfo(MyTexture)
    ' Resize bitmap to texture size (always ^2)
    MyBitmap = New Bitmap(MyBitmap, MyTextureInfo.RealWidth, MyTextureInfo.RealHeight)
    ' Lock bitmap data
    Dim MyBitmapData As BitmapData = MyBitmap.LockBits(New Rectangle(0, 0, MyBitmap.Width, MyBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)
    ' Allocate buffer
    Dim buffer(MyBitmap.Width * MyBitmap.Height) As Integer
    ' Copy data from bitmap to buffer
    System.Runtime.InteropServices.Marshal.Copy(MyBitmapData.Scan0, buffer, 0, MyBitmap.Width * MyBitmap.Height)
    ' Unlock bitmap
    MyBitmap.UnlockBits(MyBitmapData)
    ' Lock texture
    TF.LockTexture(MyTexture, False)
    ' Write buffer into texture
    TF.SetPixelArray(MyTexture, 0, 0, MyBitmapData.Width, MyBitmapData.Height, buffer)
    ' Unlock texture
    TF.UnlockTexture(MyTexture, True)
End Sub

TF is TVTextureFactory object.

If you don’t resize the bitmap you may end up with blank space around the copied area or copying only part of the bitmap (if it’s larger than the texture). You can however skip this if you are sure that both bitmap and texture have the same size. Textures come are stored sizes which are powers of 2 (2,4,8,16,...,256,512,...). Even if you load a texture of size 50×100 it will be stored as 64×128 texture.

Converting images from other sources

The main idea behind this method is to copy the data using Marshall class (fast) into an integer array and to use SetPixelArray to update the texture. This is relatively fast but if you have another data source you can use the same method to copy the data over to TV.

Avoid converting from your data source to Bitmap and then to TV if possible.

Usage

If you are using some kind of imaging library for capturing images from webcams or scanners that produces Bitmap/Image data for displaying on forms you can use this method to display the same data within TV.

You can use it to render webcam video by converting each captured frame and rendering it.

If you however have access to the image data directly without using Bitmaps you should use it. An example is managed OpenCV which offers both access to image data and produces Bitmaps. In this case it is better/faster to use the data directly instead of converting it to Bitmap first and then converting it into texture.

 
tutorialsarticlesandexamples/converting_bitmap_to_texture.txt · Last modified: 2013/11/22 13:32