In android I have taken a rotating sphere example given here. It creates a simple app showing a rotating sphere (the earth).
Now, in a class derived from GLSurfaceView I wait for an even (like a touch-screen event) in order to exchange the renderer. I want the current renderer to stop rendering, and the GLSurfaceView should use a different renderer instead (to display some other object).
I have tried to use the following code:
public class MyGLSurfaceView extends GLSurfaceView {
Context mycontext;
MyGLSurfaceView(Context context) {
super(context);
mycontext = context;
}
public boolean onTouchEvent(MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
Log.d("onTouchEvent",String.format("keyCode: %d coords: %d %d", event.getActionMasked(), x, y));
GlRenderer renderer = new GlRenderer(mycontext);
setRenderer(renderer);
return super.onTouchEvent(event);
}
}
which gives the following error:
FATAL EXCEPTION: main
Process: com.jimscosmos.opengltexturedsphere, PID: 25708
java.lang.IllegalStateException: setRenderer has already been called for this instance.
I guess I have to stop/remove/destroy the 'old' renderer, but I did not find anything useful for that in the documentation. Maybe my approach is completely wrong? What else to do? How to do it right?
If you insist, technically it can be achieved using a 'mediator' - as suggested here: Change GlSurfaceView renderer.
However - I think this is an overhead you really do not need. Simply prepare various objects and change the various rendering properties in a single renderer.
Related
I have 2 separate Android app (apk).
App 1 creates SurfaceView inside it and should provide AIDL methods for other apps to obtain an instance of SurfaceHolder for such SurfaceView. So the other apps will be able to draw on that view, displayed inside app number 1.
I was able to transfer Surface itself via aidl easily, since it implements Parcelable interface.
// IMainService.aidl
package com.commonsware.cwac.preso.demo.service;
import android.view.Surface;
interface IMainService {
Surface getSurf();
}
But 3-rd party sdk need SurfaceHolder to draw on. So the question is - how can I create SurfaceHolder for a given Surface instance, or how can I transfer SurfaceHolder via AIDL. Is there any examples of how I can implement Parcelable for SurfaceHolder?
My use-case (if its matter): App 1 starts as a Service and draw UI on Presentation Screen. And I need a way to get another apps display Navigation Data via Nokia Here Mobile SDK inside app 1. I need SurfaceHolder in order to use this api.
Any help will be appreciated.
After a while, finally create a solution that works well with Here OffscreenRender API.
At one app I create SurfaceHolder and this app provide AIDL (see at the post above). With this AIDL I was able to correctly send Surface object and then, on app 2 side, make SurfaceHolder from it.
public class MySurfaceHolder implements SurfaceHolder {
private Surface surface;
private Rect rect;
MySurfaceHolder(Surface surface, Rect rect) {
this.surface = surface;
this.rect = rect;
}
///....
#Override
public Canvas lockCanvas() {
return surface.lockCanvas(this.rect);
}
#Override
public Canvas lockCanvas(Rect rect) {
return surface.lockCanvas(rect);
}
#Override
public void unlockCanvasAndPost(Canvas canvas) {
surface.unlockCanvasAndPost(canvas);
}
#Override
public Rect getSurfaceFrame() {
return rect;
}
#Override
public Surface getSurface() {
return surface;
}
}
Basically, its my own SurfaceHolder, which get initialized by my own, instead of system. This approach need extend AIDL to be able to request Rect sizes, as well.
Hope that will be helpful for someone.
I have a standard GLSurfaceView class:
public class TestSurfaceView extends GLSurfaceView {
public MainRenderer mRenderer;
public GStreamerSurfaceView(Context context) {
super(context);
setEGLContextClientVersion(2);
mRenderer = new MainRenderer(context);
setRenderer(mRenderer);
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
}
I have a Renderer class that implements GLSurfaceView.Renderer:
public class MainRenderer implements GLSurfaceView.Renderer {
private int[] hTex;
private SurfaceTexture mSTexture;
private Context context;
MainRenderer(Context c) {
context = c;
}
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
}
public void onDrawFrame(GL10 unused) {
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
}
public void onSurfaceCreated(GL10 arg0, javax.microedition.khronos.egl.EGLConfig arg1) {
}
}
In a separate JNI thread, I have some video data (YUV format) uploaded to an OpenGLES texture. I receive in Java the notification that a new texture is available and I have the corresponding texture id.
How can I display the content of this texture in the Renderer class with minimum performance impact?
For cases where the frames are coming from Camera or MediaCodec there are some very efficient solutions. It sounds like you're generating or decoding the video in software, though, which puts a mild spin on things (though you do have a SurfaceTexture declared in your code, which is odd). The trick is the "OpenGL ES texture" part, because the texture is associated with the EGL context, and the EGL context can only be active in one thread at a time.
Because you're using GLSurfaceView, rather than plain SurfaceView, you don't have control over the EGL context in the GLSurfaceView's renderer thread. The easiest way to work around this is to jump through some hoops to create a second EGL context that is shared with the first. Once you've done that, the texture created in the separate JNI thread will be available to the GLSurfaceView renderer thread.
You can find an example of this in Grafika's "show + capture camera" activity. If you look at the onDrawFrame() method in CameraCaptureActivity.java you can see it calling updateSharedContext(), which passes a message to the thread running TextureMovieEncoder to cause it to run handleUpdateSharedContext(), which (re-)creates the surface used to feed a video encoder.
If you use plain SurfaceView instead, and do your own EGL and thread management, the code will be less twisty. You can create both contexts at once, then just pass one to the thread that's producing images. You could also create a single context and use eglMakeCurrent() to shift it between threads, but that could be expensive on some platforms.
Update: the Grafika "show + capture camera" implementation has a race condition; see this bug report for details on the problem and solution. You have to perform some extra steps when creating a texture in one thread and using it in another. It's usually better to do everything in one context on one thread. The other activities in Grafika use a plain SurfaceView and do their own EGL context and thread management.
I am rendering a rajawali renderer object as
public void onCreate(Bundle savedInstanceState)
{
// initializing camera etc.
mSurfaceView.setZOrderMediaOverlay(true);
setGLBackgroundTransparent(true);
mRenderer = new Renderer(this);
mRenderer.setSurfaceView(mSurfaceView);
super.setRenderer(mRenderer);
mRenderer.setCameraPosition(0, 0, 20);
}
where mRenderer is an object of a class Renderer that extends rajawalirenderer
public class Renderer extends RajawaliRenderer
{
...// code for rendering a textured sphere
}
Now I want to stop the rendering of this 3d object(sphere) on some event handler, say button click. (And once the rendering is stopped, I again want to render a different 3d object on button click.)
How can I stop the rendering of 3d object sphere?
After searching a bit, I found the answer. There's a method named removeChild that-
Requests the removal of a child from the scene.
Parameters:
child Object3D child to be removed.
Returns:
boolean True if the child was successfully queued for removal.
Example..
getCurrentScene().removeChild(3d_Object);
where 3d_Object is the object which we don't want to render.
[EDIT] Ignore this post, it was a noob's mistake [/EDIT]
I started Android last week (= I'm pretty new to it :) ) and I'm banging my head on a problem:
I try to perfom a raycasting to get the objects under a point of the screen.
I found out that the GLU.gluUnproject method was what I needed, after a decent amount of failures, I found a solution
I've copied the MatrixGrabber, MatrixStack and MatrixTrackingGL classes in my project, they seem fine.
the method I use goes as follow:
static public Vertex unProject( float x, float y, World world )
{
world.mg = new MatrixGrabber();
world.mg.getCurrentState(world.gl);
float[] pos = new float[4];
GLU.gluUnProject( x, y, 0f,
world.mg.mModelView, 0,
world.mg.mProjection, 0,
world.view().get_size(), 0,
pos, 0);
return new Vertex(pos[0], pos[1], pos[2]);
}
Vertex is a dataHolder with x,y,z floats
World extends GLSurfaceView, I do the GLWrapper replacement in the constructor:
world.mg is a MatrixGrabber()
public World( Context context )
{
super(context);
[...]
//allows matrix manipulation
setGLWrapper( new GLWrapper()
{
public GL wrap(GL gl)
{
return new MatrixTrackingGL(gl);
}
});
}
and I make sure that all the variables are instanciated when I do my call
but still I can't get this to work: the app crashes badly on the
world.mg.getCurrentState(world.gl);
call.
it also crashes it on getCurrentModelView(gl); and getCurrentProjection(gl);
I'm using Android 1.5, but tried with other versions up to 3. same thing.
I don't really know which version of OpenGLI'm using ; the GL10 is used everywhere, I don't know if it is important, all I've read concerned the GL10 "Type".
if anyone has a clue, an advice, a workaround or a solution, I'd be happy happy happy
and anyway, thanks for reading :)
private void getMatrix(GL10 gl, int mode, float[] mat) {
MatrixTrackingGL gl2 = new MatrixTrackingGL(gl);
gl2.glMatrixMode(mode);
gl2.getMatrix(mat, 0);
}
replace the casting on the first line of the MatrixGrabber.java
my World class extended GLSurfaceView and was using the MatrixTrackingGL as a wrapper.
the problem was that the Viewport also extended GLSurfaceView and was NOT using the MatrixTrackingGL... stupid.
now the world doesn't extend anything and the Viewport ( extending GLSurfaceView ) implements the Wrapper's change and everything's fine.
In my openGL game, I draw my scene normally using a GLSurfaceView.Renderer class in the onDrawFrame(). However, when I am displaying a loading screen I would like to force the screen to draw after each item of data is loaded so the loading bar can be displayed.
Is it possible to force a bufferswap during this draw call somehow? My only alternative is to stagger my loading across multiple frames which means a lot of rework..
I guess what I am trying to call is eglSwapBuffers() but I cannot find a way to access the egl context from the GLSurfaceView or GLSurfaceView.Renderer.
Thank you for your time.
You can add also this method to your GLSurfaceView.Renderer class:
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
public void swapBuffers()
{
EGL10 curEgl = (EGL10)EGLContext.getEGL();
EGLDisplay curDisplay = curEgl.eglGetCurrentDisplay();
if (curDisplay == EGL10.EGL_NO_DISPLAY) { Log.e("myApp","No default display"); return; }
EGLSurface curSurface = curEgl.eglGetCurrentSurface(EGL10.EGL_DRAW);
if (curSurface == EGL10.EGL_NO_SURFACE) { Log.e("myApp","No current surface"); return; }
curEgl.eglSwapBuffers(curDisplay, curSurface);
}
Much the same as OpenUserX03's answer, just in Java.
No you can't (or shouldn't) force swapping buffers in the onDraw method of your Renderer.
What you should do is to make the loading of your data in a separate Thread. Your onDraw method will still be called regularly, which will let you ask to the loading thread how many items were loadede to display a progress bar / message accordingly.
It's been awhile since the answer has been accepted but you can (and there is no reason you shouldn't) force swapping the buffers in the onDrawFrame() method of your Renderer.
I had the exact same problem in my OpenGL app - I needed to render a loading screen while data was being loaded. Here is my pseudo-code example of calling eglSwapBuffers() during a load (I use JNI):
public void onDrawFrame(GL10 gl)
{
MyJNILib.render();
}
MyJNILib native pseudo-code:
#include <EGL\egl.h>
...
void render()
{
...
while (loading)
{
// Do loading stuff
...
eglSwapBuffers( eglGetCurrentDisplay(), eglGetCurrentSurface( EGL_DRAW ) );
}
...
}
A solution by force is to make your custom version GLSurfaceView class based on the source code of Android.
In the source, you can find a method called swap:
/**
* Display the current render surface.
* #return the EGL error code from eglSwapBuffers.
*/
public int swap() {
if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
return mEgl.eglGetError();
}
return EGL10.EGL_SUCCESS;
}
This should be what you want. Unfortunately, however, it is a method of private inner class called EglHelper.
/**
* An EGL helper class.
*/
private static class EglHelper {
So in your custom GLSurfaceView class (copied from Google's source), make this EglHelper class public and you can use EglHelper.swap method.
public static class EglHelper {