/*
* Simbad - Robot Simulator
* Copyright (C) 2004 Louis Hugues
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
-----------------------------------------------------------------------------
* $Author: sioulseuguh $
* $Date: 2005/03/17 17:49:37 $
* $Revision: 1.7 $
* $Source: /cvsroot/simbad/src/simbad/sim/Eye.java,v $
*/
package org.myrobotlab.mapper.sim;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GraphicsConfigTemplate;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import javax.media.j3d.Appearance;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.GraphicsConfigTemplate3D;
import javax.media.j3d.ImageComponent;
import javax.media.j3d.ImageComponent2D;
import javax.media.j3d.Material;
import javax.media.j3d.Node;
import javax.media.j3d.PhysicalBody;
import javax.media.j3d.PhysicalEnvironment;
import javax.media.j3d.RestrictedAccessException;
import javax.media.j3d.View;
import javax.media.j3d.ViewPlatform;
import javax.swing.JPanel;
import javax.vecmath.Color3f;
import com.sun.j3d.utils.geometry.Sphere;
/*
* A visual sensor (and its 3d body) used to emulate monoscopic color camera.
* Vision image (offscreen rendered) is accessible via copyVisionImage().
*
* Implementation:
* Vision is rendered offscreen via a j3d viewPlatform.
* Calling update() method cause update of the associated buffered Image
* The Subclass EyeJPanel is used to display image (in AgentInspector)
*
*/
public class Eye extends SensorDevice {
/*
* a JPanel for displaying the eye image in user interface windows.
*/
public class EyeJPanel extends JPanel {
private static final long serialVersionUID = 1L;
transient BufferedImage bim;
public EyeJPanel() {
Dimension d = new Dimension(imageWidth, imageHeight);
setPreferredSize(d);
setMinimumSize(d);
// allocates a bim for capture
bim = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
}
/* should not be called too often */
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
copyVisionImage(bim);
g.drawImage(bim, 0, 0, null);
}
}
/**
* An off screen Canvas3D for offscreen rendering of a 3D scene - call render
* to ask rendering
*/
private class OffScreenCanvas3D extends Canvas3D {
private static final long serialVersionUID = 1L;
// boolean rendering;
public OffScreenCanvas3D(GraphicsConfiguration gconfig) {
super(gconfig, true);
ImageComponent2D buffer = new ImageComponent2D(ImageComponent.FORMAT_RGB, visionImage);
buffer.setCapability(ImageComponent.ALLOW_IMAGE_READ);
setOffScreenBuffer(buffer);
// rendering = false;
}
@Override
synchronized public void postSwap() {
// copy rendered image
BufferedImage bim = getOffScreenBuffer().getImage();
visionImage.setData(bim.getData());
// rendering = false;
}
synchronized void render() {
try {
renderOffScreenBuffer();
} catch (RestrictedAccessException e) {
// rendering is already in process,but we don't care
// System.err.println("Exception caught"+e.getMessage() );
}
// }
// waitForOffScreenRendering();
}
}
private ViewPlatform viewPlatform;
private View view;
private OffScreenCanvas3D offscreenCanvas3D;
protected int tempRGBABuffer[];
// the rendered offscreen image
transient BufferedImage visionImage;
protected int imageWidth;
protected int imageHeight;
Eye(float radius, int imageWidth, int imageHeight) {
this.imageWidth = imageWidth;
this.imageHeight = imageHeight;
// BufferedImage bim = new BufferedImage(imageWidth, imageHeight,
// BufferedImage.TYPE_INT_RGB);
visionImage = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
tempRGBABuffer = new int[imageWidth * imageHeight];
create3D(radius);
createViewPlatform();
}
/**
* Request to fill a bufferedImage with last capture.
*
* @param bim
* - buffered image to be filled.
*/
final public synchronized void copyVisionImage(BufferedImage bim) {
bim.setData(visionImage.getData());
}
/**
* Request to fill a SensorMatrix with last capture.
*
* @param matrix
* - to be filled
*/
final public synchronized void copyVisionImage(SensorMatrix matrix) {
visionImage.getRGB(0, 0, imageWidth, imageHeight, tempRGBABuffer, 0, imageWidth);
float array[] = matrix.getArray();
for (int i = 0; i < array.length; i++) {
int pix = tempRGBABuffer[i];
int r = (pix >> 16) & 0xff;
int g = (pix >> 8) & 0xff;
int b = (pix) & 0xff;
array[i] = (r + g + b) / (3.0f * 255.0f);
}
}
void create3D(float radius) {
super.create3D(true);
// body
if (radius > 0) {
Color3f color = new Color3f(0.8f, 0.8f, 0.0f);
Appearance appear = new Appearance();
appear.setMaterial(new Material(color, black, color, white, 100.0f));
Node node = new Sphere(radius, appear);
node.setCollidable(false);
node.setPickable(false);
addChild(node);
}
}
/** for allocating a working copy of the vision image */
final public BufferedImage createCompatibleImage() {
return new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
}
/** for allocating a SensorMatrix compabtible with device dimensions */
final public SensorMatrix createCompatibleSensorMatrix() {
return new SensorMatrix(imageWidth, imageHeight);
}
@Override
public JPanel createInspectorPanel() {
return new EyeJPanel();
}
void createViewPlatform() {
// viewplatform
viewPlatform = new ViewPlatform();
viewPlatform.setActivationRadius(100f);
viewPlatform.setViewAttachPolicy(View.NOMINAL_HEAD);
// view
view = new View();
view.setProjectionPolicy(View.PERSPECTIVE_PROJECTION);
view.setViewPolicy(View.SCREEN_VIEW);
view.attachViewPlatform(viewPlatform);
// physical body
PhysicalBody phyBody = new PhysicalBody();
view.setPhysicalBody(phyBody);
// physical environment
PhysicalEnvironment phyEnv = new PhysicalEnvironment();
view.setPhysicalEnvironment(phyEnv);
// ???? pas compris , pour l'antiliasing
GraphicsConfigTemplate3D template = new GraphicsConfigTemplate3D();
template.setSceneAntialiasing(GraphicsConfigTemplate.PREFERRED);
GraphicsConfiguration config = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getBestConfiguration(template);
// antialiasing
view.setSceneAntialiasingEnable(true);
/*
* to add a onscreen canvas canvas3d = new Canvas3D(config);
* view.addCanvas3D(canvas3d);
*/
// attach offscreen canvas to the view
offscreenCanvas3D = new OffScreenCanvas3D(config);
offscreenCanvas3D.getScreen3D().setSize(imageWidth, imageWidth);
offscreenCanvas3D.getScreen3D().setPhysicalScreenHeight(0.5);
offscreenCanvas3D.getScreen3D().setPhysicalScreenWidth(0.5);
view.addCanvas3D(offscreenCanvas3D);
addChild(viewPlatform);
// turn canvas in front of X axis
rotateY(-Math.PI / 2);
}
/**
* Returns the height of captured image.
*
* @return height in pixels
*/
public int getImageHeight() {
return imageHeight;
}
/**
* Returns the width of captured image.
*
* @return width in pixels
*/
public int getImageWidth() {
return imageWidth;
}
/** Called by simulator to render a new vision image */
@Override
protected void update() {
this.offscreenCanvas3D.render();
}
}