Your code for generating cubes is fine. The problem is you have a mesh per cube.
Here is my code that generates batched chunks 16x16 in size and gets 500fps+ for me:
Uses a sprite map for textures and a heightmap for block location. Feel free to modify.
Maps.java
[java]
package mygame.map;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.material.RenderState.FaceCullMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import com.jme3.terrain.heightmap.RawHeightMap;
import com.jme3.texture.Texture;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import mygame.entity.Tree;
import mygame.main.SharedParts;
import mygame.utils.XMLLoader;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class Map extends Node {
RawHeightMap heightMap;
static Map instance;
int chunkCountX = 16;
int chunkCountZ = 16;
int chunkCountY = 8;
int CHUNK_SIZE = 16;
Chunk[][][] chunks = new Chunk[chunkCountX][chunkCountZ][chunkCountY];
byte[][][] blockHealth = new byte[chunkCountX * CHUNK_SIZE][chunkCountZ * CHUNK_SIZE][chunkCountY * CHUNK_SIZE];
byte[][][] light = new byte[chunkCountX * CHUNK_SIZE][chunkCountZ * CHUNK_SIZE][chunkCountY * CHUNK_SIZE];
float darkness=0.66f;
Texture sheet;
Material material;
SharedParts sharedParts;
public Map(SharedParts sharedParts, String heightFile) {
this.sharedParts = sharedParts;
this.setName("Map");
try {
heightMap = new RawHeightMap(heightFile, 256);
//heightMap.load();
} catch (Exception e) {
System.out.println(e.getMessage());
}
if (sheet == null) {
sheet = sharedParts.assetManager.loadTexture("Textures/tiles.png");
sheet.setWrap(Texture.WrapMode.Clamp);
sheet.setMinFilter(Texture.MinFilter.NearestNoMipMaps);
sheet.setMagFilter(Texture.MagFilter.Nearest);
}
material = new Material(sharedParts.assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
//material.setBoolean("VertexLighting", true);
material.setBoolean("VertexColor", true);
material.setTexture("ColorMap", getSheet());
//material.getAdditionalRenderState().setWireframe(true);
}
public void update() {
for (int x = 0; x < chunkCountX; x++) {
for (int z = 0; z < chunkCountZ; z++) {
for (int y = 0; y < chunkCountY; y++) {
if(chunks[x][z][y] != null)
chunks[x][z][y].update();
}
}
}
}
public void loadXML(String xmlUrl) {
XMLLoader loader = new XMLLoader();
org.jdom2.Element root = null;
try {
root = (org.jdom2.Element) loader.load(xmlUrl);
} catch (IOException ex) {
Logger.getLogger(Map.class.getName()).log(Level.SEVERE, null, ex);
}
List<org.jdom2.Element> trees = root.getChild("entities").getChildren("tree");
for (int i = 0; i < trees.size(); i++) {
org.jdom2.Element tree1 = trees.get(i);
int x = Integer.parseInt(tree1.getAttribute("x").getValue());
int y = Integer.parseInt(tree1.getAttribute("y").getValue());
int z = Integer.parseInt(tree1.getAttribute("z").getValue());
Tree treeEntity = new Tree(sharedParts);
treeEntity.setPosition(new Vector3f(x * 2, y, z * 2));
this.attachChild(treeEntity);
System.out.println("Tree added at: " + x + " " + y + " " + z);
}
}
public void fillTileStrips(Element tiles, Document doc1) {
byte oldBlockType = -1;
int startY = 0;
for (int x = 0; x < chunkCountX * CHUNK_SIZE; x++) {
for (int z = 0; z < chunkCountZ * CHUNK_SIZE; z++) {
startY = 0;
for (int y = 0; y < chunkCountY * CHUNK_SIZE; y++) {
byte block1 = getBlock(x, z, y);
if ((y != 0) && (block1 != oldBlockType)) {
//Dont write empty blocks
if (oldBlockType != Block.EMPTY_BLOCK) {
Element strip = doc1.createElement("strip");
strip.setAttribute("x", x + "");
strip.setAttribute("z", z + "");
strip.setAttribute("y1", startY + "");
strip.setAttribute("y2", y + "");
strip.setAttribute("type", oldBlockType + "");
tiles.appendChild(strip);
}
startY = y + 1;
}
oldBlockType = block1;
}
}
}
}
public void saveXML(String xmlURL) {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = null;
try {
docBuilder = docFactory.newDocumentBuilder();
} catch (Exception e) {
System.out.println(e);
return;
}
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("map");
Element tiles = doc.createElement("tiles");
rootElement.appendChild(tiles);
fillTileStrips(tiles, doc);
doc.appendChild(rootElement);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = null;;
try {
transformer = transformerFactory.newTransformer();
} catch (Exception e) {
System.out.println(e);
return;
}
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(xmlURL + ".xml"));
// Output to console for testing
// StreamResult result = new StreamResult(System.out);
try {
transformer.transform(source, result);
} catch (Exception e) {
System.out.println(e);
}
}
public Material getMaterial() {
return material;
}
public void loadHealth() {
for (int x = 0; x < chunkCountX * CHUNK_SIZE; x++) {
for (int z = 0; z < chunkCountZ * CHUNK_SIZE; z++) {
for (int y = 0; y < chunkCountY * CHUNK_SIZE; y++) {
blockHealth[x][z][y] = 20;
}
}
}
}
/*
public void rebuild() {
//castLight();
for (int x = 0; x < chunkCountX; x++) {
for (int z = 0; z < chunkCountZ; z++) {
for (int y = 0; y < chunkCountY; y++) {
Chunk c1 = chunks[x][z][y];
if (c1.needsRebuild) {
c1.build();
}
}
}
}
}*/
public float getDarkness(){
return darkness;
}
public float getLightAverage(byte b1, byte b2, byte b3, byte b4) {
//10 * 4 is max brightness for 4 blocks
float average = (b1 + b2 + b3 + b4) / 40;
return average;
}
public byte[][][] getVertexLightZone(int x, int y, int z) {
//x2,y2,z2 = offset
byte[][][] lights = new byte[3][3][3];
for (int x2 = 0; x2 < 3; x2++) {
for (int y2 = 0; y2 < 3; y2++) {
for (int z2 = 0; z2 < 3; z2++) {
lights[x2][y2][z2] = getLightLevel((x - 1) + x2, (z - 1) + z2, (y - 1) + y2);
}
}
}
return lights;
}
public byte getLightLevel(int x, int z, int y) {
if ((x < 0) || (z < 0) || (y < 0)) {
return 0;
}
if (y >= (CHUNK_SIZE * chunkCountY)) {
return 0;
}
if (x >= (CHUNK_SIZE * chunkCountX)) {
return 0;
}
if (z >= (CHUNK_SIZE * chunkCountZ)) {
return 0;
}
if(this.getBlock(x,z,y) == Block.EMPTY_BLOCK)
return 10;
else
return 0;
}
/*
public void castLight() {
for (int x = 0; x < chunkCountX * CHUNK_SIZE; x++) {
for (int z = 0; z < chunkCountZ * CHUNK_SIZE; z++) {
for (int y = 0; y < chunkCountY * CHUNK_SIZE; y++) {
light[x][z][y] = 0;
}
}
}
for (int x = 0; x < chunkCountX * CHUNK_SIZE; x++) {
for (int z = 0; z < chunkCountZ * CHUNK_SIZE; z++) {
for (int y = (chunkCountY * CHUNK_SIZE) - 1; y >= 0; y--) {
if (getBlock(x, z, y) == Block.EMPTY_BLOCK) {
light[x][z][y] = 10;
} else {
//light[x][z][y] = 10;
y = 0;
}
}
}
}
}
*/
public void loadMap() {
for (int x = 0; x < chunkCountX; x++) {
for (int z = 0; z < chunkCountZ; z++) {
for (int y = 0; y < chunkCountY; y++) {
chunks[x][z][y] = new Chunk(x, z, y, sharedParts, this);
chunks[x][z][y].needsRebuild = true;
}
}
}
loadHeightMap();
//castLight();
loadHealth();
//loadXML("assets/map1.xml");
System.out.println("Map loaded.");
}
public Texture getSheet() {
return sheet;
}
private void loadHeightMap() {
for (int x = 0; x < 256; x++) {
for (int z = 0; z < 256; z++) {
float point = heightMap.getTrueHeightAtPoint(x, z);
int p2 = (int) Math.floor((point * (CHUNK_SIZE * chunkCountY) / 255));
//float rand = (float) (Math.random() * 4);
//int bottomPoint = (int) (rand);
int bottomPoint = 0;
for (int y = bottomPoint; y < p2; y++) {
if (point == 0) {
this.setBlock(x, z, y, Block.EMPTY_BLOCK, false);
} else {
this.setBlock(x, z, y, Block.DIRT_BLOCK, false);
if (y == (p2 - 1)) {
this.setBlock(x, z, y, Block.GRASS_BLOCK, false);
}
}
}
}
}
}
public int damageBlock(int x, int y, int z, int dmg) {
blockHealth[x][z][y] -= dmg;
return blockHealth[x][z][y];
}
public void makeDust(int x, int y, int z) {
/** Explosion effect. Uses Texture from jme3-test-data library! */
ParticleEmitter debris = new ParticleEmitter("Debris", ParticleMesh.Type.Triangle, 25);
Material debris_mat = new Material(sharedParts.assetManager, "Common/MatDefs/Misc/Particle.j3md");
debris_mat.setTexture("Texture", sharedParts.assetManager.loadTexture("Effects/dust.png"));
debris_mat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off);
debris_mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
debris.setStartSize(1.5f);
debris.setEndSize(1.6f);
debris.setLowLife(0.3f);
debris.setHighLife(1.8f);
debris.setMaterial(debris_mat);
debris.setLocalTranslation((x * 2) + 1, y + 0.5f, (z * 2) - 1);
debris.setRotateSpeed(1.2f);
debris.getParticleInfluencer().setInitialVelocity(new Vector3f(1.4f, 1.4f, 1.4f));
debris.setStartColor(new ColorRGBA(0.8f, 0.7f, 0.45f, 0.96f));
debris.setGravity(0f, 0f, 0f);
debris.getParticleInfluencer().setVelocityVariation(1.70f);
this.attachChild(debris);
debris.emitAllParticles();
debris.setParticlesPerSec(0);
}
public void destroyBlock(int x, int z, int y, byte blockType, boolean rebuild) {
if (blockType == Block.EMPTY_BLOCK && sharedParts.isServer() == false) {
makeDust(x, y, z);
}
setBlock(x, z, y, blockType, rebuild);
}
public void setBlock(int x, int z, int y, byte blockType, boolean rebuild) {
if ((x < 0) || (z < 0) || (y < 0)) {
return;
}
if (y >= (CHUNK_SIZE * chunkCountY)) {
return;
}
if (x >= (CHUNK_SIZE * chunkCountX)) {
return;
}
if (z >= (CHUNK_SIZE * chunkCountZ)) {
return;
}
int chunkX = (int) Math.floor(x / CHUNK_SIZE);
int chunkZ = (int) Math.floor(z / CHUNK_SIZE);
int chunkY = (int) Math.floor(y / CHUNK_SIZE);
final int tileX = (int) x - (chunkX * CHUNK_SIZE);
final int tileZ = (int) z - (chunkZ * CHUNK_SIZE);
final int tileY = (int) y - (chunkY * CHUNK_SIZE);
final Chunk chunk1 = chunks[chunkX][chunkZ][chunkY];
chunk1.setBlock(tileX, tileY, tileZ, blockType);
if (rebuild) {
Chunk chunk2 = null;
Chunk chunk3 = null;
Chunk chunk4 = null;
Chunk chunk5 = null;
Chunk chunk6 = null;
Chunk chunk7 = null;
//define neighboring chunks
if (tileX == 0) {
chunk2 = getChunk(chunk1.x - 1, chunk1.z, chunk1.y);
if(chunk2!=null)
chunk2.needsRebuild = true;
}
if (tileX == (CHUNK_SIZE - 1)) {
chunk3 = getChunk(chunk1.x + 1, chunk1.z, chunk1.y);
if(chunk3!=null)
chunk3.needsRebuild = true;
}
if (tileZ == 0) {
chunk4 = getChunk(chunk1.x, chunk1.z - 1, chunk1.y);
if(chunk4!=null)
chunk4.needsRebuild = true;
}
if (tileZ == (CHUNK_SIZE - 1)) {
chunk5 = getChunk(chunk1.x, chunk1.z + 1, chunk1.y);
if(chunk5!=null)
chunk5.needsRebuild = true;
}
if (tileY == 0) {
chunk6 = getChunk(chunk1.x, chunk1.z, chunk1.y - 1);
if(chunk6!=null)
chunk6.needsRebuild = true;
}
if (tileY == (CHUNK_SIZE - 1)) {
chunk7 = getChunk(chunk1.x, chunk1.z, chunk1.y + 1);
if(chunk7!=null)
chunk7.needsRebuild = true;
}
//rebuild all chunks
/*
if (chunk1 != null) {
chunk1.buildThreaded();
}
if (chunk2 != null) {
chunk2.buildThreaded();
}
if (chunk3 != null) {
chunk3.buildThreaded();
}
if (chunk4 != null) {
chunk4.buildThreaded();
}
if (chunk5 != null) {
chunk5.buildThreaded();
}
if (chunk6 != null) {
chunk6.buildThreaded();
}
if (chunk7 != null) {
chunk7.buildThreaded();
}*/
}
}
public Chunk getChunk(int x, int z, int y) {
if ((x < 0) || (z < 0) || (y < 0)) {
return null;
}
if ((x > chunkCountX) || (y > chunkCountY) || (z > chunkCountZ)) {
return null;
}
return chunks[x][z][y];
}
public byte getBlock(int x, int z, int y) {
if ((x < 0) || (z < 0) || (y < 0)) {
return 0;
}
if ((y >= (CHUNK_SIZE * chunkCountY))) {
return 0;
}
if (x >= (CHUNK_SIZE * chunkCountX)) {
return 0;
}
if (z >= (CHUNK_SIZE * chunkCountZ)) {
return 0;
}
int chunkX = (int) Math.floor(x / CHUNK_SIZE);
int chunkZ = (int) Math.floor(z / CHUNK_SIZE);
int chunkY = (int) Math.floor(y / CHUNK_SIZE);
int tileX = (int) x - (chunkX * CHUNK_SIZE);
int tileZ = (int) z - (chunkZ * CHUNK_SIZE);
int tileY = (int) y - (chunkY * CHUNK_SIZE);
Chunk chunk1 = chunks[chunkX][chunkZ][chunkY];
byte ireturn = chunk1.getBlock(tileX, tileZ, tileY);
return ireturn;
}
}
[/java]
Chunk.java
[java]
package mygame.map;
import java.util.ArrayList;
import com.jme3.bullet.collision.shapes.MeshCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.math.Vector4f;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.util.BufferUtils;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import mygame.main.SharedParts;
public class Chunk extends Geometry {
int x = 0;
int y = 0;
int z = 0;
public static int CHUNK_SIZE = 16;
public static int BLOCK_WIDTH = 2;
public static int BLOCK_HEIGHT = 2;
public static float TEXTURE_SIZE = 256;
public static float TILE_SIZE = 32;
public static float SUB_TILE_SIZE = 16;
final static ArrayList<Vector3f> vertices = new ArrayList<Vector3f>(); // points
final static ArrayList<Vector3f> normals = new ArrayList<Vector3f>(); // normals
final static ArrayList<Vector2f> texCoord = new ArrayList<Vector2f>(); // tex cords
final static ArrayList<Integer> indexes = new ArrayList<Integer>(); // indexes
final static ArrayList<Vector4f> colors = new ArrayList<Vector4f>();
public final static Vector3f normalUp = new Vector3f(0, 1, 0);
public final static Vector3f normalDown = new Vector3f(0, -1, 0);
public final static Vector3f normalRight = new Vector3f(1, 0, 0);
public final static Vector3f normalLeft = new Vector3f(-1, 0, 0);
public final static Vector3f normalFront = new Vector3f(0, 0, 1);
public final static Vector3f normalBack = new Vector3f(0, 0, -1);
public final static Vector4f darkColor = new Vector4f(0.6f,0.6f,0.6f, 0.6f);
public final static Vector4f brightColor = new Vector4f(1f, 1f, 1f, 1f);
public final static Vector4f green = new Vector4f(0,1,0,1);
//Block[][][] blocks = new Block[CHUNK_SIZE][CHUNK_SIZE][CHUNK_SIZE];
byte[][][] blocks = new byte[CHUNK_SIZE][CHUNK_SIZE][CHUNK_SIZE];
Mesh mesh = new Mesh();
RigidBodyControl chunkPhysicsNode;
SharedParts sharedParts;
Map map;
public final static int RIGHT_FACE = 0;
public final static int LEFT_FACE = 1;
public final static int TOP_FACE = 2;
public final static int BOTTOM_FACE = 3;
public final static int FRONT_FACE = 4;
public final static int BACK_FACE = 5;
boolean needsRebuild = false;
Future future;
ChunkAndPhysics futureChunk;
//private static Texture sheet;
public Chunk(int x, int z, int y, SharedParts sharedParts, Map map) {
this.x = x;
this.y = y;
this.z = z;
this.sharedParts = sharedParts;
this.map = map;
this.setName("Chunk");
initEmpty();
}
public void update(){
if(needsRebuild)
build();
}
private void initEmpty() {
for (int x = 0; x < CHUNK_SIZE; x++) {
for (int z = 0; z < CHUNK_SIZE; z++) {
for (int y = 0; y < CHUNK_SIZE; y++) {
blocks[x][z][y] = Block.EMPTY_BLOCK;
}
}
}
}
public void setBlock(int x, int y, int z, byte blockType) {
blocks[x][z][y] = blockType;
needsRebuild = true;
}
/*
public void buildThreaded(){
// A self-contained time-intensive task:
if(needsRebuild){
if(futureChunk==null && future==null){
GenerateChunk genChunk = new GenerateChunk(blocks, x, y, z, this, map, sharedParts);
future = sharedParts.executor.submit(genChunk);
} else if (future!=null) {
if(future.isDone()){
needsRebuild = false;
future = null;
}
}
}
}*/
public void build() {
int[] faces = new int[7];
colors.clear();
vertices.clear();
texCoord.clear();
indexes.clear();
normals.clear();
float middle = (SUB_TILE_SIZE / TEXTURE_SIZE);
float max = (TILE_SIZE / TEXTURE_SIZE);
//float fourth = (SUB_TILE_SIZE / 2) / TEXTURE_SIZE;
float fourth = (SUB_TILE_SIZE / TEXTURE_SIZE);
for (int x2 = 0; x2 < CHUNK_SIZE; x2++) {
for (int z2 = 0; z2 < CHUNK_SIZE; z2++) {
for (int y2 = 0; y2 < CHUNK_SIZE; y2++) {
byte myBlock = blocks[x2][z2][y2];
if (myBlock == Block.EMPTY_BLOCK) {
continue;
}
//0 = x, 1 = y
int[] spritePos = Block.getSpritePos(myBlock);
faces = checkSix(x2, y2, z2);
//None of the faces were visible
if (faces[6] == 0) {
continue;
}
//draw positions
float xPos = (float) ((this.x * CHUNK_SIZE * 2) + x2 * 2);
float zPos = (float) ((this.z * CHUNK_SIZE * 2) + z2 * 2);
float yPos = (float) ((this.y * CHUNK_SIZE * 2) + y2 * 2);
int absX = ((this.x) * CHUNK_SIZE) + x2;
int absZ = ((this.z) * CHUNK_SIZE) + z2;
int absY = ((this.y) * CHUNK_SIZE) + y2;
//float light = (float)map.getLightLevel(absX, absZ, absY)/10;
//Vector4f brightness = new Vector4f(light,light,light,light);
float startX = (TILE_SIZE / TEXTURE_SIZE) * (float) spritePos[0];
float startY = (TILE_SIZE / TEXTURE_SIZE) * (float) spritePos[1];
int verticesSize = vertices.size();
Vector3f pa = new Vector3f(xPos + 0, yPos + 0, zPos + 0);
Vector3f pb = new Vector3f(xPos + 2, yPos + 0, zPos + 0);
Vector3f pc = new Vector3f(xPos + 0, yPos + 2, zPos + 0);
Vector3f pd = new Vector3f(xPos + 2, yPos + 2, zPos + 0);
Vector3f pe = new Vector3f(xPos + 0, yPos + 0, zPos - 2);
Vector3f pf = new Vector3f(xPos + 0, yPos + 2, zPos - 2);
Vector3f pg = new Vector3f(xPos + 2, yPos + 0, zPos - 2);
Vector3f ph = new Vector3f(xPos + 2, yPos + 2, zPos - 2);
byte[][][] lights = map.getVertexLightZone(absX, absY, absZ);
//FRONT
if (faces[FRONT_FACE] == 1) {
float botLeft = Math.max(map.getDarkness(), map.getLightAverage(lights[1][1][2], lights[0][1][2], lights[1][0][2], lights[0][0][2]));
float botRight = Math.max(map.getDarkness(), map.getLightAverage(lights[1][1][2], lights[2][1][2], lights[1][0][2], lights[2][0][2]));
float topLeft = Math.max(map.getDarkness(), map.getLightAverage(lights[1][2][2], lights[0][2][2], lights[1][1][2], lights[0][1][2]));
float topRight = Math.max(map.getDarkness(), map.getLightAverage(lights[1][2][2], lights[2][2][2], lights[1][1][2], lights[2][1][2]));
vertices.add(pa);
vertices.add(pb);
vertices.add(pc);
vertices.add(pd);
indexes.add(verticesSize + 2);
indexes.add(verticesSize + 0);
indexes.add(verticesSize + 1);
indexes.add(verticesSize + 1);
indexes.add(verticesSize + 3);
indexes.add(verticesSize + 2);
texCoord.add(new Vector2f(startX, startY));
texCoord.add(new Vector2f(startX + middle, startY));
texCoord.add(new Vector2f(startX, startY + fourth));
texCoord.add(new Vector2f(startX + middle, startY + fourth));
normals.add(normalFront);
normals.add(normalFront);
normals.add(normalFront);
normals.add(normalFront);
colors.add(new Vector4f(botLeft,botLeft,botLeft, botLeft));
colors.add(new Vector4f(botRight,botRight,botRight, botRight));
colors.add(new Vector4f(topLeft,topLeft,topLeft, topLeft));
colors.add(new Vector4f(topRight,topRight,topRight, topRight));
}
//LEFT
if (faces[LEFT_FACE] == 1) {
verticesSize = vertices.size();
float botRight = Math.max(map.getDarkness(), map.getLightAverage(lights[0][1][2], lights[0][1][1], lights[0][0][2], lights[0][0][1]));
float botLeft = Math.max(map.getDarkness(), map.getLightAverage(lights[0][1][0], lights[0][1][1], lights[0][0][0], lights[0][0][1]));
float topRight = Math.max(map.getDarkness(), map.getLightAverage(lights[0][2][2], lights[0][1][1], lights[0][2][1], lights[0][1][2]));
float topLeft = Math.max(map.getDarkness(), map.getLightAverage(lights[0][2][0], lights[0][1][1], lights[0][1][0], lights[0][2][1]));
vertices.add(pe);//BOTTOM LEFT
vertices.add(pa);//BOTTOM RIGHT
vertices.add(pf);//TOP LEFT
vertices.add(pc);//TOP RIGHT
indexes.add(verticesSize + 2);
indexes.add(verticesSize + 0);
indexes.add(verticesSize + 1);
indexes.add(verticesSize + 1);
indexes.add(verticesSize + 3);
indexes.add(verticesSize + 2);
texCoord.add(new Vector2f(startX, startY));
texCoord.add(new Vector2f(startX + middle, startY));
texCoord.add(new Vector2f(startX, startY + fourth));
texCoord.add(new Vector2f(startX + middle, startY + fourth));
normals.add(normalLeft);
normals.add(normalLeft);
normals.add(normalLeft);
normals.add(normalLeft);
colors.add(new Vector4f(botLeft,botLeft,botLeft, botLeft));
colors.add(new Vector4f(botRight,botRight,botRight, botRight));
colors.add(new Vector4f(topLeft,topLeft,topLeft, topLeft));
colors.add(new Vector4f(topRight,topRight,topRight, topRight));
}
//RIGHT
if (faces[RIGHT_FACE] == 1) {
verticesSize = vertices.size();
float botRight = Math.max(map.getDarkness(), map.getLightAverage(lights[2][1][2], lights[2][1][1], lights[2][0][2], lights[2][0][1]));
float botLeft = Math.max(map.getDarkness(), map.getLightAverage(lights[2][1][0], lights[2][1][1], lights[2][0][0], lights[2][0][1]));
float topRight = Math.max(map.getDarkness(), map.getLightAverage(lights[2][2][2], lights[2][1][1], lights[2][2][1], lights[2][1][2]));
float topLeft = Math.max(map.getDarkness(), map.getLightAverage(lights[2][2][0], lights[2][1][1], lights[2][1][0], lights[2][2][1]));
vertices.add(pb);//BOTTOM LEFT
vertices.add(pg);//BOTTOM RIGHT
vertices.add(pd);//TOP LEFT
vertices.add(ph);//TOP RIGHT
indexes.add(verticesSize + 2);
indexes.add(verticesSize + 0);
indexes.add(verticesSize + 1);
indexes.add(verticesSize + 1);
indexes.add(verticesSize + 3);
indexes.add(verticesSize + 2);
texCoord.add(new Vector2f(startX, startY));
texCoord.add(new Vector2f(startX + middle, startY));
texCoord.add(new Vector2f(startX, startY + fourth));
texCoord.add(new Vector2f(startX + middle, startY + fourth));
normals.add(normalRight);
normals.add(normalRight);
normals.add(normalRight);
normals.add(normalRight);
colors.add(new Vector4f(botRight,botRight,botRight, botRight));
colors.add(new Vector4f(botLeft,botLeft,botLeft, botLeft));
colors.add(new Vector4f(topRight,topRight,topRight, topRight));
colors.add(new Vector4f(topLeft,topLeft,topLeft, topLeft));
}
//BACK
if (faces[BACK_FACE] == 1) {
verticesSize = vertices.size();
float botRight = Math.max(map.getDarkness(), map.getLightAverage(lights[1][1][0], lights[0][1][0], lights[1][0][0], lights[0][0][0]));
float botLeft = Math.max(map.getDarkness(), map.getLightAverage(lights[1][1][0], lights[2][1][0], lights[1][0][0], lights[2][0][0]));
float topRight = Math.max(map.getDarkness(), map.getLightAverage(lights[1][2][0], lights[0][2][0], lights[1][1][0], lights[0][1][0]));
float topLeft = Math.max(map.getDarkness(), map.getLightAverage(lights[1][2][0], lights[2][2][0], lights[1][1][0], lights[2][1][0]));
vertices.add(pg);//BOTTOM LEFT
vertices.add(pe);//BOTTOM RIGHT
vertices.add(ph);//TOP LEFT
vertices.add(pf);//TOP RIGHT
indexes.add(verticesSize + 2);
indexes.add(verticesSize + 0);
indexes.add(verticesSize + 1);
indexes.add(verticesSize + 1);
indexes.add(verticesSize + 3);
indexes.add(verticesSize + 2);
texCoord.add(new Vector2f(startX, startY));
texCoord.add(new Vector2f(startX + middle, startY));
texCoord.add(new Vector2f(startX, startY + fourth));
texCoord.add(new Vector2f(startX + middle, startY + fourth));
normals.add(normalBack);
normals.add(normalBack);
normals.add(normalBack);
normals.add(normalBack);
colors.add(new Vector4f(botLeft,botLeft,botLeft, botLeft));
colors.add(new Vector4f(botRight,botRight,botRight, botRight));
colors.add(new Vector4f(topLeft,topLeft,topLeft, topLeft));
colors.add(new Vector4f(topRight,topRight,topRight, topRight));
}
//TOP
if (faces[TOP_FACE] == 1) {
verticesSize = vertices.size();
float botRight = Math.max(map.getDarkness(), map.getLightAverage(lights[2][2][2], lights[2][2][1], lights[1][2][1], lights[1][2][2]));
float botLeft = Math.max(map.getDarkness(), map.getLightAverage(lights[0][2][1], lights[0][2][2], lights[1][2][1], lights[1][2][2]));
float topRight = Math.max(map.getDarkness(), map.getLightAverage(lights[2][2][1], lights[2][2][0], lights[1][2][0], lights[1][2][1]));
float topLeft = Math.max(map.getDarkness(), map.getLightAverage(lights[0][2][0], lights[0][2][1], lights[1][2][1], lights[1][2][0]));
vertices.add(pc);//BOTTOM LEFT
vertices.add(pd);//BOTTOM RIGHT
vertices.add(pf);//TOP LEFT
vertices.add(ph);//TOP RIGHT
indexes.add(verticesSize + 2);
indexes.add(verticesSize + 0);
indexes.add(verticesSize + 1);
indexes.add(verticesSize + 1);
indexes.add(verticesSize + 3);
indexes.add(verticesSize + 2);
texCoord.add(new Vector2f(startX, startY + middle));
texCoord.add(new Vector2f(startX + middle, startY + middle));
texCoord.add(new Vector2f(startX, startY + max));
texCoord.add(new Vector2f(startX + middle, startY + max));
normals.add(normalUp);
normals.add(normalUp);
normals.add(normalUp);
normals.add(normalUp);
colors.add(new Vector4f(botLeft,botLeft,botLeft, botLeft));
colors.add(new Vector4f(botRight,botRight,botRight, botRight));
colors.add(new Vector4f(topLeft,topLeft,topLeft, topLeft));
colors.add(new Vector4f(topRight,topRight,topRight, topRight));
}
//BOTTOM
if (faces[BOTTOM_FACE] == 1) {
verticesSize = vertices.size();
float botRight = Math.max(map.getDarkness(), map.getLightAverage(lights[2][0][2], lights[2][0][1], lights[1][0][1], lights[1][0][2]));
float botLeft = Math.max(map.getDarkness(), map.getLightAverage(lights[0][0][1], lights[0][0][2], lights[1][0][1], lights[1][0][2]));
float topRight = Math.max(map.getDarkness(), map.getLightAverage(lights[2][0][1], lights[2][0][0], lights[1][0][0], lights[1][0][1]));
float topLeft = Math.max(map.getDarkness(), map.getLightAverage(lights[0][0][0], lights[0][0][1], lights[1][0][1], lights[1][0][0]));
vertices.add(pa);//BOTTOM LEFT
vertices.add(pb);//BOTTOM RIGHT
vertices.add(pe);//TOP LEFT
vertices.add(pg);//TOP RIGHT
indexes.add(verticesSize + 2);
indexes.add(verticesSize + 3);
indexes.add(verticesSize + 1);
indexes.add(verticesSize + 1);
indexes.add(verticesSize + 0);
indexes.add(verticesSize + 2);
texCoord.add(new Vector2f(startX + middle, startY + middle));
texCoord.add(new Vector2f(startX + max, startY + middle));
texCoord.add(new Vector2f(startX + middle, startY + max));
texCoord.add(new Vector2f(startX + max, startY + max));
normals.add(normalDown);
normals.add(normalDown);
normals.add(normalDown);
normals.add(normalDown);
colors.add(new Vector4f(botLeft,botLeft,botLeft, botLeft));
colors.add(new Vector4f(botRight,botRight,botRight, botRight));
colors.add(new Vector4f(topLeft,topLeft,topLeft, topLeft));
colors.add(new Vector4f(topRight,topRight,topRight, topRight));
}
}
}
}
float[] c4 = convertFloats(colors);
Vector3f[] v3 = vertices.toArray(new Vector3f[vertices.size()]);
Vector3f[] n3 = normals.toArray(new Vector3f[normals.size()]);
Vector2f[] v2 = texCoord.toArray(new Vector2f[texCoord.size()]);
int indx[] = convertIntegers(indexes);
if (this.getMesh() == null) {
mesh.setBuffer(Type.Color,4, BufferUtils.createFloatBuffer(c4));
mesh.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(v3));
mesh.setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(v2));
mesh.setBuffer(Type.Normal, 3, BufferUtils.createFloatBuffer(n3));
mesh.setBuffer(Type.Index, 3, BufferUtils.createIntBuffer(indx));
mesh.updateBound();
if (sharedParts.isServer() == false) {
mesh.createCollisionData();
this.setMesh(mesh);
this.mesh.updateBound();
map.attachChild(this);
}
} else {
mesh = new Mesh();
mesh.setBuffer(Type.Color,4, BufferUtils.createFloatBuffer(c4));
mesh.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(v3));
mesh.setBuffer(Type.TexCoord, 2, BufferUtils.createFloatBuffer(v2));
mesh.setBuffer(Type.Normal, 3, BufferUtils.createFloatBuffer(n3));
mesh.setBuffer(Type.Index, 3, BufferUtils.createIntBuffer(indx));
if (sharedParts.isServer() == false) {
mesh.createCollisionData();
this.setMesh(mesh);
this.mesh.updateBound();
}
}
this.setShadowMode(ShadowMode.Receive);
setMaterial(map.getMaterial());
if (mesh.getTriangleCount() > 0) {
if (chunkPhysicsNode != null) {
sharedParts.bulletPhysics.getPhysicsSpace().remove(chunkPhysicsNode);
}
chunkPhysicsNode = new RigidBodyControl(new MeshCollisionShape(mesh), 0);
this.controls.clear();
this.addControl(chunkPhysicsNode);
sharedParts.bulletPhysics.getPhysicsSpace().add(chunkPhysicsNode);
}
colors.clear();
vertices.clear();
texCoord.clear();
indexes.clear();
normals.clear();
needsRebuild = false;
}
private int[] checkSix(int x, int y, int z) {
boolean anyVisible = true;
int faces[] = new int[7];
for (int i = 0; i < faces.length; i++) {
faces[i] = 0;
}
int absX = ((this.x) * CHUNK_SIZE) + x;
int absZ = ((this.z) * CHUNK_SIZE) + z;
int absY = ((this.y) * CHUNK_SIZE) + y;
if (map.getBlock(absX, absZ, absY + 1) == 0) {
faces[TOP_FACE] = 1;
anyVisible = true;
}
if (map.getBlock(absX - 1, absZ, absY) == 0) {
faces[LEFT_FACE] = 1;
anyVisible = true;
}
if (map.getBlock(absX + 1, absZ, absY) == 0) {
faces[RIGHT_FACE] = 1;
anyVisible = true;
}
if (map.getBlock(absX, absZ - 1, absY) == 0) {
faces[BACK_FACE] = 1;
anyVisible = true;
}
if (map.getBlock(absX, absZ + 1, absY) == 0) {
faces[FRONT_FACE] = 1;
anyVisible = true;
}
if (map.getBlock(absX, absZ, absY - 1) == 0) {
faces[BOTTOM_FACE] = 1;
anyVisible = true;
}
if (anyVisible == true) {
faces[6] = 1;
} else {
faces[6] = 0;
}
return faces;
}
public byte getBlock(int x, int z, int y) {
return blocks[x][z][y];
}
public static int[] convertIntegers(ArrayList<Integer> integers) {
int[] ret = new int[integers.size()];
for (int i = 0; i < ret.length; i++) {
ret[i] = integers.get(i).intValue();
}
return ret;
}
public static float[] convertFloats(ArrayList<Vector4f> colors) {
float[] ret = new float[colors.size()*4];
for (int i = 0; i < colors.size(); i++) {
int i2 = i*4;
ret[i2] = colors.get(i).getX();
ret[i2+1] = colors.get(i).getY();
ret[i2+2] = colors.get(i).getZ();
ret[i2+3] = colors.get(i).getW();
}
return ret;
}
}
[/java]
Block.java
[java]
package mygame.map;
public class Block {
public final static byte EMPTY_BLOCK = 0;
public final static byte GRASS_BLOCK = 1;
public final static byte STONE_BLOCK = 2;
public final static byte DIRT_BLOCK = 3;
public final static byte ROCK_BLOCK = 4;
public final static byte WOOD_BLOCK = 5;
public static int[] getSpritePos(byte blockType) {
int[] sp = new int[2];
if (blockType == EMPTY_BLOCK) {
sp[0] = -1;
sp[1] = -1;
}
if (blockType == GRASS_BLOCK) {
sp[0] = 1;
sp[1] = 0;
}
if (blockType == DIRT_BLOCK) {
sp[0] = 4;
sp[1] = 0;
}
if (blockType == STONE_BLOCK) {
sp[0] = 0;
sp[1] = 0;
}
if (blockType == ROCK_BLOCK) {
sp[0] = 5;
sp[1] = 0;
}
if (blockType == WOOD_BLOCK) {
sp[0] = 6;
sp[1] = 0;
}
return sp;
}
}
[/java]