001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/ogcwebservices/wpvs/j3d/OffScreenWPVSRenderer.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2006 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstraße 19
030     53177 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041     
042     ---------------------------------------------------------------------------*/
043    
044    package org.deegree.ogcwebservices.wpvs.j3d;
045    
046    import java.awt.Color;
047    import java.awt.image.BufferedImage;
048    import java.awt.image.RenderedImage;
049    
050    import javax.media.j3d.Appearance;
051    import javax.media.j3d.BranchGroup;
052    import javax.media.j3d.Canvas3D;
053    import javax.media.j3d.ImageComponent;
054    import javax.media.j3d.ImageComponent2D;
055    import javax.media.j3d.Light;
056    import javax.media.j3d.Locale;
057    import javax.media.j3d.Material;
058    import javax.media.j3d.RenderingAttributes;
059    import javax.media.j3d.Transform3D;
060    import javax.media.j3d.TransformGroup;
061    import javax.media.j3d.View;
062    import javax.vecmath.Color3f;
063    import javax.vecmath.Vector3d;
064    
065    import org.deegree.framework.log.ILogger;
066    import org.deegree.framework.log.LoggerFactory;
067    import org.deegree.framework.util.MapUtils;
068    import org.deegree.i18n.Messages;
069    
070    import com.sun.j3d.utils.geometry.Sphere;
071    import com.sun.j3d.utils.universe.MultiTransformGroup;
072    import com.sun.j3d.utils.universe.SimpleUniverse;
073    import com.sun.j3d.utils.universe.ViewingPlatform;
074    
075    /**
076     * The class provides the capabilitiy for rendering a <code>WPVSScene</code> to an offscreen graphic context that is
077     * represent by a <code>BufferedImage</code>. That is, the returned BufferedImage of this class's renderScene method
078     * is the response Object of a GetView request.
079     * 
080     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
081     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
082     * 
083     * @version $Revision: 7957 $ $Date: 2007-08-09 11:59:39 +0200 (Do, 09 Aug 2007) $
084     */
085    public class OffScreenWPVSRenderer extends Abstract3DRenderingEngine {
086    
087        private static ILogger LOG = LoggerFactory.getLogger( OffScreenWPVSRenderer.class );
088    
089        private int width = 800;
090    
091        private int height = 600;
092    
093        private Canvas3D offScreenCanvas3D;
094    
095        private SimpleUniverse universe;
096    
097        /**
098         * Initialzies the render class with a default width and height (800x600) and a nearclipping plane of 2
099         * 
100         * @param scene
101         *            to render
102         */
103        public OffScreenWPVSRenderer( WPVSScene scene ) {
104            this( 2, scene, 800, 600 );
105        }
106    
107        /**
108         * Initialzies the renderer class with the submitted width and height and a nearclipping plane of 2
109         * 
110         * @param scene
111         *            to render
112         * @param width
113         *            of the resulting image
114         * @param height
115         *            of the resulting image
116         */
117        public OffScreenWPVSRenderer( WPVSScene scene, int width, int height ) {
118            this( 2, scene, width, height );
119        }
120    
121        /**
122         * Initialzies the renderer class with the submitted width and height
123         * @param nearClippingPlane of the scene's viewport.
124         * @param scene
125         *            to render
126         * @param width
127         *            of the resulting image
128         * @param height
129         *            of the resulting image
130         */
131        public OffScreenWPVSRenderer( double nearClippingPlane, WPVSScene scene, int width, int height ) {
132            super( scene, nearClippingPlane );
133            this.width = width;
134            this.height = height;
135    
136            offScreenCanvas3D = createOffscreenCanvas3D();
137            universe = new SimpleUniverse( offScreenCanvas3D );
138    
139            BranchGroup sceneGroup = scene.getScene();
140    
141            addBackground( scene.getViewPoint(), sceneGroup, scene.getBackground() );
142    
143            sceneGroup.compile();
144            BranchGroup lightGroup = new BranchGroup();
145            Light[] lights = scene.getLights();
146            for ( Light light : lights ) {
147                lightGroup.addChild( light.cloneTree() );
148            }
149            lightGroup.compile();
150    
151            universe.addBranchGraph( sceneGroup );
152            universe.addBranchGraph( lightGroup );
153        }
154    
155        /**
156         * @param scene
157         *            the Scene to render
158         */
159        public void setScene( WPVSScene scene ) {
160            this.scene = scene;
161        }
162    
163        /**
164         * Renders the scene to a <code>BufferedImage</code>. This Method uses the viewmatrix of the the ViewPoint class,
165         * which the defines the necessary viewing rotations and translations for the j3d scene.
166         * 
167         * @return a <code>BufferedImage</code> where the scene has been rendered to
168         */
169        public BufferedImage renderScene() {
170    
171            // setting up the transformation of the viewingplatform according to the requested
172            // (calculated) values.
173            ViewingPlatform vp = universe.getViewingPlatform();
174            View view = universe.getViewer().getView();
175    
176            // view parameters
177            view.setBackClipDistance( farClippingPlane );
178            view.setFrontClipDistance( nearClippingPlane );
179            view.setWindowEyepointPolicy( View.RELATIVE_TO_FIELD_OF_VIEW );
180            view.setFieldOfView( scene.getViewPoint().getAngleOfView() );
181            view.setSceneAntialiasingEnable( true );
182            //view.setTransparencySortingPolicy( View.TRANSPARENCY_SORT_GEOMETRY );
183            //view.setDepthBufferFreezeTransparent( false );
184    
185            MultiTransformGroup mtg = vp.getMultiTransformGroup();
186            int transforms = mtg.getNumTransforms();
187            TransformGroup transGroup = null;
188            // if one or more transformgroups are present take the first one will be set to the
189            // viewmatrix of the ViewPoint
190            if ( transforms > 0 ) {
191                transGroup = mtg.getTransformGroup( 0 );
192            }
193            if ( transGroup == null ) {
194                LOG.logError( Messages.getMessage( "WPVS_NO_TRANSFORMS_ERROR" ) );
195                return null;
196            }
197            Transform3D viewMatrix = scene.getViewPoint().getViewMatrix();
198            transGroup.setTransform( viewMatrix );
199    
200            // draw the poi as a sphere if the Debug level is on.
201            BranchGroup sphere = new BranchGroup();
202            sphere.setCapability( BranchGroup.ALLOW_DETACH );
203            if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
204                Appearance app = new Appearance();
205                RenderingAttributes ra = new RenderingAttributes();
206                ra.setDepthBufferEnable( true );
207                app.setRenderingAttributes( ra );
208                Material material = new Material();
209                material.setAmbientColor( new Color3f( Color.WHITE ) );
210                material.setDiffuseColor( new Color3f( Color.WHITE ) );
211                app.setMaterial( material );
212                Sphere s = new Sphere( 20, app );
213                Transform3D t3d = new Transform3D();
214                t3d.setTranslation( new Vector3d( scene.getViewPoint().getPointOfInterest() ) );
215                TransformGroup tg = new TransformGroup();
216                tg.setTransform( t3d );
217                tg.addChild( s );
218                sphere.addChild( tg );
219                universe.addBranchGraph( sphere );
220            }
221    
222            // Finally draw the scene
223            view.startView();
224            offScreenCanvas3D.renderOffScreenBuffer();
225            offScreenCanvas3D.waitForOffScreenRendering();
226            view.stopView();
227    
228            // removing the sphere out of the universe
229            if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
230                Locale l = universe.getLocale();
231                l.removeBranchGraph( sphere );
232            }
233    
234            ImageComponent2D imageComponent = offScreenCanvas3D.getOffScreenBuffer();
235            if ( imageComponent == null ) {
236                LOG.logError( Messages.getMessage( "WPVS_NO_IMAGE_COMPONENT_ERROR" ) );
237                return null;
238            }
239    //        BufferedImage img = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );
240    //        Graphics2D g2d = (Graphics2D) img.getGraphics();
241    //        g2d.drawImage( imageComponent.getImage(), new AffineTransformOp( AffineTransform.getScaleInstance( 0.5, 0.5 ),
242    //                                                                         AffineTransformOp.TYPE_BICUBIC ), 0, 0 );
243            // and cleaning the universe and all of its used memory.
244            universe.cleanup();
245            return imageComponent.getImage();
246        }
247    
248        /**
249         * creates and returns a canvas for offscreen rendering
250         * 
251         * @return a offscreen Canvas3D on which the the scene will be rendered.
252         */
253        protected Canvas3D createOffscreenCanvas3D() {
254            Canvas3D offScreenCanvas3D = createCanvas( true );
255    
256            offScreenCanvas3D.getScreen3D().setPhysicalScreenHeight( MapUtils.DEFAULT_PIXEL_SIZE * height );
257            offScreenCanvas3D.getScreen3D().setPhysicalScreenWidth( MapUtils.DEFAULT_PIXEL_SIZE * width);
258            
259            
260            offScreenCanvas3D.getScreen3D().setSize( width, height );
261            BufferedImage renderedImage = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );
262    
263            ImageComponent2D imageComponent = new ImageComponent2D( ImageComponent.FORMAT_RGB, renderedImage );
264            // new ImageComponent2D( ImageComponent.FORMAT_RGB, renderedImage );
265    
266            imageComponent.setCapability( ImageComponent.ALLOW_IMAGE_READ );
267    
268            offScreenCanvas3D.setOffScreenBuffer( imageComponent );
269    
270            return offScreenCanvas3D;
271        }
272    
273        /**
274         * Called to render the scene into the offscreen Canvas3D
275         * 
276         * @param offScreenCanvas3D
277         *            to be rendered into
278         * @return a buffered image as a result of the Rendering.
279         */
280        protected RenderedImage getImage( Canvas3D offScreenCanvas3D ) {
281    
282            offScreenCanvas3D.renderOffScreenBuffer();
283            offScreenCanvas3D.waitForOffScreenRendering();
284    
285            ImageComponent2D imageComponent = offScreenCanvas3D.getOffScreenBuffer();
286    
287            return imageComponent.getImage();
288        }
289    }