Move mesh instance into a thin wrapper

master
Marc Gilleron 2019-08-25 01:11:38 +01:00
parent ed2db2b443
commit 332041751d
6 changed files with 133 additions and 63 deletions

View File

@ -1,4 +1,5 @@
#include "voxel_block.h"
#include <scene/resources/world.h>
// Helper
VoxelBlock *VoxelBlock::create(Vector3i bpos, Ref<VoxelBuffer> buffer, unsigned int size, unsigned int p_lod_index) {
@ -15,17 +16,10 @@ VoxelBlock *VoxelBlock::create(Vector3i bpos, Ref<VoxelBuffer> buffer, unsigned
return block;
}
VoxelBlock::VoxelBlock() :
voxels(NULL) {
VoxelBlock::VoxelBlock() {
}
VoxelBlock::~VoxelBlock() {
VisualServer &vs = *VisualServer::get_singleton();
if (_mesh_instance.is_valid()) {
vs.free(_mesh_instance);
_mesh_instance = RID();
}
}
void VoxelBlock::set_mesh(Ref<Mesh> mesh, Ref<World> world) {
@ -34,33 +28,27 @@ void VoxelBlock::set_mesh(Ref<Mesh> mesh, Ref<World> world) {
// which is killing performance when LOD is used (i.e many meshes are in pool but hidden)
// This needs investigation.
VisualServer &vs = *VisualServer::get_singleton();
if (mesh.is_valid()) {
if (_mesh_instance.is_valid() == false) {
if (!_mesh_instance.is_valid()) {
// Create instance if it doesn't exist
ERR_FAIL_COND(world.is_null());
_mesh_instance = vs.instance_create();
vs.instance_set_scenario(_mesh_instance, world->get_scenario());
_mesh_instance.create();
_mesh_instance.set_world(*world);
}
vs.instance_set_base(_mesh_instance, mesh->get_rid());
Transform local_transform(Basis(), _position_in_voxels.to_vec3());
vs.instance_set_transform(_mesh_instance, local_transform);
_mesh_instance.set_mesh(mesh);
_mesh_instance.set_transform(Transform(Basis(), _position_in_voxels.to_vec3()));
// TODO The day VoxelTerrain becomes a Spatial, this transform will need to be updatable separately
} else {
if (_mesh_instance.is_valid()) {
// Delete instance if it exists
vs.free(_mesh_instance);
_mesh_instance = RID();
_mesh_instance.destroy();
}
}
_mesh = mesh;
++_mesh_update_count;
// if(_mesh_update_count > 1) {
@ -69,7 +57,7 @@ void VoxelBlock::set_mesh(Ref<Mesh> mesh, Ref<World> world) {
}
bool VoxelBlock::has_mesh() const {
return _mesh.is_valid();
return _mesh_instance.get_mesh().is_valid();
}
void VoxelBlock::set_mesh_state(MeshState ms) {
@ -88,24 +76,15 @@ bool VoxelBlock::has_been_meshed() const {
return _has_been_meshed;
}
void VoxelBlock::enter_world(World *world) {
void VoxelBlock::set_world(World *world) {
if (_mesh_instance.is_valid()) {
VisualServer &vs = *VisualServer::get_singleton();
vs.instance_set_scenario(_mesh_instance, world->get_scenario());
}
}
void VoxelBlock::exit_world() {
if (_mesh_instance.is_valid()) {
VisualServer &vs = *VisualServer::get_singleton();
vs.instance_set_scenario(_mesh_instance, RID());
_mesh_instance.set_world(world);
}
}
void VoxelBlock::set_visible(bool visible) {
if (_mesh_instance.is_valid()) {
VisualServer &vs = *VisualServer::get_singleton();
vs.instance_set_visible(_mesh_instance, visible);
_mesh_instance.set_visible(visible);
}
_visible = visible;
}

View File

@ -1,11 +1,9 @@
#ifndef VOXEL_BLOCK_H
#define VOXEL_BLOCK_H
#include "../util/direct_mesh_instance.h"
#include "../voxel_buffer.h"
#include <scene/3d/mesh_instance.h>
#include <scene/3d/physics_body.h>
// Internal structure holding a reference to mesh visuals, physics and a block of voxel data.
class VoxelBlock {
public:
@ -34,8 +32,7 @@ public:
void mark_been_meshed();
bool has_been_meshed() const;
void enter_world(World *world);
void exit_world();
void set_world(World *world);
void set_visible(bool visible);
bool is_visible() const;
@ -48,11 +45,10 @@ private:
Vector3i _position_in_voxels;
Ref<Mesh> _mesh;
RID _mesh_instance;
DirectMeshInstance _mesh_instance;
int _mesh_update_count = 0;
bool _visible = true;
MeshState _mesh_state = MESH_NEVER_UPDATED;
// The mesh might be null, but we don't know if it's actually empty or if it's loading.

View File

@ -368,18 +368,12 @@ Vector3 VoxelLodTerrain::voxel_to_block_position(Vector3 vpos, unsigned int lod_
void VoxelLodTerrain::_notification(int p_what) {
struct EnterWorldAction {
struct SetWorldAction {
World *world;
EnterWorldAction(World *w) :
SetWorldAction(World *w) :
world(w) {}
void operator()(VoxelBlock *block) {
block->enter_world(world);
}
};
struct ExitWorldAction {
void operator()(VoxelBlock *block) {
block->exit_world();
block->set_world(world);
}
};
@ -411,12 +405,12 @@ void VoxelLodTerrain::_notification(int p_what) {
break;
case NOTIFICATION_ENTER_WORLD: {
EnterWorldAction ewa(*get_world());
SetWorldAction ewa(*get_world());
for_all_blocks(ewa);
} break;
case NOTIFICATION_EXIT_WORLD: {
ExitWorldAction ewa;
SetWorldAction ewa(nullptr);
for_all_blocks(ewa);
} break;

View File

@ -621,18 +621,12 @@ void VoxelTerrain::make_area_dirty(Rect3i box) {
void VoxelTerrain::_notification(int p_what) {
struct EnterWorldAction {
struct SetWorldAction {
World *world;
EnterWorldAction(World *w) :
SetWorldAction(World *w) :
world(w) {}
void operator()(VoxelBlock *block) {
block->enter_world(world);
}
};
struct ExitWorldAction {
void operator()(VoxelBlock *block) {
block->exit_world();
block->set_world(world);
}
};
@ -665,12 +659,12 @@ void VoxelTerrain::_notification(int p_what) {
case NOTIFICATION_ENTER_WORLD: {
ERR_FAIL_COND(_map.is_null());
_map->for_all_blocks(EnterWorldAction(*get_world()));
_map->for_all_blocks(SetWorldAction(*get_world()));
} break;
case NOTIFICATION_EXIT_WORLD:
ERR_FAIL_COND(_map.is_null());
_map->for_all_blocks(ExitWorldAction());
_map->for_all_blocks(SetWorldAction(nullptr));
break;
case NOTIFICATION_VISIBILITY_CHANGED:

View File

@ -0,0 +1,76 @@
#include "direct_mesh_instance.h"
#include <scene/resources/world.h>
DirectMeshInstance::DirectMeshInstance() {
}
DirectMeshInstance::~DirectMeshInstance() {
destroy();
}
bool DirectMeshInstance::is_valid() const {
return _mesh_instance.is_valid();
}
void DirectMeshInstance::create() {
ERR_FAIL_COND(_mesh_instance.is_valid());
VisualServer &vs = *VisualServer::get_singleton();
_mesh_instance = vs.instance_create();
vs.instance_set_visible(_mesh_instance, true); // TODO Is it needed?
}
void DirectMeshInstance::destroy() {
if (_mesh_instance.is_valid()) {
VisualServer &vs = *VisualServer::get_singleton();
vs.free(_mesh_instance);
_mesh_instance = RID();
_mesh.unref();
}
}
void DirectMeshInstance::set_world(World *world) {
ERR_FAIL_COND(!_mesh_instance.is_valid());
VisualServer &vs = *VisualServer::get_singleton();
if (world != nullptr) {
vs.instance_set_scenario(_mesh_instance, world->get_scenario());
} else {
vs.instance_set_scenario(_mesh_instance, RID());
}
}
void DirectMeshInstance::set_transform(Transform world_transform) {
ERR_FAIL_COND(!_mesh_instance.is_valid());
VisualServer &vs = *VisualServer::get_singleton();
vs.instance_set_transform(_mesh_instance, world_transform);
}
void DirectMeshInstance::set_mesh(Ref<Mesh> mesh) {
ERR_FAIL_COND(!_mesh_instance.is_valid());
VisualServer &vs = *VisualServer::get_singleton();
if (mesh.is_valid()) {
vs.instance_set_base(_mesh_instance, mesh->get_rid());
} else {
vs.instance_set_base(_mesh_instance, RID());
}
_mesh = mesh;
}
void DirectMeshInstance::set_material_override(Ref<Material> material) {
ERR_FAIL_COND(!_mesh_instance.is_valid());
VisualServer &vs = *VisualServer::get_singleton();
if (material.is_valid()) {
vs.instance_geometry_set_material_override(_mesh_instance, material->get_rid());
} else {
vs.instance_geometry_set_material_override(_mesh_instance, RID());
}
}
void DirectMeshInstance::set_visible(bool visible) {
ERR_FAIL_COND(!_mesh_instance.is_valid());
VisualServer &vs = *VisualServer::get_singleton();
vs.instance_set_visible(_mesh_instance, visible);
}
Ref<Mesh> DirectMeshInstance::get_mesh() const {
return _mesh;
}

View File

@ -0,0 +1,31 @@
#ifndef DIRECT_MESH_INSTANCE_H
#define DIRECT_MESH_INSTANCE_H
#include <core/rid.h>
#include <scene/resources/mesh.h>
class World;
// Thin wrapper around VisualServer mesh instance API
class DirectMeshInstance {
public:
DirectMeshInstance();
~DirectMeshInstance();
bool is_valid() const;
void create();
void destroy();
void set_world(World *world);
void set_transform(Transform world_transform);
void set_mesh(Ref<Mesh> mesh);
void set_material_override(Ref<Material> material);
void set_visible(bool visible);
Ref<Mesh> get_mesh() const;
private:
RID _mesh_instance;
Ref<Mesh> _mesh;
};
#endif // DIRECT_MESH_INSTANCE_H