The Java plan for you Valentine’s Day (second part)

Ok as I promised for while now, there is a post about simple effect you can play with in java…

Please don’t laugh of my code because lot’s of what I done in java here came from my old “souvenirs” from what I learned when I coded it in C/Dos long time ago…I was very interested in Demoscene and all big effects you can do with sin/cos/+/-/*/:

I’m sure you can optimize this code for Java but I will let you enjoy this part !

Please stop grimacing at me like that, the code works well, easy to read and fast enough… 😉

This topic is related to the first one I wrote, you should take a look on it or at least get the code.

Here is the plan:

  1. Code the smooth effect / fading
  2. Join the projectile effect we did last time to our smooth effect
  3. Play with smooth effect

The smooth effect / fading effect

The fading algorithm is one of my favorites effects, because it’s easy and also nice !

Imagine we have a screen as an array, let’s name it back[width][height]. So as this array represents our screen, you should guess the screen contains pixel/color value.   The pixel/color value is stored in an integer. So the array is an array of integer. I mention here the term integer as common sense, because as you should know in computer science we could represent an integer in several forms… We will come back to this remark later.

the fading effect consist simply in processing each pixel as below:


for each pixel ([x,y]) in back
{
  if   (x =0 || x=width||y=0||y=height)
  {
    back[x,y] = 0;
  }
  else
  {
   back[x,y+1] = average_of(pixels around [x,y]);
  }
}

That’s it ! 🙂

There are three main ways to find “pixels around [x,y]“:

The three main algorithm of fading effet

The three main algorithm of fading effet

As you can note, in the third way, the pixel value is less than the others, which means the fading effect is faster than the others.

Thing to do to get more fun ! :p

Play to find another way to understand “around”. For example you could only computing pixels on the top of the current pixel, or you can enlarge the square around the current pixel, or even more complicated algorithm..

Here is the exact algorithm I used in my code:

Algorithm used in my code

Algorithm used in my code

As you can see I used the first fashion to find pixels around but I stored the new value to the pixel just at the bottom of the current pixel. So It gives to the fading effect a direction ! The fading seems to fall down… nice !!

Thing to do to have more fun ! :p

Again play with this to find another fun directions to give to the fading… for example we could do a spiral so the fading seems to be breathed in the center, you can fading up (set value to the top of the current pixel) and simulate things like fire… etc…

Come back to our pseudo-code, it gives us:

for each pixel ([x,y]) in back
{
  if   (x =0 || x=width||y=0||y=height)
  {
    back[x,y] = 0;
  }
  else
  {
    if(y == 1)
    {
      back[x][y] = 0;
    }
    back[x,y+1] = average_of(pixels around [x,y]);
  }
}

What is theses tips around (x =0 || x=width||y=0||y=height) and (y == 1) if statement ?

The easiest way to understand still remains to leave this code and re-build to see what changed…You should see some lost pixels in the border line which make things ugly on screen… I let you wonder why et enjoy it ! 🙂 I didn’t take time to optimize this part, but I think it’s one of the easiest part to change.

Going in deeper

Firstly take a look on the main code of the effect:


for(int x = 0; x < back.length; x++){
                for(int y = 0; y < back&#91;0&#93;.length;y++){                   
                    if(x == 0 || x ==back.length-1 || y == 0
                            || y ==back&#91;0&#93;.length-1 )                    {
                        back&#91;x&#93;&#91;y&#93;&#91;0&#93; = 0;
                        back&#91;x&#93;&#91;y&#93;&#91;1&#93; = 0;
                        back&#91;x&#93;&#91;y&#93;&#91;2&#93; = 0;                   
                    }
                    else
                    {
                        if (y== 1){
                            back&#91;x&#93;&#91;y&#93;&#91;0&#93; = 0;
                            back&#91;x&#93;&#91;y&#93;&#91;1&#93; = 0;
                            back&#91;x&#93;&#91;y&#93;&#91;2&#93; = 0;                           
                        }

                        for(int c = 0;c<3;c++){                       
                            back&#91;x&#93;&#91;y+1&#93;&#91;c&#93; = (back&#91;x+1&#93;&#91;y&#93;&#91;c&#93;+
                                    back&#91;x-1&#93;&#91;y&#93;&#91;c&#93;+
                                    back&#91;x&#93;&#91;y+1&#93;&#91;c&#93;+
                                    back&#91;x&#93;&#91;y-1&#93;&#91;c&#93;)>>2;/* I put code for the third algo in comments
                                    back[x-1][y-1][c]+
                                    back[x+1][y+1][c]+
                                    back[x+1][y-1][c]+
                                    back[x-1][y+1][c])>>4;*/
                        }                       
                    }
                    front.setRGB(x,y,new Color(
                            back[x][y][0],
                            back[x][y][1],
                            back[x][y][2]).getRGB());                   
                }
            }    

            gr.drawImage(front, 0, 0, null);

