diff --git a/src/main/java/de/bixilon/minosoft/render/WorldRenderer.java b/src/main/java/de/bixilon/minosoft/render/WorldRenderer.java index 015db9c41..771951cd4 100644 --- a/src/main/java/de/bixilon/minosoft/render/WorldRenderer.java +++ b/src/main/java/de/bixilon/minosoft/render/WorldRenderer.java @@ -18,28 +18,26 @@ import de.bixilon.minosoft.game.datatypes.objectLoader.blocks.Blocks; import de.bixilon.minosoft.game.datatypes.world.*; import de.bixilon.minosoft.logging.Log; import de.bixilon.minosoft.render.blockModels.BlockModelLoader; +import de.bixilon.minosoft.render.blockModels.Face; import de.bixilon.minosoft.render.fullFace.FaceOrientation; -import de.bixilon.minosoft.render.fullFace.FullFacePosition; -import de.bixilon.minosoft.render.fullFace.RenderConstants; import de.bixilon.minosoft.render.texture.TextureLoader; -import javafx.util.Pair; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; -import static de.bixilon.minosoft.render.fullFace.RenderConstants.UV; import static de.bixilon.minosoft.render.fullFace.RenderConstants.faceDir; import static org.lwjgl.opengl.GL11.*; public class WorldRenderer { private final TextureLoader textureLoader; - private final HashMap> faces; + private final HashMap> faces; private final int faceCount = 0; private BlockModelLoader modelLoader; public WorldRenderer() { textureLoader = new TextureLoader(MainWindow.getOpenGLWindow().getWindow()); - faces = new HashMap>(); + faces = new HashMap<>(); } public void init() { @@ -67,67 +65,34 @@ public class WorldRenderer { } public void prepareBlock(BlockPosition position, Block block) { - if (block == Blocks.nullBlock) - return; + if (block.equals(Blocks.nullBlock)) + faces.put(position, null); + HashMap adjacentBlocks = new HashMap<>(); for (FaceOrientation orientation : FaceOrientation.values()) { BlockPosition neighbourPos = position.add(faceDir[orientation.getId()]); if (neighbourPos.getY() >= 0) { Block neighbourBlock = MainWindow.getConnection().getPlayer().getWorld().getBlock(neighbourPos); - if (!(neighbourBlock == Blocks.nullBlock || neighbourBlock == null)) //!modelLoader.isFull(neighbourBlock)) - // if there is a block next to the current block, don't draw the face - continue; - //TODO: fix buggy behavior, not always working correctly, probably a problem in the World or BlockPosition class + boolean isNeighbourFull = modelLoader.isFull(neighbourBlock); + adjacentBlocks.put(orientation, isNeighbourFull); + } else { + adjacentBlocks.put(orientation, false); } - /* - FullFacePosition facePosition = new FullFacePosition(position, orientation); - Pair texture = modelLoader.getBlockDescription(block).getTexture(orientation); - if (!faces.containsKey(facePosition)) { - synchronized (faces) { - faces.put(facePosition, texture); - } - } - */ + } + synchronized (faces) { + faces.put(position, modelLoader.getBlockDescription(block).prepare(adjacentBlocks)); } } public void draw() { glPushMatrix(); - /* - glBindBuffer(GL_ARRAY_BUFFER, vbo); - float[] floatArray = vertices.toArray(); - glBufferData(GL_ARRAY_BUFFER, - (FloatBuffer) BufferUtils.createFloatBuffer(vertices.size()).put( - floatArray).flip(), GL_STATIC_DRAW); - - glBindTexture(GL_TEXTURE_2D, textureLoader.getTextureID()); - glVertexPointer(3, GL_FLOAT, 28, 0L); - glTexCoordPointer(2, GL_FLOAT,28, 0L); - glDrawArrays(GL_QUADS, 0, floatArray.length); - */ glBindTexture(GL_TEXTURE_2D, textureLoader.getTextureID()); glBegin(GL_QUADS); synchronized (faces) { - for (Map.Entry> entry : faces.entrySet()) { - float[][] vertPositions = RenderConstants.FACE_VERTEX[entry.getKey().getFaceOrientation().getId()]; - - for (int vert = 0; vert < 4; vert++) { - float u = 0; - switch (UV[vert][0]) { - case 0: - u = entry.getValue().getKey(); - break; - case 1: - u = entry.getValue().getValue(); - break; - } - float x = vertPositions[vert][0] + entry.getKey().getBlockPosition().getX(); - float y = vertPositions[vert][1] + entry.getKey().getBlockPosition().getY(); - float z = vertPositions[vert][2] + entry.getKey().getBlockPosition().getZ(); - - glTexCoord2f(u, UV[vert][1]); - glVertex3f(x, y, z); + for (Map.Entry> entry : faces.entrySet()) { + for (Face face : entry.getValue()) { + face.draw(entry.getKey()); } } } diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/BlockDescription.java b/src/main/java/de/bixilon/minosoft/render/blockModels/BlockDescription.java index 32535c629..da4abeb94 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/BlockDescription.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/BlockDescription.java @@ -16,6 +16,7 @@ package de.bixilon.minosoft.render.blockModels; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import de.bixilon.minosoft.Config; +import de.bixilon.minosoft.render.fullFace.FaceOrientation; import java.io.IOException; import java.util.HashMap; @@ -68,4 +69,12 @@ public class BlockDescription { public boolean isFull() { return isFull; } + + public HashSet prepare(HashMap adjacentBlocks) { + HashSet result = new HashSet<>(); + for (SubBlock subBlock : subBlocks) { + result.addAll(subBlock.getFaces(adjacentBlocks)); + } + return result; + } } diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/BlockModelLoader.java b/src/main/java/de/bixilon/minosoft/render/blockModels/BlockModelLoader.java index afae06fca..f25ee1444 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/BlockModelLoader.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/BlockModelLoader.java @@ -368,6 +368,7 @@ public class BlockModelLoader { String path = Config.homeDir + "assets/" + mod + "/models/block/" + identifier + ".json"; JsonObject json = readJsonFromFile(path); BlockDescription description = new BlockDescription(json); + blockDescriptionMap.put(mod + ":" + identifier, description); //Log.info("Loaded model for " + mod + ":" + identifier); } catch (IOException e) { Log.debug("could not load block model for block " + mod + ":" + identifier); @@ -380,8 +381,10 @@ public class BlockModelLoader { } public BlockDescription getBlockDescription(Block block) { - if (!blockDescriptionMap.containsKey(block)) { - throw new IllegalArgumentException(String.format("No description for block %s found", block)); + String blockName = block.getMod() + ":" + block.getIdentifier(); + if (!blockDescriptionMap.containsKey(blockName)) { + System.out.println(String.format("No description for block %s found", blockName)); + System.exit(-1); } return blockDescriptionMap.get(block.getMod() + ":" + block.getIdentifier()); } diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/Face.java b/src/main/java/de/bixilon/minosoft/render/blockModels/Face.java new file mode 100644 index 000000000..6cfd8e453 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/Face.java @@ -0,0 +1,137 @@ +/* + * Codename Minosoft + * Copyright (C) 2020 Moritz Zwerger + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.render.blockModels; + +import de.bixilon.minosoft.game.datatypes.world.BlockPosition; +import de.bixilon.minosoft.render.MainWindow; +import de.bixilon.minosoft.render.fullFace.FaceOrientation; +import de.bixilon.minosoft.render.fullFace.InFaceUV; +import javafx.util.Pair; + +import static de.bixilon.minosoft.render.fullFace.RenderConstants.blockRes; +import static de.bixilon.minosoft.render.fullFace.RenderConstants.texturePackRes; +import static org.lwjgl.opengl.GL11.glTexCoord2f; +import static org.lwjgl.opengl.GL11.glVertex3f; + +public class Face { + FaceOrientation orientation; + Pair texture; + InFaceUV uv; + SubBlock subBlock; + + public Face(FaceOrientation orientation, Pair texture, InFaceUV uv, SubBlock subBlock) { + this.orientation = orientation; + this.texture = texture; + this.uv = uv; + this.subBlock = subBlock; + } + + public void draw(BlockPosition pos) { + float x1 = 0, y1 = 0, z1 = 0, x2 = 0, y2 = 0, z2 = 0; + float step = MainWindow.getRenderer().getTextureLoader().getStep(); + float u1 = texture.getKey() + (float) uv.u1 / (float) blockRes * step; + float u2 = texture.getValue() + (float) uv.u1 / (float) blockRes * step; + float v1 = (float) uv.v1 / (float) texturePackRes; + float v2 = (float) uv.v2 / (float) texturePackRes; + + switch (orientation) { + case EAST: + x1 = x2 = subBlock.pos2.x; + y1 = subBlock.pos1.y; + y2 = subBlock.pos2.y; + z1 = subBlock.pos1.z; + z2 = subBlock.pos2.z; + break; + case WEST: + x1 = x2 = subBlock.pos1.x; + y1 = subBlock.pos1.y; + y2 = subBlock.pos2.y; + z1 = subBlock.pos1.z; + z2 = subBlock.pos2.z; + break; + case UP: + y1 = y2 = subBlock.pos2.y; + x1 = subBlock.pos1.x; + x2 = subBlock.pos2.x; + z1 = subBlock.pos1.z; + z2 = subBlock.pos2.z; + break; + case DOWN: + y1 = y2 = subBlock.pos1.y; + x1 = subBlock.pos1.x; + x2 = subBlock.pos2.x; + z1 = subBlock.pos1.z; + z2 = subBlock.pos2.z; + break; + case SOUTH: + z1 = z2 = subBlock.pos2.z; + x1 = subBlock.pos1.x; + x2 = subBlock.pos2.x; + y1 = subBlock.pos1.y; + y2 = subBlock.pos2.y; + break; + case NORTH: + z1 = z2 = subBlock.pos1.z; + x1 = subBlock.pos1.x; + x2 = subBlock.pos2.x; + y1 = subBlock.pos1.y; + y2 = subBlock.pos2.y; + break; + } + switch (orientation) { + case EAST: + case WEST: + glTexCoord2f(u1, v1); + glVertex3f(x1, y1, z1); + + glTexCoord2f(u2, v1); + glVertex3f(x1, y2, z1); + + glTexCoord2f(u2, v2); + glVertex3f(x1, y2, z2); + + glTexCoord2f(u2, v2); + glVertex3f(x1, y2, z2); + break; + case UP: + case DOWN: + glTexCoord2f(u1, v1); + glVertex3f(x1, y1, z1); + + glTexCoord2f(u2, v1); + glVertex3f(x2, y1, z1); + + glTexCoord2f(u2, v2); + glVertex3f(x2, y1, z2); + + glTexCoord2f(u2, v2); + glVertex3f(x1, y1, z2); + break; + case NORTH: + case SOUTH: + glTexCoord2f(u1, v1); + glVertex3f(x1, y1, z1); + + glTexCoord2f(u2, v1); + glVertex3f(x2, y1, z1); + + glTexCoord2f(u2, v2); + glVertex3f(x2, y2, z1); + + glTexCoord2f(u2, v2); + glVertex3f(x1, y2, z1); + break; + } + } +} diff --git a/src/main/java/de/bixilon/minosoft/render/blockModels/SubBlock.java b/src/main/java/de/bixilon/minosoft/render/blockModels/SubBlock.java index ff70238aa..6e8259580 100644 --- a/src/main/java/de/bixilon/minosoft/render/blockModels/SubBlock.java +++ b/src/main/java/de/bixilon/minosoft/render/blockModels/SubBlock.java @@ -20,13 +20,14 @@ import de.bixilon.minosoft.render.fullFace.InFaceUV; import javafx.util.Pair; import java.util.HashMap; +import java.util.HashSet; public class SubBlock { SubBlockPosition pos1; // the most negative Point of the SubBlock SubBlockPosition pos2; // the most positive Point of the SubBlock HashMap> textures; - HashMap> cullFaceTextures; + HashMap cullFaceTextures; HashMap uv; @@ -46,24 +47,7 @@ public class SubBlock { } } - private void applyTexture(JsonObject faceJson, FaceOrientation orientation, HashMap variables) { - try { - uv.put(orientation, new InFaceUV(faceJson.getAsJsonArray("uv"))); - } catch (Exception e) { - uv.put(orientation, new InFaceUV()); - } - - String textureName = getRealTextureName(faceJson.get("texture").getAsString(), variables); - Pair texture = MainWindow.getRenderer().getTextureLoader().getTexture(textureName); - - if (faceJson.has("cullface")) { - cullFaceTextures.put(orientation, texture); - } else { - textures.put(orientation, texture); - } - } - - private String getRealTextureName(String textureName, HashMap variables) { + private static String getRealTextureName(String textureName, HashMap variables) { if (textureName.contains("#")) { if (variables.containsKey(textureName)) { String newName = variables.get(textureName); @@ -81,4 +65,33 @@ public class SubBlock { return textureName; } } + + private void applyTexture(JsonObject faceJson, FaceOrientation orientation, HashMap variables) { + try { + uv.put(orientation, new InFaceUV(faceJson.getAsJsonArray("uv"))); + } catch (Exception e) { + uv.put(orientation, new InFaceUV()); + } + + String textureName = getRealTextureName(faceJson.get("texture").getAsString(), variables); + Pair texture = MainWindow.getRenderer().getTextureLoader().getTexture(textureName); + + cullFaceTextures.put(orientation, faceJson.has("cullface")); + + textures.put(orientation, texture); + } + + public HashSet getFaces(HashMap adjacentBlocks) { + HashSet result = new HashSet<>(); + for (FaceOrientation orientation : FaceOrientation.values()) { + if (!textures.containsKey(orientation)) { + continue; + } + if (!(adjacentBlocks.get(orientation) && cullFaceTextures.get(orientation))) { + result.add(new Face(orientation, textures.get(orientation), + uv.get(orientation), this)); + } + } + return result; + } } diff --git a/src/main/java/de/bixilon/minosoft/render/fullFace/InFaceUV.java b/src/main/java/de/bixilon/minosoft/render/fullFace/InFaceUV.java index 1c0ecc164..39b660f01 100644 --- a/src/main/java/de/bixilon/minosoft/render/fullFace/InFaceUV.java +++ b/src/main/java/de/bixilon/minosoft/render/fullFace/InFaceUV.java @@ -16,7 +16,7 @@ package de.bixilon.minosoft.render.fullFace; import com.google.gson.JsonArray; public class InFaceUV { - int u1, v1, u2, v2; + public int u1, v1, u2, v2; public InFaceUV(JsonArray json) { u1 = json.get(0).getAsInt(); diff --git a/src/main/java/de/bixilon/minosoft/render/fullFace/RenderConstants.java b/src/main/java/de/bixilon/minosoft/render/fullFace/RenderConstants.java index fcd96b51e..6a849e45b 100644 --- a/src/main/java/de/bixilon/minosoft/render/fullFace/RenderConstants.java +++ b/src/main/java/de/bixilon/minosoft/render/fullFace/RenderConstants.java @@ -14,7 +14,10 @@ package de.bixilon.minosoft.render.fullFace; public class RenderConstants { - //TODO: fix rotated faces + public static final int texturePackRes = 16; + + public static final int blockRes = 16; + public static final float[][][] FACE_VERTEX = new float[][][]{ { {1, 0, 0}, diff --git a/src/main/java/de/bixilon/minosoft/render/texture/TextureLoader.java b/src/main/java/de/bixilon/minosoft/render/texture/TextureLoader.java index 3f7d4d064..2fcb16fd3 100644 --- a/src/main/java/de/bixilon/minosoft/render/texture/TextureLoader.java +++ b/src/main/java/de/bixilon/minosoft/render/texture/TextureLoader.java @@ -38,6 +38,7 @@ public class TextureLoader { private final int TEXTURE_PACK_RES = 16; private HashMap textureCoordinates; int imageLength = 1; + float step; public TextureLoader(long window) { try { @@ -143,6 +144,7 @@ public class TextureLoader { } catch (IOException e) { e.printStackTrace(); } + step = (float) 1 / (float) imageLength; } private int bindTexture(ByteBuffer buf, int width, int height) { @@ -183,4 +185,8 @@ public class TextureLoader { public int getTextureID() { return textureID; } + + public float getStep() { + return step; + } }