• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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.android.globaltime;
18 
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.HashMap;
25 import javax.microedition.khronos.opengles.GL10;
26 
27 import android.graphics.Canvas;
28 import android.graphics.Paint;
29 import android.view.KeyEvent;
30 
31 class Message {
32 
33     private String mText;
34     private long mExpirationTime;
35 
Message(String text, long expirationTime)36     public Message(String text, long expirationTime) {
37         this.mText = text;
38         this.mExpirationTime = expirationTime;
39     }
40 
getText()41     public String getText() {
42         return mText;
43     }
44 
getExpirationTime()45     public long getExpirationTime() {
46         return mExpirationTime;
47     }
48 }
49 
50 /**
51  * A helper class to simplify writing an Activity that renders using
52  * OpenGL ES.
53  *
54  * <p> A GLView object stores common elements of GL state and allows
55  * them to be modified interactively.  This is particularly useful for
56  * determining the proper settings of parameters such as the view
57  * frustum and light intensities during application development.
58  *
59  * <p> A GLView is not an actual View; instead, it is meant to be
60  * called from within a View to perform event processing on behalf of the
61  * actual View.
62  *
63  * <p> By passing key events to the GLView object from the View,
64  * the application can automatically allow certain parameters to
65  * be user-controlled from the keyboard.  Key events may be passed as
66  * shown below:
67  *
68  * <pre>
69  * GLView mGlView = new GLView();
70  *
71  * public boolean onKeyDown(int keyCode, KeyEvent event) {
72  *     // Hand the key to the GLView object first
73  *     if (mGlView.processKey(keyCode)) {
74  *         return;
75  *     }
76  *
77  *     switch (keyCode) {
78  *     case KeyEvent.KEY_CODE_X:
79  *         // perform app processing
80  *         break;
81  *
82  *     default:
83  *         super.onKeyDown(keyCode, event);
84  *         break;
85  *     }
86  * }
87  * </pre>
88  *
89  * <p> During drawing of a frame, the GLView object should be given the
90  * opportunity to manage GL parameters as shown below:
91  *
92  * OpenGLContext mGLContext; // initialization not shown
93  * int mNumTrianglesDrawn = 0;
94  *
95  * protected void onDraw(Canvas canvas) {
96  *     int w = getWidth();
97  *     int h = getHeight();
98  *
99  *     float ratio = (float) w / h;
100  *     mGLView.setAspectRatio(ratio);
101  *
102  *     GL10 gl = (GL10) mGLContext.getGL();
103  *     mGLContext.waitNative(canvas, this);
104  *
105  *     // Enable a light for the GLView to manipulate
106  *     gl.glEnable(GL10.GL_LIGHTING);
107  *     gl.glEnable(GL10.GL_LIGHT0);
108  *
109  *     // Allow the GLView to set GL parameters
110  *     mGLView.setTextureParameters(gl);
111  *     mGLView.setProjection(gl);
112  *     mGLView.setView(gl);
113  *     mGLView.setLights(gl, GL10.GL_LIGHT0);
114  *
115  *     // Draw some stuff (not shown)
116  *     mNumTrianglesDrawn += <num triangles just drawn>;
117  *
118  *     // Wait for GL drawing to complete
119  *     mGLContext.waitGL();
120  *
121  *     // Inform the GLView of what was drawn, and ask it to display statistics
122  *     mGLView.setNumTriangles(mNumTrianglesDrawn);
123  *     mGLView.showMessages(canvas);
124  *     mGLView.showStatistics(canvas, w);
125  * }
126  * </pre>
127  *
128  * <p> At the end of each frame, following the call to
129  * GLContext.waitGL, the showStatistics and showMessages methods
130  * will cause additional information to be displayed.
131  *
132  * <p> To enter the interactive command mode, the 'tab' key must be
133  * pressed twice in succession.  A subsequent press of the 'tab' key
134  * exits the interactive command mode.  Entering a multi-letter code
135  * sets the parameter to be modified. The 'newline' key erases the
136  * current code, and the 'del' key deletes the last letter of
137  * the code. The parameter value may be modified by pressing the
138  * keypad left or up to decrement the value and right or down to
139  * increment the value.  The current value will be displayed as an
140  * overlay above the GL rendered content.
141  *
142  * <p> The supported keyboard commands are as follows:
143  *
144  * <ul>
145  * <li>     h - display a list of commands
146  * <li>    fn - near frustum
147  * <li>    ff - far frustum
148  * <li>    tx - translate x
149  * <li>    ty - translate y
150  * <li>    tz - translate z
151  * <li>     z - zoom (frustum size)
152  * <li>    la - ambient light (all RGB channels)
153  * <li>   lar - ambient light red channel
154  * <li>   lag - ambient light green channel
155  * <li>   lab - ambient light blue channel
156  * <li>    ld - diffuse light (all RGB channels)
157  * <li>   ldr - diffuse light red channel
158  * <li>   ldg - diffuse light green channel
159  * <li>   ldb - diffuse light blue channel
160  * <li>    ls - specular light (all RGB channels)
161  * <li>   lsr - specular light red channel
162  * <li>   lsg - specular light green channel
163  * <li>   lsb - specular light blue channel
164  * <li>   lma - light model ambient (all RGB channels)
165  * <li>  lmar - light model ambient light red channel
166  * <li>  lmag - light model ambient green channel
167  * <li>  lmab - light model ambient blue channel
168  * <li>  tmin - texture min filter
169  * <li>  tmag - texture mag filter
170  * <li>  tper - texture perspective correction
171  * </ul>
172  *
173  * {@hide}
174  */
175 public class GLView {
176 
177     private static final int DEFAULT_DURATION_MILLIS = 1000;
178     private static final int STATE_KEY = KeyEvent.KEYCODE_TAB;
179     private static final int HAVE_NONE = 0;
180     private static final int HAVE_ONE = 1;
181     private static final int HAVE_TWO = 2;
182 
183     private static final float MESSAGE_Y_SPACING = 12.0f;
184 
185     private int mState = HAVE_NONE;
186 
187     private static final int NEAR_FRUSTUM  = 0;
188     private static final int FAR_FRUSTUM   = 1;
189     private static final int TRANSLATE_X   = 2;
190     private static final int TRANSLATE_Y   = 3;
191     private static final int TRANSLATE_Z   = 4;
192     private static final int ZOOM_EXPONENT = 5;
193 
194     private static final int AMBIENT_INTENSITY = 6;
195     private static final int AMBIENT_RED = 7;
196     private static final int AMBIENT_GREEN = 8;
197     private static final int AMBIENT_BLUE = 9;
198 
199     private static final int DIFFUSE_INTENSITY = 10;
200     private static final int DIFFUSE_RED = 11;
201     private static final int DIFFUSE_GREEN = 12;
202     private static final int DIFFUSE_BLUE = 13;
203 
204     private static final int SPECULAR_INTENSITY = 14;
205     private static final int SPECULAR_RED = 15;
206     private static final int SPECULAR_GREEN = 16;
207     private static final int SPECULAR_BLUE = 17;
208 
209     private static final int LIGHT_MODEL_AMBIENT_INTENSITY = 18;
210     private static final int LIGHT_MODEL_AMBIENT_RED = 19;
211     private static final int LIGHT_MODEL_AMBIENT_GREEN = 20;
212     private static final int LIGHT_MODEL_AMBIENT_BLUE = 21;
213 
214     private static final int TEXTURE_MIN_FILTER = 22;
215     private static final int TEXTURE_MAG_FILTER = 23;
216     private static final int TEXTURE_PERSPECTIVE_CORRECTION = 24;
217 
218     private static final String[] commands = {
219         "fn",
220         "ff",
221         "tx",
222         "ty",
223         "tz",
224         "z",
225         "la", "lar", "lag", "lab",
226         "ld", "ldr", "ldg", "ldb",
227         "ls", "lsr", "lsg", "lsb",
228         "lma", "lmar", "lmag", "lmab",
229         "tmin", "tmag", "tper"
230    };
231 
232     private static final String[] labels = {
233         "Near Frustum",
234         "Far Frustum",
235         "Translate X",
236         "Translate Y",
237         "Translate Z",
238         "Zoom",
239         "Ambient Intensity",
240         "Ambient Red",
241         "Ambient Green",
242         "Ambient Blue",
243         "Diffuse Intensity",
244         "Diffuse Red",
245         "Diffuse Green",
246         "Diffuse Blue",
247         "Specular Intenstity",
248         "Specular Red",
249         "Specular Green",
250         "Specular Blue",
251         "Light Model Ambient Intensity",
252         "Light Model Ambient Red",
253         "Light Model Ambient Green",
254         "Light Model Ambient Blue",
255         "Texture Min Filter",
256         "Texture Mag Filter",
257         "Texture Perspective Correction",
258     };
259 
260     private static final float[] defaults = {
261         5.0f, 100.0f,
262         0.0f, 0.0f, -50.0f,
263         0,
264         0.125f,	1.0f, 1.0f, 1.0f,
265         0.125f,	1.0f, 1.0f, 1.0f,
266         0.125f,	1.0f, 1.0f, 1.0f,
267         0.125f,	1.0f, 1.0f, 1.0f,
268         GL10.GL_NEAREST, GL10.GL_NEAREST,
269         GL10.GL_FASTEST
270     };
271 
272     private static final float[] increments = {
273         0.01f, 0.5f,
274         0.125f, 0.125f, 0.125f,
275         1.0f,
276         0.03125f, 0.1f, 0.1f, 0.1f,
277         0.03125f, 0.1f, 0.1f, 0.1f,
278         0.03125f, 0.1f, 0.1f, 0.1f,
279         0.03125f, 0.1f, 0.1f, 0.1f,
280         0, 0, 0
281     };
282 
283     private float[] params = new float[commands.length];
284 
285     private static final float mZoomScale = 0.109f;
286     private static final float mZoomBase  = 1.01f;
287 
288     private int             mParam = -1;
289     private float           mIncr = 0;
290 
291     private Paint           mPaint = new Paint();
292 
293     private float           mAspectRatio = 1.0f;
294 
295     private float           mZoom;
296 
297     // private boolean         mPerspectiveCorrection = false;
298     // private int             mTextureMinFilter = GL10.GL_NEAREST;
299     // private int             mTextureMagFilter = GL10.GL_NEAREST;
300 
301     // Counters for FPS calculation
302     private boolean         mDisplayFPS = false;
303     private boolean         mDisplayCounts = false;
304     private int             mFramesFPS = 10;
305     private long[]          mTimes = new long[mFramesFPS];
306     private int             mTimesIdx = 0;
307 
308     private Map<String,Message> mMessages = new HashMap<String,Message>();
309 
310     /**
311      * Constructs a new GLView.
312      */
GLView()313     public GLView() {
314         mPaint.setColor(0xffffffff);
315         reset();
316     }
317 
318     /**
319      * Sets the aspect ratio (width/height) of the screen.
320      *
321      * @param aspectRatio the screen width divided by the screen height
322      */
setAspectRatio(float aspectRatio)323     public void setAspectRatio(float aspectRatio) {
324         this.mAspectRatio = aspectRatio;
325     }
326 
327     /**
328      * Sets the overall ambient light intensity.  This intensity will
329      * be used to modify the ambient light value for each of the red,
330      * green, and blue channels passed to glLightfv(...GL_AMBIENT...).
331      * The default value is 0.125f.
332      *
333      * @param intensity a floating-point value controlling the overall
334      * ambient light intensity.
335      */
setAmbientIntensity(float intensity)336     public void setAmbientIntensity(float intensity) {
337         params[AMBIENT_INTENSITY] = intensity;
338     }
339 
340     /**
341      * Sets the light model ambient intensity.  This intensity will be
342      * used to modify the ambient light value for each of the red,
343      * green, and blue channels passed to
344      * glLightModelfv(GL_LIGHT_MODEL_AMBIENT...).  The default value
345      * is 0.125f.
346      *
347      * @param intensity a floating-point value controlling the overall
348      * light model ambient intensity.
349      */
setLightModelAmbientIntensity(float intensity)350     public void setLightModelAmbientIntensity(float intensity) {
351         params[LIGHT_MODEL_AMBIENT_INTENSITY] = intensity;
352     }
353 
354     /**
355      * Sets the ambient color for the red, green, and blue channels
356      * that will be multiplied by the value of setAmbientIntensity and
357      * passed to glLightfv(...GL_AMBIENT...).  The default values are
358      * {1, 1, 1}.
359      *
360      * @param ambient an arry of three floats containing ambient
361      * red, green, and blue intensity values.
362      */
setAmbientColor(float[] ambient)363     public void setAmbientColor(float[] ambient) {
364         params[AMBIENT_RED]   = ambient[0];
365         params[AMBIENT_GREEN] = ambient[1];
366         params[AMBIENT_BLUE]  = ambient[2];
367     }
368 
369     /**
370      * Sets the overall diffuse light intensity.  This intensity will
371      * be used to modify the diffuse light value for each of the red,
372      * green, and blue channels passed to glLightfv(...GL_DIFFUSE...).
373      * The default value is 0.125f.
374      *
375      * @param intensity a floating-point value controlling the overall
376      * ambient light intensity.
377      */
setDiffuseIntensity(float intensity)378     public void setDiffuseIntensity(float intensity) {
379         params[DIFFUSE_INTENSITY] = intensity;
380     }
381 
382     /**
383      * Sets the diffuse color for the red, green, and blue channels
384      * that will be multiplied by the value of setDiffuseIntensity and
385      * passed to glLightfv(...GL_DIFFUSE...).  The default values are
386      * {1, 1, 1}.
387      *
388      * @param diffuse an array of three floats containing diffuse
389      * red, green, and blue intensity values.
390      */
setDiffuseColor(float[] diffuse)391     public void setDiffuseColor(float[] diffuse) {
392         params[DIFFUSE_RED]   = diffuse[0];
393         params[DIFFUSE_GREEN] = diffuse[1];
394         params[DIFFUSE_BLUE]  = diffuse[2];
395     }
396 
397     /**
398      * Sets the overall specular light intensity.  This intensity will
399      * be used to modify the diffuse light value for each of the red,
400      * green, and blue channels passed to glLightfv(...GL_SPECULAR...).
401      * The default value is 0.125f.
402      *
403      * @param intensity a floating-point value controlling the overall
404      * ambient light intensity.
405      */
setSpecularIntensity(float intensity)406     public void setSpecularIntensity(float intensity) {
407         params[SPECULAR_INTENSITY] = intensity;
408     }
409 
410     /**
411      * Sets the specular color for the red, green, and blue channels
412      * that will be multiplied by the value of setSpecularIntensity and
413      * passed to glLightfv(...GL_SPECULAR...).  The default values are
414      * {1, 1, 1}.
415      *
416      * @param specular an array of three floats containing specular
417      * red, green, and blue intensity values.
418      */
setSpecularColor(float[] specular)419     public void setSpecularColor(float[] specular) {
420         params[SPECULAR_RED]   = specular[0];
421         params[SPECULAR_GREEN] = specular[1];
422         params[SPECULAR_BLUE]  = specular[2];
423     }
424 
425     /**
426      * Returns the current X translation of the modelview
427      * transformation as passed to glTranslatef.  The default value is
428      * 0.0f.
429      *
430      * @return the X modelview translation as a float.
431      */
getTranslateX()432     public float getTranslateX() {
433         return params[TRANSLATE_X];
434     }
435 
436     /**
437      * Returns the current Y translation of the modelview
438      * transformation as passed to glTranslatef.  The default value is
439      * 0.0f.
440      *
441      * @return the Y modelview translation as a float.
442      */
getTranslateY()443     public float getTranslateY() {
444         return params[TRANSLATE_Y];
445     }
446 
447     /**
448      * Returns the current Z translation of the modelview
449      * transformation as passed to glTranslatef.  The default value is
450      * -50.0f.
451      *
452      * @return the Z modelview translation as a float.
453      */
getTranslateZ()454     public float getTranslateZ() {
455         return params[TRANSLATE_Z];
456     }
457 
458     /**
459      * Sets the position of the near frustum clipping plane as passed
460      * to glFrustumf.  The default value is 5.0f;
461      *
462      * @param nearFrustum the near frustum clipping plane distance as
463      * a float.
464      */
setNearFrustum(float nearFrustum)465     public void setNearFrustum(float nearFrustum) {
466         params[NEAR_FRUSTUM] = nearFrustum;
467     }
468 
469     /**
470      * Sets the position of the far frustum clipping plane as passed
471      * to glFrustumf.  The default value is 100.0f;
472      *
473      * @param farFrustum the far frustum clipping plane distance as a
474      * float.
475      */
setFarFrustum(float farFrustum)476     public void setFarFrustum(float farFrustum) {
477         params[FAR_FRUSTUM] = farFrustum;
478     }
479 
computeZoom()480     private void computeZoom() {
481         mZoom = mZoomScale*(float)Math.pow(mZoomBase, -params[ZOOM_EXPONENT]);
482     }
483 
484     /**
485      * Resets all parameters to their default values.
486      */
reset()487     public void reset() {
488         for (int i = 0; i < params.length; i++) {
489             params[i] = defaults[i];
490         }
491         computeZoom();
492     }
493 
removeExpiredMessages()494     private void removeExpiredMessages() {
495         long now = System.currentTimeMillis();
496 
497         List<String> toBeRemoved = new ArrayList<String>();
498 
499         Iterator<String> keyIter = mMessages.keySet().iterator();
500         while (keyIter.hasNext()) {
501             String key = keyIter.next();
502             Message msg = mMessages.get(key);
503             if (msg.getExpirationTime() < now) {
504                 toBeRemoved.add(key);
505             }
506         }
507 
508         Iterator<String> tbrIter = toBeRemoved.iterator();
509         while (tbrIter.hasNext()) {
510             String key = tbrIter.next();
511             mMessages.remove(key);
512         }
513     }
514 
515     /**
516      * Displays the message overlay on the given Canvas.  The
517      * GLContext.waitGL method should be called prior to calling this
518      * method.  The interactive command display is drawn by this
519      * method.
520      *
521      * @param canvas the Canvas on which messages are to appear.
522      */
showMessages(Canvas canvas)523     public void showMessages(Canvas canvas) {
524         removeExpiredMessages();
525 
526         float y = 10.0f;
527 
528         List<String> l = new ArrayList<String>();
529         l.addAll(mMessages.keySet());
530         Collections.sort(l);
531 
532         Iterator<String> iter = l.iterator();
533         while (iter.hasNext()) {
534             String key = iter.next();
535             String text = mMessages.get(key).getText();
536             canvas.drawText(text, 10.0f, y, mPaint);
537             y += MESSAGE_Y_SPACING;
538         }
539     }
540 
541     private int mTriangles;
542 
543     /**
544      * Sets the number of triangles drawn in the previous frame for
545      * display by the showStatistics method.  The number of triangles
546      * is not computed by GLView but must be supplied by the
547      * calling Activity.
548      *
549      * @param triangles an Activity-supplied estimate of the number of
550      * triangles drawn in the previous frame.
551      */
setNumTriangles(int triangles)552     public void setNumTriangles(int triangles) {
553         this.mTriangles = triangles;
554     }
555 
556     /**
557      * Displays statistics on frames and triangles per second. The
558      * GLContext.waitGL method should be called prior to calling this
559      * method.
560      *
561      * @param canvas the Canvas on which statistics are to appear.
562      * @param width the width of the Canvas.
563      */
showStatistics(Canvas canvas, int width)564     public void showStatistics(Canvas canvas, int width) {
565         long endTime = mTimes[mTimesIdx] = System.currentTimeMillis();
566         mTimesIdx = (mTimesIdx + 1) % mFramesFPS;
567 
568         float th = mPaint.getTextSize();
569 
570         if (mDisplayFPS) {
571             // Use end time from mFramesFPS frames ago
572             long startTime = mTimes[mTimesIdx];
573             String fps = "" + (1000.0f*mFramesFPS/(endTime - startTime));
574 
575             // Normalize fps to XX.XX format
576             if (fps.indexOf(".") == 1) {
577                 fps = " " + fps;
578             }
579             int len = fps.length();
580             if (len == 2) {
581                 fps += ".00";
582             } else if (len == 4) {
583                 fps += "0";
584             } else if (len > 5) {
585                 fps = fps.substring(0, 5);
586             }
587 
588             canvas.drawText(fps + " fps", width - 60.0f, 10.0f, mPaint);
589         }
590 
591         if (mDisplayCounts) {
592             canvas.drawText(mTriangles + " triangles",
593                             width - 100.0f, 10.0f + th + 5, mPaint);
594         }
595     }
596 
addMessage(String key, String text, int durationMillis)597     private void addMessage(String key, String text, int durationMillis) {
598         long expirationTime = System.currentTimeMillis() + durationMillis;
599 
600         mMessages.put(key, new Message(text, expirationTime));
601     }
602 
addMessage(String key, String text)603     private void addMessage(String key, String text) {
604         addMessage(key, text, DEFAULT_DURATION_MILLIS);
605     }
606 
addMessage(String text)607     private void addMessage(String text) {
608         addMessage(text, text, DEFAULT_DURATION_MILLIS);
609     }
610 
clearMessages()611     private void clearMessages() {
612         mMessages.clear();
613     }
614 
615     String command = "";
616 
toggleFilter()617     private void toggleFilter() {
618         if (params[mParam] == GL10.GL_NEAREST) {
619             params[mParam] = GL10.GL_LINEAR;
620         } else {
621             params[mParam] = GL10.GL_NEAREST;
622         }
623         addMessage(commands[mParam],
624                    "Texture " +
625                    (mParam == TEXTURE_MIN_FILTER ? "min" : "mag") +
626                    " filter = " +
627                    (params[mParam] == GL10.GL_NEAREST ?
628                     "nearest" : "linear"));
629     }
630 
togglePerspectiveCorrection()631     private void togglePerspectiveCorrection() {
632         if (params[mParam] == GL10.GL_NICEST) {
633             params[mParam] = GL10.GL_FASTEST;
634         } else {
635             params[mParam] = GL10.GL_NICEST;
636         }
637         addMessage(commands[mParam],
638                    "Texture perspective correction = " +
639                    (params[mParam] == GL10.GL_FASTEST ?
640                     "fastest" : "nicest"));
641     }
642 
valueString()643     private String valueString() {
644         if (mParam == TEXTURE_MIN_FILTER ||
645             mParam == TEXTURE_MAG_FILTER) {
646             if (params[mParam] == GL10.GL_NEAREST) {
647                 return "nearest";
648             }
649             if (params[mParam] == GL10.GL_LINEAR) {
650                 return "linear";
651             }
652         }
653         if (mParam == TEXTURE_PERSPECTIVE_CORRECTION) {
654             if (params[mParam] == GL10.GL_FASTEST) {
655                 return "fastest";
656             }
657             if (params[mParam] == GL10.GL_NICEST) {
658                 return "nicest";
659             }
660         }
661         return "" + params[mParam];
662     }
663 
664     /**
665      *
666      * @return true if the view
667      */
hasMessages()668     public boolean hasMessages() {
669         return mState == HAVE_TWO || mDisplayFPS || mDisplayCounts;
670     }
671 
672     /**
673      * Process a key stroke.  The calling Activity should pass all
674      * keys from its onKeyDown method to this method.  If the key is
675      * part of a GLView command, true is returned and the calling
676      * Activity should ignore the key event.  Otherwise, false is
677      * returned and the calling Activity may process the key event
678      * normally.
679      *
680      * @param keyCode the key code as passed to Activity.onKeyDown.
681      *
682      * @return true if the key is part of a GLView command sequence,
683      * false otherwise.
684      */
processKey(int keyCode)685     public boolean processKey(int keyCode) {
686         // Pressing the state key twice enters the UI
687         // Pressing it again exits the UI
688         if ((keyCode == STATE_KEY) ||
689             (keyCode == KeyEvent.KEYCODE_SLASH) ||
690             (keyCode == KeyEvent.KEYCODE_PERIOD))
691         {
692             mState = (mState + 1) % 3;
693             if (mState == HAVE_NONE) {
694                 clearMessages();
695             }
696             if (mState == HAVE_TWO) {
697                 clearMessages();
698                 addMessage("aaaa", "GL", Integer.MAX_VALUE);
699                 addMessage("aaab", "", Integer.MAX_VALUE);
700                 command = "";
701             }
702             return true;
703         } else {
704             if (mState == HAVE_ONE) {
705                 mState = HAVE_NONE;
706                 return false;
707             }
708         }
709 
710         // If we're not in the UI, exit without handling the key
711         if (mState != HAVE_TWO) {
712             return false;
713         }
714 
715         if (keyCode == KeyEvent.KEYCODE_ENTER) {
716             command = "";
717         } else if (keyCode == KeyEvent.KEYCODE_DEL) {
718             if (command.length() > 0) {
719                 command = command.substring(0, command.length() - 1);
720             }
721 
722         } else if (keyCode >= KeyEvent.KEYCODE_A &&
723                    keyCode <= KeyEvent.KEYCODE_Z) {
724             command += "" + (char)(keyCode - KeyEvent.KEYCODE_A + 'a');
725         }
726 
727         addMessage("aaaa", "GL " + command, Integer.MAX_VALUE);
728 
729         if (command.equals("h")) {
730             addMessage("aaaa", "GL", Integer.MAX_VALUE);
731             addMessage("h - help");
732             addMessage("fn/ff - frustum near/far clip Z");
733             addMessage("la/lar/lag/lab - abmient intensity/r/g/b");
734             addMessage("ld/ldr/ldg/ldb - diffuse intensity/r/g/b");
735             addMessage("ls/lsr/lsg/lsb - specular intensity/r/g/b");
736             addMessage("s - toggle statistics display");
737             addMessage("tmin/tmag - texture min/mag filter");
738             addMessage("tpersp - texture perspective correction");
739             addMessage("tx/ty/tz - view translate x/y/z");
740             addMessage("z - zoom");
741             command = "";
742             return true;
743         } else if (command.equals("s")) {
744             mDisplayCounts = !mDisplayCounts;
745             mDisplayFPS = !mDisplayFPS;
746             command = "";
747             return true;
748         }
749 
750         mParam = -1;
751         for (int i = 0; i < commands.length; i++) {
752             if (command.equals(commands[i])) {
753                 mParam = i;
754                 mIncr = increments[i];
755             }
756         }
757         if (mParam == -1) {
758             return true;
759         }
760 
761         boolean addMessage = true;
762 
763         // Increment or decrement
764         if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
765             keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
766             if (mParam == ZOOM_EXPONENT) {
767                 params[mParam] += mIncr;
768                 computeZoom();
769             } else if ((mParam == TEXTURE_MIN_FILTER) ||
770                        (mParam == TEXTURE_MAG_FILTER)) {
771                 toggleFilter();
772             } else if (mParam == TEXTURE_PERSPECTIVE_CORRECTION) {
773                 togglePerspectiveCorrection();
774             } else {
775                 params[mParam] += mIncr;
776             }
777         } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP ||
778                    keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
779             if (mParam == ZOOM_EXPONENT) {
780                 params[mParam] -= mIncr;
781                 computeZoom();
782             } else if ((mParam == TEXTURE_MIN_FILTER) ||
783                        (mParam == TEXTURE_MAG_FILTER)) {
784                 toggleFilter();
785             } else if (mParam == TEXTURE_PERSPECTIVE_CORRECTION) {
786                 togglePerspectiveCorrection();
787             } else {
788                 params[mParam] -= mIncr;
789             }
790         }
791 
792         if (addMessage) {
793             addMessage(commands[mParam],
794                        labels[mParam] + ": " + valueString());
795         }
796 
797         return true;
798     }
799 
800     /**
801      * Zoom in by a given number of steps.  A negative value of steps
802      * zooms out.  Each step zooms in by 1%.
803      *
804      * @param steps the number of steps to zoom by.
805      */
zoom(int steps)806     public void zoom(int steps) {
807         params[ZOOM_EXPONENT] += steps;
808         computeZoom();
809     }
810 
811     /**
812      * Set the projection matrix using glFrustumf.  The left and right
813      * clipping planes are set at -+(aspectRatio*zoom), the bottom and
814      * top clipping planes are set at -+zoom, and the near and far
815      * clipping planes are set to the values set by setNearFrustum and
816      * setFarFrustum or interactively.
817      *
818      * <p> GL side effects:
819      * <ul>
820      *    <li>overwrites the matrix mode</li>
821      *    <li>overwrites the projection matrix</li>
822      * </ul>
823      *
824      * @param gl a GL10 instance whose projection matrix is to be modified.
825      */
setProjection(GL10 gl)826     public void setProjection(GL10 gl) {
827         gl.glMatrixMode(GL10.GL_PROJECTION);
828         gl.glLoadIdentity();
829 
830         if (mAspectRatio >= 1.0f) {
831             gl.glFrustumf(-mAspectRatio*mZoom, mAspectRatio*mZoom,
832                           -mZoom, mZoom,
833                           params[NEAR_FRUSTUM], params[FAR_FRUSTUM]);
834         } else {
835             gl.glFrustumf(-mZoom, mZoom,
836                           -mZoom / mAspectRatio, mZoom / mAspectRatio,
837                           params[NEAR_FRUSTUM], params[FAR_FRUSTUM]);
838         }
839     }
840 
841     /**
842      * Set the modelview matrix using glLoadIdentity and glTranslatef.
843      * The translation values are set interactively.
844      *
845      * <p> GL side effects:
846      * <ul>
847      * <li>overwrites the matrix mode</li>
848      * <li>overwrites the modelview matrix</li>
849      * </ul>
850      *
851      * @param gl a GL10 instance whose modelview matrix is to be modified.
852      */
setView(GL10 gl)853     public void setView(GL10 gl) {
854         gl.glMatrixMode(GL10.GL_MODELVIEW);
855         gl.glLoadIdentity();
856 
857         // Move the viewpoint backwards
858         gl.glTranslatef(params[TRANSLATE_X],
859                         params[TRANSLATE_Y],
860                         params[TRANSLATE_Z]);
861     }
862 
863     /**
864      * Sets texture parameters.
865      *
866      * <p> GL side effects:
867      * <ul>
868      * <li>sets the GL_PERSPECTIVE_CORRECTION_HINT</li>
869      * <li>sets the GL_TEXTURE_MIN_FILTER texture parameter</li>
870      * <li>sets the GL_TEXTURE_MAX_FILTER texture parameter</li>
871      * </ul>
872      *
873      * @param gl a GL10 instance whose texture parameters are to be modified.
874      */
setTextureParameters(GL10 gl)875     public void setTextureParameters(GL10 gl) {
876         gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
877                   (int)params[TEXTURE_PERSPECTIVE_CORRECTION]);
878         gl.glTexParameterf(GL10.GL_TEXTURE_2D,
879                            GL10.GL_TEXTURE_MIN_FILTER,
880                            params[TEXTURE_MIN_FILTER]);
881         gl.glTexParameterf(GL10.GL_TEXTURE_2D,
882                            GL10.GL_TEXTURE_MAG_FILTER,
883                            params[TEXTURE_MAG_FILTER]);
884     }
885 
886     /**
887      * Sets the lighting parameters for the given light.
888      *
889      * <p> GL side effects:
890      * <ul>
891      * <li>sets the GL_LIGHT_MODEL_AMBIENT intensities
892      * <li>sets the GL_AMBIENT intensities for the given light</li>
893      * <li>sets the GL_DIFFUSE intensities for the given light</li>
894      * <li>sets the GL_SPECULAR intensities for the given light</li>
895      * </ul>
896      *
897      * @param gl a GL10 instance whose texture parameters are to be modified.
898      */
setLights(GL10 gl, int lightNum)899     public void setLights(GL10 gl, int lightNum) {
900         float[] light = new float[4];
901         light[3] = 1.0f;
902 
903         float lmi = params[LIGHT_MODEL_AMBIENT_INTENSITY];
904         light[0] = params[LIGHT_MODEL_AMBIENT_RED]*lmi;
905         light[1] = params[LIGHT_MODEL_AMBIENT_GREEN]*lmi;
906         light[2] = params[LIGHT_MODEL_AMBIENT_BLUE]*lmi;
907         gl.glLightModelfv(GL10.GL_LIGHT_MODEL_AMBIENT, light, 0);
908 
909         float ai = params[AMBIENT_INTENSITY];
910         light[0] = params[AMBIENT_RED]*ai;
911         light[1] = params[AMBIENT_GREEN]*ai;
912         light[2] = params[AMBIENT_BLUE]*ai;
913         gl.glLightfv(lightNum, GL10.GL_AMBIENT, light, 0);
914 
915         float di = params[DIFFUSE_INTENSITY];
916         light[0] = params[DIFFUSE_RED]*di;
917         light[1] = params[DIFFUSE_GREEN]*di;
918         light[2] = params[DIFFUSE_BLUE]*di;
919         gl.glLightfv(lightNum, GL10.GL_DIFFUSE, light, 0);
920 
921         float si = params[SPECULAR_INTENSITY];
922         light[0] = params[SPECULAR_RED]*si;
923         light[1] = params[SPECULAR_GREEN]*si;
924         light[2] = params[SPECULAR_BLUE]*si;
925         gl.glLightfv(lightNum, GL10.GL_SPECULAR, light, 0);
926     }
927 }
928