package Hexel.rendering;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import Hexel.Engine;
import Hexel.blocks.types.Block;
import Hexel.blocks.types.BlockEmpty;
import Hexel.blocks.types.BlockTransparent;
import Hexel.chunk.Chunk;
import Hexel.chunk.Chunks;
import Hexel.math.HexGeometry;
import Hexel.math.Vector2d;
import Hexel.math.Vector3i;
import Hexel.util.MutableFloat;
import Hexel.util.ResourcePool;
import com.jogamp.common.nio.Buffers;
public class GLChunk {
public ArrayList<MutableFloat> vertexData;
public List<MutableFloat> trimmedVertexData;
public Vector3i position;
public GLBuffer buffer;
public Chunk chunk;
public Chunks chunks;
private Engine engine;
public GLChunk(Engine engine, Chunk chunk, Chunks chunks) {
this.engine = engine;
this.chunk = chunk;
this.chunks = chunks;
}
public void initBuffer(GL2 gl) {
if (this.trimmedVertexData.size() == 0) {
this.buffer = null;
vertexDataPool.recycle(this.vertexData);
this.vertexData = null;
this.trimmedVertexData = null;
return;
}
int[] bufferId = new int[] { -1 };
gl.glGenBuffers(1, bufferId, 0);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, bufferId[0]);
gl.glBufferData(GL.GL_ARRAY_BUFFER, this.trimmedVertexData.size()
* Buffers.SIZEOF_FLOAT, null, GL.GL_DYNAMIC_DRAW);
ByteBuffer byteBuffer = gl.glMapBuffer(GL.GL_ARRAY_BUFFER,
GL.GL_WRITE_ONLY);
FloatBuffer buffer = byteBuffer.order(ByteOrder.nativeOrder()).asFloatBuffer();
for (MutableFloat aVertexData : this.trimmedVertexData) {
buffer.put(aVertexData.val);
}
gl.glUnmapBuffer(GL.GL_ARRAY_BUFFER);
this.buffer = new GLBuffer(bufferId, this.trimmedVertexData.size() * Buffers.SIZEOF_FLOAT);
vertexDataPool.recycle(this.vertexData);
this.vertexData = null;
this.trimmedVertexData = null;
}
private boolean display(Block b, Block o, Face face) {
double bfb = b.getFracBottom();
double bft = b.getFracTop();
double ofb = o.getFracBottom();
double oft = o.getFracTop();
return o instanceof BlockTransparent && o.getClass() != b.getClass()
|| face == Face.TOP && (ofb != 0 || bft != 1)
|| face == Face.BOTTOM && (oft != 1 || bfb != 0)
|| ofb < ofb || bft > oft;
}
private static ResourcePool<ArrayList<MutableFloat>> vertexDataPool =
new ResourcePool<ArrayList<MutableFloat>>((Class<ArrayList<MutableFloat>>) new ArrayList<MutableFloat>().getClass());
public void genArrayList() {
this.vertexData = vertexDataPool.aquire();
Vector2d a = new Vector2d();
Vector2d b = new Vector2d();
Vector2d c = new Vector2d();
Vector2d d = new Vector2d();
Vector3i tmp = new Vector3i();
Rect r = new Rect();
Color color = new Color();
int index = 0;
for (int x = 0; x < 32; x++) {
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 32; z++) {
Block block = this.chunk.get(x, y, z);
if (block instanceof BlockEmpty)
continue;
int px = x / 2;
if (x % 2 == 0) {
HexGeometry.hexToCartesian(px, y, a);
HexGeometry.hexToCartesian(px, y + 1, b);
HexGeometry.hexToCartesian(px + 1, y, c);
HexGeometry.hexToCartesian(px + 0.5, y + 0.5, d);
} else {
HexGeometry.hexToCartesian(px + 1, y + 1, a);
HexGeometry.hexToCartesian(px, y + 1, b);
HexGeometry.hexToCartesian(px + 1, y, c);
HexGeometry.hexToCartesian(px + 0.5, y + 0.5, d);
}
Block blockZP = this.chunks.getBlock(this.chunk.cx, this.chunk.cy,
this.chunk.cz, x, y, z + 1, tmp, chunk);
boolean displayZP = display(block, blockZP, Face.TOP);
Block blockZM = this.chunks.getBlock(this.chunk.cx, this.chunk.cy,
this.chunk.cz, x, y, z - 1, tmp, chunk);
boolean displayZM = display(block, blockZM, Face.BOTTOM);
// NOTE faces wrong but it doesn't matter here, see below
// for correct
Block blockXP = this.chunks.getBlock(this.chunk.cx, this.chunk.cy,
this.chunk.cz, x + 1, y, z, tmp, chunk);
boolean displayXP = display(block, blockXP, Face.SIDEA);
Block blockXM = this.chunks.getBlock(this.chunk.cx, this.chunk.cy,
this.chunk.cz, x - 1, y, z, tmp, chunk);
boolean displayXM = display(block, blockXM, Face.SIDEB);
Block blockYP = this.chunks.getBlock(this.chunk.cx, this.chunk.cy,
this.chunk.cz, x - 1, y + 1, z, tmp, chunk);
boolean displayYP = display(block, blockYP, Face.SIDEC);
Block blockYM = this.chunks.getBlock(this.chunk.cx, this.chunk.cy,
this.chunk.cz, x + 1, y - 1, z, tmp, chunk);
boolean displayYM = display(block, blockYM, Face.SIDEB);
double fracBottom = block.getFracBottom();
double fracTop = block.getFracTop();
double topz = z / 2.0 + .5 * fracTop;
double bottomz = z / 2.0 + .5 * fracBottom;
int damageOffset;
if (block.getMaxHealth() == 0)
damageOffset = 0;
else
damageOffset = 4 * (int) (5 * (1 - block.getHealth()*1.0 / block.getMaxHealth()));
if (damageOffset < 0)
damageOffset = 0;
else if (damageOffset > 4 * 4)
damageOffset = 4 * 4;
if (displayZM) {
getColor(block, blockZM, color, Face.BOTTOM, x);
getTexRect(damageOffset + block.getBottomTextureIndex(), r);
index = addVertexData(this.vertexData, index, a.x, a.y, bottomz, r.l, r.t,
color);
index = addVertexData(this.vertexData, index, b.x, b.y, bottomz, r.l, r.b,
color);
index = addVertexData(this.vertexData, index, d.x, d.y, bottomz, r.r, r.b,
color);
index = addVertexData(this.vertexData, index, a.x, a.y, bottomz, r.l, r.t,
color);
index = addVertexData(this.vertexData, index, c.x, c.y, bottomz, r.r, r.t,
color);
index = addVertexData(this.vertexData, index, d.x, d.y, bottomz, r.r, r.b,
color);
}
{
getTexRect(damageOffset + block.getSideTextureIndex(), r);
if (x % 2 == 1 && displayYP
|| x % 2 == 0 && displayXM) {
if (x % 2 == 1)
getColor(block, blockYP, color, Face.SIDEA, x);
else
getColor(block, blockXM, color, Face.SIDEA, x);
index = addVertexData(this.vertexData, index, a.x, a.y, bottomz, r.l,
r.t, color);
index = addVertexData(this.vertexData, index, b.x, b.y, bottomz, r.r,
r.t, color);
index = addVertexData(this.vertexData, index, a.x, a.y, topz, r.l, r.b,
color);
index = addVertexData(this.vertexData, index, b.x, b.y, bottomz, r.r,
r.t, color);
index = addVertexData(this.vertexData, index, a.x, a.y, topz, r.l, r.b,
color);
index = addVertexData(this.vertexData, index, b.x, b.y, topz, r.r, r.b,
color);
}
if (x % 2 == 1 && displayXP
|| x % 2 == 0 && displayYM) {
if (x % 2 == 1)
getColor(block, blockXP, color, Face.SIDEB, x);
else
getColor(block, blockYM, color, Face.SIDEB, x);
index = addVertexData(this.vertexData, index, a.x, a.y, bottomz, r.l,
r.t, color);
index = addVertexData(this.vertexData, index, c.x, c.y, bottomz, r.r,
r.t, color);
index = addVertexData(this.vertexData, index, a.x, a.y, topz, r.l, r.b,
color);
index = addVertexData(this.vertexData, index, c.x, c.y, bottomz, r.r,
r.t, color);
index = addVertexData(this.vertexData, index, a.x, a.y, topz, r.l, r.b,
color);
index = addVertexData(this.vertexData, index, c.x, c.y, topz, r.r, r.b,
color);
}
if (x % 2 == 1 && displayXM
|| x % 2 == 0 && displayXP) {
if (x % 2 == 1)
getColor(block, blockXM, color, Face.SIDEC, x);
else
getColor(block, blockXP, color, Face.SIDEC, x);
index = addVertexData(this.vertexData, index, b.x, b.y, bottomz, r.l,
r.t, color);
index = addVertexData(this.vertexData, index, c.x, c.y, bottomz, r.r,
r.t, color);
index = addVertexData(this.vertexData, index, b.x, b.y, topz, r.l, r.b,
color);
index = addVertexData(this.vertexData, index, c.x, c.y, bottomz, r.r,
r.t, color);
index = addVertexData(this.vertexData, index, b.x, b.y, topz, r.l, r.b,
color);
index = addVertexData(this.vertexData, index, c.x, c.y, topz, r.r, r.b,
color);
}
}
if (displayZP) {
getColor(block, blockZP, color, Face.TOP, x);
getTexRect(damageOffset + block.getTopTextureIndex(), r);
index = addVertexData(this.vertexData, index, a.x, a.y, topz, r.l, r.t,
color);
index = addVertexData(this.vertexData, index, b.x, b.y, topz, r.l, r.b,
color);
index = addVertexData(this.vertexData, index, d.x, d.y, topz, r.r, r.b,
color);
index = addVertexData(this.vertexData, index, a.x, a.y, topz, r.l, r.t,
color);
index = addVertexData(this.vertexData, index, c.x, c.y, topz, r.r, r.t,
color);
index = addVertexData(this.vertexData, index, d.x, d.y, topz, r.r, r.b,
color);
}
}
}
}
this.trimmedVertexData = this.vertexData.subList(0, index);
}
private class Rect {
public double l;
public double r;
public double t;
public double b;
}
public void getTexRect(int i, Rect r) {
double texW = 1.0 / TextureAtlas.HOR;
double texH = 1.0 / TextureAtlas.VER;
double texX = i % TextureAtlas.HOR * texW;
double texY = 1 - (i / TextureAtlas.HOR + 1) * texH;
r.l = texX;
r.r = texX + texW;
r.t = texY;
r.b = texY + texH;
}
public void getColor(Block block, Block neighbor, Color color, Face face,
int x) {
color.r = 1;
color.g = 1;
color.b = 1;
if (face == Face.TOP)
color.alpha = .2;
else if (face == Face.BOTTOM)
color.alpha = .0;
else {
if (face == Face.SIDEA && x % 2 == 0)
color.alpha = .15;
else if (face == Face.SIDEA && x % 2 == 1)
color.alpha = .12;
else if (face == Face.SIDEC && x % 2 == 0) {
color.alpha = .07;
} else if (face == Face.SIDEB && x % 2 == 1) {
color.alpha = .03;
} else if (face == Face.SIDEB && x % 2 == 0) {
color.alpha = .05;
} else if (face == Face.SIDEC && x % 2 == 1)
color.alpha = .1;
}
if (neighbor instanceof BlockTransparent){
double neighborLightLevel = ((BlockTransparent)neighbor).getLightLevel();
double lightLevel = engine.getAmbientLight() - neighborLightLevel*1.0/BlockTransparent.MAX_LIGHT_LEVEL;
if (lightLevel < .1)
lightLevel = .1;
double lightAlpha = 1-lightLevel;
double colorAlpha = (1-lightAlpha)*(1-lightAlpha)*(1-lightAlpha);
color.r = color.r*colorAlpha + 0;
color.g = color.g*colorAlpha + 0;
color.b = color.b*colorAlpha + 0;
color.alpha += (1-color.alpha)*lightAlpha;
}
}
public int addVertexData(ArrayList<MutableFloat> list, int index, double x, double y,
double z, double tx, double ty, Color c) {
while (index+9 >= list.size())
list.add(new MutableFloat());
list.get(index+0).val = (float)x;
list.get(index+1).val = (float)y;
list.get(index+2).val = (float)z;
list.get(index+3).val = (float)tx;
list.get(index+4).val = (float)ty;
list.get(index+5).val = (float)c.r;
list.get(index+6).val = (float)c.g;
list.get(index+7).val = (float)c.b;
list.get(index+8).val = (float)c.alpha;
return index+9;
}
}