0

What's wrong with my coding? When I drag the texture using my finger, the texture keep on blinking and move between other place and the pointer place.

Any guidance will be appreciated~

This is the coding:

public class Stage extends GLSurfaceView{

// Stage width and height
private float w, h;

// Screen width and height
private int screenWidth, screenHeight;

// Our native vertex buffer
private FloatBuffer vertexBuffer;

private Texture tex;

MyRenderer mRenderer;

@Override
public boolean onTouchEvent(MotionEvent event) {
    final int action = event.getAction() & MotionEvent.ACTION_MASK;
    float x, y;
    int pointerIndex;
    int pointerId;

    if (action == MotionEvent.ACTION_DOWN) {
        pointerId = event.getPointerId(0);
        x = event.getX();
        y = event.getY();
        pointerIndex = 0;
    } else {
        pointerIndex = event.getActionIndex();
        pointerId = event.getPointerId(pointerIndex);
        x = event.getX(pointerIndex);
        y = event.getY(pointerIndex);
    }
    mRenderer.setXY(x, y);
    Log.v("X: ", String.valueOf(x));
    Log.v("Y: ", String.valueOf(y));
    return true;
}

public Stage(Context context, AttributeSet attrs) {
    super(context, attrs);
    setEGLConfigChooser(8, 8, 8, 8, 0, 0);
    mRenderer = new MyRenderer();
    setRenderer(mRenderer);
    setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
    float vertices[] = {
            -0.5f, -0.5f,  0.0f,  // 0. left-bottom
            0.5f, -0.5f,  0.0f,  // 1. right-bottom
            -0.5f,  0.5f,  0.0f,  // 2. left-top
            0.5f,  0.5f,  0.0f   // 3. right-top
    };

    ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
    vbb.order(ByteOrder.nativeOrder());
    vertexBuffer = vbb.asFloatBuffer();
    vertexBuffer.put(vertices);
    vertexBuffer.position(0);

    tex = new Texture(R.drawable.kdk);

}

private class MyRenderer implements GLSurfaceView.Renderer {

    private Object lock = new Object();
    float xPos;
    float yPos;
    public void setXY(float x, float y) {
        synchronized (lock) {
            xPos = x;
            yPos = y;
        }
    }

    public final void onDrawFrame(GL10 gl) {

        gl.glClear(GLES10.GL_COLOR_BUFFER_BIT);
        tex.prepare(gl, GL10.GL_CLAMP_TO_EDGE);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
        synchronized (lock) {
            tex.draw(gl, xPos, yPos, tex.getWidth(), tex.getHeight(), 0);
        }

    }

    public final void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glClearColor(0, 0, 0, 0);

        if(width > height) {
            h = 600;
            w = width * h / height;
        } else {
            w = 600;
            h = height * w / width;
        }
        screenWidth = width;
        screenHeight = height;

        xPos = w/2;
        yPos = h/2;

        gl.glViewport(0, 0, screenWidth, screenHeight);
        gl.glMatrixMode(GL10.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glOrthof(0, w, h, 0, -1, 1);
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    public final void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // Set up alpha blending
        gl.glEnable(GL10.GL_ALPHA_TEST);
        gl.glEnable(GL10.GL_BLEND);
        gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);

        // We are in 2D. Why needs depth?
        gl.glDisable(GL10.GL_DEPTH_TEST);

        // Enable vertex arrays (we'll use them to draw primitives).
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

        // Enable texture coordination arrays.
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

        tex.load(getContext());
    }

}

}

Other classes coding:

How to apply drag drop and scale in Android OpenGL ES

Community
  • 1
  • 1
Le Parkour
  • 97
  • 1
  • 15
  • It doesn't quite explain your symptoms, but yo should call `requestRender()` on the `GLSurfaceView` instance after updating the values. Otherwise it will generally not redraw. – Reto Koradi Sep 18 '15 at 05:47
  • Ya, this is the function i missed out, it make me faint... – Le Parkour Sep 18 '15 at 07:49

2 Answers2

1

Just a guess, one possible cause is that, as the updating of xPos and yPos by the UI thread is not synchronized with the render thread, some of the frames would be drawn with xPos updated but not yPos and at a wrong position. This is corrected in the next rendering cycle, causing some flickering.

You may need to use some means of synchronization to ensure that when onDrawFrame() is called, the state (xPos and yPos) is consistent.

Edit: There are many ways to do so, e.g. by using a lock. In the renderer-

private Object lock = new Object();

public void setXY(float x, float y) {
    synchronized (lock) {
        xPos = x;
        yPos = y;
    }
}

public final void onDrawFrame(GL10 gl) {
    gl.glClear(GLES10.GL_COLOR_BUFFER_BIT);
    tex.prepare(gl, GL10.GL_CLAMP_TO_EDGE);
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
    synchronized (lock) {
        tex.draw(gl, xPos, yPos, tex.getWidth(), tex.getHeight(), 0);
    }
}

(you also need to modify the call under onTouchEvent() to setXY(x, y);)

Further Edit:

