Home | History | Annotate | Download | only in animation
      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  */
     32 package jme3test.animation;
     33 
     34 import com.jme3.animation.AnimControl;
     35 import com.jme3.animation.AnimationFactory;
     36 import com.jme3.animation.LoopMode;
     37 import com.jme3.app.SimpleApplication;
     38 import com.jme3.cinematic.Cinematic;
     39 import com.jme3.cinematic.MotionPath;
     40 import com.jme3.cinematic.PlayState;
     41 import com.jme3.cinematic.events.*;
     42 import com.jme3.font.BitmapText;
     43 import com.jme3.input.ChaseCamera;
     44 import com.jme3.input.controls.ActionListener;
     45 import com.jme3.input.controls.KeyTrigger;
     46 import com.jme3.light.DirectionalLight;
     47 import com.jme3.material.Material;
     48 import com.jme3.math.ColorRGBA;
     49 import com.jme3.math.FastMath;
     50 import com.jme3.math.Quaternion;
     51 import com.jme3.math.Vector3f;
     52 import com.jme3.niftygui.NiftyJmeDisplay;
     53 import com.jme3.post.FilterPostProcessor;
     54 import com.jme3.post.filters.FadeFilter;
     55 import com.jme3.renderer.Caps;
     56 import com.jme3.renderer.queue.RenderQueue.ShadowMode;
     57 import com.jme3.scene.CameraNode;
     58 import com.jme3.scene.Geometry;
     59 import com.jme3.scene.Spatial;
     60 import com.jme3.scene.shape.Box;
     61 import com.jme3.shadow.PssmShadowRenderer;
     62 import de.lessvoid.nifty.Nifty;
     63 
     64 public 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