2

I have started to learn android and java using the android studio beta. As a first simple test app I am trying to get a basic Mandelbrot renderer working. I have gotten it to display, but now I want it faster. Can anyone give advice on the following?

  1. The docs say canvas.drawbitmap is depreciated. What should I use instead? What is the fastest ways to show a bitmap onscreen?

  2. How can I show the progress of the calculations? If I unremark the 2 lines marked "update display after each line has been calculated" there is no updating during the calculations and the extra calls to canvas.drawbitmap really slow it all down (79 seconds compared to 31 seconds without it).

  3. Is there anything I can do to speed up the general math calls?

I have tried to keep it as simple as possible for this example.

Many thanks for any tips for a newbie. I don't want to learn bad habits from the start if possible.

The layout has a single imageview aligned to the screen. The full code is

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.Display;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;

import java.text.DecimalFormat;
import java.util.Random;
import static android.graphics.Color.argb;
import static android.graphics.Color.rgb;

public class myActivity extends Activity  {

    myView myview;
    Bitmap bmp;
    Canvas myCanvas;
    ImageView img;
    Paint paint;
    Boolean started=false;
    Integer ih,iw,i,redraws,fw,fh;
    long startms,finishms;
    Random rnd;

    double xmin,xmax,ymin,ymax,padding,bailout,bailout_squared,stepx,stepy,x,y,magnitude;
    double realiters,tweenval;
    Integer col,colval1,colval2;
    Integer iterations,maxiterations,superx,supery,samplepixels,square_samplepixels,xloop,yloop;
    double zr,zi,cr,ci,xloopdouble,yloopdouble;
    int[] colorpalette = new int[256];
    int[] pixels;
    int r,g,b,r1,g1,b1,r2,g2,b2,totalr,totalg,totalb;

    private void init(){
        //screen size
        Display display = getWindowManager().getDefaultDisplay();
        Point sizePoint = new Point();
        paint = new Paint();
        display.getSize(sizePoint);
        iw=sizePoint.x;
        ih=sizePoint.y;
        //pixels array
        fw=iw;
        fh=ih;
        pixels=new int[fw*fh];
        //create bitmap
        bmp=Bitmap.createBitmap(iw, ih, Bitmap.Config.RGB_565);
        //create canvas
        myCanvas =new Canvas();
        myCanvas.setBitmap(bmp);
        img = (ImageView) findViewById(R.id.imageView1);
        rnd = new Random();
    }

