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);
}
}
|