Android Open Source - blook8r G L View






From Project

Back to project page blook8r.

License

The source code is released under:

GNU General Public License

If you think the Android project blook8r listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.github.matt.williams.blook8r;
//  ww  w.j av a 2  s  . c o  m
import java.io.IOException;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONTokener;

import android.content.Context;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.Matrix;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Toast;

import com.github.matt.williams.android.gl.BitmapTexture;
import com.github.matt.williams.android.gl.FragmentShader;
import com.github.matt.williams.android.gl.Program;
import com.github.matt.williams.android.gl.Projection;
import com.github.matt.williams.android.gl.Utils;
import com.github.matt.williams.android.gl.VertexShader;

public class GLView extends GLSurfaceView implements Renderer {

    private static final float MIN_ALTITUDE = -12.0f;
    private static final float MAX_ALTITUDE = 12.0f;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
            mTouched = true;
        } else if ((event.getActionMasked() == MotionEvent.ACTION_MOVE) &&
                   (event.getHistorySize() >= 1)) {
            mBearing += (event.getX(0) - event.getHistoricalX(0, 0)) / 6.0;
            mBearing = normalizeBearing(mBearing);
            mAltitude -= (event.getY(0) - event.getHistoricalY(0, 0)) / 50.0;
            if (mAltitude < MIN_ALTITUDE) {
                mAltitude = MIN_ALTITUDE;
            } else if (mAltitude > MAX_ALTITUDE) {
                mAltitude = MAX_ALTITUDE;
            }
        } else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
            mTouched = false;
        }
        super.onTouchEvent(event);
        return true;
    }

    private static final String TAG = "GLView";
    private Program mMapProgram;
    private Program mLocationProgram;
    private float mLocationY;
    private float mLocationX;
    private boolean mGotLocation = false;
    private Projection mProjection;
    private float[] mVertices;
    private float[] mOtherVertices;
    private float mDesiredBearing;
    private float mBearing;
    private float mAltitude;
    private BitmapTexture mLocationTexture;
    private BitmapTexture mJewleryTexture;
    private float mTargetLocationX = 1.5f;
    private float mTargetLocationY = 3.5f;
    private boolean mTouched;
    private BitmapTexture mJewleryTextureLow;
    private BitmapTexture mLocationTextureLow;
    private Toast mPendingBeaconsToast;

    private static final double CENTRE_X;
    private static final double CENTRE_Y;
    private static final double RADIUS;
    static {
        CENTRE_X = (-0.01975621696528207 + -0.01902470873661133 + -0.0191509753757757 + -0.01987457772519519) / 4;
        CENTRE_Y = (51.50525850486366 + 51.5051846939183 + 51.50471551467772 + 51.50479160522183) / 4;
        RADIUS = (Math.pow(Math.pow(-0.01975621696528207 - CENTRE_X, 2) + Math.pow(51.50525850486366 - CENTRE_Y, 2), 0.5) +
                  Math.pow(Math.pow(-0.01902470873661133 - CENTRE_X, 2) + Math.pow(51.5051846939183 - CENTRE_Y, 2), 0.5) +
                  Math.pow(Math.pow(-0.0191509753757757 - CENTRE_X, 2) + Math.pow(51.50471551467772 - CENTRE_Y, 2), 0.5) +
                  Math.pow(Math.pow(-0.01987457772519519 - CENTRE_X, 2) + Math.pow(51.50479160522183 - CENTRE_Y, 2), 0.5)) / 4;
    }

    public GLView(Context context) {
        super(context);
        initialize();
    }

    public GLView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();
    }

    private void initialize() {
        setEGLContextClientVersion(2);
        setEGLConfigChooser(8, 8, 8, 0, 16, 0);
        setRenderer(this);
        try {
            JSONArray jsonArray = (JSONArray)new JSONTokener(JSONUtils.readStream(getContext().getAssets().open("map.json"))).nextValue();
            float[] vertices = new float[jsonArray.length()];
            for (int ii = 0; ii < vertices.length; ii++) {
                vertices[ii] = (float)jsonArray.getDouble(ii);
            }
            mVertices = vertices;

            jsonArray = (JSONArray)new JSONTokener(JSONUtils.readStream(getContext().getAssets().open("other_map.json"))).nextValue();
            vertices = new float[jsonArray.length()];
            for (int ii = 0; ii < vertices.length; ii++) {
                vertices[ii] = (float)jsonArray.getDouble(ii);
            }
            mOtherVertices = vertices;
        } catch (JSONException e) {
            android.util.Log.e(TAG, "Failed to parse map.json", e);
        } catch (IOException e) {
            android.util.Log.e(TAG, "Failed to read map.json", e);
        }

        mPendingBeaconsToast = Toast.makeText(getContext(), "Locating...", Toast.LENGTH_LONG);
        mPendingBeaconsToast.show();
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        mMapProgram = new Program(new VertexShader(getResources().getString(R.string.mapVertexShader)),
                                       new FragmentShader(getResources().getString(R.string.mapFragmentShader)));
        mLocationProgram = new Program(new VertexShader(getResources().getString(R.string.locationVertexShader)),
                                       new FragmentShader(getResources().getString(R.string.locationFragmentShader)));

        mLocationTexture = new BitmapTexture(BitmapFactory.decodeResource(getResources(), R.raw.male, Utils.BITMAP_OPTIONS));
        mLocationTextureLow = new BitmapTexture(BitmapFactory.decodeResource(getResources(), R.raw.male_low, Utils.BITMAP_OPTIONS));
        mJewleryTexture = new BitmapTexture(BitmapFactory.decodeResource(getResources(), R.raw.jewelry, Utils.BITMAP_OPTIONS));
        mJewleryTextureLow = new BitmapTexture(BitmapFactory.decodeResource(getResources(), R.raw.jewelry_low, Utils.BITMAP_OPTIONS));

        mProjection = new Projection(40.0f, 60.0f, 0.0f);
        float[] matrix = new float[16];
        Matrix.setIdentityM(matrix, 0);
        Matrix.rotateM(matrix, 0, 90.0f, -1.0f, 0.0f, 0.0f);
        mProjection.setRotationMatrix(matrix);

        GLES20.glEnable(GLES20.GL_BLEND);
        Utils.checkErrors("glEnable(GLES20.GL_BLEND)");
        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
        Utils.checkErrors("glBlendFunc");

        GLES20.glEnable(GLES20.GL_DEPTH_TEST);
        Utils.checkErrors("glEnable(GLES20.GL_DEPTH_TEST)");
        GLES20.glDepthMask(true);
        Utils.checkErrors("glDepthMask");

        GLES20.glClearColor(0, 0, 0.25f, 0);
        Utils.checkErrors("glClearColor");
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    }

    public void setHighLowColors(Program program, float altitude) {
        if (altitude < -6.0f) {
            program.setUniform("lowColor", 0, 0, 0, 1);
            program.setUniform("highColor", 0.333f, 0.333f, 0.333f, 1);
        } else if (altitude < -2.0f) {
            program.setUniform("lowColor", 0, 0, 0, 1);
            program.setUniform("highColor", (altitude + 8) / 6, (altitude + 8) / 6, (altitude + 8) / 6, 1);
        } else if (altitude < 2.0f) {
            program.setUniform("lowColor", 0, 0, 0, 1);
            program.setUniform("highColor", 1, 1, 1, 1);
        } else if (altitude < 6.0f) {
            program.setUniform("lowColor", (altitude - 2) / 8, (altitude - 2) / 8, (altitude - 2) / 8, 1);
            program.setUniform("highColor", (6 - altitude) / 4, (6 - altitude) / 4, (6 - altitude) / 4, 1);
        } else {
            program.setUniform("lowColor", 0.5f, 0.5f, 0.5f, 1);
            program.setUniform("highColor", 0, 0, 0, 1);
        }
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        if (!mTouched) {
            mBearing = slideToBearing(mBearing, mDesiredBearing, 0.05f);
            float desiredAltitude = Math.round(mAltitude / 6.0f) * 6.0f;
            mAltitude = mAltitude * 0.95f + desiredAltitude * 0.05f;
        }

        float[] matrix = new float[16];
        System.arraycopy(mProjection.getViewMatrix(), 0, matrix, 0, 16);
        Matrix.rotateM(matrix, 0, -15.0f, -1.0f, 0.0f, 0.0f);
        Matrix.translateM(matrix, 0, 0, 8.0f, -3.5f);
        Matrix.rotateM(matrix, 0, mBearing + 65, 0.0f, 0.0f, 1.0f); // = 65 accounts for difference between actual compass directions and model
        Matrix.translateM(matrix, 0, -mLocationX, -mLocationY, 0);

        Matrix.translateM(matrix, 0, 0, 0, mAltitude - 12.0f);
        mMapProgram.use();
        mMapProgram.setUniform("matrix", matrix);
        setHighLowColors(mMapProgram, mAltitude - 12.0f);
        mMapProgram.setVertexAttrib("xyz", mOtherVertices, 3);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mOtherVertices.length / 3);
        Matrix.translateM(matrix, 0, 0, 0, 6.0f);

        mMapProgram.use();
        mMapProgram.setUniform("matrix", matrix);
        setHighLowColors(mMapProgram, mAltitude - 6.0f);
        mMapProgram.setVertexAttrib("xyz", mOtherVertices, 3);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mOtherVertices.length / 3);
        Matrix.translateM(matrix, 0, 0, 0, 6.0f);

        mMapProgram.use();
        mMapProgram.setUniform("matrix", matrix);
        setHighLowColors(mMapProgram, mAltitude);
        mMapProgram.setVertexAttrib("xyz", mVertices, 3);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mVertices.length / 3);

        float[] vertices;
        if (mGotLocation) {
            mLocationProgram.use();
            mLocationProgram.setUniform("matrix", matrix);
            if (mAltitude < 4.0f) {
                mLocationTexture.use(GLES20.GL_TEXTURE0);
                vertices = new float[] {mLocationX, mLocationY, 0.5f};
            } else {
                mLocationTextureLow.use(GLES20.GL_TEXTURE0);
                vertices = new float[] {mLocationX, mLocationY, -1.0f};
            }
            mLocationProgram.setUniform("texture", 0);
            mLocationProgram.setVertexAttrib("xyz", vertices, 3);
            GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1);
        }

        Matrix.translateM(matrix, 0, 0, 0, 6.0f);
        mMapProgram.use();
        mMapProgram.setUniform("matrix", matrix);
        setHighLowColors(mMapProgram, mAltitude + 6.0f);
        mMapProgram.setVertexAttrib("xyz", mOtherVertices, 3);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mOtherVertices.length / 3);

        mLocationProgram.use();
        mLocationProgram.setUniform("matrix", matrix);
        if (mAltitude < -2.0f) {
            mJewleryTexture.use(GLES20.GL_TEXTURE0);
            vertices = new float[] {mTargetLocationX, mTargetLocationY, 0.5f};
        } else {
            mJewleryTextureLow.use(GLES20.GL_TEXTURE0);
            vertices = new float[] {mTargetLocationX, mTargetLocationY, -1.0f};
        }
        mLocationProgram.setUniform("texture", 0);
        mLocationProgram.setVertexAttrib("xyz", vertices, 3);
        GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1);

        Matrix.translateM(matrix, 0, 0, 0, 6.0f);
        mMapProgram.use();
        mMapProgram.setUniform("matrix", matrix);
        setHighLowColors(mMapProgram, mAltitude + 12.0f);
        mMapProgram.setVertexAttrib("xyz", mOtherVertices, 3);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mOtherVertices.length / 3);
    }

    public void setLocation(double x, double y) {
        double[] local = CoordinateMapper.globalToLocal(x, y);
        mLocationX = (float)local[0];
        mLocationY = (float)local[1];
        mGotLocation = true;
        mPendingBeaconsToast.cancel();
        android.util.Log.e(TAG, "Got OpenGL location " + mLocationX + ", " + mLocationY);
    }

    public void setTargetLocation(double x, double y) {
        android.util.Log.e(TAG, "Got global target location " + x + ", " + y);
        double[] local = CoordinateMapper.globalToLocal(x, y);
        mTargetLocationX = (float)local[0];
        mTargetLocationY = (float)local[1];
        android.util.Log.e(TAG, "Got OpenGL target location " + mTargetLocationX + ", " + mTargetLocationY);
    }

    public float slideToBearing(float current, float desired, float alpha) {
        if ((current < -90) &&
            (desired > 90)) {
            desired -= 360;
        }
        if ((current > 90) &&
            (desired < -90)) {
            desired += 360;
        }
        current = alpha * desired + (1 - alpha) * current;
        return normalizeBearing(current);
    }

    private float normalizeBearing(float current) {
        if (current < -180) {
            current += 360;
        }
        if (current > 180) {
            current -= 360;
        }
        return current;
    }

    public void setBearing(float bearing) {
        mDesiredBearing = bearing;
    }
}




Java Source Code List

com.github.matt.williams.blook8r.Blook8rService.java
com.github.matt.williams.blook8r.CoordinateMapper.java
com.github.matt.williams.blook8r.GLActivity.java
com.github.matt.williams.blook8r.GLView.java
com.github.matt.williams.blook8r.JSONUtils.java
com.github.matt.williams.blook8r.MainActivity.java
com.github.matt.williams.blook8r.MapActivity.java