onDrawFrame, requestRender, and render thread? | OpenGL ES 2.0 - android

i have a problem running my app using an external Thread for game loop in OpenGL ES 2.0.
here is my onCreate in my Starting class:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLView = new MyGLView(this);
System.out.println(running);
setContentView(mGLView);
loop = new GameLoop();
//loop.run(); <- this is supposed to run the loop but when its called,
// nothing really appears on screen. just title of the app.
}
my GameLoop Class
private final static int maxFPS = 30;
private final static int maxFrameSkips = 5;
private final static int framePeriod = 1000 / maxFPS;
public static boolean running;
public final static String TAG = "test";
public GameLoop() {
}
#Override
public void run() {
running = StartPoint.isRunning();
long beginTime;
long timeDiff;
int sleepTime;
int framesSkipped;
sleepTime = 0;
while (running) {
running = StartPoint.isRunning();
beginTime = System.currentTimeMillis();
framesSkipped = 0;
StartPoint.mGLView.requestRender(); // <- supposed to re-render?
timeDiff = System.currentTimeMillis() - beginTime;
sleepTime = (int) (framePeriod - timeDiff);
if (sleepTime > 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
}
while (sleepTime < 0 && framesSkipped < maxFrameSkips) {
sleepTime += framePeriod;
framesSkipped++;
Log.d(TAG, "Frames Skipped");
}
}
}
and finally my renderer class:
private static final String TAG = "Renderer";
BoundsSquare square;
private final float[] mMVPMatrix = new float[16];
private final float[] mProjMatrix = new float[16];
private final float[] mVMatrix = new float[16];
private final float[] mRotationMatrix = new float[16];
private int camWidth,camHeight;
Camera2D cam;
Vector3 vec;
public long cycle = 0; // used this to determine how many cycles
//went through, it is stuck on cycle 0, nothing else happens after first render
#Override
public void onDrawFrame(GL10 nope) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
//set camera position
cam.setFrustum(mProjMatrix, mVMatrix, mMVPMatrix);
square.draw(mMVPMatrix);
//square.animate(tick);
//square.setBounds(vec);
System.out.println("Cycle " + cycle + " Ended");
cycle++;
}
#Override
public void onSurfaceChanged(GL10 nope, int width, int height) {
cam.setRatio(width, height);
GLES20.glViewport(0, 0, width, height);
}
public static int loadShader(int type, String shaderCode) {
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
#Override
public void onSurfaceCreated(GL10 gl,
javax.microedition.khronos.egl.EGLConfig config) {
GLES20.glClearColor(0.0f, 0.0f, 1.0f, 0.5f);
camWidth=480;camHeight=320;
cam= new Camera2D(0, 0, camHeight, camWidth);
// initialize a square
vec = new Vector3 (10,10,40,90);
square = new BoundsSquare(vec);
System.out.println("Surface Created");
}
so basically what happens is that if i do not call loop.run(); i get a static picture, which is basically one cycle of onDrawFrame, after its done with this, nothing else pops up on the logCat.
the next thing that happens is if i do call loop.run(), basically the loop goes through forever and everything, but, nothing appears on the screen. i just see a title screen, not the glView.
What am i doing wrong? Is there another way to update the Screen?

Threads must be started with start() not run().

Related

How to fill polygon in android using opengl-es 2.0?

I want to draw polygon as shown in images and fill it with colors.
I have tried polygon using triangle but it will not help me.Anyone know please help me out.
OpenGLProjectRenderer.java
public class OpenGLProjectRenderer implements Renderer {
List<Float> points = new ArrayList<Float>();
private static final String TAG = "Renderer";
private static final int POSITION_COMPONENT_COUNT = 2;
private static final int BYTES_PER_FLOAT = 4;
private FloatBuffer vertexData = ByteBuffer
.allocateDirect(20000 * BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
private Context context;
private int program;
private static final String A_POSITION = "a_Position";
private int aPositionLocation;
private static final String U_COLOR = "u_Color";
private int uColorLocation;
private HashMap<Integer, ArrayList<Float>> lines = new HashMap<Integer, ArrayList<Float>>();
int position = 0;
public OpenGLProjectRenderer(Context context) {
this.context = context;
}
#Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUniform4f(uColorLocation, 1.0f, 0.0f, 0.0f, 1.0f);
for (int p = 0; p < lines.size(); p++) {
vertexData.put(toFloatarray(lines.get(p)));
int vertices = (int) lines.get(p).size() / 2;
int b = vertices % 4 == 0 ? vertices-1 : vertices - 2;
Log.d(TAG,""+lines.size());
glDrawArrays(GLES20.GL_LINE_LOOP, 0, lines.size());
vertexData.clear();
}
}
#Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
}
#Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
String vertexShaderSource = TextResourceReader.readTextFileFromResource(
context, R.raw.simple_vertex_shader);
String fragmentShaderSource = TextResourceReader.readTextFileFromResource(
context, R.raw.simple_fragment_shader);
int vertexShader = ShaderHelper.compileVertexShader(vertexShaderSource);
int fragmentShader = ShaderHelper
.compileFragmentShader(fragmentShaderSource);
program = ShaderHelper.linkProgram(vertexShader, fragmentShader);
ShaderHelper.validateProgram(program);
glUseProgram(program);
uColorLocation = glGetUniformLocation(program, U_COLOR);
aPositionLocation = glGetAttribLocation(program, A_POSITION);
vertexData.position(0);
glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT,
GL_FLOAT, false, 0, vertexData);
glEnableVertexAttribArray(aPositionLocation);
}
ArrayList<Float> temp = new ArrayList<Float>();
public void handleTouchPress(float normalizedX, float normalizedY) {
Log.v(TAG + " handleTouchPress", points.size() + "");
temp.add(normalizedX);
temp.add(normalizedY);
lines.put(position, temp);
}
public void handleTouchDrag(float normalizedX, float normalizedY) {
Log.v(TAG + " handleTouchDrag", points.size() + "");
}
public float[] toFloatarray(List<Float> floatList) {
float[] floatArray = new float[floatList.size()];
int i = 0;
for (Float f : floatList) {
floatArray[i++] = (f != null ? f : Float.NaN);
}
return floatArray;
}
public void handleTouchUp(float normalizedX, float normalizedY) {
Log.v(TAG + " handleTouchUp", points.size() + "");
position++;
}}
Using above code I am able to draw polygon using above code using GL_LINE_LOOP but not able to fill created polygon.
OpenGL ES 2.0 support drawing only triangles as a basic primitives. There are 3 ways of drawing polygons using triangles,
1) Triangles
2) Triangle Strips
3) Triangle Fan
In your case you can try triangle Fan to draw a polygon, provided you know point inside the plan.
Here is an example of drawing a circle.

