/******************************************************************************* * Copyright 2014 See AUTHORS file. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.badlogic.gdx.ai.tests.steer.bullet; import com.badlogic.gdx.Application.ApplicationType; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.InputMultiplexer; import com.badlogic.gdx.ai.steer.Limiter; import com.badlogic.gdx.ai.tests.SteeringBehaviorsTest; import com.badlogic.gdx.ai.tests.steer.SteeringTestBase; import com.badlogic.gdx.ai.tests.utils.bullet.BulletConstructor; import com.badlogic.gdx.ai.tests.utils.bullet.BulletWorld; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.PerspectiveCamera; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.VertexAttributes.Usage; import com.badlogic.gdx.graphics.g3d.Environment; import com.badlogic.gdx.graphics.g3d.Material; import com.badlogic.gdx.graphics.g3d.Model; import com.badlogic.gdx.graphics.g3d.ModelBatch; import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute; import com.badlogic.gdx.graphics.g3d.attributes.FloatAttribute; import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute; import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight; import com.badlogic.gdx.graphics.g3d.environment.DirectionalShadowLight; import com.badlogic.gdx.graphics.g3d.loader.ObjLoader; import com.badlogic.gdx.graphics.g3d.utils.CameraInputController; import com.badlogic.gdx.graphics.g3d.utils.DepthShaderProvider; import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.physics.bullet.Bullet; import com.badlogic.gdx.physics.bullet.collision.btCapsuleShape; import com.badlogic.gdx.physics.bullet.collision.btConeShape; import com.badlogic.gdx.physics.bullet.linearmath.LinearMath; import com.badlogic.gdx.physics.bullet.linearmath.btIDebugDraw.DebugDrawModes; import com.badlogic.gdx.scenes.scene2d.ui.Table; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Disposable; import com.badlogic.gdx.utils.viewport.ScreenViewport; import com.badlogic.gdx.utils.viewport.Viewport; /** Base class for bullet steering behavior tests. * * @author Daniel Holderbaum */ @SuppressWarnings("deprecation") public abstract class BulletSteeringTest extends SteeringTestBase { public PerspectiveCamera camera; protected Viewport viewport; protected CameraInputController cameraController; // Set this to the path of the lib to use it on desktop instead of default lib. private final static String customDesktopLib = null; // "C:\\Xoppa\\code\\libgdx\\extensions\\gdx-bullet\\jni\\vs\\gdxBullet\\Debug\\gdxBullet.dll"; private static boolean initialized = false; public static boolean shadows = false; public static void init () { if (initialized) return; // Need to initialize bullet before using it. if (Gdx.app.getType() == ApplicationType.Desktop && customDesktopLib != null) { System.load(customDesktopLib); } else Bullet.init(); Gdx.app.log("Bullet", "Version = " + LinearMath.btGetVersion()); initialized = true; } public Environment environment; public DirectionalLight light; public ModelBatch shadowBatch; public BulletWorld world; public ObjLoader objLoader = new ObjLoader(); public ModelBuilder modelBuilder = new ModelBuilder(); public ModelBatch modelBatch; public Array<Disposable> disposables = new Array<Disposable>(); private int debugMode = DebugDrawModes.DBG_NoDebug; // DebugDrawModes.DBG_MAX_DEBUG_DRAW_MODE; protected final static Vector3 tmpV1 = new Vector3(), tmpV2 = new Vector3(); protected boolean spaceToMoveTarget; public BulletSteeringTest (SteeringBehaviorsTest container, String name) { super(container, "Bullet", name); } @Override public String getHelpMessage() { return spaceToMoveTarget ? "Keep SPACE pressed to move the target" : ""; } public BulletWorld createWorld () { return new BulletWorld(new Vector3(0, -9.81f, 0)); } protected void setNewTargetInputProcessor (SteeringBulletEntity target, Vector3 offset) { BulletTargetInputProcessor bulletTargetInputProcessor = new BulletTargetInputProcessor(target, offset, viewport, world.collisionWorld); setInputProcessor(new InputMultiplexer(bulletTargetInputProcessor, cameraController)); spaceToMoveTarget = true; } @Override public void create () { init(); environment = new Environment(); environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.3f, 0.3f, 0.3f, 1.f)); light = shadows ? new DirectionalShadowLight(1024, 1024, 20f, 20f, 1f, 300f) : new DirectionalLight(); light.set(0.8f, 0.8f, 0.8f, -0.5f, -1f, 0.7f); environment.add(light); if (shadows) environment.shadowMap = (DirectionalShadowLight)light; shadowBatch = new ModelBatch(new DepthShaderProvider()); modelBatch = new ModelBatch(); world = createWorld(); final float width = Gdx.graphics.getWidth(); final float height = Gdx.graphics.getHeight(); if (width > height) camera = new PerspectiveCamera(67f, 3f * width / height, 3f); else camera = new PerspectiveCamera(67f, 3f, 3f * height / width); camera.position.set(25f, 20f, 25f); camera.lookAt(0, 0, 0); camera.update(); viewport = new ScreenViewport(camera); cameraController = new CameraInputController(camera); inputProcessor = cameraController; // Create some simple models float size = 200f; final Model groundModel = modelBuilder.createRect( size, 0f, -size, -size, 0f, -size, -size, 0f, size, size, 0f, size, 0, 1, 0, new Material(ColorAttribute.createDiffuse(Color.WHITE), ColorAttribute.createSpecular(Color.WHITE), FloatAttribute .createShininess(16f)), Usage.Position | Usage.Normal); disposables.add(groundModel); final Model boxModel = modelBuilder.createBox(1f, 5f, 1f, new Material(ColorAttribute.createDiffuse(Color.WHITE), ColorAttribute.createSpecular(Color.WHITE), FloatAttribute.createShininess(64f)), Usage.Position | Usage.Normal); disposables.add(boxModel); final Model wallModel = modelBuilder.createBox(20f, 6f, 1f, new Material(ColorAttribute.createDiffuse(Color.WHITE), ColorAttribute.createSpecular(Color.WHITE), FloatAttribute.createShininess(64f)), Usage.Position | Usage.Normal); disposables.add(wallModel); final Model coneModel = modelBuilder.createCone(1f, 2f, 1f, 10, GL20.GL_TRIANGLES, new Material(ColorAttribute.createDiffuse(Color.YELLOW)), Usage.Position | Usage.Normal); disposables.add(coneModel); // Create a visual representation of the character. // Note that we don't use the physics part of BulletEntity, we'll do that manually final Texture texture = new Texture(Gdx.files.internal("data/badlogic.jpg")); disposables.add(texture); final Material material = new Material(TextureAttribute.createDiffuse(texture), ColorAttribute.createSpecular(1, 1, 1, 1), FloatAttribute.createShininess(8f)); final long attributes = Usage.Position | Usage.Normal | Usage.TextureCoordinates; final Model capsule = modelBuilder.createCapsule(0.49f, 2.9f, 16, material, attributes); disposables.add(capsule); // Add the constructors world.addConstructor("capsule", new BulletConstructor(capsule, 0.5f, new btCapsuleShape(0.5f, 2f))); world.addConstructor("ground", new BulletConstructor(groundModel, 0f)); // mass = 0: static body world.addConstructor("box", new BulletConstructor(boxModel, 1f)); // mass = 1kg: dynamic body world.addConstructor("staticbox", new BulletConstructor(boxModel, 0f)); // mass = 0: static body world.addConstructor("staticwall", new BulletConstructor(wallModel, 0f)); // mass = 0: static body world.addConstructor("cone", new BulletConstructor(coneModel, 1f, new btConeShape(0.5f, 2f))); // mass = 1kg: dynamic body } @Override public void update () { world.update(); cameraController.update(); } @Override public void draw () { render(false); } public void render (boolean update) { if (update) update(); viewport.update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); beginRender(true); renderWorld(); if (debugMode != DebugDrawModes.DBG_NoDebug) world.setDebugMode(debugMode); } protected void beginRender (boolean lighting) { Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); Gdx.gl.glClearColor(0, 0, 0, 0); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT); camera.update(); } protected void renderWorld () { if (shadows) { ((DirectionalShadowLight)light).begin(Vector3.Zero, camera.direction); shadowBatch.begin(((DirectionalShadowLight)light).getCamera()); world.render(shadowBatch, null); shadowBatch.end(); ((DirectionalShadowLight)light).end(); } modelBatch.begin(camera); world.render(modelBatch, environment); modelBatch.end(); } @Override public void dispose () { world.dispose(); world = null; for (Disposable disposable : disposables) disposable.dispose(); disposables.clear(); modelBatch.dispose(); modelBatch = null; shadowBatch.dispose(); shadowBatch = null; if (shadows) ((DirectionalShadowLight)light).dispose(); light = null; } protected void addMaxLinearSpeedController (Table table, final Limiter limiter) { addMaxLinearSpeedController(table, limiter, 0, 50, 0.1f); } protected void addMaxLinearAccelerationController (Table table, final Limiter limiter) { addMaxLinearAccelerationController(table, limiter, 0, 50, 0.1f); } }