import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import org.lwjgl.opengl.*; import org.lwjgl.opengl.glu.GLU; import org.lwjgl.opengl.glu.Sphere; import org.lwjgl.input.Keyboard; public class FryEgg { private boolean done = false; private final String windowTitle = "Fry a Digital Egg"; private DisplayMode displayMode; float rotation = 0f; float camx = -.5f, camy=-2.7f, camz=18, keyDelta = 0.3f; private float cameraRotation = 12.6f; private float cameraDistance = 16.7f; // Spheres Sphere sphere, lightSphere; // color of overall scene lighting float ambient[] = { .65f, .65f, .65f, 1f }; // color of light source float lightDiffuse[] = { .9f, .9f, .9f, 1f }; // direct light (yellowish) float lightSpecular[] = { .8f, .8f, .8f, 1f }; // highlight (yellowish) float lightAmbient[] ={.4f,.4f,.4f,1};// { .2f, .2f, 1f, 1f }; // scattered light (yellowish) // light position: if last value is 0, then this describes light direction. // If 1, then light position. float lightPosition[] = { -2f, 2f, 8, 1f }; // Material for planet GLMaterial yolkMaterial = new GLMaterial(); float mtlDiffuse[] = { .99f, .99f, .2f, 1f }; float mtlAmbient[] = { .85f, .85f, .2f, 1f }; float mtlSpecular[] = { .5f, .5f, .5f, 1f }; float mtlShininess = 40f; GLMaterial eggWhiteMaterial = new GLMaterial(); float[] eggd = {1,1,1,1}; float[] egga = {1,1,1,1}; float[] eggs = {1,1,1,1}; float eggShine = 4; // Material, glowing (for "light") GLMaterial materialE = new GLMaterial(); float mtlEmissive[] = { 1f, 1f, .1f, 1f }; // yellow/white /** * Main function just creates and runs the application. */ public static void main(String args[]) { FryEgg app = new FryEgg(); app.run(); } /** * Initialize the app, then sit in a render loop until done==true. */ public void run() { try { init(); while (!done) { mainloop(); render(); Display.update(); } cleanup(); } catch (Exception e) { e.printStackTrace(); System.exit(0); } } /** * Initialize the environment * * @throws Exception */ private void init() throws Exception { initDisplay(); initGL(); initShapes(); rotateCamera(); } /** * Create an OpenGL display, in this case a fullscreen window. * * @throws Exception */ private void initDisplay() throws Exception { // get all possible display resolutions DisplayMode d[] = Display.getAvailableDisplayModes(); // find a resolution we like for (int i = 0; i < d.length; i++) { if (d[i].getWidth() == 800 && d[i].getHeight() == 600 && d[i].getBitsPerPixel() == 32) { displayMode = d[i]; break; } } // set the display to the resolution we picked Display.setDisplayMode(displayMode); Display.setFullscreen(false); Display.setTitle(windowTitle); // create the window Display.create(); } /** * Initialize OpenGL * */ private void initGL() { // Select the Projection Matrix (controls perspective) GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glLoadIdentity(); // Reset The Projection Matrix // Define perspective GLU.gluPerspective(45.0f, // Field Of View (float) displayMode.getWidth() / (float) displayMode.getHeight(), // aspect // ratio 0.1f, // near Z clipping plane 100.0f); // far Z clipping plane // Select The Modelview Matrix (controls model orientation) GL11.glMatrixMode(GL11.GL_MODELVIEW); // turn depth testing on GL11.glEnable(GL11.GL_DEPTH_TEST); // OpenGL won't draw backward facing triangles ("back faces") GL11.glEnable(GL11.GL_CULL_FACE); // turn lighting on (does not create a light) GL11.glEnable(GL11.GL_LIGHTING); // Tell OpenGL to force all normal lengths to 1, // so light illuminates all surfaces evenly GL11.glEnable(GL11.GL_NORMALIZE); // Create a light // diffuse is the color of direct light from this light source // ambient is the color of reflected light from this source // position is where the light is, or it's direction setLight(GL11.GL_LIGHT1, lightDiffuse, lightAmbient, lightSpecular, lightPosition); // overall scene lighting setAmbientLight(ambient); // "planet" material settings yolkMaterial.setSurfaceColorLit(mtlDiffuse); yolkMaterial.setSurfaceColorShadow(mtlAmbient); yolkMaterial.setReflectionColor(mtlSpecular); yolkMaterial.setShininess(mtlShininess); yolkMaterial.apply(); eggWhiteMaterial.setSurfaceColorLit(eggd); eggWhiteMaterial.setSurfaceColorShadow(egga); eggWhiteMaterial.setReflectionColor(eggs); eggWhiteMaterial.setShininess(eggShine); // make a glowing material for the "light" materialE.setGlowColor(mtlEmissive); } private void initShapes() { sphere = new Sphere(); lightSphere = new Sphere(); } private void mainloop() { if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) { // Escape is pressed done = true; } if (Display.isCloseRequested()) { // Window is closed done = true; } boolean r = false; if (Keyboard.isKeyDown(Keyboard.KEY_R)) { cameraDistance -= keyDelta; r = true; } if (Keyboard.isKeyDown(Keyboard.KEY_F)) { cameraDistance += keyDelta; r = true; } if (Keyboard.isKeyDown(Keyboard.KEY_A)) { cameraRotation -= 2*keyDelta; r = true; } if (Keyboard.isKeyDown(Keyboard.KEY_D)) { cameraRotation += 2*keyDelta; r = true; } if (Keyboard.isKeyDown(Keyboard.KEY_W)) { camy += keyDelta; r = true; } if (Keyboard.isKeyDown(Keyboard.KEY_S)) { camy -= keyDelta; r = true; } if(Keyboard.isKeyDown(Keyboard.KEY_SPACE)) { lightPosition[0] = 2; } else { lightPosition[0] = -2; } if(r) rotateCamera(); if (Display.isCloseRequested()) { // Window is closed done = true; } // clear = !Keyboard.isKeyDown(Keyboard.KEY_SPACE); } private void rotateCamera() { camx = cameraDistance * (float) Math.sin(Math.toRadians(cameraRotation)); camz = cameraDistance * (float) Math.cos(Math.toRadians(cameraRotation)); System.out.printf("%5.2f, %5.2f, %5.2f\nr: %f d:%f\n:", camx, camy, camz, cameraRotation, cameraDistance); render(); } /** * Render the scene. */ private void render() { rotation += .05f; // Clear screen and depth buffer GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); // Select The Modelview Matrix (controls model orientation) GL11.glMatrixMode(GL11.GL_MODELVIEW); // Reset the Modelview matrix // this resets the coordinate system to center of screen GL11.glLoadIdentity(); GLU.gluLookAt( camx, camy, camz, // eye position 0f, 0f, 0f, // target to look at 0f, 1f, 0f); // which way is up materialE.apply(); setLight(GL11.GL_LIGHT1, lightDiffuse, lightAmbient, lightSpecular, lightPosition); // materialE.apply(); yolkMaterial.apply(); GL11.glPushMatrix(); { GL11.glScalef(3,3,3); // GL11.glColor4f(1,1,1,0.1f); sphere.draw(1, 48, 48); } GL11.glPopMatrix(); eggWhiteMaterial.apply(); GL11.glTranslatef(0, 0, 1f); GL11.glScalef(.8f,.8f,.8f); GL11.glColor4f(1,1,1,1); GL11.glNormal3f(0, 0, 1); drawQuads(); } public void drawCube() { GL11.glBegin(GL11.GL_QUADS); // Front Face GL11.glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Left GL11.glVertex3f(1.0f, -1.0f, 1.0f); // Bottom Right GL11.glVertex3f(1.0f, 1.0f, 1.0f); // Top Right GL11.glVertex3f(-1.0f, 1.0f, 1.0f); // Top Left // Back Face GL11.glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Right GL11.glVertex3f(-1.0f, 1.0f, -1.0f); // Top Right GL11.glVertex3f(1.0f, 1.0f, -1.0f); // Top Left GL11.glVertex3f(1.0f, -1.0f, -1.0f); // Bottom Left // Top Face GL11.glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left GL11.glVertex3f(-1.0f, 1.0f, 1.0f); // Bottom Left GL11.glVertex3f(1.0f, 1.0f, 1.0f); // Bottom Right GL11.glVertex3f(1.0f, 1.0f, -1.0f); // Top Right // Bottom Face GL11.glVertex3f(-1.0f, -1.0f, -1.0f); // Top Right GL11.glVertex3f(1.0f, -1.0f, -1.0f); // Top Left GL11.glVertex3f(1.0f, -1.0f, 1.0f); // Bottom Left GL11.glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Right // Right face GL11.glVertex3f(1.0f, -1.0f, -1.0f); // Bottom Right GL11.glVertex3f(1.0f, 1.0f, -1.0f); // Top Right GL11.glVertex3f(1.0f, 1.0f, 1.0f); // Top Left GL11.glVertex3f(1.0f, -1.0f, 1.0f); // Bottom Left // Left Face GL11.glVertex3f(-1.0f, -1.0f, -1.0f); // Bottom Left GL11.glVertex3f(-1.0f, -1.0f, 1.0f); // Bottom Right GL11.glVertex3f(-1.0f, 1.0f, 1.0f); // Top Right GL11.glVertex3f(-1.0f, 1.0f, -1.0f); // Top Left GL11.glEnd(); } /** * Draw a 1x1 quad, centered on the origin, facing toward +Z. * Add a normal for lighting. */ public void drawQuad(float z) { GL11.glBegin(GL11.GL_QUADS); GL11.glNormal3f( 0.0f, 0.0f, 1.0f); GL11.glVertex3f( -.5f, -.5f, z); // left bottom GL11.glVertex3f( .5f, -.5f, z); // rite bottom GL11.glVertex3f( .5f, .5f, z); // rite top GL11.glVertex3f( -.5f, .5f, z); // left top GL11.glEnd(); } /** * draw a ground plane using quads (100x100) * */ public void drawQuads() { for (int r=0; r < 50; r++) { for (int c=0; c < 50; c++) { GL11.glPushMatrix(); { GL11.glTranslatef(r-25,c-25,0); drawQuad((float)Math.random()); } GL11.glPopMatrix(); } } } private void cleanup() { Display.destroy(); } /** * Simple way to setup a light. Uses same color for direct light (diffuse), * reflected highlight (specular) and scattered light (ambient). Ambient * color is darkened to 1/4 of the light color. * * @param GLLightHandle * @param color * @param position */ public static void setLight(int GLLightHandle, float[] color, float[] position) { float[] ambientLight = { color[0] / 4f, color[1] / 4f, color[2] / 4f, color[3] / 4f }; FloatBuffer lightColor = allocFloats(color); FloatBuffer ambientColor = allocFloats(ambientLight); FloatBuffer ltPosition = allocFloats(position); GL11.glLight(GLLightHandle, GL11.GL_DIFFUSE, lightColor); // color of // the // direct // illumination GL11.glLight(GLLightHandle, GL11.GL_SPECULAR, lightColor); // color of // the // highlight // (same as // direct // light) GL11.glLight(GLLightHandle, GL11.GL_AMBIENT, ambientColor); // color of // the // scattered // light // (darker) GL11.glLight(GLLightHandle, GL11.GL_POSITION, ltPosition); GL11.glEnable(GLLightHandle); // Enable the light (GL_LIGHT1 - 7) } /** * Set the color of a 'positional' light (a light that has a specific * position within the scene).
*
* Params:
* an OpenGL light number (GL11.GL_LIGHT1),
* 'Diffuse': color of direct light from this source,
* 'Ambient': color of scattered light from this source
* 'Specular': color of this light reflected off a surface,
* position.
*/ public static void setLight(int GLLightHandle, float[] diffuseLightColor, float[] ambientLightColor, float[] specularLightColor, float[] position) { FloatBuffer ltDiffuse = allocFloats(diffuseLightColor); FloatBuffer ltAmbient = allocFloats(ambientLightColor); FloatBuffer ltSpecular = allocFloats(specularLightColor); FloatBuffer ltPosition = allocFloats(position); GL11.glLight(GLLightHandle, GL11.GL_DIFFUSE, ltDiffuse); // color of // the // direct // illumination GL11.glLight(GLLightHandle, GL11.GL_AMBIENT, ltAmbient); // color of // the // reflected // light GL11.glLight(GLLightHandle, GL11.GL_SPECULAR, ltSpecular); // color of // the // highlight // (same as // direct // light) GL11.glLight(GLLightHandle, GL11.GL_POSITION, ltPosition); GL11.glEnable(GLLightHandle); // Enable the light (GL_LIGHT1 - 7) // GL11.glLightf(GLLightHandle, GL11.GL_QUADRATIC_ATTENUATION, .005F); // // how light beam drops off } /** * Set the position of a light to the given xyz. */ public static void setLightPos(int GLLightHandle, float x, float y, float z) { float[] position = new float[] { x, y, z, 1 }; GL11.glLight(GLLightHandle, GL11.GL_POSITION, allocFloats(position)); } /** * Set the color of the Global Ambient Light. Affects all objects in scene * regardless of their placement. */ public static void setAmbientLight(float[] ambientLightColor) { FloatBuffer ltAmbient = allocFloats(ambientLightColor); GL11.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, ltAmbient); } public static final int SIZE_FLOAT = 4; public static FloatBuffer allocFloats(int howmany) { return ByteBuffer.allocateDirect(howmany * SIZE_FLOAT).order(ByteOrder.nativeOrder()) .asFloatBuffer(); } public static FloatBuffer allocFloats(float[] floatarray) { FloatBuffer fb = ByteBuffer.allocateDirect(floatarray.length * SIZE_FLOAT).order( ByteOrder.nativeOrder()).asFloatBuffer(); fb.put(floatarray).flip(); return fb; } }