1/* 2 * Copyright (c) 2009-2010 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 */ 32package jme3test.animation; 33 34import com.jme3.animation.AnimControl; 35import com.jme3.animation.AnimationFactory; 36import com.jme3.animation.LoopMode; 37import com.jme3.app.SimpleApplication; 38import com.jme3.cinematic.Cinematic; 39import com.jme3.cinematic.MotionPath; 40import com.jme3.cinematic.PlayState; 41import com.jme3.cinematic.events.*; 42import com.jme3.font.BitmapText; 43import com.jme3.input.ChaseCamera; 44import com.jme3.input.controls.ActionListener; 45import com.jme3.input.controls.KeyTrigger; 46import com.jme3.light.DirectionalLight; 47import com.jme3.material.Material; 48import com.jme3.math.ColorRGBA; 49import com.jme3.math.FastMath; 50import com.jme3.math.Quaternion; 51import com.jme3.math.Vector3f; 52import com.jme3.niftygui.NiftyJmeDisplay; 53import com.jme3.post.FilterPostProcessor; 54import com.jme3.post.filters.FadeFilter; 55import com.jme3.renderer.Caps; 56import com.jme3.renderer.queue.RenderQueue.ShadowMode; 57import com.jme3.scene.CameraNode; 58import com.jme3.scene.Geometry; 59import com.jme3.scene.Spatial; 60import com.jme3.scene.shape.Box; 61import com.jme3.shadow.PssmShadowRenderer; 62import de.lessvoid.nifty.Nifty; 63 64public class TestCinematic extends SimpleApplication { 65 66 private Spatial model; 67 private Spatial teapot; 68 private MotionPath path; 69 private MotionTrack cameraMotionTrack; 70 private Cinematic cinematic; 71 private ChaseCamera chaseCam; 72 private FilterPostProcessor fpp; 73 private FadeFilter fade; 74 private float time = 0; 75 76 public static void main(String[] args) { 77 TestCinematic app = new TestCinematic(); 78 app.start(); 79 80 81 82 } 83 84 @Override 85 public void simpleInitApp() { 86 //just some text 87 NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(getAssetManager(), 88 getInputManager(), 89 getAudioRenderer(), 90 getGuiViewPort()); 91 Nifty nifty; 92 nifty = niftyDisplay.getNifty(); 93 nifty.fromXmlWithoutStartScreen("Interface/Nifty/CinematicTest.xml"); 94 getGuiViewPort().addProcessor(niftyDisplay); 95 guiFont = assetManager.loadFont("Interface/Fonts/Default.fnt"); 96 final BitmapText text = new BitmapText(guiFont, false); 97 text.setSize(guiFont.getCharSet().getRenderedSize()); 98 text.setText("Press enter to play/pause cinematic"); 99 text.setLocalTranslation((cam.getWidth() - text.getLineWidth()) / 2, cam.getHeight(), 0); 100 guiNode.attachChild(text); 101 102 103 createScene(); 104 105 cinematic = new Cinematic(rootNode, 20); 106 stateManager.attach(cinematic); 107 108 createCameraMotion(); 109 110 //creating spatial animation for the teapot 111 AnimationFactory factory = new AnimationFactory(20, "teapotAnim"); 112 factory.addTimeTranslation(0, new Vector3f(10, 0, 10)); 113 factory.addTimeTranslation(20, new Vector3f(10, 0, -10)); 114 factory.addTimeScale(10, new Vector3f(4, 4, 4)); 115 factory.addTimeScale(20, new Vector3f(1, 1, 1)); 116 factory.addTimeRotationAngles(20, 0, 4 * FastMath.TWO_PI, 0); 117 AnimControl control = new AnimControl(); 118 control.addAnim(factory.buildAnimation()); 119 teapot.addControl(control); 120 121 //fade in 122 cinematic.addCinematicEvent(0, new FadeEvent(true)); 123 // cinematic.activateCamera(0, "aroundCam"); 124 cinematic.addCinematicEvent(0, new AnimationTrack(teapot, "teapotAnim", LoopMode.DontLoop)); 125 cinematic.addCinematicEvent(0, cameraMotionTrack); 126 cinematic.addCinematicEvent(0, new SoundTrack("Sound/Environment/Nature.ogg", LoopMode.Loop)); 127 cinematic.addCinematicEvent(3f, new SoundTrack("Sound/Effects/kick.wav")); 128 cinematic.addCinematicEvent(3, new SubtitleTrack(nifty, "start", 3, "jMonkey engine really kicks A...")); 129 cinematic.addCinematicEvent(5.1f, new SoundTrack("Sound/Effects/Beep.ogg", 1)); 130 cinematic.addCinematicEvent(2, new AnimationTrack(model, "Walk", LoopMode.Loop)); 131 cinematic.activateCamera(0, "topView"); 132 // cinematic.activateCamera(10, "aroundCam"); 133 134 //fade out 135 cinematic.addCinematicEvent(19, new FadeEvent(false)); 136// cinematic.addCinematicEvent(19, new AbstractCinematicEvent() { 137// 138// @Override 139// public void onPlay() { 140// fade.setDuration(1f / cinematic.getSpeed()); 141// fade.fadeOut(); 142// 143// } 144// 145// @Override 146// public void onUpdate(float tpf) { 147// } 148// 149// @Override 150// public void onStop() { 151// } 152// 153// @Override 154// public void onPause() { 155// } 156// }); 157 158 cinematic.addListener(new CinematicEventListener() { 159 160 public void onPlay(CinematicEvent cinematic) { 161 chaseCam.setEnabled(false); 162 System.out.println("play"); 163 } 164 165 public void onPause(CinematicEvent cinematic) { 166 System.out.println("pause"); 167 } 168 169 public void onStop(CinematicEvent cinematic) { 170 chaseCam.setEnabled(true); 171 fade.setValue(1); 172 System.out.println("stop"); 173 } 174 }); 175 176 //cinematic.setSpeed(2); 177 flyCam.setEnabled(false); 178 chaseCam = new ChaseCamera(cam, model, inputManager); 179 initInputs(); 180 181 } 182 183 private void createCameraMotion() { 184 185 CameraNode camNode = cinematic.bindCamera("topView", cam); 186 camNode.setLocalTranslation(new Vector3f(0, 50, 0)); 187 camNode.lookAt(teapot.getLocalTranslation(), Vector3f.UNIT_Y); 188 189 CameraNode camNode2 = cinematic.bindCamera("aroundCam", cam); 190 path = new MotionPath(); 191 path.setCycle(true); 192 path.addWayPoint(new Vector3f(20, 3, 0)); 193 path.addWayPoint(new Vector3f(0, 3, 20)); 194 path.addWayPoint(new Vector3f(-20, 3, 0)); 195 path.addWayPoint(new Vector3f(0, 3, -20)); 196 path.setCurveTension(0.83f); 197 cameraMotionTrack = new MotionTrack(camNode2, path); 198 cameraMotionTrack.setLoopMode(LoopMode.Loop); 199 cameraMotionTrack.setLookAt(model.getWorldTranslation(), Vector3f.UNIT_Y); 200 cameraMotionTrack.setDirectionType(MotionTrack.Direction.LookAt); 201 202 } 203 204 private void createScene() { 205 206 model = (Spatial) assetManager.loadModel("Models/Oto/Oto.mesh.xml"); 207 model.center(); 208 model.setShadowMode(ShadowMode.CastAndReceive); 209 rootNode.attachChild(model); 210 211 Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); 212 mat.setColor("Color", ColorRGBA.Cyan); 213 214 teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); 215 teapot.setLocalTranslation(10, 0, 10); 216 teapot.setMaterial(mat); 217 teapot.setShadowMode(ShadowMode.CastAndReceive); 218 rootNode.attachChild(teapot); 219 220 Material matSoil = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); 221 matSoil.setBoolean("UseMaterialColors", true); 222 matSoil.setColor("Ambient", ColorRGBA.Gray); 223 matSoil.setColor("Diffuse", ColorRGBA.Green); 224 matSoil.setColor("Specular", ColorRGBA.Black); 225 226 Geometry soil = new Geometry("soil", new Box(new Vector3f(0, -6.0f, 0), 50, 1, 50)); 227 soil.setMaterial(matSoil); 228 soil.setShadowMode(ShadowMode.Receive); 229 rootNode.attachChild(soil); 230 DirectionalLight light = new DirectionalLight(); 231 light.setDirection(new Vector3f(0, -1, -1).normalizeLocal()); 232 light.setColor(ColorRGBA.White.mult(1.5f)); 233 rootNode.addLight(light); 234 235 fpp = new FilterPostProcessor(assetManager); 236 fade = new FadeFilter(); 237 fpp.addFilter(fade); 238 239 if (renderer.getCaps().contains(Caps.GLSL100)) { 240 PssmShadowRenderer pssm = new PssmShadowRenderer(assetManager, 512, 1); 241 pssm.setDirection(new Vector3f(0, -1, -1).normalizeLocal()); 242 pssm.setShadowIntensity(0.4f); 243 viewPort.addProcessor(pssm); 244 viewPort.addProcessor(fpp); 245 } 246 } 247 248 private void initInputs() { 249 inputManager.addMapping("togglePause", new KeyTrigger(keyInput.KEY_RETURN)); 250 inputManager.addMapping("navFwd", new KeyTrigger(keyInput.KEY_RIGHT)); 251 inputManager.addMapping("navBack", new KeyTrigger(keyInput.KEY_LEFT)); 252 ActionListener acl = new ActionListener() { 253 254 public void onAction(String name, boolean keyPressed, float tpf) { 255 if (name.equals("togglePause") && keyPressed) { 256 if (cinematic.getPlayState() == PlayState.Playing) { 257 cinematic.pause(); 258 time = cinematic.getTime(); 259 } else { 260 cinematic.play(); 261 } 262 } 263 264 if (cinematic.getPlayState() != PlayState.Playing) { 265 if (name.equals("navFwd") && keyPressed) { 266 time += 0.25; 267 FastMath.clamp(time, 0, cinematic.getInitialDuration()); 268 cinematic.setTime(time); 269 } 270 if (name.equals("navBack") && keyPressed) { 271 time -= 0.25; 272 FastMath.clamp(time, 0, cinematic.getInitialDuration()); 273 cinematic.setTime(time); 274 } 275 276 } 277 } 278 }; 279 inputManager.addListener(acl, "togglePause", "navFwd", "navBack"); 280 } 281 282 private class FadeEvent extends AbstractCinematicEvent { 283 284 boolean in = true; 285 float value = 0; 286 287 public FadeEvent(boolean in) { 288 super(1); 289 this.in = in; 290 value = in ? 0 : 1; 291 } 292 293 @Override 294 public void onPlay() { 295 296 fade.setDuration(1f / cinematic.getSpeed()); 297 if (in) { 298 fade.fadeIn(); 299 } else { 300 fade.fadeOut(); 301 } 302 fade.setValue(value); 303 304 } 305 306 @Override 307 public void setTime(float time) { 308 super.setTime(time); 309 if (time >= fade.getDuration()) { 310 value = in ? 1 : 0; 311 fade.setValue(value); 312 } else { 313 value = time; 314 if (in) { 315 fade.setValue(time / cinematic.getSpeed()); 316 } else { 317 fade.setValue(1 - time / cinematic.getSpeed()); 318 } 319 } 320 } 321 322 @Override 323 public void onUpdate(float tpf) { 324 } 325 326 @Override 327 public void onStop() { 328 } 329 330 @Override 331 public void onPause() { 332 value = fade.getValue(); 333 fade.pause(); 334 } 335 } 336} 337