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
17package com.badlogic.gdx.tests.g3d;
18
19import com.badlogic.gdx.Gdx;
20import com.badlogic.gdx.Input.Buttons;
21import com.badlogic.gdx.Input.Keys;
22import com.badlogic.gdx.graphics.Camera;
23import com.badlogic.gdx.graphics.Color;
24import com.badlogic.gdx.graphics.g3d.Environment;
25import com.badlogic.gdx.graphics.g3d.Model;
26import com.badlogic.gdx.graphics.g3d.ModelBatch;
27import com.badlogic.gdx.graphics.g3d.ModelInstance;
28import com.badlogic.gdx.graphics.g3d.Renderable;
29import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
30import com.badlogic.gdx.graphics.g3d.attributes.DirectionalLightsAttribute;
31import com.badlogic.gdx.graphics.g3d.attributes.PointLightsAttribute;
32import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
33import com.badlogic.gdx.graphics.g3d.environment.PointLight;
34import com.badlogic.gdx.graphics.g3d.model.Animation;
35import com.badlogic.gdx.graphics.g3d.shaders.DefaultShader;
36import com.badlogic.gdx.graphics.g3d.shaders.DefaultShader.Config;
37import com.badlogic.gdx.graphics.g3d.utils.AnimationController;
38import com.badlogic.gdx.graphics.g3d.utils.DefaultShaderProvider;
39import com.badlogic.gdx.graphics.g3d.utils.ShaderProvider;
40import com.badlogic.gdx.graphics.profiling.GLProfiler;
41import com.badlogic.gdx.graphics.profiling.GL20Profiler;
42import com.badlogic.gdx.graphics.profiling.GL30Profiler;
43import com.badlogic.gdx.math.MathUtils;
44import com.badlogic.gdx.math.Matrix4;
45import com.badlogic.gdx.math.Quaternion;
46import com.badlogic.gdx.math.Vector3;
47import com.badlogic.gdx.math.collision.BoundingBox;
48import com.badlogic.gdx.scenes.scene2d.Actor;
49import com.badlogic.gdx.scenes.scene2d.ui.CheckBox;
50import com.badlogic.gdx.scenes.scene2d.ui.Label;
51import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
52import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.ChangeEvent;
53import com.badlogic.gdx.utils.Array;
54import com.badlogic.gdx.utils.ObjectMap;
55import com.badlogic.gdx.utils.StringBuilder;
56
57/** @author Daniel Holderbaum */
58public class Benchmark3DTest extends BaseG3dHudTest {
59
60	protected Environment environment;
61
62	protected Label vertexCountLabel, textureBindsLabel, shaderSwitchesLabel, drawCallsLabel, glCallsLabel,
63		lightsLabel;
64
65	protected CheckBox lightingCheckBox, lightsCheckBox;
66
67	protected boolean lighting;
68
69	@Override
70	public void create () {
71		super.create();
72
73		GLProfiler.enable();
74
75		randomizeLights();
76
77		cam.position.set(10, 10, 10);
78		cam.lookAt(0, 0, 0);
79		cam.update();
80		showAxes = true;
81		lighting = true;
82
83		vertexCountLabel = new Label("Vertices: 999", skin);
84		vertexCountLabel.setPosition(0, fpsLabel.getTop());
85		hud.addActor(vertexCountLabel);
86
87		textureBindsLabel = new Label("Texture bindings: 999", skin);
88		textureBindsLabel.setPosition(0, vertexCountLabel.getTop());
89		hud.addActor(textureBindsLabel);
90
91		shaderSwitchesLabel = new Label("Shader switches: 999", skin);
92		shaderSwitchesLabel.setPosition(0, textureBindsLabel.getTop());
93		hud.addActor(shaderSwitchesLabel);
94
95		drawCallsLabel = new Label("Draw calls: 999", skin);
96		drawCallsLabel.setPosition(0, shaderSwitchesLabel.getTop());
97		hud.addActor(drawCallsLabel);
98
99		glCallsLabel = new Label("GL calls: 999", skin);
100		glCallsLabel.setPosition(0, drawCallsLabel.getTop());
101		hud.addActor(glCallsLabel);
102
103		lightsLabel = new Label("Lights: 999", skin);
104		lightsLabel.setPosition(0, glCallsLabel.getTop());
105		hud.addActor(lightsLabel);
106
107		lightingCheckBox = new CheckBox("Lighting", skin);
108		lightingCheckBox.setChecked(lighting);
109		lightingCheckBox.addListener(new ChangeListener() {
110			@Override
111			public void changed (ChangeEvent event, Actor actor) {
112				lighting = lightingCheckBox.isChecked();
113			}
114		});
115		lightingCheckBox.setPosition(hudWidth - lightingCheckBox.getWidth(), gridCheckBox.getTop());
116		hud.addActor(lightingCheckBox);
117
118		lightsCheckBox = new CheckBox("Randomize lights", skin);
119		lightsCheckBox.setChecked(false);
120		lightsCheckBox.addListener(new ChangeListener() {
121			@Override
122			public void changed (ChangeEvent event, Actor actor) {
123				lightsCheckBox.setChecked(false);
124				randomizeLights();
125			}
126		});
127		lightsCheckBox.setPosition(hudWidth - lightsCheckBox.getWidth(), lightingCheckBox.getTop());
128		hud.addActor(lightsCheckBox);
129
130		moveCheckBox.remove();
131		rotateCheckBox.remove();
132	}
133
134	protected void randomizeLights () {
135		int pointLights = MathUtils.random(5);
136		int directionalLights = MathUtils.random(5);
137
138		DefaultShader.Config config = new Config();
139		config.numDirectionalLights = directionalLights;
140		config.numPointLights = pointLights;
141		config.numSpotLights = 0;
142
143		modelBatch.dispose();
144		modelBatch = new ModelBatch(new DefaultShaderProvider(config));
145
146		environment = new Environment();
147		environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1.f));
148
149		for (int i = 0; i < pointLights; i++) {
150			environment.add(new PointLight().set(randomColor(), randomPosition(), MathUtils.random(10f)));
151		}
152
153		for (int i = 0; i < directionalLights; i++) {
154			environment.add(new DirectionalLight().set(randomColor(), randomPosition()));
155		}
156	}
157
158	protected Color randomColor () {
159		return new Color(MathUtils.random(1.0f), MathUtils.random(1.0f), MathUtils.random(1.0f), MathUtils.random(1.0f));
160	}
161
162	protected Vector3 randomPosition () {
163		return new Vector3(MathUtils.random(-10f, 10f), MathUtils.random(-10f, 10f), MathUtils.random(-10f, 10f));
164	}
165
166	private final Vector3 tmpV = new Vector3();
167	private final Quaternion tmpQ = new Quaternion();
168	private final BoundingBox bounds = new BoundingBox();
169
170	protected void getStatus (final StringBuilder stringBuilder) {
171		stringBuilder.setLength(0);
172		stringBuilder.append("GL calls: ");
173		stringBuilder.append(GLProfiler.calls);
174		glCallsLabel.setText(stringBuilder);
175
176		stringBuilder.setLength(0);
177		stringBuilder.append("Draw calls: ");
178		stringBuilder.append(GLProfiler.drawCalls);
179		drawCallsLabel.setText(stringBuilder);
180
181		stringBuilder.setLength(0);
182		stringBuilder.append("Shader switches: ");
183		stringBuilder.append(GLProfiler.shaderSwitches);
184		shaderSwitchesLabel.setText(stringBuilder);
185
186		stringBuilder.setLength(0);
187		stringBuilder.append("Texture bindings: ");
188		stringBuilder.append(GLProfiler.textureBindings);
189		textureBindsLabel.setText(stringBuilder);
190
191		stringBuilder.setLength(0);
192		stringBuilder.append("Vertices: ");
193		stringBuilder.append(GLProfiler.vertexCount.total);
194		vertexCountLabel.setText(stringBuilder);
195
196		DirectionalLightsAttribute dirLights = (DirectionalLightsAttribute)environment.get(DirectionalLightsAttribute.Type);
197		PointLightsAttribute pointLights = (PointLightsAttribute)environment.get(PointLightsAttribute.Type);
198
199		stringBuilder.setLength(0);
200		stringBuilder.append("Lights: ");
201
202		stringBuilder.append((dirLights == null ? 0 : dirLights.lights.size) + (pointLights == null ? 0 : pointLights.lights.size));
203		stringBuilder.append(", Directional: ");
204		stringBuilder.append(dirLights == null ? 0 : dirLights.lights.size);
205		stringBuilder.append(", Point: ");
206		stringBuilder.append(pointLights == null ? 0 : pointLights.lights.size);
207		lightsLabel.setText(stringBuilder);
208
209		GLProfiler.reset();
210
211		stringBuilder.setLength(0);
212		super.getStatus(stringBuilder);
213	}
214
215	@Override
216	protected void render (ModelBatch batch, Array<ModelInstance> instances) {
217		if (lighting) {
218			batch.render(instances, environment);
219		} else {
220			batch.render(instances);
221		}
222	}
223
224	protected String currentlyLoading;
225
226	@Override
227	protected void onModelClicked (final String name) {
228		if (name == null) return;
229
230		currentlyLoading = "data/" + name;
231		assets.load(currentlyLoading, Model.class);
232		loading = true;
233	}
234
235	@Override
236	protected void onLoaded () {
237		if (currentlyLoading == null || currentlyLoading.length() == 0) return;
238
239		final ModelInstance instance = new ModelInstance(assets.get(currentlyLoading, Model.class));
240		instance.transform = new Matrix4().idt();
241		instance.transform.setToTranslation(MathUtils.random(-10, 10), MathUtils.random(-10, 10), MathUtils.random(-10, 10));
242		instance.transform.rotate(Vector3.X, MathUtils.random(-180, 180));
243		instance.transform.rotate(Vector3.Y, MathUtils.random(-180, 180));
244		instance.transform.rotate(Vector3.Z, MathUtils.random(-180, 180));
245		instances.add(instance);
246	}
247
248	@Override
249	public boolean keyUp (int keycode) {
250		if (keycode == Keys.SPACE || keycode == Keys.MENU) {
251			onLoaded();
252		}
253		return super.keyUp(keycode);
254	}
255
256	@Override
257	public boolean touchUp (int screenX, int screenY, int pointer, int button) {
258		onModelClicked(models[MathUtils.random(models.length-1)]);
259		return false;
260	}
261
262	@Override
263	public void dispose () {
264		super.dispose();
265		GLProfiler.disable();
266	}
267
268}