aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/makamys/neodymium/renderer/SimpleChunkMesh.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/makamys/neodymium/renderer/SimpleChunkMesh.java')
-rw-r--r--src/main/java/makamys/neodymium/renderer/SimpleChunkMesh.java350
1 files changed, 350 insertions, 0 deletions
diff --git a/src/main/java/makamys/neodymium/renderer/SimpleChunkMesh.java b/src/main/java/makamys/neodymium/renderer/SimpleChunkMesh.java
new file mode 100644
index 0000000..964dec8
--- /dev/null
+++ b/src/main/java/makamys/neodymium/renderer/SimpleChunkMesh.java
@@ -0,0 +1,350 @@
+package makamys.neodymium.renderer;
+
+import static org.lwjgl.opengl.GL11.GL_FLOAT;
+import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER;
+import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER;
+import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW;
+import static org.lwjgl.opengl.GL15.glBufferData;
+import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray;
+import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
+
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.util.Arrays;
+import java.util.List;
+
+import org.lwjgl.BufferUtils;
+
+import makamys.neodymium.LODMod;
+import makamys.neodymium.util.MCUtil;
+import net.minecraft.block.Block;
+import net.minecraft.block.BlockGrass;
+import net.minecraft.block.BlockLeaves;
+import net.minecraft.block.material.Material;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+import net.minecraft.client.renderer.texture.TextureMap;
+import net.minecraft.entity.Entity;
+import net.minecraft.init.Blocks;
+import net.minecraft.nbt.NBTTagString;
+import net.minecraft.util.IIcon;
+import net.minecraft.world.biome.BiomeGenBase;
+import net.minecraft.world.chunk.Chunk;
+
+public class SimpleChunkMesh extends Mesh {
+
+ private FloatBuffer vertices;
+
+ public static int usedRAM;
+ public static int instances;
+ public static int divisions = 4;
+
+ private static boolean isSolid(Block block) {
+ return block.isBlockNormalCube() && block.isOpaqueCube() && block.renderAsNormalBlock();
+ }
+
+ private static boolean isBad(Block block) {
+ for(Class clazz : LODMod.blockClassBlacklist) {
+ if(clazz.isInstance(block)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static List<SimpleChunkMesh> generateSimpleMeshes(Chunk target){
+ SimpleChunkMesh pass1 = new SimpleChunkMesh(target.xPosition, target.zPosition, divisions * divisions * 25, 0);
+ SimpleChunkMesh pass2 = new SimpleChunkMesh(target.xPosition, target.zPosition, divisions * divisions * 25, 1);
+
+ SimpleChunkMeshBuilder builder = new SimpleChunkMeshBuilder();
+
+ for(int divX = 0; divX < divisions; divX++) {
+ for(int divZ = 0; divZ < divisions; divZ++) {
+ IIcon icon = null;
+ int color = 0xFFFFFFFF;
+ int size = 16 / divisions;
+ int y = 255;
+ boolean foundWater = false;
+
+ int xOff = divX * size;
+ int zOff = divZ * size;
+
+ int biomeId = target.getBiomeArray()[xOff << 4 | zOff] & 255;
+ if(biomeId == 255) {
+ System.out.println("Missing biome data for chunk " + target.xPosition + ", " + target.zPosition);
+ }
+ BiomeGenBase biome = BiomeGenBase.getBiome(biomeId) == null ? BiomeGenBase.plains : BiomeGenBase.getBiome(biomeId);
+
+ for(y = 255; y > 0; y--) {
+ Block block = target.getBlock(xOff, y, zOff);
+
+ int worldX = target.xPosition * 16 + divX * size;
+ int worldY = y;
+ int worldZ = target.zPosition * 16 + divZ * size;
+
+ if(!foundWater && block.getMaterial() == Material.water) {
+ foundWater = true;
+ int meta = target.getBlockMetadata(xOff, y, zOff);
+ IIcon waterIcon = block.getIcon(1, meta);
+
+ int waterColor = biome.getWaterColorMultiplier();
+ waterColor |= 0xFF000000;
+ pass2.addFaceYPos(worldX, worldY, worldZ, size, size, waterIcon, waterColor, 1);
+ }
+
+ if(isSolid(block) && isBad(block)) {
+ for(int dx = -1; dx <= 1; dx++) {
+ for(int dz = -1; dz <= 1; dz++) {
+ int newX = xOff + dx;
+ int newZ = zOff + dz;
+ if(newX >= 0 && newX < 16 && newZ >= 0 && newZ < 16) {
+ Block newBlock = target.getBlock(newX, y, newZ);
+ if(!isBad(newBlock)) {
+ xOff += dx;
+ zOff += dz;
+ worldX += dx;
+ worldZ += dz;
+ block = newBlock;
+ }
+ }
+ }
+ }
+ }
+ if(isSolid(block)) {
+
+ float brightnessMult = foundWater ? 0.2f : 1f;
+ int meta = target.getBlockMetadata(xOff, y, zOff);
+ icon = block.getIcon(1, meta);
+
+ if(block instanceof BlockGrass) {
+ color = biome.getBiomeGrassColor(worldX, y, worldZ);
+ } else if(block instanceof BlockLeaves) {
+ color = biome.getBiomeFoliageColor(worldX, y, worldZ);
+ } else {
+ color = block.colorMultiplier(Minecraft.getMinecraft().theWorld, worldX, y, worldZ);
+ }
+ color = (0xFF << 24) | ((color >> 16 & 0xFF) << 0) | ((color >> 8 & 0xFF) << 8) | ((color >> 0 & 0xFF) << 16);
+
+ if((LODMod.forceVanillaBiomeTemperature ? MCUtil.getBiomeTemperatureVanilla(biome, worldX, y, worldZ)
+ : biome.getFloatTemperature(worldX, y, worldZ)) < 0.15f) {
+
+ builder.addCube(divX, divZ, worldY + 0.2f, 1f, Blocks.snow_layer.getIcon(1, 0), 0xFFFFFFFF, brightnessMult);
+ builder.addCube(divX, divZ, worldY - 0.8f, -1, icon, color, brightnessMult);
+ } else {
+ builder.addCube(divX, divZ, worldY, -1, icon, color, brightnessMult);
+ }
+
+
+ break;
+ }
+ }
+ }
+ }
+
+ builder.render(pass1, target.xPosition, target.zPosition);
+
+ pass1.finish();
+ pass2.finish();
+
+ return Arrays.asList(new SimpleChunkMesh[] {pass1.quadCount != 0 ? pass1 : null, pass2.quadCount != 0 ? pass2 : null});
+ }
+
+ private static class SimpleChunkMeshBuilder {
+ int maxIconsPerColumn = 2;
+ float[][][] heights = new float[divisions][divisions][maxIconsPerColumn];
+ float[][][] depths = new float[divisions][divisions][maxIconsPerColumn];
+ IIcon[][][] icons = new IIcon[divisions][divisions][maxIconsPerColumn];
+ int[][][] colors = new int[divisions][divisions][maxIconsPerColumn];
+ float[][][] brightnessMults = new float[divisions][divisions][maxIconsPerColumn];
+
+ public void addCube(int x, int z, float height, float depth, IIcon icon, int color, float brightnessMult) {
+ IIcon[] iconz = icons[x][z];
+ int i = iconz[0] == null ? 0 : 1;
+ if(iconz[0] != null && iconz[1] != null) {
+ throw new IllegalStateException("Too many icons in column");
+ }
+
+ heights[x][z][i] = height;
+ depths[x][z][i] = depth;
+ icons[x][z][i] = icon;
+ colors[x][z][i] = color;
+ brightnessMults[x][z][i] = brightnessMult;
+ }
+
+ public void render(SimpleChunkMesh mesh, int chunkX, int chunkZ) {
+ float size = 16 / divisions;
+
+ for(int x = 0; x < divisions; x++) {
+ for(int z = 0; z < divisions; z++) {
+ float worldX = chunkX * 16 + x * size;
+ float worldZ = chunkZ * 16 + z * size;
+ for(int i = 0; i < maxIconsPerColumn; i++) {
+ IIcon icon = icons[x][z][i];
+ if(icon != null) {
+ float height = heights[x][z][i];
+ float depthValue = depths[x][z][i];
+ float depth = depthValue == -1 ? height : depthValue;
+ int color = colors[x][z][i];
+ float brightnessMult = brightnessMults[x][z][i];
+
+ if(i == 0) {
+ mesh.addFaceYPos(worldX, height, worldZ, size, size, icon, color, brightnessMult);
+ }
+ float heightX0 = x > 0 ? heights[x - 1][z][0] : 0;
+ if(heightX0 < height) {
+ mesh.addFaceX2(worldX, height, worldZ, Math.min(depth, height - heightX0), size, icon, color, brightnessMult);
+ }
+
+ float heightX1 = x < divisions - 1 ? heights[x + 1][z][0] : 0;
+ if(heightX1 < height) {
+ mesh.addFaceX1(worldX + size, height, worldZ, Math.min(depth, height - heightX1), size, icon, color, brightnessMult);
+ }
+
+ float heightZ0 = z > 0 ? heights[x][z - 1][0] : 0;
+ if(heightZ0 < height) {
+ mesh.addFaceZ1(worldX, height, worldZ, size, Math.min(depth, height - heightZ0), icon, color, brightnessMult);
+ }
+
+ float heightZ1 = z < divisions - 1 ? heights[x][z + 1][0] : 0;
+ if(heightZ1 < height) {
+ mesh.addFaceZ2(worldX, height, worldZ + size, size, Math.min(depth, height - heightZ1), icon, color, brightnessMult);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public SimpleChunkMesh(int x, int z, int maxQuads, int pass) {
+ this.x = x;
+ this.y = 64;
+ this.z = z;
+ this.pass = pass;
+
+ buffer = BufferUtils.createByteBuffer(4 * 6 * 7 * maxQuads);
+ vertices = buffer.asFloatBuffer();
+ }
+
+ public void finish() {
+ vertices.flip();
+ buffer.limit(vertices.limit() * 4);
+
+ // may want to shrink the buffers to actual size to not waste memory
+
+ usedRAM += buffer.limit();
+ instances++;
+ }
+
+ private void addCube(float x, float y, float z, float sizeX, float sizeZ, float sizeY, IIcon icon, int color, float brightnessMult) {
+ addFaceYPos(x, y, z, sizeX, sizeZ, icon, color, brightnessMult);
+ addFaceZ1(x, y, z, sizeX, sizeY, icon, color, brightnessMult);
+ addFaceZ2(x, y, z + sizeZ, sizeX, sizeY, icon, color, brightnessMult);
+ addFaceX1(x + sizeX, y, z, sizeX, sizeY, icon, color, brightnessMult);
+ addFaceX2(x, y, z, sizeX, sizeY, icon, color, brightnessMult);
+ }
+
+ private void addFaceZ1(float x, float y, float z, float sizeX, float sizeY, IIcon icon, int color, float brightnessMult) {
+ addFace(
+ x + 0, y - sizeY, z + 0,
+ x + 0, y + 0, z + 0,
+ x + sizeX, y + 0, z + 0,
+ x + sizeX, y - sizeY, z + 0,
+ icon, color, (int)(200 * brightnessMult)
+ );
+ }
+
+ private void addFaceZ2(float x, float y, float z, float sizeX, float sizeY, IIcon icon, int color, float brightnessMult) {
+ addFace(
+ x + sizeX, y - sizeY, z,
+ x + sizeX, y + 0, z,
+ x + 0, y + 0, z,
+ x + 0, y - sizeY, z,
+ icon, color, (int)(200 * brightnessMult)
+ );
+ }
+
+ private void addFaceX1(float x, float y, float z, float sizeY, float sizeZ, IIcon icon, int color, float brightnessMult) {
+ addFace(
+ x, y - sizeY, z + 0,
+ x, y + 0, z + 0,
+ x, y + 0, z + sizeZ,
+ x, y - sizeY, z + sizeZ,
+ icon, color, (int)(160 * brightnessMult)
+ );
+ }
+
+ private void addFaceX2(float x, float y, float z, float sizeY, float sizeZ, IIcon icon, int color, float brightnessMult) {
+ addFace(
+ x + 0, y - sizeY, z + sizeZ,
+ x + 0, y + 0, z + sizeZ,
+ x + 0, y + 0, z + 0,
+ x + 0, y - sizeY, z + 0,
+ icon, color, (int)(160 * brightnessMult)
+ );
+ }
+
+ private void addFaceYPos(float x, float y, float z, float sizeX, float sizeZ, IIcon icon, int color, float brightnessMult) {
+ addFace(
+ x + 0, y + 0, z + 0,
+ x + 0, y + 0, z + sizeZ,
+ x + sizeX, y + 0, z + sizeZ,
+ x + sizeX, y + 0, z + 0,
+ icon, color, (int)(240 * brightnessMult)
+ );
+ }
+
+ private void addFace(float p1x, float p1y, float p1z,
+ float p2x, float p2y, float p2z,
+ float p3x, float p3y, float p3z,
+ float p4x, float p4y, float p4z,
+ IIcon icon, int color, int brightness) {
+ int off = vertices.position() * 4;
+ vertices.put(new float[] {
+ p1x, p1y, p1z, icon.getMinU(), icon.getMaxV(), 0, 0,
+ p2x, p2y, p2z, icon.getMinU(), icon.getMinV(), 0, 0,
+ p4x, p4y, p4z, icon.getMaxU(), icon.getMaxV(), 0, 0,
+ p2x, p2y, p2z, icon.getMinU(), icon.getMinV(), 0, 0,
+ p3x, p3y, p3z, icon.getMaxU(), icon.getMinV(), 0, 0,
+ p4x, p4y, p4z, icon.getMaxU(), icon.getMaxV(), 0, 0
+ });
+ buffer.putInt(off + 0 * getStride() + 6 * 4, color);
+ buffer.putShort(off + 0 * getStride() + 5 * 4 + 2, (short)brightness);
+ buffer.putInt(off + 1 * getStride() + 6 * 4, color);
+ buffer.putShort(off + 1 * getStride() + 5 * 4 + 2, (short)brightness);
+ buffer.putInt(off + 2 * getStride() + 6 * 4, color);
+ buffer.putShort(off + 2 * getStride() + 5 * 4 + 2, (short)brightness);
+ buffer.putInt(off + 3 * getStride() + 6 * 4, color);
+ buffer.putShort(off + 3 * getStride() + 5 * 4 + 2, (short)brightness);
+ buffer.putInt(off + 4 * getStride() + 6 * 4, color);
+ buffer.putShort(off + 4 * getStride() + 5 * 4 + 2, (short)brightness);
+ buffer.putInt(off + 5 * getStride() + 6 * 4, color);
+ buffer.putShort(off + 5 * getStride() + 5 * 4 + 2, (short)brightness);
+
+ quadCount++;
+ }
+
+ public int getStride() {
+ return (3 * 4 + 8 + 4 + 4);
+ }
+
+ public void destroy() {
+ usedRAM -= buffer.limit();
+ instances--;
+ }
+
+ public static void prepareFarChunkOnServer(Chunk chunk) {
+ for(int divX = 0; divX < divisions; divX++) {
+ for(int divZ = 0; divZ < divisions; divZ++) {
+ int size = 16 / divisions;
+
+ int xOff = divX * size;
+ int zOff = divZ * size;
+
+ chunk.getBiomeGenForWorldCoords(xOff, zOff, chunk.worldObj.getWorldChunkManager());
+ }
+ }
+ }
+
+}