OSDN Git Service

189be62f18ad80da7aae57f0ebdd4ee13674c9e7
[mikumikustudio/MikuMikuStudio.git] / src / jmetest / terrain / TestIsland.java
1 /*
2  * Copyright (c) 2003-2009 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 
17  *   may be used to endorse or promote products derived from this software 
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 package jmetest.terrain;
34
35 import java.nio.FloatBuffer;
36
37 import jmetest.effects.water.TestQuadWater;
38
39 import com.jme.app.SimplePassGame;
40 import com.jme.image.Texture;
41 import com.jme.math.Plane;
42 import com.jme.math.Vector3f;
43 import com.jme.renderer.ColorRGBA;
44 import com.jme.renderer.pass.RenderPass;
45 import com.jme.scene.PassNode;
46 import com.jme.scene.PassNodeState;
47 import com.jme.scene.Skybox;
48 import com.jme.scene.Spatial;
49 import com.jme.scene.Spatial.TextureCombineMode;
50 import com.jme.scene.shape.Quad;
51 import com.jme.scene.state.BlendState;
52 import com.jme.scene.state.CullState;
53 import com.jme.scene.state.FogState;
54 import com.jme.scene.state.TextureState;
55 import com.jme.scene.state.ZBufferState;
56 import com.jme.util.TextureManager;
57 import com.jmex.effects.water.WaterRenderPass;
58 import com.jmex.terrain.TerrainPage;
59 import com.jmex.terrain.util.RawHeightMap;
60
61 /**
62  * TestIsland shows multipass texturesplatting(6 passes) through usage
63  * of the PassNode together with jME's water effect and a skybox. A simpler
64  * version of the terrain without splatting is created and used for rendering
65  * into the reflection/refraction of the water.
66  * 
67  * @author Heightmap and textures originally from Jadestone(but heavily
68  *         downsampled)
69  * @author Rikard Herlitz (MrCoder)
70  */
71
72 public class TestIsland extends SimplePassGame {
73
74     private WaterRenderPass waterEffectRenderPass;
75     private Quad waterQuad;
76     private Spatial splatTerrain;
77     private Spatial reflectionTerrain;
78     private Skybox skybox;
79
80     private float farPlane = 10000.0f;
81     private float textureScale = 0.07f;
82     private float globalSplatScale = 90.0f;
83
84     public static void main(String[] args) {
85         TestIsland app = new TestIsland();
86         app.setConfigShowMode(ConfigShowMode.AlwaysShow);
87         app.start();
88     }
89
90     protected void simpleUpdate() {
91         skybox.getLocalTranslation().set(cam.getLocation());
92         skybox.updateGeometricState(0.0f, true);
93
94         Vector3f transVec = new Vector3f(cam.getLocation().x,
95                 waterEffectRenderPass.getWaterHeight(), cam.getLocation().z);
96         setTextureCoords(0, transVec.x, -transVec.z, textureScale);
97         setVertexCoords(transVec.x, transVec.y, transVec.z);
98     }
99
100     protected void simpleInitGame() {
101         display.setTitle("Test Island");
102
103         setupEnvironment();
104
105         createTerrain();
106         createReflectionTerrain();
107
108         buildSkyBox();
109
110         rootNode.attachChild(skybox);
111         rootNode.attachChild(splatTerrain);
112
113         waterEffectRenderPass = new WaterRenderPass(cam, 6, false, true);
114         waterEffectRenderPass.setWaterPlane(new Plane(new Vector3f(0.0f, 1.0f,
115                 0.0f), 0.0f));
116         waterEffectRenderPass.setClipBias(-1.0f);
117         waterEffectRenderPass.setReflectionThrottle(0.0f);
118         waterEffectRenderPass.setRefractionThrottle(0.0f);
119
120         waterQuad = new Quad("waterQuad", 1, 1);
121         FloatBuffer normBuf = waterQuad.getNormalBuffer();
122         normBuf.clear();
123         normBuf.put(0).put(1).put(0);
124         normBuf.put(0).put(1).put(0);
125         normBuf.put(0).put(1).put(0);
126         normBuf.put(0).put(1).put(0);
127
128         waterEffectRenderPass.setWaterEffectOnSpatial(waterQuad);
129         rootNode.attachChild(waterQuad);
130
131         waterEffectRenderPass.setReflectedScene(skybox);
132         waterEffectRenderPass.addReflectedScene(reflectionTerrain);
133         waterEffectRenderPass.setSkybox(skybox);
134         pManager.add(waterEffectRenderPass);
135
136         RenderPass rootPass = new RenderPass();
137         rootPass.add(rootNode);
138         pManager.add(rootPass);
139
140         // BloomRenderPass bloomRenderPass = new BloomRenderPass(cam, 4);
141         // if (!bloomRenderPass.isSupported()) {
142         // Text t = new Text("Text", "GLSL Not supported on this computer.");
143         // t.setRenderQueueMode(Renderer.QUEUE_ORTHO);
144         // t.setLightCombineMode(Spatial.LightCombineMode.Off);
145         // t.setLocalTranslation(new Vector3f(0, 20, 0));
146         // fpsNode.attachChild(t);
147         // } else {
148         // bloomRenderPass.setExposurePow(2.0f);
149         // bloomRenderPass.setBlurIntensityMultiplier(0.5f);
150         //            
151         // bloomRenderPass.add(rootNode);
152         // bloomRenderPass.setUseCurrentScene(true);
153         // pManager.add(bloomRenderPass);
154         // }
155
156         RenderPass statPass = new RenderPass();
157         statPass.add(statNode);
158         pManager.add(statPass);
159
160         rootNode.setCullHint(Spatial.CullHint.Never);
161         rootNode.setCullHint(Spatial.CullHint.Never);
162     }
163
164     private void createTerrain() {
165         RawHeightMap heightMap = new RawHeightMap(TestIsland.class
166                 .getClassLoader().getResource(
167                         "jmetest/data/texture/terrain/heights.raw"),
168                 129, RawHeightMap.FORMAT_16BITLE, false);
169
170         Vector3f terrainScale = new Vector3f(5, 0.003f, 6);
171         heightMap.setHeightScale(0.001f);
172         TerrainPage page = new TerrainPage("Terrain", 33, heightMap.getSize(),
173                 terrainScale, heightMap.getHeightMap());
174         page.getLocalTranslation().set(0, -9.5f, 0);
175         page.setDetailTexture(1, 1);
176
177         // create some interesting texturestates for splatting
178         TextureState ts1 = createSplatTextureState(
179                 "jmetest/data/texture/terrain/baserock.jpg", null);
180
181         TextureState ts2 = createSplatTextureState(
182                 "jmetest/data/texture/terrain/darkrock.jpg",
183                 "jmetest/data/texture/terrain/darkrockalpha.png");
184
185         TextureState ts3 = createSplatTextureState(
186                 "jmetest/data/texture/terrain/deadgrass.jpg",
187                 "jmetest/data/texture/terrain/deadalpha.png");
188
189         TextureState ts4 = createSplatTextureState(
190                 "jmetest/data/texture/terrain/nicegrass.jpg",
191                 "jmetest/data/texture/terrain/grassalpha.png");
192
193         TextureState ts5 = createSplatTextureState(
194                 "jmetest/data/texture/terrain/road.jpg",
195                 "jmetest/data/texture/terrain/roadalpha.png");
196
197         TextureState ts6 = createLightmapTextureState("jmetest/data/texture/terrain/lightmap.jpg");
198
199         // alpha used for blending the passnodestates together
200         BlendState as = display.getRenderer().createBlendState();
201         as.setBlendEnabled(true);
202         as.setSourceFunction(BlendState.SourceFunction.SourceAlpha);
203         as.setDestinationFunction(BlendState.DestinationFunction.OneMinusSourceAlpha);
204         as.setTestEnabled(true);
205         as.setTestFunction(BlendState.TestFunction.GreaterThan);
206         as.setEnabled(true);
207
208         // alpha used for blending the lightmap
209         BlendState as2 = display.getRenderer().createBlendState();
210         as2.setBlendEnabled(true);
211         as2.setSourceFunction(BlendState.SourceFunction.DestinationColor);
212         as2.setDestinationFunction(BlendState.DestinationFunction.SourceColor);
213         as2.setTestEnabled(true);
214         as2.setTestFunction(BlendState.TestFunction.GreaterThan);
215         as2.setEnabled(true);
216
217         // //////////////////// PASS STUFF START
218         // try out a passnode to use for splatting
219         PassNode splattingPassNode = new PassNode("SplatPassNode");
220         splattingPassNode.attachChild(page);
221
222         PassNodeState passNodeState = new PassNodeState();
223         passNodeState.setPassState(ts1);
224         splattingPassNode.addPass(passNodeState);
225
226         passNodeState = new PassNodeState();
227         passNodeState.setPassState(ts2);
228         passNodeState.setPassState(as);
229         splattingPassNode.addPass(passNodeState);
230
231         passNodeState = new PassNodeState();
232         passNodeState.setPassState(ts3);
233         passNodeState.setPassState(as);
234         splattingPassNode.addPass(passNodeState);
235
236         passNodeState = new PassNodeState();
237         passNodeState.setPassState(ts4);
238         passNodeState.setPassState(as);
239         splattingPassNode.addPass(passNodeState);
240
241         passNodeState = new PassNodeState();
242         passNodeState.setPassState(ts5);
243         passNodeState.setPassState(as);
244         splattingPassNode.addPass(passNodeState);
245
246         passNodeState = new PassNodeState();
247         passNodeState.setPassState(ts6);
248         passNodeState.setPassState(as2);
249         splattingPassNode.addPass(passNodeState);
250         // //////////////////// PASS STUFF END
251
252         // lock some things to increase the performance
253         splattingPassNode.lockBounds();
254         splattingPassNode.lockTransforms();
255         splattingPassNode.lockShadows();
256
257         splatTerrain = splattingPassNode;
258         splatTerrain.setCullHint(Spatial.CullHint.Dynamic);
259
260     }
261
262     private void createReflectionTerrain() {
263         RawHeightMap heightMap = new RawHeightMap(TestIsland.class
264                 .getClassLoader().getResource(
265                         "jmetest/data/texture/terrain/heights.raw"),
266                 129, RawHeightMap.FORMAT_16BITLE, false);
267
268         Vector3f terrainScale = new Vector3f(5, 0.003f, 6);
269         heightMap.setHeightScale(0.001f);
270         TerrainPage page = new TerrainPage("Terrain", 33, heightMap.getSize(),
271                 terrainScale, heightMap.getHeightMap());
272         page.getLocalTranslation().set(0, -9.5f, 0);
273         page.setDetailTexture(1, 1);
274
275         // create some interesting texturestates for splatting
276         TextureState ts1 = display.getRenderer().createTextureState();
277         Texture t0 = TextureManager.loadTexture(TestIsland.class
278                 .getClassLoader().getResource(
279                         "jmetest/data/texture/terrain/terrainlod.jpg"),
280                 Texture.MinificationFilter.Trilinear,
281                 Texture.MagnificationFilter.Bilinear);
282         t0.setWrap(Texture.WrapMode.Repeat);
283         t0.setApply(Texture.ApplyMode.Modulate);
284         t0.setScale(new Vector3f(1.0f, 1.0f, 1.0f));
285         ts1.setTexture(t0, 0);
286
287         // //////////////////// PASS STUFF START
288         // try out a passnode to use for splatting
289         PassNode splattingPassNode = new PassNode("SplatPassNode");
290         splattingPassNode.attachChild(page);
291
292         PassNodeState passNodeState = new PassNodeState();
293         passNodeState.setPassState(ts1);
294         splattingPassNode.addPass(passNodeState);
295         // //////////////////// PASS STUFF END
296
297         // lock some things to increase the performance
298         splattingPassNode.lockBounds();
299         splattingPassNode.lockTransforms();
300         splattingPassNode.lockShadows();
301
302         reflectionTerrain = splattingPassNode;
303
304         initSpatial(reflectionTerrain);
305     }
306
307     private void setupEnvironment() {
308         cam.setFrustumPerspective(45.0f, (float) display.getWidth()
309                 / (float) display.getHeight(), 1f, farPlane);
310         cam.setLocation(new Vector3f(-320, 80, -270));
311         cam.lookAt(new Vector3f(0, 0, 0), Vector3f.UNIT_Y);
312         cam.update();
313
314         CullState cs = display.getRenderer().createCullState();
315         cs.setCullFace(CullState.Face.Back);
316         rootNode.setRenderState(cs);
317
318         lightState.detachAll();
319         rootNode.setLightCombineMode(Spatial.LightCombineMode.Off);
320
321         FogState fogState = display.getRenderer().createFogState();
322         fogState.setDensity(1.0f);
323         fogState.setEnabled(true);
324         fogState.setColor(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
325         fogState.setEnd(farPlane);
326         fogState.setStart(farPlane / 10.0f);
327         fogState.setDensityFunction(FogState.DensityFunction.Linear);
328         fogState.setQuality(FogState.Quality.PerVertex);
329         rootNode.setRenderState(fogState);
330     }
331
332     private void addAlphaSplat(TextureState ts, String alpha) {
333         Texture t1 = TextureManager.loadTexture(TestIsland.class
334                 .getClassLoader().getResource(alpha),
335                 Texture.MinificationFilter.Trilinear,
336                 Texture.MagnificationFilter.Bilinear);
337         t1.setWrap(Texture.WrapMode.Repeat);
338         t1.setApply(Texture.ApplyMode.Combine);
339         t1.setCombineFuncRGB(Texture.CombinerFunctionRGB.Replace);
340         t1.setCombineSrc0RGB(Texture.CombinerSource.Previous);
341         t1.setCombineOp0RGB(Texture.CombinerOperandRGB.SourceColor);
342         t1.setCombineFuncAlpha(Texture.CombinerFunctionAlpha.Replace);
343         ts.setTexture(t1, ts.getNumberOfSetTextures());
344     }
345
346     private TextureState createSplatTextureState(String texture, String alpha) {
347         TextureState ts = display.getRenderer().createTextureState();
348
349         Texture t0 = TextureManager.loadTexture(TestIsland.class
350                 .getClassLoader().getResource(texture),
351                 Texture.MinificationFilter.Trilinear,
352                 Texture.MagnificationFilter.Bilinear);
353         t0.setWrap(Texture.WrapMode.Repeat);
354         t0.setApply(Texture.ApplyMode.Modulate);
355         t0.setScale(new Vector3f(globalSplatScale, globalSplatScale, 1.0f));
356         ts.setTexture(t0, 0);
357
358         if (alpha != null) {
359             addAlphaSplat(ts, alpha);
360         }
361
362         return ts;
363     }
364
365     private TextureState createLightmapTextureState(String texture) {
366         TextureState ts = display.getRenderer().createTextureState();
367
368         Texture t0 = TextureManager.loadTexture(TestIsland.class
369                 .getClassLoader().getResource(texture),
370                 Texture.MinificationFilter.Trilinear,
371                 Texture.MagnificationFilter.Bilinear);
372         t0.setWrap(Texture.WrapMode.Repeat);
373         ts.setTexture(t0, 0);
374
375         return ts;
376     }
377
378     private void buildSkyBox() {
379         skybox = new Skybox("skybox", 10, 10, 10);
380
381         String dir = "jmetest/data/skybox1/";
382         Texture north = TextureManager.loadTexture(TestQuadWater.class
383                 .getClassLoader().getResource(dir + "1.jpg"),
384                 Texture.MinificationFilter.BilinearNearestMipMap,
385                 Texture.MagnificationFilter.Bilinear);
386         Texture south = TextureManager.loadTexture(TestQuadWater.class
387                 .getClassLoader().getResource(dir + "3.jpg"),
388                 Texture.MinificationFilter.BilinearNearestMipMap,
389                 Texture.MagnificationFilter.Bilinear);
390         Texture east = TextureManager.loadTexture(TestQuadWater.class
391                 .getClassLoader().getResource(dir + "2.jpg"),
392                 Texture.MinificationFilter.BilinearNearestMipMap,
393                 Texture.MagnificationFilter.Bilinear);
394         Texture west = TextureManager.loadTexture(TestQuadWater.class
395                 .getClassLoader().getResource(dir + "4.jpg"),
396                 Texture.MinificationFilter.BilinearNearestMipMap,
397                 Texture.MagnificationFilter.Bilinear);
398         Texture up = TextureManager.loadTexture(TestQuadWater.class
399                 .getClassLoader().getResource(dir + "6.jpg"),
400                 Texture.MinificationFilter.BilinearNearestMipMap,
401                 Texture.MagnificationFilter.Bilinear);
402         Texture down = TextureManager.loadTexture(TestQuadWater.class
403                 .getClassLoader().getResource(dir + "5.jpg"),
404                 Texture.MinificationFilter.BilinearNearestMipMap,
405                 Texture.MagnificationFilter.Bilinear);
406
407         skybox.setTexture(Skybox.Face.North, north);
408         skybox.setTexture(Skybox.Face.West, west);
409         skybox.setTexture(Skybox.Face.South, south);
410         skybox.setTexture(Skybox.Face.East, east);
411         skybox.setTexture(Skybox.Face.Up, up);
412         skybox.setTexture(Skybox.Face.Down, down);
413         skybox.preloadTextures();
414
415         CullState cullState = display.getRenderer().createCullState();
416         cullState.setCullFace(CullState.Face.None);
417         cullState.setEnabled(true);
418         skybox.setRenderState(cullState);
419
420         ZBufferState zState = display.getRenderer().createZBufferState();
421         zState.setEnabled(false);
422         skybox.setRenderState(zState);
423
424         FogState fs = display.getRenderer().createFogState();
425         fs.setEnabled(false);
426         skybox.setRenderState(fs);
427
428         skybox.setLightCombineMode(Spatial.LightCombineMode.Off);
429         skybox.setCullHint(Spatial.CullHint.Never);
430         skybox.setTextureCombineMode(TextureCombineMode.Replace);
431         skybox.updateRenderState();
432
433         skybox.lockBounds();
434         skybox.lockMeshes();
435     }
436
437     private void setVertexCoords(float x, float y, float z) {
438         FloatBuffer vertBuf = waterQuad.getVertexBuffer();
439         vertBuf.clear();
440
441         vertBuf.put(x - farPlane).put(y).put(z - farPlane);
442         vertBuf.put(x - farPlane).put(y).put(z + farPlane);
443         vertBuf.put(x + farPlane).put(y).put(z + farPlane);
444         vertBuf.put(x + farPlane).put(y).put(z - farPlane);
445     }
446
447     private void setTextureCoords(int buffer, float x, float y,
448             float textureScale) {
449         x *= textureScale * 0.5f;
450         y *= textureScale * 0.5f;
451         textureScale = farPlane * textureScale;
452         FloatBuffer texBuf;
453         texBuf = waterQuad.getTextureCoords(buffer).coords;
454         texBuf.clear();
455         texBuf.put(x).put(textureScale + y);
456         texBuf.put(x).put(y);
457         texBuf.put(textureScale + x).put(y);
458         texBuf.put(textureScale + x).put(textureScale + y);
459     }
460
461     private void initSpatial(Spatial spatial) {
462         ZBufferState buf = display.getRenderer().createZBufferState();
463         buf.setEnabled(true);
464         buf.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
465         spatial.setRenderState(buf);
466
467         CullState cs = display.getRenderer().createCullState();
468         cs.setCullFace(CullState.Face.Back);
469         spatial.setRenderState(cs);
470
471         spatial.setCullHint(Spatial.CullHint.Never);
472
473         spatial.updateGeometricState(0.0f, true);
474         spatial.updateRenderState();
475     }
476 }