set fps of sprite animation in android - android

i created a sprite class and in this example it runs a spritesheet of 44 frames, i want to set the frame rate to 10fps so the all animation will be 4 seconds more or less.
this is my code, it works but with very slow rate and i cant understand why:
package sprite2.sprite2;
import sprite2.sprite2.Sprite2Activity.Panel;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
public class Sprite {
int x,y;
int xSpeed, ySpeed;
int height, width;
Bitmap b;
Panel ov;
int currentFrame = 0;
int direction = 0;
int framePeriod;
long frameTicker;
int frameNr;
public Sprite(Panel panel, Bitmap _scratch) {
b = _scratch;
ov = panel;
height = 480;
width = b.getWidth()/44;
x = y = 0;
ySpeed = 0;
framePeriod = 1000 / 10;
frameTicker = 0;
frameNr = 44;
// TODO Auto-generated constructor stub
}
public void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
update(System.currentTimeMillis());
int srcX = currentFrame * width;
Rect src = new Rect (srcX, 0 , srcX+width, height);
Rect dest = new Rect(0, 0, canvas.getWidth(), canvas.getHeight());
canvas.drawBitmap(b, src, dest, null);
}
public void update(long videotime) {
if (videotime > frameTicker + framePeriod) {
frameTicker = videotime;
// increment the frame
currentFrame++;
if (currentFrame >= frameNr) {
currentFrame = 0;
}
}
}
}

Related

Animate noise on Android

I want to do some "mist effect" with Perlin 3D noise, the Z axis for number of animation frame.
I'm using a grid of 16x9 LinearLayouts for this, all of them with the same background color, and changing their alpha transparency to the values of Perlin noise.
Works quite well on my tablet, but with 32x18 things begin to crawl a bit, and on my phone I see nothing, just some artifacts - like random image tearing.
Would a custom view and drawing directly on canvas (then upsizing the whole thing) be faster and safer?
Or is the problem generating 3D noise so fast while updating screen?
Drawing directly into canvas is the appropriate way to do it. No more "artifact" problems, and way better framerate. It's also very easy to do.
Here's a working example of a MistView class:
package com.example.yourapp; // don't forget to change this
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.View;
import android.os.Handler;
import java.util.Random;
public class MistView extends View {
SimplexNoise sN = new SimplexNoise(); // you'll need a working SimplexNoise class
Paint[][] paints = null;
float floathex[][];
final static int W = 32;
final static int H = 18;
float widthf, heightf;
int z = 0;
final static int R = 128; // you can play with color here
final static int G = 128;
final static int B = 128;
Random rand = new Random();
final int xoff = random(-100000, 100000);
final int yoff = random(-100000, 100000);
final int zoff = random(-100000, 100000);
Handler myHandler = new Handler();
Runnable myRunnable = new Runnable() {
#Override
public void run() {
z++;
reDraw();
}
};
public MistView(Context context) {
super(context);
this.paints = new Paint[W][H];
for (int w = 0; w < W; w++)
{
for (int h = 0; h < H; h++)
{
this.paints[w][h] = new Paint();
this.paints[w][h].setStyle(Paint.Style.FILL);
}
}
}
public MistView(Context context, AttributeSet attributeSet)
{
super(context, attributeSet);
this.paints = new Paint[W][H];
for (int w = 0; w < W; w++)
{
for (int h = 0; h < H; h++)
{
this.paints[w][h] = new Paint();
this.paints[w][h].setStyle(Paint.Style.FILL);
}
}
}
#Override
public void onDraw(Canvas canvas) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.MULTIPLY);
if (widthf == 0)
widthf = canvas.getWidth() / (float) W;
if (heightf == 0)
heightf = canvas.getHeight() / (float) H;
floathex = sN.generateOctavedSimplexNoise(W, H, z, xoff, yoff, zoff, 8, 0.05f, 0.05f);
for (int w = 0; w < W; w++)
{
for (int h = 0; h < H; h++)
{
int a = Math.round(64* ((floathex[w][h] + 1f)/2f));
if (a < 0)
a = 0;
this.paints[w][h].setColor(Color.argb(a, R, G, B));
canvas.drawRect(w * widthf, h * heightf, (w + 1) * widthf, (h + 1) * heightf, this.paints[w][h]);
}
}
myHandler.postDelayed(myRunnable, 60);
}
protected void reDraw() {
this.invalidate();
}
public int random(int min, int max) {
return (int) (rand.nextFloat() * (max - min + 1)) + min;
}
}

