/*
* File name: VideoPlugin3D.java (package eas.simulation.users.students.fabianRigoll.sim3D.physicalSimulation.videoPlugin3D)
* Author(s): Fabian
* Java version: 6.0
* Generation date: 15.04.2011 (09:39:25)
*
* This class contains large parts of the JBullet Framework bei Martin Dvorak.
* Therefore the following license must be included:
*
* * Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz>
*
* Bullet Continuous Collision Detection and Physics Library
* Copyright (c) 2003-2008 Erwin Coumans http://www.bulletphysics.com/
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
*
*
*
* (c) This file and the EAS (Easy Agent Simulation) framework containing it
* is protected by Creative Commons by-nc-sa license. Any altered or
* further developed versions of this file have to meet the agreements
* stated by the license conditions.
*
* In a nutshell
* -------------
* You are free:
* - to Share -- to copy, distribute and transmit the work
* - to Remix -- to adapt the work
*
* Under the following conditions:
* - Attribution -- You must attribute the work in the manner specified by the
* author or licensor (but not in any way that suggests that they endorse
* you or your use of the work).
* - Noncommercial -- You may not use this work for commercial purposes.
* - Share Alike -- If you alter, transform, or build upon this work, you may
* distribute the resulting work only under the same or a similar license to
* this one.
*
* + Detailed license conditions (Germany):
* http://creativecommons.org/licenses/by-nc-sa/3.0/de/
* + Detailed license conditions (unported):
* http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
*
* This header must be placed in the beginning of any version of this file.
*/
package eas.plugins.standard.visualization.visualization3D;
import static com.bulletphysics.demos.opengl.IGL.GL_AMBIENT;
import static com.bulletphysics.demos.opengl.IGL.GL_COLOR_BUFFER_BIT;
import static com.bulletphysics.demos.opengl.IGL.GL_DEPTH_BUFFER_BIT;
import static com.bulletphysics.demos.opengl.IGL.GL_DEPTH_TEST;
import static com.bulletphysics.demos.opengl.IGL.GL_DIFFUSE;
import static com.bulletphysics.demos.opengl.IGL.GL_LESS;
import static com.bulletphysics.demos.opengl.IGL.GL_LIGHT0;
import static com.bulletphysics.demos.opengl.IGL.GL_LIGHT1;
import static com.bulletphysics.demos.opengl.IGL.GL_LIGHTING;
import static com.bulletphysics.demos.opengl.IGL.GL_MODELVIEW;
import static com.bulletphysics.demos.opengl.IGL.GL_POSITION;
import static com.bulletphysics.demos.opengl.IGL.GL_PROJECTION;
import static com.bulletphysics.demos.opengl.IGL.GL_SMOOTH;
import static com.bulletphysics.demos.opengl.IGL.GL_SPECULAR;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import javax.imageio.ImageIO;
import javax.vecmath.Matrix3f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector3f;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import com.bulletphysics.BulletGlobals;
import com.bulletphysics.BulletStats;
import com.bulletphysics.collision.dispatch.CollisionObject;
import com.bulletphysics.demos.opengl.GLShapeDrawer;
import com.bulletphysics.demos.opengl.LwjglGL;
import com.bulletphysics.dynamics.DynamicsWorld;
import com.bulletphysics.dynamics.RigidBody;
import com.bulletphysics.linearmath.Clock;
import com.bulletphysics.linearmath.DefaultMotionState;
import com.bulletphysics.linearmath.QuaternionUtil;
import com.bulletphysics.linearmath.Transform;
import com.bulletphysics.linearmath.VectorUtil;
import eas.plugins.AbstractDefaultPlugin;
import eas.simulation.Wink;
import eas.simulation.event.EASEvent;
import eas.simulation.spatial.sim3D.physicalSimulation.standardAgents.AbstractAgent3D;
import eas.simulation.spatial.sim3D.physicalSimulation.standardEnvironments.AbstractEnvironment3D;
import eas.startSetup.ParCollection;
import eas.startSetup.SingleParameter;
import eas.startSetup.parameterDatatypes.Datatypes;
/**
*
* * Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz>
*
* Bullet Continuous Collision Detection and Physics Library
* Copyright (c) 2003-2008 Erwin Coumans http://www.bulletphysics.com/
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* @author Fabian (adapted work from Martin Dvorak's JBullet)
*
*/
public class VideoPlugin3D extends
AbstractDefaultPlugin<AbstractEnvironment3D<AbstractAgent3D<?>>> {
/**
*
*/
private static final long serialVersionUID = -472396947478196475L;
private static String pfad = "VideoPlugin3DFolder";
/**
* Amount by which the camera is shifted each time.
*/
private static final float STEPSIZE = 10;
/**
* Internal clock.
*/
private Clock clock = new Clock();
/**
* The physics world to be drawn.
*/
private static DynamicsWorld dynamicsWorld;
/**
* The camera's distance from the point it is supposed to look at.
*/
private static float cameraDistance = 0;
//private final static float STANDARD_CAMERA_DISTANCE = 50;
private static float STANDARD_CAMERA_DISTANCE;
private final static float STANDARD_CAMERA_ELE = 20f;
private final static float STANDARD_CAMERA_AZI = 0;
private final static Vector3f cameraUp = new Vector3f(0f, 1f, 0f);
private static float ele = STANDARD_CAMERA_ELE;
private static float azi = STANDARD_CAMERA_AZI;
private static boolean followAgent = false;
private static AbstractAgent3D<?> agentToFollow = null;
private static Vector3f cameraPosition = new Vector3f(0f, 0f, 0f);
private static Vector3f cameraTargetPosition = new Vector3f(0f, 0f, 0f);
private static int forwardAxis = 2;
private final static Transform m = new Transform();
private static int glutScreenWidth = 0;
private static int glutScreenHeight = 0;
private static Vector3f wireColor = new Vector3f();
private long lastTime;
private int frames = 0;
private int lastFrames = 0;
private int windowWidth = 1024;
private int windowHeight = 768;
private double mouseSensitivityX = 1;
private double mouseSensitivityY = 0.35;
private double mouseSensitivityW = 0.1;
private static LwjglGL gl = new LwjglGL();
private static boolean quit = false;
private static String title = "videoplugin3d ";
private static boolean mouseControlsActive = true;
public static void setDynamicsWorld(DynamicsWorld dynamicsWorldToBeDrawn) {
dynamicsWorld = dynamicsWorldToBeDrawn;
}
/**
* Allow or disallow controls.
* @param active Boolean: true - allow controls. false - disallow them.
*/
public static void setMouseControls(boolean active) {
mouseControlsActive = active;
}
@Override
public List<String> getRequiredPlugins() {
return null;
}
@Override
public List<SingleParameter> getParameters() {
ArrayList<SingleParameter> list = new ArrayList<SingleParameter>();
list.add(new SingleParameter("windowWidth", Datatypes.INTEGER, 1024,
"Breite des Fensters (1024, " + "falls nichts angegeben).",
this.id().toUpperCase()));
list.add(new SingleParameter("windowHeight", Datatypes.INTEGER, 768,
"Höhe des Fensters (768, " + "falls nichts angegeben).", this
.id().toUpperCase()));
list.add(new SingleParameter("mouseSensitivityX", Datatypes.DOUBLE,
1.0, "Mausempfindlichkeit horizontal.", this.id().toUpperCase()));
list.add(new SingleParameter("mouseSensitivityY", Datatypes.DOUBLE,
0.35, "Mausempfindlichkeit vertikal.", this.id().toUpperCase()));
list.add(new SingleParameter("mouseSensitivityW", Datatypes.DOUBLE,
0.012, "Mausempfindlichkeit Scrollrad.", this.id()
.toUpperCase()));
list.add(new SingleParameter("standardCameraDistance", Datatypes.DOUBLE,
50.0, "Entfernung der Kamera vom zu beobachtenden Objekt.", this.id().toUpperCase()));
return list;
}
@Override
public String id() {
return "videoplugin3d";
}
@Override
public void runBeforeSimulation(
final AbstractEnvironment3D<AbstractAgent3D<?>> env,
final ParCollection params) {
pfad = params.getStdDirectory();
// Get the physics world to be drawn on screen.
dynamicsWorld = env.getDynamicsWorld();
// Store params locally.
this.windowWidth = params.getParValueInt("windowWidth");
this.windowHeight = params.getParValueInt("windowHeight");
this.mouseSensitivityX = params.getParValueDouble("mouseSensitivityX");
this.mouseSensitivityY = params.getParValueDouble("mouseSensitivityY");
this.mouseSensitivityW = params.getParValueDouble("mouseSensitivityW");
STANDARD_CAMERA_DISTANCE = params.getParValueDouble("standardCameraDistance").floatValue();
// Create new display.
if (this.windowHeight <= 0) {
this.windowHeight = 400;
}
if (this.windowWidth <= 0) {
this.windowWidth = 400;
}
try {
Display.destroy();
}
catch (Exception e) {
}
try {
Display.setDisplayMode(new DisplayMode(windowWidth, windowHeight));
Display.setTitle(title);
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
}
myinit();
reshape(windowWidth, windowHeight);
setCameraDistance(STANDARD_CAMERA_DISTANCE);
//clientResetScene();
lastTime = System.currentTimeMillis();
Mouse.setGrabbed(true);
}
@Override
public void runAfterSimulation(
final AbstractEnvironment3D<AbstractAgent3D<?>> env,
final ParCollection params) {
}
@Override
public void runDuringSimulation(
final AbstractEnvironment3D<AbstractAgent3D<?>> env, Wink simZyk,
final ParCollection params) {
clientMoveAndDisplay();
Display.update();
while (Keyboard.next()) {
if (Keyboard.getEventCharacter() != '\0') {
keyboardCallback(Keyboard.getEventCharacter());
}
if (Keyboard.getEventKey() == Keyboard.KEY_ESCAPE)
quit = true;
if (Keyboard.getEventKey() == Keyboard.KEY_Q)
quit = true;
}
float dx = Mouse.getDX();
float dy = Mouse.getDY();
float dw = Mouse.getDWheel();
if (mouseControlsActive) {
stepHorizontalBySteps(dx * mouseSensitivityX);
stepVerticalBySteps(dy * mouseSensitivityY);
zoomBySteps(dw * mouseSensitivityW);
}
// Calculate frame-rate.
long time = System.currentTimeMillis();
if (time - lastTime < 1000) {
frames++;
} else {
lastFrames = frames;
lastTime = time;
frames = 0;
}
Display.setTitle(
title + " | Tick: " +
simZyk + " | Duration: " + clock.getTimeMilliseconds()/100/10.0 +
"s | FPS: " + lastFrames);
if (quit) {
env.getSimTime().timeTerminate();
}
}
@Override
public void handleEvent(EASEvent e,
final AbstractEnvironment3D<AbstractAgent3D<?>> env,
Wink lastTimeStep, final ParCollection params) {
}
public void setOrthographicProjection() {
// switch to projection mode
gl.glMatrixMode(GL_PROJECTION);
// save previous matrix which contains the
// settings for the perspective projection
gl.glPushMatrix();
// reset matrix
gl.glLoadIdentity();
// set a 2D orthographic projection
gl.gluOrtho2D(0f, glutScreenWidth, 0f, glutScreenHeight);
gl.glMatrixMode(GL_MODELVIEW);
gl.glLoadIdentity();
// invert the y axis, down is positive
gl.glScalef(1f, -1f, 1f);
// mover the origin from the bottom left corner
// to the upper left corner
gl.glTranslatef(0f, -glutScreenHeight, 0f);
}
public void resetPerspectiveProjection() {
gl.glMatrixMode(GL_PROJECTION);
gl.glPopMatrix();
gl.glMatrixMode(GL_MODELVIEW);
updateCamera();
}
public float getDeltaTimeMicroseconds() {
float dt = clock.getTimeMicroseconds();
clock.reset();
return dt;
}
public static void renderme() {
updateCamera();
if (dynamicsWorld != null) {
int numObjects = dynamicsWorld.getNumCollisionObjects();
wireColor.set(1f, 0f, 0f);
for (int i = 0; i < numObjects; i++) {
CollisionObject colObj = dynamicsWorld
.getCollisionObjectArray().getQuick(i);
RigidBody body = RigidBody.upcast(colObj);
if (body != null && body.getMotionState() != null) {
DefaultMotionState myMotionState = (DefaultMotionState) body
.getMotionState();
m.set(myMotionState.graphicsWorldTrans);
} else {
colObj.getWorldTransform(m);
}
wireColor.set(1f, 1f, 0.5f); // wants deactivation
if ((i & 1) != 0) {
wireColor.set(0f, 0f, 1f);
}
// color differently for active, sleeping, wantsdeactivation
// states
if (colObj.getActivationState() == 1) // active
{
if ((i & 1) != 0) {
// wireColor.add(new Vector3f(1f, 0f, 0f));
wireColor.x += 1f;
} else {
// wireColor.add(new Vector3f(0.5f, 0f, 0f));
wireColor.x += 0.5f;
}
}
if (colObj.getActivationState() == 2) // ISLAND_SLEEPING
{
if ((i & 1) != 0) {
// wireColor.add(new Vector3f(0f, 1f, 0f));
wireColor.y += 1f;
} else {
// wireColor.add(new Vector3f(0f, 0.5f, 0f));
wireColor.y += 0.5f;
}
}
GLShapeDrawer.drawOpenGL(gl, m, colObj.getCollisionShape(),
wireColor, 0);
}
}
updateCamera();
}
public static void clientMoveAndDisplay() {
gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// simple dynamics world doesn't handle fixed-time-stepping
// float ms = getDeltaTimeMicroseconds();
// step the simulation
if (dynamicsWorld != null) {
// dynamicsWorld.stepSimulation(ms / 1000000f);
// optional but useful: debug drawing
//dynamicsWorld.debugDrawWorld();
}
renderme();
}
public static void updateCamera() {
gl.glMatrixMode(GL_PROJECTION);
gl.glLoadIdentity();
float rele = (float) Math.toRadians(ele);
float razi = (float) Math.toRadians(azi);
Quat4f rot = new Quat4f();
// Quaternion für 2. Achse (y, also nach oben) berechnen
// bei Drehung um "razi" im Bogenmaß. Entspricht Drehung
// nach links und rechts.
QuaternionUtil.setRotation(rot, cameraUp, razi);
Vector3f eyePos = new Vector3f();
eyePos.set(0f, 0f, 0f);
// 3. Koordinate setzen für den Abstand. 3. Achse bzw. z ist nach vorne.
VectorUtil.setCoord(eyePos, forwardAxis, -cameraDistance);
Vector3f forward = new Vector3f();
forward.set(eyePos.x, eyePos.y, eyePos.z);
if (forward.lengthSquared() < BulletGlobals.FLT_EPSILON) {
forward.set(1f, 0f, 0f);
}
Vector3f right = new Vector3f();
right.cross(cameraUp, forward);
Quat4f roll = new Quat4f();
QuaternionUtil.setRotation(roll, right, -rele);
Matrix3f tmpMat1 = new Matrix3f();
Matrix3f tmpMat2 = new Matrix3f();
tmpMat1.set(rot);
tmpMat2.set(roll);
tmpMat1.mul(tmpMat2);
tmpMat1.transform(eyePos);
cameraPosition.set(eyePos);
if (glutScreenWidth > glutScreenHeight) {
float aspect = glutScreenWidth / (float) glutScreenHeight;
gl.glFrustum(-aspect, aspect, -1.0, 1.0, 1.0, 10000.0);
} else {
float aspect = glutScreenHeight / (float) glutScreenWidth;
gl.glFrustum(-1.0, 1.0, -aspect, aspect, 1.0, 10000.0);
}
// Das Ziel neu setzen, so dass die Kamera neu ausgerichtet wird.
if (followAgent && agentToFollow != null) {
cameraTargetPosition = agentToFollow.getPosition();
}
gl.glMatrixMode(GL_MODELVIEW);
gl.glLoadIdentity();
// Verschiebe die Kamera in Richtung des zu beobachtenden Objekts.
cameraPosition.add(cameraTargetPosition);
gl.gluLookAt(cameraPosition.x, cameraPosition.y, cameraPosition.z,
cameraTargetPosition.x, cameraTargetPosition.y,
cameraTargetPosition.z, cameraUp.x, cameraUp.y, cameraUp.z);
}
public static void setCameraDistance(float dist) {
cameraDistance = dist;
}
public DynamicsWorld getDynamicsWorld() {
return dynamicsWorld;
}
public static void reshape(int w, int h) {
glutScreenWidth = w;
glutScreenHeight = h;
gl.glViewport(0, 0, w, h);
updateCamera();
}
public static void myinit() {
float[] light_ambient = new float[] { 0.2f, 0.2f, 0.2f, 1.0f };
float[] light_diffuse = new float[] { 1.0f, 1.0f, 1.0f, 1.0f };
float[] light_specular = new float[] { 1.0f, 1.0f, 1.0f, 1.0f };
/* light_position is NOT default value */
float[] light_position0 = new float[] { 1.0f, 10.0f, 1.0f, 0.0f };
float[] light_position1 = new float[] { -1.0f, -10.0f, -1.0f, 0.0f };
gl.glLight(GL_LIGHT0, GL_AMBIENT, light_ambient);
gl.glLight(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
gl.glLight(GL_LIGHT0, GL_SPECULAR, light_specular);
gl.glLight(GL_LIGHT0, GL_POSITION, light_position0);
gl.glLight(GL_LIGHT1, GL_AMBIENT, light_ambient);
gl.glLight(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
gl.glLight(GL_LIGHT1, GL_SPECULAR, light_specular);
gl.glLight(GL_LIGHT1, GL_POSITION, light_position1);
gl.glEnable(GL_LIGHTING);
gl.glEnable(GL_LIGHT0);
gl.glEnable(GL_LIGHT1);
gl.glShadeModel(GL_SMOOTH);
gl.glEnable(GL_DEPTH_TEST);
gl.glDepthFunc(GL_LESS);
gl.glClearColor(0.7f, 0.7f, 0.7f, 0f);
}
public void clientResetScene() {
BulletStats.gNumDeepPenetrationChecks = 0;
BulletStats.gNumGjkChecks = 0;
int numObjects = 0;
if (dynamicsWorld != null) {
// dynamicsWorld.stepSimulation(1f / 60f, 0);
numObjects = dynamicsWorld.getNumCollisionObjects();
}
for (int i = 0; i < numObjects; i++) {
CollisionObject colObj = dynamicsWorld.getCollisionObjectArray()
.getQuick(i);
RigidBody body = RigidBody.upcast(colObj);
if (body != null) {
if (body.getMotionState() != null) {
DefaultMotionState myMotionState = (DefaultMotionState) body
.getMotionState();
myMotionState.graphicsWorldTrans
.set(myMotionState.startWorldTrans);
colObj.setWorldTransform(myMotionState.graphicsWorldTrans);
colObj.setInterpolationWorldTransform(myMotionState.startWorldTrans);
colObj.activate();
}
// removed cached contact points
dynamicsWorld
.getBroadphase()
.getOverlappingPairCache()
.cleanProxyFromPairs(colObj.getBroadphaseHandle(),
getDynamicsWorld().getDispatcher());
body = RigidBody.upcast(colObj);
if (body != null && !body.isStaticObject()) {
RigidBody.upcast(colObj).setLinearVelocity(
new Vector3f(0f, 0f, 0f));
RigidBody.upcast(colObj).setAngularVelocity(
new Vector3f(0f, 0f, 0f));
}
}
}
}
public void stepLeft() {
azi -= STEPSIZE;
if (azi < 0) {
azi += 360;
}
updateCamera();
}
public void stepRight() {
azi += STEPSIZE;
if (azi >= 360) {
azi -= 360;
}
updateCamera();
}
public void stepUp() {
ele += STEPSIZE;
if (ele >= 360) {
ele -= 360;
}
updateCamera();
}
public void stepDown() {
ele -= STEPSIZE;
if (ele < 0) {
ele += 360;
}
updateCamera();
}
public void stepHorizontalBySteps(double stepSize) {
azi -= (int) stepSize;
if (azi < 0) {
azi += 360;
}
updateCamera();
}
public void stepVerticalBySteps(double stepSize) {
ele += (int) stepSize;
if (ele >= 360) {
ele -= 360;
}
updateCamera();
}
public void zoomIn() {
cameraDistance -= 5f;
updateCamera();
if (cameraDistance < 0.1f) {
cameraDistance = 0.1f;
}
}
public void zoomOut() {
cameraDistance += 5f;
updateCamera();
}
public void zoomBySteps(double stepsize) {
cameraDistance -= (int) stepsize;
updateCamera();
if (cameraDistance < 0.1f) {
cameraDistance = 0.1f;
}
}
/*
* Resets the camera's position.
*/
public static void resetCamera() {
cameraDistance = STANDARD_CAMERA_DISTANCE;
azi = STANDARD_CAMERA_AZI;
ele = STANDARD_CAMERA_ELE;
cameraPosition = new Vector3f(0, 0, 0);
updateCamera();
}
/*
* public void setCameraUp(Vector3f camUp) { cameraUp.set(camUp); }
*
* public void setCameraForwardAxis(int axis) { forwardAxis = axis; }
*/
public Vector3f getCameraPosition() {
return cameraPosition;
}
public Vector3f getCameraTargetPosition() {
return cameraTargetPosition;
}
public static void setCameraTargetPosition(Vector3f target) {
followAgent = false;
agentToFollow = null;
cameraTargetPosition = target;
}
public static void setCameraToFollowAgentPosition(AbstractAgent3D<?> agent) {
followAgent = true;
agentToFollow = agent;
cameraTargetPosition = agent.getPosition();
}
private void keyboardCallback(char key) {
switch (key) {
case 'a':
stepLeft();
break;
case 'd':
stepRight();
break;
case 'w':
stepUp();
break;
case 's':
stepDown();
break;
case 'y':
zoomIn();
break;
case 'x':
zoomOut();
break;
case ' ':
resetCamera();
break;
case 'b':
saveScreenshot();
break;
default:
break;
}
}
/**
* Returns a BufferedImage of the current scene. Use with care (slows down
* the simulation!).
*
* @return BufferedImage of the current scene.
*/
public static BufferedImage getBufferedImage() {
int frameWidth = Display.getDisplayMode().getWidth();
int frameHeight = Display.getDisplayMode().getHeight();
BufferedImage screenshot = null;
// allocate space for RBG pixels
ByteBuffer fb = ByteBuffer.allocateDirect(frameWidth * frameHeight * 3);
int[] pixels = new int[frameWidth * frameHeight];
int bindex;
// grab a copy of the current frame contents as RGB
/*
GL11.glReadPixels(0, 0, frameWidth, frameHeight, GL11.GL_RGB,
GL11.GL_UNSIGNED_BYTE, fb);*/
// GL_BYTE statt GL_UNSIGNED_BYTE, später *2 wg. Bug!
GL11.glReadPixels(0, 0, frameWidth, frameHeight, GL11.GL_RGB,
GL11.GL_BYTE, fb);
// convert RGB data in ByteBuffer to integer array
for (int i = 0; i < pixels.length; i++) {
bindex = i * 3;
// *2, wg. Bug
pixels[i] = ((fb.get(bindex + 0)*2 << 16)) + ((fb.get(bindex + 1)*2 << 8))
+ ((fb.get(bindex + 2)*2 << 0));
}
// Create a BufferedImage with the RGB pixels
try {
screenshot = new BufferedImage(frameWidth, frameHeight,
BufferedImage.TYPE_INT_RGB);
screenshot.setRGB(0, 0, frameWidth, frameHeight, pixels, 0,
frameWidth);
// * Flip Image Y Axis *
AffineTransform tx = AffineTransform.getScaleInstance(1, -1);
tx.translate(0, -screenshot.getHeight(null));
AffineTransformOp op = new AffineTransformOp(tx,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
screenshot = op.filter(screenshot, null);
} catch (Exception e) {
System.out.println("ScreenShot exception: " + e);
}
return screenshot;
}
/*
* Take a screenshot and save it as png.
*/
public static void saveScreenshot() {
try {
Calendar c = new GregorianCalendar();
String path = pfad + File.separator;
File file = new File(path + "VideoPlugin3D-Screenshot-"
+ c.get(Calendar.YEAR) + "-"
+ (c.get(Calendar.MONTH)+1) + "-"
+ c.get(Calendar.DAY_OF_MONTH) + "-"
+ c.get(Calendar.HOUR_OF_DAY) + "-"
+ c.get(Calendar.MINUTE) + "-"
+ c.get(Calendar.SECOND)
+ ".png");
ImageIO.write(getBufferedImage(), "png", file);
System.out.print("\nScreenshot saved to ");
System.out.println(file.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public List<String> getSupportedPlugins() {
return null;
}
@Override
public void onSimulationResumed(AbstractEnvironment3D<AbstractAgent3D<?>> env, Wink resumeTime,
ParCollection params) {
}
}