Plotting Android screen :)

As promised here is my former application fireworks which I migrated to Android OS.

I changed a little bit the application in order to handle touch event, so it’s not a fireworks anymore, it’s a kind of  wasted-time ZEN application 🙂

The app is very simple, when you touched the screen it draws you a square in magenta and the screen is continuously blurred… the result aim to be a ZEN application ! 😉

Of course, it’s more for education purpose…

Here is a screen of our final application:

Check it !

Check it !

So we have  these 4 steps below in order to get the same result:

  1. Create an Android project and an activity
  2. Implement onDraw function to compute and draw result / do some optimization in order to have a decent frame rate
  3. Handle finger touch

Please note that I assume you already have the SDK installed (1.1 or higher)  and you know how to create a new project.

1 – Create a project and a activity

We created an activity and an anonymous class derived from View (Graphique which means graphic in french :p ) class. We have to do so because we want to override the onDraw function of the view then we can draw on the current View.

The anonymous class is an ugly solution. Because the application structure is very simple we can avoid this rule 😉 But yes try to never use anonymous class as all good books told you!

We also defined a Bitmap which represents the back screen. We will firstly draw on the back screen before copy it to main screen (real phone screen). It’s a kind of double buffer. Also don’t forget to define a Paint which tell to Android how you want to draw the pixels.

<pre>public class Fireworks extends Activity{
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(new Graphique(this));        
 }
 private static class Graphique extends View {
 private Paint mPaints, mFramePaint ;

 public Graphique(Context context) {
 super(context);
 mFramePaint = new Paint();
 mFramePaint.setAntiAlias(true);
 mFramePaint.setStyle(Paint.Style.STROKE);
 mFramePaint.setStrokeWidth(0);
 mPaints = new Paint();
 mPaints.setAntiAlias(true);
 mPaints.setStyle(Paint.Style.FILL);
 mPaints.setColor(Color.BLUE);

 this.bufferscreen = Bitmap.createBitmap(
 315,425,Bitmap.Config.ARGB_8888);
  }
 @Override
 protected void onDraw(Canvas canvas) {
 canvas.drawBitmap(this.bufferscreen, 0.0f,0.0f,mFramePaint);
 invalidate();
 }
 }
}

2 – Implement onDraw function to compute and draw result

Here is the core of our application. Please refer to my original post to know how the algorithm is working.

You have to focus here on the mini_buffer and optimization code. Because it’s very slow to compute the screen entirely, I created a mini screen with fewer pixels where we draw and compute them. When all computing are finished I project the mini screen to the buffer screen with the real size. And after that I copy the buffer screen to the real phone’s screen. It’s seems very complex but in fact it’s very simple, please stay with me 🙂

For instance my real screen sizes are 100/100 and my mini screen are 10/10 (width/height). So we did all maths in the 10/10 screen then project it to the 100/100. Which mean:

– I have originally 100*100 pixels to compute, finally I only compute 10*10 (one line in the real screen !)

-1 pixel in my mini screen represents a square of 10/10 pixels in my real screen.

-my real screen will pixelize ! Yes it’s the fact, but the gain I earned by computing one single line instead of 100 lines is much relevant! Any way you can change the projection in order to match exactly what you need.

Finally what is this ?


r = (
 (
 ((p1 >> 16) & 0xff)+
 ((p2 >> 16) & 0xff)+
 ((p3 >> 16) & 0xff)+
 ((p4 >> 16) & 0xff)
 )>>2
 )<<16;

&#91;/sourcecode&#93;

Because of the algorithm (<a href="https://tuanbach.wordpress.com/2009/01/26/the-java-plan-for-you-valentines-day-second-part/">please refer to my previous post</a>) I have to extract each component (RGB) and compute separately these with pixel's components around. Then the pixel's components are stored as below:

Pixel = Red (8 bytes) | Green (8bytes) | Blue (8bytes)

So to get the component I wanted I have to shift to the right and do an AND to 0xff. The steps below will explain you why:

Pixel &gt;&gt; 16 &lt;==&gt; Pixel = 8 Unknown bytes | 8 Unknown bytes | Red (8 bytes)

0xff &lt;==&gt; 00000000 | 00000000 | 11111111

[ 8 Unknown bytes | 8 Unknown bytes | Red (8 bytes) ] AND 00000000 | 00000000 | 11111111 &lt;==&gt; 00000000 | 00000000 | Red (8 bytes)

Now I have the red component of my pixel, I can do it with all components. note that for the Blue component you don't have to shift any bytes, because it 's already at the beginning.

Then I add all red's components, divide them by 4  by shifting to the right by 2. Yes it works, when you shift n to the right you divide your number by 2*n. The proof can be found on Google, or you can practice some exercises by trying to get the proof yourself. It's due to the binary, with the same reason when you shift by 1 in the decimal system (human system) to the right you divide by 10 (e.g 100&gt;&gt;1 &lt;==&gt; 10)