    // calculates and displays the Mandelbrot fractal
    private void Mandelbrot(){

        startms= SystemClock.uptimeMillis();

        //coordinates
//        xmin=-1.6345100402832;
//        xmax=-1.63043992784288;
//        ymin=-0.00209962230258512;
//        ymax=0.00209259351094558;
        xmin=-2.3;
        xmax=2.3;
        ymin=-2.1;
        ymax=2.1;

        fw=iw;
        fh=ih;

        //adjust coords to match screen aspect
        if (iw<ih) {
            padding=(xmax-xmin)/iw*(ih-iw);
            ymin=ymin-padding/2.0;
            ymax=ymax+padding/2.0;
        } else {
            padding=(ymax-ymin)/ih*(iw-ih);
            xmin=xmin-padding/2.0;
            xmax=xmax+padding/2.0;
        }

        bailout=8.0; //needs to be higher than default 2 for the CPM coloring to be smooth
        bailout_squared=bailout*bailout;
        maxiterations=64;
        samplepixels=1;
        square_samplepixels=samplepixels*samplepixels;

        //random color palette
        for (col=0;col<256;col++){
            colorpalette[col]=android.graphics.Color.argb(255,rnd.nextInt(256),rnd.nextInt(256),rnd.nextInt(256));
        }

        stepx=(xmax-xmin)/fw/samplepixels;
        stepy=(ymax-ymin)/fh/samplepixels;

        for (yloop=0;yloop<fh;yloop++){
            for (xloop=0;xloop<fw;xloop++){

                totalr=0;
                totalg=0;
                totalb=0;
                r=0;
                g=0;
                b=0;
                xloopdouble=(double)xloop;
                yloopdouble=(double)yloop;

                for (supery=0;supery<samplepixels;supery++)
                {
                    for (superx=0;superx<samplepixels;superx++)
                    {
                        cr = xmin+xloopdouble/(double)fw*(xmax-xmin)+(stepx*(double)superx);
                        ci = ymin+yloopdouble/(double)fh*(ymax-ymin)+(stepy*(double)supery);

                        zr = 0.0;
                        zi = 0.0;
                        magnitude=0.0;

                        for(iterations=0; iterations<maxiterations; iterations++)
                        {
                            i=iterations;

                            x = (zr * zr - zi * zi) + cr;
                            y = (zi * zr + zr * zi) + ci;

                            magnitude=(x * x + y * y);
                            if(magnitude>bailout_squared) break;

                            zr = x;
                            zi = y;
                        }

                        if (iterations>=maxiterations) {
                            r=0;
                            g=0;
                            b=0;
                        } else {
                            //CPM smooth colors
                            realiters=iterations+1-((Math.log(Math.log(Math.sqrt(magnitude)))/Math.log(2.0)));
                            colval1=(int) Math.floor(realiters % 255);
                            colval2=(colval1+1) % 255;
                            tweenval=realiters-Math.floor(realiters);
                            r1=Color.red(colorpalette[colval1]);
                            g1=Color.green(colorpalette[colval1]);
                            b1=Color.blue(colorpalette[colval1]);
                            r2=Color.red(colorpalette[colval2]);
                            g2=Color.green(colorpalette[colval2]);
                            b2=Color.blue(colorpalette[colval2]);
                            r=(int) (r1+((r2-r1)*tweenval));
                            g=(int) (g1+((g2-g1)*tweenval));
                            b=(int) (b1+((b2-b1)*tweenval));
                        }
                        totalr=totalr+r;
                        totalg=totalg+g;
                        totalb=totalb+b;
                    }
                }

                r=(int) totalr/square_samplepixels;
                g=(int) totalg/square_samplepixels;
                b=(int) totalb/square_samplepixels;

                //update pixels array
                pixels[xloop+yloop*fw]=rgb(r, g, b);
            }

            //update display after each line has been calculated
            //myCanvas.drawBitmap(pixels,0,fw,0,0,fw,fh,false,null);
            //if (img != null) img.invalidate();
        }

        myCanvas.drawBitmap(pixels,0,fw,0,0,fw,fh,false,null);
        finishms=SystemClock.uptimeMillis();
    }


    private void updateTimeTaken(){
        //turn antialiasing on
        paint.setAntiAlias(true);
        // draw some text using FILL style
        paint.setStyle(Paint.Style.FILL);
        paint.setTextSize(30);

        DecimalFormat myFormatter = new DecimalFormat("#,###,###");

        paint.setColor(Color.BLACK);
        myCanvas.drawText("Time taken = " + myFormatter.format(finishms - startms) + " ms", 15, 45, paint);
        paint.setColor(Color.WHITE);
        myCanvas.drawText("Time taken = " + myFormatter.format(finishms - startms) + " ms", 14, 44, paint);

        paint.setColor(Color.BLACK);
        myCanvas.drawText("Screen size = " + String.valueOf(iw) + " x " + String.valueOf(ih), 15, 85, paint);
        paint.setColor(Color.WHITE);
        myCanvas.drawText("Screen size = " + String.valueOf(iw) + " x " + String.valueOf(ih), 14, 84, paint);

    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        //fullscreen no menu
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        redraws=0;
        super.onCreate(savedInstanceState);
        myview = new myView(this);

        setContentView(myview);

        init();

        started=true;

        Mandelbrot();
        updateTimeTaken();

    }

    private class myView extends View{
        public myView(Context context){
            super(context);
        }

        @Override protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            //draw off screen bitmap to screen
            if (started==true){
                canvas.drawBitmap(bmp,0,0,paint);
            }

        }

    }
}
Some1Else
  • 715
  • 11
  • 26
  • 1
    Is there any reason why you are using `Integer` instead of `int`? – Azar Nov 10 '14 at 22:25
  • @Azar I had no idea of the difference. Changing all Integers to ints is almost twice as fast. Thanks for pointing that out. – Some1Else Nov 10 '14 at 22:35
  • 1
    That's a surprisingly dramatic difference, but it _does_ save quite a bit of overhead. Glad I could help. – Azar Nov 10 '14 at 22:36

0 Answers0