ok, let me give a detailed description of the problem. I have two java files and one image:
Code:
/**
* AnimationScreen.java
*
* Author: Mark Sohm
*
*/
package com.msohm.animationDemo;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.container.FullScreen;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.system.Characters;
import net.rim.device.api.ui.UiApplication;
import java.util.Date;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.system.Alert;
import net.rim.device.api.util.MathUtilities;
//Optimized avg fps 7100 = 34, 7290 sim = 51 - this wasn't so good after all. :)
//Non optimized (draw house/sun, no clearAll) avg fps 7100 = 17, 7290 sim = 51
//Non optimized (using invalidate, no _drawHouse = false) avg fps 7100 = 25, 7290 sim = 51
//Non optimized (using invalidate, no _drawHouse = false, not overriding paintBackground) avg fps 7100 = 25, 7290 sim = 51
// - but without overriding it things have to be redrawn every time.
//Can't test with just using invalidate vs calling paint directly or else
//the entire screen is cleared.
//Optimized (using invalidate(#, #, #, #), not overriding paintBackground, no clearAll, _drawHouse/sun)
// avg fps 7100 = 51, 7290 sim = 51
//Optimized using invalidate(####), using _drawHouse saves ~ 400 ms per animation vs no _drawHouse.
public class AnimationScreen extends FullScreen
{
private final static boolean SHOW_FRAMERATE = true; //Controls the showing of the framerate dialog.
//Images.
private final static Bitmap brick = Bitmap.getBitmapResource("brick.png");
private int _frameNo; //The current frame number.
private int _runnerXVal; //X coordinate of the runner.
private int _runnerFrame; //The current frame of the runner.
private boolean _currentlyAnimating; //Set to true if an animation is in progress.
//Boolean variables to control what is drawn on the screen.
private boolean _drawRunner;
public AnimationScreen()
{
super();
initialize();
}
//Initialize variables to their starting values.
private void initialize()
{
_drawRunner = true;
_frameNo = 0;
_runnerFrame = 0;
//Draw the screen in its initial state.
invalidate();
}
private class AnimationThread extends Thread
{
Date rightNow = new Date();
long animTime;
int fps;
int tempY = Graphics.getScreenHeight() - 50;
public void run()
{
int count;
//Sleep 50ms to allow the invalidate method in the initialize method to fully execute.
//This ensures that the screen is fully redrawn in its initial state before
//this thread starts modifying drawing values, otherwise we'll see frames out of sync.
try
{
sleep(50);
}
catch (Exception ex)
{
System.out.println("Couldn't sleep!");
}
//Get the start time for the animation (FPS timer).
animTime = rightNow.getTime();
_frameNo = 0;
UiApplication.getUiApplication().invokeAndWait(new Runnable() {
public void run()
{
//We want to clear the entire screen so call invalidate
//instead of invalidate(#, #, #, #).
invalidate();
++_frameNo;
}
});
//Draw the house with the door open.
//We don't need to obtain an event lock when using invalidate(#, #, #, #);
invalidate(170, tempY, 5, 40);
//Draw the person running out of the house.
_drawRunner = true;
//If show framerate is enabled calculate and display
//the freamrate.
if(SHOW_FRAMERATE)
{
//Reset the time.
rightNow = new Date();
//Calculate the number of seconds the animation animated for.
//We selpt for 2710 ms so subtract that value from the total time.
animTime = (rightNow.getTime() - animTime) - 2910;
//Ensure we don't divide by 0.
if ((animTime / 1000) > 0)
{
//If the animation took longer than a second, calculate it.
fps = (int)(_frameNo / (animTime / 1000));
}
else
{
//Otherwise assume 1 second.
fps = _frameNo;
}
//Display the frames per second.
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run()
{
Dialog.alert("Animation time: " + animTime + " ms.\nAvg FPS: " + fps);
}
});
}
//Animation is over.
_currentlyAnimating = false;
}
}
public static Bitmap rotateImage(Bitmap oldB, int angle) throws Exception
{
int w = oldB.getWidth();
int h = oldB.getHeight();
double angRad = (angle % 360)*(Math.PI/180);
Bitmap newB = new Bitmap(w,h);
int[] oldD = new int[w*h];
int[] newD = new int[w*h];
oldB.getARGB(oldD, 0, w, 0, 0, w, h);
int axisX = w/2;
int axisY = h/2;
for(int x = 0; x < oldD.length; x++)
{
int oldX = x%w;
int oldY = x/w;
int op = oldX-axisX;
int adj = oldY-axisY;
double oldT = MathUtilities.atan2(op, adj);
double rad = Math.sqrt((op*op)+(adj*adj));
double newT = oldT+angRad;
int newX = (int)MathUtilities.round((rad*Math.sin(newT))+(double)axisX);
int newY = (int)MathUtilities.round((rad*Math.cos(newT))+(double)axisY);
if(newX<0||newY<0||newX>=w||newY>=h)
{
newD[x] = 0x00000000;
}
else
{
newD[x] = oldD[(newY*w)+newX];
}
}
newB.setARGB(newD, 0, w, 0, 0, w, h);
return newB;
}
//Let's paint!
protected void paint(Graphics graphics)
{
//Get the screen resolution.
int width = Graphics.getScreenWidth();
int height = Graphics.getScreenHeight();
//Counters for the for loops.
int count, count2;
//Variables to hold temporary x and y values.
//Storing these in a defined variable is more efficent
//then calculating them inline as the inline calculation
//will create a temporary int variable for each calculation.
//This would result in the creation of a lot of garbage.
int tempX, tempY;
if (_drawRunner)
{
try{
rotateImage(brick, 59);
}catch (Exception ex) {
ex.printStackTrace();
}
graphics.drawBitmap(width-30, height-60, 20, 10, brick, 0, 0);
} //end if (_drawRunner)
} //end paint
//Invoked when the trackwheel is clicked.
public boolean trackwheelClick(int status, int time)
{
boolean retVal = false;
//Only start the animation if one is not in progress.
if (!_currentlyAnimating)
{
_currentlyAnimating = true;
initialize();
AnimationThread animationThread = new AnimationThread();
animationThread.start();
retVal = true;
}
return retVal;
}
//Invoked when the trackwheel is released.
public boolean trackwheelUnclick(int status, int time)
{
return false;
}
//Invoked when the trackwheel is rolled.
public boolean trackwheelRoll(int amount, int status, int time)
{
return false;
}
//Invoked when a key is pressed.
public boolean keyChar(char key, int status, int time)
{
boolean retVal = false;
int tempY = Graphics.getScreenHeight() - 50;
switch (key)
{
case Characters.ESCAPE:
System.exit(0);
retVal = true;
break;
case Characters.ENTER:
case Characters.SPACE:
//Only start the animation if one is not in progress.
if (!_currentlyAnimating)
{
_currentlyAnimating = true;
initialize();
AnimationThread animationThread = new AnimationThread();
animationThread.start();
retVal = true;
}
break;
default:
break;
}
return retVal;
}
//Implementation of KeyListener.keyStatus.
public boolean keyStatus(int keycode, int time)
{
return false;
}
//Implementation of KeyListener.keyDown.
public boolean keyDown(int keycode, int time)
{
return false;
}
//Implementation of KeyListener.keyRepeat.
public boolean keyRepeat(int keycode, int time)
{
return false;
}
//Implementation of KeyListener.keyUp.
public boolean keyUp(int keycode, int time)
{
return false;
}
} This is the other java file:
Code:
package com.msohm.animationDemo;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.system.*;
import net.rim.device.api.util.*;
import java.util.*;
public class AnimationDemo extends UiApplication
{
//The application enters the event thread by invoking the enterEventDispatcher method.
public static void main(String[] args)
{
AnimationDemo theApp = new AnimationDemo();
theApp.enterEventDispatcher();
}
public AnimationDemo()
{
AnimationScreen animScreen = new AnimationScreen();
pushScreen(animScreen);
}
} And the png image I attached. Now, in the AnimationScreen.java file you can find the following code:
Code:
public static Bitmap rotateImage(Bitmap oldB, int angle) throws Exception
{
int w = oldB.getWidth();
int h = oldB.getHeight();
double angRad = (angle % 360)*(Math.PI/180);
Bitmap newB = new Bitmap(w,h);
int[] oldD = new int[w*h];
int[] newD = new int[w*h];
oldB.getARGB(oldD, 0, w, 0, 0, w, h);
int axisX = w/2;
int axisY = h/2;
for(int x = 0; x < oldD.length; x++)
{
int oldX = x%w;
int oldY = x/w;
int op = oldX-axisX;
int adj = oldY-axisY;
double oldT = MathUtilities.atan2(op, adj);
double rad = Math.sqrt((op*op)+(adj*adj));
double newT = oldT+angRad;
int newX = (int)MathUtilities.round((rad*Math.sin(newT))+(double)axisX);
int newY = (int)MathUtilities.round((rad*Math.cos(newT))+(double)axisY);
if(newX<0||newY<0||newX>=w||newY>=h)
{
newD[x] = 0x00000000;
}
else
{
newD[x] = oldD[(newY*w)+newX];
}
}
newB.setARGB(newD, 0, w, 0, 0, w, h);
return newB;
} And I am using this method inside the paint method:
Code:
protected void paint(Graphics graphics)
{
//Get the screen resolution.
int width = Graphics.getScreenWidth();
int height = Graphics.getScreenHeight();
//Counters for the for loops.
int count, count2;
int tempX, tempY;
if (_drawRunner)
{
try{
rotateImage(brick, 59);
}catch (Exception ex) {
ex.printStackTrace();
}
graphics.drawBitmap(width-30, height-60, 20, 10, brick, 0, 0);
} //end if (_drawRunner)
} //end paint The problem is that the brick image is not rotating at a given angle. I hope you understand my question. Let me know please.