package gl; import gl.scenegraph.MeshComponent; import java.util.Date; import javax.microedition.khronos.opengles.GL10; import util.Log; import util.Vec; import worldData.Visitor; /** * Great tutorials: * http://iphonedevelopment.blogspot.com/2009/05/opengl-es-from-ground-up-part-4 * -let.html * * http://www.sjbaker.org/steve/omniv/opengl_lighting.html * * Some good hints (how to create flashlight effect, moving lights etc): * http://www.opengl.org/resources/faq/technical/lights.htm * * Basics plus code examples: http://glprogramming.com/red/chapter05.html * * A lot of text, detailed information: * http://www.falloutsoftware.com/tutorials/gl/gl8.htm * * * * About light models: * http://www.talisman.org/opengl-1.1/Reference/glLightModel.html * * * * the current problem with lightning might be that the normals of every shape * have to be calculated to enable correct lightning and when working with * moving and rotating objects this would cost a lot of time. so at the moment * its not fully implemented! * * @author Spobo * */ public class LightSource extends MeshComponent { private static final String LOG_TAG = "LightSource"; private int myLightId; /** * specular light is the white dot on the ball. Try something like { 0.7f, * 0.7f, 0.7f, 1 } */ private float[] specularLightColor; /** * diffuse light is the bright part around the white dot on the ball. Try * something like { 0.5f, 0.5f, 0.5f, 1 } */ private float[] diffuseLightColor; /** * ambient light is the light emitted by everything (has no source, is the * ground level level). * * The simples way to control the ambient light is to set it to a certain * value on one light source and to { 0, 0, 0, 1 } on all other * light-sources! */ private float[] ambientLightColor;// = { 0, 0, 0, 1 }; // private float[] myPosition = { 0, 0, 10, 0 }; /** * it this is null the light source will not be interpreted as a spot light. * This has to be something like { 0, 0, -1 } */ private float[] mySpotDirection; /** * 45 would meen 90 degree field of vision! */ private float cutoffAngle = 20; /** * @param glLightId * something between GL10.GL_LIGHT0 and GL10.GL_LIGHT7 (8 * light-sources maximum) */ public LightSource(int glLightId) { super(null); this.myLightId = glLightId; } public void switchOn(GL10 gl) { Log.d(LOG_TAG, "Now switching lightsource " + myLightId + " to on!"); gl.glEnable(myLightId); // if it has an ambient component enable it: if (ambientLightColor != null) gl.glLightfv(myLightId, GL10.GL_AMBIENT, ambientLightColor, 0); if (diffuseLightColor != null) gl.glLightfv(myLightId, GL10.GL_DIFFUSE, diffuseLightColor, 0); if (specularLightColor != null) gl.glLightfv(myLightId, GL10.GL_SPECULAR, specularLightColor, 0); if (myPosition != null) gl.glLightfv(myLightId, GL10.GL_POSITION, myPosition.getArrayVersion(), 0); // if it is a spotlight: if (mySpotDirection != null) { gl.glLightfv(myLightId, GL10.GL_SPOT_DIRECTION, GLUtilityClass.createAndInitFloatBuffer(mySpotDirection)); gl.glLightf(myLightId, GL10.GL_SPOT_CUTOFF, cutoffAngle); } setDefaultSimpleMaterialStuff(gl); } // default material values which should be overwritten by each mesh later: private float x = 0.3f; private float materialAmbient[] = new float[] { x, x, x, 1 }; private float materialDiffuse[] = new float[] { x, x, x, 1 }; private float materialSpecular[] = new float[] { x, x, x, 1 }; /** * TODO move this somewhere else, if material is used it should be set to * default values by each mesh individually! * * @param gl */ private void setDefaultSimpleMaterialStuff(GL10 gl) { /* * A default material is defined here but all objects should define a * custom one if they have a special type of meterial! */ gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, materialAmbient, 0); gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, materialDiffuse, 0); gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, materialSpecular, 0); gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, 5.0f); // otherMaterialStuffThatDoesNotWork(gl); // use the colors of the meshes, this should not be set if every element // has a correct material i think.. not sure gl.glEnable(GL10.GL_COLOR_MATERIAL); } // private FloatBuffer mab; // // private FloatBuffer mdb; // // private FloatBuffer msb; // // private void otherMaterialStuffThatDoesNotWork(GL10 gl) { // mab = ByteBuffer.allocateDirect(4 * 4).order(ByteOrder.nativeOrder()) // .asFloatBuffer(); // mab.put(new float[] { 1.0f, 0.0f, 0.0f, 1.0f }); // mab.position(0); // mdb = ByteBuffer.allocateDirect(4 * 4).order(ByteOrder.nativeOrder()) // .asFloatBuffer(); // mdb.put(new float[] { 0.0f, 1.0f, 0.0f, 1.0f }); // mdb.position(0); // msb = ByteBuffer.allocateDirect(4 * 4).order(ByteOrder.nativeOrder()) // .asFloatBuffer(); // msb.put(new float[] { 0.0f, 0.0f, 1.0f, 1.0f }); // msb.position(0); // // gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, mab); // gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, mdb); // gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, msb); // gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, 128.0f); // } public void switchOff(GL10 gl) { gl.glDisable(myLightId); } public static LightSource newDefaultAmbientLight(int lightId) { LightSource l = new LightSource(lightId); float b = 0.05f; float[] color = { b, b, b, 1 }; l.ambientLightColor = color; return l; } public static LightSource newDefaultDefuseLight(int lightId, Vec lightPosition) { LightSource l = new LightSource(lightId); float b = 0.7f; float[] color = { b, b, b, 1 }; l.diffuseLightColor = color; l.myPosition = lightPosition.copy(); return l; } public static LightSource newDefaultSpotLight(int lightId, Vec lightPosition, Vec lightTargetPosition) { LightSource l = new LightSource(lightId); float b = 0.2f; float[] color = { b, b, b, 1 }; l.specularLightColor = color; l.myPosition = lightPosition.copy(); if (lightTargetPosition != null) { Vec directionVec = Vec.sub(lightTargetPosition, lightPosition) .normalize(); float[] direction = { directionVec.x, directionVec.y, directionVec.z }; l.mySpotDirection = direction; } return l; } /** * // TODO calculate the position of the sun to set the sun light-source at * the correct place * * http://www.srrb.noaa.gov/highlights/sunrise/calcdetails.html * * and * * http://www.srrb.noaa.gov/highlights/sunrise/program.txt * * @param lightId * @param currentDate * @return */ public static LightSource newDefaultDayLight(int lightId, Date currentDate) { LightSource l = new LightSource(lightId); float b = 0.4f; float[] color = { b, b, b, 1 }; l.specularLightColor = color; Vec lightPosition = new Vec(100, 100, 100); l.myPosition = lightPosition; Vec directionVec = Vec.sub(new Vec(), lightPosition).normalize(); float[] direction = { directionVec.x, directionVec.y, directionVec.z }; l.mySpotDirection = direction; return l; } @Override public boolean accept(Visitor visitor) { return true; } @Override public void draw(GL10 gl, Renderable parent) { /* * the lightsource can be added as a normal mesh to the world to allow * movements * * read the part about moving lightsources * http://www.opengl.org/resources/faq/technical/lights.htm * * also read "Position and Attenuation" in * http://fly.cc.fer.hr/~unreal/theredbook/chapter06.html */ if (myPosition == null) { myPosition = new Vec(); } gl.glLightfv(myLightId, GL10.GL_POSITION, myPosition.getArrayVersion(), 0); } }