Fatal exception (Thread)

I wanted to make some water ripples in my android application so I used this javascript code http://jsfiddle.net/esteewhy/5Ht3b/6/ converted into C code like it is shown here Live Wallpaper Water Ripple Effect (by esteewhy).
I have a main activity, which calls the water ripples activity after clicking a button. The water ripples are working great with my mutable bitmap, the problem is when I clicked the "back" button of the android device, the system crashes throwing this error:
FATAL EXCEPTION: Thread-2556
java.lang.NullPointerException
at com.wheelly.whater.WaterView.onDraw (line 149)
at com.wheelly.whater.WaterView$GameThread.run (line 255)
I guess there is some problem handling the Thread or the activities themselves.
Here is the code of the Water Ripples:
public class WaterView extends SurfaceView implements SurfaceHolder.Callback {
GameThread thread;
public static Bitmap icon;
//Measure frames per second.
long now;
int framesCount=0;
int framesCountAvg=0;
long framesTimer=0;
Paint fpsPaint=new Paint();
//Frame speed
long timeNow;
long timePrev = 0;
long timePrevFrame = 0;
long timeDelta;
private int width = 480;
private int height = 800;
private short riprad = 6;
boolean flip;
private short[] ripplemap, last_map;
Bitmap ripple;
private static final String TAG = null;
private Rippler rippler;
public WaterView(Context context) {
super(context);
initialize();
}
void initialize() {
//CB
icon = BitmapFactory.decodeResource(getResources(), R.drawable.sand100);
icon = convertToMutable(icon);
//--
rippler = new NativeRippler();
reinitgGlobals();
fpsPaint.setTextSize(30);
//Set thread
getHolder().addCallback(this);
setFocusable(true);
}
void reinitgGlobals() {
int size = width * (height + 2) * 2;
ripplemap = new short[size];
last_map = new short[size];
Bitmap texture = createBackground(width, height); // this creates a MUTABLE bitmap
ripple = texture;
_td = new int[width * height];
texture.getPixels(_td, 0, width, 0, 0, width, height);
_rd = new int[width * height];
}
void randomizer() {
final Random rnd = new Random();
final Handler disHAndler = new Handler();
final Runnable disturbWater = new Runnable() {
#Override
public void run() {
disturb(rnd.nextInt(width), rnd.nextInt(height));
disHAndler.postDelayed(this, 7000);
}
};
disHAndler.post(disturbWater);
}
private static Bitmap createBackground(int width, int height) {
Canvas cb = new Canvas (icon);
cb.save();
cb.restore();
return icon;
}
private Bitmap convertToMutable(Bitmap bitmap) {
try {
File file = new File("/mnt/sdcard/sample/temp.txt");
file.getParentFile().mkdirs();
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
int width_mutable = bitmap.getWidth();
int height_mutable = bitmap.getHeight();
FileChannel channel = randomAccessFile.getChannel();
MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, width_mutable*height_mutable*4);
bitmap.copyPixelsToBuffer(map);
bitmap.recycle();
bitmap = Bitmap.createBitmap(width_mutable, height_mutable, Config.ARGB_8888);
map.position(0);
bitmap.copyPixelsFromBuffer(map);
channel.close();
randomAccessFile.close();
} catch (FileNotFoundException e) {
Log.i(TAG, "::onActivityResult:" + ""+Log.getStackTraceString(e));
} catch (IOException e) {
Log.i(TAG, "::onActivityResult:" + ""+Log.getStackTraceString(e));
}
return bitmap;
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
reinitgGlobals();
}
#Override
protected void onDraw(android.graphics.Canvas canvas) {
super.onDraw(canvas);
newframe();
canvas.drawBitmap(ripple, 0, 0, null);
//Measure frame rate (unit: frames per second).
now=System.currentTimeMillis();
canvas.drawText(framesCountAvg+" fps", 40, 70, fpsPaint);
framesCount++;
if(now-framesTimer>1000) {
framesTimer=now;
framesCountAvg=framesCount;
framesCount=0;
}
}
/**
* Disturb water at specified point
*/
private void disturb(int dx, int dy) {
rippler.disturb(dx, dy, width, height, riprad, ripplemap, flip);
}
int[] _td;
int[] _rd;
/**
* Generates new ripples
*/
private void newframe() {
System.arraycopy(_td, 0, _rd, 0, width * height);
flip = !flip;
rippler.transformRipples(height, width, ripplemap, last_map, _td, _rd, flip);
ripple.setPixels(_rd, 0, width, 0, 0, width, height);
}
#Override
public synchronized boolean onTouchEvent(MotionEvent event) {
disturb((int)event.getX(), (int)event.getY());
return true;
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
thread = new GameThread(getHolder(), this);
thread.setRunning(true);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
boolean retry = true;
thread.setRunning(false);
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
}
}
}
class GameThread extends Thread {
private SurfaceHolder surfaceHolder;
private WaterView gameView;
private boolean run = false;
public GameThread(SurfaceHolder surfaceHolder, WaterView gameView) {
this.surfaceHolder = surfaceHolder;
this.gameView = gameView;
}
public void setRunning(boolean run) {
this.run = run;
}
public SurfaceHolder getSurfaceHolder() {
return surfaceHolder;
}
#Override
public void run() {
Canvas c;
while (run) {
c = null;
//limit frame rate to max 60fps
timeNow = System.currentTimeMillis();
timeDelta = timeNow - timePrevFrame;
if ( timeDelta < 16) {
try {
Thread.sleep(16 - timeDelta);
}
catch(InterruptedException e) {
}
}
timePrevFrame = System.currentTimeMillis();
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
//call methods to draw and process next fame
gameView.onDraw(c);
}
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
I found the solution:
I had to interrupt the thread in the onPause method of the activity instead of doing it in the onStop method. Now it is just working fine.
Thanks a LOT to all of you for helping me with that problem.
you should shut down your working thread in the method Activity.onStop
#Override
protected void onStop() {
thread.interrupt();
super.onStop();
}
in the run method of GameThread check if thread was interrupted right before you call gameView.onDraw(c); like this:
if(isInterrupted()) {
break;
}
gameView.onDraw(c);
BTW, probably it would be better if you replace gameView.onDraw(c) with gameView.invalidate();
Don't call onDraw directly on a view, but rather call gameView.invalidate()
synchronized (surfaceHolder) {
//call methods to draw and process next fame
gameView.invalidate();
}
If it doesn't work, try using debugger with a breakpoint to see which variable is null exactly

Consequences of recycling Bitmaps?

Hi in my application I have an explosion animation that comes up extremely often. when creating an explosion I load 3 images from resources then once the explosion animation is over I recycle those 3 images. I am constantly doing this and have noticed framerate drops. Is their a better way of doing this like static bitmaps or something?
I once made an application, a simple canvas on which bombs exploded.
I used a tiled bitmap composed of each step of the explosion and drew only a part of it, which changes often in order to create the animation effect.
It updates steps automatically following currentTimestamp
So this is the explosion class:
public class ExplosionAnimated {
private static final String TAG = ExplosionAnimated.class.getSimpleName();
private Bitmap mBitmap;
private Rect mSourceRect;
private int mFrameCountX;
private int mFrameCountY;
private int mCurrentFrame;
private long mFrameTicker;
private int mFramePeriod;
private int mSpriteWidth;
private int mSpriteHeight;
private int mX;
private int mY;
private boolean mFinished = false;
public ExplosionAnimated(Bitmap pBitmap, int pX, int pY,
int pFrameCountX, int pFrameCountY, int pFps) {
this.mBitmap = pBitmap;
this.mX = pX;
this.mY = pY;
this.mCurrentFrame = 0;
this.mFrameCountX = pFrameCountX;
this.mFrameCountY = pFrameCountY;
this.mSpriteWidth = pBitmap.getWidth() / pFrameCountX;
this.mSpriteHeight = pBitmap.getHeight() / pFrameCountY;
this.mSourceRect = new Rect(0, 0, this.mSpriteWidth, this.mSpriteHeight);
this.mFramePeriod = 1000 / pFps;
this.mFrameTicker = 0l;
}
public void update(long gameTime) {
if (gameTime > this.mFrameTicker + this.mFramePeriod) {
this.mFrameTicker = gameTime;
this.mCurrentFrame++;
if (this.mCurrentFrame >= this.mFramePeriod) {
this.mCurrentFrame = 0;
this.mFinished = true;
}
}
if (!this.mFinished) {
this.mSourceRect.left = this.mCurrentFrame * this.mSpriteWidth;
this.mSourceRect.right = this.mSourceRect.left + this.mSpriteWidth;
}
}
public void draw(Canvas canvas) {
Rect destRect = new Rect(this.mX, this.mY,
this.mX + this.mSpriteWidth,
this.mY + this.mSpriteHeight);
canvas.drawBitmap(this.mBitmap, this.mSourceRect, destRect, null);
}
public boolean isFinished() {
return this.mFinished;
}
}
These are methods from an object (Bomb.java for exemple) that starts explosion and draw it:
public void explode(Context pContext, Canvas pCanvas) {
this.mState = State.EXPLODING;
this.mExplosion = new ExplosionAnimated(this.mExplosionBitmap,
(int) this.mX, (int) this.mY, 7, 3, 7);
}
public void doDraw(Canvas pCanvas) {
if (this.mState == State.EXPLODING) {
if (this.mExplosion.isFinished()) {
this.mState = State.EXPLODED;
} else {
this.mExplosion.update(System.currentTimeMillis());
this.mExplosion.draw(pCanvas);
}
} else {
pCanvas.drawBitmap(this.mBombBitmap, this.mX, this.mY, null);
}
}
I used a Thread and a SurfaceView to continually draw the bomb (or the explosion), giving just the currentTimestamp to update the explosion.
I hope it helps, and if you need I can show and explain more code

Motion Streak for specific Sprites?

AndEngine GLES2 has an example for a full scene motion streak/blur which works great, but I would like to apply that motion blur to only specific sprites.
Kind of like I don't want my characters to motion blur, just the spells(Sprites).
This is what I am using to do a motion blur right now, it is simply the AndEngine example, but the problem is it seems to take a snapshot of the whole screen, apply an aplha, and then merge it with the next frame of the screen, and I would only like to apply this "alpha" blurring affect to individual sprites.
#Override
public Engine onCreateEngine(EngineOptions pEngineOptions) {
return new Engine(pEngineOptions) {
private static final int RENDERTEXTURE_COUNT = 2;
private boolean mRenderTextureInitialized;
private final RenderTexture[] mRenderTextures = new RenderTexture[RENDERTEXTURE_COUNT];
private final Sprite[] mRenderTextureSprites = new Sprite[RENDERTEXTURE_COUNT];
private int mCurrentRenderTextureIndex = 0;
#Override
public void onDrawFrame(final GLState pGLState) throws InterruptedException {
final boolean firstFrame = !this.mRenderTextureInitialized;
if(firstFrame) {
this.initRenderTextures(pGLState);
this.mRenderTextureInitialized = true;
}
final int surfaceWidth = this.mCamera.getSurfaceWidth();
final int surfaceHeight = this.mCamera.getSurfaceHeight();
final int currentRenderTextureIndex = this.mCurrentRenderTextureIndex;
final int otherRenderTextureIndex = (currentRenderTextureIndex + 1) % RENDERTEXTURE_COUNT;
this.mRenderTextures[currentRenderTextureIndex].begin(pGLState, false, true);
{
/* Draw current frame. */
super.onDrawFrame(pGLState);
/* Draw previous frame with reduced alpha. */
if(!firstFrame) {
if(Info.motionStreaking) {
this.mRenderTextureSprites[otherRenderTextureIndex].setAlpha(0.9f);
this.mRenderTextureSprites[otherRenderTextureIndex].onDraw(pGLState, this.mCamera);
}
}
}
this.mRenderTextures[currentRenderTextureIndex].end(pGLState);
/* Draw combined frame with full alpha. */
{
pGLState.pushProjectionGLMatrix();
pGLState.orthoProjectionGLMatrixf(0, surfaceWidth, 0, surfaceHeight, -1, 1);
{
this.mRenderTextureSprites[otherRenderTextureIndex].setAlpha(1);
this.mRenderTextureSprites[otherRenderTextureIndex].onDraw(pGLState, this.mCamera);
}
pGLState.popProjectionGLMatrix();
}
/* Flip RenderTextures. */
this.mCurrentRenderTextureIndex = otherRenderTextureIndex;
}
private void initRenderTextures(final GLState pGLState) {
final int surfaceWidth = this.mCamera.getSurfaceWidth();
final int surfaceHeight = this.mCamera.getSurfaceHeight();
final VertexBufferObjectManager vertexBufferObjectManager = this.getVertexBufferObjectManager();
for(int i = 0; i <= 1; i++) {
this.mRenderTextures[i] = new RenderTexture(DodgingGame.this.getTextureManager(), surfaceWidth, surfaceHeight);
this.mRenderTextures[i].init(pGLState);
final ITextureRegion renderTextureATextureRegion = TextureRegionFactory.extractFromTexture(this.mRenderTextures[i]);
this.mRenderTextureSprites[i] = new Sprite(0, 0, renderTextureATextureRegion, vertexBufferObjectManager);
}
}
};
}
How can I change it to work for specific sprites instead of the whole visible screen?
You could use a particle system to create motion blur effect.

Andengine MotionStreakExample and screenshots

I want to capture the screen by rendering scene into the RenderTexture, i've tried to do this in MotionStreakExample and everything is ok, but when i copy code to my project i have this picture (maybe there are some troubles with textures... i can't understand):
#Override
public Engine onCreateEngine(EngineOptions pEngineOptions) {
return new Engine(pEngineOptions) {
private boolean mRenderTextureInitialized;
private RenderTexture mRenderTextures ;
private Sprite mRenderTextureSprites ;
#Override
public void onDrawFrame(final GLState pGLState) throws InterruptedException {
final boolean firstFrame = !this.mRenderTextureInitialized;
if(firstFrame) {
this.initRenderTextures(pGLState);
this.mRenderTextureInitialized = true;
}
final int surfaceWidth = WIDTH*2;
final int surfaceHeight = HEIGHT;
this.mRenderTextures.begin(pGLState, false, true);
{
/* Draw current frame. */
super.onDrawFrame(pGLState);
/* Draw previous frame with reduced alpha. */
}
this.mRenderTextures.end(pGLState);
{
pGLState.pushProjectionGLMatrix();
pGLState.orthoProjectionGLMatrixf(0, surfaceWidth, 0, surfaceHeight, -1, 1);
{
this.mRenderTextureSprites.setAlpha(1);
this.mRenderTextureSprites.onDraw(pGLState, this.mCamera);
}
pGLState.popProjectionGLMatrix();
}
if (needToSave)
{
needToSave = false;
FSHelper.saveBitmapToFile(this.mRenderTextures.getBitmap(pGLState), SAVED_PATH+"/test.png");
}
/* Flip RenderTextures. */
}
private void initRenderTextures(final GLState pGLState) {
final int surfaceWidth = WIDTH*2;
final int surfaceHeight = HEIGHT;
final VertexBufferObjectManager vertexBufferObjectManager = mEngine.getVertexBufferObjectManager();
this.mRenderTextures = new RenderTexture(mEngine.getTextureManager(), surfaceWidth, surfaceHeight);
this.mRenderTextures.init(pGLState);
final ITextureRegion renderTextureATextureRegion = TextureRegionFactory.extractFromTexture(this.mRenderTextures);
this.mRenderTextureSprites = new Sprite(0, 0, renderTextureATextureRegion, vertexBufferObjectManager);
}
};
}
PS. this cross with red background is a sprite on my scene.
Andengine already has an infrastructure for taking screenshots, have you tried using that? Take a look at the example:
https://github.com/nicolasgramlich/AndEngineExamples/blob/GLES2/src/org/andengine/examples/ScreenCaptureExample.java
I found the answer !
Textures are loaded dynamicly and on the first frame i haven't load textures at all, because i have a choose dialog there and create all textures after it. I need to call initRenderTextures each time when textures are changed.

Categories

Resources