• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.GL20;
22 import com.badlogic.gdx.graphics.Texture;
23 import com.badlogic.gdx.graphics.VertexAttributes.Usage;
24 import com.badlogic.gdx.graphics.g3d.Environment;
25 import com.badlogic.gdx.graphics.g3d.Material;
26 import com.badlogic.gdx.graphics.g3d.Model;
27 import com.badlogic.gdx.graphics.g3d.ModelBatch;
28 import com.badlogic.gdx.graphics.g3d.ModelInstance;
29 import com.badlogic.gdx.graphics.g3d.attributes.BlendingAttribute;
30 import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
31 import com.badlogic.gdx.graphics.g3d.attributes.FloatAttribute;
32 import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute;
33 import com.badlogic.gdx.graphics.g3d.environment.DirectionalShadowLight;
34 import com.badlogic.gdx.graphics.g3d.model.Animation;
35 import com.badlogic.gdx.graphics.g3d.model.Node;
36 import com.badlogic.gdx.graphics.g3d.utils.AnimationController;
37 import com.badlogic.gdx.graphics.g3d.utils.DepthShaderProvider;
38 import com.badlogic.gdx.graphics.g3d.utils.MeshBuilder;
39 import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder;
40 import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
41 import com.badlogic.gdx.math.Matrix4;
42 import com.badlogic.gdx.math.Vector3;
43 import com.badlogic.gdx.math.collision.BoundingBox;
44 import com.badlogic.gdx.utils.Array;
45 import com.badlogic.gdx.utils.StringBuilder;
46 
47 public class Animation3DTest extends BaseG3dHudTest {
48 	ModelInstance skydome;
49 	Model floorModel;
50 	ModelInstance character;
51 	Node ship;
52 	ModelInstance tree;
53 	AnimationController animation;
54 	DirectionalShadowLight shadowLight;
55 	ModelBatch shadowBatch;
56 
57 	Environment lights;
58 
59 	@Override
create()60 	public void create () {
61 		super.create();
62 		lights = new Environment();
63 		lights.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1.f));
64 		lights.add((shadowLight = new DirectionalShadowLight(1024, 1024, 30f, 30f, 1f, 100f))
65 			.set(0.8f, 0.8f, 0.8f, -.4f, -.4f, -.4f));
66 		lights.shadowMap = shadowLight;
67 		inputController.rotateLeftKey = inputController.rotateRightKey = inputController.forwardKey = inputController.backwardKey = 0;
68 		cam.position.set(25, 25, 25);
69 		cam.lookAt(0, 0, 0);
70 		cam.update();
71 		modelsWindow.setVisible(false);
72 		assets.load("data/g3d/skydome.g3db", Model.class);
73 		assets.load("data/g3d/concrete.png", Texture.class);
74 		assets.load("data/tree.png", Texture.class);
75 		assets.load("data/g3d/ship.obj", Model.class);
76 		loading = true;
77 		trForward.translation.set(0, 0, 8f);
78 		trBackward.translation.set(0, 0, -8f);
79 		trLeft.rotation.setFromAxis(Vector3.Y, 90);
80 		trRight.rotation.setFromAxis(Vector3.Y, -90);
81 
82 		ModelBuilder builder = new ModelBuilder();
83 		builder.begin();
84 		builder.node().id = "floor";
85 		MeshPartBuilder part = builder.part("floor", GL20.GL_TRIANGLES, Usage.Position | Usage.TextureCoordinates | Usage.Normal,
86 			new Material("concrete"));
87 		((MeshBuilder)part).ensureRectangles(1600);
88 		for (float x = -200f; x < 200f; x += 10f) {
89 			for (float z = -200f; z < 200f; z += 10f) {
90 				part.rect(x, 0, z + 10f, x + 10f, 0, z + 10f, x + 10f, 0, z, x, 0, z, 0, 1, 0);
91 			}
92 		}
93 		builder.node().id = "tree";
94 		part = builder.part("tree", GL20.GL_TRIANGLES, Usage.Position | Usage.TextureCoordinates | Usage.Normal,
95 			new Material("tree"));
96 		part.rect( 0f, 0f, -10f, 10f, 0f, -10f, 10f, 10f, -10f,  0f, 10f, -10f, 0, 0, 1f);
97 		part.setUVRange(1, 0, 0, 1);
98 		part.rect(10f, 0f, -10f,  0f, 0f, -10f,  0f, 10f, -10f, 10f, 10f, -10f, 0, 0, -1f);
99 		floorModel = builder.end();
100 
101 		shadowBatch = new ModelBatch(new DepthShaderProvider());
102 	}
103 
104 	final AnimationController.Transform trTmp = new AnimationController.Transform();
105 	final AnimationController.Transform trForward = new AnimationController.Transform();
106 	final AnimationController.Transform trBackward = new AnimationController.Transform();
107 	final AnimationController.Transform trRight = new AnimationController.Transform();
108 	final AnimationController.Transform trLeft = new AnimationController.Transform();
109 	final Matrix4 tmpMatrix = new Matrix4();
110 	final Vector3 tmpVector = new Vector3();
111 	int status = 0;
112 	final static int idle = 1;
113 	final static int walk = 2;
114 	final static int back = 3;
115 	final static int attack = 4;
116 	float angle = 0f;
117 
118 	@Override
render()119 	public void render () {
120 		if (character != null) {
121 			animation.update(Gdx.graphics.getDeltaTime());
122 			if (Gdx.input.isKeyPressed(Keys.UP)) {
123 				if (!animation.inAction) {
124 					trTmp.idt().lerp(trForward, Gdx.graphics.getDeltaTime() / animation.current.animation.duration);
125 					character.transform.mul(trTmp.toMatrix4(tmpMatrix));
126 				}
127 				if (status != walk) {
128 					animation.animate("Walk", -1, 1f, null, 0.2f);
129 					status = walk;
130 				}
131 			} else if (Gdx.input.isKeyPressed(Keys.DOWN)) {
132 				if (!animation.inAction) {
133 					trTmp.idt().lerp(trBackward, Gdx.graphics.getDeltaTime() / animation.current.animation.duration);
134 					character.transform.mul(trTmp.toMatrix4(tmpMatrix));
135 				}
136 				if (status != back) {
137 					animation.animate("Walk", -1, -1f, null, 0.2f);
138 					status = back;
139 				}
140 			} else if (status != idle) {
141 				animation.animate("Idle", -1, 1f, null, 0.2f);
142 				status = idle;
143 			}
144 			if (Gdx.input.isKeyPressed(Keys.RIGHT) && (status == walk || status == back) && !animation.inAction) {
145 				trTmp.idt().lerp(trRight, Gdx.graphics.getDeltaTime() / animation.current.animation.duration);
146 				character.transform.mul(trTmp.toMatrix4(tmpMatrix));
147 			} else if (Gdx.input.isKeyPressed(Keys.LEFT) && (status == walk || status == back) && !animation.inAction) {
148 				trTmp.idt().lerp(trLeft, Gdx.graphics.getDeltaTime() / animation.current.animation.duration);
149 				character.transform.mul(trTmp.toMatrix4(tmpMatrix));
150 			}
151 			if (Gdx.input.isKeyPressed(Keys.SPACE) && !animation.inAction) {
152 				animation.action("Attack", 1, 1f, null, 0.2f);
153 			}
154 			if (Gdx.input.isKeyJustPressed(Keys.Z))
155 				ship.parts.get(0).enabled = !ship.parts.get(0).enabled;
156 		}
157 
158 		if (character != null) {
159 			shadowLight.begin(character.transform.getTranslation(tmpVector), cam.direction);
160 			shadowBatch.begin(shadowLight.getCamera());
161 			if (character != null) shadowBatch.render(character);
162 			if (tree != null) shadowBatch.render(tree);
163 			shadowBatch.end();
164 			shadowLight.end();
165 		}
166 		super.render();
167 	}
168 
169 	@Override
render(ModelBatch batch, Array<ModelInstance> instances)170 	protected void render (ModelBatch batch, Array<ModelInstance> instances) {
171 		batch.render(instances, lights);
172 		if (skydome != null) batch.render(skydome);
173 	}
174 
175 	@Override
getStatus(StringBuilder stringBuilder)176 	protected void getStatus (StringBuilder stringBuilder) {
177 		super.getStatus(stringBuilder);
178 		stringBuilder.append(" use arrow keys to walk around, space to attack, Z to toggle attached node.");
179 	}
180 
181 	@Override
onModelClicked(final String name)182 	protected void onModelClicked (final String name) {
183 	}
184 
185 	@Override
onLoaded()186 	protected void onLoaded () {
187 		if (skydome == null) {
188 			skydome = new ModelInstance(assets.get("data/g3d/skydome.g3db", Model.class));
189 			floorModel.getMaterial("concrete").set(TextureAttribute.createDiffuse(assets.get("data/g3d/concrete.png", Texture.class)));
190 			floorModel.getMaterial("tree").set(
191 				TextureAttribute.createDiffuse(assets.get("data/tree.png", Texture.class)),
192 				new BlendingAttribute()
193 				);
194 			instances.add(new ModelInstance(floorModel, "floor"));
195 			instances.add(tree = new ModelInstance(floorModel, "tree"));
196 			assets.load("data/g3d/knight.g3db", Model.class);
197 			loading = true;
198 		} else if (character == null) {
199 			character = new ModelInstance(assets.get("data/g3d/knight.g3db", Model.class));
200 			BoundingBox bbox = new BoundingBox();
201 			character.calculateBoundingBox(bbox);
202 			character.transform.setToRotation(Vector3.Y, 180).trn(0, -bbox.min.y, 0);
203 			instances.add(character);
204 			animation = new AnimationController(character);
205 			animation.animate("Idle", -1, 1f, null, 0.2f);
206 			status = idle;
207 			for (Animation anim : character.animations)
208 				Gdx.app.log("Test", anim.id);
209 			// Now attach the node of another model at the tip of this knights sword:
210 			ship = assets.get("data/g3d/ship.obj", Model.class).nodes.get(0).copy();
211 			ship.detach();
212 			ship.translation.x = 10f; // offset from the sword node to the tip of the sword, in rest pose
213 			ship.rotation.set(Vector3.Z, 90f);
214 			ship.scale.scl(5f);
215 			ship.parts.get(0).enabled = false;
216 			character.getNode("sword").addChild(ship);
217 		}
218 	}
219 
220 	@Override
dispose()221 	public void dispose () {
222 		super.dispose();
223 		floorModel.dispose();
224 		shadowLight.dispose();
225 	}
226 }
227