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 36 public Message(String text, long expirationTime) { 37 this.mText = text; 38 this.mExpirationTime = expirationTime; 39 } 40 41 public String getText() { 42 return mText; 43 } 44 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 476 public void setFarFrustum(float farFrustum) { 477 params[FAR_FRUSTUM] = farFrustum; 478 } 479 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 */ 487 public void reset() { 488 for (int i = 0; i < params.length; i++) { 489 params[i] = defaults[i]; 490 } 491 computeZoom(); 492 } 493 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 */ 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 */ 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 */ 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 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 603 private void addMessage(String key, String text) { 604 addMessage(key, text, DEFAULT_DURATION_MILLIS); 605 } 606 607 private void addMessage(String text) { 608 addMessage(text, text, DEFAULT_DURATION_MILLIS); 609 } 610 611 private void clearMessages() { 612 mMessages.clear(); 613 } 614 615 String command = ""; 616 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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