001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wpvs/j3d/OffScreenWPVSRenderer.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 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.OrderedGroup;
059    import javax.media.j3d.RenderingAttributes;
060    import javax.media.j3d.Transform3D;
061    import javax.media.j3d.TransformGroup;
062    import javax.media.j3d.View;
063    import javax.vecmath.Color3f;
064    import javax.vecmath.Vector3d;
065    
066    import org.deegree.framework.log.ILogger;
067    import org.deegree.framework.log.LoggerFactory;
068    import org.deegree.framework.util.MapUtils;
069    import org.deegree.i18n.Messages;
070    
071    import com.sun.j3d.utils.geometry.Sphere;
072    import com.sun.j3d.utils.universe.MultiTransformGroup;
073    import com.sun.j3d.utils.universe.SimpleUniverse;
074    import com.sun.j3d.utils.universe.ViewingPlatform;
075    
076    /**
077     * The class provides the capabilitiy for rendering a <code>WPVSScene</code> to an offscreen graphic context that is
078     * represent by a <code>BufferedImage</code>. That is, the returned BufferedImage of this class's renderScene method
079     * is the response Object of a GetView request.
080     * 
081     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
082     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
083     * 
084     * @version $Revision: 9345 $ $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $
085     */
086    public class OffScreenWPVSRenderer extends Abstract3DRenderingEngine {
087    
088        private static ILogger LOG = LoggerFactory.getLogger( OffScreenWPVSRenderer.class );
089    
090        private Canvas3D offScreenCanvas3D;
091    
092        private SimpleUniverse universe;
093    
094        /**
095         * Initialzies the render class with a default width and height (800x600) and a nearclipping plane of 2
096         * 
097         * @param canvas
098         *            to render upon
099         * 
100         * @param scene
101         *            to render
102         */
103        public OffScreenWPVSRenderer( Canvas3D canvas, WPVSScene scene ) {
104            this( canvas, 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 canvas
111         *            to render upon
112         * 
113         * @param scene
114         *            to render
115         * @param width
116         *            of the resulting image
117         * @param height
118         *            of the resulting image
119         */
120        public OffScreenWPVSRenderer( Canvas3D canvas, WPVSScene scene, int width, int height ) {
121            this( canvas, 2, scene, width, height );
122        }
123    
124        /**
125         * Initialzies the renderer class with the submitted width and height
126         * 
127         * @param canvas
128         *            to render upon
129         * @param nearClippingPlane
130         *            of the scene's viewport.
131         * 
132         * @param scene
133         *            to render
134         * @param width
135         *            of the resulting image
136         * @param height
137         *            of the resulting image
138         */
139        public OffScreenWPVSRenderer( Canvas3D canvas, double nearClippingPlane, WPVSScene scene, int width, int height ) {
140            super( scene, nearClippingPlane );
141    
142            // offScreenCanvas3D = WPVSConfiguration.getCanvas3D();
143            offScreenCanvas3D = canvas;
144            if ( offScreenCanvas3D == null ) {
145                LOG.logError( "Did not retrieve a Canvas3D from the Configuraion, cannot proceed" );
146                return;
147            }
148            offScreenCanvas3D.getScreen3D().setPhysicalScreenHeight( MapUtils.DEFAULT_PIXEL_SIZE * height );
149            offScreenCanvas3D.getScreen3D().setPhysicalScreenWidth( MapUtils.DEFAULT_PIXEL_SIZE * width );
150    
151            offScreenCanvas3D.getScreen3D().setSize( width, height );
152            BufferedImage renderedImage = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );
153    
154            ImageComponent2D imageComponent = new ImageComponent2D( ImageComponent.FORMAT_RGB, renderedImage );
155            // new ImageComponent2D( ImageComponent.FORMAT_RGB, renderedImage );
156    
157            imageComponent.setCapability( ImageComponent.ALLOW_IMAGE_READ );
158    
159            offScreenCanvas3D.setOffScreenBuffer( imageComponent );
160    
161            universe = new SimpleUniverse( offScreenCanvas3D );
162    
163            OrderedGroup theScene = scene.getScene();
164            BranchGroup sceneGroup = new BranchGroup();
165            sceneGroup.addChild( theScene );
166    
167            addBackground( scene.getViewPoint(), sceneGroup, scene.getBackground() );
168    
169            sceneGroup.compile();
170            BranchGroup lightGroup = new BranchGroup();
171            Light[] lights = scene.getLights();
172            for ( Light light : lights ) {
173                lightGroup.addChild( light.cloneTree() );
174            }
175            lightGroup.compile();
176    
177            universe.addBranchGraph( sceneGroup );
178            universe.addBranchGraph( lightGroup );
179        }
180    
181        /**
182         * @param scene
183         *            the Scene to render
184         */
185        public void setScene( WPVSScene scene ) {
186            this.scene = scene;
187        }
188    
189        /**
190         * Renders the scene to a <code>BufferedImage</code>. This Method uses the viewmatrix of the the ViewPoint class,
191         * which the defines the necessary viewing rotations and translations for the j3d scene.
192         * 
193         * @return a <code>BufferedImage</code> where the scene has been rendered to
194         */
195        public BufferedImage renderScene() {
196    
197            // setting up the transformation of the viewingplatform according to the requested
198            // (calculated) values.
199            ViewingPlatform vp = universe.getViewingPlatform();
200            View view = universe.getViewer().getView();
201    
202            // view parameters
203            view.setBackClipDistance( farClippingPlane );
204            view.setFrontClipDistance( nearClippingPlane );
205            view.setWindowEyepointPolicy( View.RELATIVE_TO_FIELD_OF_VIEW );
206            view.setFieldOfView( scene.getViewPoint().getAngleOfView() );
207            view.setSceneAntialiasingEnable( true );
208            // view.setTransparencySortingPolicy( View.TRANSPARENCY_SORT_GEOMETRY );
209            // view.setDepthBufferFreezeTransparent( false );
210    
211            MultiTransformGroup mtg = vp.getMultiTransformGroup();
212            int transforms = mtg.getNumTransforms();
213            TransformGroup transGroup = null;
214            // if one or more transformgroups are present take the first one will be set to the
215            // viewmatrix of the ViewPoint
216            if ( transforms > 0 ) {
217                transGroup = mtg.getTransformGroup( 0 );
218            }
219            if ( transGroup == null ) {
220                LOG.logError( Messages.getMessage( "WPVS_NO_TRANSFORMS_ERROR" ) );
221                return null;
222            }
223            Transform3D viewMatrix = scene.getViewPoint().getViewMatrix();
224            transGroup.setTransform( viewMatrix );
225    
226            // draw the poi as a sphere if the Debug level is on.
227            BranchGroup sphere = new BranchGroup();
228            sphere.setCapability( BranchGroup.ALLOW_DETACH );
229            if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
230                Appearance app = new Appearance();
231                RenderingAttributes ra = new RenderingAttributes();
232                ra.setDepthBufferEnable( true );
233                app.setRenderingAttributes( ra );
234                Material material = new Material();
235                material.setAmbientColor( new Color3f( Color.WHITE ) );
236                material.setDiffuseColor( new Color3f( Color.WHITE ) );
237                app.setMaterial( material );
238                Sphere s = new Sphere( 20, app );
239                Transform3D t3d = new Transform3D();
240                t3d.setTranslation( new Vector3d( scene.getViewPoint().getPointOfInterest() ) );
241                TransformGroup tg = new TransformGroup();
242                tg.setTransform( t3d );
243                tg.addChild( s );
244                sphere.addChild( tg );
245                universe.addBranchGraph( sphere );
246            }
247    
248            // Finally draw the scene
249            view.startView();
250            offScreenCanvas3D.renderOffScreenBuffer();
251            offScreenCanvas3D.waitForOffScreenRendering();
252            view.stopView();
253            // removing the sphere out of the universe
254            if ( LOG.getLevel() == ILogger.LOG_DEBUG ) {
255                Locale l = universe.getLocale();
256                l.removeBranchGraph( sphere );
257            }
258    
259            ImageComponent2D imageComponent = offScreenCanvas3D.getOffScreenBuffer();
260            if ( imageComponent == null ) {
261                LOG.logError( Messages.getMessage( "WPVS_NO_IMAGE_COMPONENT_ERROR" ) );
262                return null;
263            }
264            /**
265             * If using the TestWPVS class option NO_NEW_REQUEST, make sure to comment following two lines as well as the
266             * WPVSConfiguration.releaseCanvas3D( canvas ); line in the DefaultGetViewHandler#handleRequest.
267             */
268            // and cleaning the universe and all of its used memory.
269                    universe.cleanup();
270            view.removeAllCanvas3Ds();
271            return imageComponent.getImage();
272        }
273    
274        /**
275         * Called to render the scene into the offscreen Canvas3D
276         * 
277         * @param offScreenCanvas3D
278         *            to be rendered into
279         * @return a buffered image as a result of the Rendering.
280         */
281        protected RenderedImage getImage( Canvas3D offScreenCanvas3D ) {
282    
283            offScreenCanvas3D.renderOffScreenBuffer();
284            offScreenCanvas3D.waitForOffScreenRendering();
285    
286            ImageComponent2D imageComponent = offScreenCanvas3D.getOffScreenBuffer();
287    
288            return imageComponent.getImage();
289        }
290    }