aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/tectech/util/StructureVBO.java
blob: 2b07d066431c060232640284c96cb016440e67fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package tectech.util;

import java.util.HashMap;
import java.util.HashSet;

import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.init.Blocks;

import org.apache.commons.lang3.tuple.Pair;

import com.gtnewhorizon.gtnhlib.client.renderer.CapturingTessellator;
import com.gtnewhorizon.gtnhlib.client.renderer.TessellatorManager;
import com.gtnewhorizon.gtnhlib.client.renderer.vbo.VertexBuffer;
import com.gtnewhorizon.gtnhlib.client.renderer.vertex.DefaultVertexFormat;

public class StructureVBO {

    private String[][] structure;

    private final HashSet<Character> values = new HashSet<>();
    private final HashMap<Character, Pair<Block, Integer>> mapper = new HashMap<>();

    public StructureVBO assignStructure(String[][] structure) {
        this.structure = structure;
        return this;
    }

    public StructureVBO addMapping(char letter, Block block) {
        mapper.put(letter, Pair.of(block, 0));
        return this;
    }

    public StructureVBO addMapping(char letter, Block block, int meta) {
        mapper.put(letter, Pair.of(block, meta));
        return this;
    }

    public TextureUpdateRequester getTextureUpdateRequestor() {
        TextureUpdateRequester textureUpdateRequester = new TextureUpdateRequester();
        for (char key : mapper.keySet()) {
            Pair<Block, Integer> pair = mapper.get(key);
            textureUpdateRequester.add(pair.getLeft(), pair.getRight());
        }
        return textureUpdateRequester;
    }

    private boolean isOpaqueAt(int x, int y, int z) {
        char letter = structure[x][y].charAt(z);
        if (letter == ' ') return false;
        Pair<Block, Integer> info = mapper.get(letter);
        if (info == null) return false;
        if (info.getLeft() == Blocks.air) return false;
        return info.getLeft()
            .isOpaqueCube();
    }

    private FaceVisibility getVisibleFaces(int x, int y, int z) {
        FaceVisibility visibility = new FaceVisibility();
        int maxX = structure.length - 1;
        int maxY = structure[0].length - 1;
        int maxZ = structure[0][0].length() - 1;
        // X is ordered from left to right
        if ((x > 0) && (isOpaqueAt(x - 1, y, z))) visibility.left = false;
        if ((x < maxX) && (isOpaqueAt(x + 1, y, z))) visibility.right = false;
        // Y is ordered from top to bottom
        if ((y > 0) && (isOpaqueAt(x, y - 1, z))) visibility.top = false;
        if ((y < maxY) && (isOpaqueAt(x, y + 1, z))) visibility.bottom = false;
        // Z is ordered from front to back
        if ((z > 0) && (isOpaqueAt(x, y, z - 1))) visibility.back = false;
        if ((z < maxZ) && (isOpaqueAt(x, y, z + 1))) visibility.front = false;
        return visibility;
    }

    public VertexBuffer build() {
        TessellatorManager.startCapturing();
        CapturingTessellator tess = (CapturingTessellator) TessellatorManager.get();
        FaceCulledRenderBlocks renderer = new FaceCulledRenderBlocks(Minecraft.getMinecraft().theWorld);
        renderer.enableAO = false;

        for (int x = 0; x < structure.length; x++) {
            String[] plane = structure[x];
            for (int y = 0; y < plane.length; y++) {
                String row = plane[y];
                for (int z = 0; z < row.length(); z++) {
                    char letter = row.charAt(z);
                    if (letter == ' ') continue;
                    Pair<Block, Integer> info = mapper.get(letter);
                    if (info == null) {
                        values.add(letter);
                        continue;
                    }
                    if (info.getLeft() == Blocks.air) continue;

                    FaceVisibility faceInfo = getVisibleFaces(x, y, z);

                    if (faceInfo.isEntireObscured()) continue;

                    renderer.setFaceVisibility(faceInfo);

                    // The floor division is intended to produce proper offsets
                    tess.setTranslation(
                        -structure.length / 2f + x,
                        plane.length / 2f - y, // y needs to be drawn from top to bottom
                        -row.length() / 2f + z);

                    renderer.renderBlockAsItem(info.getLeft(), info.getRight(), 1f);
                }
            }
        }

        return TessellatorManager.stopCapturingToVBO(DefaultVertexFormat.POSITION_TEXTURE_NORMAL);
    }
}