android drawRect not drawing anything

I've run into a wall with this basic drawRect not showing anything and I cannot figure out why.
onDraw
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
canvas.drawCircle(circle1x, circle1y, circleRadius, circlePaint);
canvas.drawCircle(circle2x, circle2y, circleRadius, circlePaint);
canvas.drawRect(rect, rectPaint);
}
setupCropping
Is running before the onDraw and is called from the View constructor to set up all the var's
private void setupCropping() {
final float scale = getContext().getResources().getDisplayMetrics().density;
circleRadius = (int) (circleRadiusDp * scale + 0.5f);
DisplayMetrics metrics = new DisplayMetrics();
((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
displayX = metrics.widthPixels;
displayY = metrics.heightPixels;
cropAreaY = displayY / 3;
cropAreaX = displayX;
//Setting up the circles for adjusting
circle1x = displayX / 2;
circle1y = displayY / 2 - (cropAreaY / 2);
circle2x = displayX / 2;
circle2y = displayY / 2 + (cropAreaY / 2);
canvasPaint = new Paint();
canvasPaint.setColor(0xffffff00);
circlePaint = new Paint();
circlePaint.setColor(0xffffff00);
circlePaint.setAntiAlias(true);
rectPaint = new Paint();
rectPaint.setColor(0xffffff00);
rect = new Rect();
rect.set(0, circle1y, 0, displayY - cropAreaY - circle1y);
}
The drawCircle works perfectly and draws as I'd expect it, I've checked the numbers being given to drawRect and they are set as they should be so I really don't know what could be going wrong here.
Full View class
package com.samplersnapshoot.domiq.samplersnapshoot;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.concurrent.CountDownLatch;
/**
* Created by domix on 14.8.2015..
*/
public class CroppingView extends View {
public final String TAG = "DEBUG";
private Canvas cropCanvas;
private Bitmap canvasBitmap;
private int displayX;
private int displayY;
private int circle1x = 0;
private int circle2x = 0;
private int circle1y = 0;
private int circle2y = 0;
private int circleRadiusDp = 20;
private int circleRadius = 100;
private int cropAreaX = 0;
private int cropAreaY = 0;
private Rect rect;
private Paint canvasPaint;
private Paint circlePaint;
private Paint rectPaint;
public CroppingView(Context context, AttributeSet attrs){
super(context, attrs);
setupCropping();
}
private void setupCropping() {
final float scale = getContext().getResources().getDisplayMetrics().density;
circleRadius = (int) (circleRadiusDp * scale + 0.5f);
DisplayMetrics metrics = new DisplayMetrics();
((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics);
displayX = metrics.widthPixels;
displayY = metrics.heightPixels;
cropAreaY = displayY / 3;
cropAreaX = displayX;
//Setting up the circles for adjusting
circle1x = displayX / 2;
circle1y = displayY / 2 - (cropAreaY / 2);
circle2x = displayX / 2;
circle2y = displayY / 2 + (cropAreaY / 2);
canvasPaint = new Paint();
canvasPaint.setColor(0xffffff00);
circlePaint = new Paint();
circlePaint.setColor(0xffffff00);
circlePaint.setAntiAlias(true);
rectPaint = new Paint();
rectPaint.setARGB(50, 135, 225, 255);
}
/*#Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
displayX = widthMeasureSpec;
displayY = heightMeasureSpec;
invalidate();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}*/
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//Getting bitmap
getPath myPath = new getPath();
final File myFile = myPath.getLastModifiedFile();
final CountDownLatch latch = new CountDownLatch(1);
Thread getCanvasBitmap = new Thread() {
public void run() {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inDither = true;
opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
int i = 0;
while (canvasBitmap == null && ++i < 500) {
System.gc();
Log.d(TAG, "Trying again: " + i);
canvasBitmap = BitmapFactory.decodeFile(myFile.getAbsolutePath(), opt);
}
latch.countDown();
}
};
getCanvasBitmap.start();
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
//Turning into mutable bitmap
myFile.getParentFile().mkdirs();
RandomAccessFile randomAccessFile = null;
try {
randomAccessFile = new RandomAccessFile(myFile, "rw");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
int bWidth = canvasBitmap.getWidth();
int bHeight = canvasBitmap.getHeight();
FileChannel channel = randomAccessFile.getChannel();
MappedByteBuffer map = null;
try {
map = channel.map(FileChannel.MapMode.READ_WRITE, 0, bWidth*bHeight*4);
} catch (IOException e) {
e.printStackTrace();
}
canvasBitmap.copyPixelsToBuffer(map);
canvasBitmap.recycle();
this.canvasBitmap = Bitmap.createBitmap(bWidth, bHeight, Bitmap.Config.ARGB_8888);
map.position(0);
this.canvasBitmap.copyPixelsFromBuffer(map);
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
randomAccessFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
Log.d(TAG, "Display vars:" + displayX + " " + displayY);
canvas.drawCircle(circle1x, circle1y, circleRadius, circlePaint);
canvas.drawCircle(circle2x, circle2y, circleRadius, circlePaint);
rect = new Rect();
rect.set(5, circle1y, displayX, displayY - cropAreaY - circle1y);
canvas.drawRect(rect, rectPaint);
}
}
The class is far from well coded, I have yet to integrate a lot of functionality and clean it up.
rect.set(0, circle1y, 0, displayY - cropAreaY - circle1y);
Both your left and right coordinates are 0. Go figure.
It's
rect.set(int left, int top, int right, int bottom);
EDIT:
Okay I managed to pinpoint the issue. The following line is in your View class
rect.set(5, circle1y, displayX, displayY - cropAreaY - circle1y);
Using the same calculations in your code, for a device with a 480x800 display, I'm getting the following coordinate values.
rect.set(5, 267, 480, 267);
Again, you have overlapping sides of your Rect; Both your top and bottom sides are on the same Y coordinate. This will produce a rectangle of 262 pixels wide and ZERO HEIGHT.
All you need to do is to update your coordinates calculation and supply the proper coordinates. Otherwise, your Rect should draw just fine.

Class does not draw on the canvas

Why does this AI class doesn't draw to the canvas?
package com.dragon.game;
import android.graphics.*;
import com.dragon.game.Game.*;
import java.util.*;
public class AI {
public static Bitmap a;
int x, y, dirX, dirY;
int width, height;
long start, stop;
boolean fg = true;
SurView ov;
Random r = new Random();
public AI(SurView surView, Bitmap ai){
a = ai;
ov = surView;
width = a.getWidth();
height = a.getHeight();
x = Remote.wt / 4;
y = Remote.wt / 4;
}
public void update(){
x++;
}
public void onDraw(Canvas canvas){
if(fg){
x = Remote.wt / 4;
y = Remote.wt / 4;
fg = false;
}
update();
Rect src = new Rect(0, 0, width, height);
Rect dst = new Rect(x, y, x + Remote.pw, y + Remote.pw);
canvas.drawBitmap(a, src, dst, null);
}
}
The reason is that you have initialized Bitmap a inside Public AI method and then you are using it inside onDraw method , you cannot do this , either you have to initialize it globally or you have to give a reference to it

How to set-up automatic collision with just an update() function?

I've just started with Android programming using eclipse and recently came across this problem. I have a bunch of sprites assigned to an arraylist. Now, I want to make it so that collision is detected automatically between sprites but the template I'm currently using can only detect collision between the surface's borders and the moving sprites. Each sprite's position and speed is generated randomly.
How can I change the update() function in my Sprite() class to detect collision between the moving sprites themselves and at the same changing/bouncing to the opposite direction?
Here's my Sprite class template:
package com.gameproject.cai_test;
import java.util.Random;
public Sprite(GameView gameView, Bitmap bmp) {
this.width = bmp.getWidth() / BMP_COLUMNS;
this.height = bmp.getHeight() / BMP_ROWS;
this.gameView = gameView;
this.bmp = bmp;
Random rnd = new Random();
x = rnd.nextInt(gameView.getWidth() - width);
y = rnd.nextInt(gameView.getHeight() - height);
xSpeed = rnd.nextInt(MAX_SPEED * 2) - MAX_SPEED;
ySpeed = rnd.nextInt(MAX_SPEED * 2) - MAX_SPEED;
}
private void update() {
if (x >= gameView.getWidth() - width - xSpeed || x + xSpeed <= 0) {
xSpeed = -xSpeed;
}
x = x + xSpeed;
if (y >= gameView.getHeight() - height - ySpeed || y + ySpeed <= 0) {
ySpeed = -ySpeed;
}
y = y + ySpeed;
currentFrame = ++currentFrame % BMP_COLUMNS;
}
public void onDraw(Canvas canvas) {
update();
int srcX = currentFrame * width;
int srcY = getAnimationRow() * height;
Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
Rect dst = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, src, dst, null);
}
private int getAnimationRow() {
double dirDouble = (Math.atan2(xSpeed, ySpeed) / (Math.PI / 2) + 2);
int direction = (int) Math.round(dirDouble) % BMP_ROWS;
return DIRECTION_TO_ANIMATION_MAP[direction];
}
//gameplay operations
//only values from 0 to 9 will be picked; each assigned its own sprite in the list
public int randomValue(){
Random rnd = new Random();
RandomValue = rnd.nextInt(10);
return RandomValue;
}
//sequence operation from addition, subtraction, multiplication, and division
public int produceSum(){
int addOne = 0;
int addTwo = 0;
Sum = addOne + addTwo;
return Sum;
}
public int produceDiff(){
int deductOne = 0;
int deductTwo = 0;
Difference = deductOne - deductTwo;
return Difference;
}
public int produceProduct(){
int multiOne = 0;
int multiTwo = 0;
Product = multiOne * multiTwo;
return Product;
}
public int produceQuotient(){
int divideOne = 0;
int divideTwo = 0;
Quotient = divideOne / divideTwo;
return Quotient;
}
//each time this returns true, the game is reset with new operation
//compares the value of the bubble picked to the random number being compared through operations
public boolean compareBubbleValue(int randomBubble, int bubbleValue){
if (randomBubble == bubbleValue){
return true;
}
return false;
}
}
As you can see, the update() method only checks the collision between the moving sprites and the borders.
Okey, so lets name your array of sprites spriteArray and loop through it twice
public Rect getBounds(){ //put this in your sprite and enemy-class.
return new Rect(x, y, x+width, y+height);
}
Public void checkCollision(){
for (int i = 0; i<spriteArray.size(); i++){
Rect mySprite = spriteArray.get(i).getBounds(); //create rect for every sprite in array
for (int j = 0; j<spriteArray.size(); i++){
Rect myOtherSprite = spriteArray.get(i).getBounds();
if(mySprite.intersect(myOtherSprite)){ //check if they touch
//Todo code here
}
}
}
}
then you just put this method in your update-method.
Here's the coding for the GameView class (pardon the mess, it's a jumble of codes and comments):
package com.gameproject.cai_test;
public class GameView extends SurfaceView {
private Bitmap bmp;
private Bitmap background;
private Bitmap backgroundImage;
private Bitmap pop;
private SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private List<Sprite> sprites = new ArrayList<Sprite>();
private List<TempSprite> temps = new ArrayList<TempSprite>();
private int[] bubbleValue = {0,1,2,3,4,5,6,7,8,9,10};
private long lastClick;
private SpriteObject timer;
private SpriteObject morebanner;
private SpriteObject formulaBox;
private SpriteObject levelbanner1;
private SurfaceHolder surfaceHolder;
public GameView(Context context) {
super(context);
gameLoopThread = new GameLoopThread(this);
timer = new SpriteObject (BitmapFactory.decodeResource(getResources(), R.drawable.hourglass), 1200, 100);
morebanner = new SpriteObject(BitmapFactory.decodeResource(getResources(), R.drawable.morebanner), 650, 300);
formulaBox = new SpriteObject(BitmapFactory.decodeResource(getResources(), R.drawable.formulabox), 650, 600);
background = BitmapFactory.decodeResource(getResources(), R.drawable.background);
backgroundImage = BitmapFactory.decodeResource(getResources(), R.drawable.background);
pop = BitmapFactory.decodeResource(getResources(), R.drawable.pop);
final Toast toast1 = Toast.makeText(context, "LEVEL 1 start", Toast.LENGTH_LONG);
holder = getHolder();
holder.addCallback(new Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
//setSurfaceSize(getWidth(), getHeight());
toast1.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
toast1.show();
createSprites();
gameLoopThread.setRunning(true);
gameLoopThread.start();
//banner();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
}
private void createSprites() {
sprites.add(createSprite(R.drawable.bubble1));
sprites.add(createSprite(R.drawable.bubble2));
sprites.add(createSprite(R.drawable.bubble3));
sprites.add(createSprite(R.drawable.bubble4));
sprites.add(createSprite(R.drawable.bubble5));
sprites.add(createSprite(R.drawable.bubble6));
sprites.add(createSprite(R.drawable.bubble7));
sprites.add(createSprite(R.drawable.bubble8));
sprites.add(createSprite(R.drawable.bubble9));
sprites.add(createSprite(R.drawable.bubble10));
for (int i = 0; i <= 10; i++){
bubbleValue[i] = sprites.indexOf(i);
}
}
private Sprite createSprite(int resource) {
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resource);
return new Sprite(this, bmp);
}
public void setSurfaceSize(int width, int height)
{
synchronized (surfaceHolder)
{
int canvasWidth = width;
int canvasHeight = height;
backgroundImage = Bitmap.createScaledBitmap(backgroundImage, width, height, true);
}
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
//levelbanner1.draw(canvas);//causes error when applied;for reference only
for (int i = temps.size() - 1; i >= 0; i--) {
temps.get(i).onDraw(canvas);
}
for (Sprite sprite : sprites) {
timer.draw(canvas);
//formulaBox.draw(canvas);
sprite.onDraw(canvas);
}
if (sprites.size() == 0){
morebanner.draw(canvas);
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (System.currentTimeMillis() - lastClick > 300) {
lastClick = System.currentTimeMillis();
float x = event.getX();
float y = event.getY();
synchronized (getHolder()) {
for (int i = sprites.size() - 1; i >= 0; i--) {
Sprite sprite = sprites.get(i);
if (sprite.isCollition(x, y)) {
sprites.remove(sprite);
temps.add(new TempSprite(temps, this, x, y, pop));
break;
}
}
}
}
return true;
}
public void update(){
//for possible check of collision bet. sprites
//
}
}
I've tried assigning a Rect for the sprites here and checking collision on the bottom update() function but result gets awry and produces a runtime error. Probably would be better if its automated in the Sprite class update() function, just as it does for border collision.
If you want to have nice and proper collisions between your sprites, maybe looking at a physics engine like http://www.jbox2d.org/ would help.
It will handle a lot of the complex specific cases for you (tunnelling, time of impact, broadphase for early discard...)

how to modify bitmapmesh sample to include fisheye effect?

I've some sample code that comes with Android that distorts a bitmap image(Bitmapmesh.java). I'm wanting a circle placed on my image that gives a fisheye effect. I'm new to android and especially graphics, is it possible to create this effect in the bitmapmesh sample?
I'm not sure where to start with this so any pointers would be appreciated. Can anyone give me a high level view of what's involved, eg i'd like to place a circle on the image firstly. i've placed buttons over images before that seem to float, this was done by using a relative layout then adding child buttons. what i'm tring to do now is different and will probably involve calling some onDraw method? i also have an algorithm that does the distortion, i'm just not sure how to apply this to the image.
Below is the bitmapmesh code. Can anyone talk me through where to start, even if it's just placing the circle on the image first, then i can tackle implementing the effect.
thanks mat
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import android.content.Context;
import android.graphics.;
import android.os.Bundle;
import android.os.Environment;
import android.view.;
import android.util.FloatMath;
public class BitMapFishEye extends GraphicsActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SampleView(this));
}
private static class SampleView extends View {
private static final int WIDTH = 20;
private static final int HEIGHT = 20;
private static final int COUNT = (WIDTH + 1) * (HEIGHT + 1);
private final Bitmap mBitmap;
private final float[] mVerts = new float[COUNT*2];
private final float[] mOrig = new float[COUNT*2];
private final Matrix mMatrix = new Matrix();
private final Matrix mInverse = new Matrix();
private File tempFile;
private byte[] imageArray;
private static void setXY(float[] array, int index, float x, float y) {
array[index*2 + 0] = x;
array[index*2 + 1] = y;
}
public SampleView(Context context) {
super(context);
setFocusable(true);
/* mBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.beach);*/
tempFile = new File(Environment.getExternalStorageDirectory().
getAbsolutePath() + "/"+"image.jpg");
imageArray = new byte[(int)tempFile.length()];
try{
InputStream is = new FileInputStream(tempFile);
BufferedInputStream bis = new BufferedInputStream(is);
DataInputStream dis = new DataInputStream(bis);
int i = 0;
while (dis.available() > 0) {
imageArray[i] = dis.readByte();
i++;
}
dis.close();
} catch (Exception e) {
e.printStackTrace();
}
BitmapFactory.Options bfo = new BitmapFactory.Options();
bfo.inSampleSize = 5;
mBitmap = BitmapFactory.decodeByteArray(imageArray, 0, imageArray.length, bfo);
float w = mBitmap.getWidth();
float h = mBitmap.getHeight();
// construct our mesh
int index = 0;
for (int y = 0; y <= HEIGHT; y++) {
float fy = h * y / HEIGHT;
for (int x = 0; x <= WIDTH; x++) {
float fx = w * x / WIDTH;
setXY(mVerts, index, fx, fy);
setXY(mOrig, index, fx, fy);
index += 1;
}
}
mMatrix.setTranslate(10, 10);
mMatrix.invert(mInverse);
}
#Override protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFCCCCCC);
canvas.concat(mMatrix);
canvas.drawBitmapMesh(mBitmap, WIDTH, HEIGHT, mVerts, 0,
null, 0, null);
}
private void warp(float cx, float cy) {
final float K = 10000;
float[] src = mOrig;
float[] dst = mVerts;
for (int i = 0; i < COUNT*2; i += 2) {
float x = src[i+0];
float y = src[i+1];
float dx = cx - x;
float dy = cy - y;
float dd = dx*dx + dy*dy;
float d = FloatMath.sqrt(dd);
float pull = K / (dd + 0.000001f);
pull /= (d + 0.000001f);
// android.util.Log.d("skia", "index " + i + " dist=" + d + " pull=" + pull);
if (pull >= 1) {
dst[i+0] = cx;
dst[i+1] = cy;
} else {
dst[i+0] = x + dx * pull;
dst[i+1] = y + dy * pull;
}
}
}
private int mLastWarpX = -9999; // don't match a touch coordinate
private int mLastWarpY;
#Override public boolean onTouchEvent(MotionEvent event) {
float[] pt = { event.getX(), event.getY() };
mInverse.mapPoints(pt);
int x = (int)pt[0];
int y = (int)pt[1];
if (mLastWarpX != x || mLastWarpY != y) {
mLastWarpX = x;
mLastWarpY = y;
warp(pt[0], pt[1]);
invalidate();
}
return true;
}
}
}

Categories

Resources