mesh_chunk *build_mesh_chunk_for_coord(int x, int y) { int cx = MESH_CHUNK_X_FOR_WORLD_X(x); int slot_x = cx & (MESH_CHUNK_CACHE_X-1); int cy = MESH_CHUNK_Y_FOR_WORLD_Y(y); int slot_y = cy & (MESH_CHUNK_CACHE_Y-1); mesh_chunk *mc = &mesh_cache[slot_y][slot_x]; if (mc->vbuf) { assert(mc->chunk_x != cx || mc->chunk_y != cy); free_mesh_chunk(mc); } { stbvox_mesh_maker mm; chunk_set cs; int i,j; vec3i wc = { x,y,0 }; for (j=0; j < 4; ++j) for (i=0; i < 4; ++i) cs.chunk[j][i] = get_gen_chunk_for_coord(x + (i-1)*GEN_CHUNK_SIZE_X, y + (j-1)*GEN_CHUNK_SIZE_Y); stbvox_init_mesh_maker(&mm); generate_mesh_for_chunk_set(&mm, mc, wc, &cs, vertex_build_buffer, sizeof(vertex_build_buffer), face_buffer); upload_mesh(mc, vertex_build_buffer, face_buffer); } return mc; }
void render_voxel_world(float campos[3]) { int num_build_remaining; int distance; float x = campos[0], y = campos[1]; int qchunk_x, qchunk_y; int cam_x, cam_y; int i,j, rad; #ifdef SINGLE_THREADED_MESHBUILD num_build_remaining = 1; #else num_build_remaining = 0; #endif cam_x = (int) floor(x); cam_y = (int) floor(y); qchunk_x = C_MESH_CHUNK_X_FOR_WORLD_X(cam_x); qchunk_y = C_MESH_CHUNK_Y_FOR_WORLD_Y(cam_y); request_mesh_generation(qchunk_x, qchunk_y, cam_x, cam_y); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.5); stbglUseProgram(main_prog); setup_uniforms(campos); // set uniforms to default values inefficiently glActiveTextureARB(GL_TEXTURE2_ARB); stbglEnableVertexAttribArray(0); rad = view_distance >> MESH_CHUNK_SIZE_X_LOG2; view_dist_for_display = view_distance; { float lighting[2][3] = { { 0,0,0 }, { 0.75,0.75,0.65f } }; float bright = 32; lighting[0][0] = light_pos[0]; lighting[0][1] = light_pos[1]; lighting[0][2] = light_pos[2]; lighting[1][0] *= bright; lighting[1][1] *= bright; lighting[1][2] *= bright; stbglUniform3fv(stbgl_find_uniform(main_prog, "light_source"), 2, lighting[0]); } quads_rendered = 0; quads_considered = 0; chunk_storage_rendered = 0; chunk_storage_considered = 0; chunk_locations = 0; chunks_considered = 0; chunks_in_frustum = 0; compute_frustum(); for (distance = 0; distance <= rad; ++distance) { for (j=-distance; j <= distance; ++j) { for (i=-distance; i <= distance; ++i) { int cx = qchunk_x + i; int cy = qchunk_y + j; int slot_x = cx & (C_MESH_CHUNK_CACHE_X-1); int slot_y = cy & (C_MESH_CHUNK_CACHE_Y-1); mesh_chunk *mc = c_mesh_cache[slot_y][slot_x]; if (stb_max(abs(i),abs(j)) != distance) continue; if (i*i + j*j > rad*rad) continue; if (mc == NULL || mc->chunk_x != cx || mc->chunk_y != cy || mc->vbuf == 0) { float estimated_bounds[2][3]; if (num_build_remaining == 0) continue; estimated_bounds[0][0] = (float) ( cx << MESH_CHUNK_SIZE_X_LOG2); estimated_bounds[0][1] = (float) ( cy << MESH_CHUNK_SIZE_Y_LOG2); estimated_bounds[0][2] = (float) (0); estimated_bounds[1][0] = (float) ((cx+1) << MESH_CHUNK_SIZE_X_LOG2); estimated_bounds[1][1] = (float) ((cy+1) << MESH_CHUNK_SIZE_Y_LOG2); estimated_bounds[1][2] = (float) (255); if (!is_box_in_frustum(estimated_bounds[0], estimated_bounds[1])) continue; mc = build_mesh_chunk_for_coord(cx * C_MESH_CHUNK_CACHE_X, cy * C_MESH_CHUNK_CACHE_Y); --num_build_remaining; } ++chunk_locations; ++chunks_considered; quads_considered += mc->num_quads; chunk_storage_considered += mc->num_quads * 20; if (mc->num_quads) { if (is_box_in_frustum(mc->bounds[0], mc->bounds[1])) { // @TODO if in range, frustum cull stbglUniform3fv(stbgl_find_uniform(main_prog, "transform"), 3, mc->transform[0]); glBindBufferARB(GL_ARRAY_BUFFER_ARB, mc->vbuf); glVertexAttribIPointer(0, 1, GL_UNSIGNED_INT, 4, (void*) 0); glBindTexture(GL_TEXTURE_BUFFER_ARB, mc->fbuf_tex); glDrawArrays(GL_QUADS, 0, mc->num_quads*4); quads_rendered += mc->num_quads; ++chunks_in_frustum; chunk_storage_rendered += mc->num_quads * 20; } } } } } if (num_build_remaining) { for (j=-rad; j <= rad; ++j) { for (i=-rad; i <= rad; ++i) { int cx = qchunk_x + i; int cy = qchunk_y + j; int slot_x = cx & (C_MESH_CHUNK_CACHE_X-1); int slot_y = cy & (C_MESH_CHUNK_CACHE_Y-1); mesh_chunk *mc = c_mesh_cache[slot_y][slot_x]; if (mc->chunk_x != cx || mc->chunk_y != cy || mc->vbuf == 0) { mc = build_mesh_chunk_for_coord(cx * C_MESH_CHUNK_CACHE_X, cy * C_MESH_CHUNK_CACHE_Y); --num_build_remaining; if (num_build_remaining == 0) goto done; } } } done: ; } { built_mesh bm; while (get_next_built_mesh(&bm)) { if (!bm.mc->has_triangles) { // server: physics_process_mesh_chunk(bm.mc); // don't free the physics data below, because the above call copies them bm.mc->allocs = NULL; free_mesh_chunk(bm.mc); } else { //s_process_mesh_chunk(bm.mc); // client: upload_mesh(bm.mc, bm.vertex_build_buffer, bm.face_buffer); set_mesh_chunk_for_coord(bm.mc->chunk_x * MESH_CHUNK_SIZE_X, bm.mc->chunk_y * MESH_CHUNK_SIZE_Y, bm.mc); free(bm.face_buffer); free(bm.vertex_build_buffer); bm.mc = NULL; } } } chunk_storage_total = 0; for (j=0; j < C_MESH_CHUNK_CACHE_Y; ++j) for (i=0; i < C_MESH_CHUNK_CACHE_X; ++i) if (c_mesh_cache[j][i] != NULL && c_mesh_cache[j][i]->vbuf) chunk_storage_total += c_mesh_cache[j][i]->num_quads * 20; stbglDisableVertexAttribArray(0); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glActiveTextureARB(GL_TEXTURE0_ARB); stbglUseProgram(0); }