179 lines
5.2 KiB
C++
179 lines
5.2 KiB
C++
#include <core/hash_map.h>
|
|
#include <core/math/vector3.h>
|
|
#include <scene/resources/packed_scene.h>
|
|
#include <scene/resources/primitive_meshes.h>
|
|
#include <scene/3d/mesh_instance.h>
|
|
#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<TerrainObject> &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<int> ids;
|
|
ids.resize(rcount);
|
|
printf("ids size: %d rcount: %d\n", ids.size(), rcount);
|
|
HashMap<int, List<Transform> > 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<Transform>();
|
|
instances[obj_id].push_back(xfptr[j * lod_offset]);
|
|
printf("6");
|
|
}
|
|
const List<TerrainObject>::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<Transform>();
|
|
Ref<Mesh> 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<Transform>::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<struct new_point> &nps = new_points[*org][j];
|
|
mi->add_mesh(mesh_grass[j]);
|
|
mi->set_instance_count(id, nps.size());
|
|
const List<struct new_point>::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<LodMultiMesh3D *>::Element *e = meshes.front();
|
|
while(e) {
|
|
LodMultiMesh3D *ve = e->get();
|
|
List<LodMultiMesh3D *>::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<LodMultiMesh3D *>::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> world)
|
|
{
|
|
if (!world.ptr())
|
|
printf("exited world %p\n", gworld.ptr());
|
|
gworld = world;
|
|
List<LodMultiMesh3D *>::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());
|
|
}
|
|
|