1using Kestrel.Framework.World;
2using Silk.NET.OpenGL;
3
4namespace Kestrel.Framework.Client.Graphics.Buffers;
5
6public class ChunkMesh(ClientState clientState, Chunk chunk) : Mesh(clientState)
7{
8 readonly Chunk chunk = chunk;
9
10 public override unsafe void Generate()
11 {
12 vao = clientState.Window.GL.GenVertexArray();
13 clientState.Window.GL.BindVertexArray(vao);
14
15 vbo = clientState.Window.GL.GenBuffer();
16 clientState.Window.GL.BindBuffer(BufferTargetARB.ArrayBuffer, vbo);
17
18 Mesher mesher = new();
19 Chunk? topChunk = chunk.World.GetChunk(chunk.ChunkX, chunk.ChunkY + 1, chunk.ChunkZ);
20 Chunk? bottomChunk = chunk.World.GetChunk(chunk.ChunkX, chunk.ChunkY - 1, chunk.ChunkZ);
21 Chunk? northChunk = chunk.World.GetChunk(chunk.ChunkX, chunk.ChunkY, chunk.ChunkZ + 1);
22 Chunk? southChunk = chunk.World.GetChunk(chunk.ChunkX, chunk.ChunkY, chunk.ChunkZ - 1);
23 Chunk? westChunk = chunk.World.GetChunk(chunk.ChunkX - 1, chunk.ChunkY, chunk.ChunkZ);
24 Chunk? eastChunk = chunk.World.GetChunk(chunk.ChunkX + 1, chunk.ChunkY, chunk.ChunkZ);
25
26 if (!chunk.IsEmpty)
27 {
28 for (int x = 0; x < chunk.World.ChunkSize; x++)
29 {
30 for (int y = 0; y < chunk.World.ChunkSize; y++)
31 {
32 for (int z = 0; z < chunk.World.ChunkSize; z++)
33 {
34 float wx = chunk.ChunkX * chunk.World.ChunkSize + x;
35 float wy = chunk.ChunkY * chunk.World.ChunkSize + y;
36 float wz = chunk.ChunkZ * chunk.World.ChunkSize + z;
37
38 BlockType? block = chunk.GetBlock(x, y, z);
39 if (block == BlockType.Air || block == null)
40 continue;
41
42 if (y + 1 >= chunk.World.ChunkSize)
43 {
44 if (topChunk != null)
45 {
46 if (topChunk.GetBlock(x, 0, z) == BlockType.Air)
47 mesher.AddUpFace(block.Value, x, y, z);
48 }
49 else
50 {
51 // mesher.AddUpFace(block.Value, x, y, z);
52 }
53 }
54 else if (chunk.GetBlock(x, y + 1, z) == BlockType.Air)
55 {
56 mesher.AddUpFace(block.Value, x, y, z);
57 }
58
59 if (y - 1 < 0)
60 {
61 if (bottomChunk != null)
62 {
63 if (bottomChunk.GetBlock(x, chunk.World.ChunkSize - 1, z) == BlockType.Air)
64 mesher.AddDownFace(block.Value, x, y, z);
65 }
66 else
67 {
68 // mesher.AddDownFace(block.Value, x, y, z);
69 }
70 }
71 else if (chunk.GetBlock(x, y - 1, z) == BlockType.Air)
72 {
73 mesher.AddDownFace(block.Value, x, y, z);
74 }
75
76 if (x + 1 >= chunk.World.ChunkSize)
77 {
78 if (eastChunk != null)
79 {
80 if (eastChunk.GetBlock(0, y, z) == BlockType.Air)
81 mesher.AddEastFace(block.Value, x, y, z);
82 }
83 else
84 {
85 // mesher.AddEastFace(block.Value, x, y, z);
86 }
87 }
88 else if (chunk.GetBlock(x + 1, y, z) == BlockType.Air)
89 {
90 mesher.AddEastFace(block.Value, x, y, z);
91 }
92
93 if (x - 1 < 0)
94 {
95 if (westChunk != null)
96 {
97 if (westChunk.GetBlock(chunk.World.ChunkSize - 1, y, z) == BlockType.Air)
98 mesher.AddWestFace(block.Value, x, y, z);
99 }
100 else
101 {
102 // mesher.AddWestFace(block.Value, x, y, z);
103 }
104 }
105 else if (chunk.GetBlock(x - 1, y, z) == BlockType.Air)
106 {
107 mesher.AddWestFace(block.Value, x, y, z);
108 }
109
110 if (z + 1 >= chunk.World.ChunkSize)
111 {
112 if (northChunk != null)
113 {
114 if (northChunk.GetBlock(x, y, 0) == BlockType.Air)
115 mesher.AddNorthFace(block.Value, x, y, z);
116 }
117 else
118 {
119 // mesher.AddNorthFace(block.Value, x, y, z);
120 }
121 }
122 else if (chunk.GetBlock(x, y, z + 1) == BlockType.Air)
123 {
124 mesher.AddNorthFace(block.Value, x, y, z);
125 }
126
127 if (z - 1 < 0)
128 {
129 if (southChunk != null)
130 {
131 if (southChunk.GetBlock(x, y, chunk.World.ChunkSize - 1) == BlockType.Air)
132 mesher.AddSouthFace(block.Value, x, y, z);
133 }
134 else
135 {
136 // mesher.AddSouthFace(block.Value, x, y, z);
137 }
138 }
139 else if (chunk.GetBlock(x, y, z - 1) == BlockType.Air)
140 {
141 mesher.AddSouthFace(block.Value, x, y, z);
142 }
143 }
144 }
145 }
146 }
147
148 Vertices = mesher.Vertices.ToArray();
149
150 fixed (float* buf = Vertices)
151 clientState.Window.GL.BufferData(BufferTargetARB.ArrayBuffer, (nuint)(Vertices.Length * sizeof(float)), buf, BufferUsageARB.StaticDraw);
152
153 clientState.Window.GL.EnableVertexAttribArray(0);
154 clientState.Window.GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, 6 * sizeof(float), (void*)0);
155
156 clientState.Window.GL.EnableVertexAttribArray(1);
157 clientState.Window.GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 6 * sizeof(float), (void*)(3 * sizeof(float)));
158
159 clientState.Window.GL.EnableVertexAttribArray(2);
160 clientState.Window.GL.VertexAttribPointer(2, 1, VertexAttribPointerType.Float, false, 6 * sizeof(float), (void*)(5 * sizeof(float)));
161
162 // Clean up
163 clientState.Window.GL.BindVertexArray(0);
164 clientState.Window.GL.BindBuffer(BufferTargetARB.ArrayBuffer, 0);
165 }
166}