SHARE
TWEET

GLPixelFont2.java

ulfben Mar 16th, 2019 (edited) 77 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // GLPixelFont2 provides meshes to render basic ASCII characters in OpenGL.
  2. // The font is fixed-width 5x7, and contains [0,9], uppercase [A,Z] and - . : = ?
  3. // Sample: https://giphy.com/gifs/text-opengl-pixelfont-BZiUFIQN3gGlnS7fie
  4. // Ulf Benjaminsson, 2019-03-15, ulfbenjaminsson.com
  5.  
  6. // The first GLPixelFont stored "pixels" as char '1' / '0'. A char is 2 bytes in Java, so:
  7. //      46 (characters) * 7 (height) * 5 (width) * 16 (bits) = 25760 bit, or 3220 bytes
  8. //      See: https://pastebin.com/MA7ZuB6Q
  9. // Version 2 stores "pixels" as bits in a byte array, so:
  10. //      46 (characters) * 7 (height) * 8 (width) * 1 (bits) = 2576 bit, or 322 byte
  11. //      Ergo: 10x less memory.
  12.  
  13. public class GLPixelFont2 {
  14.     private static final int HEIGHT = 7; //characters are 7 units tall
  15.     private static final int WIDTH = 8; //characters are 8 units wide
  16.     private static final int CHAR_COUNT = 46; //the font definition contains 46 entries
  17.     private static final int OFFSET = 45; //it start at ASCII code 45 "-", and ends at 90 "Z".
  18.     private static final float SCALE = 0.75f; //scale vertex coordinates.
  19.     private final Mesh[] _glyphs = new Mesh[CHAR_COUNT]; //a vertex buffer for each glyph, for rendering with OpenGL.
  20.  
  21.     public GLPixelFont2() {
  22.         for (int c = 0; c < CHAR_COUNT; c++) {
  23.             _glyphs[c] = null;
  24.         }
  25.     }
  26.     //invalid characters will be null - make sure your renderer skips those!
  27.     public Mesh[] getString(final String s){
  28.         final int count = s.length();
  29.         final Mesh[] result = new Mesh[count];
  30.         for(int i = 0; i < count; i++){
  31.             result[i] = getChar(s.charAt(i));
  32.         }
  33.         return result;
  34.     }
  35.  
  36.     public Mesh getChar(char c){
  37.         c = Character.toUpperCase(c);
  38.         if(c < OFFSET || c >= OFFSET+CHAR_COUNT){
  39.             return null;
  40.         }
  41.         final int i = c - OFFSET;
  42.         if(_glyphs[i] == null){
  43.             _glyphs[i] = createMeshForGlyph(c);
  44.         }
  45.         return _glyphs[i];
  46.     }
  47.  
  48.     private Mesh createMeshForGlyph(final char c){
  49.         assert(c >= OFFSET && c < OFFSET+CHAR_COUNT);
  50.         final int charIndex = c-OFFSET;
  51.         final float z = 0;
  52.         final float[] vertices = new float[HEIGHT*WIDTH*Mesh.COORDS_PER_VERTEX];
  53.         int i = 0;
  54.         for (int y = 0; y < HEIGHT; y++) {
  55.             for (int x = 0; x < WIDTH; x++) {
  56.                 final int posByte = HEIGHT * charIndex + (x/WIDTH) + y; //thank Bog for Wolfram Alpha!
  57.                 final int posBit = x;
  58.                 final int bit = (BITMAP[posByte] >> (7-posBit) & 0x01);
  59.                 if((BITMAP[posByte] >> (7-posBit) & 0x01) == 0){continue;}
  60.                 vertices[i++] =  x*SCALE;
  61.                 vertices[i++] = -y*SCALE; //OpenGL has inverted y-axis.
  62.                 vertices[i++] =  z;
  63.             }
  64.         }
  65.         final float[] clean = Arrays.copyOfRange(vertices, 0, i);
  66.         return new Mesh(clean, GLES20.GL_POINTS);
  67.     }
  68.  
  69.     private static final byte[] BITMAP = {
  70.         /*[ind  asc sym]*/
  71.         /*[0    45  '-']*/  0x0, 0x0, 0x0, 0x1f, 0x0, 0x0, 0x0,
  72.         /*[1    46  '.']*/  0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xc,
  73.         /*[2    47  '/']*/  0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
  74.         /*[3    48  '0']*/  0xe, 0x11, 0x13, 0x15, 0x19, 0x11, 0xe,
  75.         /*[4    49  '1']*/  0x4, 0xc, 0x4, 0x4, 0x4, 0x4, 0xe,
  76.         /*[5    50  '2']*/  0xe, 0x11, 0x1, 0x2, 0x4, 0x8, 0x1f,
  77.         /*[6    51  '3']*/  0xe, 0x11, 0x1, 0x6, 0x1, 0x11, 0xe,
  78.         /*[7    52  '4']*/  0x2, 0x6, 0xa, 0x12, 0x1f, 0x2, 0x7,
  79.         /*[8    53  '5']*/  0x1f, 0x10, 0x1e, 0x1, 0x1, 0x11, 0xe,
  80.         /*[9    54  '6']*/  0xe, 0x11, 0x10, 0x1e, 0x11, 0x11, 0xe,
  81.         /*[10   55  '7']*/  0x1f, 0x11, 0x2, 0x2, 0x4, 0x4, 0x4,
  82.         /*[11   56  '8']*/  0xe, 0x11, 0x11, 0xe, 0x11, 0x11, 0xe,
  83.         /*[12   57  '9']*/  0xe, 0x11, 0x11, 0xf, 0x1, 0x1, 0xe,
  84.         /*[13   58  ':']*/  0x0, 0xc, 0xc, 0x0, 0xc, 0xc, 0x0,
  85.         /*[14   59  ';']*/  0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
  86.         /*[15   60  '<']*/  0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
  87.         /*[16   61  '=']*/  0x0, 0x0, 0x1f, 0x0, 0x1f, 0x0, 0x0,
  88.         /*[17   62  '>']*/  0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
  89.         /*[18   63  '?']*/  0xe, 0x11, 0x11, 0x2, 0x4, 0x0, 0x4,
  90.         /*[19   64  '@']*/  0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f,
  91.         /*[20   65  'A']*/  0xe, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11,
  92.         /*[21   66  'B']*/  0x1e, 0x11, 0x11, 0x1e, 0x11, 0x11, 0x1e,
  93.         /*[22   67  'C']*/  0xe, 0x11, 0x10, 0x10, 0x10, 0x11, 0xe,
  94.         /*[23   68  'D']*/  0x1e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1e,
  95.         /*[24   69  'E']*/  0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x1f,
  96.         /*[25   70  'F']*/  0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x10,
  97.         /*[26   71  'G']*/  0xe, 0x11, 0x10, 0x17, 0x11, 0x11, 0xe,
  98.         /*[27   72  'H']*/  0x11, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11,
  99.         /*[28   73  'I']*/  0xe, 0x4, 0x4, 0x4, 0x4, 0x4, 0xe,
  100.         /*[29   74  'J']*/  0x1, 0x1, 0x1, 0x1, 0x11, 0x11, 0xe,
  101.         /*[30   75  'K']*/  0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11,
  102.         /*[31   76  'L']*/  0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1f,
  103.         /*[32   77  'M']*/  0x11, 0x1b, 0x15, 0x15, 0x11, 0x11, 0x11,
  104.         /*[33   78  'N']*/  0x11, 0x11, 0x19, 0x15, 0x13, 0x11, 0x11,
  105.         /*[34   79  'O']*/  0xe, 0x11, 0x11, 0x11, 0x11, 0x11, 0xe,
  106.         /*[35   80  'P']*/  0x1e, 0x11, 0x11, 0x1e, 0x10, 0x10, 0x10,
  107.         /*[36   81  'Q']*/  0xe, 0x11, 0x11, 0x11, 0x15, 0x12, 0xd,
  108.         /*[37   82  'R']*/  0x1e, 0x11, 0x11, 0x1e, 0x14, 0x12, 0x11,
  109.         /*[38   83  'S']*/  0xf, 0x10, 0x10, 0xe, 0x1, 0x1, 0x1e,
  110.         /*[39   84  'T']*/  0x1f, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4,
  111.         /*[40   85  'U']*/  0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0xe,
  112.         /*[41   86  'V']*/  0x11, 0x11, 0x11, 0x11, 0x11, 0xa, 0x4,
  113.         /*[42   87  'W']*/  0x11, 0x11, 0x11, 0x15, 0x15, 0x15, 0xa,
  114.         /*[43   88  'X']*/  0x11, 0x11, 0xa, 0x4, 0xa, 0x11, 0x11,
  115.         /*[44   89  'Y']*/  0x11, 0x11, 0x11, 0xa, 0x4, 0x4, 0x4,
  116.         /*[45   90  'Z']*/  0x1f, 0x1, 0x2, 0x4, 0x8, 0x10, 0x1f
  117.     };
  118. }
  119.  
  120. //Mesh.java, to save your struggles. :)
  121. public class Mesh {
  122.     private static final String TAG = "Mesh";
  123.     public static final int SIZE_OF_FLOAT = Float.SIZE/Byte.SIZE; //32bit/8bit = 4 bytes
  124.     public static final int COORDS_PER_VERTEX = 3; //X, Y, Z
  125.     public static final int VERTEX_STRIDE = COORDS_PER_VERTEX * SIZE_OF_FLOAT; // number of bytes per vertex
  126.  
  127.     public FloatBuffer _vertexBuffer = null;
  128.     public int _vertexCount = 0;
  129.     public int _drawMode = GLES20.GL_TRIANGLES;
  130.  
  131.     public Mesh(final float[] geometry){
  132.         init(geometry, GLES20.GL_TRIANGLES);
  133.     }
  134.     public Mesh(final float[] geometry, final int drawMode){
  135.         init(geometry, drawMode);
  136.     }
  137.     private void init(final float[] geometry, final int drawMode){
  138.         setVertices(geometry);
  139.         setDrawmode(drawMode);
  140.     }
  141.  
  142.     public void setDrawmode(int drawMode){
  143.         assert(drawMode == GLES20.GL_TRIANGLES
  144.                 || drawMode == GLES20.GL_LINES
  145.                 || drawMode == GLES20.GL_POINTS);
  146.         _drawMode = drawMode;
  147.     }
  148.  
  149.     public void setVertices(final float[] geometry){
  150.         // create a floating point buffer from a ByteBuffer
  151.         _vertexBuffer = ByteBuffer.allocateDirect(geometry.length * SIZE_OF_FLOAT)
  152.                 .order(ByteOrder.nativeOrder()) // use the device hardware's native byte order
  153.                 .asFloatBuffer();
  154.         _vertexBuffer.put(geometry); //add the coordinates to the FloatBuffer
  155.         _vertexBuffer.position(0); // set the buffer to read the first coordinate
  156.         _vertexCount = geometry.length / COORDS_PER_VERTEX;
  157.     }
  158. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top