And I shift back the component to the right position (16 for red, 8 for green, 0 for blue).

When I finished to compute I regroup all my components by doing a simple OR:

respix = 0xff000000 | r | g | b;
<blockquote>Note that I added the alpha component on the left of my variable because Android system stored the pixel as ARGB.</blockquote>
Finally I do the projection by writing my pixel square in the buffer screen. In my code I divided the real screen by 5, so I have to draw a square of 5/5 in my buffer for each pixel from my mini buffer.



int index,r,g,b,index2;
 int[] buffer = this.mini_buffer;
 int p1,p2,p3,p4;
 int respix;
 for(int y = 85 -2;y>0; y--)
 {
 for(int x = 63-2;x>0; x--)
 {
 index = y*63+ x;
 p1 = buffer[index+63];
 p2 = buffer[index-63];
 p3 = buffer[index+1];
 p4 = buffer[index-1];
 r = (
 (
 ((p1 >> 16) & 0xff)+
 ((p2 >> 16) & 0xff)+
 ((p3 >> 16) & 0xff)+
 ((p4 >> 16) & 0xff)
 )>>2
 )<<16;
 g = (
 (
 ((p1 >> 8) & 0xff)+
 ((p2 >> 8) & 0xff)+
 ((p3 >> 8) & 0xff)+
 ((p4 >> 8) & 0xff)
 )>>2
 )<<8;
 b = (
 (
 ((p1) & 0xff)+
 ((p2) & 0xff)+
 ((p3) & 0xff)+
 ((p4) & 0xff)
 )>>2
 );
 //compute pixel color
 respix = 0xff000000 | r | g | b;
 index2 = (y*5)*315+ (x*5);
 //write color pixels to front screen
 this.buffer_class[index2]= respix;
 this.buffer_class[index2+1]= respix;
 this.buffer_class[index2+2]= respix;
 this.buffer_class[index2+3]= respix;
 this.buffer_class[index2+4]= respix;

 this.buffer_class[index2+315]= respix;
 this.buffer_class[index2+315+1]= respix;
 this.buffer_class[index2+315+2]= respix;
 this.buffer_class[index2+315+3]= respix;
 this.buffer_class[index2+315+4]= respix;

 this.buffer_class[index2+630]= respix;
 this.buffer_class[index2+630+1]= respix;
 this.buffer_class[index2+630+2]= respix;
 this.buffer_class[index2+630+3]= respix;
 this.buffer_class[index2+630+4]= respix;

 this.buffer_class[index2+945]= respix;
 this.buffer_class[index2+945+1]= respix;
 this.buffer_class[index2+945+2]= respix;
 this.buffer_class[index2+945+3]= respix;
 this.buffer_class[index2+945+4]= respix;

 this.buffer_class[index2+1260]= respix;
 this.buffer_class[index2+1260+1]= respix;
 this.buffer_class[index2+1260+2]= respix;
 this.buffer_class[index2+1260+3]= respix;
 this.buffer_class[index2+1260+4]= respix;

 //write color pixels to back screen
 buffer[index] = respix;
 }                
 }      
 //            

 this.bufferscreen.setPixels(this.buffer_class,0,315,0,0,315,425);

 canvas.drawBitmap(this.bufferscreen, 0.0f,0.0f,mFramePaint);
 invalidate();
 }
 }

3-Handle finger touch

Final point I implement the right interface in order to handle the touch events and trackball events. Because it’s very simple, it avoids explanation…

You have to focus here on the Finger class, which represents the finger square to draw when user touches the screen. Note that I have to blit pixel in the mini buffer!

