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