mirror of
https://github.com/introlab/rtabmap_ros.git
synced 2026-10-04 16:57:46 +08:00
444 lines
13 KiB
Java
444 lines
13 KiB
Java
//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<RI_TEXT_STOP; ++c)
|
|
{
|
|
Rect textBounds = new Rect();
|
|
textPaint.getTextBounds(String.valueOf(c), 0, 1, textBounds);
|
|
if(textBounds.height() + textBounds.bottom > 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<RI_TEXT_STOP; ++c)
|
|
{
|
|
Rect textBounds = new Rect();
|
|
textPaint.getTextBounds(String.valueOf(c), 0, 1, textBounds);
|
|
canvas.drawText(String.valueOf(c), (i%colCount)*RI_TEXT_HEIGHT_BASE, (i/colCount) * mTextHeight + RI_TEXT_HEIGHT_BASE, textPaint);
|
|
mCharacterWidth[i] = textPaint.measureText(String.valueOf(c));
|
|
++i;
|
|
}
|
|
|
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
|
|
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
|
|
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
|
|
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
|
|
|
|
//Clean up
|
|
bitmap.recycle();
|
|
}
|
|
|
|
public void setTextureID(int val)
|
|
{
|
|
texturenr = val;
|
|
}
|
|
|
|
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 the shader
|
|
return shader;
|
|
}
|
|
|
|
|
|
public void AddCharRenderInformation(float[] vec, float[] cs, float[] uv, short[] indi)
|
|
{
|
|
// We need a base value because the object has indices related to
|
|
// that object and not to this collection so basicly we need to
|
|
// translate the indices to align with the vertexlocation in ou
|
|
// vecs array of vectors.
|
|
short base = (short) (index_vecs / 3);
|
|
|
|
// We should add the vec, translating the indices to our saved vector
|
|
for(int i=0;i<vec.length;i++)
|
|
{
|
|
vecs[index_vecs] = vec[i];
|
|
index_vecs++;
|
|
}
|
|
|
|
// We should add the colors, so we can use the same texture for multiple effects.
|
|
for(int i=0;i<cs.length;i++)
|
|
{
|
|
colors[index_colors] = cs[i];
|
|
index_colors++;
|
|
}
|
|
|
|
// We should add the uvs
|
|
for(int i=0;i<uv.length;i++)
|
|
{
|
|
uvs[index_uvs] = uv[i];
|
|
index_uvs++;
|
|
}
|
|
|
|
// We handle the indices
|
|
for(int j=0;j<indi.length;j++)
|
|
{
|
|
indices[index_indices] = (short) (base + indi[j]);
|
|
index_indices++;
|
|
}
|
|
}
|
|
|
|
public void PrepareDrawInfo(Vector<TextObject> 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<TextObject> 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<text.length(); j++)
|
|
{
|
|
// get ascii value
|
|
char c = text.charAt(j);
|
|
int c_val = (int)c;
|
|
|
|
int indx = c_val-RI_TEXT_START;
|
|
|
|
if(indx<0 || indx>=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;
|
|
}
|
|
}
|