// Copyright 2008 Google Inc.
//
// 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.google.android.stardroid.renderer;
import com.google.android.stardroid.R;
import com.google.android.stardroid.renderer.util.IndexBuffer;
import com.google.android.stardroid.renderer.util.NightVisionColorBuffer;
import com.google.android.stardroid.renderer.util.TexCoordBuffer;
import com.google.android.stardroid.renderer.util.TextureManager;
import com.google.android.stardroid.renderer.util.TextureReference;
import com.google.android.stardroid.renderer.util.VertexBuffer;
import com.google.android.stardroid.source.LineSource;
import com.google.android.stardroid.units.GeocentricCoordinates;
import com.google.android.stardroid.units.Vector3;
import com.google.android.stardroid.util.MathUtil;
import com.google.android.stardroid.util.VectorUtil;
import java.util.EnumSet;
import java.util.List;
import javax.microedition.khronos.opengles.GL10;
public class PolyLineObjectManager extends RendererObjectManager {
private VertexBuffer mVertexBuffer = new VertexBuffer(true);
private NightVisionColorBuffer mColorBuffer = new NightVisionColorBuffer(true);
private TexCoordBuffer mTexCoordBuffer = new TexCoordBuffer(true);
private IndexBuffer mIndexBuffer = new IndexBuffer(true);
private TextureReference mTexRef = null;
private boolean mOpaque = true;
public PolyLineObjectManager(int layer, TextureManager textureManager) {
super(layer, textureManager);
}
public void updateObjects(List<LineSource> lines, EnumSet<UpdateType> updateType) {
// We only care about updates to positions, ignore any other updates.
if (!updateType.contains(UpdateType.Reset) &&
!updateType.contains(UpdateType.UpdatePositions)) {
return;
}
int numLineSegments = 0;
for (LineSource l : lines) {
numLineSegments += l.getVertices().size() - 1;
}
// To render everything in one call, we render everything as a line list
// rather than a series of line strips.
int numVertices = 4 * numLineSegments;
int numIndices = 6 * numLineSegments;
VertexBuffer vb = mVertexBuffer;
vb.reset(4 * numLineSegments);
NightVisionColorBuffer cb = mColorBuffer;
cb.reset(4 * numLineSegments);
TexCoordBuffer tb = mTexCoordBuffer;
tb.reset(numVertices);
IndexBuffer ib = mIndexBuffer;
ib.reset(numIndices);
// See comment in PointObjectManager for justification of this calculation.
float fovyInRadians = 60 * MathUtil.PI / 180.0f;
float sizeFactor = MathUtil.tan(fovyInRadians * 0.5f) / 480;
boolean opaque = true;
short vertexIndex = 0;
for (LineSource l : lines) {
List<GeocentricCoordinates> coords = l.getVertices();
if (coords.size() < 2)
continue;
// If the color isn't fully opaque, set opaque to false.
int color = l.getColor();
opaque &= (color & 0xff000000) == 0xff000000;
// Add the vertices.
for (int i = 0; i < coords.size() - 1; i++) {
Vector3 p1 = coords.get(i);
Vector3 p2 = coords.get(i+1);
Vector3 u = VectorUtil.difference(p2, p1);
// The normal to the quad should face the origin at its midpoint.
Vector3 avg = VectorUtil.sum(p1, p2);
avg.scale(0.5f);
// I'm assuming that the points will already be on a unit sphere. If this is not the case,
// then we should normalize it here.
Vector3 v = VectorUtil.normalized(VectorUtil.crossProduct(u, avg));
v.scale(sizeFactor * l.getLineWidth());
// Add the vertices
// Lower left corner
vb.addPoint(VectorUtil.difference(p1, v));
cb.addColor(color);
tb.addTexCoords(0, 1);
// Upper left corner
vb.addPoint(VectorUtil.sum(p1, v));
cb.addColor(color);
tb.addTexCoords(0, 0);
// Lower left corner
vb.addPoint(VectorUtil.difference(p2, v));
cb.addColor(color);
tb.addTexCoords(1, 1);
// Upper left corner
vb.addPoint(VectorUtil.sum(p2, v));
cb.addColor(color);
tb.addTexCoords(1, 0);
// Add the indices
short bottomLeft = vertexIndex++;
short topLeft = vertexIndex++;
short bottomRight = vertexIndex++;
short topRight = vertexIndex++;
// First triangle
ib.addIndex(bottomLeft);
ib.addIndex(topLeft);
ib.addIndex(bottomRight);
// Second triangle
ib.addIndex(bottomRight);
ib.addIndex(topLeft);
ib.addIndex(topRight);
}
}
mOpaque = opaque;
}
@Override
public void reload(GL10 gl, boolean fullReload) {
mTexRef = textureManager().getTextureFromResource(gl, R.drawable.line);
mVertexBuffer.reload();
mColorBuffer.reload();
mTexCoordBuffer.reload();
mIndexBuffer.reload();
}
@Override
protected void drawInternal(GL10 gl) {
if (mIndexBuffer.size() == 0)
return;
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glEnable(GL10.GL_TEXTURE_2D);
mTexRef.bind(gl);
gl.glEnable(GL10.GL_CULL_FACE);
gl.glFrontFace(GL10.GL_CW);
gl.glCullFace(GL10.GL_BACK);
if (!mOpaque) {
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
}
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
mVertexBuffer.set(gl);
mColorBuffer.set(gl, getRenderState().getNightVisionMode());
mTexCoordBuffer.set(gl);
mIndexBuffer.draw(gl, GL10.GL_TRIANGLES);
if (!mOpaque) {
gl.glDisable(GL10.GL_BLEND);
}
gl.glDisable(GL10.GL_TEXTURE_2D);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
}