package kukaWii.simulation; import java.awt.Font; import java.awt.Frame; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.media.opengl.DebugGL; import javax.media.opengl.GL; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCanvas; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLEventListener; import javax.media.opengl.glu.GLU; import javax.media.opengl.glu.GLUquadric; import javax.xml.ws.Holder; import kukaWii.movement.MoveAction; import kukaWii.movement.MovementService; import com.sun.opengl.util.Animator; import com.sun.opengl.util.FPSAnimator; import com.sun.opengl.util.j2d.TextRenderer; /** * Dient zur Simulation von 3-dimensionalen Bewegungen im Raum. JOGL: * http://download.java.net/media/jogl/builds/archive/jsr-231-1.1.1a/ * * @author Kai Hufenbach * */ public class Simulator { private final float[] x = new float[1]; private final float[] y = new float[1]; private final float[] z = new float[1]; /** * Erzeugt eine neue Simulator Klasse. Dabei wird ein JOGL Fenster mit einer * Roten Kugel geöffnet, die mit einer bestimmten Geschwindigkeit relativ * bewegt werden kann. */ public Simulator() { GLCapabilities caps = new GLCapabilities(); final GLCanvas canvas = new GLCanvas(caps); final Frame frame = new Frame("Movement Simulator"); frame.add(canvas); frame.setSize(800, 800); x[0] = 0; y[0] = 0; z[0] = 0; frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.addKeyListener(new KeyAdapter() { @Override public void keyTyped(KeyEvent evt) { if(evt.getKeyChar() == ' '){ reset(); } } }); canvas.addGLEventListener(new GLEventListener() { Animator animator; GLU glu; TextRenderer textRenderer; int framecount = 0; long fps = 0; MoveAction remainingMove = null; long timeDifference; long tsBefore = System.currentTimeMillis(); long timeToSecond = 0; float remainingTimeDifference = 0; MovementService movementService = MovementService.getService(); @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { GL gl = drawable.getGL(); gl.glViewport(0, 0, width, height); } @Override public void init(GLAutoDrawable drawable) { movementService.setTakeAction(MovementService.NULL); GL gl = drawable.getGL(); glu = new GLU(); drawable.setGL(new DebugGL(gl)); gl.glEnable(GL.GL_DEPTH_TEST); gl.glDepthFunc(GL.GL_LEQUAL); gl.glShadeModel(GL.GL_SMOOTH); gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); gl.glClearColor(0f, 0f, 0f, 1f); // Beleuchtung float SHINE_ALL_DIRECTIONS = 1; float[] lightPos = { -30, -10, 100, SHINE_ALL_DIRECTIONS }; float[] lightColorAmbient = { 0.4f, 0.4f, 0.4f, 1f }; float[] lightColorSpecular = { 0.6f, 0.6f, 0.6f, 1f }; gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, lightPos, 0); gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, lightColorAmbient, 0); gl.glLightfv(GL.GL_LIGHT1, GL.GL_SPECULAR, lightColorSpecular, 0); gl.glEnable(GL.GL_LIGHT1); gl.glEnable(GL.GL_LIGHTING); float[] rgba = { 0.9f, 0.2f, 0.2f }; gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT, rgba, 0); gl.glMaterialfv(GL.GL_FRONT, GL.GL_SPECULAR, rgba, 0); gl.glMaterialf(GL.GL_FRONT, GL.GL_SHININESS, 2.5f); textRenderer = new TextRenderer(new Font("SansSerif", Font.PLAIN, 14)); animator = new FPSAnimator(canvas, 50); animator.start(); } @Override public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { // TODO Auto-generated method stub } @Override public void display(GLAutoDrawable drawable) { if (!animator.isAnimating()) { return; } GL gl = drawable.getGL(); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); setCamera(gl, glu, 1000); gl.glPushMatrix(); gl.glLoadIdentity(); // Zeitdifferenz zwischen dem letzten Mal neuzeichnen wird hier berechnet calculateFPS(); //Wenn keine Bewegung mehr abzuarbeiten ist, dann eine neue holen if (remainingMove == null) { remainingMove = movementService.getNextMoveAction(); } //Es ist noch eine Bewegung abzuarbeiten if (remainingMove != null) { //Um wieviel kann ich mich bewegen? (Zeit zwischen Neuzeichnen und verbleibender vorherigen Bewegung) double moveDistance = (timeDifference + remainingTimeDifference) * remainingMove.getSpeed(); remainingTimeDifference = 0; //Wieweit muss ich mich eigentlich für das Paket insgesamt bewegen? float remainingDistance = (float) Math.sqrt((remainingMove .getX() * remainingMove.getX()) + (remainingMove.getY() * remainingMove.getY()) + (remainingMove.getZ() * remainingMove.getZ())); double proportion = moveDistance / remainingDistance; //Die Bewegung kann nicht vollständig abgearbeitet werden if (proportion < 1) { //Partielle Anteile berechnen double partX = proportion * remainingMove.getX(); double partY = proportion * remainingMove.getY(); double partZ = proportion * remainingMove.getZ(); //Position verändern x[0] += partX; y[0] += partY; z[0] += partZ; //Verbleibende Bewegung berechnen remainingMove.setX(remainingMove.getX() - partX); remainingMove.setY(remainingMove.getY() - partY); remainingMove.setZ(remainingMove.getZ() - partZ); } //Die Bewegung kann vollständig abgearbeitet werden else { //Position verändern x[0] += remainingMove.getX(); y[0] += remainingMove.getY(); z[0] += remainingMove.getZ(); //Es stand für die Bewegung ja mehr Zeit zur Verfügung, den Rest für das nächste mal merken if(proportion != 1){ remainingTimeDifference = timeDifference - (float)((1/proportion)*timeDifference); } remainingMove = null; } gl.glTranslatef(x[0], y[0], z[0]); } GLUquadric ball = glu.gluNewQuadric(); glu.gluQuadricDrawStyle(ball, GLU.GLU_FILL); glu.gluQuadricNormals(ball, GLU.GLU_FLAT); glu.gluQuadricOrientation(ball, GLU.GLU_OUTSIDE); final float radius = 10f; final int slices = 64; final int stacks = 64; glu.gluSphere(ball, radius, slices, stacks); glu.gluDeleteQuadric(ball); gl.glPopMatrix(); // Text textRenderer.beginRendering(drawable.getWidth(), drawable.getHeight()); textRenderer.setColor(1.0f, 1.0f, 1.0f, 0.7f); textRenderer.draw("X: " + x[0], drawable.getWidth() - 80, drawable.getHeight() - 20); textRenderer.draw("Y: " + y[0], drawable.getWidth() - 80, drawable.getHeight() - 45); textRenderer.draw("Z: " + z[0], drawable.getWidth() - 80, drawable.getHeight() - 70); textRenderer.draw("FPS: " + fps, drawable.getWidth() - 80, drawable.getHeight() - 95); textRenderer.endRendering(); } private void setCamera(GL gl, GLU glu, float distance) { gl.glMatrixMode(GL.GL_PROJECTION); gl.glLoadIdentity(); float widthHeightRatio = (float) canvas.getWidth() / (float) canvas.getHeight(); glu.gluPerspective(45, widthHeightRatio, 1, 1000); glu.gluLookAt(0, 0, distance, 0, 0, 0, 0, 1, 0); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); } private void calculateFPS() { framecount++; long ts = System.currentTimeMillis(); timeDifference = ts - tsBefore; tsBefore = ts; timeToSecond += timeDifference; if (timeToSecond > 1000) { fps = framecount / (timeToSecond / 1000); framecount = 0; timeToSecond = 0; } } }); frame.setVisible(true); } private void reset(){ x[0] = 0; y[0] = 0; z[0] = 0; } public static void main(String[] args) { new Simulator(); } }