1 /******************************************************************************* 2 * Copyright 2011 See AUTHORS file. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 ******************************************************************************/ 16 17 package com.badlogic.gdx.tests; 18 19 import com.badlogic.gdx.Gdx; 20 import com.badlogic.gdx.Input.Keys; 21 import com.badlogic.gdx.InputAdapter; 22 import com.badlogic.gdx.InputMultiplexer; 23 import com.badlogic.gdx.graphics.Color; 24 import com.badlogic.gdx.graphics.GL20; 25 import com.badlogic.gdx.graphics.glutils.ShapeRenderer; 26 import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; 27 import com.badlogic.gdx.math.Interpolation; 28 import com.badlogic.gdx.math.MathUtils; 29 import com.badlogic.gdx.math.Vector2; 30 import com.badlogic.gdx.scenes.scene2d.Actor; 31 import com.badlogic.gdx.scenes.scene2d.Stage; 32 import com.badlogic.gdx.scenes.scene2d.ui.List; 33 import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; 34 import com.badlogic.gdx.scenes.scene2d.ui.Skin; 35 import com.badlogic.gdx.scenes.scene2d.ui.Table; 36 import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; 37 import com.badlogic.gdx.tests.utils.GdxTest; 38 import com.badlogic.gdx.utils.Align; 39 import com.badlogic.gdx.utils.reflect.ClassReflection; 40 import com.badlogic.gdx.utils.reflect.Field; 41 import com.badlogic.gdx.utils.viewport.ScreenViewport; 42 43 public class InterpolationTest extends GdxTest { 44 Stage stage; 45 private Skin skin; 46 private Table table; 47 List<String> list; 48 String interpolationNames[], selectedInterpolation; 49 private ShapeRenderer renderer; 50 float graphSize, steps, time = 0, duration = 2.5f; 51 Vector2 startPosition = new Vector2(), targetPosition = new Vector2(), position = new Vector2(); 52 53 /** resets {@link #startPosition} and {@link #targetPosition} */ resetPositions()54 void resetPositions () { 55 startPosition.set(stage.getWidth() - stage.getWidth() / 5f, stage.getHeight() - stage.getHeight() / 5f); 56 targetPosition.set(startPosition.x, stage.getHeight() / 5f); 57 } 58 59 /** @return the {@link #position} with the {@link #selectedInterpolation interpolation} applied */ getPosition(float time)60 Vector2 getPosition (float time) { 61 position.set(targetPosition); 62 position.sub(startPosition); 63 position.scl(getInterpolation(selectedInterpolation).apply(time / duration)); 64 position.add(startPosition); 65 return position; 66 } 67 68 /** @return the {@link #selectedInterpolation selected} interpolation */ getInterpolation(String name)69 private Interpolation getInterpolation (String name) { 70 try { 71 return (Interpolation)ClassReflection.getField(Interpolation.class, name).get(null); 72 } catch (Exception e) { 73 throw new RuntimeException(e); 74 } 75 } 76 77 @Override create()78 public void create () { 79 Gdx.gl.glClearColor(.3f, .3f, .3f, 1); 80 renderer = new ShapeRenderer(); 81 82 skin = new Skin(Gdx.files.internal("data/uiskin.json")); 83 84 stage = new Stage(new ScreenViewport()); 85 resetPositions(); 86 87 Field[] interpolationFields = ClassReflection.getFields(Interpolation.class); 88 89 // see how many fields are actually interpolations (for safety; other fields may be added with future) 90 int interpolationMembers = 0; 91 for (int i = 0; i < interpolationFields.length; i++) 92 if (ClassReflection.isAssignableFrom(Interpolation.class, interpolationFields[i].getDeclaringClass())) 93 interpolationMembers++; 94 95 // get interpolation names 96 interpolationNames = new String[interpolationMembers]; 97 for (int i = 0; i < interpolationFields.length; i++) 98 if (ClassReflection.isAssignableFrom(Interpolation.class, interpolationFields[i].getDeclaringClass())) 99 interpolationNames[i] = interpolationFields[i].getName(); 100 selectedInterpolation = interpolationNames[0]; 101 102 list = new List(skin); 103 list.setItems(interpolationNames); 104 list.addListener(new ChangeListener() { 105 public void changed (ChangeEvent event, Actor actor) { 106 selectedInterpolation = list.getSelected(); 107 time = 0; 108 resetPositions(); 109 } 110 }); 111 112 ScrollPane scroll = new ScrollPane(list, skin); 113 scroll.setFadeScrollBars(false); 114 scroll.setScrollingDisabled(true, false); 115 116 table = new Table(); 117 table.setFillParent(true); 118 table.add(scroll).expandX().left().width(100); 119 stage.addActor(table); 120 121 Gdx.input.setInputProcessor(new InputMultiplexer(new InputAdapter() { 122 public boolean scrolled (int amount) { 123 if (!Gdx.input.isKeyPressed(Keys.CONTROL_LEFT)) return false; 124 duration -= amount / 15f; 125 duration = MathUtils.clamp(duration, 0, Float.POSITIVE_INFINITY); 126 return true; 127 } 128 129 }, stage, new InputAdapter() { 130 public boolean touchDown (int screenX, int screenY, int pointer, int button) { 131 if (!Float.isNaN(time)) // if "walking" was interrupted by this touch down event 132 startPosition.set(getPosition(time)); // set startPosition to the current position 133 targetPosition.set(stage.screenToStageCoordinates(targetPosition.set(screenX, screenY))); 134 time = 0; 135 return true; 136 } 137 138 })); 139 } 140 render()141 public void render () { 142 Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 143 144 float bottomLeftX = Gdx.graphics.getWidth() / 2 - graphSize / 2, bottomLeftY = Gdx.graphics.getHeight() / 2 - graphSize / 2; 145 146 // only show up to two decimals 147 String text = String.valueOf(duration); 148 if (text.length() > 4) text = text.substring(0, text.lastIndexOf('.') + 3); 149 text = "duration: " + text + " s (ctrl + scroll to change)"; 150 stage.getBatch().begin(); 151 list.getStyle().font.draw(stage.getBatch(), text, bottomLeftX + graphSize / 2, bottomLeftY + graphSize 152 + list.getStyle().font.getLineHeight(), 0, Align.center, false); 153 stage.getBatch().end(); 154 155 renderer.begin(ShapeType.Line); 156 renderer.rect(bottomLeftX, bottomLeftY, graphSize, graphSize); // graph bounds 157 float lastX = bottomLeftX, lastY = bottomLeftY; 158 for (float step = 0; step <= steps; step++) { 159 Interpolation interpolation = getInterpolation(selectedInterpolation); 160 float percent = step / steps; 161 float x = bottomLeftX + graphSize * percent, y = bottomLeftY + graphSize * interpolation.apply(percent); 162 renderer.line(lastX, lastY, x, y); 163 lastX = x; 164 lastY = y; 165 } 166 time += Gdx.graphics.getDeltaTime(); 167 if (time > duration) { 168 time = Float.NaN; // stop "walking" 169 startPosition.set(targetPosition); // set startPosition to targetPosition for next click 170 } 171 // draw time marker 172 renderer.line(bottomLeftX + graphSize * time / duration, bottomLeftY, bottomLeftX + graphSize * time / duration, 173 bottomLeftY + graphSize); 174 // draw path 175 renderer.setColor(Color.GRAY); 176 renderer.line(startPosition, targetPosition); 177 renderer.setColor(Color.WHITE); 178 renderer.end(); 179 180 // draw the position 181 renderer.begin(ShapeType.Filled); 182 if (!Float.isNaN(time)) // don't mess up position if time is NaN 183 getPosition(time); 184 renderer.circle(position.x, position.y, 7); 185 renderer.end(); 186 187 stage.act(); 188 stage.draw(); 189 } 190 resize(int width, int height)191 public void resize (int width, int height) { 192 stage.getViewport().update(width, height, true); 193 table.invalidateHierarchy(); 194 195 renderer.setProjectionMatrix(stage.getViewport().getCamera().combined); 196 197 graphSize = 0.75f * Math.min(stage.getViewport().getWorldWidth(), stage.getViewport().getWorldHeight()); 198 steps = graphSize * 0.5f; 199 } 200 dispose()201 public void dispose () { 202 stage.dispose(); 203 skin.dispose(); 204 } 205 } 206