4

I have a byte array representing an image.

Each byte represents an intensity value (0-255) of either R,G or B of a particular pixel. So for a 640x480 image the byte array is of size 640*480*3 (each pixel has 3 bytes representing it).

The bytes are in order of pixels. For instance:

image[0] = the R value of x=0 y=0 
image[1] = the G value of x=0 y=0
image[2] = the B value of x=0 y=0
image[3] = the R value of x=1 y=0

and so on.

I am wondering what the most efficient way to draw this to screen in XNA is?

My thoughts are to do the following.

  1. Create a new Texture2d object
  2. During the draw() method, loop through the byte array and set the values on the Texture2D object
  3. Draw this filled in object to the screen.

Is this the fastest way to do this? I can also store the byte array in a different order/format if it is more efficient. Is there any downside to doing the looping during the draw() method? Would it be better to do it during update()?

EDIT:

I have attempted to use setData() on a Texture2D inorder to create a new texture every time my byte array updates (usually once a frame). The fps is now below 15 whereas before it was at 60. The code is as follows:

    public static Texture2D getImageFrame(GraphicsDevice gd)
    {
        if (cameraTex == null)
        {
            cameraTex = new Texture2D(gd, 640, 480, false, SurfaceFormat.Color);
        }
        cameraTex.SetData(imageFrame);
        return cameraTex;
    }

Which is called every draw() cycle.

Surely there has to be a more efficient way of doing this?

Jkh2
  • 1,010
  • 1
  • 13
  • 25
  • I would highly recommend looking into using the Flyweight pattern as a design pattern to consider when developing this application. I think one of your bigger challenges will be the overall retrieval/storage of this data, in a time sensitive manner, on each iteration of your draw/update. http://en.wikipedia.org/wiki/Flyweight_pattern – George Johnston Mar 19 '12 at 18:40
  • In terms of storing the byte array, I am not passing it around as an object. It is updated every frame from another process and I am looking for a way to convert this data into a drawable texture2d every frame. – Jkh2 Mar 19 '12 at 18:55
  • You probably want to do something with [SetData](http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.texture2d.setdata.aspx), then. – thedaian Mar 19 '12 at 19:15
  • I have attempted to use setdata passing in my byte[] as input. It crashes with an exception says that the size of the data is too large or too big. The byte array is 640*480*3. does anyone know what size setData is expected for an image size of 640x480? – Jkh2 Mar 19 '12 at 21:02
  • EDIT: sorted it out, forgot the alpha channel... Now the new problem is that this is very slow. My framerate is now under 15 when before it was rock-solid at 60. – Jkh2 Mar 19 '12 at 21:08

1 Answers1

2

Depending on the way in which the byte array is updated (may be worth noting), you can probably update a smaller segment of a texture using the SetData overloads that use index and count parameters.

Obviously you'll need to add some way of tracking what regions of pixels have last changed for this to work (again depends on the structure of your program). In any case, I had a similar performance hit with drawing a blood splatter texture on another texture recently, and managed to minimize the hit using this method.

public void SetData (T[] data, int startIndex, int elementCount)

public void SetData (int level, Nullable rect, T[] data, int startIndex, int elementCount)

http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.graphics.texture2d.setdata.aspx

Community
  • 1
  • 1
kallotec
  • 449
  • 6
  • 17
  • 1
    Since the code is called each time you Draw(), you can also probably create a flag saying if the byte array has actually been updated, so if (bytesUpdated) – kallotec Mar 20 '12 at 19:57