/* * 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(); } }