#include #include #include #include #include #include "direct_lod_multimesh.h" #include "world_chunk.h" #include "terrain_object.h" #include "world_terrain_lod.h" void WorldTerrainLod::init_lod(int mind, int maxd, float density_range) { int i; min_dist = mind; max_dist = maxd; this->density_range = density_range; } void WorldTerrainLod::update() { } void WorldTerrainLod::create_chunk(const WorldChunk *chunk, const List &obj_list) { int i, j, id; if (mesh_h.has(chunk->get_loc())) return; int lod_offset = 1 << chunk->get_lod(); int obj_count = obj_list.size(); printf("create_chunk started %d\n", obj_count); LodMultiMesh3D *mi = memnew(LodMultiMesh3D); id = 0; int rcount = chunk->get_transforms_count() / lod_offset; const Transform *xfptr = chunk->get_transforms(); const float *variances = chunk->get_variance(); Vector ids; ids.resize(rcount); printf("ids size: %d rcount: %d\n", ids.size(), rcount); HashMap > instances; for (j = 0; j < rcount; j++) { float variance = variances[j * lod_offset]; int obj_id = (int)(variance * obj_count); printf("3 %d %d", j, rcount); ids.write[j] = obj_id; if (!instances.has(obj_id)) instances[obj_id] = List(); instances[obj_id].push_back(xfptr[j * lod_offset]); printf("6"); } const List::Element *e = obj_list.front(); int count = 0; while (e) { printf("obj: %d\n", count); const TerrainObject *obj = &e->get(); if (!instances.has(count)) instances[count] = List(); Ref mesh = obj->get_mesh(chunk->get_lod()); printf("lod: %d mesh: %p, instance count: %d\n", chunk->get_lod(), mesh.ptr(), instances[count].size()); mi->add_mesh(obj->get_mesh(chunk->get_lod())); mi->set_instance_count(count, instances[count].size()); const List::Element *ep = instances[count].front(); int pcount = 0; while (ep) { const Transform &pxform = ep->get(); printf("ep %d %d %ls\n", count, pcount, String(pxform.origin).c_str()); mi->set_instance_transform(count, pcount++, pxform); ep = ep->next(); } e = e->next(); count++; } #if 0 for (j = 0; j < mesh_grass.size(); j++) { if (!new_points[*org].has(j)) continue; const List &nps = new_points[*org][j]; mi->add_mesh(mesh_grass[j]); mi->set_instance_count(id, nps.size()); const List::Element *e = nps.front(); int icount = 0; while(e) { mi->set_instance_transform(id, icount++, e->get().xform); e = e->next(); } id++; } #endif mi->hide(); mi->set_world(NULL); mi->set_global_transform(Transform(Basis(), chunk->get_loc().to_vec3())); meshes.push_back(mi); mesh_h[chunk->get_loc()] = mi; mi->set_world(gworld.ptr()); mi->show(); } void WorldTerrainLod::cleanup(const Transform &vxform) { if (meshes.size() > 0) printf("meshes.size() %p %d\n", this, meshes.size()); List::Element *e = meshes.front(); while(e) { LodMultiMesh3D *ve = e->get(); List::Element *ne = e->next(); Vector3 rpos = ve->get_center(); Vector3 vpos = vxform.origin; Vector3i loc(ve->get_global_transform().origin); if (!valid_org(vxform, ve->get_global_transform().origin, 0.5f)) { memfree(ve); meshes.erase(e); mesh_h.erase(loc); } e = ne; } } static inline bool too_close(const Transform &vxform, const Vector3 &org, float zmin) { Vector3 lpoint = vxform.xform_inv(org); if (-lpoint.z < zmin) return true; return false; } bool WorldTerrainLod::valid_org(const Transform &vxform, const Vector3 &org, float margin) const { bool ret = true; float view_angle = M_PI / 3.0f; float view_s = Math::sin(view_angle); if (too_close(vxform, org, min_dist)) return false; // if (vxform.origin.distance_squared_to(org) > max_dist * max_dist) // return false; //if (min_dist > 0 && vxform.origin.distance_squared_to(org) < min_dist * min_dist) // return false; Vector3 lpoint = vxform.xform_inv(org); /* View is in -Z direction */ if (lpoint.z > -min_dist + margin || lpoint.z < -max_dist - margin) ret = false; if (lpoint.x < -view_s * max_dist -8.0f - margin|| lpoint.x > view_s * max_dist + 8.0f + margin) ret = false; if (lpoint.y < -36.0f || lpoint.y > 36.0f) ret = false; return ret; } void WorldTerrainLod::update_visibility(const Transform &vxform) { List::Element *e = meshes.front(); while(e) { LodMultiMesh3D *mi = e->get(); Transform xform = mi->get_global_transform(); // Vector3 lpoint = vxform.xform_inv(xform.origin); if (mi->is_visible() && !valid_org(vxform, xform.origin, 1.0f)) { mi->hide(); mi->set_world(NULL); } else if (!mi->is_visible() && valid_org(vxform, xform.origin, 0.0f)) { mi->show(); mi->set_world(gworld.ptr()); } e = e->next(); } } void WorldTerrainLod::set_world(Ref world) { if (!world.ptr()) printf("exited world %p\n", gworld.ptr()); gworld = world; List::Element *e = meshes.front(); while(e) { LodMultiMesh3D *mi = e->get(); mi->set_world(gworld.ptr()); e = e->next(); } if (gworld.ptr()) printf("entered world %p\n", gworld.ptr()); }