package org.jrenner.fps.terrain; import org.jrenner.fps.Assets; import org.jrenner.fps.Log; import org.jrenner.fps.Main; import org.jrenner.fps.Physics; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.VertexAttribute; import com.badlogic.gdx.graphics.VertexAttributes; import com.badlogic.gdx.graphics.VertexAttributes.Usage; import com.badlogic.gdx.graphics.g3d.Material; import com.badlogic.gdx.graphics.g3d.Model; import com.badlogic.gdx.graphics.g3d.ModelInstance; import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute; import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute; import com.badlogic.gdx.graphics.g3d.model.MeshPart; import com.badlogic.gdx.graphics.g3d.model.NodePart; import com.badlogic.gdx.graphics.g3d.utils.MeshPartBuilder; import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder; import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.physics.bullet.collision.btBvhTriangleMeshShape; import com.badlogic.gdx.physics.bullet.collision.btCollisionObject; import com.badlogic.gdx.physics.bullet.collision.btCollisionShape; import com.badlogic.gdx.physics.bullet.collision.btStaticPlaneShape; import com.badlogic.gdx.utils.Array; public class Terrain { public static Array<TerrainChunk> chunks; public static void init () { chunks = new Array<TerrainChunk>(); } private static Matrix4 mtx = new Matrix4(); public static void addChunk (TerrainChunk chunk, int x, int z) { mtx.setToTranslation(x, 0, z); chunk.modelInstance.transform.set(mtx); // Physics mtx.rotate(Vector3.X, -90); if (chunk.body != null) chunk.body.setWorldTransform(mtx); // Add chunk to list chunks.add(chunk); } // === Chunk creation === // /** * Create a Terrain Chunk and use the Model for both visual and Collision * @param model * @return */ public static TerrainChunk CreateMeshChunk (Model model) { return CreateMeshChunk(model, model); } /** * * @param model the model which is used for rendering * @param collisionMesh a mesh used for collision * @return */ public static TerrainChunk CreateMeshChunk (Model model, Model collisionMesh) { // Creates collision out the collision mesh btCollisionObject obj = new btCollisionObject(); btCollisionShape shape = new btBvhTriangleMeshShape(collisionMesh.meshParts); obj.setCollisionShape(shape); Physics.applyStaticGeometryCollisionFlags(obj); Physics.inst.addStaticGeometryToWorld(obj); return new TerrainChunk(new ModelInstance(model), obj); } /** * Use this for memory optimization and performance. It takes only one model which needs to have a collision * mesh and a visual node * * @param model * @param visualNode node name of the visual mesh used for rendering * @param collisionNode node name of the collision mesh * @return */ public static TerrainChunk CreateMeshChunk (Model model, String visualNode, String collisionNode ) { Array<NodePart> nodes = model.getNode(collisionNode).parts; Array<MeshPart> parts = new Array<MeshPart>(); for (NodePart part : nodes) { parts.add(part.meshPart); } // Creates collision out the collision mesh btCollisionObject obj = new btCollisionObject(); btCollisionShape shape = new btBvhTriangleMeshShape(parts); obj.setCollisionShape(shape); Physics.applyStaticGeometryCollisionFlags(obj); Physics.inst.addStaticGeometryToWorld(obj); return new TerrainChunk(new ModelInstance(model, visualNode), obj); } /** * Return a heightmap chunk * TODO NOT IMPLEMENTED! * @param heightmap * @param tex * @param width * @param height * @return */ public static TerrainChunk CreateHeightMapChunk (FileHandle heightmap, Texture tex, int width, int height) { HeightMap hp = new HeightMap(heightmap, 10, 10, false, 3); HeightMapModel md = new HeightMapModel(hp); //Model model = md.ground; md.ground.materials.get(0).set(TextureAttribute.createDiffuse(tex)); //btCollisionObject obj = new btCollisionObject(); //btCollisionShape shape = new btBvhTriangleMeshShape(model.meshParts); //obj.setCollisionShape(shape); ////Physics.applyStaticGeometryCollisionFlags(obj); //Physics.inst.addStaticGeometryToWorld(obj); TerrainChunk ch = new TerrainChunk(); ch.setModelInstance(md.ground); return ch; } /** * Creates a plane, used for testing * @param size the size of the plane * @return */ public static TerrainChunk CreatePlaneChunk (float size) { TerrainChunk chunk = new TerrainChunk(); // graphical representation of the ground Log.debug("createLevel - create ground"); if (Main.isClient()) { ModelBuilder mb = new ModelBuilder(); mb.begin(); Vector3 bl = new Vector3(); Vector3 tl = new Vector3(); Vector3 tr = new Vector3(); Vector3 br = new Vector3(); Vector3 norm = new Vector3(0f, 1f, 0f); // the size of each rect that makes up the ground Texture groundTex = Assets.manager.get("textures/ground1.jpg", Texture.class); Material groundMat = new Material(TextureAttribute.createDiffuse(groundTex)); MeshPartBuilder mpb = mb.part("ground", GL20.GL_TRIANGLES, Usage.Position | Usage.Normal | Usage.TextureCoordinates, groundMat); float u1 = 0f; float v1 = 0f; float u2 = size / 5f; float v2 = size / 5f; mpb.setUVRange(u1, v1, u2, v2); bl.set(0, 0, 0); tl.set(0, 0, size); tr.set(size, 0, size); br.set(size, 0, 0); // mpb.rect(bl, tl, tr, br, norm); int divisions = ((int)size) / 4; mpb.patch(bl, tl, tr, br, norm, divisions, divisions); Model groundModel = mb.end(); chunk.modelInstance = new ModelInstance(groundModel); } // physical representation of the ground btCollisionObject groundObj = new btCollisionObject(); btCollisionShape groundShape = new btStaticPlaneShape(Vector3.Y, 0f); groundObj.setCollisionShape(groundShape); Physics.applyStaticGeometryCollisionFlags(groundObj); Physics.inst.addStaticGeometryToWorld(groundObj); chunk.body = groundObj; return chunk; } }