static Bool gather_collision_geometry(collision_geometry *cg, int base_x, int base_y, int base_z) { int cx0 = C_MESH_CHUNK_X_FOR_WORLD_X(base_x); int cy0 = C_MESH_CHUNK_Y_FOR_WORLD_Y(base_y); int cx1 = C_MESH_CHUNK_X_FOR_WORLD_X(base_x+COLLIDE_BLOB_X-1)+1; int cy1 = C_MESH_CHUNK_Y_FOR_WORLD_Y(base_y+COLLIDE_BLOB_Y-1)+1; int j,i; Bool found_bad = False; memset(cg, 0, sizeof(*cg)); cg->x = base_x; cg->y = base_y; cg->z = base_z; for (j=cy0; j < cy1; ++j) { for (i=cx0; i < cx1; ++i) { int x0 = i << MESH_CHUNK_SIZE_X_LOG2; int y0 = j << MESH_CHUNK_SIZE_Y_LOG2; mesh_chunk *mc = get_physics_chunk_for_coord(x0,y0); if (mc == NULL) { found_bad = True; } else { int a,b; int rx1 = x0 + MESH_CHUNK_SIZE_X; int ry1 = y0 + MESH_CHUNK_SIZE_Y; int rx0 = stb_max(x0, base_x); int ry0 = stb_max(y0, base_y); rx1 = stb_min(rx1, base_x+COLLIDE_BLOB_X); ry1 = stb_min(ry1, base_y+COLLIDE_BLOB_Y); for (b=ry0; b < ry1; ++b) { for (a=rx0; a < rx1; ++a) { phys_chunk_run *pcr = mc->pc.column[b - y0][a - x0]; int z=0; while (z < MAX_Z) { int next_z = z + pcr->length; if (base_z <= next_z && z < base_z + COLLIDE_BLOB_Z) { int z0 = stb_max(base_z, z); int z1 = stb_min(base_z+COLLIDE_BLOB_Z, next_z); int k; for (k=z0; k < z1; ++k) cg->data[b-base_y][a-base_x][k-base_z] = pcr->type; } z = next_z; ++pcr; } } } } } } return !found_bad; }
mesh_chunk *get_physics_chunk_for_coord(int x, int y) { int cx = C_MESH_CHUNK_X_FOR_WORLD_X(x); int cy = C_MESH_CHUNK_Y_FOR_WORLD_Y(y); int rx = cx & (S_PHYSICS_CACHE_X-1); int ry = cy & (S_PHYSICS_CACHE_Y-1); mesh_chunk *mc = &s_phys_cache[ry][rx]; if (mc->chunk_x == cx && mc->chunk_y == cy) return mc; return NULL; }
void physics_process_mesh_chunk(mesh_chunk *mc) { int player_cx = C_MESH_CHUNK_X_FOR_WORLD_X(player_x); int player_cy = C_MESH_CHUNK_Y_FOR_WORLD_Y(player_y); // if it's within the player bounds, update it if (mc->chunk_x >= player_cx - S_PHYSICS_CACHE_X/2 && mc->chunk_x < player_cx + S_PHYSICS_CACHE_X/2 && mc->chunk_y >= player_cy - S_PHYSICS_CACHE_Y/2 && mc->chunk_y < player_cy + S_PHYSICS_CACHE_Y/2) { int phys_cache_x = (mc->chunk_x & (S_PHYSICS_CACHE_X-1)); int phys_cache_y = (mc->chunk_y & (S_PHYSICS_CACHE_Y-1)); mesh_chunk *phys_cache_mc = &s_phys_cache[phys_cache_y][phys_cache_x]; free_mesh_chunk_physics(phys_cache_mc); *phys_cache_mc = *mc; } update_physics_cache_feedback(); }
int physics_set_player_coord(requested_mesh *rm, int max_req, int px, int py) { int i,j,n=0; int player_cx, player_cy; player_x = px; player_y = py; player_cx = C_MESH_CHUNK_X_FOR_WORLD_X(player_x); player_cy = C_MESH_CHUNK_Y_FOR_WORLD_Y(player_y); for (j=0; j < S_PHYSICS_CACHE_Y; ++j) { for (i=0; i < S_PHYSICS_CACHE_X; ++i) { int rx = player_cx - S_PHYSICS_CACHE_X/2 + i; int ry = player_cy - S_PHYSICS_CACHE_Y/2 + j; mesh_chunk *phys_cache_mc = &s_phys_cache[ry & (S_PHYSICS_CACHE_Y-1)][rx & (S_PHYSICS_CACHE_X-1)]; if (phys_cache_mc->chunk_x != rx || phys_cache_mc->chunk_y != ry) { if (n < max_req) { rm[n].x = rx << MESH_CHUNK_SIZE_X_LOG2; rm[n].y = ry << MESH_CHUNK_SIZE_Y_LOG2; rm[n].state = RMS_requested; rm[n].needs_triangles = False; ++n; } } } } update_physics_cache_feedback(); #if 1 return n; #else return 0; #endif }
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); }