//package ri.blog.opengl008; package com.introlab.rtabmap; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.ShortBuffer; import java.util.Iterator; import java.util.Vector; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Rect; import android.graphics.Typeface; import android.opengl.GLES20; import android.opengl.GLUtils; import android.text.TextPaint; public class TextManager { /* SHADER Text * * This shader is for rendering 2D text textures straight from a texture * Color and alpha blended. * */ public static final String vs_Text = "uniform mat4 uMVPMatrix;" + "attribute vec4 vPosition;" + "attribute vec4 a_Color;" + "attribute vec2 a_texCoord;" + "varying vec4 v_Color;" + "varying vec2 v_texCoord;" + "void main() {" + " gl_Position = uMVPMatrix * vPosition;" + " v_texCoord = a_texCoord;" + " v_Color = a_Color;" + "}"; public static final String fs_Text = "precision mediump float;" + "varying vec4 v_Color;" + "varying vec2 v_texCoord;" + "uniform sampler2D s_texture;" + "void main() {" + " gl_FragColor = texture2D( s_texture, v_texCoord ) * v_Color;" + " gl_FragColor.rgb *= v_Color.a;" + "}"; public static int sp_Text; public static final int RI_TEXT_TEXTURE_SIZE = 512; // 512 public static final float RI_TEXT_HEIGHT_BASE = 32.0f; public static final char RI_TEXT_START = ' '; public static final char RI_TEXT_STOP = '~'+1; public float getMaxTextHeight() {return mTextHeight;} private float mUVWidth; private float mUVHeight; private float mTextHeight; private FloatBuffer vertexBuffer; private FloatBuffer textureBuffer; private FloatBuffer colorBuffer; private ShortBuffer drawListBuffer; private float[] vecs; private float[] uvs; private short[] indices; private float[] colors; private int index_vecs; private int index_indices; private int index_uvs; private int index_colors; private int texturenr; private int[] mTextures; private float uniformscale = 1.0f; float[] mCharacterWidth; public TextManager(Context context) { // Create the arrays vecs = new float[3 * 10]; colors = new float[4 * 10]; uvs = new float[2 * 10]; indices = new short[10]; // init as 0 as default texturenr = 0; // Text shader int vshadert = TextManager.loadShader(GLES20.GL_VERTEX_SHADER, TextManager.vs_Text); int fshadert = TextManager.loadShader(GLES20.GL_FRAGMENT_SHADER, TextManager.fs_Text); TextManager.sp_Text = GLES20.glCreateProgram(); GLES20.glAttachShader(TextManager.sp_Text, vshadert); GLES20.glAttachShader(TextManager.sp_Text, fshadert); // add the fragment shader to program GLES20.glLinkProgram(TextManager.sp_Text); // creates OpenGL ES program executables // Generate Textures, if more needed, alter these numbers. mTextures = new int[1]; GLES20.glGenTextures(1, mTextures, 0); // Create an empty, mutable bitmap Bitmap bitmap = Bitmap.createBitmap(RI_TEXT_TEXTURE_SIZE, RI_TEXT_TEXTURE_SIZE, Bitmap.Config.ARGB_4444); // get a canvas to paint over the bitmap Canvas canvas = new Canvas(bitmap); bitmap.eraseColor(0); // Draw the text TextPaint textPaint = new TextPaint(); textPaint.setTextSize(RI_TEXT_HEIGHT_BASE); textPaint.setColor(Color.WHITE); textPaint.setAntiAlias(true); textPaint.setTypeface(Typeface.create("Arial", Typeface.BOLD)); // compute real maximum height mTextHeight=0.0f; for(char c=RI_TEXT_START; c mTextHeight) { mTextHeight = textBounds.height() + textBounds.bottom; } } mUVWidth = (float)RI_TEXT_HEIGHT_BASE/(float)RI_TEXT_TEXTURE_SIZE; mUVHeight = mTextHeight/(float)RI_TEXT_TEXTURE_SIZE; int colCount = RI_TEXT_TEXTURE_SIZE/(int)RI_TEXT_HEIGHT_BASE; mCharacterWidth = new float[RI_TEXT_STOP-RI_TEXT_START]; int i=0; for(char c=RI_TEXT_START; c txtcollection) { // Reset the indices. index_vecs = 0; index_indices = 0; index_uvs = 0; index_colors = 0; // Get the total amount of characters int charcount = 0; for (TextObject txt : txtcollection) { if(txt!=null) { if(!(txt.text==null)) { charcount += txt.text.length(); } } } // Create the arrays we need with the correct size. vecs = null; colors = null; uvs = null; indices = null; vecs = new float[charcount * 12]; colors = new float[charcount * 16]; uvs = new float[charcount * 8]; indices = new short[charcount * 6]; } public void PrepareDraw(Vector txtcollection) { // Setup all the arrays PrepareDrawInfo(txtcollection); // Using the iterator protects for problems with concurrency for( Iterator< TextObject > it = txtcollection.iterator(); it.hasNext() ; ) { TextObject txt = it.next(); if(txt!=null) { if(!(txt.text==null)) { convertTextToTriangleInfo(txt); } } } } public void Draw(float[] m) { if(vecs.length > 0) { GLES20.glDisable(GLES20.GL_DEPTH_TEST); // Set the correct shader for our grid object. GLES20.glUseProgram(sp_Text); // The vertex buffer. ByteBuffer bb = ByteBuffer.allocateDirect(vecs.length * 4); bb.order(ByteOrder.nativeOrder()); vertexBuffer = bb.asFloatBuffer(); vertexBuffer.put(vecs); vertexBuffer.position(0); // The vertex buffer. ByteBuffer bb3 = ByteBuffer.allocateDirect(colors.length * 4); bb3.order(ByteOrder.nativeOrder()); colorBuffer = bb3.asFloatBuffer(); colorBuffer.put(colors); colorBuffer.position(0); // The texture buffer ByteBuffer bb2 = ByteBuffer.allocateDirect(uvs.length * 4); bb2.order(ByteOrder.nativeOrder()); textureBuffer = bb2.asFloatBuffer(); textureBuffer.put(uvs); textureBuffer.position(0); // initialize byte buffer for the draw list ByteBuffer dlb = ByteBuffer.allocateDirect(indices.length * 2); dlb.order(ByteOrder.nativeOrder()); drawListBuffer = dlb.asShortBuffer(); drawListBuffer.put(indices); drawListBuffer.position(0); // get handle to vertex shader's vPosition member int mPositionHandle = GLES20.glGetAttribLocation(sp_Text, "vPosition"); // Enable a handle to the triangle vertices GLES20.glEnableVertexAttribArray(mPositionHandle); // Prepare the background coordinate data GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBuffer); int mTexCoordLoc = GLES20.glGetAttribLocation(sp_Text, "a_texCoord" ); // Prepare the texturecoordinates GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, textureBuffer); GLES20.glEnableVertexAttribArray ( mPositionHandle ); GLES20.glEnableVertexAttribArray ( mTexCoordLoc ); int mColorHandle = GLES20.glGetAttribLocation(sp_Text, "a_Color"); // Enable a handle to the triangle vertices GLES20.glEnableVertexAttribArray(mColorHandle); // Prepare the background coordinate data GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 0, colorBuffer); // get handle to shape's transformation matrix int mtrxhandle = GLES20.glGetUniformLocation(sp_Text, "uMVPMatrix"); // Apply the projection and view transformation GLES20.glUniformMatrix4fv(mtrxhandle, 1, false, m, 0); int mSamplerLoc = GLES20.glGetUniformLocation (sp_Text, "s_texture" ); // Texture activate unit 0 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); // Bind the texture to this unit. GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]); // Set the sampler texture unit to our selected id GLES20.glUniform1i ( mSamplerLoc, texturenr); // Draw the triangle GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer); // Disable vertex array GLES20.glDisableVertexAttribArray(mPositionHandle); GLES20.glDisableVertexAttribArray(mTexCoordLoc); GLES20.glDisableVertexAttribArray(mColorHandle); } } private void convertTextToTriangleInfo(TextObject val) { // Get attributes from text object float x = val.x; float y = val.y; String text = val.text; // Create for(int j=0; j=mCharacterWidth.length) { // unknown character, we will add a space for it to be save. indx = 0; } int colCount = RI_TEXT_TEXTURE_SIZE/(int)RI_TEXT_HEIGHT_BASE; // Calculate the uv parts int row = indx / colCount; int col = indx % colCount; float v = row * mUVHeight; float v2 = v + mUVHeight; float u = col * mUVWidth; float u2 = u + mCharacterWidth[indx]/(float)RI_TEXT_TEXTURE_SIZE; // Creating the triangle information float[] vec = new float[12]; float[] uv = new float[8]; float[] colors = new float[16]; vec[0] = x; vec[1] = y + (mTextHeight * uniformscale); vec[2] = 0.99f; vec[3] = x; vec[4] = y; vec[5] = 0.99f; vec[6] = x + (mCharacterWidth[indx] * uniformscale); vec[7] = y; vec[8] = 0.99f; vec[9] = x + (mCharacterWidth[indx] * uniformscale); vec[10] = y + (mTextHeight * uniformscale); vec[11] = 0.99f; colors = new float[] {val.color[0], val.color[1], val.color[2], val.color[3], val.color[0], val.color[1], val.color[2], val.color[3], val.color[0], val.color[1], val.color[2], val.color[3], val.color[0], val.color[1], val.color[2], val.color[3] }; // 0.001f = texture bleeding hack/fix uv[0] = u+0.001f; uv[1] = v+0.001f; uv[2] = u+0.001f; uv[3] = v2-0.001f; uv[4] = u2-0.001f; uv[5] = v2-0.001f; uv[6] = u2-0.001f; uv[7] = v+0.001f; short[] inds = {0, 1, 2, 0, 2, 3}; // Add our triangle information to our collection for 1 render call. AddCharRenderInformation(vec, colors, uv, inds); // Calculate the new position x += (mCharacterWidth[indx] * uniformscale); } } public float getUniformscale() { return uniformscale; } public void setUniformscale(float uniformscale) { this.uniformscale = uniformscale; } }