master uint/magnolia / source / world / chunk.c
  1#include <stdlib.h>
  2#include <string.h>
  3
  4#include "util.h"
  5#include "world/chunk.h"
  6
  7#define MAX_MESH_VERTICES 65535U
  8
  9static void      add_face(MGVertex* vertices, u16* indices, u32* vertex_count, u32* index_count, const BlockFace* face,
 10                          i32 x, i32 y, i32 z);
 11static BlockType chunk_section_get_neighbour(const ChunkSection* section, const ChunkSection* neighbours[6], i32 x,
 12                                             i32 y, i32 z);
 13
 14/* 6 = number of faces on a cube */
 15static const i32 face_offsets[6][3] = {
 16	{ 0, 0, -1 }, { 0, 0, 1 }, { -1, 0, 0 }, { 1, 0, 0 }, { 0, -1, 0 }, { 0, 1, 0 }
 17};
 18
 19/* add face vertices and indices */
 20static void add_face(MGVertex* vertices, u16* indices, u32* vertex_count, u32* index_count, const BlockFace* face,
 21                     i32 x, i32 y, i32 z)
 22{
 23	MGVertex vtx;
 24	u32      base;
 25	i32      i;
 26
 27	base = *vertex_count;
 28
 29	for (i = 0; i < 4; i++) {
 30		vtx = face->vertices[i];
 31
 32		vtx.x += x;
 33		vtx.y += y;
 34		vtx.z += z;
 35
 36		vertices[(*vertex_count)++] = vtx;
 37	}
 38
 39	indices[(*index_count)++] = (u16)(base + 0);
 40	indices[(*index_count)++] = (u16)(base + 1);
 41	indices[(*index_count)++] = (u16)(base + 2);
 42	indices[(*index_count)++] = (u16)(base + 0);
 43	indices[(*index_count)++] = (u16)(base + 2);
 44	indices[(*index_count)++] = (u16)(base + 3);
 45}
 46
 47/* get block type from section or neighbouring sections
 48   returns the BlockType or BLOCK_AIR if not found */
 49static BlockType chunk_section_get_neighbour(const ChunkSection* section, const ChunkSection* neighbours[6], i32 x,
 50                                             i32 y, i32 z)
 51{
 52	if (neighbours) {
 53		if (z < 0 && neighbours[0])
 54			return chunk_section_get(neighbours[0], x, y, CHUNK_SECTION_DEPTH - 1);
 55		if (z >= CHUNK_SECTION_DEPTH && neighbours[1])
 56			return chunk_section_get(neighbours[1], x, y, 0);
 57		if (x < 0 && neighbours[2])
 58			return chunk_section_get(neighbours[2], CHUNK_SECTION_WIDTH - 1, y, z);
 59		if (x >= CHUNK_SECTION_WIDTH && neighbours[3])
 60			return chunk_section_get(neighbours[3], 0, y, z);
 61		if (y < 0 && neighbours[4])
 62			return chunk_section_get(neighbours[4], x, CHUNK_SECTION_HEIGHT - 1, z);
 63		if (y >= CHUNK_SECTION_HEIGHT && neighbours[5])
 64			return chunk_section_get(neighbours[5], x, 0, z);
 65	}
 66
 67	return chunk_section_get(section, x, y, z);
 68}
 69
 70void chunk_clear(Chunk* chunk)
 71{
 72	i32 section;
 73
 74	if (!chunk)
 75		return;
 76
 77	for (section = 0; section < CHUNK_SECTION_COUNT; section++) {
 78		if (!chunk->sections[section])
 79			continue;
 80
 81		chunk_section_mesh_destroy(chunk->sections[section]);
 82		free(chunk->sections[section]);
 83		chunk->sections[section] = NULL;
 84	}
 85
 86	chunk->section_mask = 0;
 87}
 88
 89void chunk_remove(Chunk* chunk)
 90{
 91	if (!chunk)
 92		return;
 93
 94	chunk_clear(chunk);
 95	memset(chunk, 0, sizeof(*chunk));
 96}
 97
 98void chunk_section_create(ChunkSection* section)
 99{
100	i32 x;
101	i32 y;
102	i32 z;
103
104	if (!section)
105		return;
106
107	memset(section, 0, sizeof(*section));
108	for (z = 0; z < CHUNK_SECTION_DEPTH; z++) {
109		for (x = 0; x < CHUNK_SECTION_WIDTH; x++) {
110			for (y = 0; y < CHUNK_SECTION_HEIGHT - 5; y++)
111				chunk_section_set(section, x, y, z, BLOCK_STONE);
112
113			chunk_section_set(section, x, CHUNK_SECTION_HEIGHT - 5, z, BLOCK_DIRT);
114		}
115	}
116
117	/* dih */
118	chunk_section_set(section, 6, 12, 8, BLOCK_BRICK);
119	chunk_section_set(section, 8, 12, 8, BLOCK_BRICK);
120	chunk_section_set(section, 7, 13, 8, BLOCK_BRICK);
121	chunk_section_set(section, 7, 14, 8, BLOCK_BRICK);
122	chunk_section_set(section, 7, 15, 8, BLOCK_STONE);
123}
124
125i8 chunk_section_decode(ChunkSection* section, const u8* data, size_t size)
126{
127	i32 index;
128	i32 x;
129	i32 y;
130	i32 z;
131	u16 state;
132
133	if (!section || !data)
134		return 0;
135
136	if (size < 8192)
137		return 0;
138
139	chunk_section_mesh_destroy(section);
140	memset(section, 0, sizeof(*section));
141
142	for (index = 0; index < 4096; index++) {
143		/* combine first two bytes to get block state (l operation
144		   is little endian) */
145		state = (u16)data[index * 2] | ((u16)data[index * 2 + 1] << 8);
146
147		/* convert index->3D */
148		x = index & 15;
149		z = (index >> 4) & 15;
150		y = (index >> 8) & 15;
151
152		chunk_section_set(section, x, y, z, state);
153	}
154
155	return 1;
156}
157
158BlockType chunk_section_get(const ChunkSection* section, i32 x, i32 y, i32 z)
159{
160	if (!section)
161		return BLOCK_AIR;
162
163	if (x < 0 || x >= CHUNK_SECTION_WIDTH)
164		return BLOCK_AIR;
165
166	if (y < 0 || y >= CHUNK_SECTION_HEIGHT)
167		return BLOCK_AIR;
168
169	if (z < 0 || z >= CHUNK_SECTION_DEPTH)
170		return BLOCK_AIR;
171
172	return section->blocks[x][y][z];
173}
174
175void chunk_section_set(ChunkSection* section, i32 x, i32 y, i32 z, BlockType block)
176{
177	if (!section)
178		return;
179
180	if (x < 0 || x >= CHUNK_SECTION_WIDTH)
181		return;
182
183	if (y < 0 || y >= CHUNK_SECTION_HEIGHT)
184		return;
185
186	if (z < 0 || z >= CHUNK_SECTION_DEPTH)
187		return;
188
189	section->blocks[x][y][z] = block;
190}
191
192i8 chunk_section_mesh_create(ChunkSection* section, const ChunkSection* neighbours[6])
193{
194	MGVertex*        vertices[BLOCK_TEXTURE_COUNT];
195	u16*             indices[BLOCK_TEXTURE_COUNT];
196	u32              face_counts[BLOCK_TEXTURE_COUNT];
197	u32              vertex_counts[BLOCK_TEXTURE_COUNT];
198	u32              index_counts[BLOCK_TEXTURE_COUNT];
199	MGMeshDesc       desc;
200	BlockType        block;
201	BlockType        neighbour;
202	const BlockFace* faces;
203	i32              face_count;
204	i32              texture;
205	i32              face;
206	i32              x;
207	i32              y;
208	i32              z;
209
210	if (!section)
211		return 0;
212
213	chunk_section_mesh_destroy(section);
214
215	memset(vertices, 0, sizeof(vertices));
216	memset(indices, 0, sizeof(indices));
217	memset(face_counts, 0, sizeof(face_counts));
218	memset(vertex_counts, 0, sizeof(vertex_counts));
219	memset(index_counts, 0, sizeof(index_counts));
220
221	for (texture = 0; texture < BLOCK_TEXTURE_COUNT; texture++)
222		section->meshes[texture] = MGMESH_INVALID;
223
224	/* count visible faces belonging to each block type  */
225	for (z = 0; z < CHUNK_SECTION_DEPTH; z++) {
226		for (y = 0; y < CHUNK_SECTION_HEIGHT; y++) {
227			for (x = 0; x < CHUNK_SECTION_WIDTH; x++) {
228				block = chunk_section_get(section, x, y, z);
229
230				if (block == BLOCK_AIR)
231					continue;
232
233				faces = block_model_faces(block, &face_count);
234				for (face = 0; face < face_count; face++) {
235					if (faces[face].texture < 0)
236						continue;
237					if (faces[face].cullface >= 0) {
238						texture = faces[face].cullface;
239						neighbour = chunk_section_get_neighbour(
240						    section, neighbours, x + face_offsets[texture][0],
241						    y + face_offsets[texture][1], z + face_offsets[texture][2]);
242						if (neighbour != BLOCK_AIR && block_model_occludes(neighbour))
243							continue;
244					}
245					face_counts[faces[face].texture]++;
246				}
247			}
248		}
249	}
250
251	/* allocate  for each block type */
252	for (texture = 0; texture < BLOCK_TEXTURE_COUNT; texture++) {
253		if (face_counts[texture] == 0)
254			continue;
255
256		if (face_counts[texture] * 4U > MAX_MESH_VERTICES) {
257			mg_log(LOG_ERR, "Chunk mesh exceeds u16 vertex limit");
258			goto fail;
259		}
260
261		vertices[texture] = malloc(face_counts[texture] * 4U * sizeof(*vertices[texture]));
262		indices[texture] = malloc(face_counts[texture] * 6U * sizeof(*indices[texture]));
263		if (!vertices[texture] || !indices[texture]) {
264			mg_log(LOG_ERR, "Failed to allocate chunk mesh");
265			goto fail;
266		}
267	}
268
269	/* omit culled model faces hidden by a full cube */
270	for (z = 0; z < CHUNK_SECTION_DEPTH; z++) {
271		for (y = 0; y < CHUNK_SECTION_HEIGHT; y++) {
272			for (x = 0; x < CHUNK_SECTION_WIDTH; x++) {
273				block = chunk_section_get(section, x, y, z);
274
275				if (block == BLOCK_AIR)
276					continue;
277
278				faces = block_model_faces(block, &face_count);
279				for (face = 0; face < face_count; face++) {
280					texture = faces[face].texture;
281					if (texture < 0)
282						continue;
283					if (faces[face].cullface >= 0) {
284						texture = faces[face].cullface;
285						neighbour = chunk_section_get_neighbour(
286						    section, neighbours, x + face_offsets[texture][0],
287						    y + face_offsets[texture][1], z + face_offsets[texture][2]);
288						if (neighbour != BLOCK_AIR && block_model_occludes(neighbour))
289							continue;
290					}
291
292					texture = faces[face].texture;
293					add_face(vertices[texture], indices[texture], &vertex_counts[texture],
294					         &index_counts[texture], &faces[face], x, y, z);
295				}
296			}
297		}
298	}
299
300	/* upload one mesh for each texture */
301	for (texture = 0; texture < BLOCK_TEXTURE_COUNT; texture++) {
302		if (index_counts[texture] == 0)
303			continue;
304
305		desc.vtc = vertices[texture];
306		desc.vtcc = vertex_counts[texture];
307		desc.idc = indices[texture];
308		desc.idcc = index_counts[texture];
309
310		section->meshes[texture] = renderer_mesh_create(&desc);
311
312		if (section->meshes[texture] == MGMESH_INVALID) {
313			mg_log(LOG_ERR, "Failed to upload chunk mesh");
314			goto fail;
315		}
316	}
317
318	for (texture = 0; texture < BLOCK_TEXTURE_COUNT; texture++) {
319		free(indices[texture]);
320		free(vertices[texture]);
321	}
322
323	return 1;
324
325fail:
326	for (texture = 0; texture < BLOCK_TEXTURE_COUNT; texture++) {
327		free(indices[texture]);
328		free(vertices[texture]);
329	}
330
331	chunk_section_mesh_destroy(section);
332	return 0;
333}
334
335void chunk_section_mesh_destroy(ChunkSection* section)
336{
337	i32 texture;
338
339	if (!section)
340		return;
341
342	for (texture = 0; texture < BLOCK_TEXTURE_COUNT; texture++) {
343		renderer_mesh_destroy(section->meshes[texture]);
344		section->meshes[texture] = MGMESH_INVALID;
345	}
346}