uint map_f_chunkhash(void *ptr) { ulong hash = (ulong)ptr; hash = (hash & 0x3f) | (((hash >> 21) & 0x0f) << 12) | (((hash >> 42) & 0x3f) << 6); return (uint)hash; } void world_init(window_t *win, double x, double y, double z, float yaw, float pitch) { world_t *world = win->world = mem_zeros(sizeof(world_t), MEM_WORLD); tbl_init(&world->global_geom, 4, 32, sizeof(geometry_t*), MEM_OBJECT); world->obj_id = 0ULL; // world->size_x = x; // world->size_y = y; // world->size_z = z; // world->clamp_xz = (clamp & WORLD_CLAMP_XZ) ? 1 : 0; // world->clamp_y = (clamp & WORLD_CLAMP_Y) ? 1 : 0; world->n_chunks = world->n_objects = world->n_lights = world->s_lights = 0; map_init(&world->chunk_map, map_f_chunkhash, map_f_inteq, 32, MEM_WORLD); // world->chunks = mem_alloc(sizeof(chunk_t*) * x * y * z, MEM_WORLD); // memset(world->chunks, 0, sizeof(chunk_t*) * x * y * z); tbl_init(&world->chunk_table, 16384, 32, sizeof(chunk_t), MEM_CHUNK); map_init(&world->obj_map, map_f_inthash, map_f_inteq, 32, MEM_OBJMAP); world->light_dirty = world->chunks_dirty = 0; world->dirty_first = world->dirty_queue = NULL; world->gravity = 0.8; world->friction = 0.8; world->entity = &world->entity_base; ent_init(world->entity, world, x, y, z, yaw, pitch); cam_init(&world->camera, x, y + world->entity->eye, z, yaw, pitch); sys_assert(world->post_buf = fb_init(&world->fb_post, &world->fbtex_post, &world->rbo_post, win, 0)); glCreateBuffers(1, &world->light_buf); glNamedBufferData(world->light_buf, LIGHT_SSIZE * gdr.light_max, NULL, GL_DYNAMIC_DRAW); } void world_unload(world_t *world); void world_delete(window_t *win) { world_t *world = win->world; // logd("t", "%d", world->obj_map.stored); world_unload(world); // chunk_delete(&world->global, 0); // mem_free(world->chunks); // tbl_clear(&world->chunk_table); // map_clear(&world->obj_map); glDeleteBuffers(1, &world->light_buf); fb_remove(world->post_buf); mem_free(world); } void chunk_dirty(chunk_t *chunk) { if(!(chunk->dirty)) { if(chunk->world->dirty_first) chunk->world->dirty_queue->next_dirty = chunk; else chunk->world->dirty_first = chunk; chunk->world->dirty_queue = chunk; chunk->next_dirty = NULL; chunk->world->chunks_dirty = 1; chunk->dirty = 1; } } chunk_t *chunk_get(world_t *world, int x, int y, int z, byte load) { ulong id = CHUNK_ID(x, y, z); // if(CHUNK_OUT(world, x, y, z)) // return &world->global; // int offset = CHUNK_STRIDE(world, x, y, z); chunk_t *chunk = map_get(&world->chunk_map, (void*)id); if(chunk) return chunk; else if(!load) return NULL; sys_assert(chunk = (chunk_t*)tbl_push(&world->chunk_table)); chunk->x = x; chunk->y = y; chunk->z = z; chunk->drawlist = NULL; chunk->dirty = 0; chunk->size = 1; chunk->world = world; tbl_init(&chunk->obj_table, 4, 32, sizeof(geometry_t), MEM_OBJECT); tbl_init(&chunk->light_table, 2, 32, sizeof(light_t), MEM_LIGHTS); lst_init(&chunk->poly_list, CHUNK_POLY_GROW, MEM_POLY); chunk->poly_pool = mem_alloc(CHUNK_POLY_GROW * sizeof(polygon_t), MEM_POLY); AABB_SET(chunk->box, (double)(int)(x * CHUNK_SIZE), (double)(int)(y * CHUNK_SIZE), (double)(int)(z * CHUNK_SIZE), (double)(int)((x + 1) * CHUNK_SIZE), (double)(int)((y + 1) * CHUNK_SIZE), (double)(int)((z + 1) * CHUNK_SIZE)) map_put(&world->chunk_map, (void*)id, chunk); world->n_chunks += 1; return chunk; } void chunk_resize(chunk_t *chunk, int size) { // table_t obj_table; list_t poly_list; polygon_t *poly_pool; ulong pos = 0; uint id; geometry_t *geom; // geometry_t *ngeom; polygon_t *poly; polygon_t *npoly; // tbl_init(&obj_table, size * wld.chunk_cap / 32, 32, sizeof(geometry_t), MEM_OBJECT); lst_init(&poly_list, size * CHUNK_POLY_GROW, MEM_POLY); poly_pool = mem_alloc(size * CHUNK_POLY_GROW * sizeof(polygon_t), MEM_POLY); // logd("TST", "chunk @ %d %d %d -> %d %d ---> %d %d", chunk->x, chunk->y, chunk->z, chunk->obj_table.size, chunk->poly_list.size, obj_table.size, poly_list.size); while(geom = tbl_iter(&chunk->obj_table, &pos)) { // ngeom = (geometry_t*)tbl_push(&obj_table); // memcpy(ngeom, geom, sizeof(geometry_t)); // sys_assert(!map_put(&chunk->world->obj_map, (void*)geom->id, ngeom)) poly = &chunk->poly_pool[geom->polys]; geom->polys = 0xffffffff; while(poly) { id = lst_push(&poly_list); if(geom->polys != 0xffffffff) { npoly->next = id; } else { geom->polys = id; } npoly = &poly_pool[id]; memcpy(npoly, poly, sizeof(polygon_t)); // npoly->id = id; poly = (poly->next == 0xffffffff) ? NULL : &chunk->poly_pool[poly->next]; } npoly->next = 0xffffffff; } // tbl_clear(&chunk->obj_table); lst_free(&chunk->poly_list); mem_free(chunk->poly_pool); // memcpy(&chunk->obj_table, &obj_table, sizeof(table_t)); memcpy(&chunk->poly_list, &poly_list, sizeof(list_t)); chunk->poly_pool = poly_pool; chunk->size = size; } // void chunk_resize_light(chunk_t *chunk, int size) { // table_t light_table; // ulong pos = 0; // light_t *light; // light_t *nlight; // tbl_init(&light_table, size * wld.chunk_light / 32, 32, sizeof(light_t), MEM_LIGHTS); // logd("TST", "chunk @ %d %d %d -> %d ---> %d", chunk->x, chunk->y, chunk->z, chunk->light_table.size, light_table.size); // while(light = tbl_iter(&chunk->light_table, &pos)) { // nlight = (light_t*)tbl_push(&light_table); // memcpy(nlight, light, sizeof(light_t)); // sys_assert(!map_put(&chunk->world->obj_map, (void*)light->id, nlight)) // } // tbl_clear(&chunk->light_table); // memcpy(&chunk->light_table, &light_table, sizeof(table_t)); // chunk->light_size = size; // } void vec_tri_normal(vertex_t *result, vertex_b *vertices) { vec3 u, v; glm_vec3_sub(vertices[1].pos, vertices[0].pos, u); glm_vec3_sub(vertices[2].pos, vertices[0].pos, v); glm_vec3_crossn(u, v, v); for(int n = 0; n < 3; n++) { glm_vec3_copy(v, result[n].normal); } } geometry_t *chunk_add(chunk_t *chunk, polygon_b *polys, int n_polys, float x, float y, float z) { geometry_t *obj; if(chunk->poly_list.stored + n_polys > chunk->poly_list.size) chunk_resize(chunk, chunk->size + (((chunk->poly_list.stored + n_polys) - chunk->poly_list.size) + (CHUNK_POLY_GROW - 1)) / CHUNK_POLY_GROW); sys_assert(obj = (geometry_t*)tbl_push(&chunk->obj_table)); // if(!obj) { // chunk_resize(chunk, chunk->size + 1); // obj = (geometry_t*)tbl_push(&chunk->obj_table); // } // logd("TST", "chunk @ %d %d %d -> %d %d", chunk->x, chunk->y, chunk->z, chunk->obj_table.stored, chunk->poly_list.stored); vertex_b *bvertex; vertex_t *nvertex; uint id; polygon_t *poly; AABB_SET(obj->collision, x + polys[0].vertices[0].pos[0], y + polys[0].vertices[0].pos[1], z + polys[0].vertices[0].pos[2], x + polys[0].vertices[0].pos[0], y + polys[0].vertices[0].pos[1], z + polys[0].vertices[0].pos[2]) obj->polys = id = lst_push(&chunk->poly_list); poly = &chunk->poly_pool[id]; for(int c = 0; c < n_polys; c++) { if(c) { id = lst_push(&chunk->poly_list); poly->next = id; poly = &chunk->poly_pool[id]; } // poly->id = id; poly->material = polys[c].material; vec_tri_normal(poly->vertices, polys[c].vertices); for(int v = 0; v < 3; v++) { bvertex = &polys[c].vertices[v]; nvertex = &poly->vertices[v]; box_union(NULL, &obj->collision, x + bvertex->pos[0], y + bvertex->pos[1], z + bvertex->pos[2]); nvertex->pos[0] = x + bvertex->pos[0] - chunk->box.x1; nvertex->pos[1] = y + bvertex->pos[1] - chunk->box.y1; nvertex->pos[2] = z + bvertex->pos[2] - chunk->box.z1; // norm(nvertex->pos, nvertex->normal); // VEC3_SET(nvertex->normal, 0.0f, 1.0f, 0.0f); nvertex->coord[0] = bvertex->coord[0]; nvertex->coord[1] = bvertex->coord[1]; } } poly->next = 0xffffffff; // obj->n_polys = n_polys; // chunk->dirty = 1; if(obj->collision.x2 - obj->collision.x1 >= (float)CHUNK_SIZE || obj->collision.y2 - obj->collision.y1 >= (float)CHUNK_SIZE || obj->collision.z2 - obj->collision.z1 >= (float)CHUNK_SIZE) { obj->global = tbl_push(&chunk->world->global_geom); *(obj->global) = obj; } else { obj->global = NULL; } return obj; } ulong world_add(world_t *world, polygon_b *polys, int n_polys, float x, float y, float z) { chunk_t *chunk; geometry_t *obj; ulong id; chunk = chunk_get(world, NEG_OFFSET(x, CHUNK_SIZE), NEG_OFFSET(y, CHUNK_SIZE), NEG_OFFSET(z, CHUNK_SIZE), 1); // if(!chunk) // return 0; obj = chunk_add(chunk, polys, n_polys, x, y, z); // if(!obj) // return 0; id = world->obj_id += 1ULL; map_put(&world->obj_map, (void*)id, obj); obj->id = id; obj->chunk_x = chunk->x; obj->chunk_y = chunk->y; obj->chunk_z = chunk->z; world->n_objects += 1; chunk_dirty(chunk); return id; } void chunk_remove(chunk_t *chunk, geometry_t *geom) { uint poly = geom->polys; while(poly != 0xffffffff) { lst_pop(&chunk->poly_list, poly); poly = (&chunk->poly_pool[poly])->next; } if(geom->global) tbl_pop(&chunk->world->global_geom, geom->global); tbl_pop(&chunk->obj_table, geom); if((chunk->size > 1) && (chunk->poly_list.stored <= (CHUNK_POLY_GROW * (chunk->size - 1)))) // && (chunk->obj_table.stored <= (((wld.chunk_cap / 32) * (chunk->size - 1)) * (32 * (chunk->size - 1))))) chunk_resize(chunk, chunk->size - 1); // chunk->dirty = 1; } void world_remove(world_t *world, ulong id) { chunk_t *chunk; geometry_t *obj; obj = map_get(&world->obj_map, (void*)id); if(!obj) return; chunk = chunk_get(world, obj->chunk_x, obj->chunk_y, obj->chunk_z, 0); if(!chunk) return; chunk_remove(chunk, obj); map_remove(&world->obj_map, (void*)id); world->n_objects -= 1; chunk_dirty(chunk); } // void chunk_remove_light(chunk_t *chunk, light_t *light) { // tbl_pop(&chunk->light_table, light); // } ulong world_add_light(world_t *world, light_b *lamp, float x, float y, float z) { chunk_t *chunk; light_t *light; ulong id; chunk = chunk_get(world, NEG_OFFSET(x, CHUNK_SIZE), NEG_OFFSET(y, CHUNK_SIZE), NEG_OFFSET(z, CHUNK_SIZE), 1); // if(!chunk) // return 0; sys_assert(light = (light_t*)tbl_push(&chunk->light_table)); // if(!light) { // chunk_resize_light(chunk, chunk->light_size + 1); // light = (light_t*)tbl_push(&chunk->light_table); // } id = world->obj_id += 1ULL; map_put(&world->obj_map, (void*)id, light); light_init_base(light, lamp); light->id = id; VEC3_SET(light->pos, x, y, z); world->n_lights += 1; world->light_dirty = 1; return id; } void world_set_light(world_t *world, ulong id, light_b *lamp) { light_t *light = map_get(&world->obj_map, (void*)id); if(!light) return; light_init_base(light, lamp); world->light_dirty = 1; } void world_remove_light(world_t *world, ulong id) { chunk_t *chunk; light_t *light; light = map_get(&world->obj_map, (void*)id); if(!light) return; chunk = chunk_get(world, NEG_OFFSET(light->pos[0], CHUNK_SIZE), NEG_OFFSET(light->pos[1], CHUNK_SIZE), NEG_OFFSET(light->pos[2], CHUNK_SIZE), 0); if(!chunk) return; tbl_pop(&chunk->light_table, light); map_remove(&world->obj_map, (void*)id); world->n_lights -= 1; // if((chunk->light_size > 1) && (chunk->light_table.stored <= (((wld.chunk_light / 32) * (chunk->light_size - 1)) * (32 * (chunk->light_size - 1))))) // chunk_resize_light(chunk, chunk->light_size - 1); world->light_dirty = 1; } void chunk_clear(chunk_t *chunk, byte unmap) { ulong pos = 0; geometry_t *geom; uint poly; while(geom = tbl_iter(&chunk->obj_table, &pos)) { if(unmap) map_remove(&chunk->world->obj_map, (void*)geom->id); poly = geom->polys; while(poly != 0xffffffff) { lst_pop(&chunk->poly_list, poly); poly = (&chunk->poly_pool[poly])->next; } if(geom->global) tbl_pop(&chunk->world->global_geom, geom->global); } chunk->world->n_objects -= chunk->obj_table.stored; chunk->world->n_lights -= chunk->light_table.stored; if(chunk->light_table.stored) chunk->world->light_dirty = 1; tbl_clear(&chunk->obj_table); tbl_clear(&chunk->light_table); if(chunk->size > 1) chunk_resize(chunk, 1); // if(chunk->light_size > 1) // chunk_resize_light(chunk, 1); // chunk->dirty = 1; chunk_dirty(chunk); } void chunk_update(chunk_t *chunk) { if(chunk->dirty) { drawlist_t *list = chunk->drawlist; if(list) { draw_destroy(list); } else if(chunk->obj_table.stored) { chunk->drawlist = list = tbl_push(&gdr.drawlists); } if(chunk->obj_table.stored && list) { draw_build(chunk, list); } else if(list) { tbl_pop(&gdr.drawlists, list); chunk->drawlist = NULL; } chunk->dirty = 0; } } void chunk_delete(chunk_t *chunk, byte unmap) { chunk_clear(chunk, unmap); chunk_update(chunk); tbl_clear(&chunk->obj_table); tbl_clear(&chunk->light_table); lst_free(&chunk->poly_list); mem_free(chunk->poly_pool); } void chunk_unload(world_t *world, int x, int y, int z) { // if(CHUNK_OUT(world, x, y, z)) // return; ulong id = CHUNK_ID(x, y, z); chunk_t *chunk = map_remove(&world->chunk_map, (void*)id); if(chunk) { chunk_delete(chunk, 1); // world->chunks[offset] = NULL; tbl_pop(&world->chunk_table, chunk); world->n_chunks -= 1; } } void world_update(world_t *world) { if(world->chunks_dirty) { int pos = 0; chunk_t *chunk = world->dirty_first; chunk_t *nchunk; while(chunk) { chunk_update(chunk); if(chunk->obj_table.stored == 0 && chunk->light_table.stored == 0) { nchunk = chunk->next_dirty; chunk_unload(world, chunk->x, chunk->y, chunk->z); chunk = nchunk; } else { chunk = chunk->next_dirty; } } world->dirty_first = world->dirty_queue = NULL; world->chunks_dirty = 0; } if(world->light_dirty) { light_calc(world); world->light_dirty = 0; } } void world_unload(world_t *world) { ulong pos = 0; chunk_t *chunk; while(chunk = tbl_iter(&world->chunk_table, &pos)) { chunk_delete(chunk, 0); } map_clear(&world->chunk_map); tbl_clear(&world->global_geom); tbl_clear(&world->chunk_table); map_clear(&world->obj_map); world->n_chunks = world->n_objects = world->n_lights = 0; } void vec_make_quad(polygon_b *polys, float u, float v, float w, float p, float q, int m, int n, int o) { byte uflip = m < 0; byte vflip = n < 0; m = (m < 0) ? (-1 - m) : (m - 1); n = (n < 0) ? (-1 - n) : (n - 1); o -= 1; for(int c = 0; c < 3; c++) { polys[0].vertices[c].pos[o] = w; polys[1].vertices[c].pos[o] = w; } polys[0].vertices[0].pos[m] = polys[1].vertices[2].pos[m] = u; polys[0].vertices[0].pos[n] = polys[1].vertices[2].pos[n] = v; polys[0].vertices[0].coord[0] = polys[1].vertices[2].coord[0] = uflip ? p : 0.0f; polys[0].vertices[0].coord[1] = polys[1].vertices[2].coord[1] = vflip ? q : 0.0f; polys[0].vertices[1].pos[m] = u + p; polys[0].vertices[1].pos[n] = v; polys[0].vertices[1].coord[0] = uflip ? 0.0f : p; polys[0].vertices[1].coord[1] = vflip ? q : 0.0f; polys[0].vertices[2].pos[m] = polys[1].vertices[0].pos[m] = u + p; polys[0].vertices[2].pos[n] = polys[1].vertices[0].pos[n] = v + q; polys[0].vertices[2].coord[0] = polys[1].vertices[0].coord[0] = uflip ? 0.0f : p; polys[0].vertices[2].coord[1] = polys[1].vertices[0].coord[1] = vflip ? 0.0f : q; polys[1].vertices[1].pos[m] = u; polys[1].vertices[1].pos[n] = v + q; polys[1].vertices[1].coord[0] = uflip ? p : 0.0f; polys[1].vertices[1].coord[1] = vflip ? 0.0f : q; } void vec_make_dquad(polygon_b *polys, float x, float y, float z, float xsize, float ysize, float zsize, material_t *material, byte dir, byte shift) { float offset = shift ? 1.0f : 0.0f; switch(dir) { case FACE_WEST: vec_make_quad(polys, z, y, x, zsize, ysize, 3, 2, 1); break; case FACE_EAST: vec_make_quad(polys, z, y, x + offset * xsize, zsize, ysize, -3, 2, 1); break; case FACE_DOWN: vec_make_quad(polys, x, z, y, xsize, zsize, 1, 3, 2); break; case FACE_UP: vec_make_quad(polys, x, z, y + offset * ysize, xsize, zsize, 1, 3, 2); break; case FACE_NORTH: vec_make_quad(polys, x, y, z, xsize, ysize, 1, 2, 3); break; case FACE_SOUTH: vec_make_quad(polys, x, y, z + offset * zsize, xsize, ysize, -1, 2, 3); break; } polys[0].material = polys[1].material = material; } ulong world_add_floor(world_t *world, float x, float y, float z, float xsize, float zsize, material_t *material) { polygon_b polys[2]; vec_make_dquad(polys, 0.0f, 0.0f, 0.0f, xsize, 0.0f, zsize, material, FACE_UP, 0); return world_add(world, polys, 2, x, y, z); } ulong world_add_box(world_t *world, float x, float y, float z, float xsize, float ysize, float zsize, material_t *material) { polygon_b polys[12]; for(int n = 0; n < 6; n++) { vec_make_dquad(&polys[n << 1], 0.0f, 0.0f, 0.0f, xsize, ysize, zsize, material, n, 1); } return world_add(world, polys, 12, x, y, z); } void vec_make_gquad(polygon_b *polys, float x, float z, float p, float q, float y00, float y10, float y01, float y11) { polys[0].vertices[0].pos X = polys[1].vertices[2].pos X = x; polys[0].vertices[0].pos Y = polys[1].vertices[2].pos Y = y00; polys[0].vertices[0].pos Z = polys[1].vertices[2].pos Z = z; polys[0].vertices[0].coord[0] = polys[1].vertices[2].coord[0] = 0.0f; polys[0].vertices[0].coord[1] = polys[1].vertices[2].coord[1] = 0.0f; polys[0].vertices[1].pos X = x + p; polys[0].vertices[1].pos Y = y10; polys[0].vertices[1].pos Z = z; polys[0].vertices[1].coord[0] = p; polys[0].vertices[1].coord[1] = 0.0f; polys[0].vertices[2].pos X = polys[1].vertices[0].pos X = x + p; polys[0].vertices[2].pos Y = polys[1].vertices[0].pos Y = y11; polys[0].vertices[2].pos Z = polys[1].vertices[0].pos Z = z + q; polys[0].vertices[2].coord[0] = polys[1].vertices[0].coord[0] = p; polys[0].vertices[2].coord[1] = polys[1].vertices[0].coord[1] = q; polys[1].vertices[1].pos X = x; polys[1].vertices[1].pos Y = y01; polys[1].vertices[1].pos Z = z + q; polys[1].vertices[1].coord[0] = 0.0f; polys[1].vertices[1].coord[1] = q; } void world_add_graph(world_t *world, graph2_func *func, void *p, float x, float y, float z, float xsize, float ysize, float zsize, material_t *material, uint xvals, uint zvals, float xoffset, float zoffset, float xrange, float zrange, uint frag) { uint xfrags = (xvals + frag - 1) / frag; uint zfrags = (zvals + frag - 1) / frag; uint fdx = frag; uint fdz = frag; uint sx, sz, fx, fz, gx, gz; polygon_b *polys = mem_alloc(sizeof(polygon_b) * 2 * frag * frag, MEM_POLY); polygon_b *poly; for(sx = 0; sx < xfrags; sx++) { if(sx == xfrags - 1) fdx = xvals - ((xfrags - 1) * frag); for(sz = 0; sz < zfrags; sz++) { if(sz == zfrags - 1) fdz = zvals - ((zfrags - 1) * frag); for(fx = 0; fx < fdx; fx++) { gx = sx * frag + fx; for(fz = 0; fz < fdz; fz++) { gz = sz * frag + fz; poly = &polys[(fx + fz * fdx) * 2]; poly[0].material = poly[1].material = material; vec_make_gquad(poly, xsize * (float)fx / (float)xvals, zsize * (float)fz / (float)zvals, xsize / (float)xvals, zsize / (float)zvals, func(p, xoffset + (float)gx / (float)xvals * xrange, zoffset + (float)gz / (float)zvals * zrange) * ysize, func(p, xoffset + (float)(gx + 1) / (float)xvals * xrange, zoffset + (float)gz / (float)zvals * zrange) * ysize, func(p, xoffset + (float)gx / (float)xvals * xrange, zoffset + (float)(gz + 1) / (float)zvals * zrange) * ysize, func(p, xoffset + (float)(gx + 1) / (float)xvals * xrange, zoffset + (float)(gz + 1) / (float)zvals * zrange) * ysize); // logi("t", "%d %d; %d %d; %d %d; %.1f %.1f -> %.1f", sx, sz, fx, fz, gx, gz, // xoffset + (float)gx / (float)xvals * xrange, zoffset + (float)gz / (float)zvals * zrange, poly[0].vertices[0].pos Y); } } world_add(world, polys, fdx * fdz * 2, x + (xsize * (float)(sx * frag) / (float)xvals), y, z + (zsize * (float)(sz * frag) / (float)zvals)); } } mem_free(polys); }