TextManager.java
Go to the documentation of this file.
1 //package ri.blog.opengl008;
2 package com.introlab.rtabmap;
3 
4 import java.nio.ByteBuffer;
5 import java.nio.ByteOrder;
6 import java.nio.FloatBuffer;
7 import java.nio.ShortBuffer;
8 import java.util.Iterator;
9 import java.util.Vector;
10 
11 import android.content.Context;
12 import android.graphics.Bitmap;
13 import android.graphics.Canvas;
14 import android.graphics.Color;
15 import android.graphics.Rect;
16 import android.graphics.Typeface;
17 import android.opengl.GLES20;
18 import android.opengl.GLUtils;
19 import android.text.TextPaint;
20 import android.util.Log;
21 
22 public class TextManager {
23 
24  /* SHADER Text
25  *
26  * This shader is for rendering 2D text textures straight from a texture
27  * Color and alpha blended.
28  *
29  */
30  public static final String vs_Text =
31  "uniform mat4 uMVPMatrix;" +
32  "attribute vec4 vPosition;" +
33  "attribute vec2 a_texCoord;" +
34  "varying vec2 v_texCoord;" +
35  "void main() {" +
36  " gl_Position = uMVPMatrix * vPosition;" +
37  " v_texCoord = a_texCoord;" +
38  "}";
39  public static final String fs_Text =
40  "precision mediump float;" +
41  "uniform float uColor;" +
42  "varying vec2 v_texCoord;" +
43  "uniform sampler2D s_texture;" +
44  "void main() {" +
45  " gl_FragColor = texture2D( s_texture, v_texCoord );" +
46  " gl_FragColor.rgb *= uColor;" +
47  "}";
48 
49  public static int sp_Text;
50 
51  public static final int RI_TEXT_TEXTURE_SIZE = 512; // 512
52  public static final float RI_TEXT_HEIGHT_BASE = 32.0f;
53  public static final char RI_TEXT_START = ' ';
54  public static final char RI_TEXT_STOP = '\u00B0'+1;
55 
56  public float getMaxTextHeight() {return mTextHeight;}
57 
58  private float mUVWidth;
59  private float mUVHeight;
60  private float mTextHeight;
61  private float mColor;
62 
63  private FloatBuffer vertexBuffer;
64  private FloatBuffer textureBuffer;
65  private ShortBuffer drawListBuffer;
66 
67  private float[] vecs;
68  private float[] uvs;
69  private short[] indices;
70 
71  private int index_vecs;
72  private int index_indices;
73  private int index_uvs;
74 
75  private int texturenr;
76  private int[] mTextures;
77 
78  private float uniformscale = 1.0f;
79 
80  float[] mCharacterWidth;
81 
82  public TextManager(Context context)
83  {
84  // Create the arrays
85  vecs = new float[3 * 10];
86  uvs = new float[2 * 10];
87  indices = new short[10];
88 
89  // init as 0 as default
90  texturenr = 0;
91 
92  // Text shader
93  int vshadert = TextManager.loadShader(GLES20.GL_VERTEX_SHADER, TextManager.vs_Text);
94  int fshadert = TextManager.loadShader(GLES20.GL_FRAGMENT_SHADER, TextManager.fs_Text);
95 
96  TextManager.sp_Text = GLES20.glCreateProgram();
97  GLES20.glAttachShader(TextManager.sp_Text, vshadert);
98  GLES20.glAttachShader(TextManager.sp_Text, fshadert); // add the fragment shader to program
99  GLES20.glLinkProgram(TextManager.sp_Text); // creates OpenGL ES program executables
100 
101  // Generate Textures, if more needed, alter these numbers.
102  mTextures = new int[1];
103  GLES20.glGenTextures(1, mTextures, 0);
104 
105  // Create an empty, mutable bitmap
106  Bitmap bitmap = Bitmap.createBitmap(RI_TEXT_TEXTURE_SIZE, RI_TEXT_TEXTURE_SIZE, Bitmap.Config.ARGB_4444);
107  // get a canvas to paint over the bitmap
108  Canvas canvas = new Canvas(bitmap);
109  bitmap.eraseColor(0);
110 
111  // Draw the text
112  TextPaint textPaint = new TextPaint();
113  textPaint.setTextSize(RI_TEXT_HEIGHT_BASE);
114  textPaint.setColor(Color.WHITE);
115  textPaint.setAntiAlias(true);
116  textPaint.setTypeface(Typeface.create("Arial", Typeface.BOLD));
117 
118  // compute real maximum height
119  mTextHeight=0.0f;
120  for(char c=RI_TEXT_START; c<RI_TEXT_STOP; ++c)
121  {
122  Rect textBounds = new Rect();
123  textPaint.getTextBounds(String.valueOf(c), 0, 1, textBounds);
124  if(textBounds.height() + textBounds.bottom > mTextHeight)
125  {
126  mTextHeight = textBounds.height() + textBounds.bottom;
127  }
128  }
129  mUVWidth = (float)RI_TEXT_HEIGHT_BASE/(float)RI_TEXT_TEXTURE_SIZE;
130  mUVHeight = mTextHeight/(float)RI_TEXT_TEXTURE_SIZE;
131  mColor = 1.0f;
132 
133  int colCount = RI_TEXT_TEXTURE_SIZE/(int)RI_TEXT_HEIGHT_BASE;
134  mCharacterWidth = new float[RI_TEXT_STOP-RI_TEXT_START];
135  int i=0;
136  for(char c=RI_TEXT_START; c<RI_TEXT_STOP; ++c)
137  {
138  Rect textBounds = new Rect();
139  textPaint.getTextBounds(String.valueOf(c), 0, 1, textBounds);
140  canvas.drawText(String.valueOf(c), (i%colCount)*RI_TEXT_HEIGHT_BASE, (i/colCount) * mTextHeight + RI_TEXT_HEIGHT_BASE, textPaint);
141  mCharacterWidth[i] = textPaint.measureText(String.valueOf(c));
142  ++i;
143  }
144 
145  GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
146  GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
147  GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
148  GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
149 
150  //Clean up
151  bitmap.recycle();
152  }
153 
154  public void setTextureID(int val)
155  {
156  texturenr = val;
157  }
158 
159  public static int loadShader(int type, String shaderCode){
160 
161  // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
162  // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
163  int shader = GLES20.glCreateShader(type);
164 
165  // add the source code to the shader and compile it
166  GLES20.glShaderSource(shader, shaderCode);
167  GLES20.glCompileShader(shader);
168 
169  // return the shader
170  return shader;
171  }
172 
173 
174  public void AddCharRenderInformation(float[] vec, float[] cs, float[] uv, short[] indi)
175  {
176  // We need a base value because the object has indices related to
177  // that object and not to this collection so basicly we need to
178  // translate the indices to align with the vertexlocation in ou
179  // vecs array of vectors.
180  short base = (short) (index_vecs / 3);
181 
182  // We should add the vec, translating the indices to our saved vector
183  for(int i=0;i<vec.length;i++)
184  {
185  vecs[index_vecs] = vec[i];
186  index_vecs++;
187  }
188 
189  // We should add the uvs
190  for(int i=0;i<uv.length;i++)
191  {
192  uvs[index_uvs] = uv[i];
193  index_uvs++;
194  }
195 
196  // We handle the indices
197  for(int j=0;j<indi.length;j++)
198  {
199  indices[index_indices] = (short) (base + indi[j]);
200  index_indices++;
201  }
202  }
203 
204  public void PrepareDrawInfo(Vector<TextObject> txtcollection)
205  {
206  // Reset the indices.
207  index_vecs = 0;
208  index_indices = 0;
209  index_uvs = 0;
210 
211  // Get the total amount of characters
212  int charcount = 0;
213  for (TextObject txt : txtcollection) {
214  if(txt!=null)
215  {
216  if(!(txt.text==null))
217  {
218  charcount += txt.text.length();
219  }
220  }
221  }
222 
223  // Create the arrays we need with the correct size.
224  vecs = null;
225  uvs = null;
226  indices = null;
227 
228  vecs = new float[charcount * 12];
229  uvs = new float[charcount * 8];
230  indices = new short[charcount * 6];
231 
232  }
233 
234  public void PrepareDraw(Vector<TextObject> txtcollection)
235  {
236  // Setup all the arrays
237  PrepareDrawInfo(txtcollection);
238 
239  // Using the iterator protects for problems with concurrency
240  for( Iterator< TextObject > it = txtcollection.iterator(); it.hasNext() ; )
241  {
242  TextObject txt = it.next();
243  if(txt!=null)
244  {
245  if(!(txt.text==null))
246  {
248  }
249  }
250  }
251  }
252 
253  public void Draw(float[] m)
254  {
255  if(vecs.length > 0)
256  {
257  GLES20.glDisable(GLES20.GL_DEPTH_TEST);
258  GLES20.glEnable(GLES20.GL_BLEND);
259 
260  // Set the correct shader for our grid object.
261  GLES20.glUseProgram(sp_Text);
262 
263  // The vertex buffer.
264  ByteBuffer bb = ByteBuffer.allocateDirect(vecs.length * 4);
265  bb.order(ByteOrder.nativeOrder());
266  vertexBuffer = bb.asFloatBuffer();
267  vertexBuffer.put(vecs);
268  vertexBuffer.position(0);
269 
270  // The texture buffer
271  ByteBuffer bb2 = ByteBuffer.allocateDirect(uvs.length * 4);
272  bb2.order(ByteOrder.nativeOrder());
273  textureBuffer = bb2.asFloatBuffer();
274  textureBuffer.put(uvs);
275  textureBuffer.position(0);
276 
277  // initialize byte buffer for the draw list
278  ByteBuffer dlb = ByteBuffer.allocateDirect(indices.length * 2);
279  dlb.order(ByteOrder.nativeOrder());
280  drawListBuffer = dlb.asShortBuffer();
281  drawListBuffer.put(indices);
282  drawListBuffer.position(0);
283 
284  // get handle to vertex shader's vPosition member
285  int mPositionHandle = GLES20.glGetAttribLocation(sp_Text, "vPosition");
286 
287  // Enable a handle to the triangle vertices
288  GLES20.glEnableVertexAttribArray(mPositionHandle);
289 
290  // Prepare the background coordinate data
291  GLES20.glVertexAttribPointer(mPositionHandle, 3,
292  GLES20.GL_FLOAT, false,
293  0, vertexBuffer);
294 
295  int mTexCoordLoc = GLES20.glGetAttribLocation(sp_Text, "a_texCoord" );
296 
297  // Prepare the texturecoordinates
298  GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT,
299  false,
300  0, textureBuffer);
301 
302  GLES20.glEnableVertexAttribArray ( mPositionHandle );
303  GLES20.glEnableVertexAttribArray ( mTexCoordLoc );
304 
305  // get handle to shape's transformation matrix
306  int mtrxhandle = GLES20.glGetUniformLocation(sp_Text, "uMVPMatrix");
307 
308  // Apply the projection and view transformation
309  GLES20.glUniformMatrix4fv(mtrxhandle, 1, false, m, 0);
310 
311  // get handle to color value
312  int colorhandle = GLES20.glGetUniformLocation(sp_Text, "uColor");
313  GLES20.glUniform1f(colorhandle, mColor);
314 
315  int mSamplerLoc = GLES20.glGetUniformLocation (sp_Text, "s_texture" );
316 
317  // Texture activate unit 0
318  GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
319  // Bind the texture to this unit.
320  GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
321  // Set the sampler texture unit to our selected id
322  GLES20.glUniform1i ( mSamplerLoc, texturenr);
323 
324  // Draw the triangle
325  GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
326 
327  // Disable vertex array
328  GLES20.glDisableVertexAttribArray(mPositionHandle);
329  GLES20.glDisableVertexAttribArray(mTexCoordLoc);
330  }
331  }
332 
334  {
335  // Get attributes from text object
336  float x = val.x;
337  float y = val.y;
338  String text = val.text;
339 
340  Log.i("RTABMapActivity", String.format("convertTextToTriangleInfo() set status=%s", text));
341 
342  // Create
343  for(int j=0; j<text.length(); j++)
344  {
345  // get ascii value
346  char c = text.charAt(j);
347  int c_val = (int)c;
348 
349  int indx = c_val-RI_TEXT_START;
350 
351  if(indx<0 || indx>=mCharacterWidth.length) {
352  // unknown character, we will add a space for it to be save.
353  indx = 0;
354  }
355 
356  int colCount = RI_TEXT_TEXTURE_SIZE/(int)RI_TEXT_HEIGHT_BASE;
357 
358  // Calculate the uv parts
359  int row = indx / colCount;
360  int col = indx % colCount;
361 
362  float v = row * mUVHeight;
363  float v2 = v + mUVHeight;
364  float u = col * mUVWidth;
365  float u2 = u + mCharacterWidth[indx]/(float)RI_TEXT_TEXTURE_SIZE;
366 
367  // Creating the triangle information
368  float[] vec = new float[12];
369  float[] uv = new float[8];
370  float[] colors = new float[16];
371 
372  vec[0] = x;
373  vec[1] = y + (mTextHeight * uniformscale);
374  vec[2] = 0.99f;
375  vec[3] = x;
376  vec[4] = y;
377  vec[5] = 0.99f;
378  vec[6] = x + (mCharacterWidth[indx] * uniformscale);
379  vec[7] = y;
380  vec[8] = 0.99f;
381  vec[9] = x + (mCharacterWidth[indx] * uniformscale);
382  vec[10] = y + (mTextHeight * uniformscale);
383  vec[11] = 0.99f;
384 
385  colors = new float[]
386  {val.color[0], val.color[1], val.color[2], val.color[3],
387  val.color[0], val.color[1], val.color[2], val.color[3],
388  val.color[0], val.color[1], val.color[2], val.color[3],
389  val.color[0], val.color[1], val.color[2], val.color[3]
390  };
391  // 0.001f = texture bleeding hack/fix
392  uv[0] = u+0.001f;
393  uv[1] = v+0.001f;
394  uv[2] = u+0.001f;
395  uv[3] = v2-0.001f;
396  uv[4] = u2-0.001f;
397  uv[5] = v2-0.001f;
398  uv[6] = u2-0.001f;
399  uv[7] = v+0.001f;
400 
401  short[] inds = {0, 1, 2, 0, 2, 3};
402 
403  // Add our triangle information to our collection for 1 render call.
404  AddCharRenderInformation(vec, colors, uv, inds);
405 
406  // Calculate the new position
407  x += (mCharacterWidth[indx] * uniformscale);
408  }
409  }
410 
411  public float getUniformscale() {
412  return uniformscale;
413  }
414 
415  public void setUniformscale(float uniformscale) {
416  this.uniformscale = uniformscale;
417  }
418 
419  public void setColor(float color) {
420  mColor = color;
421  }
422 }
static int loadShader(int type, String shaderCode)
GLM_FUNC_DECL genType::row_type row(genType const &m, length_t const &index)
void PrepareDrawInfo(Vector< TextObject > txtcollection)
void setUniformscale(float uniformscale)
static final int RI_TEXT_TEXTURE_SIZE
static final float RI_TEXT_HEIGHT_BASE
void AddCharRenderInformation(float[] vec, float[] cs, float[] uv, short[] indi)
void convertTextToTriangleInfo(TextObject val)
void PrepareDraw(Vector< TextObject > txtcollection)


rtabmap
Author(s): Mathieu Labbe
autogenerated on Mon Dec 14 2020 03:37:06