0

I was following a OpenGL tutorial (https://developer.android.com/training/graphics/opengl/touch.html#angle) and I did everything right I think. But my code crashes on mRenderer.setAngle(mRenderer.getAngle() +((dx + dy) * TOUCH_SCALE_FACTOR));

Edit I also added this to get the height and width

DisplayMetrics displayMetrics = new DisplayMetrics();
    ((Activity) getContext()).getWindowManager()
            .getDefaultDisplay()
            .getMetrics(displayMetrics);
final int height = displayMetrics.heightPixels;
final int width = displayMetrics.widthPixels;

Code:

public class OpenGL extends Fragment {
    private GLSurfaceView mGLView;
    private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
    private float mPreviousX;
    private float mPreviousY;
    OpenGLRenderer mRenderer;

    public OpenGL() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        mGLView = new GLSurfaceView(getActivity());
        mGLView.setEGLContextClientVersion(2);
        mGLView.setRenderer(new OpenGLRenderer());
        // Render the view only when there is a change in the drawing data
        mGLView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

        DisplayMetrics displayMetrics = new DisplayMetrics();
        ((Activity) getContext()).getWindowManager()
                .getDefaultDisplay()
                .getMetrics(displayMetrics);
        final int height = displayMetrics.heightPixels;
        final int width = displayMetrics.widthPixels;

        mGLView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent e) {

                // MotionEvent reports input details from the touch screen
                // and other input controls. In this case, you are only
                // interested in events where the touch position changed.

                float x = e.getX();
                float y = e.getY();

                switch (e.getAction()) {
                    case MotionEvent.ACTION_MOVE:
                        float dx = x - mPreviousX;
                        float dy = y - mPreviousY;

                        // reverse direction of rotation above the mid-line
                        if (y > height / 2) {
                            dx = dx * -1;
                        }

                        // reverse direction of rotation to left of the mid-line
                        if (x < width / 2) {
                            dy = dy * -1;
                        }

                        mRenderer.setAngle(
                                mRenderer.getAngle() +
                                        ((dx + dy) * TOUCH_SCALE_FACTOR));
                        mGLView.requestRender();
                }
                mPreviousX = x;
                mPreviousY = y;
                return true;
            }
        });
        return mGLView;
    }

    @Override
    public void onResume() {
        super.onResume();
        mGLView.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
        mGLView.onPause();
    }
}

OpenGLRenderer Class

class OpenGLRenderer implements GLSurfaceView.Renderer {
    private Triangle mRectangle;
    // mMVPMatrix is an abbreviation for "Model View Projection Matrix"
    private final float[] mMVPMatrix = new float[16];
    private final float[] mProjectionMatrix = new float[16];
    private final float[] mViewMatrix = new float[16];
    private float[] mRotationMatrix = new float[16];
    float[] scratch = new float[16];
    public volatile float mAngle;

    public float getAngle() {
        return mAngle;
    }

    public void setAngle(float angle) {
        mAngle = angle;
    }

    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // Set the background frame color
        //GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

        mRectangle = new Triangle();
    }

    public void onDrawFrame(GL10 gl) {
        // Redraw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        // Set the camera position (View matrix)
        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

        // Calculate the projection and view transformation
        Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mViewMatrix, 0);

        // Create a rotation for the triangle
        // long time = SystemClock.uptimeMillis() % 4000L;
        // float angle = 0.090f * ((int) time);
        Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);

        // Combine the rotation matrix with the projection and camera view
        // Note that the mMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);

        // Draw triangle
        mRectangle.drawMatrix(scratch);
    }

    public void onSurfaceChanged(GL10 gl, int width, int 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;
    }
}

Triangle Class

class Triangle {
    private final String vertexShaderCodeMatrix =
     // This matrix member variable provides a hook to manipulate
     // the coordinates of the objects that use this vertex shader
     "uniform mat4 uMVPMatrix;" +
             "attribute vec4 vPosition;" +
             "void main() {" +
             // the matrix must be included as a modifier of gl_Position
             // Note that the uMVPMatrix factor *must be first* in order
             // for the matrix multiplication product to be correct.
             "  gl_Position = uMVPMatrix * vPosition;" +
             "}";

    // Use to access and set the view transformation
    private int mMVPMatrixHandle;


    private final String vertexShaderCode =
         "attribute vec4 vPosition;" +
                 "void main() {" +
                 "  gl_Position = vPosition;" +
                 "}";

    private final String fragmentShaderCode =
         "precision mediump float;" +
                 "uniform vec4 vColor;" +
                 "void main() {" +
                 "  gl_FragColor = vColor;" +
                 "}";

    // number of coordinates per vertex in this array
    static final int COORDS_PER_VERTEX = 3;
    static float triangleCoords[] = {   // in counterclockwise order:
         0.0f,  0.622008459f, 0.0f, // top
         -0.5f, -0.311004243f, 0.0f, // bottom left
         0.5f, -0.311004243f, 0.0f  // bottom right
    };

    // Set color with red, green, blue and alpha (opacity) values
    float color[] = { 0.5f, 0.5f, 0.5f, 1.0f };

    private final int mProgram;

    private short[] indices = {0,1,2,0,2,3};

    private FloatBuffer vertexBuffer;
    private ShortBuffer indexBuffer;

