Thursday, March 24, 2011

SteelSeries 3.8 (slim down release)

Like i mentioned in my last post there is a new release of the SteelSeries swing component library. I have to release another version of the library because i added two new components to it and made some modifications that i explained in my last post too.

Klaus Rheinwald asked me for an artificial horizon component that he needed and so i started adding one to the library. Fortunately i created one last year on my trip to JFokus and got some insider information of Mikael Grev who is an active fighter pilot and a coder (you might know one of his projects called MiGLayout which is a really nice Java Layout Manager). 
So the result of this work looks like this...

Horizon

The Horizon component is located in the extras package of the SteelSeries and you could customize it by defining the color of the sky, the background and the indicator (setPointerColor()). You could define pitch and roll and the horizon will hopefully display the right view. There's only one little problem left which occurs if you have a pitch larger than 90°. A real artificial horizon will flip over by rotating around 180° but i was not able to implement it in a way that looks good enough. I will spend some time to this problem later on, so stay tuned...

Klaus Rheinwald also pointed me to the Compass component that's already in the SteelSeries library and he mentioned that on an airplane the compass looks different in the way that the "needle" is fixed and the scale is rotating...
Ok, that was a piece of cake because in principle this is the same behaviour as the RadialCounter just with another pointer. Long story short, here is the AirCompass component...

AirCompass

The design was taken from a real aviation instrument and the whole creation time for this component was only around 2 hours. You could set the value in the range of 0 to 360 degrees and the scale will rotate around the airplane in the center. The color could be changed by the pointerColor property of the component.

In the last release i forgot to mention that there was also a new FrameDesign and BackgroundColor that one could choose for the gauges and because i added another FrameDesign i will present both of it in this post...

Left: FrameDesign.GOLD, BackgroundColor.BROWN, PointerType.TYPE7

Right: FrameDesign.CHROME, KnobType.BIG_CHROME_KNOB, PointerType.TYPE7

On the left gauge you see the FrameDesign.GOLD with the new BackgroundColor.BROWN and on the right gauge you see the new FrameDesign.CHROME. In addition to the new FrameDesign you could see also another new PointerType.TYPE7 in both gauges and a new KnobType.BIG_CHROME_KNOB (on the right gauge).

Another user of the SteelSeries library asked me if it would be possible to get a square frame on the Clock component too...and of course this is possible...here we go...

Left: FrameType.ROUND
Right: FrameType.SQUARE

Another modification was the reduction of the memory footprint of the components. I mentioned this in my last post already, so it's not needed to repeat myself here. Nearly all components now make use of this combined layer technique.

The test application is now also updated to the 3.8 release of the library and is still available here as a webstart app.

At least i fixed a memory leak that occurred when using the setValueAnimated() method. After i made some long term tests over the last days the problem seems to be fixed now.

Like i said before, just let me know if you need some special component and i'll try to implement it if i'll find the time...

That's it for today, enjoy the upcoming weekend and keep coding...



Wednesday, March 23, 2011

Slim down...

Today i would like to talk about some experiments that i made to reduce the memory footprint of the steelseries components.
As you could read in the first post on this blog i mentioned the problem with the what i called "Layer Technique", where you split your component in different layers. With this technique you create an image for each layer of the component, in my case this means i create images for the frame, background, tickmarks, title, lcd background, pointer, knobs and foreground. The memory footprint of a typical image of a radial component in the steelseries could then be calculated as follows:

The default size of a radial component is 200x200 pixels and i'm using an alpha channel which results in a memory footprint of one image of:

200 x 200 x 4 byte = 160 000 bytes 
(4 byte = 1 byte for red, 1 byte for green, 1 byte for blue and 1 byte for alpha)

This means that a standard radial component in it's default visualization (containing a frame, background, title, tickmarks, pointer, knobs and foreground) will have a memory footprint (only of the images) of: 

7 x 160 000 bytes = 1 120 000 bytes = 1.07 Mb

That seems to be ok even if it's a lot of memory just for the visualization but in these days computers have lots of ram and powerful processors so it should not be a problem.
But if you imagine a huge display showing 20 radial components of a size of 300x300 pixels it could get up to:

20 x 300 x 300 x 4 byte x 7 = 50 400 000 bytes = 48.07 Mb

You might want to say "come on...it's only 50 megabytes, where is the problem" and you might be right but to me it looks too much...which means i had to slim down the memory footprint of the components.

I faced the same problem in the canvas version of the steelseries components and i used the same optimization in the swing version, i combine layers in as less images as possible.
This means i combine the frame, background, title, tickmarks and lcd background in one image and the knob and foreground in another image. Well it's not a huge improvement but it feels better. To give you an idea how i realized it let me show you some code...

