001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/ogcwebservices/wpvs/j3d/OffScreenWPVSRenderer.java $
002    /*----------------------------------------------------------------------------
003     This file is part of deegree, http://deegree.org/
004     Copyright (C) 2001-2009 by:
005     Department of Geography, University of Bonn
006     and
007     lat/lon GmbH
008    
009     This library is free software; you can redistribute it and/or modify it under
010     the terms of the GNU Lesser General Public License as published by the Free
011     Software Foundation; either version 2.1 of the License, or (at your option)
012     any later version.
013     This library is distributed in the hope that it will be useful, but WITHOUT
014     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
015     FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
016     details.
017     You should have received a copy of the GNU Lesser General Public License
018     along with this library; if not, write to the Free Software Foundation, Inc.,
019     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020    
021     Contact information:
022    
023     lat/lon GmbH
024     Aennchenstr. 19, 53177 Bonn
025     Germany
026     http://lat-lon.de/
027    
028     Department of Geography, University of Bonn
029     Prof. Dr. Klaus Greve
030     Postfach 1147, 53001 Bonn
031     Germany
032     http://www.geographie.uni-bonn.de/deegree/
033    
034     e-mail: info@deegree.org
035     ----------------------------------------------------------------------------*/
036    
037    package org.deegree.ogcwebservices.wpvs.j3d;
038    
039    import java.awt.Color;
040    import java.awt.image.BufferedImage;
041    import java.awt.image.RenderedImage;
042    
043    import javax.media.j3d.Appearance;
044    import javax.media.j3d.BranchGroup;
045    import javax.media.j3d.Canvas3D;
046    import javax.media.j3d.ImageComponent;
047    import javax.media.j3d.ImageComponent2D;
048    import javax.media.j3d.Light;
049    import javax.media.j3d.Locale;
050    import javax.media.j3d.Material;
051    import javax.media.j3d.OrderedGroup;
052    import javax.media.j3d.RenderingAttributes;
053    import javax.media.j3d.Transform3D;
054    import javax.media.j3d.TransformGroup;
055    import javax.media.j3d.View;
056    import javax.vecmath.Color3f;
057    import javax.vecmath.Vector3d;
058    
059    import org.deegree.framework.log.ILogger;
060    import org.deegree.framework.log.LoggerFactory;
061    import org.deegree.framework.util.MapUtils;
062    import org.deegree.i18n.Messages;
063    
064    import com.sun.j3d.utils.geometry.Sphere;
065    import com.sun.j3d.utils.universe.MultiTransformGroup;
066    import com.sun.j3d.utils.universe.SimpleUniverse;
067    import com.sun.j3d.utils.universe.ViewingPlatform;
068    
069    /**
070     * The class provides the capabilitiy for rendering a <code>WPVSScene</code> to an offscreen graphic context that is
071     * represent by a <code>BufferedImage</code>. That is, the returned BufferedImage of this class's renderScene method is
072     * the response Object of a GetView request.
073     * 
074     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
075     * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
076     * 
077     * @version $Revision: 19665 $ $Date: 2009-09-16 10:11:29 +0200 (Mi, 16. Sep 2009) $
078     */
079    public class OffScreenWPVSRenderer extends Abstract3DRenderingEngine {
080    
081        private static ILogger LOG = LoggerFactory.getLogger( OffScreenWPVSRenderer.class );
082    
083        private Canvas3D offScreenCanvas3D;
084    
085        private SimpleUniverse universe;
086    
087        private final boolean renderAntialiased;
088    
089        /**
090         * Initializes the render class with a default width and height (800x600) and a nearclipping plane of 2
091         * 
092         * @param canvas
093         *            to render upon
094         * 
095         * @param scene
096         *            to render
097         */
098        public OffScreenWPVSRenderer( Canvas3D canvas, WPVSScene scene ) {
099            this( canvas, 2, scene, 800, 600, true );
100        }
101    
102        /**
103         * Initializes the renderer class with the submitted width and height and a nearclipping plane of 2
104         * 
105         * @param canvas
106         *            to render upon
107         * 
108         * @param scene
109         *            to render
110         * @param width
111         *            of the resulting image
112         * @param height
113         *            of the resulting image
114         * @param antialiased
115         *            true if the scene should be rendered antialiased
116         */
117        public OffScreenWPVSRenderer( Canvas3D canvas, WPVSScene scene, int width, int height, boolean antialiased ) {
118            this( canvas, 2, scene, width, height, antialiased );
119        }
120    
121        /**
122         * Initializes the renderer class with the submitted width and height
123         * 
124         * @param canvas
125         *            to render upon
126         * @param nearClippingPlane
127         *            of the scene's viewport.
128         * 
129         * @param scene
130         *            to render
131         * @param width
132         *            of the resulting image
133         * @param height
134         *            of the resulting image
135         * @param antialiased
136         *            true if the scene should be rendered antialiased
137         */
138        public OffScreenWPVSRenderer( Canvas3D canvas, double nearClippingPlane, WPVSScene scene, int width, int height,
139                                      boolean antialiased ) {
140            super( scene, nearClippingPlane );
141    
142            // offScreenCanvas3D = WPVSConfiguration.getCanvas3D();
143            offScreenCanvas3D = canvas;
144            if ( offScreenCanvas3D == null ) {
145                throw new IllegalArgumentException( "Did not retrieve a Canvas3D from the Configuraion, cannot proceed" );
146            }
147            offScreenCanvas3D.getScreen3D().setPhysicalScreenHeight( MapUtils.DEFAULT_PIXEL_SIZE * height );
148            offScreenCanvas3D.getScreen3D().setPhysicalScreenWidth( MapUtils.DEFAULT_PIXEL_SIZE * width );
149    
150            offScreenCanvas3D.getScreen3D().setSize( width, height );
151            BufferedImage renderedImage = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );
152    
153            ImageComponent2D imageComponent = new ImageComponent2D( ImageComponent.FORMAT_RGB, renderedImage );
154            // new ImageComponent2D( ImageComponent.FORMAT_RGB, renderedImage );
155    
156            imageComponent.setCapability( ImageComponent.ALLOW_IMAGE_READ );
157    
158            offScreenCanvas3D.setOffScreenBuffer( imageComponent );
159    
160            universe = new SimpleUniverse( offScreenCanvas3D );
161    
162            OrderedGroup theScene = scene.getScene();
163            BranchGroup sceneGroup = new BranchGroup();
164            sceneGroup.addChild( theScene );
165    
166            addBackground( scene.getViewPoint(), sceneGroup, scene.getBackground() );
167    
168            sceneGroup.compile();
169            BranchGroup lightGroup = new BranchGroup();
170            Light[] lights = scene.getLights();
171            for ( Light light : lights ) {
172                lightGroup.addChild( light.cloneTree() );
173            }
174            lightGroup.compile();
175    
176            universe.addBranchGraph( sceneGroup );
177            universe.addBranchGraph( lightGroup );
178            this.renderAntialiased = antialiased;
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( renderAntialiased );
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    }