title: What is the most performant way to draw a rotated bitmap on an Android canvas?
body: <p>I'm working on an app where we hand rolled some star maps. So I don't have to talk in the abstract, here is the app in question: <a href="https://play.google.com/store/apps/details?id=com.tw.fireballs" rel="nofollow">https://play.google.com/store/apps/details?id=com.tw.fireballs</a></p>
  
  <p>If you look on the store listing, you can see we use an image just above the horizon...mostly because it looks super pretty. It's not an issue on lower resolution devices, they don't seem to suffer a huge issue rendering it due to lower number of pixels involved. On a higher resolution device like my HTC One or my wifes Nexus 5, there is a big framerate drop when it's on the screen. It's not bad enough to prevent me releasing it, but I'd like to improve it if possible.</p>
  
  <p>I'm currently just using a SurfaceView, and drawing to a canvas acquired by mSurfaceHolder.lockCanvas(null), so it's not hardware accelerated. I tried implementing it as a regular view which is, but overall it actually went slower, so before I take the plunge into OpenGL land I want to explore if there is something I can do to speed this up.</p>
  
  <p>Essentially, we start with a thin (opaque) image "slice" through the horizon, scale it up to the size of the diagonal of the screen and rotate it around to match the orientation of the device.</p>
  
  <p>The drawing code is as follows:</p>
  
  <pre><code>private void loadResources() {
      BitmapFactory.Options options = new BitmapFactory.Options();
      options.inPreferredConfig = Bitmap.Config.RGB_565;
      mHorizonImage = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.star_map_background, options);
  }
  
  @Override
  public void updateDimensions(int width, int height) {
      super.updateDimensions(width, height);
  
      int horizonHeight = mCanvasHeight / 3;
      int horizonWidth = (int) Math.sqrt(Math.pow(mCanvasHeight, 2) + Math.pow(mCanvasWidth, 2));
  
      mHorizonImage = Bitmap.createScaledBitmap(mHorizonImage, horizonWidth, horizonHeight, false);
  }
  
  @Override
  public void drawOn(Canvas canvas) {
      double upScreen = -mProjection.distanceFromScreen * Math.tan(Math.toRadians(mOrientation.elevation));
      double rightWithTiltCheat = upScreen * Math.sin(Math.toRadians(mOrientation.tilt));
      double upWithTiltCheat = upScreen * Math.cos(Math.toRadians(mOrientation.tilt));
  
      float x = (float) (mCanvasWidth / 2 * (1 + rightWithTiltCheat / mProjection.screenWidthInCm));
      float y = (float) (mCanvasHeight / 2 * (1 - upWithTiltCheat / mProjection.screenHeightInCm));
  
      canvas.save();
      canvas.translate(x, y);
      canvas.rotate((float) mOrientation.tilt);
      canvas.drawBitmap(mHorizonImage, -mHorizonImage.getWidth() / 2, -mHorizonImage.getHeight(), null);
      canvas.restore();
  }
  </code></pre>
  
  <p>Is there a more efficient way to do this that won't be so affected by screen resolution? We've bandied around a few ideas, but I'd be keen to hear from someone who knows this stuff better than I. If you have any questions, please ask, I'd be grateful for any assistance.</p>
  
  <p>Cheers,
  Nathan</p>