Home | History | Annotate | Download | only in spritetext
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.apis.graphics.spritetext;
     18 
     19 import java.io.IOException;
     20 import java.io.InputStream;
     21 import java.nio.ByteBuffer;
     22 import java.nio.ByteOrder;
     23 import java.nio.FloatBuffer;
     24 import java.nio.ShortBuffer;
     25 
     26 import javax.microedition.khronos.egl.EGLConfig;
     27 import javax.microedition.khronos.opengles.GL10;
     28 
     29 import android.content.Context;
     30 import android.graphics.Bitmap;
     31 import android.graphics.BitmapFactory;
     32 import android.graphics.Paint;
     33 import android.opengl.GLSurfaceView;
     34 import android.opengl.GLU;
     35 import android.opengl.GLUtils;
     36 import android.os.SystemClock;
     37 import android.util.Log;
     38 
     39 import com.example.android.apis.R;
     40 
     41 public class SpriteTextRenderer implements GLSurfaceView.Renderer{
     42 
     43     public SpriteTextRenderer(Context context) {
     44         mContext = context;
     45         mTriangle = new Triangle();
     46         mProjector = new Projector();
     47         mLabelPaint = new Paint();
     48         mLabelPaint.setTextSize(32);
     49         mLabelPaint.setAntiAlias(true);
     50         mLabelPaint.setARGB(0xff, 0x00, 0x00, 0x00);
     51     }
     52 
     53     public void onSurfaceCreated(GL10 gl, EGLConfig config) {
     54         /*
     55          * By default, OpenGL enables features that improve quality
     56          * but reduce performance. One might want to tweak that
     57          * especially on software renderer.
     58          */
     59         gl.glDisable(GL10.GL_DITHER);
     60 
     61         /*
     62          * Some one-time OpenGL initialization can be made here
     63          * probably based on features of this particular context
     64          */
     65         gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
     66                 GL10.GL_FASTEST);
     67 
     68         gl.glClearColor(.5f, .5f, .5f, 1);
     69         gl.glShadeModel(GL10.GL_SMOOTH);
     70         gl.glEnable(GL10.GL_DEPTH_TEST);
     71         gl.glEnable(GL10.GL_TEXTURE_2D);
     72 
     73         /*
     74          * Create our texture. This has to be done each time the
     75          * surface is created.
     76          */
     77 
     78         int[] textures = new int[1];
     79         gl.glGenTextures(1, textures, 0);
     80 
     81         mTextureID = textures[0];
     82         gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
     83 
     84         gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,
     85                 GL10.GL_NEAREST);
     86         gl.glTexParameterf(GL10.GL_TEXTURE_2D,
     87                 GL10.GL_TEXTURE_MAG_FILTER,
     88                 GL10.GL_LINEAR);
     89 
     90         gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
     91                 GL10.GL_CLAMP_TO_EDGE);
     92         gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
     93                 GL10.GL_CLAMP_TO_EDGE);
     94 
     95         gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
     96                 GL10.GL_REPLACE);
     97 
     98         InputStream is = mContext.getResources()
     99                 .openRawResource(R.raw.robot);
    100         Bitmap bitmap;
    101         try {
    102             bitmap = BitmapFactory.decodeStream(is);
    103         } finally {
    104             try {
    105                 is.close();
    106             } catch(IOException e) {
    107                 // Ignore.
    108             }
    109         }
    110 
    111         GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
    112         bitmap.recycle();
    113 
    114         if (mLabels != null) {
    115             mLabels.shutdown(gl);
    116         } else {
    117             mLabels = new LabelMaker(true, 256, 64);
    118         }
    119         mLabels.initialize(gl);
    120         mLabels.beginAdding(gl);
    121         mLabelA = mLabels.add(gl, "A", mLabelPaint);
    122         mLabelB = mLabels.add(gl, "B", mLabelPaint);
    123         mLabelC = mLabels.add(gl, "C", mLabelPaint);
    124         mLabelMsPF = mLabels.add(gl, "ms/f", mLabelPaint);
    125         mLabels.endAdding(gl);
    126 
    127         if (mNumericSprite != null) {
    128             mNumericSprite.shutdown(gl);
    129         } else {
    130             mNumericSprite = new NumericSprite();
    131         }
    132         mNumericSprite.initialize(gl, mLabelPaint);
    133     }
    134 
    135     public void onDrawFrame(GL10 gl) {
    136         /*
    137          * By default, OpenGL enables features that improve quality
    138          * but reduce performance. One might want to tweak that
    139          * especially on software renderer.
    140          */
    141         gl.glDisable(GL10.GL_DITHER);
    142 
    143         gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
    144                 GL10.GL_MODULATE);
    145 
    146         /*
    147          * Usually, the first thing one might want to do is to clear
    148          * the screen. The most efficient way of doing this is to use
    149          * glClear().
    150          */
    151 
    152         gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    153 
    154         /*
    155          * Now we're ready to draw some 3D objects
    156          */
    157 
    158         gl.glMatrixMode(GL10.GL_MODELVIEW);
    159         gl.glLoadIdentity();
    160 
    161         GLU.gluLookAt(gl, 0.0f, 0.0f, -2.5f,
    162                 0.0f, 0.0f, 0.0f,
    163                 0.0f, 1.0f, 0.0f);
    164 
    165         gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    166         gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    167 
    168         gl.glActiveTexture(GL10.GL_TEXTURE0);
    169         gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
    170         gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
    171                 GL10.GL_REPEAT);
    172         gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
    173                 GL10.GL_REPEAT);
    174 
    175         if (false) {
    176             long time = SystemClock.uptimeMillis();
    177             if (mLastTime != 0) {
    178                 long delta = time - mLastTime;
    179                 Log.w("time", Long.toString(delta));
    180             }
    181             mLastTime = time;
    182         }
    183 
    184         long time = SystemClock.uptimeMillis() % 4000L;
    185         float angle = 0.090f * ((int) time);
    186 
    187         gl.glRotatef(angle, 0, 0, 1.0f);
    188         gl.glScalef(2.0f, 2.0f, 2.0f);
    189 
    190         mTriangle.draw(gl);
    191 
    192         mProjector.getCurrentModelView(gl);
    193         mLabels.beginDrawing(gl, mWidth, mHeight);
    194         drawLabel(gl, 0, mLabelA);
    195         drawLabel(gl, 1, mLabelB);
    196         drawLabel(gl, 2, mLabelC);
    197         float msPFX = mWidth - mLabels.getWidth(mLabelMsPF) - 1;
    198         mLabels.draw(gl, msPFX, 0, mLabelMsPF);
    199         mLabels.endDrawing(gl);
    200 
    201         drawMsPF(gl, msPFX);
    202     }
    203 
    204     private void drawMsPF(GL10 gl, float rightMargin) {
    205         long time = SystemClock.uptimeMillis();
    206         if (mStartTime == 0) {
    207             mStartTime = time;
    208         }
    209         if (mFrames++ == SAMPLE_PERIOD_FRAMES) {
    210             mFrames = 0;
    211             long delta = time - mStartTime;
    212             mStartTime = time;
    213             mMsPerFrame = (int) (delta * SAMPLE_FACTOR);
    214         }
    215         if (mMsPerFrame > 0) {
    216             mNumericSprite.setValue(mMsPerFrame);
    217             float numWidth = mNumericSprite.width();
    218             float x = rightMargin - numWidth;
    219             mNumericSprite.draw(gl, x, 0, mWidth, mHeight);
    220         }
    221     }
    222 
    223     private void drawLabel(GL10 gl, int triangleVertex, int labelId) {
    224         float x = mTriangle.getX(triangleVertex);
    225         float y = mTriangle.getY(triangleVertex);
    226         mScratch[0] = x;
    227         mScratch[1] = y;
    228         mScratch[2] = 0.0f;
    229         mScratch[3] = 1.0f;
    230         mProjector.project(mScratch, 0, mScratch, 4);
    231         float sx = mScratch[4];
    232         float sy = mScratch[5];
    233         float height = mLabels.getHeight(labelId);
    234         float width = mLabels.getWidth(labelId);
    235         float tx = sx - width * 0.5f;
    236         float ty = sy - height * 0.5f;
    237         mLabels.draw(gl, tx, ty, labelId);
    238     }
    239 
    240     public void onSurfaceChanged(GL10 gl, int w, int h) {
    241         mWidth = w;
    242         mHeight = h;
    243         gl.glViewport(0, 0, w, h);
    244         mProjector.setCurrentView(0, 0, w, h);
    245 
    246         /*
    247         * Set our projection matrix. This doesn't have to be done
    248         * each time we draw, but usually a new projection needs to
    249         * be set when the viewport is resized.
    250         */
    251 
    252         float ratio = (float) w / h;
    253         gl.glMatrixMode(GL10.GL_PROJECTION);
    254         gl.glLoadIdentity();
    255         gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
    256         mProjector.getCurrentProjection(gl);
    257     }
    258 
    259     private int mWidth;
    260     private int mHeight;
    261     private Context mContext;
    262     private Triangle mTriangle;
    263     private int mTextureID;
    264     private int mFrames;
    265     private int mMsPerFrame;
    266     private final static int SAMPLE_PERIOD_FRAMES = 12;
    267     private final static float SAMPLE_FACTOR = 1.0f / SAMPLE_PERIOD_FRAMES;
    268     private long mStartTime;
    269     private LabelMaker mLabels;
    270     private Paint mLabelPaint;
    271     private int mLabelA;
    272     private int mLabelB;
    273     private int mLabelC;
    274     private int mLabelMsPF;
    275     private Projector mProjector;
    276     private NumericSprite mNumericSprite;
    277     private float[] mScratch = new float[8];
    278     private long mLastTime;
    279 }
    280 
    281 class Triangle {
    282     public Triangle() {
    283 
    284         // Buffers to be passed to gl*Pointer() functions
    285         // must be direct, i.e., they must be placed on the
    286         // native heap where the garbage collector cannot
    287         // move them.
    288         //
    289         // Buffers with multi-byte datatypes (e.g., short, int, float)
    290         // must have their byte order set to native order
    291 
    292         ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
    293         vbb.order(ByteOrder.nativeOrder());
    294         mFVertexBuffer = vbb.asFloatBuffer();
    295 
    296         ByteBuffer tbb = ByteBuffer.allocateDirect(VERTS * 2 * 4);
    297         tbb.order(ByteOrder.nativeOrder());
    298         mTexBuffer = tbb.asFloatBuffer();
    299 
    300         ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);
    301         ibb.order(ByteOrder.nativeOrder());
    302         mIndexBuffer = ibb.asShortBuffer();
    303 
    304         for (int i = 0; i < VERTS; i++) {
    305             for(int j = 0; j < 3; j++) {
    306                 mFVertexBuffer.put(sCoords[i*3+j]);
    307             }
    308         }
    309 
    310         for (int i = 0; i < VERTS; i++) {
    311             for(int j = 0; j < 2; j++) {
    312                 mTexBuffer.put(sCoords[i*3+j] * 2.0f + 0.5f);
    313             }
    314         }
    315 
    316         for(int i = 0; i < VERTS; i++) {
    317             mIndexBuffer.put((short) i);
    318         }
    319 
    320         mFVertexBuffer.position(0);
    321         mTexBuffer.position(0);
    322         mIndexBuffer.position(0);
    323     }
    324 
    325     public void draw(GL10 gl) {
    326         gl.glFrontFace(GL10.GL_CCW);
    327         gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
    328         gl.glEnable(GL10.GL_TEXTURE_2D);
    329         gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTexBuffer);
    330         gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, VERTS,
    331                 GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
    332     }
    333 
    334     public float getX(int vertex) {
    335         return sCoords[3*vertex];
    336     }
    337 
    338     public float getY(int vertex) {
    339         return sCoords[3*vertex+1];
    340     }
    341 
    342     private final static int VERTS = 3;
    343 
    344     private FloatBuffer mFVertexBuffer;
    345     private FloatBuffer mTexBuffer;
    346     private ShortBuffer mIndexBuffer;
    347     // A unit-sided equalateral triangle centered on the origin.
    348     private final static float[] sCoords = {
    349             // X, Y, Z
    350             -0.5f, -0.25f, 0,
    351              0.5f, -0.25f, 0,
    352              0.0f,  0.559016994f, 0
    353     };
    354 }
    355