Java tutorial
/* This file is part of Ikou. Ikou is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License. Ikou is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Ikou. If not, see <http://www.gnu.org/licenses/>. */ package com.andgate.ikou.render; import com.andgate.ikou.model.Floor; import com.andgate.ikou.model.TilePalette; import com.andgate.ikou.model.TileSector; import com.andgate.ikou.model.TileStack; import com.andgate.ikou.utility.Array2d; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Mesh; import com.badlogic.gdx.graphics.PerspectiveCamera; import com.badlogic.gdx.graphics.g3d.Renderable; import com.badlogic.gdx.graphics.g3d.RenderableProvider; import com.badlogic.gdx.math.Matrix4; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.math.collision.BoundingBox; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Disposable; import com.badlogic.gdx.utils.Pool; public class FloorRender implements RenderableProvider, Disposable { private static final int SUBSECTOR_SIZE = TileSector.SIZE; private SectorMesh[][] sectorMeshes; public final Matrix4 floorTransform = new Matrix4(); private PerspectiveCamera camera; private Vector3 position = new Vector3(); private Vector3 size = new Vector3(); private float scale = 1.0f; public FloorRender(Floor floor) { this.camera = null; buildMeshes(floor); calculateSize(); } public PerspectiveCamera getCamera() { return camera; } public void setCamera(PerspectiveCamera camera) { this.camera = camera; } private void buildMeshes(Floor floor) { Array2d<TileSector> sectors = floor.getMasterSector().getSectors(); TilePalette palette = floor.getPalette(); int rows = sectors.size; sectorMeshes = new SectorMesh[rows][]; for (int currRow = 0; currRow < rows; currRow++) { int columns = sectors.get(currRow).size; sectorMeshes[currRow] = new SectorMesh[columns]; for (int currColumn = 0; currColumn < columns; currColumn++) { int offsetX = currColumn * TileSector.SIZE; int offsetZ = currRow * TileSector.SIZE; SectorMesh sectorMesh = new SectorMesh(floor.getMasterSector(), currRow, currColumn, palette, offsetX, offsetZ); sectorMesh.setNeedsRebuild(); sectorMeshes[currRow][currColumn] = sectorMesh; } } } private void calculateSize() { size.x = 0; size.y = 0; size.z = 0; for (SectorMesh[] sectorMeshRow : sectorMeshes) { for (SectorMesh sectorMesh : sectorMeshRow) { Mesh mesh = sectorMesh.getMesh(); if (mesh != null) { BoundingBox bbox = mesh.calculateBoundingBox(); size.x += bbox.getWidth(); size.y = Math.max(size.y, bbox.getHeight()); size.z += bbox.getDepth(); } } } } public float getWidth() { return size.x * scale; } public float getHeight() { return size.y * scale; } public float getDepth() { return size.z * scale; } public void setPosition(Vector3 position) { this.position.set(position); applyTransforms(); } public void translate(float x, float y, float z) { this.position.add(x, y, z); applyTransforms(); } public void centerOnOrigin() { translate(getWidth() / -2.0f, 0.0f, getDepth() / -2.0f); } public void scaleToBoxSize(float length) { float floorLength = size.x > size.z ? size.x : size.z; scale = length / floorLength; applyTransforms(); } private void applyTransforms() { floorTransform.idt().translate(position).scl(scale); } public void resetTransform() { floorTransform.idt(); position.setZero(); scale = 1.0f; } private final Vector3 subsectorPosition = new Vector3(); @Override public void getRenderables(Array<Renderable> renderables, Pool<Renderable> pool) { for (int i = 0; i < sectorMeshes.length; i++) { for (int j = 0; j < sectorMeshes[i].length; j++) { Mesh mesh = sectorMeshes[i][j].getMesh(); if (inFrustum(i, j) && (mesh != null)) { Renderable renderable = pool.obtain(); renderable.material = TileStack.TILE_MATERIAL; renderable.meshPartOffset = 0; renderable.meshPartSize = mesh.getNumIndices(); renderable.primitiveType = GL20.GL_TRIANGLES; renderable.mesh = mesh; renderables.add(renderable); renderable.worldTransform.set(floorTransform); } } } } private boolean inFrustum(int sectorRow, int sectorColumn) { if (camera == null) return true; floorTransform.getTranslation(subsectorPosition); subsectorPosition.x += sectorColumn * SUBSECTOR_SIZE; subsectorPosition.z += sectorRow * SUBSECTOR_SIZE; return camera.frustum.sphereInFrustum(subsectorPosition, SUBSECTOR_SIZE * 1.5f); } @Override public void dispose() { disposeMeshes(); } public void disposeMeshes() { for (SectorMesh[] sectorMeshRow : sectorMeshes) { for (SectorMesh sectorMesh : sectorMeshRow) { if (sectorMesh != null) sectorMesh.dispose(); } } } }