auto import from //depot/cupcake/@135843

This commit is contained in:
The Android Open Source Project
2009-03-03 18:28:16 -08:00
parent d2f2b1d7b7
commit d4aee0c0ca
2356 changed files with 0 additions and 295812 deletions

View File

@@ -1,101 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.globaltime;
import javax.microedition.khronos.opengles.GL10;
/**
* A class that draws a ring with a given center and inner and outer radii.
* The inner and outer rings each have a color and the remaining pixels are
* colored by interpolation. GlobalTime uses this class to simulate an
* "atmosphere" around the earth.
*/
public class Annulus extends Shape {
/**
* Constructs an annulus.
*
* @param centerX the X coordinate of the center point
* @param centerY the Y coordinate of the center point
* @param Z the fixed Z for the entire ring
* @param innerRadius the inner radius
* @param outerRadius the outer radius
* @param rInner the red channel of the color of the inner ring
* @param gInner the green channel of the color of the inner ring
* @param bInner the blue channel of the color of the inner ring
* @param aInner the alpha channel of the color of the inner ring
* @param rOuter the red channel of the color of the outer ring
* @param gOuter the green channel of the color of the outer ring
* @param bOuter the blue channel of the color of the outer ring
* @param aOuter the alpha channel of the color of the outer ring
* @param sectors the number of sectors used to approximate curvature
*/
public Annulus(float centerX, float centerY, float Z,
float innerRadius, float outerRadius,
float rInner, float gInner, float bInner, float aInner,
float rOuter, float gOuter, float bOuter, float aOuter,
int sectors) {
super(GL10.GL_TRIANGLES, GL10.GL_UNSIGNED_SHORT,
false, false, true);
int radii = sectors + 1;
int[] vertices = new int[2 * 3 * radii];
int[] colors = new int[2 * 4 * radii];
short[] indices = new short[2 * 3 * radii];
int vidx = 0;
int cidx = 0;
int iidx = 0;
for (int i = 0; i < radii; i++) {
float theta = (i * TWO_PI) / (radii - 1);
float cosTheta = (float) Math.cos(theta);
float sinTheta = (float) Math.sin(theta);
vertices[vidx++] = toFixed(centerX + innerRadius * cosTheta);
vertices[vidx++] = toFixed(centerY + innerRadius * sinTheta);
vertices[vidx++] = toFixed(Z);
vertices[vidx++] = toFixed(centerX + outerRadius * cosTheta);
vertices[vidx++] = toFixed(centerY + outerRadius * sinTheta);
vertices[vidx++] = toFixed(Z);
colors[cidx++] = toFixed(rInner);
colors[cidx++] = toFixed(gInner);
colors[cidx++] = toFixed(bInner);
colors[cidx++] = toFixed(aInner);
colors[cidx++] = toFixed(rOuter);
colors[cidx++] = toFixed(gOuter);
colors[cidx++] = toFixed(bOuter);
colors[cidx++] = toFixed(aOuter);
}
for (int i = 0; i < sectors; i++) {
indices[iidx++] = (short) (2 * i);
indices[iidx++] = (short) (2 * i + 1);
indices[iidx++] = (short) (2 * i + 2);
indices[iidx++] = (short) (2 * i + 1);
indices[iidx++] = (short) (2 * i + 3);
indices[iidx++] = (short) (2 * i + 2);
}
allocateBuffers(vertices, null, null, colors, indices);
}
}

View File