Old version: 
public BufferedImage create_FRAME_Image(int size)
{
    GraphicsConfiguration GFX_CONF = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
    BufferedImage image = GFX_CONF.createCompatibleImage(size, size, TRANSLUCENT);
    Graphics2D g2 = image.createGraphics();
    ...
    // Do some fancy drawing here
    ...
    g2.dispose();
    return frameImage;
}

New version:
public BufferedImage create_Frame_Image(int size, BufferedImage image)
{
    if (image == null)
    {
        GraphicsConfiguration GFX_CONF = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        BufferedImage image = GFX_CONF.createCompatibleImage(size, size, TRANSLUCENT);
    }
    Graphics2D g2 = image.createGraphics();
    ...
    // Do some fancy drawing here
    ...
    g2.dispose();
    return image;
}

As you can see the new version takes an image as parameter and if this parameter is not null it will draw the fancy painting code on the given image and returns it again. With this technique you could create an image in the component and pass it to all methods that you would like to add to the image and you will end up with one image only, instead of many images.
The drawback of this method is that you have to create the whole background image each time you change one of the images (e.g. the backgroundcolor of the gauge) but it will reduce the memory footprint.

Another modification i made was again located in the image creation methods. Because the image creation methods will be called at the time of initialization (before the component is really realized) with a size of 0 they have to return something. In the former release i returned an empty image of the default size which means 200 x 200 pixels. But this image was never used because once the component was realized, the image was created again with the default size and the old image was thrown away. By using VisualVM i was able to see a peak in memory usage directly after initialization of the components which was huge. In the current release i return an empty image of the size 1 x 1 pixel which again reduced the memory footprint a bit.

Like i mentioned in my very first post there are more areas of potential "weight loss", e.g. the pointer image could be only of the size of the pointer instead of the full image size etc. 

I'm not sure if this was the right approach but it works and i would love to hear other ideas on how to reduce the memory footprint...

The next release of the SteelSeries library (3.8) will contain all these modifications and will be available soon...so stay tuned and keep coding...

Thursday, March 10, 2011

SteelSeries 3.7.2

And another one...
nearly two weeks ago Andreas Ehlert contacted me and asked me if i could create some component that he would like to use to visualize the wind direction on a ship. An example of such a gauge could be found here.


He sent me some images and i started creating a version of this gauge for the SteelSeries library. Here is an image of the new component...

WindDirection

This gauge has two pointers where one pointer shows the measured direction from where the wind is coming from and the second pointer shows the real direction from where the wind is coming. The second pointer only has a setValue2() method but no setValue2Animated() method. The second pointer could have a all other properties that the standard pointer has like pointerType, pointerColor etc.
The lcd display in the component is not coupled to the pointer value but will show the windspeed in knots which has to be set by using setLcdValue().

In addition to this new gauge i made some modifications to the existing ones in the library. First i added a lcd display to the altimeter gauge which should it make more easy to directly read the visualized value, here is a little screenshot...

Altimeter incl. LCD

The other component i modified is the RadialCounter. I made some minor graphical modifications that hopefuly improves the look of the component a bit because i was not satisfied with it. On the left you see the new version and on the right you see the old version.


To be honest i'm still not sure if the new version will be finished forever but at the moment it seems to be better than the old one. The biggest problem with the old one was that you never saw the real value of the gauge which was the reason for the lcd display. Now one could set the value for example to 20 which will rotate the tickmarks two times and the lcd will show the value increasing up to 20.


In addition to the modifications above i also added another pointer type which is called TYPE6 and looks like this...


PointerType.TYPE6


Another small modification is the ability to select different shapes for the tickmarks. There are three types of tickmarks:



  • MiniTickmarks
  • MinorTickmarks
  • MajorTickmarks



which could get a shape of eu.hansolo.steelseries.tools.TickmarkType.
The available types are



  • LINE
  • CIRCLE
  • TRIANGLE
  • SQUARE

In this release only LINE and CIRCLE are supported but i'll try to implement also TRIANGLE and SQUARE in a future release of the library.
The CIRCLE type on the major tickmarks will look like this...


TickmarkType.CIRCLE


In the last version there have still been problems with some components like the lcd etc. when drag'n drop it to a panel in a visual design editor like Matisse in Netbeans. The initial size after the component was dropped to the container was wrong. This is fixed now.


If you like the components in the library but miss a specific one that you could need...just let me know and i'll try to add it to the lib. One component on my list is for example an artificial horizon that i created 1.5 years ago and would like to add to the library in the future.

So that's it for today...