001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/ogcwebservices/wpvs/j3d/TexturedSurface.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     Aennchenstr. 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    package org.deegree.ogcwebservices.wpvs.j3d;
044    
045    import java.awt.image.BufferedImage;
046    import java.io.IOException;
047    import java.net.URL;
048    
049    import javax.media.j3d.Appearance;
050    import javax.media.j3d.Material;
051    import javax.media.j3d.TexCoordGeneration;
052    import javax.media.j3d.Texture;
053    import javax.vecmath.Vector4f;
054    
055    import org.deegree.framework.util.ImageUtils;
056    import org.deegree.model.spatialschema.Position;
057    import org.deegree.model.spatialschema.Ring;
058    import org.deegree.model.spatialschema.Surface;
059    import org.deegree.ogcwebservices.wpvs.configuration.RenderingConfiguration;
060    
061    import com.sun.j3d.utils.geometry.GeometryInfo;
062    import com.sun.j3d.utils.geometry.NormalGenerator;
063    import com.sun.j3d.utils.image.TextureLoader;
064    
065    /**
066     * 
067     * 
068     * 
069     * @version $Revision: 9345 $
070     * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
071     * @author last edited by: $Author: apoth $
072     * 
073     * @version 1.0. $Revision: 9345 $, $Date: 2007-12-27 17:22:25 +0100 (Do, 27 Dez 2007) $
074     * 
075     * @since 2.0
076     */
077    public class TexturedSurface extends ColoredSurface {
078    
079        private Texture texture = null;
080    
081        private BufferedImage textureImg = null;
082    
083        private float[][] textureCoords = null;
084        
085        /**
086         * creates a TexturedSurface from a geometry, color informations and a texture image. Since a
087         * texture image be somehow transparent it is useful to be able to define a surfaces color. This
088         * constructor will use default coordinates to adjust a texture onto a surface.
089         * 
090         * @param objectID
091         *            an Id for this Surface, for example a db primary key
092         * @param parentID
093         *            an Id for the parent of this Surface, for example if this is a wall the parent is
094         *            the building.
095         * @param surface
096         *            the ogc:geometry surface which holds the point references of a polygon, not to be
097         *            confused with a j3d Object which this class represents.
098         * @param red
099         * @param green
100         * @param blue
101         * @param transparency
102         * @param textureImg
103         */
104        public TexturedSurface( String objectID, String parentID, Surface surface, float red,
105                               float green, float blue, float transparency, BufferedImage textureImg ) {
106            super( objectID, parentID, surface, red, green, blue, transparency );
107            this.textureImg = textureImg;
108            createTexture( textureImg );
109            setAppearance( createAppearance() );
110        }
111    
112        /**
113         * creates a TexturedSurface from a geometry, Material and a texture image. Since a texture
114         * image be somehow transparent it is useful to be able to define a surfaces color. This
115         * constructor will use default coordinates to adjust a texture onto a surface.
116         * 
117         * @param objectID
118         *            an Id for this Surface, for example a db primary key
119         * @param parentID
120         *            an Id for the parent of this Surface, for example if this is a wall the parent is
121         *            the building.
122         * @param surface
123         *            the ogc:geometry surface which holds the point references of a polygon, not to be
124         *            confused with a j3d Object which this class represents.
125         * @param material
126         * @param transparency
127         * @param textureImg
128         */
129        public TexturedSurface( String objectID, String parentID, Surface surface, Material material,
130                               float transparency, BufferedImage textureImg ) {
131            super( objectID, parentID, surface, material, transparency );
132            this.textureImg = textureImg;
133            createTexture( textureImg );
134            setAppearance( createAppearance() );
135        }
136    
137        /**
138         * creates a TexturedSurface from a geometry, color informations and a reference to a texture
139         * image. Since a texture image be somehow transparent it is useful to be able to define a
140         * surfaces color. This constructor will use default coordinates to adjust a texture onto a
141         * surface.
142         * 
143         * @param objectID
144         *            an Id for this Surface, for example a db primary key
145         * @param parentID
146         *            an Id for the parent of this Surface, for example if this is a wall the parent is
147         *            the building.
148         * @param surface
149         *            the ogc:geometry surface which holds the point references of a polygon, not to be
150         *            confused with a j3d Object which this class represents.
151         * @param red
152         * @param green
153         * @param blue
154         * @param transparency
155         * @param textureImg
156         * @throws IOException
157         */
158        public TexturedSurface( String objectID, String parentID, Surface surface, float red,
159                               float green, float blue, float transparency, URL textureImg )
160                                throws IOException {
161            super( objectID, parentID, surface, red, green, blue, transparency );
162            this.textureImg = ImageUtils.loadImage( textureImg );
163            createTexture( this.textureImg );
164            setAppearance( createAppearance() );
165        }
166    
167        /**
168         * creates a TexturedSurface from a geometry, Material and a reference to a texture image. Since
169         * a texture image be somehow transparent it is useful to be able to define a surfaces color.
170         * This constructor will use default coordinates to adjust a texture onto a surface.
171         * 
172         * @param objectID
173         *            an Id for this Surface, for example a db primary key
174         * @param parentID
175         *            an Id for the parent of this Surface, for example if this is a wall the parent is
176         *            the building.
177         * @param surface
178         *            the ogc:geometry surface which holds the point references of a polygon, not to be
179         *            confused with a j3d Object which this class represents.
180         * @param material
181         * @param transparency
182         * @param textureImg
183         * @throws IOException
184         */
185        public TexturedSurface( String objectID, String parentID, Surface surface, Material material,
186                               float transparency, URL textureImg ) throws IOException {
187            super( objectID, parentID, surface, material, transparency );
188    
189            this.textureImg = ImageUtils.loadImage( textureImg );
190            createTexture( this.textureImg );
191            setAppearance( createAppearance() );
192        }
193    
194        /**
195         * creates a TexturedSurface from a geometry, color informations and a texture image. Since a
196         * texture image be somehow transparent it is useful to be able to define a surfaces color.
197         * 
198         * @param objectID
199         *            an Id for this Surface, for example a db primary key
200         * @param parentID
201         *            an Id for the parent of this Surface, for example if this is a wall the parent is
202         *            the building.
203         * @param surface
204         *            the ogc:geometry surface which holds the point references of a polygon, not to be
205         *            confused with a j3d Object which this class represents.
206         * @param red
207         * @param green
208         * @param blue
209         * @param transparency
210         * @param textureImg
211         * @param textureCoords
212         */
213        public TexturedSurface( String objectID, String parentID, Surface surface, float red,
214                               float green, float blue, float transparency, BufferedImage textureImg,
215                               float[][] textureCoords ) {
216            super( objectID, parentID, surface, red, green, blue, transparency );
217    
218            this.textureImg = textureImg;
219            this.textureCoords = textureCoords;
220            createTexture( textureImg );
221            setAppearance( createAppearance() );
222    
223        }
224    
225        /**
226         * creates a TexturedSurface from a geometry, Material and a texture image. Since a texture
227         * image be somehow transparent it is useful to be able to define a surfaces color.
228         * 
229         * @param objectID
230         *            an Id for this Surface, for example a db primary key
231         * @param parentID
232         *            an Id for the parent of this Surface, for example if this is a wall the parent is
233         *            the building.
234         * @param surface
235         *            the ogc:geometry surface which holds the point references of a polygon, not to be
236         *            confused with a j3d Object which this class represents.
237         * @param material
238         * @param transparency
239         * @param textureImg
240         * @param textureCoords
241         */
242        public TexturedSurface( String objectID, String parentID, Surface surface, Material material,
243                               float transparency, BufferedImage textureImg, float[][] textureCoords ) {
244            super( objectID, parentID, surface, material, transparency );
245    
246            this.textureImg = textureImg;
247            this.textureCoords = textureCoords;
248            createTexture( textureImg );
249            setAppearance( createAppearance() );
250        }
251    
252        /**
253         * creates a TexturedSurface from a geometry, color informations and a reference to a texture
254         * image. Since a texture image be somehow transparent it is useful to be able to define a
255         * surfaces color.
256         * 
257         * @param objectID
258         *            an Id for this Surface, for example a db primary key
259         * @param parentID
260         *            an Id for the parent of this Surface, for example if this is a wall the parent is
261         *            the building.
262         * @param surface
263         *            the ogc:geometry surface which holds the point references of a polygon, not to be
264         *            confused with a j3d Object which this class represents.
265         * @param red
266         * @param green
267         * @param blue
268         * @param transparency
269         * @param textureImg
270         * @param textureCoords
271         * @throws IOException
272         */
273        public TexturedSurface( String objectID, String parentID, Surface surface, float red,
274                               float green, float blue, float transparency, URL textureImg,
275                               float[][] textureCoords ) throws IOException {
276            super( objectID, parentID, surface, red, green, blue, transparency );
277    
278            this.textureImg = ImageUtils.loadImage( textureImg );
279            this.textureCoords = textureCoords;
280            createTexture( this.textureImg );
281            setAppearance( createAppearance() );
282        }
283    
284        /**
285         * creates a TexturedSurface from a geometry, Material and a reference to a texture image. Since
286         * a texture image be somehow transparent it is useful to be able to define a surfaces color.
287         * 
288         * @param objectID
289         *            an Id for this Surface, for example a db primary key
290         * @param parentID
291         *            an Id for the parent of this Surface, for example if this is a wall the parent is
292         *            the building.
293         * @param surface
294         *            the ogc:geometry surface which holds the point references of a polygon, not to be
295         *            confused with a j3d Object which this class represents.
296         * @param material
297         * @param transparency
298         * @param textureImg
299         * @param textureCoords
300         * @throws IOException
301         */
302        public TexturedSurface( String objectID, String parentID, Surface surface, Material material,
303                               float transparency, URL textureImg, float[][] textureCoords )
304                                throws IOException {
305            super( objectID, parentID, surface, material, transparency );
306            this.textureImg = ImageUtils.loadImage( textureImg );
307            this.textureCoords = textureCoords;
308            createTexture( this.textureImg );
309            setAppearance( createAppearance() );
310        }
311    
312        private void createTexture( BufferedImage textureImg ) {
313            try {
314                texture = new TextureLoader( textureImg ).getTexture();
315                texture.setEnable( true );
316                texture.setCapability( Texture.ALLOW_ENABLE_WRITE );
317            } catch ( Exception e ) {
318                e.printStackTrace();
319            }
320        }
321    
322        /**
323         * @return the texture of this surface.
324         */
325        public BufferedImage getTexture() {
326            return textureImg;
327        }
328    
329        /**
330         * this method must be called before addin the surface to a Group
331         */
332        @Override
333        public void compile() {
334    
335            GeometryInfo geometryInfo = new GeometryInfo( GeometryInfo.POLYGON_ARRAY );
336    
337            Position[] pos = surface.getSurfaceBoundary().getExteriorRing().getPositions();
338            Ring[] innerRings = surface.getSurfaceBoundary().getInteriorRings();
339            //the last point is the same as the first, therefore not needed.
340            int numberOfPointsInSurface = pos.length -1; 
341            int k = 1;
342            int l = 3 * (numberOfPointsInSurface );
343            if ( innerRings != null ) {
344                for ( int i = 0; i < innerRings.length; i++ ) {
345                    k++;
346                    l += ( 3 * innerRings[i].getPositions().length );
347                }
348            }
349    
350            float[] coords = new float[l];
351            int contourCounts[] = { k };
352            int[] stripCounts = new int[k];
353            k = 0;
354            stripCounts[k++] = numberOfPointsInSurface;
355            //System.out.println( "surface length: " + pos.length );
356            int z = 0;
357            for ( int i = 0; i < numberOfPointsInSurface; i++ ) {
358                coords[z++] = (float) pos[i].getX();
359                coords[z++] = (float) pos[i].getY();
360                coords[z++] = (float) pos[i].getZ();
361            }
362    
363            if ( innerRings != null ) {
364                for ( int j = 0; j < innerRings.length; j++ ) {
365                    pos = innerRings[j].getPositions();
366                    stripCounts[k++] = pos.length;
367                    for ( int i = 0; i < pos.length; i++ ) {
368                        coords[z++] = (float) pos[i].getX();
369                        coords[z++] = (float) pos[i].getY();
370                        coords[z++] = (float) pos[i].getZ();
371                    }
372                }
373            }
374    
375            geometryInfo.setCoordinates( coords );
376            geometryInfo.setStripCounts( stripCounts );
377            geometryInfo.setContourCounts( contourCounts );
378    
379            // manually set texture coordinates must be done befor
380            // normals all calculated
381            if ( textureCoords != null ) {
382                geometryInfo.setTextureCoordinateParams( textureCoords.length, 2 );
383                
384                float[] texc = new float[numberOfPointsInSurface*2];
385                for ( int i = 0; i < textureCoords.length ; i++ ) {
386                 for( int newCount = 0; newCount < (numberOfPointsInSurface*2); newCount++ ){
387                        texc[newCount] = textureCoords[i][newCount];
388                    }
389                    geometryInfo.setTextureCoordinates( i, texc );
390                }
391            }
392    
393            NormalGenerator ng = new NormalGenerator();
394            ng.generateNormals( geometryInfo );
395    
396            setGeometry( geometryInfo.getGeometryArray() );
397    
398            setAppearanceOverrideEnable( true );
399        }
400    
401        private Appearance createAppearance() {
402            Appearance ap = getAppearance();
403            if ( texture != null ) {
404                ap.setTexture( texture );
405                ap.setTextureAttributes( RenderingConfiguration.getInstance().getTextureAttributes() );
406    
407                if ( textureCoords == null ) {
408                    // automatic creation of texture coordinates is behavior of
409                    // the appearance
410                    TexCoordGeneration tcg = new TexCoordGeneration(
411                                                                     TexCoordGeneration.OBJECT_LINEAR,
412                                                                     TexCoordGeneration.TEXTURE_COORDINATE_2 );
413                    tcg.setPlaneS( new Vector4f( 1, 1, 0, 0 ) );
414                    tcg.setPlaneT( new Vector4f( 0, 0, 1, 0 ) );
415                    ap.setTexCoordGeneration( tcg );
416                }
417            }
418            return ap;
419        }
420    
421    }
422