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.g3d; 18 19 import com.badlogic.gdx.Gdx; 20 import com.badlogic.gdx.Input.Keys; 21 import com.badlogic.gdx.graphics.Color; 22 import com.badlogic.gdx.graphics.GL20; 23 import com.badlogic.gdx.graphics.g3d.Material; 24 import com.badlogic.gdx.graphics.g3d.Model; 25 import com.badlogic.gdx.graphics.g3d.ModelBatch; 26 import com.badlogic.gdx.graphics.g3d.ModelInstance; 27 import com.badlogic.gdx.graphics.g3d.attributes.BlendingAttribute; 28 import com.badlogic.gdx.graphics.g3d.model.Animation; 29 import com.badlogic.gdx.graphics.g3d.model.Node; 30 import com.badlogic.gdx.graphics.g3d.utils.AnimationController; 31 import com.badlogic.gdx.graphics.glutils.ShapeRenderer; 32 import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; 33 import com.badlogic.gdx.math.Quaternion; 34 import com.badlogic.gdx.math.Vector3; 35 import com.badlogic.gdx.utils.Array; 36 import com.badlogic.gdx.utils.ObjectMap; 37 import com.badlogic.gdx.utils.Pool; 38 import com.badlogic.gdx.utils.StringBuilder; 39 40 public class SkeletonTest extends BaseG3dHudTest { 41 ShapeRenderer shapeRenderer; 42 ObjectMap<ModelInstance, AnimationController> animationControllers = new ObjectMap<ModelInstance, AnimationController>(); 43 44 @Override create()45 public void create () { 46 super.create(); 47 showAxes = false; 48 shapeRenderer = new ShapeRenderer(); 49 shapeRenderer.setColor(Color.WHITE); 50 onModelClicked("g3d/knight.g3db"); 51 } 52 53 private final static Vector3 tmpV = new Vector3(); 54 private final static Pool<Vector3> vectorPool = new Pool<Vector3>() { 55 @Override 56 protected Vector3 newObject () { 57 return new Vector3(); 58 } 59 }; 60 private final static Quaternion tmpQ = new Quaternion(); 61 62 @Override render(ModelBatch batch, Array<ModelInstance> instances)63 protected void render (ModelBatch batch, Array<ModelInstance> instances) { 64 for (ObjectMap.Entry<ModelInstance, AnimationController> e : animationControllers.entries()) 65 e.value.update(Gdx.graphics.getDeltaTime()); 66 for (final ModelInstance instance : instances) 67 renderSkeleton(instance); 68 batch.render(instances); 69 } 70 renderSkeleton(final ModelInstance instance)71 public void renderSkeleton (final ModelInstance instance) { 72 shapeRenderer.setProjectionMatrix(cam.combined); 73 shapeRenderer.begin(ShapeType.Line); 74 for (Node node : instance.nodes) { 75 shapeRenderer.setColor(node.isAnimated ? Color.RED : Color.YELLOW); 76 node.globalTransform.getTranslation(tmpV); 77 shapeRenderer.box(tmpV.x, tmpV.y, tmpV.z, 0.5f, 0.5f, 0.5f); 78 for (Node child : node.getChildren()) 79 renderSkeleton(tmpV, child); 80 } 81 shapeRenderer.end(); 82 } 83 renderSkeleton(final Vector3 from, final Node node)84 public void renderSkeleton (final Vector3 from, final Node node) { 85 final Vector3 pos = vectorPool.obtain(); 86 node.globalTransform.getTranslation(pos); 87 shapeRenderer.setColor(node.isAnimated ? Color.RED : Color.YELLOW); 88 shapeRenderer.box(pos.x, pos.y, pos.z, 0.5f, 0.5f, 0.5f); 89 shapeRenderer.setColor(Color.WHITE); 90 shapeRenderer.line(from.x, from.y, from.z, pos.x, pos.y, pos.z); 91 for (Node child : node.getChildren()) 92 renderSkeleton(pos, child); 93 vectorPool.free(pos); 94 } 95 96 @Override getStatus(StringBuilder stringBuilder)97 protected void getStatus (StringBuilder stringBuilder) { 98 super.getStatus(stringBuilder); 99 100 for (final ModelInstance instance : instances) { 101 if (instance.animations.size > 0) { 102 stringBuilder.append(" press space or menu to switch animation"); 103 break; 104 } 105 } 106 } 107 108 protected String currentlyLoading; 109 110 @Override onModelClicked(final String name)111 protected void onModelClicked (final String name) { 112 if (name == null) return; 113 114 currentlyLoading = "data/" + name; 115 assets.load(currentlyLoading, Model.class); 116 loading = true; 117 } 118 119 @Override onLoaded()120 protected void onLoaded () { 121 if (currentlyLoading == null || currentlyLoading.isEmpty()) return; 122 123 instances.clear(); 124 animationControllers.clear(); 125 final ModelInstance instance = new ModelInstance(assets.get(currentlyLoading, Model.class)); 126 for (Material m : instance.materials) 127 m.set(new BlendingAttribute(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA, 0.8f)); 128 instances.add(instance); 129 if (instance.animations.size > 0) animationControllers.put(instance, new AnimationController(instance)); 130 currentlyLoading = null; 131 } 132 switchAnimation()133 protected void switchAnimation () { 134 for (ObjectMap.Entry<ModelInstance, AnimationController> e : animationControllers.entries()) { 135 int animIndex = 0; 136 if (e.value.current != null) { 137 for (int i = 0; i < e.key.animations.size; i++) { 138 final Animation animation = e.key.animations.get(i); 139 if (e.value.current.animation == animation) { 140 animIndex = i; 141 break; 142 } 143 } 144 } 145 animIndex = (animIndex + 1) % e.key.animations.size; 146 e.value.animate(e.key.animations.get(animIndex).id, -1, 1f, null, 0.2f); 147 } 148 } 149 150 @Override keyUp(int keycode)151 public boolean keyUp (int keycode) { 152 if (keycode == Keys.SPACE || keycode == Keys.MENU) switchAnimation(); 153 return super.keyUp(keycode); 154 } 155 } 156