Thing you should notice, if you don’t know how pixel are managed by your computer is why am I doing this :


for(int c = 0;c<3;c++){                       
                            back&#91;x&#93;&#91;y+1&#93;&#91;c&#93; = (back&#91;x+1&#93;&#91;y&#93;&#91;c&#93;+
                                    back&#91;x-1&#93;&#91;y&#93;&#91;c&#93;+
                                    back&#91;x&#93;&#91;y+1&#93;&#91;c&#93;+
                                    back&#91;x&#93;&#91;y-1&#93;&#91;c&#93;)>>2;/* I put code for the third algo in comments
                                    back[x-1][y-1][c]+
                                    back[x+1][y+1][c]+
                                    back[x+1][y-1][c]+
                                    back[x-1][y+1][c])>>4;*/
                        }

As you can see, I computed each component of the pixel (Red,Green and Blue) instead of computing directly in integer, for intance something like this:


 back[x][y+1]= (back[x+1][y]+ back[x-1][y]+ back[x][y+1]+back[x][y-1])/4;

There are two reasons for this, firstly because it doesn’t give you the same result. See the example below:

Difference between integer and component computing

Difference between integer and component computing

As you can see the rest of division prevent us from computing the right result.

The second reason took its roots from how graphic cards manufacturers managed pixels for years ago. The problem is that they used their own rules, and there are no standard on how stored pixel in memory.

For example for 16 bits depth color, how could we divided properly 16 bits for three components R/G/B ?? Some manufacturers decided to avoid the 16th bit, and stored as {R =5bits ; G = 5bits ; B=5bits} = 15bits. And some others decided to give to green componenent more bits (because human eye is more sensible to green), then we got {R=5bits ; G=6bits;B=5bits}.

Basically RGB integer is stored as below by the main part of manufacturers:

15bit = {5,5,5}

16bit = {5,6,5}

24bit={8,8,8}  (8bit == 1byte, simple operation to get RGB component 😉 )

32bit={8,8,8,8 } (the 4th byte is the component Alpha of the pixel, which refers to the transparency of the pixel)

And that’s not all ! Some manufacturers stored component in different order than RGB, for instance BGR ! So how could we manage this? We had to check which configuration is used on the current card, there is no other solution.

Fortunately the class Color in Java, help you to get the right structure for your integer, take a look on the source of the Color class, and you will see bit operations I’m talking about here.

For the best geek of you

You can play to recreate your own Color class and try to optimize it ! To success you have to get some tutorials on bit operations like shifting and bit masking.

Ok enough words now, let’s see the result of all our efforts:

Java me!

It's better in motion ! 😉

Get sources code here! It’s really better in motion ! 😉

Now is your turn ! Dance in Java but don’t forget to go out with your girl at Valentine’s day ! 😉

Advertisements

3 Comments

  1. vd11

    Waow !! That’s really a great effect !! Thanks for this !!
    I use your code and add explosion sound, ant the final effect is really impressive 😉
    But while I was reading your code, I wonder where are the threads…I didn’t find one…I really have to read your first valentine’s day to understand your method !!

    I’m waiting for another great tutorial !!!

Trackbacks

  1. Android development « Tuan’s Blablabla… :)
  2. Plotting Android screen :) « Tuan’s Blablabla… :)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: