com.badlogic.gdx.tests.g3d.voxel.VoxelWorld.java Source code

Java tutorial

Introduction

Here is the source code for com.badlogic.gdx.tests.g3d.voxel.VoxelWorld.java

Source

/*******************************************************************************
 * Copyright 2011 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.tests.g3d.voxel;

import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g3d.Material;
import com.badlogic.gdx.graphics.g3d.Renderable;
import com.badlogic.gdx.graphics.g3d.RenderableProvider;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pool;

public class VoxelWorld implements RenderableProvider {
    public static final int CHUNK_SIZE_X = 16;
    public static final int CHUNK_SIZE_Y = 16;
    public static final int CHUNK_SIZE_Z = 16;

    public final VoxelChunk[] chunks;
    public final Mesh[] meshes;
    public final Material[] materials;
    public final boolean[] dirty;
    public final int[] numVertices;
    public float[] vertices;
    public final int chunksX;
    public final int chunksY;
    public final int chunksZ;
    public final int voxelsX;
    public final int voxelsY;
    public final int voxelsZ;
    public int renderedChunks;
    public int numChunks;
    private final TextureRegion[] tiles;

    public VoxelWorld(TextureRegion[] tiles, int chunksX, int chunksY, int chunksZ) {
        this.tiles = tiles;
        this.chunks = new VoxelChunk[chunksX * chunksY * chunksZ];
        this.chunksX = chunksX;
        this.chunksY = chunksY;
        this.chunksZ = chunksZ;
        this.numChunks = chunksX * chunksY * chunksZ;
        this.voxelsX = chunksX * CHUNK_SIZE_X;
        this.voxelsY = chunksY * CHUNK_SIZE_Y;
        this.voxelsZ = chunksZ * CHUNK_SIZE_Z;
        int i = 0;
        for (int y = 0; y < chunksY; y++) {
            for (int z = 0; z < chunksZ; z++) {
                for (int x = 0; x < chunksX; x++) {
                    VoxelChunk chunk = new VoxelChunk(CHUNK_SIZE_X, CHUNK_SIZE_Y, CHUNK_SIZE_Z);
                    chunk.offset.set(x * CHUNK_SIZE_X, y * CHUNK_SIZE_Y, z * CHUNK_SIZE_Z);
                    chunks[i++] = chunk;
                }
            }
        }
        int len = CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z * 6 * 6 / 3;
        short[] indices = new short[len];
        short j = 0;
        for (i = 0; i < len; i += 6, j += 4) {
            indices[i + 0] = (short) (j + 0);
            indices[i + 1] = (short) (j + 1);
            indices[i + 2] = (short) (j + 2);
            indices[i + 3] = (short) (j + 2);
            indices[i + 4] = (short) (j + 3);
            indices[i + 5] = (short) (j + 0);
        }
        this.meshes = new Mesh[chunksX * chunksY * chunksZ];
        for (i = 0; i < meshes.length; i++) {
            meshes[i] = new Mesh(true, CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z * 6 * 4,
                    CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z * 36 / 3, VertexAttribute.Position(),
                    VertexAttribute.Normal());
            meshes[i].setIndices(indices);
        }
        this.dirty = new boolean[chunksX * chunksY * chunksZ];
        for (i = 0; i < dirty.length; i++)
            dirty[i] = true;

        this.numVertices = new int[chunksX * chunksY * chunksZ];
        for (i = 0; i < numVertices.length; i++)
            numVertices[i] = 0;

        this.vertices = new float[VoxelChunk.VERTEX_SIZE * 6 * CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
        this.materials = new Material[chunksX * chunksY * chunksZ];
        for (i = 0; i < materials.length; i++) {
            materials[i] = new Material(new ColorAttribute(ColorAttribute.Diffuse, MathUtils.random(0.5f, 1f),
                    MathUtils.random(0.5f, 1f), MathUtils.random(0.5f, 1f), 1));
        }
    }

    public void set(float x, float y, float z, byte voxel) {
        int ix = (int) x;
        int iy = (int) y;
        int iz = (int) z;
        int chunkX = ix / CHUNK_SIZE_X;
        if (chunkX < 0 || chunkX >= chunksX)
            return;
        int chunkY = iy / CHUNK_SIZE_Y;
        if (chunkY < 0 || chunkY >= chunksY)
            return;
        int chunkZ = iz / CHUNK_SIZE_Z;
        if (chunkZ < 0 || chunkZ >= chunksZ)
            return;
        chunks[chunkX + chunkZ * chunksX + chunkY * chunksX * chunksZ].set(ix % CHUNK_SIZE_X, iy % CHUNK_SIZE_Y,
                iz % CHUNK_SIZE_Z, voxel);
    }

    public byte get(float x, float y, float z) {
        int ix = (int) x;
        int iy = (int) y;
        int iz = (int) z;
        int chunkX = ix / CHUNK_SIZE_X;
        if (chunkX < 0 || chunkX >= chunksX)
            return 0;
        int chunkY = iy / CHUNK_SIZE_Y;
        if (chunkY < 0 || chunkY >= chunksY)
            return 0;
        int chunkZ = iz / CHUNK_SIZE_Z;
        if (chunkZ < 0 || chunkZ >= chunksZ)
            return 0;
        return chunks[chunkX + chunkZ * chunksX + chunkY * chunksX * chunksZ].get(ix % CHUNK_SIZE_X,
                iy % CHUNK_SIZE_Y, iz % CHUNK_SIZE_Z);
    }

    public float getHighest(float x, float z) {
        int ix = (int) x;
        int iz = (int) z;
        if (ix < 0 || ix >= voxelsX)
            return 0;
        if (iz < 0 || iz >= voxelsZ)
            return 0;
        // FIXME optimize
        for (int y = voxelsY - 1; y > 0; y--) {
            if (get(ix, y, iz) > 0)
                return y + 1;
        }
        return 0;
    }

    public void setColumn(float x, float y, float z, byte voxel) {
        int ix = (int) x;
        int iy = (int) y;
        int iz = (int) z;
        if (ix < 0 || ix >= voxelsX)
            return;
        if (iy < 0 || iy >= voxelsY)
            return;
        if (iz < 0 || iz >= voxelsZ)
            return;
        // FIXME optimize
        for (; iy > 0; iy--) {
            set(ix, iy, iz, voxel);
        }
    }

    public void setCube(float x, float y, float z, float width, float height, float depth, byte voxel) {
        int ix = (int) x;
        int iy = (int) y;
        int iz = (int) z;
        int iwidth = (int) width;
        int iheight = (int) height;
        int idepth = (int) depth;
        int startX = Math.max(ix, 0);
        int endX = Math.min(voxelsX, ix + iwidth);
        int startY = Math.max(iy, 0);
        int endY = Math.min(voxelsY, iy + iheight);
        int startZ = Math.max(iz, 0);
        int endZ = Math.min(voxelsZ, iz + idepth);
        // FIXME optimize
        for (iy = startY; iy < endY; iy++) {
            for (iz = startZ; iz < endZ; iz++) {
                for (ix = startX; ix < endX; ix++) {
                    set(ix, iy, iz, voxel);
                }
            }
        }
    }

    @Override
    public void getRenderables(Array<Renderable> renderables, Pool<Renderable> pool) {
        renderedChunks = 0;
        for (int i = 0; i < chunks.length; i++) {
            VoxelChunk chunk = chunks[i];
            Mesh mesh = meshes[i];
            if (dirty[i]) {
                int numVerts = chunk.calculateVertices(vertices);
                numVertices[i] = numVerts / 4 * 6;
                mesh.setVertices(vertices, 0, numVerts * VoxelChunk.VERTEX_SIZE);
                dirty[i] = false;
            }
            if (numVertices[i] == 0)
                continue;
            Renderable renderable = pool.obtain();
            renderable.material = materials[i];
            renderable.mesh = mesh;
            renderable.meshPartOffset = 0;
            renderable.meshPartSize = numVertices[i];
            renderable.primitiveType = GL20.GL_TRIANGLES;
            renderables.add(renderable);
            renderedChunks++;
        }
    }
}