@@ -1,241 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.globaltime;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TimeZone;
/**
* A class representing a city, with an associated position, time zone name,
* and raw offset from UTC.
*/
public class City implements Comparable<City> {
private static Map<String,City> cities = new HashMap<String,City>();
private static City[] citiesByRawOffset;
private String name;
private String timeZoneID;
private TimeZone timeZone = null;
private int rawOffset;
private float latitude, longitude;
private float x, y, z;
/**
* Loads the city database. The cities must be stored in order by raw
* offset from UTC.
*/
public static void loadCities(InputStream is) throws IOException {
DataInputStream dis = new DataInputStream(is);
int numCities = dis.readInt();
citiesByRawOffset = new City[numCities];
byte[] buf = new byte[24];
for (int i = 0; i < numCities; i++) {
String name = dis.readUTF();
String tzid = dis.readUTF();
dis.read(buf);
// The code below is a faster version of:
// int rawOffset = dis.readInt();
// float latitude = dis.readFloat();
// float longitude = dis.readFloat();
// float cx = dis.readFloat();
// float cy = dis.readFloat();
// float cz = dis.readFloat();
int rawOffset =
(buf[ 0] << 24) | ((buf[ 1] & 0xff) << 16) |
((buf[ 2] & 0xff) << 8) | (buf[ 3] & 0xff);
int ilat = (buf[ 4] << 24) | ((buf[ 5] & 0xff) << 16) |
((buf[ 6] & 0xff) << 8) | (buf[ 7] & 0xff);
int ilon = (buf[ 8] << 24) | ((buf[ 9] & 0xff) << 16) |
((buf[10] & 0xff) << 8) | (buf[11] & 0xff);
int icx = (buf[12] << 24) | ((buf[13] & 0xff) << 16) |
((buf[14] & 0xff) << 8) | (buf[15] & 0xff);
int icy = (buf[16] << 24) | ((buf[17] & 0xff) << 16) |
((buf[18] & 0xff) << 8) | (buf[19] & 0xff);
int icz = (buf[20] << 24) | ((buf[21] & 0xff) << 16) |
((buf[22] & 0xff) << 8) | (buf[23] & 0xff);
float latitude = Float.intBitsToFloat(ilat);
float longitude = Float.intBitsToFloat(ilon);
float cx = Float.intBitsToFloat(icx);
float cy = Float.intBitsToFloat(icy);
float cz = Float.intBitsToFloat(icz);
City city = new City(name, tzid, rawOffset,
latitude, longitude, cx, cy, cz);
cities.put(name, city);
citiesByRawOffset[i] = city;
}
}
/**
* Returns the cities, ordered by name.
*/
public static City[] getCitiesByName() {
City[] ocities = new City[cities.size()];
Iterator<City> iter = cities.values().iterator();
int idx = 0;
while (iter.hasNext()) {
ocities[idx++] = iter.next();
}
Arrays.sort(ocities);
return ocities;
}
/**
* Returns the cities, ordered by offset, accounting for summer/daylight
* savings time. This requires reading the entire time zone database
* behind the scenes.
*/
public static City[] getCitiesByOffset() {
City[] ocities = new City[cities.size()];
Iterator<City> iter = cities.values().iterator();
int idx = 0;
while (iter.hasNext()) {
ocities[idx++] = iter.next();
}
Arrays.sort(ocities, new Comparator() {
public int compare(Object o1, Object o2) {
long now = System.currentTimeMillis();
City c1 = (City)o1;
City c2 = (City)o2;
TimeZone tz1 = c1.getTimeZone();
TimeZone tz2 = c2.getTimeZone();
int off1 = tz1.getOffset(now);
int off2 = tz2.getOffset(now);
if (off1 == off2) {
float dlat = c2.getLatitude() - c1.getLatitude();
if (dlat < 0.0f) return -1;
if (dlat > 0.0f) return 1;
return 0;
}
return off1 - off2;
}
});
return ocities;
}
/**
* Returns the cities, ordered by offset, accounting for summer/daylight
* savings time. This does not require reading the time zone database
* since the cities are pre-sorted.
*/
public static City[] getCitiesByRawOffset() {
return citiesByRawOffset;
}
/**
* Returns an Iterator over all cities, in raw offset order.
*/
public static Iterator<City> iterator() {
return cities.values().iterator();
}
/**
* Returns the total number of cities.
*/
public static int numCities() {
return cities.size();
}
/**
* Constructs a city with the given name, time zone name, raw offset,
* latitude, longitude, and 3D (X, Y, Z) coordinate.
*/
public City(String name, String timeZoneID,
int rawOffset,
float latitude, float longitude,
float x, float y, float z) {
this.name = name;
this.timeZoneID = timeZoneID;
this.rawOffset = rawOffset;
this.latitude = latitude;
this.longitude = longitude;
this.x = x;
this.y = y;
this.z = z;
}
public String getName() {
return name;
}
public TimeZone getTimeZone() {
if (timeZone == null) {
timeZone = TimeZone.getTimeZone(timeZoneID);
}
return timeZone;
}
public float getLongitude() {
return longitude;
}
public float getLatitude() {
return latitude;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public float getZ() {
return z;
}
public float getRawOffset() {
return rawOffset / 3600000.0f;
}
public int getRawOffsetMillis() {
return rawOffset;
}
/**
* Returns this city's offset from UTC, taking summer/daylight savigns
* time into account.
*/
public float getOffset() {
long now = System.currentTimeMillis();
if (timeZone == null) {
timeZone = TimeZone.getTimeZone(timeZoneID);
}
return timeZone.getOffset(now) / 3600000.0f;
}
/**
* Compares this city to another by name.
*/
public int compareTo(City o) {
return name.compareTo(o.name);
}
}

View File

@@ -1,332 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.globaltime;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.text.format.DateUtils;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
/**
* A class that draws an analog clock face with information about the current
* time in a given city.
*/
public class Clock {
static final int MILLISECONDS_PER_MINUTE = 60 * 1000;
static final int MILLISECONDS_PER_HOUR = 60 * 60 * 1000;
private City mCity = null;
private long mCitySwitchTime;
private long mTime;
private float mColorRed = 1.0f;
private float mColorGreen = 1.0f;
private float mColorBlue = 1.0f;
private long mOldOffset;
private Interpolator mClockHandInterpolator =
new AccelerateDecelerateInterpolator();
public Clock() {
// Empty constructor
}
/**
* Adds a line to the given Path. The line extends from
* radius r0 to radius r1 about the center point (cx, cy),
* at an angle given by pos.
*
* @param path the Path to draw to
* @param radius the radius of the outer rim of the clock
* @param pos the angle, with 0 and 1 at 12:00
* @param cx the X coordinate of the clock center
* @param cy the Y coordinate of the clock center
* @param r0 the starting radius for the line
* @param r1 the ending radius for the line
*/
private static void drawLine(Path path,
float radius, float pos, float cx, float cy, float r0, float r1) {
float theta = pos * Shape.TWO_PI - Shape.PI_OVER_TWO;
float dx = (float) Math.cos(theta);
float dy = (float) Math.sin(theta);
float p0x = cx + dx * r0;
float p0y = cy + dy * r0;
float p1x = cx + dx * r1;
float p1y = cy + dy * r1;
float ox = (p1y - p0y);
float oy = -(p1x - p0x);
float norm = (radius / 2.0f) / (float) Math.sqrt(ox * ox + oy * oy);
ox *= norm;
oy *= norm;
path.moveTo(p0x - ox, p0y - oy);
path.lineTo(p1x - ox, p1y - oy);
path.lineTo(p1x + ox, p1y + oy);
path.lineTo(p0x + ox, p0y + oy);
path.close();
}
/**
* Adds a vertical arrow to the given Path.
*
* @param path the Path to draw to
*/
private static void drawVArrow(Path path,
float cx, float cy, float width, float height) {
path.moveTo(cx - width / 2.0f, cy);
path.lineTo(cx, cy + height);
path.lineTo(cx + width / 2.0f, cy);
path.close();
}
/**
* Adds a horizontal arrow to the given Path.
*
* @param path the Path to draw to
*/
private static void drawHArrow(Path path,
float cx, float cy, float width, float height) {
path.moveTo(cx, cy - height / 2.0f);
path.lineTo(cx + width, cy);
path.lineTo(cx, cy + height / 2.0f);
path.close();
}
/**
* Returns an offset in milliseconds to be subtracted from the current time
* in order to obtain an smooth interpolation between the previously
* displayed time and the current time.
*/
private long getOffset(float lerp) {
long doffset = (long) (mCity.getOffset() *
(float) MILLISECONDS_PER_HOUR - mOldOffset);
int sign;
if (doffset < 0) {
doffset = -doffset;
sign = -1;
} else {
sign = 1;
}
while (doffset > 12L * MILLISECONDS_PER_HOUR) {
doffset -= 12L * MILLISECONDS_PER_HOUR;
}
if (doffset > 6L * MILLISECONDS_PER_HOUR) {
doffset = 12L * MILLISECONDS_PER_HOUR - doffset;
sign = -sign;
}
// Interpolate doffset towards 0
doffset = (long)((1.0f - lerp)*doffset);
// Keep the same seconds count
long dh = doffset / (MILLISECONDS_PER_HOUR);
doffset -= dh * MILLISECONDS_PER_HOUR;
long dm = doffset / MILLISECONDS_PER_MINUTE;
doffset = sign * (60 * dh + dm) * MILLISECONDS_PER_MINUTE;
return doffset;
}
/**
* Set the city to be displayed. setCity(null) resets things so the clock
* hand animation won't occur next time.
*/
public void setCity(City city) {
if (mCity != city) {
if (mCity != null) {
mOldOffset =
(long) (mCity.getOffset() * (float) MILLISECONDS_PER_HOUR);
} else if (city != null) {
mOldOffset =
(long) (city.getOffset() * (float) MILLISECONDS_PER_HOUR);
} else {
mOldOffset = 0L; // this will never be used
}
this.mCitySwitchTime = System.currentTimeMillis();
this.mCity = city;
}
}
public void setTime(long time) {
this.mTime = time;
}
/**
* Draws the clock face.
*
* @param canvas the Canvas to draw to
* @param cx the X coordinate of the clock center
* @param cy the Y coordinate of the clock center
* @param radius the radius of the clock face
* @param alpha the translucency of the clock face
* @param textAlpha the translucency of the text
* @param showCityName if true, display the city name
* @param showTime if true, display the time digitally
* @param showUpArrow if true, display an up arrow
* @param showDownArrow if true, display a down arrow
* @param showLeftRightArrows if true, display left and right arrows
* @param prefixChars number of characters of the city name to draw in bold
*/
public void drawClock(Canvas canvas,
float cx, float cy, float radius, float alpha, float textAlpha,
boolean showCityName, boolean showTime,
boolean showUpArrow, boolean showDownArrow, boolean showLeftRightArrows,
int prefixChars) {
Paint paint = new Paint();
paint.setAntiAlias(true);
int iradius = (int)radius;
TimeZone tz = mCity.getTimeZone();
// Compute an interpolated time to animate between the previously
// displayed time and the current time
float lerp = Math.min(1.0f,
(System.currentTimeMillis() - mCitySwitchTime) / 500.0f);
lerp = mClockHandInterpolator.getInterpolation(lerp);
long doffset = lerp < 1.0f ? getOffset(lerp) : 0L;
// Determine the interpolated time for the given time zone
Calendar cal = Calendar.getInstance(tz);
cal.setTimeInMillis(mTime - doffset);
int hour = cal.get(Calendar.HOUR_OF_DAY);
int minute = cal.get(Calendar.MINUTE);
int second = cal.get(Calendar.SECOND);
int milli = cal.get(Calendar.MILLISECOND);
float offset = tz.getRawOffset() / (float) MILLISECONDS_PER_HOUR;
float daylightOffset = tz.inDaylightTime(new Date(mTime)) ?
tz.getDSTSavings() / (float) MILLISECONDS_PER_HOUR : 0.0f;
float absOffset = offset < 0 ? -offset : offset;
int offsetH = (int) absOffset;
int offsetM = (int) (60.0f * (absOffset - offsetH));
hour %= 12;
// Get the city name and digital time strings
String cityName = mCity.getName();
cal.setTimeInMillis(mTime);
String time = DateUtils.timeString(cal.getTimeInMillis()) + " " +
DateUtils.getDayOfWeekString(cal.get(Calendar.DAY_OF_WEEK),
DateUtils.LENGTH_SHORT) + " " +
" (UTC" +
(offset >= 0 ? "+" : "-") +
offsetH +
(offsetM == 0 ? "" : ":" + offsetM) +
(daylightOffset == 0 ? "" : "+" + daylightOffset) +
")";
float th = paint.getTextSize();
float tw;
// Set the text color
paint.setARGB((int) (textAlpha * 255.0f),
(int) (mColorRed * 255.0f),
(int) (mColorGreen * 255.0f),
(int) (mColorBlue * 255.0f));
tw = paint.measureText(cityName);
if (showCityName) {
// Increment prefixChars to include any spaces
for (int i = 0; i < prefixChars; i++) {
if (cityName.charAt(i) == ' ') {
++prefixChars;
}
}
// Draw the city name
canvas.drawText(cityName, cx - tw / 2, cy - radius - th, paint);
// Overstrike the first 'prefixChars' characters
canvas.drawText(cityName.substring(0, prefixChars),
cx - tw / 2 + 1, cy - radius - th, paint);
}
tw = paint.measureText(time);
if (showTime) {
canvas.drawText(time, cx - tw / 2, cy + radius + th + 5, paint);
}
paint.setARGB((int)(alpha * 255.0f),
(int)(mColorRed * 255.0f),
(int)(mColorGreen * 255.0f),
(int)(mColorBlue * 255.0f));
paint.setStyle(Paint.Style.FILL);
canvas.drawOval(new RectF(cx - 2, cy - 2, cx + 2, cy + 2), paint);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(radius * 0.12f);
canvas.drawOval(new RectF(cx - iradius, cy - iradius,
cx + iradius, cy + iradius),
paint);
float r0 = radius * 0.1f;
float r1 = radius * 0.4f;
float r2 = radius * 0.6f;
float r3 = radius * 0.65f;
float r4 = radius * 0.7f;
float r5 = radius * 0.9f;
Path path = new Path();
float ss = second + milli / 1000.0f;
float mm = minute + ss / 60.0f;
float hh = hour + mm / 60.0f;
// Tics for the hours
for (int i = 0; i < 12; i++) {
drawLine(path, radius * 0.12f, i / 12.0f, cx, cy, r4, r5);
}
// Hour hand
drawLine(path, radius * 0.12f, hh / 12.0f, cx, cy, r0, r1);
// Minute hand
drawLine(path, radius * 0.12f, mm / 60.0f, cx, cy, r0, r2);
// Second hand
drawLine(path, radius * 0.036f, ss / 60.0f, cx, cy, r0, r3);
if (showUpArrow) {
drawVArrow(path, cx + radius * 1.13f, cy - radius,
radius * 0.15f, -radius * 0.1f);
}
if (showDownArrow) {
drawVArrow(path, cx + radius * 1.13f, cy + radius,
radius * 0.15f, radius * 0.1f);
}
if (showLeftRightArrows) {
drawHArrow(path, cx - radius * 1.3f, cy, -radius * 0.1f,
radius * 0.15f);
drawHArrow(path, cx + radius * 1.3f, cy, radius * 0.1f,
radius * 0.15f);
}
paint.setStyle(Paint.Style.FILL);
canvas.drawPath(path, paint);
}
}

View File

@@ -1,927 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.globaltime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import javax.microedition.khronos.opengles.GL10;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.KeyEvent;
class Message {
private String mText;
private long mExpirationTime;
public Message(String text, long expirationTime) {
this.mText = text;
this.mExpirationTime = expirationTime;
}
public String getText() {
return mText;
}
public long getExpirationTime() {
return mExpirationTime;
}
}
/**
* A helper class to simplify writing an Activity that renders using
* OpenGL ES.
*
* <p> A GLView object stores common elements of GL state and allows
* them to be modified interactively. This is particularly useful for
* determining the proper settings of parameters such as the view
* frustum and light intensities during application development.
*
* <p> A GLView is not an actual View; instead, it is meant to be
* called from within a View to perform event processing on behalf of the
* actual View.
*
* <p> By passing key events to the GLView object from the View,
* the application can automatically allow certain parameters to
* be user-controlled from the keyboard. Key events may be passed as
* shown below:
*
* <pre>
* GLView mGlView = new GLView();
*
* public boolean onKeyDown(int keyCode, KeyEvent event) {
* // Hand the key to the GLView object first
* if (mGlView.processKey(keyCode)) {
* return;
* }
*
* switch (keyCode) {
* case KeyEvent.KEY_CODE_X:
* // perform app processing
* break;
*
* default:
* super.onKeyDown(keyCode, event);
* break;
* }
* }
* </pre>
*
* <p> During drawing of a frame, the GLView object should be given the
* opportunity to manage GL parameters as shown below:
*
* OpenGLContext mGLContext; // initialization not shown
* int mNumTrianglesDrawn = 0;
*
* protected void onDraw(Canvas canvas) {
* int w = getWidth();
* int h = getHeight();
*
* float ratio = (float) w / h;
* mGLView.setAspectRatio(ratio);
*
* GL10 gl = (GL10) mGLContext.getGL();
* mGLContext.waitNative(canvas, this);
*
* // Enable a light for the GLView to manipulate
* gl.glEnable(GL10.GL_LIGHTING);
* gl.glEnable(GL10.GL_LIGHT0);
*
* // Allow the GLView to set GL parameters
* mGLView.setTextureParameters(gl);
* mGLView.setProjection(gl);
* mGLView.setView(gl);
* mGLView.setLights(gl, GL10.GL_LIGHT0);
*
* // Draw some stuff (not shown)
* mNumTrianglesDrawn += <num triangles just drawn>;
*
* // Wait for GL drawing to complete
* mGLContext.waitGL();
*
* // Inform the GLView of what was drawn, and ask it to display statistics
* mGLView.setNumTriangles(mNumTrianglesDrawn);
* mGLView.showMessages(canvas);
* mGLView.showStatistics(canvas, w);
* }
* </pre>
*
* <p> At the end of each frame, following the call to
* GLContext.waitGL, the showStatistics and showMessages methods
* will cause additional information to be displayed.
*
* <p> To enter the interactive command mode, the 'tab' key must be
* pressed twice in succession. A subsequent press of the 'tab' key
* exits the interactive command mode. Entering a multi-letter code
* sets the parameter to be modified. The 'newline' key erases the
* current code, and the 'del' key deletes the last letter of
* the code. The parameter value may be modified by pressing the
* keypad left or up to decrement the value and right or down to
* increment the value. The current value will be displayed as an
* overlay above the GL rendered content.
*
* <p> The supported keyboard commands are as follows:
*
* <ul>
* <li> h - display a list of commands
* <li> fn - near frustum
* <li> ff - far frustum
* <li> tx - translate x
* <li> ty - translate y
* <li> tz - translate z
* <li> z - zoom (frustum size)
* <li> la - ambient light (all RGB channels)
* <li> lar - ambient light red channel
* <li> lag - ambient light green channel
* <li> lab - ambient light blue channel
* <li> ld - diffuse light (all RGB channels)
* <li> ldr - diffuse light red channel
* <li> ldg - diffuse light green channel
* <li> ldb - diffuse light blue channel
* <li> ls - specular light (all RGB channels)
* <li> lsr - specular light red channel
* <li> lsg - specular light green channel
* <li> lsb - specular light blue channel
* <li> lma - light model ambient (all RGB channels)
* <li> lmar - light model ambient light red channel
* <li> lmag - light model ambient green channel
* <li> lmab - light model ambient blue channel
* <li> tmin - texture min filter
* <li> tmag - texture mag filter
* <li> tper - texture perspective correction
* </ul>
*
* {@hide}
*/
public class GLView {
private static final int DEFAULT_DURATION_MILLIS = 1000;
private static final int STATE_KEY = KeyEvent.KEYCODE_TAB;
private static final int HAVE_NONE = 0;
private static final int HAVE_ONE = 1;
private static final int HAVE_TWO = 2;
private static final float MESSAGE_Y_SPACING = 12.0f;
private int mState = HAVE_NONE;
private static final int NEAR_FRUSTUM = 0;
private static final int FAR_FRUSTUM = 1;
private static final int TRANSLATE_X = 2;
private static final int TRANSLATE_Y = 3;
private static final int TRANSLATE_Z = 4;
private static final int ZOOM_EXPONENT = 5;
private static final int AMBIENT_INTENSITY = 6;
private static final int AMBIENT_RED = 7;
private static final int AMBIENT_GREEN = 8;
private static final int AMBIENT_BLUE = 9;
private static final int DIFFUSE_INTENSITY = 10;
private static final int DIFFUSE_RED = 11;
private static final int DIFFUSE_GREEN = 12;
private static final int DIFFUSE_BLUE = 13;
private static final int SPECULAR_INTENSITY = 14;
private static final int SPECULAR_RED = 15;
private static final int SPECULAR_GREEN = 16;
private static final int SPECULAR_BLUE = 17;
private static final int LIGHT_MODEL_AMBIENT_INTENSITY = 18;
private static final int LIGHT_MODEL_AMBIENT_RED = 19;
private static final int LIGHT_MODEL_AMBIENT_GREEN = 20;
private static final int LIGHT_MODEL_AMBIENT_BLUE = 21;
private static final int TEXTURE_MIN_FILTER = 22;
private static final int TEXTURE_MAG_FILTER = 23;
private static final int TEXTURE_PERSPECTIVE_CORRECTION = 24;
private static final String[] commands = {
"fn",
"ff",
"tx",
"ty",
"tz",
"z",
"la", "lar", "lag", "lab",
"ld", "ldr", "ldg", "ldb",
"ls", "lsr", "lsg", "lsb",
"lma", "lmar", "lmag", "lmab",
"tmin", "tmag", "tper"
};
private static final String[] labels = {
"Near Frustum",
"Far Frustum",
"Translate X",
"Translate Y",
"Translate Z",
"Zoom",
"Ambient Intensity",
"Ambient Red",
"Ambient Green",
"Ambient Blue",
"Diffuse Intensity",
"Diffuse Red",
"Diffuse Green",
"Diffuse Blue",
"Specular Intenstity",
"Specular Red",
"Specular Green",
"Specular Blue",
"Light Model Ambient Intensity",
"Light Model Ambient Red",
"Light Model Ambient Green",
"Light Model Ambient Blue",
"Texture Min Filter",
"Texture Mag Filter",
"Texture Perspective Correction",
};
private static final float[] defaults = {
5.0f, 100.0f,
0.0f, 0.0f, -50.0f,
0,
0.125f, 1.0f, 1.0f, 1.0f,
0.125f, 1.0f, 1.0f, 1.0f,
0.125f, 1.0f, 1.0f, 1.0f,
0.125f, 1.0f, 1.0f, 1.0f,
GL10.GL_NEAREST, GL10.GL_NEAREST,
GL10.GL_FASTEST
};
private static final float[] increments = {
0.01f, 0.5f,
0.125f, 0.125f, 0.125f,
1.0f,
0.03125f, 0.1f, 0.1f, 0.1f,
0.03125f, 0.1f, 0.1f, 0.1f,
0.03125f, 0.1f, 0.1f, 0.1f,
0.03125f, 0.1f, 0.1f, 0.1f,
0, 0, 0
};
private float[] params = new float[commands.length];
private static final float mZoomScale = 0.109f;
private static final float mZoomBase = 1.01f;
private int mParam = -1;
private float mIncr = 0;
private Paint mPaint = new Paint();
private float mAspectRatio = 1.0f;
private float mZoom;
// private boolean mPerspectiveCorrection = false;
// private int mTextureMinFilter = GL10.GL_NEAREST;
// private int mTextureMagFilter = GL10.GL_NEAREST;
// Counters for FPS calculation
private boolean mDisplayFPS = false;
private boolean mDisplayCounts = false;
private int mFramesFPS = 10;
private long[] mTimes = new long[mFramesFPS];
private int mTimesIdx = 0;
private Map<String,Message> mMessages = new HashMap<String,Message>();
/**
* Constructs a new GLView.
*/
public GLView() {
mPaint.setColor(0xffffffff);
reset();
}
/**
* Sets the aspect ratio (width/height) of the screen.
*
* @param aspectRatio the screen width divided by the screen height
*/
public void setAspectRatio(float aspectRatio) {
this.mAspectRatio = aspectRatio;
}
/**
* Sets the overall ambient light intensity. This intensity will
* be used to modify the ambient light value for each of the red,
* green, and blue channels passed to glLightfv(...GL_AMBIENT...).
* The default value is 0.125f.
*
* @param intensity a floating-point value controlling the overall
* ambient light intensity.
*/
public void setAmbientIntensity(float intensity) {
params[AMBIENT_INTENSITY] = intensity;
}
/**
* Sets the light model ambient intensity. This intensity will be
* used to modify the ambient light value for each of the red,
* green, and blue channels passed to
* glLightModelfv(GL_LIGHT_MODEL_AMBIENT...). The default value
* is 0.125f.
*
* @param intensity a floating-point value controlling the overall
* light model ambient intensity.
*/
public void setLightModelAmbientIntensity(float intensity) {
params[LIGHT_MODEL_AMBIENT_INTENSITY] = intensity;
}
/**
* Sets the ambient color for the red, green, and blue channels
* that will be multiplied by the value of setAmbientIntensity and
* passed to glLightfv(...GL_AMBIENT...). The default values are
* {1, 1, 1}.
*
* @param ambient an arry of three floats containing ambient
* red, green, and blue intensity values.
*/
public void setAmbientColor(float[] ambient) {
params[AMBIENT_RED] = ambient[0];
params[AMBIENT_GREEN] = ambient[1];
params[AMBIENT_BLUE] = ambient[2];
}
/**
* Sets the overall diffuse light intensity. This intensity will
* be used to modify the diffuse light value for each of the red,
* green, and blue channels passed to glLightfv(...GL_DIFFUSE...).
* The default value is 0.125f.
*
* @param intensity a floating-point value controlling the overall
* ambient light intensity.
*/
public void setDiffuseIntensity(float intensity) {
params[DIFFUSE_INTENSITY] = intensity;
}
/**
* Sets the diffuse color for the red, green, and blue channels
* that will be multiplied by the value of setDiffuseIntensity and
* passed to glLightfv(...GL_DIFFUSE...). The default values are
* {1, 1, 1}.
*
* @param diffuse an array of three floats containing diffuse
* red, green, and blue intensity values.
*/
public void setDiffuseColor(float[] diffuse) {
params[DIFFUSE_RED] = diffuse[0];
params[DIFFUSE_GREEN] = diffuse[1];
params[DIFFUSE_BLUE] = diffuse[2];
}
/**
* Sets the overall specular light intensity. This intensity will
* be used to modify the diffuse light value for each of the red,
* green, and blue channels passed to glLightfv(...GL_SPECULAR...).
* The default value is 0.125f.
*
* @param intensity a floating-point value controlling the overall
* ambient light intensity.
*/
public void setSpecularIntensity(float intensity) {
params[SPECULAR_INTENSITY] = intensity;
}
/**
* Sets the specular color for the red, green, and blue channels
* that will be multiplied by the value of setSpecularIntensity and
* passed to glLightfv(...GL_SPECULAR...). The default values are
* {1, 1, 1}.
*
* @param specular an array of three floats containing specular
* red, green, and blue intensity values.
*/
public void setSpecularColor(float[] specular) {
params[SPECULAR_RED] = specular[0];
params[SPECULAR_GREEN] = specular[1];
params[SPECULAR_BLUE] = specular[2];
}
/**
* Returns the current X translation of the modelview
* transformation as passed to glTranslatef. The default value is
* 0.0f.
*
* @return the X modelview translation as a float.
*/
public float getTranslateX() {
return params[TRANSLATE_X];
}
/**
* Returns the current Y translation of the modelview
* transformation as passed to glTranslatef. The default value is
* 0.0f.
*
* @return the Y modelview translation as a float.
*/
public float getTranslateY() {
return params[TRANSLATE_Y];
}
/**
* Returns the current Z translation of the modelview
* transformation as passed to glTranslatef. The default value is
* -50.0f.
*
* @return the Z modelview translation as a float.
*/
public float getTranslateZ() {
return params[TRANSLATE_Z];
}
/**
* Sets the position of the near frustum clipping plane as passed
* to glFrustumf. The default value is 5.0f;
*
* @param nearFrustum the near frustum clipping plane distance as
* a float.
*/
public void setNearFrustum(float nearFrustum) {
params[NEAR_FRUSTUM] = nearFrustum;
}
/**
* Sets the position of the far frustum clipping plane as passed
* to glFrustumf. The default value is 100.0f;
*
* @param farFrustum the far frustum clipping plane distance as a
* float.
*/
public void setFarFrustum(float farFrustum) {
params[FAR_FRUSTUM] = farFrustum;
}
private void computeZoom() {
mZoom = mZoomScale*(float)Math.pow(mZoomBase, -params[ZOOM_EXPONENT]);
}
/**
* Resets all parameters to their default values.
*/
public void reset() {
for (int i = 0; i < params.length; i++) {
params[i] = defaults[i];
}
computeZoom();
}
private void removeExpiredMessages() {
long now = System.currentTimeMillis();
List<String> toBeRemoved = new ArrayList<String>();
Iterator<String> keyIter = mMessages.keySet().iterator();
while (keyIter.hasNext()) {
String key = keyIter.next();
Message msg = mMessages.get(key);
if (msg.getExpirationTime() < now) {
toBeRemoved.add(key);
}
}
Iterator<String> tbrIter = toBeRemoved.iterator();
while (tbrIter.hasNext()) {
String key = tbrIter.next();
mMessages.remove(key);
}
}
/**
* Displays the message overlay on the given Canvas. The
* GLContext.waitGL method should be called prior to calling this
* method. The interactive command display is drawn by this
* method.
*
* @param canvas the Canvas on which messages are to appear.
*/
public void showMessages(Canvas canvas) {
removeExpiredMessages();
float y = 10.0f;
List<String> l = new ArrayList<String>();
l.addAll(mMessages.keySet());
Collections.sort(l);
Iterator<String> iter = l.iterator();
while (iter.hasNext()) {
String key = iter.next();
String text = mMessages.get(key).getText();
canvas.drawText(text, 10.0f, y, mPaint);
y += MESSAGE_Y_SPACING;
}
}
private int mTriangles;
/**
* Sets the number of triangles drawn in the previous frame for
* display by the showStatistics method. The number of triangles
* is not computed by GLView but must be supplied by the
* calling Activity.
*
* @param triangles an Activity-supplied estimate of the number of
* triangles drawn in the previous frame.
*/
public void setNumTriangles(int triangles) {
this.mTriangles = triangles;
}
/**
* Displays statistics on frames and triangles per second. The
* GLContext.waitGL method should be called prior to calling this
* method.
*
* @param canvas the Canvas on which statistics are to appear.
* @param width the width of the Canvas.
*/
public void showStatistics(Canvas canvas, int width) {
long endTime = mTimes[mTimesIdx] = System.currentTimeMillis();
mTimesIdx = (mTimesIdx + 1) % mFramesFPS;
float th = mPaint.getTextSize();
if (mDisplayFPS) {
// Use end time from mFramesFPS frames ago
long startTime = mTimes[mTimesIdx];
String fps = "" + (1000.0f*mFramesFPS/(endTime - startTime));
// Normalize fps to XX.XX format
if (fps.indexOf(".") == 1) {
fps = " " + fps;
}
int len = fps.length();
if (len == 2) {
fps += ".00";
} else if (len == 4) {
fps += "0";
} else if (len > 5) {
fps = fps.substring(0, 5);
}
canvas.drawText(fps + " fps", width - 60.0f, 10.0f, mPaint);
}
if (mDisplayCounts) {
canvas.drawText(mTriangles + " triangles",
width - 100.0f, 10.0f + th + 5, mPaint);
}
}
private void addMessage(String key, String text, int durationMillis) {
long expirationTime = System.currentTimeMillis() + durationMillis;
mMessages.put(key, new Message(text, expirationTime));
}
private void addMessage(String key, String text) {
addMessage(key, text, DEFAULT_DURATION_MILLIS);
}
private void addMessage(String text) {
addMessage(text, text, DEFAULT_DURATION_MILLIS);
}
private void clearMessages() {
mMessages.clear();
}
String command = "";
private void toggleFilter() {
if (params[mParam] == GL10.GL_NEAREST) {
params[mParam] = GL10.GL_LINEAR;
} else {
params[mParam] = GL10.GL_NEAREST;
}
addMessage(commands[mParam],
"Texture " +
(mParam == TEXTURE_MIN_FILTER ? "min" : "mag") +
" filter = " +
(params[mParam] == GL10.GL_NEAREST ?
"nearest" : "linear"));
}
private void togglePerspectiveCorrection() {
if (params[mParam] == GL10.GL_NICEST) {
params[mParam] = GL10.GL_FASTEST;
} else {
params[mParam] = GL10.GL_NICEST;
}
addMessage(commands[mParam],
"Texture perspective correction = " +
(params[mParam] == GL10.GL_FASTEST ?
"fastest" : "nicest"));
}
private String valueString() {
if (mParam == TEXTURE_MIN_FILTER ||
mParam == TEXTURE_MAG_FILTER) {
if (params[mParam] == GL10.GL_NEAREST) {
return "nearest";
}
if (params[mParam] == GL10.GL_LINEAR) {
return "linear";
}
}
if (mParam == TEXTURE_PERSPECTIVE_CORRECTION) {
if (params[mParam] == GL10.GL_FASTEST) {
return "fastest";
}
if (params[mParam] == GL10.GL_NICEST) {
return "nicest";
}
}
return "" + params[mParam];
}
/**
*
* @return true if the view
*/
public boolean hasMessages() {
return mState == HAVE_TWO || mDisplayFPS || mDisplayCounts;
}
/**
* Process a key stroke. The calling Activity should pass all
* keys from its onKeyDown method to this method. If the key is
* part of a GLView command, true is returned and the calling
* Activity should ignore the key event. Otherwise, false is
* returned and the calling Activity may process the key event
* normally.
*
* @param keyCode the key code as passed to Activity.onKeyDown.
*
* @return true if the key is part of a GLView command sequence,
* false otherwise.
*/
public boolean processKey(int keyCode) {
// Pressing the state key twice enters the UI
// Pressing it again exits the UI
if ((keyCode == STATE_KEY) ||
(keyCode == KeyEvent.KEYCODE_SLASH) ||
(keyCode == KeyEvent.KEYCODE_PERIOD))
{
mState = (mState + 1) % 3;
if (mState == HAVE_NONE) {
clearMessages();
}
if (mState == HAVE_TWO) {
clearMessages();
addMessage("aaaa", "GL", Integer.MAX_VALUE);
addMessage("aaab", "", Integer.MAX_VALUE);
command = "";
}
return true;
} else {
if (mState == HAVE_ONE) {
mState = HAVE_NONE;
return false;
}
}
// If we're not in the UI, exit without handling the key
if (mState != HAVE_TWO) {
return false;
}
if (keyCode == KeyEvent.KEYCODE_ENTER) {
command = "";
} else if (keyCode == KeyEvent.KEYCODE_DEL) {
if (command.length() > 0) {
command = command.substring(0, command.length() - 1);
}
} else if (keyCode >= KeyEvent.KEYCODE_A &&
keyCode <= KeyEvent.KEYCODE_Z) {
command += "" + (char)(keyCode - KeyEvent.KEYCODE_A + 'a');
}
addMessage("aaaa", "GL " + command, Integer.MAX_VALUE);
if (command.equals("h")) {
addMessage("aaaa", "GL", Integer.MAX_VALUE);
addMessage("h - help");
addMessage("fn/ff - frustum near/far clip Z");
addMessage("la/lar/lag/lab - abmient intensity/r/g/b");
addMessage("ld/ldr/ldg/ldb - diffuse intensity/r/g/b");
addMessage("ls/lsr/lsg/lsb - specular intensity/r/g/b");
addMessage("s - toggle statistics display");
addMessage("tmin/tmag - texture min/mag filter");
addMessage("tpersp - texture perspective correction");
addMessage("tx/ty/tz - view translate x/y/z");
addMessage("z - zoom");
command = "";
return true;
} else if (command.equals("s")) {
mDisplayCounts = !mDisplayCounts;
mDisplayFPS = !mDisplayFPS;
command = "";
return true;
}
mParam = -1;
for (int i = 0; i < commands.length; i++) {
if (command.equals(commands[i])) {
mParam = i;
mIncr = increments[i];
}
}
if (mParam == -1) {
return true;
}
boolean addMessage = true;
// Increment or decrement
if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
if (mParam == ZOOM_EXPONENT) {
params[mParam] += mIncr;
computeZoom();
} else if ((mParam == TEXTURE_MIN_FILTER) ||
(mParam == TEXTURE_MAG_FILTER)) {
toggleFilter();
} else if (mParam == TEXTURE_PERSPECTIVE_CORRECTION) {
togglePerspectiveCorrection();
} else {
params[mParam] += mIncr;
}
} else if (keyCode == KeyEvent.KEYCODE_DPAD_UP ||
keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
if (mParam == ZOOM_EXPONENT) {
params[mParam] -= mIncr;
computeZoom();
} else if ((mParam == TEXTURE_MIN_FILTER) ||
(mParam == TEXTURE_MAG_FILTER)) {
toggleFilter();
} else if (mParam == TEXTURE_PERSPECTIVE_CORRECTION) {
togglePerspectiveCorrection();
} else {
params[mParam] -= mIncr;
}
}
if (addMessage) {
addMessage(commands[mParam],
labels[mParam] + ": " + valueString());
}
return true;
}
/**
* Zoom in by a given number of steps. A negative value of steps
* zooms out. Each step zooms in by 1%.
*
* @param steps the number of steps to zoom by.
*/
public void zoom(int steps) {
params[ZOOM_EXPONENT] += steps;
computeZoom();
}
/**
* Set the projection matrix using glFrustumf. The left and right
* clipping planes are set at -+(aspectRatio*zoom), the bottom and
* top clipping planes are set at -+zoom, and the near and far
* clipping planes are set to the values set by setNearFrustum and
* setFarFrustum or interactively.
*
* <p> GL side effects:
* <ul>
* <li>overwrites the matrix mode</li>
* <li>overwrites the projection matrix</li>
* </ul>
*
* @param gl a GL10 instance whose projection matrix is to be modified.
*/
public void setProjection(GL10 gl) {
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
if (mAspectRatio >= 1.0f) {
gl.glFrustumf(-mAspectRatio*mZoom, mAspectRatio*mZoom,
-mZoom, mZoom,
params[NEAR_FRUSTUM], params[FAR_FRUSTUM]);
} else {
gl.glFrustumf(-mZoom, mZoom,
-mZoom / mAspectRatio, mZoom / mAspectRatio,
params[NEAR_FRUSTUM], params[FAR_FRUSTUM]);
}
}
/**
* Set the modelview matrix using glLoadIdentity and glTranslatef.
* The translation values are set interactively.
*
* <p> GL side effects:
* <ul>
* <li>overwrites the matrix mode</li>
* <li>overwrites the modelview matrix</li>
* </ul>
*
* @param gl a GL10 instance whose modelview matrix is to be modified.
*/
public void setView(GL10 gl) {
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
// Move the viewpoint backwards
gl.glTranslatef(params[TRANSLATE_X],
params[TRANSLATE_Y],
params[TRANSLATE_Z]);
}
/**
* Sets texture parameters.
*
* <p> GL side effects:
* <ul>
* <li>sets the GL_PERSPECTIVE_CORRECTION_HINT</li>
* <li>sets the GL_TEXTURE_MIN_FILTER texture parameter</li>
* <li>sets the GL_TEXTURE_MAX_FILTER texture parameter</li>
* </ul>
*
* @param gl a GL10 instance whose texture parameters are to be modified.
*/
public void setTextureParameters(GL10 gl) {
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
(int)params[TEXTURE_PERSPECTIVE_CORRECTION]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MIN_FILTER,
params[TEXTURE_MIN_FILTER]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MAG_FILTER,
params[TEXTURE_MAG_FILTER]);
}
/**
* Sets the lighting parameters for the given light.
*
* <p> GL side effects:
* <ul>
* <li>sets the GL_LIGHT_MODEL_AMBIENT intensities
* <li>sets the GL_AMBIENT intensities for the given light</li>
* <li>sets the GL_DIFFUSE intensities for the given light</li>
* <li>sets the GL_SPECULAR intensities for the given light</li>
* </ul>
*
* @param gl a GL10 instance whose texture parameters are to be modified.
*/
public void setLights(GL10 gl, int lightNum) {
float[] light = new float[4];
light[3] = 1.0f;
float lmi = params[LIGHT_MODEL_AMBIENT_INTENSITY];
light[0] = params[LIGHT_MODEL_AMBIENT_RED]*lmi;
light[1] = params[LIGHT_MODEL_AMBIENT_GREEN]*lmi;
light[2] = params[LIGHT_MODEL_AMBIENT_BLUE]*lmi;
gl.glLightModelfv(GL10.GL_LIGHT_MODEL_AMBIENT, light, 0);
float ai = params[AMBIENT_INTENSITY];
light[0] = params[AMBIENT_RED]*ai;
light[1] = params[AMBIENT_GREEN]*ai;
light[2] = params[AMBIENT_BLUE]*ai;
gl.glLightfv(lightNum, GL10.GL_AMBIENT, light, 0);
float di = params[DIFFUSE_INTENSITY];
light[0] = params[DIFFUSE_RED]*di;
light[1] = params[DIFFUSE_GREEN]*di;
light[2] = params[DIFFUSE_BLUE]*di;
gl.glLightfv(lightNum, GL10.GL_DIFFUSE, light, 0);
float si = params[SPECULAR_INTENSITY];
light[0] = params[SPECULAR_RED]*si;
light[1] = params[SPECULAR_GREEN]*si;
light[2] = params[SPECULAR_BLUE]*si;
gl.glLightfv(lightNum, GL10.GL_SPECULAR, light, 0);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,118 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.globaltime;
public class LatLongSphere extends Sphere {
public LatLongSphere(float centerX, float centerY, float centerZ,
float radius, int lats, int longs,
float minLongitude, float maxLongitude,
boolean emitTextureCoordinates,
boolean emitNormals,
boolean emitColors,
boolean flatten) {
super(emitTextureCoordinates, emitNormals, emitColors);
int tris = 2 * (lats - 1) * (longs - 1);
int[] vertices = new int[3 * lats * longs];
int[] texcoords = new int[2 * lats * longs];
int[] colors = new int[4 * lats * longs];
int[] normals = new int[3 * lats * longs];
short[] indices = new short[3 * tris];
int vidx = 0;
int tidx = 0;
int nidx = 0;
int cidx = 0;
int iidx = 0;
minLongitude *= DEGREES_TO_RADIANS;
maxLongitude *= DEGREES_TO_RADIANS;
for (int i = 0; i < longs; i++) {
float fi = (float) i / (longs - 1);
// theta is the longitude
float theta =
(maxLongitude - minLongitude) * (1.0f - fi) + minLongitude;
float sinTheta = (float) Math.sin(theta);
float cosTheta = (float) Math.cos(theta);
for (int j = 0; j < lats; j++) {
float fj = (float) j / (lats - 1);
// phi is the latitude
float phi = PI * fj;
float sinPhi = (float) Math.sin(phi);
float cosPhi = (float) Math.cos(phi);
float x = cosTheta * sinPhi;
float y = cosPhi;
float z = sinTheta * sinPhi;
if (flatten) {
// Place vertices onto a flat projection
vertices[vidx++] = toFixed(2.0f * fi - 1.0f);
vertices[vidx++] = toFixed(0.5f - fj);
vertices[vidx++] = toFixed(0.0f);
} else {
// Place vertices onto the surface of a sphere
// with the given center and radius
vertices[vidx++] = toFixed(x * radius + centerX);
vertices[vidx++] = toFixed(y * radius + centerY);
vertices[vidx++] = toFixed(z * radius + centerZ);
}
if (emitTextureCoordinates) {
texcoords[tidx++] = toFixed(1.0f - (theta / (TWO_PI)));
texcoords[tidx++] = toFixed(fj);
}
if (emitNormals) {
float norm = 1.0f / Shape.length(x, y, z);
normals[nidx++] = toFixed(x * norm);
normals[nidx++] = toFixed(y * norm);
normals[nidx++] = toFixed(z * norm);
}
// 0 == black, 65536 == white
if (emitColors) {
colors[cidx++] = (i % 2) * 65536;
colors[cidx++] = 0;
colors[cidx++] = (j % 2) * 65536;
colors[cidx++] = 65536;
}
}
}
for (int i = 0; i < longs - 1; i++) {
for (int j = 0; j < lats - 1; j++) {
int base = i * lats + j;
// Ensure both triangles have the same final vertex
// since this vertex carries the color for flat
// shading
indices[iidx++] = (short) (base);
indices[iidx++] = (short) (base + 1);
indices[iidx++] = (short) (base + lats + 1);
indices[iidx++] = (short) (base + lats);
indices[iidx++] = (short) (base);
indices[iidx++] = (short) (base + lats + 1);
}
}
allocateBuffers(vertices, texcoords, normals, colors, indices);
}
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.globaltime;
import javax.microedition.khronos.opengles.GL10;
/**
* A class representing a set of GL_POINT objects. GlobalTime uses this class
* to draw city lights on the night side of the earth.
*/
public class PointCloud extends Shape {
/**
* Constructs a PointCloud with a point at each of the given vertex
* (x, y, z) positions.
* @param vertices an array of (x, y, z) positions given in fixed-point.
*/
public PointCloud(int[] vertices) {
this(vertices, 0, vertices.length);
}
/**
* Constructs a PointCloud with a point at each of the given vertex
* (x, y, z) positions.
* @param vertices an array of (x, y, z) positions given in fixed-point.
* @param off the starting offset of the vertices array
* @param len the number of elements of the vertices array to use
*/
public PointCloud(int[] vertices, int off, int len) {
super(GL10.GL_POINTS, GL10.GL_UNSIGNED_SHORT,
false, false, false);
int numPoints = len / 3;
short[] indices = new short[numPoints];
for (int i = 0; i < numPoints; i++) {
indices[i] = (short)i;
}
allocateBuffers(vertices, null, null, null, indices);
this.mNumIndices = mIndexBuffer.capacity();
}
@Override public int getNumTriangles() {
return mNumIndices * 2;
}
}

View File

@@ -1,270 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.globaltime;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.opengles.GL10;
/**
* An abstract superclass for various three-dimensional objects to be drawn
* using OpenGL ES. Each subclass is responsible for setting up NIO buffers
* containing vertices, texture coordinates, colors, normals, and indices.
* The {@link #draw(GL10)} method draws the object to the given OpenGL context.
*/
public abstract class Shape {
public static final int INT_BYTES = 4;
public static final int SHORT_BYTES = 2;
public static final float DEGREES_TO_RADIANS = (float) Math.PI / 180.0f;
public static final float PI = (float) Math.PI;
public static final float TWO_PI = (float) (2.0 * Math.PI);
public static final float PI_OVER_TWO = (float) (Math.PI / 2.0);
protected int mPrimitive;
protected int mIndexDatatype;
protected boolean mEmitTextureCoordinates;
protected boolean mEmitNormals;
protected boolean mEmitColors;
protected IntBuffer mVertexBuffer;
protected IntBuffer mTexcoordBuffer;
protected IntBuffer mColorBuffer;
protected IntBuffer mNormalBuffer;
protected Buffer mIndexBuffer;
protected int mNumIndices = -1;
/**
* Constructs a Shape.
*
* @param primitive a GL primitive type understood by glDrawElements,
* such as GL10.GL_TRIANGLES
* @param indexDatatype the GL datatype for the index buffer, such as
* GL10.GL_UNSIGNED_SHORT
* @param emitTextureCoordinates true to enable use of the texture
* coordinate buffer
* @param emitNormals true to enable use of the normal buffer
* @param emitColors true to enable use of the color buffer
*/
protected Shape(int primitive,
int indexDatatype,
boolean emitTextureCoordinates,
boolean emitNormals,
boolean emitColors) {
mPrimitive = primitive;
mIndexDatatype = indexDatatype;
mEmitTextureCoordinates = emitTextureCoordinates;
mEmitNormals = emitNormals;
mEmitColors = emitColors;
}
/**
* Converts the given floating-point value to fixed-point.
*/
public static int toFixed(float x) {
return (int) (x * 65536.0);
}
/**
* Converts the given fixed-point value to floating-point.
*/
public static float toFloat(int x) {
return (float) (x / 65536.0);
}
/**
* Computes the cross-product of two vectors p and q and places
* the result in out.
*/
public static void cross(float[] p, float[] q, float[] out) {
out[0] = p[1] * q[2] - p[2] * q[1];
out[1] = p[2] * q[0] - p[0] * q[2];
out[2] = p[0] * q[1] - p[1] * q[0];
}
/**
* Returns the length of a vector, given as three floats.
*/
public static float length(float vx, float vy, float vz) {
return (float) Math.sqrt(vx * vx + vy * vy + vz * vz);
}
/**
* Returns the length of a vector, given as an array of three floats.
*/
public static float length(float[] v) {
return length(v[0], v[1], v[2]);
}
/**
* Normalizes the given vector of three floats to have length == 1.0.
* Vectors with length zero are unaffected.
*/
public static void normalize(float[] v) {
float length = length(v);
if (length != 0.0f) {
float norm = 1.0f / length;
v[0] *= norm;
v[1] *= norm;
v[2] *= norm;
}
}
/**
* Returns the number of triangles associated with this shape.
*/
public int getNumTriangles() {
if (mPrimitive == GL10.GL_TRIANGLES) {
return mIndexBuffer.capacity() / 3;
} else if (mPrimitive == GL10.GL_TRIANGLE_STRIP) {
return mIndexBuffer.capacity() - 2;
}
return 0;
}
/**
* Copies the given data into the instance
* variables mVertexBuffer, mTexcoordBuffer, mNormalBuffer, mColorBuffer,
* and mIndexBuffer.
*
* @param vertices an array of fixed-point vertex coordinates
* @param texcoords an array of fixed-point texture coordinates
* @param normals an array of fixed-point normal vector coordinates
* @param colors an array of fixed-point color channel values
* @param indices an array of short indices
*/
public void allocateBuffers(int[] vertices, int[] texcoords, int[] normals,
int[] colors, short[] indices) {
allocate(vertices, texcoords, normals, colors);
ByteBuffer ibb =
ByteBuffer.allocateDirect(indices.length * SHORT_BYTES);
ibb.order(ByteOrder.nativeOrder());
ShortBuffer shortIndexBuffer = ibb.asShortBuffer();
shortIndexBuffer.put(indices);
shortIndexBuffer.position(0);
this.mIndexBuffer = shortIndexBuffer;
}
/**
* Copies the given data into the instance
* variables mVertexBuffer, mTexcoordBuffer, mNormalBuffer, mColorBuffer,
* and mIndexBuffer.
*
* @param vertices an array of fixed-point vertex coordinates
* @param texcoords an array of fixed-point texture coordinates
* @param normals an array of fixed-point normal vector coordinates
* @param colors an array of fixed-point color channel values
* @param indices an array of int indices
*/
public void allocateBuffers(int[] vertices, int[] texcoords, int[] normals,
int[] colors, int[] indices) {
allocate(vertices, texcoords, normals, colors);
ByteBuffer ibb =
ByteBuffer.allocateDirect(indices.length * INT_BYTES);
ibb.order(ByteOrder.nativeOrder());
IntBuffer intIndexBuffer = ibb.asIntBuffer();
intIndexBuffer.put(indices);
intIndexBuffer.position(0);
this.mIndexBuffer = intIndexBuffer;
}
/**
* Allocate the vertex, texture coordinate, normal, and color buffer.
*/
private void allocate(int[] vertices, int[] texcoords, int[] normals,
int[] colors) {
ByteBuffer vbb =
ByteBuffer.allocateDirect(vertices.length * INT_BYTES);
vbb.order(ByteOrder.nativeOrder());
mVertexBuffer = vbb.asIntBuffer();
mVertexBuffer.put(vertices);
mVertexBuffer.position(0);
if ((texcoords != null) && mEmitTextureCoordinates) {
ByteBuffer tbb =
ByteBuffer.allocateDirect(texcoords.length * INT_BYTES);
tbb.order(ByteOrder.nativeOrder());
mTexcoordBuffer = tbb.asIntBuffer();
mTexcoordBuffer.put(texcoords);
mTexcoordBuffer.position(0);
}
if ((normals != null) && mEmitNormals) {
ByteBuffer nbb =
ByteBuffer.allocateDirect(normals.length * INT_BYTES);
nbb.order(ByteOrder.nativeOrder());
mNormalBuffer = nbb.asIntBuffer();
mNormalBuffer.put(normals);
mNormalBuffer.position(0);
}
if ((colors != null) && mEmitColors) {
ByteBuffer cbb =
ByteBuffer.allocateDirect(colors.length * INT_BYTES);
cbb.order(ByteOrder.nativeOrder());
mColorBuffer = cbb.asIntBuffer();
mColorBuffer.put(colors);
mColorBuffer.position(0);
}
}
/**
* Draws the shape to the given OpenGL ES 1.0 context. Texture coordinates,
* normals, and colors are emitted according the the preferences set for
* this shape.
*/
public void draw(GL10 gl) {
gl.glVertexPointer(3, GL10.GL_FIXED, 0, mVertexBuffer);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
if (mEmitTextureCoordinates) {
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, mTexcoordBuffer);
gl.glEnable(GL10.GL_TEXTURE_2D);
} else {
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisable(GL10.GL_TEXTURE_2D);
}
if (mEmitNormals) {
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl.glNormalPointer(GL10.GL_FIXED, 0, mNormalBuffer);
} else {
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
}
if (mEmitColors) {
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glColorPointer(4, GL10.GL_FIXED, 0, mColorBuffer);
} else {
gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
}
gl.glDrawElements(mPrimitive,
mNumIndices > 0 ? mNumIndices : mIndexBuffer.capacity(),
mIndexDatatype,
mIndexBuffer);
}
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.globaltime;
import javax.microedition.khronos.opengles.GL10;
public class Sphere extends Shape {
public Sphere(boolean emitTextureCoordinates,
boolean emitNormals, boolean emitColors) {
super(GL10.GL_TRIANGLES, GL10.GL_UNSIGNED_SHORT,
emitTextureCoordinates, emitNormals, emitColors);
}
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.globaltime;
import java.nio.ByteBuffer;
public class Texture {
private ByteBuffer data;
private int width, height;
public Texture(ByteBuffer data, int width, int height) {
this.data = data;
this.width = width;
this.height = height;
}
public ByteBuffer getData() {
return data;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}