package gl;
import geo.GeoObj;
import gl.animations.AnimationFaceToCamera;
import gl.animations.AnimationRotate;
import gl.scenegraph.MeshComponent;
import gl.scenegraph.MultiColoredShape;
import gl.scenegraph.Shape;
import gl.textures.TextureManager;
import gl.textures.Textured2dShape;
import gl.textures.TexturedRenderData;
import gl.textures.TexturedShape;
import javax.microedition.khronos.opengles.GL10;
import util.IO;
import util.Log;
import util.Vec;
import worldData.Obj;
import worldData.Visitor;
import worldData.World;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Typeface;
import android.widget.TextView;
/**
* Use this factory to understand how to create 3D objects with {@link Shape}s
* and {@link RenderGroup}s. Often it is more efficient to create the objects
* you need manually and not combine objects created with this factory. The
* benefits of algorithmic objects are that they are much more flexible and
* random {@link Vec}tors can be used to add a unique touch to each object.
*
* Loading object from externmal files like md3 is the alternative to this
* approach.
*
*
* @author Spobo
*
*/
public class GLFactory {
private static final String LOG_TAG = "GLFactory";
private static GLFactory myInstance = new GLFactory();
private GLFactory() {
}
public static GLFactory getInstance() {
return myInstance;
}
public Shape newSquare(Color canBeNull) {
Shape s = new Shape(canBeNull);
s.add(new Vec(-1, 1, 0));
s.add(new Vec(-1, -1, 0));
s.add(new Vec(1, -1, 0));
s.add(new Vec(1, -1, 0));
s.add(new Vec(1, 1, 0));
s.add(new Vec(-1, 1, 0));
return s;
}
public MeshComponent newCube(Color canBeNull) {
MeshComponent g = new Shape();
Shape s1 = newSquare(canBeNull);
g.addChild(s1);
Shape s2 = newSquare(canBeNull);
s2.setPosition(new Vec(0, 0, 2));
g.addChild(s2);
Shape s3 = newSquare(canBeNull);
s3.setPosition(new Vec(0, 1, 1));
s3.setRotation(new Vec(90, 0, 0));
g.addChild(s3);
Shape s4 = newSquare(canBeNull);
s4.setPosition(new Vec(0, -1, 1));
s4.setRotation(new Vec(90, 0, 0));
g.addChild(s4);
return g;
}
public Shape newTreangle(Color canBeNull) {
Shape s = new Shape(canBeNull);
s.add(new Vec(0, 0, 0.8f));
s.add(new Vec(0, 0.8f, 0));
s.add(new Vec(0.8f, 0, 0));
return s;
}
public Shape newHexagon(Color canBeNull) {
Shape s = new Shape(canBeNull);
s.add(new Vec(0, -1, 0));
s.add(new Vec(0, 1, 0));
s.add(new Vec(1, 0.5f, 0));
s.add(new Vec(0, -1, 0));
s.add(new Vec(0, 1, 0));
s.add(new Vec(-1, 0.5f, 0));
s.add(new Vec(0, -1, 0));
s.add(new Vec(1, 0.5f, 0));
s.add(new Vec(1, -0.5f, 0));
s.add(new Vec(0, -1, 0));
s.add(new Vec(-1, 0.5f, 0));
s.add(new Vec(-1, -0.5f, 0));
return s;
}
/**
* see {@link GLFactory#newTexturedSquare(String, Bitmap, float)}
*
* @param bitmapName
* @param bitmap
* @return A 1 x 1 meter square
*/
public MeshComponent newTexturedSquare(String bitmapName, Bitmap bitmap) {
return newTexturedSquare(bitmapName, bitmap, 1);
}
/**
* see {@link GLFactory#newTexturedSquare(String, Bitmap, float)}
*
* @param context
* @param iconId
* The id of the icon that should be used as the texture (will
* also be used as the unique texture name)
* @param heightInMeters
* @return
*/
public MeshComponent newTexturedSquare(Context context, int iconId,
float heightInMeters) {
return newTexturedSquare("" + iconId,
IO.loadBitmapFromId(context, iconId), heightInMeters);
}
/**
* Please read
* {@link TextureManager#addTexture(TexturedRenderData, Bitmap, String)} for
* information about the parameters.
*
* @param bitmapName
* see
* {@link TextureManager#addTexture(TexturedRenderData, Bitmap, String)}
* @param bitmap
* see
* {@link TextureManager#addTexture(TexturedRenderData, Bitmap, String)}
* @param heightInMeters
* the square will have this height and width
* @return
*/
public MeshComponent newTexturedSquare(String bitmapName, Bitmap bitmap,
float heightInMeters) {
if (bitmapName == null) {
Log.e(LOG_TAG,
"No bitmap id set, can't be added to Texture Manager!");
return null;
}
if (bitmap == null) {
Log.e(LOG_TAG, "Passed bitmap was null!");
return null;
}
TexturedShape s = new TexturedShape(bitmapName, bitmap);
float f = (float) bitmap.getHeight() / (float) bitmap.getWidth();
float x = heightInMeters / f;
float w2 = -x / 2;
float h2 = -heightInMeters / 2;
Log.d(LOG_TAG, "Creating textured mesh for " + bitmapName);
Log.v(LOG_TAG, " > bitmap.getHeight()=" + bitmap.getHeight());
Log.v(LOG_TAG, " > bitmap.getWidth()=" + bitmap.getWidth());
Log.v(LOG_TAG, " > height/width factor=" + f);
Log.v(LOG_TAG, " > w2=" + w2);
Log.v(LOG_TAG, " > h2=" + h2);
s.add(new Vec(-w2, 0, -h2), 0, 0);
s.add(new Vec(-w2, 0, h2), 0, 1);
s.add(new Vec(w2, 0, -h2), 1, 0);
s.add(new Vec(w2, 0, h2), 1, 1);
s.add(new Vec(-w2, 0, h2), 0, 1);
s.add(new Vec(w2, 0, -h2), 1, 0);
return s;
}
public MeshComponent newTextured2dShape(Bitmap bitmap, String bitmapName) {
Textured2dShape s = new Textured2dShape(bitmap, bitmapName);
return s;
}
public MeshComponent newArrow() {
Color top = Color.blue();
Color bottom = Color.red();
Color edge1 = Color.red();
Color edge2 = Color.redTransparent();
float height = 4f;
float x = 0.7f;
float y = 0f;
return newArrow(x, y, height, top, edge1, bottom, edge2);
}
public MeshComponent newCuror() {
Color top = Color.silver1();
Color bottom = Color.silver2();
Color edge1 = Color.blackTransparent();
Color edge2 = Color.blackTransparent();
float height = 2;
float x = 0.7f;
float y = 0f;
MeshComponent a = newArrow(x, y, height, top, edge1, bottom, edge2);
a.setScale(new Vec(0.3f, 0.3f, 0.3f));
return a;
}
private MeshComponent newArrow(float x, float y, float height, Color top,
Color edge1, Color bottom, Color edge2) {
MeshComponent pyr = new Shape(null);
MultiColoredShape s = new MultiColoredShape();
s.add(new Vec(-x, 0, height), top);
s.add(new Vec(1, 0, 0), edge1);
s.add(new Vec(-y, 0, -height), bottom);
MultiColoredShape s2 = new MultiColoredShape();
s2.add(new Vec(0, -x, height), top);
s2.add(new Vec(0, 1, 0), edge2);
s2.add(new Vec(0, -y, -height), bottom);
MultiColoredShape s3 = new MultiColoredShape();
s3.add(new Vec(x, 0, height), top);
s3.add(new Vec(-1, 0, 0), edge1);
s3.add(new Vec(y, 0, -height), bottom);
MultiColoredShape s4 = new MultiColoredShape();
s4.add(new Vec(0, x, height), top);
s4.add(new Vec(0, -1, 0), edge2);
s4.add(new Vec(0, y, -height), bottom);
pyr.addChild(s);
pyr.addChild(s2);
pyr.addChild(s3);
pyr.addChild(s4);
GLFactory.getInstance().addRotateAnimation(pyr, 120, new Vec(0, 0, 1));
return pyr;
}
public GeoObj newPositionMarker(GLCamera camera) {
GeoObj o = camera.getGPSPositionAsGeoObj();
Shape diamond = newDiamond(Color.getRandomRGBColor());
diamond.setScale(new Vec(0.4f, 0.4f, 0.4f));
o.setComp(diamond);
return o;
}
private void addRotateAnimation(MeshComponent target, int speed,
Vec rotationVec) {
AnimationRotate a = new AnimationRotate(speed, rotationVec);
target.addAnimation(a);
}
public MeshComponent newGrid(Color netColor, float spaceBetweenNetStrings,
int lineCount) {
Shape s = new Shape(netColor);
s.setLineDrawing();
float coord = (lineCount - 1) * spaceBetweenNetStrings / 2;
Vec start = new Vec(coord, coord, 0);
Vec end = new Vec(coord, -coord, 0);
for (int i = 0; i < lineCount; i++) {
s.add(start.copy());
s.add(end.copy());
start.x -= spaceBetweenNetStrings;
end.x -= spaceBetweenNetStrings;
}
start = new Vec(coord, coord, 0);
end = new Vec(-coord, coord, 0);
for (int i = 0; i < lineCount; i++) {
s.add(start.copy());
s.add(end.copy());
start.y -= spaceBetweenNetStrings;
end.y -= spaceBetweenNetStrings;
}
return s;
}
public Obj newSolarSystem(Vec position) {
Obj solarSystem = new Obj();
MeshComponent sunBox = new Shape();
if (position != null)
sunBox.setPosition(position);
solarSystem.setComp(sunBox);
MeshComponent earthRing = new Shape();
MeshComponent earthBox = new Shape();
earthRing.addChild(earthBox);
MeshComponent sun = GLFactory.getInstance().newNSidedPolygonWithGaps(
20, Color.red());
GLFactory.getInstance().addRotateAnimation(sun, 30, new Vec(1, 1, 1));
sunBox.addChild(sun);
GLFactory.getInstance().addRotateAnimation(earthRing, 40,
new Vec(0.5f, 0.3f, 1));
earthBox.setPosition(new Vec(3, 0, 0));
sunBox.addChild(earthRing);
MeshComponent earth = GLFactory.getInstance().newCircle(Color.green());
earth.scaleEqual(0.5f);
earthBox.addChild(earth);
MeshComponent moonring = new Shape();
MeshComponent moon = GLFactory.getInstance().newCircle(Color.white());
moon.setPosition(new Vec(1, 0, 0));
moon.scaleEqual(0.2f);
GLFactory.getInstance().addRotateAnimation(moonring, 80,
new Vec(0, 1, -1));
moonring.addChild(moon);
earthBox.addChild(moonring);
return solarSystem;
}
public Obj newHexGroupTest(Vec pos) {
Obj hex = new Obj();
MeshComponent g1 = new Shape(null, pos);
hex.setComp(g1);
g1.addChild(this.newHexagon(null));
MeshComponent g2 = new Shape(Color.blue(), new Vec(0, 5, 0.1f));
g2.addAnimation(new AnimationRotate(60, new Vec(0, 0, 1)));
g1.addChild(g2);
g2.addChild(this.newHexagon(null));
MeshComponent g3 = new Shape(Color.red(), new Vec(0, 4, 0));
g3.addAnimation(new AnimationRotate(30, new Vec(0, 0, 1)));
g2.addChild(g3);
g3.addChild(this.newHexagon(null));
MeshComponent g4 = new Shape(Color.green(), new Vec(0, 2, 0));
g4.addAnimation(new AnimationRotate(15, new Vec(0, 0, 1)));
g3.addChild(g4);
g4.addChild(this.newHexagon(null));
// Vec v = g4.getAbsolutePosition();
// System.out.println("absolut Pos: " + v);
return hex;
}
public Shape newDiamond(Color canBeNull) {
Shape s = new Shape(canBeNull);
float width = 0.7f;
float heigth = 2f;
float c = -0.1f; // a factor for asymmetric shaping in x direction
Vec top = new Vec(0, 0, heigth);
Vec bottom = new Vec(0, 0, -heigth);
Vec e1 = new Vec(-width + c, 0, 0);
Vec e4 = new Vec(width - c, 0, 0);
Vec e2 = new Vec(-width / 2 + c, width, 0);
Vec e6 = new Vec(-width / 2 + c, -width, 0);
Vec e3 = new Vec(width / 2 - c, width, 0);
Vec e5 = new Vec(width / 2 - c, -width, 0);
s.add(top);
s.add(e1);
s.add(e2);
s.add(top);
s.add(e2);
s.add(e3);
s.add(top);
s.add(e3);
s.add(e4);
s.add(top);
s.add(e4);
s.add(e5);
s.add(top);
s.add(e5);
s.add(e6);
s.add(top);
s.add(e6);
s.add(e1);
s.add(bottom);
s.add(e1);
s.add(e2);
s.add(bottom);
s.add(e2);
s.add(e3);
s.add(bottom);
s.add(e3);
s.add(e4);
s.add(bottom);
s.add(e4);
s.add(e5);
s.add(bottom);
s.add(e5);
s.add(e6);
s.add(bottom);
s.add(e6);
s.add(e1);
return s;
}
public Shape newDirectedPath(GeoObj from, GeoObj to, Color color) {
return GLFactory.getInstance().newDirectedPath(
to.getVirtualPosition(from), color);
}
public Shape newDirectedPath(Vec lineEndPos, Color c) {
Shape s = new Shape(c);
Vec orth = Vec.getOrthogonalHorizontal(lineEndPos).normalize()
.mult(0.9f);
Vec orthClone = orth.getNegativeClone();
float down = 0.5f;
Vec l = lineEndPos.copy().setLength(0.3f);
orth.add(l);
orth.z -= down;
orthClone.add(l);
orthClone.z -= down;
Vec start = new Vec().add(l.mult(3));
s.add(orth);
s.add(start);
s.add(lineEndPos);
s.add(start);
s.add(orthClone);
s.add(lineEndPos);
return s;
}
public MeshComponent newUndirectedPath(GeoObj from, GeoObj to, Color color) {
return GLFactory.getInstance().newUndirectedPath(
to.getVirtualPosition(from), color);
}
public Shape newUndirectedPath(Vec lineEnd, Color c) {
float down = 0.5f;
Vec e2 = Vec.getOrthogonalHorizontal(lineEnd).normalize().mult(0.9f);
Vec e1 = e2.getNegativeClone();
e2.z -= down;
e1.z -= down;
Vec l25percent = Vec.mult(0.25f, lineEnd);
Vec l75percent = Vec.mult(0.75f, lineEnd);
Vec e3 = Vec.add(lineEnd, e1);
Vec e4 = Vec.add(lineEnd, e2);
e3.z -= down;
e4.z -= down;
Shape s = new Shape(c);
s.add(e1);
s.add(e2);
s.add(l75percent);
s.add(e3);
s.add(e4);
s.add(l25percent);
return s;
}
public Shape newNSidedPolygon(int numberOfSides, float radius, Color c) {
Shape s = new Shape(c);
Vec v = new Vec(radius, 0, 0);
double factor = 360. / numberOfSides;
// there have to be n triangles:
for (int i = 0; i < numberOfSides; i++) {
s.add(v.copy());
v.rotateAroundZAxis(factor);
s.add(v.copy());
// v.rotateAroundZAxis(factor);
s.add(new Vec()); // middle
}
return s;
}
public Shape newCircle(Color c) {
return newNSidedPolygon(20, 1, c);
}
public Shape newNSidedPolygonWithGaps(int numberOfSides, Color c) {
Shape s = new Shape(c);
Vec v = new Vec(1, 0, 0);
double factor = 360 / numberOfSides;
// there have to be n triangles:
for (int i = 0; i < numberOfSides / 2; i++) {
s.add(v.copy());
v.rotateAroundZAxis(factor);
s.add(v.copy());
v.rotateAroundZAxis(factor);
s.add(new Vec()); // middle
}
return s;
}
private static final float HEIGHT_TO_SIDE_FACTOR = (float) (2f / Math
.sqrt(3f));
public Shape newPyramid(Vec center, float height, Color color) {
Shape p = new Shape(color);
// side length:
float a = HEIGHT_TO_SIDE_FACTOR * Math.abs(height);
Vec p1 = new Vec(center.x - 1f / 2f * a, center.y - 1f / 3f
* Math.abs(height), 0f);
Vec p2 = new Vec(center.x + 1f / 2f * a, center.y - 1f / 3f
* Math.abs(height), 0f);
Vec p3 = new Vec(center.x, center.y + 2f / 3f * Math.abs(height), 0f);
Vec p4 = new Vec(center.x, center.y, height);
p.add(p1);
p.add(p2);
p.add(p3);
p.add(p1);
p.add(p2);
p.add(p4);
p.add(p2);
p.add(p3);
p.add(p4);
p.add(p3);
p.add(p1);
p.add(p4);
return p;
}
public static void resetInstance() {
myInstance = new GLFactory();
}
public MeshComponent newCube() {
return newCube(null);
}
public MeshComponent newCoordinateSystem() {
return new MeshComponent(null) {
@Override
public boolean accept(Visitor visitor) {
return false;
}
@Override
public void draw(GL10 gl, Renderable parent) {
CordinateAxis.draw(gl);
}
};
}
/**
* will face to the camera. also read
* {@link GLFactory#newTexturedSquare(String, Bitmap, float)}
*
* @param textToDisplay
* @param textPosition
* @param textSize
* @param context
* @param glCamera
* @return
*/
public Obj newTextObject(String textToDisplay, Vec textPosition,
Context context, GLCamera glCamera) {
float textSize = 1;
TextView v = new TextView(context);
v.setTypeface(null, Typeface.BOLD);
// Set textcolor to black:
// v.setTextColor(new Color(0, 0, 0, 1).toIntARGB());
v.setText(textToDisplay);
Obj o = new Obj();
MeshComponent mesh = this.newTexturedSquare("textBitmap"
+ textToDisplay, util.IO.loadBitmapFromView(v), textSize);
mesh.setPosition(textPosition);
mesh.addAnimation(new AnimationFaceToCamera(glCamera));
o.setComp(mesh);
return o;
}
/**
* also read {@link GLFactory#newTexturedSquare(String, Bitmap, float)}
*
* @param latitude
* @param longitude
* @param bitmap
* the loaded bitmap (e.g. via
* {@link IO#loadBitmapFromURL(String)}
* @param uniqueBitmapName
* a unique bitmap name
* @param heightInMeters
* @param glCamera
* @return an {@link GeoObj} which can be added to the {@link World} e.g.
*/
public GeoObj newIconFacingToCamera(double latitude, double longitude,
Bitmap bitmap, String uniqueBitmapName, float heightInMeters,
GLCamera glCamera) {
MeshComponent triangleMesh = GLFactory.getInstance().newTexturedSquare(
uniqueBitmapName, bitmap, heightInMeters);
triangleMesh.addChild(new AnimationFaceToCamera(glCamera, 0.5f));
GeoObj o = new GeoObj(latitude, longitude);
o.setComp(triangleMesh);
return o;
}
}