Vector looping

Hi,

Re: MemoryImageSource

Basically, you can represent an image by an array of ints, and so instead of drawing rects over and over (which could be slow, and prone to garbage creation) you can directly modify the integer in the array to set the appropriate color (either black or blue). When you are done going through the array, you signal the image that the image has been changed, and then you can draw it to the screen. Check out the API docs on MemoryImage source but here’s a little code snipit that gets an image of a car and makes it semi-transparent by changing the alpha bit of the int of the pixel and then creating an image out of that array.

image contains the opaque image of the car.


      // load up transparent image for the car
      int[] pixels = new int[image.getWidth() * image.getHeight()];
      PixelGrabber pg = new PixelGrabber(image, 0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());
      try
      {
        pg.grabPixels();
      }
      catch(InterruptedException e)
      {}

      for(int ctr = 0; ctr < pixels.length; ctr++) 
      {
        int alpha = (pixels[ctr] >> 24) & 0xff;
        if (alpha != 0)
        {
          // set this pixels transparancy to 25%
          pixels[ctr] =  0x4F000000 | (pixels[ctr] & 0x00FFFFFF);
        }
      }
      carTransImages[i] = Toolkit.getDefaultToolkit().createImage(
        new MemoryImageSource(image.getWidth(),image.getHeight(),pixels,0,image.getWidth()));
    }

Now, don’t quote me, but I think that if you create an image from a MemoryImageSource, the array of integers is the actual data of the image, so modifying the array will actually modify the image. This, obviosuly is a very non-OO way to manipulate images, but the whole theme behind the water applet seems to fit very nicely into this model.

-Chris

Chris’s explination is much better than mine, listen to him :slight_smile:

Chris,

I was wondering that exact thing about manipulating the int array instead of using the new* methods… if this is the case, and changing the array changes the source, that is gonna be slick as hell for performance minded programming that needs that functionality…

Can anyone verify/deny this?

I did do a performance comparision between drawing an image and doing an arraycopy of a block of pixels and saw virtually no difference when in the case of where the image was the same size as the drawing surface (maybe under the covers there is a check to see if the geometry of the image is the same as the drawing surface, it does a straight memory copy). I kinda stopped there (I’m a lazy bastard) because when drawing a smaller image to a larger surface, you aren’t writing a continuous line of arrays anymore, you have to do one array copy per row of the smaller image to the proper offset of the drawing surface (this is a bit unclear, I know, but i’m sorry). Stick with drawImage when the image and the drawing surface is compatable…I think it does exactly what you would do if you modified the image source by hand. In the case of this water applet, however, if 1 droplet is exactly 1 pixel, then you save yourself the overhead of a drawRect or DrawLine or FillRect and instead just do a single integer assignment (this, I would argue would be much faster).

-Chris

Be very careful with speeding up iteration - as someone else has pointed out, the best performance boost will most likely come from using different data-structures, and different algorithms - but there are some pitfalls here. The rest of this explains the problems and gotchas. Although it appears not to be directly relevant to the original poster’s situation, anyone trying to use the suggestions in their oen programs might benefit from reading it :). PS I’m sure those providing suggestions realise the dangers, but I know there’s plenty of people reading this who won’t.

The suggestion to iterate with for() from i=0 to i=Vector.size() is really dangerous. The suggestion to take the array-form of the Vector with Vector.toArray() is not so dangerous, but both will often give you very unexpected, very hard to track down bugs (unless you appreciate what you’re doing). The iterator() system isn’t only there to provide compatibility with the Collection interface, nor just to look pretty.

If you read the start of the Vector (and many other Collections classes) API javadocs, you’ll find a paragraph mentioning that “the iterator provided is fail-fast” with an explanation of what that means.

In the first example (the really dangerous one), the size of the Vector can change WHILST you are in the middle of your for loop. If it increases in size, you will not get ALL of the elements (and, depending on the implementation of the Vector, you may end up doing some - or even many - elements twice, or even more times! This is one of those very confusing bugs). If it decreases, you’ll be accessing items outside the size of the Vector. This is most likely why you heard the suggestion “wrap it in a try{ }catch( ArrayIndexOutOfBoundsException” - to prevent crashes in the case where the Vector shrinks. Note, this still provides NO PROTECTION AT ALL if the Vector grows.

In the second example, we can guarantee that the array will NOT change in size or contents. However, if it takes a significant time to iterate over that array (unlikely, but I’ve seen cases where it happens, e.g. when the array contains Sockets, and the for() loop is sending a message on each), then you may find your app appears to “ignore” things once they’ve been added to the Vector.

blahh bllahh, I appreciate the post… those are important points to consider…

My water applet…
http://www.cfxweb.net/java.php?op=contest&num=3rd&entry=marvin

(source code is there somewhere too)

Nice job, very smoothe, no jerks. You handle memory allocation very well. :slight_smile:

-Chris