    public Triangle() {

         // initialize vertex byte buffer for shape coordinates
         ByteBuffer bb = ByteBuffer.allocateDirect(
                 // (number of coordinate values * 4 bytes per float)
                 triangleCoords.length * 4);
         // use the device hardware's native byte order
         bb.order(ByteOrder.nativeOrder());

         // create a floating point buffer from the ByteBuffer
         vertexBuffer = bb.asFloatBuffer();
         // add the coordinates to the FloatBuffer
         vertexBuffer.put(triangleCoords);
         // set the buffer to read the first coordinate
         vertexBuffer.position(0);

         int vertexShader = OpenGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
                 vertexShaderCode);
         int fragmentShader = OpenGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
                 fragmentShaderCode);

         // create empty OpenGL ES Program
         mProgram = GLES20.glCreateProgram();

         // add the vertex shader to program
         GLES20.glAttachShader(mProgram, vertexShader);

         // add the fragment shader to program
         GLES20.glAttachShader(mProgram, fragmentShader);

         // creates OpenGL ES program executables
         GLES20.glLinkProgram(mProgram);
    }

    private int mPositionHandle;
    private int mColorHandle;

    private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
    private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

    public void draw() {
        // Add program to OpenGL ES environment
        GLES20.glUseProgram(mProgram);

        // get handle to vertex shader's vPosition member
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

        // Enable a handle to the triangle vertices
        GLES20.glEnableVertexAttribArray(mPositionHandle);

        // Prepare the triangle coordinate data
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
             GLES20.GL_FLOAT, false,
             vertexStride, vertexBuffer);

        // get handle to fragment shader's vColor member
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

        // Set color for drawing the triangle
        GLES20.glUniform4fv(mColorHandle, 1, color, 0);

        // Draw the triangle
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

        // Disable vertex array
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }

    public void drawMatrix(float[] mvpMatrix) { // pass in the calculated transformation matrix


         // Add program to OpenGL ES environment
         GLES20.glUseProgram(mProgram);

         // get handle to vertex shader's vPosition member
         mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

         // Enable a handle to the triangle vertices
         GLES20.glEnableVertexAttribArray(mPositionHandle);

         // Prepare the triangle coordinate data
         GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                 GLES20.GL_FLOAT, false,
                 vertexStride, vertexBuffer);

         // get handle to fragment shader's vColor member
         mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

         // Set color for drawing the triangle
         GLES20.glUniform4fv(mColorHandle, 1, color, 0);

         // Draw the triangle
         GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

         // Disable vertex array
         GLES20.glDisableVertexAttribArray(mPositionHandle);

         // get handle to shape's transformation matrix
         mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");

         // Pass the projection and view transformation to the shader
         GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

         // Draw the triangle
         GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

         // Disable vertex array
         GLES20.glDisableVertexAttribArray(mPositionHandle);
    }
}

04-26 10:55:22.153 31562-31562/com.example.tiagosilva.amob_android E/InputEventReceiver: Exception dispatching input event. 04-26 10:55:22.153 31562-31562/com.example.tiagosilva.amob_android E/MessageQueue-JNI: Exception in MessageQueue callback: handleReceiveCallback 04-26 10:55:22.174 31562-31562/com.example.tiagosilva.amob_android E/MessageQueue-JNI: java.lang.NullPointerException: Attempt to invoke virtual method 'float com.example.tiagosilva.amob_android.OpenGLRenderer.getAngle()' on a null object reference at com.example.tiagosilva.amob_android.OpenGL$1.onTouch(OpenGL.java:95) at android.view.View.dispatchTouchEvent(View.java:10019) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:413) at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1808) at android.app.Activity.dispatchTouchEvent(Activity.java:3061) at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:71) at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:71) at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:375) at android.view.View.dispatchPointerEvent(View.java:10243) at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4438) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4306) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3906) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3872) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3999) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3880) at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4056) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3906) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3872) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3880) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853) at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6246) at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6220) at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6181) at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6349) at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185) at android.os.MessageQueue.nativePollOnce(Native Method) at android.os.MessageQueue.next(MessageQueue.java:323) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:6119) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 04-26 10:55:22.204 31562-31562/com.example.tiagosilva.amob_android E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.tiagosilva.amob_android, PID: 31562 java.lang.NullPointerException: Attempt to invoke virtual method 'float com.example.tiagosilva.amob_android.OpenGLRenderer.getAngle()' on a null object reference at com.example.tiagosilva.amob_android.OpenGL$1.onTouch(OpenGL.java:95) at android.view.View.dispatchTouchEvent(View.java:10019) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2632) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2321) at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:413) at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1808) at android.app.Activity.dispatchTouchEvent(Activity.java:3061) at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:71) at android.support.v7.view.WindowCallbackWrapper.dispatchTouchEvent(WindowCallbackWrapper.java:71) at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:375) at android.view.View.dispatchPointerEvent(View.java:10243) at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4438) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4306) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3906) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3872) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3999) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3880) at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4056) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3906) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3872) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3880) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3853) at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:6246) at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:6220) at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:6181) at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:6349) at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185) at android.os.MessageQueue.nativePollOnce(Native Method) at android.os.MessageQueue.next(MessageQueue.java:323) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:6119) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

1 Answer 1

1

You never initialize the mRenderer ...variable

OpenGLRenderer mRenderer;

that's why mRenderer.getAngle() gives you a null pointer exception.

java.lang.NullPointerException: Attempt to invoke virtual method 'float com.example.tiagosilva.amob_android.OpenGLRenderer.getAngle()' on a null object reference

try initialize it in your onCreateView()

mRenderer = new OpenGLRenderer();
Sign up to request clarification or add additional context in comments.

2 Comments

dont crash now but doesnt rotate either xD

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.