All Downloads are FREE. Search and download functionalities are using the official Maven repository.

playn.android.AndroidCanvas Maven / Gradle / Ivy

/**
 * Copyright 2011 The PlayN Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package playn.android;

import java.util.LinkedList;

import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;

import pythagoras.f.FloatMath;

import playn.core.*;

public class AndroidCanvas extends Canvas {

  private static Matrix m = new Matrix();
  private static Rect rect = new Rect();
  private static RectF rectf = new RectF();

  private final android.graphics.Canvas canvas;
  private final LinkedList paintStack = new LinkedList<>();

  public AndroidCanvas(Graphics gfx, AndroidImage image) {
    super(gfx, image);
    canvas = new android.graphics.Canvas(image.bitmap());
    paintStack.addFirst(new AndroidCanvasState());
    float factor = image.scale().factor;
    scale(factor, factor);
  }

  void draw(Bitmap bitmap, float dx, float dy, float dw, float dh,
            float sx, float sy, float sw, float sh) {
    rect.set((int) sx, (int) sy, (int) (sx + sw), (int) (sy + sh));
    rectf.set(dx, dy, dx + dw, dy + dh);
    canvas.drawBitmap(bitmap, rect, rectf, currentState().prepareImage());
    isDirty = true;
  }

  public float alpha() {
    return currentState().alpha;
  }

  @Override public Canvas clear() {
    canvas.drawColor(0, PorterDuff.Mode.SRC);
    isDirty = true;
    return this;
  }

  @Override public Canvas clearRect(float x, float y, float width, float height) {
    canvas.save();
    canvas.clipRect(x, y, x + width, y + height);
    // drawColor: "Fill the entire canvas' bitmap (restricted to the current clip) with the
    // specified color and porter-duff xfermode."
    canvas.drawColor(0, PorterDuff.Mode.SRC);
    canvas.restore();
    isDirty = true;
    return this;
  }

  @Override public Canvas clip(Path clipPath) {
    canvas.clipPath(((AndroidPath) clipPath).path);
    return this;
  }

  @Override public Canvas clipRect(float x, float y, float width, float height) {
    canvas.clipRect(x, y, x + width, y + height);
    return this;
  }

  @Override public Canvas drawLine(float x0, float y0, float x1, float y1) {
    canvas.drawLine(x0, y0, x1, y1, currentState().prepareStroke());
    isDirty = true;
    return this;
  }

  @Override public Canvas drawPoint(float x, float y) {
    canvas.drawPoint(x, y, currentState().prepareStroke());
    isDirty = true;
    return this;
  }

  @Override public Canvas drawArc(float cx, float cy, float r, float startAngle, float arcAngle) {
    float left = cx - r;
    float top = cy - r;
    float right = cx + r;
    float bottom = cy + r;
    rectf.set(left, top, right, bottom);
    canvas.drawArc(rectf, -FloatMath.toDegrees(startAngle), -FloatMath.toDegrees(arcAngle),
                   false, currentState().prepareStroke());
    isDirty = true;
    return this;
  }

  @Override public Canvas drawText(String text, float x, float y) {
    canvas.drawText(text, x, y, currentState().prepareFill());
    isDirty = true;
    return this;
  }

  @Override public Canvas fillCircle(float x, float y, float radius) {
    canvas.drawCircle(x, y, radius, currentState().prepareFill());
    isDirty = true;
    return this;
  }

  @Override public Canvas fillPath(Path path) {
    canvas.drawPath(((AndroidPath) path).path, currentState().prepareFill());
    isDirty = true;
    return this;
  }

  @Override public Canvas fillRect(float x, float y, float width, float height) {
    float left = x;
    float top = y;
    float right = left + width;
    float bottom = top + height;
    canvas.drawRect(left, top, right, bottom, currentState().prepareFill());
    isDirty = true;
    return this;
  }

  @Override public Canvas fillRoundRect(float x, float y, float width, float height, float radius) {
    rectf.set(x, y, x + width, y + height);
    canvas.drawRoundRect(rectf, radius, radius, currentState().prepareFill());
    isDirty = true;
    return this;
  }

  @Override public Canvas fillText(TextLayout layout, float x, float y) {
    ((AndroidTextLayout)layout).draw(canvas, x, y, currentState().prepareFill());
    isDirty = true;
    return this;
  }

  @Override public Canvas restore() {
    canvas.restore();
    paintStack.removeFirst();

    assert paintStack.size() > 0 : "Unbalanced save/restore";
    return this;
  }

  @Override public Canvas rotate(float angle) {
    canvas.rotate(rad2deg(angle));
    return this;
  }

  @Override public Canvas save() {
    canvas.save();
    paintStack.addFirst(new AndroidCanvasState(currentState()));
    return this;
  }

  @Override public Canvas scale(float x, float y) {
    canvas.scale(x, y);
    return this;
  }

  @Override public Canvas setAlpha(float alpha) {
    currentState().setAlpha(alpha);
    return this;
  }

  @Override public Canvas setCompositeOperation(Composite composite) {
    currentState().setCompositeOperation(composite);
    return this;
  }

  @Override public Canvas setFillColor(int color) {
    currentState().setFillColor(color);
    return this;
  }

  @Override public Canvas setFillGradient(Gradient gradient) {
    currentState().setFillGradient((AndroidGradient) gradient);
    return this;
  }

  @Override public Canvas setFillPattern(Pattern pattern) {
    currentState().setFillPattern((AndroidPattern) pattern);
    return this;
  }

  @Override public Canvas setLineCap(LineCap cap) {
    currentState().setLineCap(cap);
    return this;
  }

  @Override public Canvas setLineJoin(LineJoin join) {
    currentState().setLineJoin(join);
    return this;
  }

  @Override public Canvas setMiterLimit(float miter) {
    currentState().setMiterLimit(miter);
    return this;
  }

  @Override public Canvas setStrokeColor(int color) {
    currentState().setStrokeColor(color);
    return this;
  }

  @Override public Canvas setStrokeWidth(float strokeWidth) {
    currentState().setStrokeWidth(strokeWidth);
    return this;
  }

  @Override public Image snapshot() {
    Bitmap bitmap = ((AndroidImage)this.image).bitmap();
    return new AndroidImage(gfx, image.scale(), bitmap.copy(bitmap.getConfig(), false), "");
  }

  @Override public Canvas strokeCircle(float x, float y, float radius) {
    canvas.drawCircle(x, y, radius, currentState().prepareStroke());
    isDirty = true;
    return this;
  }

  @Override public Canvas strokePath(Path path) {
    canvas.drawPath(((AndroidPath) path).path, currentState().prepareStroke());
    isDirty = true;
    return this;
  }

  @Override public Canvas strokeRect(float x, float y, float width, float height) {
    float left = x;
    float top = y;
    float right = left + width;
    float bottom = top + height;
    canvas.drawRect(left, top, right, bottom, currentState().prepareStroke());
    isDirty = true;
    return this;
  }

  @Override public Canvas strokeRoundRect(float x, float y, float width, float height,
                                          float radius) {
    rectf.set(x, y, x + width, y + height);
    canvas.drawRoundRect(rectf, radius, radius, currentState().prepareStroke());
    isDirty = true;
    return this;
  }

  @Override public Canvas strokeText(TextLayout layout, float x, float y) {
    ((AndroidTextLayout)layout).draw(canvas, x, y, currentState().prepareStroke());
    isDirty = true;
    return this;
  }

  @Override public Canvas transform(float m11, float m12, float m21, float m22,
                                    float dx, float dy) {
    m.setValues(new float[] {m11, m21, dx, m12, m22, dy, 0, 0, 1});
    canvas.concat(m);
    return this;
  }

  @Override public Canvas translate(float x, float y) {
    canvas.translate(x, y);
    return this;
  }

  @Override protected AndroidCanvas gc() {
    return this;
  }

  private AndroidCanvasState currentState() {
    return paintStack.peek();
  }

  private float rad2deg(double deg) {
    return (float) (deg * 360 / (2 * Math.PI));
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy