OpenGL ES SDK for Android ARM Developer Center
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
TextObject.java
Go to the documentation of this file.
1 /* Copyright (c) 2013-2017, ARM Limited and Contributors
2  *
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge,
6  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 package com.arm.malideveloper.openglessdk.highqualitytextjava;
22 
24 
25 import java.nio.ByteBuffer;
26 import java.nio.ByteOrder;
27 import java.nio.FloatBuffer;
28 
29 import android.graphics.Bitmap;
30 import android.graphics.Canvas;
31 import android.graphics.Color;
32 import android.graphics.Paint;
33 import android.graphics.PorterDuffXfermode;
35 import android.opengl.GLES20;
36 import android.opengl.GLUtils;
37 import android.opengl.Matrix;
38 
39 public class TextObject {
40 
41  private float theAnimRotZ = 0.0f;
42  private Vector4f thePosition = new Vector4f();
43  private String theText = new String("Empty");;
44  private float textSize = 20;
45  private int bitmapWidth;
46  private int bitmapHeight;
47  private boolean isUpdateNeeded = true;
48  private int theViewportWidth = 0;
49  private int theViewportHeight = 0;
50 
51  // Constructor initialize all necessary members
52  public TextObject() {
53  super();
54  //
55  bitmapWidth = 1;
56  bitmapHeight = 1;
57  }
58 
59  public void setText(String aText) {
60  theText = aText;
61  isUpdateNeeded = true;
62  }
63 
64  public void setPosition(float aX, float aY, float aZ) {
65  thePosition.set(aX, aY, aZ, 1.0f);
66  isUpdateNeeded = true;
67  }
68 
69  public void setRelPos(float aX, float aY, float aZ) {
71  thePosition.y + aY,
72  thePosition.z + aZ);
73 
74  // Preventing going too far-from or close-to the screen
75  if (thePosition.z > 0.9f)
76  thePosition.z = 0.9f;
77  if (thePosition.z < -4.0f)
78  thePosition.z = -4.0f;
79  }
80 
81  void update() {
82  if (isUpdateNeeded == false)
83  return;
84  /* [Update Text Size] */
85  // 1. Calculate bounding box in screen coordinates with current matrices
86  Vector4f cLT = new Vector4f(-0.5f,-0.5f, 0.0f, 1.0f);
87  Vector4f cLB = new Vector4f(-0.5f, 0.5f, 0.0f, 1.0f);
88  Vector4f cRT = new Vector4f( 0.5f,-0.5f, 0.0f, 1.0f);
89  Vector4f cRB = new Vector4f( 0.5f, 0.5f, 0.0f, 1.0f);
90 
91  // Instead of calculating matrices again lets reuse ones which were already calculated
92  // for rendering purpose. One important thing is the update() method must be called
93  // after render() method
94  cLT.makePixelCoords(mMVPMatrix, theViewportWidth, theViewportHeight);
95  cLB.makePixelCoords(mMVPMatrix, theViewportWidth, theViewportHeight);
96  cRT.makePixelCoords(mMVPMatrix, theViewportWidth, theViewportHeight);
97  cRB.makePixelCoords(mMVPMatrix, theViewportWidth, theViewportHeight);
98 
99  // 2. Evaluate font size based on the height of bounding box corners
100  Vector4f vl = Vector4f.sub(cLB, cLT);
101  Vector4f vr = Vector4f.sub(cRB, cRT);
102  textSize = (vl.length3() + vr.length3()) / 2.0f;
103  /* [Update Text Size] */
104 
105  // 3. Generate texture with the new evaluated font size
106  drawCanvasToTexture(theText, textSize);
107 
108  android.util.Log.i("INFO", "bmpSize[" + bitmapWidth + ", " + bitmapHeight + "]");
109 
110  isUpdateNeeded = false;
111  }
112 
113  // Load shaders, create vertices, texture coordinates etc.
114  public void init() {
115  // Initialize the triangle vertex array
116  initShapes();
117 
118  int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
119  int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
120  HighQualityTextRenderer.checkGLError("loadShaders");
121 
122  mProgram = GLES20.glCreateProgram(); // Create empty OpenGL Program
123  GLES20.glAttachShader(mProgram, vertexShader); // Add the vertex shader to program
124  HighQualityTextRenderer.checkGLError("glAttachShader:vert");
125  GLES20.glAttachShader(mProgram, fragmentShader); // Add the fragment shader to program
126  HighQualityTextRenderer.checkGLError("glAttachShader:frag");
127  GLES20.glLinkProgram(mProgram); // Creates OpenGL program executables
128  HighQualityTextRenderer.checkGLError("glLinkProgram");
129  GLES20.glUseProgram(mProgram);
130  HighQualityTextRenderer.checkGLError("glUseProgram");
131 
132  // Get handle to the vertex shader's vPosition member
133  maPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
134  HighQualityTextRenderer.checkGLError("glGetAttribLocation:vPosition");
135  // Get handle to the vertex shader's vPosition member
136  maTexCoordsHandle = GLES20.glGetAttribLocation(mProgram, "vTexCoord");
137  HighQualityTextRenderer.checkGLError("glGetAttribLocation:vTexCoord");
138  // get handle to uniform parameter
139  muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
140  HighQualityTextRenderer.checkGLError("glGetUniformLocation:uMVPMatrix");
141  muTextureHandle = GLES20.glGetUniformLocation(mProgram, "u_s2dTexture");
142  HighQualityTextRenderer.checkGLError("glGetUniformLocation:u_s2dTexture");
143 
144  GLES20.glHint(GLES20.GL_GENERATE_MIPMAP_HINT, GLES20.GL_NICEST);
145  HighQualityTextRenderer.checkGLError("glHint");
146  GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
147  HighQualityTextRenderer.checkGLError("glActiveTexture");
148  GLES20.glGenTextures(1, textureId, 0);
149  HighQualityTextRenderer.checkGLError("glGenTextures");
150  //
151  GLES20.glUniform1i(muTextureHandle, 0);
152  HighQualityTextRenderer.checkGLError("glUniform1i");
153  GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId[0]);
154  HighQualityTextRenderer.checkGLError("glBindTexture");
155  // Setup texture parameters
156  GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
157  HighQualityTextRenderer.checkGLError("glTexParameterf:GL_TEXTURE_MAG_FILTER");
158  GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR);
159  HighQualityTextRenderer.checkGLError("glTexParameterf:GL_TEXTURE_MIN_FILTER");
160  GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
161  HighQualityTextRenderer.checkGLError("glTexParameterf:GL_TEXTURE_WRAP_S");
162  GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
163  HighQualityTextRenderer.checkGLError("glTexParameterf:GL_TEXTURE_WRAP_T");
164  }
165 
166 
167  public void render() {
168  // Add program to OpenGL environment
169  GLES20.glUseProgram(mProgram);
170 
171  theAnimRotZ += 0.5f;
172 
173  // Apply a ModelView Projection transformation
174  Matrix.setIdentityM(mMMatrix, 0);
175  Matrix.rotateM(mMMatrix, 0, theAnimRotZ, 0.0f, 0.0f, 1.0f);
176  Matrix.scaleM(mMMatrix, 0, (float)bitmapWidth / (float)bitmapHeight, (float)1.0f, 1.0f);
177  Matrix.translateM(mMMatrix, 0, thePosition.x, thePosition.y, thePosition.z);
178 
179  Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
180  Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
181 
182  GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
183 
184  // Prepare the triangle data
185  GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 12, quadVB);
186  GLES20.glEnableVertexAttribArray(maPositionHandle);
187  // Prepare the triangle data
188  GLES20.glVertexAttribPointer(maTexCoordsHandle, 3, GLES20.GL_FLOAT, false, 12, quadCB);
189  GLES20.glEnableVertexAttribArray(maTexCoordsHandle);
190 
191  // Draw the triangle
192  GLES20.glDisable(GLES20.GL_CULL_FACE);
193  GLES20.glEnable(GLES20.GL_BLEND);
194  GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
195  GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
196  }
197 
198  void updateCamera(int aWidth,
199  int aHeight) {
200  theViewportWidth = aWidth;
201  theViewportHeight = aHeight;
202 
203  float ratio = (float)aWidth / (float)aHeight;
204 
205  // This projection matrix is applied to object coodinates
206  Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 0.1f, 100.0f);
207  Matrix.setLookAtM(mVMatrix, 0, 0, 0, 1, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
208  //
209  isUpdateNeeded = true;
210  }
211 
212  /* [Draw Canvas To Texture] */
213  private void drawCanvasToTexture(
214  String aText,
215  float aFontSize) {
216 
217  if (aFontSize < 8.0f)
218  aFontSize = 8.0f;
219 
220  if (aFontSize > 500.0f)
221  aFontSize = 500.0f;
222 
223  Paint textPaint = new Paint();
224  textPaint.setTextSize(aFontSize);
225  textPaint.setFakeBoldText(false);
226  textPaint.setAntiAlias(true);
227  textPaint.setARGB(255, 255, 255, 255);
228  // If a hinting is available on the platform you are developing, you should enable it (uncomment the line below).
229  //textPaint.setHinting(Paint.HINTING_ON);
230  textPaint.setSubpixelText(true);
231  textPaint.setXfermode(new PorterDuffXfermode(Mode.SCREEN));
232 
233  float realTextWidth = textPaint.measureText(aText);
234 
235  // Creates a new mutable bitmap, with 128px of width and height
236  bitmapWidth = (int)(realTextWidth + 2.0f);
237  bitmapHeight = (int)aFontSize + 2;
238 
239  Bitmap textBitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
240  textBitmap.eraseColor(Color.argb(0, 255, 255, 255));
241  // Creates a new canvas that will draw into a bitmap instead of rendering into the screen
242  Canvas bitmapCanvas = new Canvas(textBitmap);
243  // Set start drawing position to [1, base_line_position]
244  // The base_line_position may vary from one font to another but it usually is equal to 75% of font size (height).
245  bitmapCanvas.drawText(aText, 1, 1.0f + aFontSize * 0.75f, textPaint);
246 
247  GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId[0]);
248  HighQualityTextRenderer.checkGLError("glBindTexture");
249  // Assigns the OpenGL texture with the Bitmap
250  GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, textBitmap, 0);
251  // Free memory resources associated with this texture
252  textBitmap.recycle();
253 
254  // After the image has been subloaded to texture, regenerate mipmaps
255  GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
256  HighQualityTextRenderer.checkGLError("glGenerateMipmap");
257  }
258  /* [Draw Canvas To Texture] */
259 
260  private void initShapes(){
261 
262  float quadVerts[] = {
263  // X, Y, Z
264  -0.5f, -0.5f, 0,
265  -0.5f, 0.5f, 0,
266  0.5f, -0.5f, 0,
267  0.5f, 0.5f, 0
268  };
269 
270  float quadCoords[] = {
271  // X, Y, Z
272  0.0f, 1.0f, 0,
273  0.0f, 0.0f, 0,
274  1.0f, 1.0f, 0,
275  1.0f, 0.0f, 0
276  };
277 
278  // Initialize vertex Buffer for triangle
279  ByteBuffer vbb = ByteBuffer.allocateDirect(
280  // (# of coordinate values * 4 bytes per float)
281  quadVerts.length * 4);
282  vbb.order(ByteOrder.nativeOrder()); // Use the device hardware's native byte order
283  quadVB = vbb.asFloatBuffer(); // Create a floating point buffer from the ByteBuffer
284  quadVB.put(quadVerts); // Add the coordinates to the FloatBuffer
285  quadVB.position(0); // Set the buffer to read the first coordinate
286 
287  vbb = ByteBuffer.allocateDirect(
288  // (# of coordinate values * 4 bytes per float)
289  quadCoords.length * 4);
290  vbb.order(ByteOrder.nativeOrder()); // Use the device hardware's native byte order
291  quadCB = vbb.asFloatBuffer(); // Create a floating point buffer from the ByteBuffer
292  quadCB.put(quadCoords); // Add the coordinates to the FloatBuffer
293  quadCB.position(0); // Set the buffer to read the first coordinate
294  }
295 
296  private int loadShader(int type, String shaderCode)
297  {
298  // Create a vertex shader type (GLES20.GL_VERTEX_SHADER)
299  // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
300  int shader = GLES20.glCreateShader(type);
301 
302  // Add the source code to the shader and compile it
303  GLES20.glShaderSource(shader, shaderCode);
304  GLES20.glCompileShader(shader);
305 
306  return shader;
307  }
308 
309  private int muMVPMatrixHandle;
310  private int muTextureHandle;
311  private float[] mMVPMatrix = new float[16];
312  private float[] mMMatrix = new float[16];
313  private float[] mVMatrix = new float[16];
314  private float[] mProjMatrix = new float[16];
315 
316 
317  private int mProgram;
318  private int maPositionHandle;
319  private int maTexCoordsHandle;
320  private int[] textureId = new int[1];
321  private FloatBuffer quadVB;
322  private FloatBuffer quadCB;
323 
324  private final String vertexShaderCode =
325  // This matrix member variable provides a hook to manipulate
326  // the coordinates of the objects that use this vertex shader
327  "uniform mat4 uMVPMatrix; \n" +
328 
329  "attribute vec4 vPosition; \n" +
330  "attribute vec4 vTexCoord; \n" +
331 
332  "varying vec4 v_v4TexCoord; \n" +
333 
334  "void main(){ \n" +
335 
336  // The matrix must be included as a modifier of gl_Position
337  " v_v4TexCoord = vTexCoord; \n" +
338  " gl_Position = uMVPMatrix * vPosition; \n" +
339 
340  "} \n";
341 
342  private final String fragmentShaderCode =
343  "precision mediump float; \n" +
344  "uniform sampler2D u_s2dTexture; \n" +
345  "varying vec4 v_v4TexCoord; \n" +
346  "void main(){ \n" +
347  " gl_FragColor = texture2D(u_s2dTexture, v_v4TexCoord.xy); \n" +
348  "} \n";
349 }
precision highp int
Definition: hiz_cull.cs:38
GLfloat GLfloat f
Definition: gl2ext.h:2707
GLenum type
Definition: gl2ext.h:133
GLint GLint GLint GLint GLint x
Definition: gl2ext.h:574
precision highp float
Definition: hiz_cull.cs:37
GLint y
Definition: gl2ext.h:179