<pre>public class Fireworks extends Activity{

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(new Graphique(this));        
 }
 private static class Graphique extends View {
 private Paint mPaints, mFramePaint;
 private RectF mRect;
 protected Bitmap bufferscreen;
 int buffer_class[],mini_buffer[];
 Finger finger;
 public Graphique(Context context) {
 super(context);
 finger = new Finger();
 mFramePaint = new Paint();
 mFramePaint.setAntiAlias(true);
 mFramePaint.setStyle(Paint.Style.STROKE);
 mFramePaint.setStrokeWidth(0);
 mPaints = new Paint();
 mPaints.setAntiAlias(true);
 mPaints.setStyle(Paint.Style.FILL);
 mPaints.setColor(Color.BLUE);
 mRect = new RectF(5, 5, 315, 425);
 this.bufferscreen = Bitmap.createBitmap(
 315,425,Bitmap.Config.ARGB_8888);
 this.buffer_class = new int[315*425];
 this.mini_buffer = new int[63*85];
 }
 public boolean onTouchEvent(MotionEvent ev){
 if(ev.getAction() == MotionEvent.ACTION_UP)
 this.finger.bprint = false;
 else
 this.finger.bprint = true;
 this.finger.parametre_x((ev.getX()*63)/315);
 this.finger.parametre_y((ev.getY()*105)/425);
 return true;
 }
 public boolean  onTrackballEvent  (MotionEvent event){
 this.finger.parametre_x(((this.finger.donne_x()+(Math.random()*100))*63)/315);
 this.finger.parametre_y(((this.finger.donne_y()+(Math.random()*100))*105)/425);
 return true;
 }
 @Override
 protected void onDraw(Canvas canvas) {
 int index,r,g,b,index2;
 int[] buffer = this.mini_buffer;
 int p1,p2,p3,p4;
 int respix;
 finger.dessine(this.mini_buffer,63,85);
 for(int y = 85 -2;y>0; y--)
 {
 for(int x = 63-2;x>0; x--)
 {
 index = y*63+ x;
 p1 = buffer[index+63];
 p2 = buffer[index-63];
 p3 = buffer[index+1];
 p4 = buffer[index-1];
 r = (
 (
 ((p1 >> 16) & 0xff)+
 ((p2 >> 16) & 0xff)+
 ((p3 >> 16) & 0xff)+
 ((p4 >> 16) & 0xff)
 )>>2
 )<<16;
 g = (
 (
 ((p1 >> 8) & 0xff)+
 ((p2 >> 8) & 0xff)+
 ((p3 >> 8) & 0xff)+
 ((p4 >> 8) & 0xff)
 )>>2
 )<<8;
 b = (
 (
 ((p1) & 0xff)+
 ((p2) & 0xff)+
 ((p3) & 0xff)+
 ((p4) & 0xff)
 )>>2
 );
 //compute pixel color
 respix = 0xff000000 | r | g | b;
 index2 = (y*5)*315+ (x*5);
 //write color pixels to front screen
 this.buffer_class[index2]= respix;
 this.buffer_class[index2+1]= respix;
 this.buffer_class[index2+2]= respix;
 this.buffer_class[index2+3]= respix;
 this.buffer_class[index2+4]= respix;

 this.buffer_class[index2+315]= respix;
 this.buffer_class[index2+315+1]= respix;
 this.buffer_class[index2+315+2]= respix;
 this.buffer_class[index2+315+3]= respix;
 this.buffer_class[index2+315+4]= respix;

 this.buffer_class[index2+630]= respix;
 this.buffer_class[index2+630+1]= respix;
 this.buffer_class[index2+630+2]= respix;
 this.buffer_class[index2+630+3]= respix;
 this.buffer_class[index2+630+4]= respix;

 this.buffer_class[index2+945]= respix;
 this.buffer_class[index2+945+1]= respix;
 this.buffer_class[index2+945+2]= respix;
 this.buffer_class[index2+945+3]= respix;
 this.buffer_class[index2+945+4]= respix;

 this.buffer_class[index2+1260]= respix;
 this.buffer_class[index2+1260+1]= respix;
 this.buffer_class[index2+1260+2]= respix;
 this.buffer_class[index2+1260+3]= respix;
 this.buffer_class[index2+1260+4]= respix;
 //write color pixels to back screen
 buffer[index] = respix;
 }                
 }      
 this.bufferscreen.setPixels(this.buffer_class,0,315,0,0,315,425);
 canvas.drawBitmap(this.bufferscreen, 0.0f,0.0f,mFramePaint);
 invalidate();
 }
 }
}
<pre>

Here is the finger code

public class Finger extends    Point {

public boolean bprint=true;

Finger(){
super();
this.pw = 10;
this.ph = 10;
this.couleur = Color.MAGENTA;

}

protected void dessine(int buffer [], int w, int h) {
if(!this.bprint)
return;
if(this.donne_x() > 0 && this.donne_x()+pw < w && this.donne_y()> 0 && this.donne_y()+ph < h){ for(int x = 0;x [/caption]

Advertisements

4 Comments

  1. vd11

    Really a good lesson of how to translate a Java Project in Android Java system !!! All is clear and interesting. I read it at work, but i’d like to test it on my own project !!! If only I got time to code…
    Thanks for all, good tutorial, once more 😉

  2. Hasith

    if you don’t mind can i have the source of this. your previous post is awesome. can’t we implement fire work view in android

    • tuanbach

      Thanks for your interest,

      I’m thinking to write more tutorials soon and your comment encourages me 🙂 (about physics engine on Android, if it can interest you)

      I’ll update the post and put the download link here.
      (surely tomorrow)

      Please come back soon and check for updates.

      Regards,
      Tuan

      • Hasith

        hi Tuan,
        thank for your reply. Tuan is there a way to achieve the firework for android??
        i’ve tried to do it but couldn’t achieve it. if you can help me out.

        regards,
        hasith

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: