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 }