• 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