/* * Copyright (C) 2016 Baidu, Inc. All Rights Reserved. */ package baidumapsdk.demo.map; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.ShortBuffer; import java.util.ArrayList; import java.util.List; import javax.microedition.khronos.opengles.GL10; import com.baidu.mapapi.map.BaiduMap; import com.baidu.mapapi.map.BaiduMap.OnMapDrawFrameCallback; import com.baidu.mapapi.map.BitmapDescriptorFactory; import com.baidu.mapapi.map.MapStatus; import com.baidu.mapapi.map.MapView; import com.baidu.mapapi.map.MarkerOptions; import com.baidu.mapapi.model.LatLng; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.PointF; import android.opengl.GLES20; import android.opengl.GLUtils; import android.os.Bundle; import android.util.Log; import baidumapsdk.demo.R; /** * 此demo用来展示如何在地图绘制的每帧中再额外绘制一些用户自己的内容 */ public class OpenglDemo extends Activity implements OnMapDrawFrameCallback { private static final String LTAG = OpenglDemo.class.getSimpleName(); // 地图相关 MapView mMapView; BaiduMap mBaiduMap; Bitmap bitmap; private LatLng latlng1 = new LatLng(39.97923, 116.357428); LatLng latlng2 = new LatLng(39.94923, 116.397428); LatLng latlng3 = new LatLng(39.96923, 116.437428); private int mProgramObject; private int mTexID; private FloatBuffer mVertices; private ShortBuffer mTexCoords; private final float[] mVerticesData = { -0.5f, -0.5f, 0, 0.5f, -0.5f, 0, -0.5f, 0.5f, 0, 0.5f, 0.5f, 0 }; private final short[] mTexCoordsData = {0, 1, 1, 1, 0, 0, 1, 0}; private boolean mBfirst = false; private List<LatLng> latLngPolygon; { latLngPolygon = new ArrayList<LatLng>(); latLngPolygon.add(latlng1); latLngPolygon.add(latlng2); latLngPolygon.add(latlng3); } private float[] vertexs; private FloatBuffer vertexBuffer; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_opengl); // 初始化地图 mMapView = (MapView) findViewById(R.id.bmapView); mBaiduMap = mMapView.getMap(); mBaiduMap.setOnMapDrawFrameCallback(this); bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.ground_overlay); MarkerOptions marker1 = new MarkerOptions(); marker1.icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_marka)); marker1.position(latlng2); mBaiduMap.addOverlay(marker1); MarkerOptions marker2 = new MarkerOptions(); marker2.icon(BitmapDescriptorFactory.fromResource(R.drawable.icon_markb)); marker2.position(latlng3); mBaiduMap.addOverlay(marker2); } @Override protected void onPause() { mMapView.onPause(); super.onPause(); mBfirst = false; } @Override protected void onResume() { mMapView.onResume(); // onResume 纹理失效 textureId = -1; super.onResume(); } @Override protected void onDestroy() { mMapView.onDestroy(); super.onDestroy(); } @Deprecated public void onMapDrawFrame(GL10 gl, MapStatus drawingMapStatus) { if (mBaiduMap.getProjection() != null) { // calPolylinePoint(drawingMapStatus); // drawPolyline(gl, Color.argb(255, 255, 0, 0), vertexBuffer, 10, 3, // drawingMapStatus); // drawTexture(gl, bitmap, drawingMapStatus); drawFrame(drawingMapStatus); // drawFrame2(drawingMapStatus); } } @Override public void onMapDrawFrame(MapStatus drawingMapStatus) { if (mBaiduMap.getProjection() != null) { // calPolylinePoint(drawingMapStatus); // drawPolyline(gl, Color.argb(255, 255, 0, 0), vertexBuffer, 10, 3, // drawingMapStatus); // drawTexture(gl, bitmap, drawingMapStatus); drawFrame(drawingMapStatus); } } // 采用屏幕坐标, 有抖动,有累计误差 private void drawFrame(MapStatus drawingMapStatus) { PointF p1f = mBaiduMap.getProjection().toOpenGLNormalization(latlng2 , drawingMapStatus); PointF p2f = mBaiduMap.getProjection().toOpenGLNormalization(latlng3 , drawingMapStatus); float mVerticesData[] = new float[] { p1f.x, p1f.y, 0.0f, p2f.x, p1f.y, 0.0f, p1f.x, p2f.y, 0.0f, p2f.x, p2f.y, 0.0f }; mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4) .order(ByteOrder.nativeOrder()).asFloatBuffer(); mVertices.put(mVerticesData).position(0); mTexCoords = ByteBuffer.allocateDirect(mTexCoordsData.length * 2) .order(ByteOrder.nativeOrder()).asShortBuffer(); mTexCoords.put(mTexCoordsData).position(0); if(!mBfirst) { comipleShaderAndLinkProgram(); loadTexture(); mBfirst = true; } GLES20.glUseProgram(mProgramObject); GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, mVertices); GLES20.glEnableVertexAttribArray(0); GLES20.glVertexAttribPointer(1, 2, GLES20.GL_SHORT, false, 0, mTexCoords); GLES20.glEnableVertexAttribArray(1); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexID); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); } private void comipleShaderAndLinkProgram() { final String vShaderStr = "attribute vec4 a_position; \n" +"attribute vec2 a_texCoords; \n" +"varying vec2 v_texCoords; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" +" v_texCoords = a_texCoords; \n" + "} \n"; final String fShaderStr = "precision mediump float; \n" +"uniform sampler2D u_Texture; \n" +"varying vec2 v_texCoords; \n" + "void main() \n" + "{ \n" + " gl_FragColor = texture2D(u_Texture, v_texCoords) ;\n" + "} \n"; int vertexShader; int fragmentShader; int programObject; int[] linked = new int[1]; // Load the vertex/fragment shaders vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vShaderStr); fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fShaderStr); // Create the program object programObject = GLES20.glCreateProgram(); if (programObject == 0) { return ; } GLES20.glAttachShader(programObject, vertexShader); GLES20.glAttachShader(programObject, fragmentShader); // Bind vPosition to attribute 0 GLES20.glBindAttribLocation(programObject, 0, "a_position"); GLES20.glBindAttribLocation(programObject, 1, "a_texCoords"); // Link the program GLES20.glLinkProgram(programObject); // Check the link status GLES20.glGetProgramiv(programObject, GLES20.GL_LINK_STATUS, linked, 0); if (linked[0] == 0) { Log.e(LTAG, "Error linking program:"); Log.e(LTAG, GLES20.glGetProgramInfoLog(programObject)); GLES20.glDeleteProgram(programObject); return ; } mProgramObject = programObject; } private int loadShader(int shaderType, String shaderSource) { int shader; int[] compiled = new int[1]; // Create the shader object shader = GLES20.glCreateShader(shaderType); if (shader == 0) { return 0; } // Load the shader source GLES20.glShaderSource(shader, shaderSource); // Compile the shader GLES20.glCompileShader(shader); // Check the compile status GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); if (compiled[0] == 0) { Log.e(LTAG, GLES20.glGetShaderInfoLog(shader)); GLES20.glDeleteShader(shader); return 0; } return shader; } private void loadTexture() { bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.ground_overlay); if (bitmap != null) { int []texID = new int[1]; GLES20.glGenTextures(1, texID, 0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texID[0]); mTexID = texID[0]; GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT); GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); bitmap.recycle(); } } public void calPolylinePoint(MapStatus mspStatus) { PointF[] polyPoints = new PointF[latLngPolygon.size()]; vertexs = new float[3 * latLngPolygon.size()]; int i = 0; for (LatLng xy : latLngPolygon) { polyPoints[i] = mBaiduMap.getProjection().toOpenGLLocation(xy, mspStatus); vertexs[i * 3] = polyPoints[i].x; vertexs[i * 3 + 1] = polyPoints[i].y; vertexs[i * 3 + 2] = 0.0f; i++; } for (int j = 0; j < vertexs.length; j++) { Log.d(LTAG, "vertexs[" + j + "]: " + vertexs[j]); } vertexBuffer = makeFloatBuffer(vertexs); } private FloatBuffer makeFloatBuffer(float[] fs) { ByteBuffer bb = ByteBuffer.allocateDirect(fs.length * 4); bb.order(ByteOrder.nativeOrder()); FloatBuffer fb = bb.asFloatBuffer(); fb.put(fs); fb.position(0); return fb; } private void drawPolyline(GL10 gl, int color, FloatBuffer lineVertexBuffer, float lineWidth, int pointSize, MapStatus drawingMapStatus) { gl.glEnable(GL10.GL_BLEND); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); float colorA = Color.alpha(color) / 255f; float colorR = Color.red(color) / 255f; float colorG = Color.green(color) / 255f; float colorB = Color.blue(color) / 255f; gl.glVertexPointer(3, GL10.GL_FLOAT, 0, lineVertexBuffer); gl.glColor4f(colorR, colorG, colorB, colorA); gl.glLineWidth(lineWidth); gl.glDrawArrays(GL10.GL_LINE_STRIP, 0, pointSize); gl.glDisable(GL10.GL_BLEND); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } int textureId = -1; /** * 使用opengl坐标绘制 * * @param gl * @param bitmap * @param drawingMapStatus */ public void drawTexture(GL10 gl, Bitmap bitmap, MapStatus drawingMapStatus) { PointF p1 = mBaiduMap.getProjection().toOpenGLLocation(latlng2, drawingMapStatus); PointF p2 = mBaiduMap.getProjection().toOpenGLLocation(latlng3, drawingMapStatus); ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4 * 3 * 4); byteBuffer.order(ByteOrder.nativeOrder()); FloatBuffer vertices = byteBuffer.asFloatBuffer(); vertices.put(new float[] { p1.x, p1.y, 0.0f, p2.x, p1.y, 0.0f, p1.x, p2.y, 0.0f, p2.x, p2.y, 0.0f }); ByteBuffer indicesBuffer = ByteBuffer.allocateDirect(6 * 2); indicesBuffer.order(ByteOrder.nativeOrder()); ShortBuffer indices = indicesBuffer.asShortBuffer(); indices.put(new short[] { 0, 1, 2, 1, 2, 3 }); ByteBuffer textureBuffer = ByteBuffer.allocateDirect(4 * 2 * 4); textureBuffer.order(ByteOrder.nativeOrder()); FloatBuffer texture = textureBuffer.asFloatBuffer(); texture.put(new float[] { 0, 1f, 1f, 1f, 0f, 0f, 1f, 0f }); indices.position(0); vertices.position(0); texture.position(0); // 生成纹理 if (textureId == -1) { int textureIds[] = new int[1]; gl.glGenTextures(1, textureIds, 0); textureId = textureIds[0]; Log.d(LTAG, "textureId: " + textureId); gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST); gl.glBindTexture(GL10.GL_TEXTURE_2D, 0); } gl.glEnable(GL10.GL_TEXTURE_2D); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glEnable(GL10.GL_BLEND); gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // 绑定纹理ID gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertices); gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texture); gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 6, GL10.GL_UNSIGNED_SHORT, indices); gl.glDisable(GL10.GL_TEXTURE_2D); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glDisable(GL10.GL_BLEND); } /** * Convert width to openGL width * * @param width * @return Width in openGL */ public static float toGLWidth2(float width, MapStatus mapStatus) { float winRoundW = (float) Math.abs(mapStatus.winRound.right - mapStatus.winRound.left); return 2 * width / winRoundW - 1; } /** * Convert height to openGL height * * @param height * @return Height in openGL */ public static float toGLHeight2(float height, MapStatus mapStatus) { float winRoundH = (float) Math.abs(mapStatus.winRound.top - mapStatus.winRound.bottom); return 1 - 2 * height / winRoundH; } }