As you have used setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); you need to call requestRender(); after updating the position on the onTouchEvent handler as mentioned by Reto Koradi above:

mRenderer.setXY(x, y);
requestRender();

In this case the synchronization code may not be necessary since the rendering is only triggered by requestRender() after both x and y are updated, and most probably would not take place in parallel.

headuck
  • 2,763
  • 16
  • 19
  • When I print the float x and y it's show the x value always negative, what's wrong with this? – Le Parkour Sep 18 '15 at 03:10
  • This is another question. See http://stackoverflow.com/questions/6237200/motionevent-gety-and-getx-return-incorrect-values – headuck Sep 18 '15 at 03:14
  • Ah just remove the `static` from the lock as there should be only one instance of the renderer. – headuck Sep 18 '15 at 03:18
  • there is never use of setXY function and unable to call setXY – Le Parkour Sep 18 '15 at 03:23
  • Call mRenderer.setXY in your onTouchEvent, instead of calling setX and setY separately – headuck Sep 18 '15 at 03:29
  • Ya can't, previously the setX function also not work, it work because of import android.annotation.TargetApi; – Le Parkour Sep 18 '15 at 03:32
  • Did you miss `mRenderer`? i.e. call `mRenderer.setXY(x,y);` – headuck Sep 18 '15 at 03:35
  • Ya, it's true, I'm trying now thanks bro, you helped me – Le Parkour Sep 18 '15 at 03:36
  • The error come out FATAL EXCEPTION: GLThread 960 java.lang.NullPointerException – Le Parkour Sep 18 '15 at 03:41
  • I think the lock problem, the error is on the line synchronized (lock) { tex.draw or the private field lock never used – Le Parkour Sep 18 '15 at 03:43
  • My bad, forgot to call `new Object()`. code modified. – headuck Sep 18 '15 at 03:47
  • I have updated my code, you can have a see, now the texture not move at all, I think the x and y value not pass from the touch method to the onDrawFrame – Le Parkour Sep 18 '15 at 03:57
  • OK try to test it myself. – headuck Sep 18 '15 at 04:07
  • Full coding of other class is here http://stackoverflow.com/questions/32556914/how-to-apply-drag-drop-and-scale-in-android-opengl-es/ – Le Parkour Sep 18 '15 at 04:08
  • Turn out that it is a problem elsewhere - you set the render mode to `RENDERMODE_WHEN_DIRTY`. So immediately after `mRenderer.setXY(x, y);` you need to call `requestRender();`. Separately, as advised in the answer from which you get the code, you need to set `xPos = x * w / screenWidth;` and `yPos = y * h / screenHeight;` for correct position calculation. – headuck Sep 18 '15 at 07:32
  • Thanks Bro you help me a lot, I am appreciate it~ – Le Parkour Sep 18 '15 at 07:49
  • For future readers of this QA you may consider reverting the code in the question above to the original one, and list the issues encountered. – headuck Sep 18 '15 at 07:57
  • Sir, I have an question, it's possible to add a onClickListener on the texture? – Le Parkour Sep 18 '15 at 08:12
  • You may use a gesturedetector in the onTouchEvent. See http://stackoverflow.com/questions/19538747/how-to-use-both-ontouch-and-onclick-for-an-imagebutton . Perhaps you should ask a separate question if that answer does not help. – headuck Sep 18 '15 at 08:19
  • But that one not a button, is a texture draw with OpenGL – Le Parkour Sep 18 '15 at 08:30
  • The mechanism is the same. You feed the gesturedetector with MotionEvent, and the gesture detector will determine if a click has taken place. If you have any problem on this may be you should open a separate new question of detecting both touch and click events on a opengl texture, pointing to this question on the code. – headuck Sep 18 '15 at 08:39
  • I mean texture have no id like the button have – Le Parkour Sep 18 '15 at 08:44
  • You do not need any id to use the gesture detector. You are already intercepting the touch events, and can feed the events to the detector. – headuck Sep 18 '15 at 08:47
  • I think I need to spend time to study it again, anyway thanks bro! – Le Parkour Sep 18 '15 at 09:04
  • I have post a new question about how to set a touch/click listener for the texture in OpenGL-ES but I still question it's possible? http://stackoverflow.com/questions/32834363/how-to-set-ontouch-listener-for-drawn-texture-in-android-opengl-es – Le Parkour Sep 29 '15 at 03:29
1

I would do it by queueing events (from the Touch listener) to the GLThread by calling queueEvent() of GLSurfaceView Pass the x, y parameters in the runnable posted alongwith.

Runnable mRunnable = new Runnable() {
    @Override
    public void run() {
        mRenderer.setXY(x, y);
    }
}

Assign x and y to global variables,

And replace

mRenderer.setXY(x, y);

with

queueEvent(mRunnable);

And then call requestRender() in order to request redrawing.

On the GLRenderer's side, set the x, y params to the ones received from the runnable. And use the values in onDraw() method.

And remove the synchronisation blocks, since everything is now happening in GL thread itself.

Sahil Bajaj
  • 890
  • 6
  • 16